--- old/src/jdk.vm.ci/share/classes/module-info.java 2016-12-07 13:47:22.614870202 -0800 +++ new/src/jdk.vm.ci/share/classes/module-info.java 2016-12-07 13:47:22.537866819 -0800 @@ -35,4 +35,31 @@ jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory; provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory; + + exports jdk.vm.ci.aarch64 to + jdk.vm.compiler; + exports jdk.vm.ci.amd64 to + jdk.vm.compiler; + exports jdk.vm.ci.code to + jdk.vm.compiler; + exports jdk.vm.ci.code.site to + jdk.vm.compiler; + exports jdk.vm.ci.code.stack to + jdk.vm.compiler; + exports jdk.vm.ci.common to + jdk.vm.compiler; + exports jdk.vm.ci.hotspot to + jdk.vm.compiler; + exports jdk.vm.ci.hotspot.aarch64 to + jdk.vm.compiler; + exports jdk.vm.ci.hotspot.amd64 to + jdk.vm.compiler; + exports jdk.vm.ci.hotspot.sparc to + jdk.vm.compiler; + exports jdk.vm.ci.meta to + jdk.vm.compiler; + exports jdk.vm.ci.runtime to + jdk.vm.compiler; + exports jdk.vm.ci.sparc to + jdk.vm.compiler; } --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/make/CompileTools.gmk 2016-12-07 13:47:22.820879254 -0800 @@ -0,0 +1,162 @@ +# +# Copyright (c) 2016, 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 must be the first rule +default: all + +include $(SPEC) +include MakeBase.gmk + +include JavaCompilation.gmk +include SetupJavaCompilers.gmk + +TARGETS := + +# Hook to include the corresponding custom file, if present. +$(eval $(call IncludeCustomExtension, hotspot, CompileTools.gmk)) + +ifeq ($(INCLUDE_GRAAL), true) + VM_CI_SRC_DIR := $(HOTSPOT_TOPDIR)/src/jdk.vm.ci/share/classes + + SRC_DIR := $(HOTSPOT_TOPDIR)/src/jdk.vm.compiler/share/classes + + ############################################################################## + # Compile the annotation processors + $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := \ + $(SRC_DIR)/org.graalvm.compiler.common/src \ + $(SRC_DIR)/org.graalvm.compiler.core/src \ + $(SRC_DIR)/org.graalvm.compiler.core.common/src \ + $(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \ + $(SRC_DIR)/org.graalvm.compiler.api.collections/src \ + $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \ + $(SRC_DIR)/org.graalvm.compiler.asm/src \ + $(SRC_DIR)/org.graalvm.compiler.bytecode/src \ + $(SRC_DIR)/org.graalvm.compiler.code/src \ + $(SRC_DIR)/org.graalvm.compiler.debug/src \ + $(SRC_DIR)/org.graalvm.compiler.graph/src \ + $(SRC_DIR)/org.graalvm.compiler.lir/src \ + $(SRC_DIR)/org.graalvm.compiler.loop/src \ + $(SRC_DIR)/org.graalvm.compiler.loop.phases/src \ + $(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \ + $(SRC_DIR)/org.graalvm.compiler.nodes/src \ + $(SRC_DIR)/org.graalvm.compiler.options/src \ + $(SRC_DIR)/org.graalvm.compiler.phases/src \ + $(SRC_DIR)/org.graalvm.compiler.phases.common/src \ + $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \ + $(SRC_DIR)/org.graalvm.compiler.virtual/src \ + $(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \ + $(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \ + $(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \ + $(VM_CI_SRC_DIR)/jdk.vm.ci.runtime/src \ + $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \ + , \ + EXCLUDE_FILES := $(EXCLUDE_FILES), \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor, \ + JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor.jar, \ + )) + + TARGETS += $(BUILD_VM_COMPILER_MATCH_PROCESSOR) + + ############################################################################## + + $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_NODEINFO_PROCESSOR, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := \ + $(SRC_DIR)/org.graalvm.compiler.nodeinfo/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, \ + )) + + TARGETS += $(BUILD_VM_COMPILER_NODEINFO_PROCESSOR) + + ############################################################################## + + $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_OPTIONS_PROCESSOR, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := \ + $(SRC_DIR)/org.graalvm.compiler.options/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_VERIFIER, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := \ + $(SRC_DIR)/org.graalvm.compiler.common/src \ + $(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \ + $(SRC_DIR)/org.graalvm.compiler.api.collections/src \ + $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \ + $(SRC_DIR)/org.graalvm.compiler.code/src \ + $(SRC_DIR)/org.graalvm.compiler.core.common/src \ + $(SRC_DIR)/org.graalvm.compiler.debug/src \ + $(SRC_DIR)/org.graalvm.compiler.graph/src \ + $(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \ + $(SRC_DIR)/org.graalvm.compiler.options/src \ + $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \ + $(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \ + $(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \ + $(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \ + $(VM_CI_SRC_DIR)/jdk.vm.ci.runtime/src \ + $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \ + , \ + EXCLUDE_FILES := $(EXCLUDE_FILES), \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier, \ + JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier.jar, \ + )) + + TARGETS += $(BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER) + + ############################################################################## + + $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_SERVICEPROVIDER_PROCESSOR, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := \ + $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \ + $(SRC_DIR)/org.graalvm.compiler.serviceprovider.processor/src \ + $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \ + , \ + EXCLUDE_FILES := $(EXCLUDE_FILES), \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor, \ + JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor.jar, \ + )) + + TARGETS += $(BUILD_VM_COMPILER_SERVICEPROVIDER_PROCESSOR) + + ############################################################################## +endif + +all: $(TARGETS) + +.PHONY: all --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/make/Tools.gmk 2016-12-07 13:47:23.086890942 -0800 @@ -0,0 +1,69 @@ +# +# Copyright (c) 2016, 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 is meant to be included by makefiles using any of the build tools +# compiled by CompileTools.gmk. It assumes that CompileTools.gmk has already +# been run in a separate top level target. It should contain definitions for +# build tools targets without defining the rules to build them so that usage of +# those tools can define prerequisites to them. + +include JavaCompilation.gmk + +# Hook to include the corresponding custom file, if present. +$(eval $(call IncludeCustomExtension, hotspot, Tools.gmk)) + +ifeq ($(ENABLE_AOT), true) + $(eval $(call SetupJavaCompilationCompileTarget, \ + BUILD_VM_COMPILER_MATCH_PROCESSOR, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor, \ + SETUP := GENERATE_JDKBYTECODE, \ + )) + + $(eval $(call SetupJavaCompilationCompileTarget, \ + BUILD_VM_COMPILER_NODEINFO_PROCESSOR, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor, \ + SETUP := GENERATE_JDKBYTECODE, \ + )) + + $(eval $(call SetupJavaCompilationCompileTarget, \ + BUILD_VM_COMPILER_OPTIONS_PROCESSOR, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor, \ + SETUP := GENERATE_JDKBYTECODE, \ + )) + + $(eval $(call SetupJavaCompilationCompileTarget, \ + BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier, \ + SETUP := GENERATE_JDKBYTECODE, \ + )) + + $(eval $(call SetupJavaCompilationCompileTarget, \ + BUILD_VM_COMPILER_SERVICEPROVIDER_PROCESSOR, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor, \ + SETUP := GENERATE_JDKBYTECODE, \ + )) +endif +################################################################################ --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/make/gensrc/Gensrc-jdk.vm.compiler.gmk 2016-12-07 13:47:23.350902543 -0800 @@ -0,0 +1,142 @@ +# +# Copyright (c) 2016, 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. +# + +default: all + +include $(SPEC) +include MakeBase.gmk +include Tools.gmk + +$(eval $(call IncludeCustomExtension, hotspot, gensrc/Gensrc-jdk.vm.compiler.gmk)) + +GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE) +SRC_DIR := $(HOTSPOT_TOPDIR)/src/$(MODULE)/share/classes + +################################################################################ + +PROC_SRC_SUBDIRS := \ + org.graalvm.compiler.code \ + org.graalvm.compiler.common \ + org.graalvm.compiler.core \ + org.graalvm.compiler.core.aarch64 \ + org.graalvm.compiler.core.amd64 \ + org.graalvm.compiler.core.common \ + org.graalvm.compiler.core.sparc \ + org.graalvm.compiler.debug \ + org.graalvm.compiler.hotspot \ + org.graalvm.compiler.hotspot.aarch64 \ + org.graalvm.compiler.hotspot.amd64 \ + org.graalvm.compiler.hotspot.sparc \ + 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 CacheFind, $(PROC_SRC_DIRS))) + +ALL_SRC_DIRS := $(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-exports jdk.vm.ci/jdk.vm.ci.aarch64=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.amd64=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.code=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.code.site=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.code.stack=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.common=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.hotspot=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.hotspot.aarch64=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.hotspot.amd64=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.hotspot.events=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.hotspot.sparc=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.hotspotvmconfig=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.inittimer=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.meta=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.runtime=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.services=ALL-UNNAMED \ + --add-exports jdk.vm.ci/jdk.vm.ci.sparc=ALL-UNNAMED \ + # + +$(GENSRC_DIR)/_gensrc_proc_done: $(PROC_SRCS) $(PROCESSOR_JARS) + $(call MakeDir, $(@D)) + $(eval $(call ListPathsSafely,PROC_SRCS,$(@D)/_gensrc_proc_files)) + $(JAVA_SMALL) $(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 + ($(CD) $(GENSRC_DIR)/META-INF/providers && \ + for i in $$($(LS)); do \ + c=$$($(CAT) $$i | $(TR) -d '\n\r'); \ + $(ECHO) "provides $$c with $$i;" >> $@; \ + done); \ + $(ECHO) "uses org.graalvm.compiler.options.OptionDescriptors;" >> $@; \ + for i in $$($(FIND) $(GENSRC_DIR) -name '*_OptionDescriptors.java'); do \ + c=$$($(ECHO) $$i | $(SED) 's:.*/jdk\.vm\.compiler/\(.*\)\.java:\1:' | $(TR) '/' '.'); \ + $(ECHO) "provides org.graalvm.compiler.options.OptionDescriptors with $$c;" >> $@; \ + done + +TARGETS += $(GENSRC_DIR)/module-info.java.extra + +################################################################################ + +all: $(TARGETS) + +.PHONY: default all --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/module-info.java 2016-12-07 13:47:23.616914231 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016, 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. + */ + +module jdk.vm.compiler { + requires java.instrument; + requires java.management; + requires jdk.management; + requires jdk.vm.ci; + + // sun.misc.Unsafe is used + requires jdk.unsupported; + + uses org.graalvm.compiler.code.DisassemblerProvider; + uses org.graalvm.compiler.core.match.MatchStatementSet; + uses org.graalvm.compiler.debug.DebugConfigCustomizer; + uses org.graalvm.compiler.debug.DebugInitializationParticipant; + uses org.graalvm.compiler.debug.TTYStreamProvider; + uses org.graalvm.compiler.hotspot.CompilerConfigurationFactory; + uses org.graalvm.compiler.hotspot.HotSpotBackendFactory; + uses org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory; + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.collections/src/org/graalvm/compiler/api/collections/CollectionsProvider.java 2016-12-07 13:47:23.882925920 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, 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.collections; + +import java.util.Map; +import java.util.Set; + +/** + * A factory for creating collections. + */ +public interface CollectionsProvider { + + /** + * Creates a set that uses reference-equality in place of object-equality when comparing + * entries. + */ + Set newIdentitySet(); + + /** + * Creates a map that uses reference-equality in place of object-equality when comparing keys. + */ + Map newIdentityMap(); + + /** + * Creates a map that uses reference-equality in place of object-equality when comparing keys. + * + * @param expectedMaxSize the expected maximum size of the map + */ + Map newIdentityMap(int expectedMaxSize); + + /** + * Creates a map that uses reference-equality in place of object-equality when comparing keys. + * + * @param initFrom the returned map is populated with the entries in this map + */ + Map newIdentityMap(Map initFrom); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.collections/src/org/graalvm/compiler/api/collections/DefaultCollectionsProvider.java 2016-12-07 13:47:24.147937564 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014, 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.collections; + +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; + +/** + * A default implementation of {@link CollectionsProvider} that creates standard JDK collection + * class objects. + */ +public class DefaultCollectionsProvider implements CollectionsProvider { + + @Override + public Set newIdentitySet() { + return Collections.newSetFromMap(newIdentityMap()); + } + + @Override + public Map newIdentityMap() { + return new IdentityHashMap<>(); + } + + @Override + public Map newIdentityMap(int expectedMaxSize) { + return new IdentityHashMap<>(expectedMaxSize); + } + + @Override + public Map newIdentityMap(Map initFrom) { + return new IdentityHashMap<>(initFrom); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/AllocationInstrumentationTest.java 2016-12-07 13:47:24.412949209 -0800 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2016, 2016, 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.io.IOException; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; + +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@SuppressWarnings("try") +public class AllocationInstrumentationTest extends GraalCompilerTest { + + private TinyInstrumentor instrumentor; + + public AllocationInstrumentationTest() { + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(ClassA.class, "notInlinedMethod"); + method.setNotInlineable(); + + try { + instrumentor = new TinyInstrumentor(AllocationInstrumentationTest.class, "instrumentation"); + } catch (IOException e) { + Assert.fail("unable to initialize the instrumentor: " + e); + } + } + + public static class ClassA { + // This method should be marked as not inlineable + public void notInlinedMethod() { + } + } + + public static boolean allocationWasExecuted; + + private static void resetFlag() { + allocationWasExecuted = false; + } + + static void instrumentation() { + GraalDirectives.instrumentationBeginForPredecessor(); + allocationWasExecuted = true; + GraalDirectives.instrumentationEnd(); + } + + public static void notEscapeSnippet() { + @SuppressWarnings("unused") + ClassA a = new ClassA(); // a does not escape + } + + @Test + public void testNotEscape() { + try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) { + Class clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "notEscapeSnippet", Opcodes.NEW); + ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "notEscapeSnippet"); + executeExpected(method, null); // ensure the method is fully resolved + resetFlag(); + // The allocation in the snippet does not escape and will be optimized away. We expect + // the instrumentation is removed. + InstalledCode code = getCode(method); + code.executeVarargs(); + Assert.assertFalse("allocation should not take place", allocationWasExecuted); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + + public static void mustEscapeSnippet() { + ClassA a = new ClassA(); + a.notInlinedMethod(); // a escapses + } + + @Test + public void testMustEscape() { + try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) { + Class clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "mustEscapeSnippet", Opcodes.NEW); + ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "mustEscapeSnippet"); + executeExpected(method, null); // ensure the method is fully resolved + resetFlag(); + // The allocation in the snippet escapes. We expect the instrumentation is preserved. + InstalledCode code = getCode(method); + code.executeVarargs(); + Assert.assertTrue("allocation should take place", allocationWasExecuted); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + + public static void partialEscapeSnippet(boolean condition) { + ClassA a = new ClassA(); + + if (condition) { + a.notInlinedMethod(); // a escapes in the then-clause + } + } + + @Test + public void testPartialEscape() { + try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) { + Class clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "partialEscapeSnippet", Opcodes.NEW); + ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "partialEscapeSnippet"); + executeExpected(method, null, true); // ensure the method is fully resolved + resetFlag(); + // The allocation in the snippet escapes in the then-clause, and will be relocated to + // this branch. We expect the instrumentation follows and will only be effective when + // the then-clause is taken. + InstalledCode code = getCode(method); + code.executeVarargs(false); + Assert.assertFalse("allocation should not take place", allocationWasExecuted); + code.executeVarargs(true); + Assert.assertTrue("allocation should take place", allocationWasExecuted); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java 2016-12-07 13:47:24.679960941 -0800 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2015, 2015, 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.junit.Assert; +import org.junit.Test; + +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; + +/** + * Tests for {@link GraalDirectives#blackhole}. + * + * There are two snippets for each kind: + *
    + *
  • blackhole<Kind>Snippet verifies that dead code elimination is prevented by the + * blackhole directive. + *
  • <kind>Snippet verifies that dead code elimination does happen if the blackhole + * directive is not there. + *
+ * + */ +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 boolean 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()); + } + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java 2016-12-07 13:47:24.941972453 -0800 @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2015, 2015, 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.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.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 jdk.vm.ci.meta.ResolvedJavaMethod; + +public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest { + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + @Repeatable(AnchorSnippet.class) + private @interface NodeCount { + + Class 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(); + } + + private static List 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 boolean checkLowTierGraph(StructuredGraph graph) { + List 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 nodes = graph.getNodes().filter(nodeCount.nodeClass()); + Assert.assertEquals(nodeCount.nodeClass().getSimpleName(), nodeCount.expectedCount(), nodes.count()); + } + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/DeoptimizeDirectiveTest.java 2016-12-07 13:47:25.209984229 -0800 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015, 2015, 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 (Throwable 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); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IsMethodInlineDirectiveTest.java 2016-12-07 13:47:25.474995875 -0800 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016, 2016, 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.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class IsMethodInlineDirectiveTest extends GraalCompilerTest { + + public IsMethodInlineDirectiveTest() { + HotSpotResolvedJavaMethod calleeSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(IsMethodInlineDirectiveTest.class, "calleeSnippet"); + calleeSnippet.shouldBeInlined(); + + HotSpotResolvedJavaMethod calleeWithInstrumentationSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(IsMethodInlineDirectiveTest.class, "calleeWithInstrumentationSnippet"); + calleeWithInstrumentationSnippet.shouldBeInlined(); + } + + public static boolean rootMethodSnippet() { + return GraalDirectives.isMethodInlined(); + } + + @SuppressWarnings("try") + @Test + public void testRootMethod() { + ResolvedJavaMethod method = getResolvedJavaMethod("rootMethodSnippet"); + executeExpected(method, null); // ensure the method is fully resolved + // The target method is not inlined. We expect the result to be false. + InstalledCode code = getCode(method); + try { + Result result = new Result(code.executeVarargs(), null); + assertEquals(new Result(false, null), result); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + + public static boolean calleeSnippet() { + return GraalDirectives.isMethodInlined(); + } + + public static boolean callerSnippet() { + return calleeSnippet(); + } + + @Test + public void testInlinedCallee() { + ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet"); + executeExpected(method, null); // ensure the method is fully resolved + // calleeSnippet will be inlined. We expect the result to be true. + InstalledCode code = getCode(method); + try { + Result result = new Result(code.executeVarargs(), null); + assertEquals(new Result(true, null), result); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + + static boolean isCalleeInlined; + static boolean isCallerInlined; + + public static void calleeWithInstrumentationSnippet() { + GraalDirectives.instrumentationBegin(); + isCalleeInlined = GraalDirectives.isMethodInlined(); + GraalDirectives.instrumentationEnd(); + } + + public static void callerSnippet1() { + calleeWithInstrumentationSnippet(); + + GraalDirectives.instrumentationBegin(); + isCallerInlined = GraalDirectives.isMethodInlined(); + GraalDirectives.instrumentationEnd(); + } + + @SuppressWarnings("try") + @Test + public void testInlinedCalleeWithInstrumentation() { + try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) { + ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet1"); + executeExpected(method, null); // ensure the method is fully resolved + isCalleeInlined = false; + isCallerInlined = false; + // calleeWithInstrumentationSnippet will be inlined. We expect the flag1 set in + // calleeWithInstrumentationSnippet to be true, and the flag2 set in callerSnippet1 to + // be false. + InstalledCode code = getCode(method); + code.executeVarargs(); + assertTrue("calleWithInstrumentationSnippet should be inlined", isCalleeInlined); + assertFalse("callerSnippet1 should not be inlined", isCallerInlined); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IterationDirectiveTest.java 2016-12-07 13:47:25.739007475 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, 2015, 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 boolean checkLowTierGraph(StructuredGraph graph) { + NodeIterable 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); + + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/LockInstrumentationTest.java 2016-12-07 13:47:26.004019120 -0800 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016, 2016, 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.io.IOException; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; + +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@SuppressWarnings("try") +public class LockInstrumentationTest extends GraalCompilerTest { + + private TinyInstrumentor instrumentor; + + public LockInstrumentationTest() { + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(ClassA.class, "notInlinedMethod"); + method.setNotInlineable(); + + try { + instrumentor = new TinyInstrumentor(LockInstrumentationTest.class, "instrumentation"); + } catch (IOException e) { + Assert.fail("unable to initialize the instrumentor: " + e); + } + } + + public static class ClassA { + + // This method should be marked as not inlineable + public void notInlinedMethod() { + } + + } + + public static final Object lock = new Object(); + public static boolean lockAfterCheckPoint; + public static boolean checkpoint; + + private static void resetFlags() { + lockAfterCheckPoint = false; + checkpoint = false; + } + + static void instrumentation() { + GraalDirectives.instrumentationBeginForPredecessor(); + lockAfterCheckPoint = checkpoint; + GraalDirectives.instrumentationEnd(); + } + + public static void lockSnippet() { + synchronized (lock) { + checkpoint = true; + ClassA a = new ClassA(); + a.notInlinedMethod(); + } + } + + @Test + public void testLock() { + try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) { + Class clazz = instrumentor.instrument(LockInstrumentationTest.class, "lockSnippet", Opcodes.MONITORENTER); + ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "lockSnippet"); + executeExpected(method, null); // ensure the method is fully resolved + resetFlags(); + // The monitorenter anchors. We expect the instrumentation set the flag before passing + // the checkpoint. + InstalledCode code = getCode(method); + code.executeVarargs(); + Assert.assertFalse("expected lock was performed before checkpoint", lockAfterCheckPoint); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + + public static void postponeLockSnippet() { + ClassA a = new ClassA(); + + synchronized (a) { + checkpoint = true; + a.notInlinedMethod(); + } + + } + + @Test + public void testNonEscapeLock() { + try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) { + Class clazz = instrumentor.instrument(LockInstrumentationTest.class, "postponeLockSnippet", Opcodes.MONITORENTER); + ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "postponeLockSnippet"); + executeExpected(method, null); // ensure the method is fully resolved + resetFlags(); + // The lock in the snippet will be relocated before the invocation to + // notInlinedMethod(), i.e., after the checkpoint. We expect the instrumentation follows + // and flag will be set to true. + InstalledCode code = getCode(method); + code.executeVarargs(); + Assert.assertTrue("expected lock was performed after checkpoint", lockAfterCheckPoint); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java 2016-12-07 13:47:26.268030720 -0800 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2015, 2015, 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.junit.Assert; +import org.junit.Test; + +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; + +/** + * Tests for {@link GraalDirectives#opaque}. + * + * There are two snippets for each kind: + *
    + *
  • opaque<Kind>Snippet verifies that constant folding is prevented by the opaque + * directive. + *
  • <kind>Snippet verifies that constant folding does happen if the opaque directive is not + * there. + *
+ * + */ +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 boolean checkLowTierGraph(StructuredGraph graph) { + OpaqueSnippet snippet = graph.method().getAnnotation(OpaqueSnippet.class); + for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) { + Assert.assertEquals(snippet.expectedReturnNode(), returnNode.result().getClass()); + } + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java 2016-12-07 13:47:26.533042364 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 2015, 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.AbstractBeginNode; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.StructuredGraph; + +public class ProbabilityDirectiveTest extends GraalCompilerTest { + + 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); + } + + @Override + protected boolean checkLowTierGraph(StructuredGraph graph) { + NodeIterable ifNodes = graph.getNodes(IfNode.TYPE); + Assert.assertEquals("IfNode count", 1, ifNodes.count()); + + IfNode ifNode = ifNodes.first(); + AbstractBeginNode trueSuccessor = ifNode.trueSuccessor(); + Assert.assertEquals("branch probability of " + ifNode, 0.125, ifNode.probability(trueSuccessor), 0); + + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/RootNameDirectiveTest.java 2016-12-07 13:47:26.799054053 -0800 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2016, 2016, 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.io.ByteArrayOutputStream; +import java.lang.reflect.Method; +import java.util.Formatter; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import com.google.monitoring.runtime.instrumentation.common.com.google.common.base.Objects; +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.printer.IdealGraphPrinter; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class RootNameDirectiveTest extends GraalCompilerTest { + + public RootNameDirectiveTest() { + HotSpotResolvedJavaMethod rootNameAtCalleeSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(RootNameDirectiveTest.class, "rootNameAtCalleeSnippet"); + rootNameAtCalleeSnippet.shouldBeInlined(); + + HotSpotResolvedJavaMethod rootNameWithinInstrumentationSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(RootNameDirectiveTest.class, "rootNameWithinInstrumentationSnippet"); + rootNameWithinInstrumentationSnippet.shouldBeInlined(); + } + + private static String toString(ResolvedJavaMethod method) { + return method.getDeclaringClass().toJavaName() + "." + method.getName() + method.getSignature().toMethodDescriptor(); + } + + public static String rootNameSnippet() { + return GraalDirectives.rootName(); + } + + @Test + public void testRootName() { + ResolvedJavaMethod method = getResolvedJavaMethod("rootNameSnippet"); + executeExpected(method, null); // ensure the method is fully resolved + // The target snippet is already the root method. We expect the name of the target snippet + // is returned. + InstalledCode code = getCode(method); + try { + Result result = new Result(code.executeVarargs(), null); + assertEquals(new Result(toString(method), null), result); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + + public static String rootNameAtCalleeSnippet() { + return GraalDirectives.rootName(); + } + + public static String callerSnippet() { + return rootNameAtCalleeSnippet(); + } + + @Test + public void testRootNameAtCallee() { + ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet"); + executeExpected(method, null); // ensure the method is fully resolved + // The target snippet is the compilation root of rootNameAtCalleeSnippet() because the later + // will be inlined. We expect the name of the target snippet is returned. + InstalledCode code = getCode(method); + try { + Result result = new Result(code.executeVarargs(), null); + assertEquals(new Result(toString(method), null), result); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + + static String rootNameInCallee; + static String rootNameInCaller; + + @BytecodeParserForceInline + public static void rootNameWithinInstrumentationSnippet() { + GraalDirectives.instrumentationBegin(); + rootNameInCallee = GraalDirectives.rootName(); + GraalDirectives.instrumentationEnd(); + } + + public static void callerSnippet1() { + rootNameWithinInstrumentationSnippet(); + + GraalDirectives.instrumentationBegin(); + rootNameInCaller = GraalDirectives.rootName(); + GraalDirectives.instrumentationEnd(); + } + + @SuppressWarnings("try") + private void assertEquals(StructuredGraph graph, InstalledCode code, Object expected, Object actual) { + if (!Objects.equal(expected, actual)) { + Formatter buf = new Formatter(); + + try (Scope s = Debug.sandbox("PrintingGraph", null)) { + Map properties = new HashMap<>(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IdealGraphPrinter printer = new IdealGraphPrinter(baos, true, getSnippetReflection()); + printer.beginGroup("RootNameDirectiveTest", "RootNameDirectiveTest", graph.method(), -1, null); + properties.put("graph", graph.toString()); + properties.put("scope", Debug.currentScope()); + printer.print(graph, graph.method().format("%H.%n(%p)"), properties); + printer.endGroup(); + printer.close(); + buf.format("-- Graph -- %n%s", baos.toString()); + } catch (Throwable e) { + buf.format("%nError printing graph: %s", e); + } + try { + CodeCacheProvider codeCache = getCodeCache(); + Method disassemble = codeCache.getClass().getMethod("disassemble", InstalledCode.class); + buf.format("%n-- Code -- %n%s", disassemble.invoke(codeCache, code)); + } catch (NoSuchMethodException e) { + // Not a HotSpotCodeCacheProvider + } catch (Exception e) { + buf.format("%nError disassembling code: %s", e); + } + Assert.assertEquals(buf.toString(), expected, actual); + } + } + + @SuppressWarnings("try") + @Test + public void testRootNameWithinInstrumentationAtCallee() { + try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) { + ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet1"); + executeExpected(method, null); // ensure the method is fully resolved + rootNameInCallee = null; + rootNameInCaller = null; + // We expect both rootName1 and rootName2 are set to the name of the target snippet. + StructuredGraph graph = parseForCompile(method); + InstalledCode code = getCode(method, graph); + code.executeVarargs(); + assertEquals(graph, code, toString(method), rootNameInCallee); + assertEquals(graph, code, rootNameInCallee, rootNameInCaller); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/TinyInstrumentor.java 2016-12-07 13:47:27.063065653 -0800 @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2016, 2016, 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.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.graalvm.compiler.test.ExportingClassLoader; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode; +import jdk.internal.org.objectweb.asm.tree.ClassNode; +import jdk.internal.org.objectweb.asm.tree.IincInsnNode; +import jdk.internal.org.objectweb.asm.tree.InsnList; +import jdk.internal.org.objectweb.asm.tree.JumpInsnNode; +import jdk.internal.org.objectweb.asm.tree.LabelNode; +import jdk.internal.org.objectweb.asm.tree.LineNumberNode; +import jdk.internal.org.objectweb.asm.tree.MethodNode; +import jdk.internal.org.objectweb.asm.tree.VarInsnNode; + +/** + * The {@code TinyInstrumentor} is a bytecode instrumentor using ASM bytecode manipulation + * framework. It injects given code snippet into a target method and creates a temporary class as + * the container. Because the target method is cloned into the temporary class, it is required that + * the target method is public static. Any referred method/field in the target method or the + * instrumentation snippet should be made public as well. + */ +public class TinyInstrumentor implements Opcodes { + + private InsnList instrumentationInstructions; + private int instrumentationMaxLocal; + + /** + * Create a instrumentor with a instrumentation snippet. The snippet is specified with the given + * class {@code instrumentationClass} and the given method name {@code methodName}. + */ + public TinyInstrumentor(Class instrumentationClass, String methodName) throws IOException { + MethodNode instrumentationMethod = getMethodNode(instrumentationClass, methodName); + assert instrumentationMethod != null; + assert (instrumentationMethod.access | ACC_STATIC) != 0; + assert "()V".equals(instrumentationMethod.desc); + instrumentationInstructions = cloneInstructions(instrumentationMethod.instructions); + instrumentationMaxLocal = instrumentationMethod.maxLocals; + // replace return instructions with a goto unless there is a single return at the end. In + // that case, simply remove the return. + List returnInstructions = new ArrayList<>(); + for (AbstractInsnNode instruction : selectAll(instrumentationInstructions)) { + if (instruction instanceof LineNumberNode) { + instrumentationInstructions.remove(instruction); + } else if (instruction.getOpcode() == RETURN) { + returnInstructions.add(instruction); + } + } + LabelNode exit = new LabelNode(); + if (returnInstructions.size() == 1) { + AbstractInsnNode returnInstruction = returnInstructions.get(0); + if (instrumentationInstructions.getLast() != returnInstruction) { + instrumentationInstructions.insertBefore(returnInstruction, new JumpInsnNode(GOTO, exit)); + } + instrumentationInstructions.remove(returnInstruction); + } else { + for (AbstractInsnNode returnInstruction : returnInstructions) { + instrumentationInstructions.insertBefore(returnInstruction, new JumpInsnNode(GOTO, exit)); + instrumentationInstructions.remove(returnInstruction); + } + } + instrumentationInstructions.add(exit); + } + + /** + * @return a {@link MethodNode} called {@code methodName} in the given class. + */ + private static MethodNode getMethodNode(Class clazz, String methodName) throws IOException { + ClassReader classReader = new ClassReader(clazz.getName()); + ClassNode classNode = new ClassNode(); + classReader.accept(classNode, ClassReader.SKIP_FRAMES); + + for (MethodNode methodNode : classNode.methods) { + if (methodNode.name.equals(methodName)) { + return methodNode; + } + } + return null; + } + + /** + * Create a {@link ClassNode} with empty constructor. + */ + private static ClassNode emptyClass(String name) { + ClassNode classNode = new ClassNode(); + classNode.visit(52, ACC_SUPER | ACC_PUBLIC, name.replace('.', '/'), null, "java/lang/Object", new String[]{}); + + MethodVisitor mv = classNode.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitMaxs(1, 1); + mv.visitEnd(); + + return classNode; + } + + /** + * Helper method for iterating the given {@link InsnList}. + */ + private static Iterable selectAll(InsnList instructions) { + return new Iterable() { + @Override + public Iterator iterator() { + return instructions.iterator(); + } + }; + } + + /** + * Make a clone of the given {@link InsnList}. + */ + private static InsnList cloneInstructions(InsnList instructions) { + Map labelMap = new HashMap<>(); + for (AbstractInsnNode instruction : selectAll(instructions)) { + if (instruction instanceof LabelNode) { + LabelNode clone = new LabelNode(new Label()); + LabelNode original = (LabelNode) instruction; + labelMap.put(original, clone); + } + } + InsnList clone = new InsnList(); + for (AbstractInsnNode insn : selectAll(instructions)) { + clone.add(insn.clone(labelMap)); + } + return clone; + } + + /** + * Shifts all local variable slot references by a specified amount. + */ + private static void shiftLocalSlots(InsnList instructions, int offset) { + for (AbstractInsnNode insn : selectAll(instructions)) { + if (insn instanceof VarInsnNode) { + VarInsnNode varInsn = (VarInsnNode) insn; + varInsn.var += offset; + + } else if (insn instanceof IincInsnNode) { + IincInsnNode iincInsn = (IincInsnNode) insn; + iincInsn.var += offset; + } + } + } + + /** + * Instrument the target method specified by the class {@code targetClass} and the method name + * {@code methodName}. For each occurrence of the {@code opcode}, the instrumentor injects a + * copy of the instrumentation snippet. + */ + public Class instrument(Class targetClass, String methodName, int opcode) throws IOException, ClassNotFoundException { + return instrument(targetClass, methodName, opcode, true); + } + + public Class instrument(Class targetClass, String methodName, int opcode, boolean insertAfter) throws IOException, ClassNotFoundException { + // create a container class + String className = targetClass.getName() + "$$" + methodName; + ClassNode classNode = emptyClass(className); + // duplicate the target method and add to the container class + MethodNode methodNode = getMethodNode(targetClass, methodName); + MethodNode newMethodNode = new MethodNode(methodNode.access, methodNode.name, methodNode.desc, methodNode.signature, methodNode.exceptions.toArray(new String[methodNode.exceptions.size()])); + methodNode.accept(newMethodNode); + classNode.methods.add(newMethodNode); + // perform bytecode instrumentation + for (AbstractInsnNode instruction : selectAll(newMethodNode.instructions)) { + if (instruction.getOpcode() == opcode) { + InsnList instrumentation = cloneInstructions(instrumentationInstructions); + shiftLocalSlots(instrumentation, newMethodNode.maxLocals); + newMethodNode.maxLocals += instrumentationMaxLocal; + if (insertAfter) { + newMethodNode.instructions.insert(instruction, instrumentation); + } else { + newMethodNode.instructions.insertBefore(instruction, instrumentation); + } + } + } + // dump a byte array and load the class with a dedicated loader to separate the namespace + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + classNode.accept(classWriter); + byte[] bytes = classWriter.toByteArray(); + return new Loader(className, bytes).findClass(className); + } + + private static class Loader extends ExportingClassLoader { + + private String className; + private byte[] bytes; + + Loader(String className, byte[] bytes) { + super(TinyInstrumentor.class.getClassLoader()); + this.className = className; + this.bytes = bytes; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals(className)) { + return defineClass(name, bytes, 0, bytes.length); + } else { + return super.findClass(name); + } + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java 2016-12-07 13:47:27.329077342 -0800 @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2015, 2015, 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; + +import java.nio.charset.Charset; + +// 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() { + } + + /** + * 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() { + } + + /** + * 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%): + * + * + * if (injectBranchProbability(0.9, a > b)) { + * // ... + * } + * + * + * 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): + * + * + * for (int i = 0; injectIterationCount(500, i < array.length); i++) { + * // ... + * } + * + * + * @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 opaque(T value) { + return value; + } + + public static 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) { + } + + /** + * Marks the beginning of an instrumentation boundary. The instrumentation code will be folded + * during compilation and will not affect inlining heuristics regarding graph size except one on + * compiled low-level graph size (e.g., {@code GraalOptions.SmallCompiledLowLevelGraphSize}). + */ + public static void instrumentationBegin() { + } + + /** + * Marks the beginning of an instrumentation boundary and associates the instrumentation with + * the preceding bytecode. If the instrumented instruction is {@code new}, then instrumentation + * will adapt to optimizations concerning allocation, and only be executed if allocation really + * happens. + * + * Example (the instrumentation is associated with {@code new}): + * + *
+ * + *
+     *  0  new java.lang.Object
+     *  3  invokestatic org.graalvm.compiler.api.directives.GraalDirectives.instrumentationBeginForPredecessor() : void
+     *  6  invokestatic AllocationProfiler.countActualAllocation() : void
+     *  9  invokestatic org.graalvm.compiler.api.directives.GraalDirectives.instrumentationEnd() : void
+     * 12  invokespecial java.lang.Object()
+     * 
+ * + *
+ * + * @see #instrumentationBegin() + */ + public static void instrumentationBeginForPredecessor() { + } + + /** + * Marks the end of the instrumentation boundary. + * + * @see #instrumentationBegin() + */ + public static void instrumentationEnd() { + } + + /** + * @return true if the enclosing method is inlined. + */ + public static boolean isMethodInlined() { + return false; + } + + private static final Charset UTF8 = Charset.forName("UTF-8"); + + /** + * @return the name of the root method for the current compilation task. If the enclosing method + * is inlined, it returns the name of the method into which it is inlined. + */ + public static String rootName() { + return new String(rawRootName(), UTF8); + } + + public static byte[] rawRootName() { + return new byte[0]; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/ClassSubstitution.java 2016-12-07 13:47:27.594088986 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011, 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. + *

+ * 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. + *

+ * This method is provided for cases where the original class is not accessible (according to + * Java language access control rules). + *

+ * 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. + */ + boolean optional() default false; +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/Fold.java 2016-12-07 13:47:27.857100543 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, 2014, 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. The caller should always pass {@code null}. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + public @interface InjectedParameter { + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java 2016-12-07 13:47:28.122112187 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +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 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 method used to do the substitution is compiler dependent but every + * compiler should require substitute methods to be annotated with {@link MethodSubstitution}. In + * addition, a compiler is recommended to implement {@link MethodSubstitutionRegistry} to advertise + * the mechanism by which it supports registration of method substitutes. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface MethodSubstitution { + + /** + * Gets the name of the original method. + *

+ * 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. + *

+ * 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; +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitutionRegistry.java 2016-12-07 13:47:28.388123876 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.api.replacements; + +import java.lang.reflect.Type; + +/** + * A registry for {@link MethodSubstitution}s. + */ +public interface MethodSubstitutionRegistry { + + /** + * Gets the type representing the receiver (i.e., {@code this}) argument in a non-static method. + */ + Class getReceiverType(); + + /** + * Registers a substitution method. + * + * @param substituteDeclaringClass the class declaring the substitute method + * @param name the name of both the original and substitute method + * @param argumentTypes the argument types of the method. Element 0 of this array must be + * {@link #getReceiverType()} iff the method is non-static. Upon returning, element 0 + * will have been rewritten to {@code declaringClass}. + */ + default void registerMethodSubstitution(Class substituteDeclaringClass, String name, Type... argumentTypes) { + registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes); + } + + /** + * Registers a substitution method. + * + * @param substituteDeclaringClass the class declaring the substitute method + * @param name the name of both the original method + * @param substituteName the name of the substitute method + * @param argumentTypes the argument types of the method. Element 0 of this array must be + * {@link #getReceiverType()} iff the method is non-static. Upon returning, element 0 + * will have been rewritten to {@code declaringClass}. + */ + void registerMethodSubstitution(Class substituteDeclaringClass, String name, String substituteName, Type... argumentTypes); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/Snippet.java 2016-12-07 13:47:28.652135476 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011, 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 { + + /** + * 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 { + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java 2016-12-07 13:47:28.916147077 -0800 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2014, 2015, 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. + *

+ * 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 asObject(Class type, JavaConstant constant); + + /** + * 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} if it is an + * {@link ResolvedJavaType#isInstance(JavaConstant) instance of} {@code type} otherwise + * {@code null} + */ + Object asObject(ResolvedJavaType 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} + */ + JavaConstant forBoxed(JavaKind kind, Object 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 getInjectedNodeIntrinsicParameter(Class type); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetTemplateCache.java 2016-12-07 13:47:29.180158677 -0800 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.api.replacements; + +/** + * Marker interface for classes that cache snippet templates. + */ +public interface SnippetTemplateCache { +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/overview.html 2016-12-07 13:47:29.445170322 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.api project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalJVMCICompiler.java 2016-12-07 13:47:29.710181966 -0800 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015, 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(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalRuntime.java 2016-12-07 13:47:29.977193699 -0800 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012, 2012, 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; + +public interface GraalRuntime { + + String getName(); + + T getCapability(Class clazz); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.test/overview.html 2016-12-07 13:47:30.243205387 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.api.test project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/Graal.java 2016-12-07 13:47:30.514217295 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, 2015, 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 jdk.vm.ci.runtime.JVMCI; +import jdk.vm.ci.runtime.JVMCICompiler; +import jdk.vm.ci.services.Services; + +import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; +import org.graalvm.compiler.api.runtime.GraalRuntime; + +/** + * 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.exportJVMCITo(Graal.class); + 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 getRequiredCapability(Class 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 getCapability(Class clazz) { + return null; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/GraalAPITest.java 2016-12-07 13:47:30.780228984 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, 2015, 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()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/AArch64MacroAssemblerTest.java 2016-12-07 13:47:31.051240892 -0800 @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2013, 2015, 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.asm.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 AArch64MacroAssemblerTest extends GraalTest { + + private AArch64MacroAssembler masm; + private TestProtectedAssembler asm; + private Register base; + private Register index; + private Register scratch; + + private static EnumSet computeFeatures() { + EnumSet features = EnumSet.noneOf(AArch64.CPUFeature.class); + features.add(CPUFeature.FP); + return features; + } + + private static EnumSet computeFlags() { + EnumSet 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); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java 2016-12-07 13:47:31.319252668 -0800 @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2013, 2015, 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 + protected void ldar(int size, Register rt, Register rn) { + super.ldar(size, rt, rn); + } + + @Override + protected void stlr(int size, Register rt, Register rn) { + super.stlr(size, 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 + protected void bfm(int size, Register dst, Register src, int r, int s) { + super.bfm(size, dst, src, r, s); + } + + @Override + protected void ubfm(int size, Register dst, Register src, int r, int s) { + super.ubfm(size, dst, src, r, s); + } + + @Override + protected 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 + protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { + super.adds(size, dst, src1, src2, shiftType, imm); + } + + @Override + protected 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 + protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { + super.sub(size, dst, src1, src2, extendType, shiftAmt); + } + + @Override + protected 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 ror(int size, Register dst, Register src1, Register src2) { + super.ror(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 + protected 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(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Address.java 2016-12-07 13:47:31.593264708 -0800 @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.asm.aarch64; + +import static jdk.vm.ci.aarch64.AArch64.zr; + +import org.graalvm.compiler.asm.AbstractAddress; +import org.graalvm.compiler.asm.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 + *

+ * 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, + AddressingMode, + } + + 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 addressingMode ==IMMEDIATE_UNSCALED the value will be returned + * as the 9bit signed representation. + */ + public int getImmediate() { + switch (addressingMode) { + case IMMEDIATE_UNSCALED: + case IMMEDIATE_POST_INDEXED: + case IMMEDIATE_PRE_INDEXED: + // 9-bit signed value + return immediate & NumUtil.getNbitNumberInt(9); + case IMMEDIATE_SCALED: + // Unsigned value can be returned as-is. + return immediate; + case PC_LITERAL: + // 21-bit signed value, but lower 2 bits are always 0 and are shifted out. + 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(); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java 2016-12-07 13:47:31.858276353 -0800 @@ -0,0 +1,2499 @@ +/* + * Copyright (c) 2013, 2016, 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 org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADD; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADDS; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.AND; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ANDS; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ASRV; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BFM; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BIC; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BICS; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BLR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BRK; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLREX; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLS; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLZ; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSEL; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSINC; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSNEG; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.DMB; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EON; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EOR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EXTR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FABS; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FADD; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCCMP; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCMP; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCMPZERO; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCSEL; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTDS; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTSD; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTZS; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FDIV; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMADD; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMOV; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMSUB; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMUL; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FNEG; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTZ; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSQRT; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSUB; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HINT; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HLT; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAXR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDP; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDRS; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDXR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LSLV; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LSRV; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MADD; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVK; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVN; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVZ; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MSUB; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ORN; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ORR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RBIT; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RET; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.REVW; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.REVX; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RORV; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SBFM; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SCVTF; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SDIV; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STLR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STLXR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STP; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STXR; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SUB; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SUBS; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.UBFM; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.UDIV; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.FP32; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.FP64; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.General32; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.General64; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.floatFromSize; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.generalFromSize; +import static jdk.vm.ci.aarch64.AArch64.CPU; +import static jdk.vm.ci.aarch64.AArch64.SIMD; +import static jdk.vm.ci.aarch64.AArch64.r0; +import static jdk.vm.ci.aarch64.AArch64.sp; +import static jdk.vm.ci.aarch64.AArch64.zr; + +import java.util.Arrays; + +import org.graalvm.compiler.asm.Assembler; +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; + +public abstract class AArch64Assembler extends Assembler { + + public static class LogicalImmediateTable { + + private static final Immediate[] IMMEDIATE_TABLE = buildImmediateTable(); + + private static final int ImmediateOffset = 10; + private static final int ImmediateRotateOffset = 16; + private static final int ImmediateSizeOffset = 22; + + /** + * Specifies whether immediate can be represented in all cases (YES), as a 64bit instruction + * (SIXTY_FOUR_BIT_ONLY) or not at all (NO). + */ + enum Representable { + YES, + SIXTY_FOUR_BIT_ONLY, + NO + } + + /** + * Tests whether an immediate can be encoded for logical instructions. + * + * @param is64bit if true immediate is considered a 64-bit pattern. If false we may use a + * 64-bit instruction to load the 32-bit pattern into a register. + * @return enum specifying whether immediate can be used for 32- and 64-bit logical + * instructions ({@code #Representable.YES}), for 64-bit instructions only ( + * {@link Representable#SIXTY_FOUR_BIT_ONLY}) or not at all ( + * {@link Representable#NO}). + */ + public static Representable isRepresentable(boolean is64bit, long immediate) { + int pos = getLogicalImmTablePos(is64bit, immediate); + if (pos < 0) { + // if 32bit instruction we can try again as 64bit immediate which may succeed. + // i.e. 0xffffffff fails as a 32bit immediate but works as 64bit one. + if (!is64bit) { + assert NumUtil.isUnsignedNbit(32, immediate); + pos = getLogicalImmTablePos(true, immediate); + return pos >= 0 ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.NO; + } + return Representable.NO; + } + Immediate imm = IMMEDIATE_TABLE[pos]; + return imm.only64bit() ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.YES; + } + + public static Representable isRepresentable(int immediate) { + return isRepresentable(false, immediate & 0xFFFF_FFFFL); + } + + public static int getLogicalImmEncoding(boolean is64bit, long value) { + int pos = getLogicalImmTablePos(is64bit, value); + assert pos >= 0 : "Value cannot be represented as logical immediate: " + value + ", is64bit=" + is64bit; + Immediate imm = IMMEDIATE_TABLE[pos]; + assert is64bit || !imm.only64bit() : "Immediate can only be represented for 64bit, but 32bit instruction specified"; + return IMMEDIATE_TABLE[pos].encoding; + } + + /** + * @param is64bit if true also allow 64-bit only encodings to be returned. + * @return If positive the return value is the position into the IMMEDIATE_TABLE for the + * given immediate, if negative the immediate cannot be encoded. + */ + private static int getLogicalImmTablePos(boolean is64bit, long value) { + Immediate imm; + if (!is64bit) { + // 32bit instructions can only have 32bit immediates. + if (!NumUtil.isUnsignedNbit(32, value)) { + return -1; + } + // If we have a 32bit instruction (and therefore immediate) we have to duplicate it + // across 64bit to find it in the table. + imm = new Immediate(value << 32 | value); + } else { + imm = new Immediate(value); + } + int pos = Arrays.binarySearch(IMMEDIATE_TABLE, imm); + if (pos < 0) { + return -1; + } + if (!is64bit && IMMEDIATE_TABLE[pos].only64bit()) { + return -1; + } + return pos; + } + + /** + * To quote 5.4.2: [..] an immediate is a 32 or 64 bit pattern viewed as a vector of + * identical elements of size e = 2, 4, 8, 16, 32 or (in the case of bimm64) 64 bits. Each + * element contains the same sub-pattern: a single run of 1 to e-1 non-zero bits, rotated by + * 0 to e-1 bits. It is encoded in the following: 10-16: rotation amount (6bit) starting + * from 1s in the LSB (i.e. 0111->1011->1101->1110) 16-22: This stores a combination of the + * number of set bits and the pattern size. The pattern size is encoded as follows (x is + * used to store the number of 1 bits - 1) e pattern 2 1111xx 4 1110xx 8 110xxx 16 10xxxx 32 + * 0xxxxx 64 xxxxxx 22: if set we have an instruction with 64bit pattern? + */ + private static final class Immediate implements Comparable { + public final long imm; + public final int encoding; + + Immediate(long imm, boolean is64, int s, int r) { + this.imm = imm; + this.encoding = computeEncoding(is64, s, r); + } + + // Used to be able to binary search for an immediate in the table. + Immediate(long imm) { + this(imm, false, 0, 0); + } + + /** + * Returns true if this pattern is only representable as 64bit. + */ + public boolean only64bit() { + return (encoding & (1 << ImmediateSizeOffset)) != 0; + } + + private static int computeEncoding(boolean is64, int s, int r) { + int sf = is64 ? 1 : 0; + return sf << ImmediateSizeOffset | r << ImmediateRotateOffset | s << ImmediateOffset; + } + + @Override + public int compareTo(Immediate o) { + return Long.compare(imm, o.imm); + } + } + + private static Immediate[] buildImmediateTable() { + final int nrImmediates = 5334; + final Immediate[] table = new Immediate[nrImmediates]; + int nrImms = 0; + for (int logE = 1; logE <= 6; logE++) { + int e = 1 << logE; + long mask = NumUtil.getNbitNumberLong(e); + for (int nrOnes = 1; nrOnes < e; nrOnes++) { + long val = (1L << nrOnes) - 1; + // r specifies how much we rotate the value + for (int r = 0; r < e; r++) { + long immediate = (val >>> r | val << (e - r)) & mask; + // Duplicate pattern to fill whole 64bit range. + switch (logE) { + case 1: + immediate |= immediate << 2; + immediate |= immediate << 4; + immediate |= immediate << 8; + immediate |= immediate << 16; + immediate |= immediate << 32; + break; + case 2: + immediate |= immediate << 4; + immediate |= immediate << 8; + immediate |= immediate << 16; + immediate |= immediate << 32; + break; + case 3: + immediate |= immediate << 8; + immediate |= immediate << 16; + immediate |= immediate << 32; + break; + case 4: + immediate |= immediate << 16; + immediate |= immediate << 32; + break; + case 5: + immediate |= immediate << 32; + break; + } + // 5 - logE can underflow to -1, but we shift this bogus result + // out of the masked area. + int sizeEncoding = (1 << (5 - logE)) - 1; + int s = ((sizeEncoding << (logE + 1)) & 0x3f) | (nrOnes - 1); + table[nrImms++] = new Immediate(immediate, /* is64bit */e == 64, s, r); + } + } + } + Arrays.sort(table); + assert nrImms == nrImmediates : nrImms + " instead of " + nrImmediates + " in table."; + assert checkDuplicates(table) : "Duplicate values in table."; + return table; + } + + private static boolean checkDuplicates(Immediate[] table) { + for (int i = 0; i < table.length - 1; i++) { + if (table[i].imm >= table[i + 1].imm) { + return false; + } + } + return true; + } + } + + private static final int RdOffset = 0; + private static final int Rs1Offset = 5; + private static final int Rs2Offset = 16; + private static final int Rs3Offset = 10; + private static final int RtOffset = 0; + private static final int RnOffset = 5; + private static final int Rt2Offset = 10; + + /* Helper functions */ + private static int rd(Register reg) { + return reg.encoding << RdOffset; + } + + private static int rs1(Register reg) { + return reg.encoding << Rs1Offset; + } + + private static int rs2(Register reg) { + return reg.encoding << Rs2Offset; + } + + private static int rs3(Register reg) { + return reg.encoding << Rs3Offset; + } + + private static int rt(Register reg) { + return reg.encoding << RtOffset; + } + + private static int rt2(Register reg) { + return reg.encoding << Rt2Offset; + } + + private static int rn(Register reg) { + return reg.encoding << RnOffset; + } + + /** + * Enumeration of all different instruction kinds: General32/64 are the general instructions + * (integer, branch, etc.), for 32-, respectively 64-bit operands. FP32/64 is the encoding for + * the 32/64bit float operations + */ + protected enum InstructionType { + General32(0b00 << 30, 32, true), + General64(0b10 << 30, 64, true), + FP32(0x00000000, 32, false), + FP64(0x00400000, 64, false); + + public final int encoding; + public final int width; + public final boolean isGeneral; + + InstructionType(int encoding, int width, boolean isGeneral) { + this.encoding = encoding; + this.width = width; + this.isGeneral = isGeneral; + } + + public static InstructionType generalFromSize(int size) { + assert size == 32 || size == 64; + return size == 32 ? General32 : General64; + } + + public static InstructionType floatFromSize(int size) { + assert size == 32 || size == 64; + return size == 32 ? FP32 : FP64; + } + + } + + private static final int ImmediateOffset = 10; + private static final int ImmediateRotateOffset = 16; + private static final int ImmediateSizeOffset = 22; + private static final int ExtendTypeOffset = 13; + + private static final int AddSubImmOp = 0x11000000; + private static final int AddSubShift12 = 0b01 << 22; + private static final int AddSubSetFlag = 0x20000000; + + private static final int LogicalImmOp = 0x12000000; + + private static final int MoveWideImmOp = 0x12800000; + private static final int MoveWideImmOffset = 5; + private static final int MoveWideShiftOffset = 21; + + private static final int BitfieldImmOp = 0x13000000; + + private static final int AddSubShiftedOp = 0x0B000000; + private static final int ShiftTypeOffset = 22; + + private static final int AddSubExtendedOp = 0x0B200000; + + private static final int MulOp = 0x1B000000; + private static final int DataProcessing1SourceOp = 0x5AC00000; + private static final int DataProcessing2SourceOp = 0x1AC00000; + + private static final int Fp1SourceOp = 0x1E204000; + private static final int Fp2SourceOp = 0x1E200800; + private static final int Fp3SourceOp = 0x1F000000; + + private static final int FpConvertOp = 0x1E200000; + private static final int FpImmOp = 0x1E201000; + private static final int FpImmOffset = 13; + + private static final int FpCmpOp = 0x1E202000; + + private static final int PcRelImmHiOffset = 5; + private static final int PcRelImmLoOffset = 29; + + private static final int PcRelImmOp = 0x10000000; + + private static final int UnconditionalBranchImmOp = 0x14000000; + private static final int UnconditionalBranchRegOp = 0xD6000000; + private static final int CompareBranchOp = 0x34000000; + + private static final int ConditionalBranchImmOffset = 5; + + private static final int ConditionalSelectOp = 0x1A800000; + private static final int ConditionalConditionOffset = 12; + + private static final int LoadStoreScaledOp = 0b111_0_01_00 << 22; + private static final int LoadStoreUnscaledOp = 0b111_0_00_00 << 22; + + private static final int LoadStoreRegisterOp = 0b111_0_00_00_1 << 21 | 0b10 << 10; + + private static final int LoadLiteralOp = 0x18000000; + + private static final int LoadStorePostIndexedOp = 0b111_0_00_00_0 << 21 | 0b01 << 10; + private static final int LoadStorePreIndexedOp = 0b111_0_00_00_0 << 21 | 0b11 << 10; + + private static final int LoadStoreUnscaledImmOffset = 12; + private static final int LoadStoreScaledImmOffset = 10; + private static final int LoadStoreScaledRegOffset = 12; + private static final int LoadStoreIndexedImmOffset = 12; + private static final int LoadStoreTransferSizeOffset = 30; + private static final int LoadStoreFpFlagOffset = 26; + private static final int LoadLiteralImmeOffset = 5; + + private static final int LoadStorePairOp = 0b101_0_010 << 23; + @SuppressWarnings("unused") private static final int LoadStorePairPostIndexOp = 0b101_0_001 << 23; + @SuppressWarnings("unused") private static final int LoadStorePairPreIndexOp = 0b101_0_011 << 23; + private static final int LoadStorePairImm7Offset = 15; + + private static final int LogicalShiftOp = 0x0A000000; + + private static final int ExceptionOp = 0xD4000000; + private static final int SystemImmediateOffset = 5; + + @SuppressWarnings("unused") private static final int SimdImmediateOffset = 16; + + private static final int BarrierOp = 0xD503301F; + private static final int BarrierKindOffset = 8; + + /** + * Encoding for all instructions. + */ + public enum Instruction { + BCOND(0x54000000), + CBNZ(0x01000000), + CBZ(0x00000000), + + B(0x00000000), + BL(0x80000000), + BR(0x001F0000), + BLR(0x003F0000), + RET(0x005F0000), + + LDR(0x00000000), + LDRS(0x00800000), + LDXR(0x081f7c00), + LDAR(0x8dffc00), + LDAXR(0x85ffc00), + + STR(0x00000000), + STXR(0x08007c00), + STLR(0x089ffc00), + STLXR(0x0800fc00), + + LDP(0b1 << 22), + STP(0b0 << 22), + + ADR(0x00000000), + ADRP(0x80000000), + + ADD(0x00000000), + ADDS(ADD.encoding | AddSubSetFlag), + SUB(0x40000000), + SUBS(SUB.encoding | AddSubSetFlag), + + NOT(0x00200000), + AND(0x00000000), + BIC(AND.encoding | NOT.encoding), + ORR(0x20000000), + ORN(ORR.encoding | NOT.encoding), + EOR(0x40000000), + EON(EOR.encoding | NOT.encoding), + ANDS(0x60000000), + BICS(ANDS.encoding | NOT.encoding), + + ASRV(0x00002800), + RORV(0x00002C00), + LSRV(0x00002400), + LSLV(0x00002000), + + CLS(0x00001400), + CLZ(0x00001000), + RBIT(0x00000000), + REVX(0x00000C00), + REVW(0x00000800), + + MOVN(0x00000000), + MOVZ(0x40000000), + MOVK(0x60000000), + + CSEL(0x00000000), + CSNEG(0x40000400), + CSINC(0x00000400), + + BFM(0x20000000), + SBFM(0x00000000), + UBFM(0x40000000), + EXTR(0x13800000), + + MADD(0x00000000), + MSUB(0x00008000), + SDIV(0x00000C00), + UDIV(0x00000800), + + FMOV(0x00000000), + FMOVCPU2FPU(0x00070000), + FMOVFPU2CPU(0x00060000), + + FCVTDS(0x00028000), + FCVTSD(0x00020000), + + FCVTZS(0x00180000), + SCVTF(0x00020000), + + FABS(0x00008000), + FSQRT(0x00018000), + FNEG(0x00010000), + + FRINTZ(0x00058000), + + FADD(0x00002000), + FSUB(0x00003000), + FMUL(0x00000000), + FDIV(0x00001000), + FMAX(0x00004000), + FMIN(0x00005000), + + FMADD(0x00000000), + FMSUB(0x00008000), + + FCMP(0x00000000), + FCMPZERO(0x00000008), + FCCMP(0x1E200400), + FCSEL(0x1E200C00), + + INS(0x4e081c00), + UMOV(0x4e083c00), + + CNT(0xe205800), + USRA(0x6f001400), + + HLT(0x00400000), + BRK(0x00200000), + + CLREX(0xd5033f5f), + HINT(0xD503201F), + DMB(0x000000A0), + + BLR_NATIVE(0xc0000000); + + public final int encoding; + + Instruction(int encoding) { + this.encoding = encoding; + } + + } + + public enum ShiftType { + LSL(0), + LSR(1), + ASR(2), + ROR(3); + + public final int encoding; + + ShiftType(int encoding) { + this.encoding = encoding; + } + } + + public enum ExtendType { + UXTB(0), + UXTH(1), + UXTW(2), + UXTX(3), + SXTB(4), + SXTH(5), + SXTW(6), + SXTX(7); + + public final int encoding; + + ExtendType(int encoding) { + this.encoding = encoding; + } + } + + /** + * Condition Flags for branches. See 4.3 + */ + public enum ConditionFlag { + // Integer | Floating-point meanings + /** Equal | Equal. */ + EQ(0x0), + + /** Not Equal | Not equal or unordered. */ + NE(0x1), + + /** Unsigned Higher or Same | Greater than, equal or unordered. */ + HS(0x2), + + /** Unsigned lower | less than. */ + LO(0x3), + + /** Minus (negative) | less than. */ + MI(0x4), + + /** Plus (positive or zero) | greater than, equal or unordered. */ + PL(0x5), + + /** Overflow set | unordered. */ + VS(0x6), + + /** Overflow clear | ordered. */ + VC(0x7), + + /** Unsigned higher | greater than or unordered. */ + HI(0x8), + + /** Unsigned lower or same | less than or equal. */ + LS(0x9), + + /** Signed greater than or equal | greater than or equal. */ + GE(0xA), + + /** Signed less than | less than or unordered. */ + LT(0xB), + + /** Signed greater than | greater than. */ + GT(0xC), + + /** Signed less than or equal | less than, equal or unordered. */ + LE(0xD), + + /** Always | always. */ + AL(0xE), + + /** Always | always (identical to AL, just to have valid 0b1111 encoding). */ + NV(0xF); + + public final int encoding; + + ConditionFlag(int encoding) { + this.encoding = encoding; + } + + /** + * @return ConditionFlag specified by decoding. + */ + public static ConditionFlag fromEncoding(int encoding) { + return values()[encoding]; + } + + public ConditionFlag negate() { + switch (this) { + case EQ: + return NE; + case NE: + return EQ; + case HS: + return LO; + case LO: + return HS; + case MI: + return PL; + case PL: + return MI; + case VS: + return VC; + case VC: + return VS; + case HI: + return LS; + case LS: + return HI; + case GE: + return LT; + case LT: + return GE; + case GT: + return LE; + case LE: + return GT; + case AL: + case NV: + default: + throw GraalError.shouldNotReachHere(); + } + } + } + + public AArch64Assembler(TargetDescription target) { + super(target); + } + + /* Conditional Branch (5.2.1) */ + + /** + * Branch conditionally. + * + * @param condition may not be null. + * @param imm21 Signed 21-bit offset, has to be word aligned. + */ + protected void b(ConditionFlag condition, int imm21) { + b(condition, imm21, -1); + } + + /** + * Branch conditionally. Inserts instruction into code buffer at pos. + * + * @param condition may not be null. + * @param imm21 Signed 21-bit offset, has to be word aligned. + * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. + */ + protected void b(ConditionFlag condition, int imm21, int pos) { + if (pos == -1) { + emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding); + } else { + emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding, pos); + } + } + + /** + * Compare register and branch if non-zero. + * + * @param reg general purpose register. May not be null, zero-register or stackpointer. + * @param size Instruction size in bits. Should be either 32 or 64. + * @param imm21 Signed 21-bit offset, has to be word aligned. + */ + protected void cbnz(int size, Register reg, int imm21) { + conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, -1); + } + + /** + * Compare register and branch if non-zero. + * + * @param reg general purpose register. May not be null, zero-register or stackpointer. + * @param size Instruction size in bits. Should be either 32 or 64. + * @param imm21 Signed 21-bit offset, has to be word aligned. + * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. + */ + protected void cbnz(int size, Register reg, int imm21, int pos) { + conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, pos); + } + + /** + * Compare and branch if zero. + * + * @param reg general purpose register. May not be null, zero-register or stackpointer. + * @param size Instruction size in bits. Should be either 32 or 64. + * @param imm21 Signed 21-bit offset, has to be word aligned. + */ + protected void cbz(int size, Register reg, int imm21) { + conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, -1); + } + + /** + * Compare register and branch if zero. + * + * @param reg general purpose register. May not be null, zero-register or stackpointer. + * @param size Instruction size in bits. Should be either 32 or 64. + * @param imm21 Signed 21-bit offset, has to be word aligned. + * @param pos Position at which instruction is inserted into buffer. -1 means insert at end. + */ + protected void cbz(int size, Register reg, int imm21, int pos) { + conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, pos); + } + + private void conditionalBranchInstruction(Register reg, int imm21, InstructionType type, Instruction instr, int pos) { + assert reg.getRegisterCategory().equals(CPU); + int instrEncoding = instr.encoding | CompareBranchOp; + if (pos == -1) { + emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg)); + } else { + emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg), pos); + } + } + + private static int getConditionalBranchImm(int imm21) { + assert NumUtil.isSignedNbit(21, imm21) && (imm21 & 0x3) == 0 : "Immediate has to be 21bit signed number and word aligned"; + int imm = (imm21 & NumUtil.getNbitNumberInt(21)) >> 2; + return imm << ConditionalBranchImmOffset; + } + + /* Unconditional Branch (immediate) (5.2.2) */ + + /** + * @param imm28 Signed 28-bit offset, has to be word aligned. + */ + protected void b(int imm28) { + unconditionalBranchImmInstruction(imm28, Instruction.B, -1); + } + + /** + * + * @param imm28 Signed 28-bit offset, has to be word aligned. + * @param pos Position where instruction is inserted into code buffer. + */ + protected void b(int imm28, int pos) { + unconditionalBranchImmInstruction(imm28, Instruction.B, pos); + } + + /** + * Branch and link return address to register X30. + * + * @param imm28 Signed 28-bit offset, has to be word aligned. + */ + public void bl(int imm28) { + unconditionalBranchImmInstruction(imm28, Instruction.BL, -1); + } + + private void unconditionalBranchImmInstruction(int imm28, Instruction instr, int pos) { + assert NumUtil.isSignedNbit(28, imm28) && (imm28 & 0x3) == 0 : "Immediate has to be 28bit signed number and word aligned"; + int imm = (imm28 & NumUtil.getNbitNumberInt(28)) >> 2; + int instrEncoding = instr.encoding | UnconditionalBranchImmOp; + if (pos == -1) { + emitInt(instrEncoding | imm); + } else { + emitInt(instrEncoding | imm, pos); + } + } + + /* Unconditional Branch (register) (5.2.3) */ + + /** + * Branches to address in register and writes return address into register X30. + * + * @param reg general purpose register. May not be null, zero-register or stackpointer. + */ + public void blr(Register reg) { + unconditionalBranchRegInstruction(BLR, reg); + } + + /** + * Branches to address in register. + * + * @param reg general purpose register. May not be null, zero-register or stackpointer. + */ + protected void br(Register reg) { + unconditionalBranchRegInstruction(BR, reg); + } + + /** + * Return to address in register. + * + * @param reg general purpose register. May not be null, zero-register or stackpointer. + */ + public void ret(Register reg) { + unconditionalBranchRegInstruction(RET, reg); + } + + private void unconditionalBranchRegInstruction(Instruction instr, Register reg) { + assert reg.getRegisterCategory().equals(CPU); + assert !reg.equals(zr); + assert !reg.equals(sp); + emitInt(instr.encoding | UnconditionalBranchRegOp | rs1(reg)); + } + + /* Load-Store Single Register (5.3.1) */ + + /** + * Loads a srcSize value from address into rt zero-extending it. + * + * @param srcSize size of memory read in bits. Must be 8, 16, 32 or 64. + * @param rt general purpose register. May not be null or stackpointer. + * @param address all addressing modes allowed. May not be null. + */ + public void ldr(int srcSize, Register rt, AArch64Address address) { + assert rt.getRegisterCategory().equals(CPU); + assert srcSize == 8 || srcSize == 16 || srcSize == 32 || srcSize == 64; + int transferSize = NumUtil.log2Ceil(srcSize / 8); + loadStoreInstruction(LDR, rt, address, General32, transferSize); + } + + /** + * Loads a srcSize value from address into rt sign-extending it. + * + * @param targetSize size of target register in bits. Must be 32 or 64. + * @param srcSize size of memory read in bits. Must be 8, 16 or 32, but may not be equivalent to + * targetSize. + * @param rt general purpose register. May not be null or stackpointer. + * @param address all addressing modes allowed. May not be null. + */ + protected void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) { + assert rt.getRegisterCategory().equals(CPU); + assert (srcSize == 8 || srcSize == 16 || srcSize == 32) && srcSize != targetSize; + int transferSize = NumUtil.log2Ceil(srcSize / 8); + loadStoreInstruction(LDRS, rt, address, generalFromSize(targetSize), transferSize); + } + + /** + * Stores register rt into memory pointed by address. + * + * @param destSize number of bits written to memory. Must be 8, 16, 32 or 64. + * @param rt general purpose register. May not be null or stackpointer. + * @param address all addressing modes allowed. May not be null. + */ + public void str(int destSize, Register rt, AArch64Address address) { + assert rt.getRegisterCategory().equals(CPU); + assert destSize == 8 || destSize == 16 || destSize == 32 || destSize == 64; + int transferSize = NumUtil.log2Ceil(destSize / 8); + loadStoreInstruction(STR, rt, address, General64, transferSize); + } + + private void loadStoreInstruction(Instruction instr, Register reg, AArch64Address address, InstructionType type, int log2TransferSize) { + assert log2TransferSize >= 0 && log2TransferSize < 4; + int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; + int is32Bit = type.width == 32 ? 1 << ImmediateSizeOffset : 0; + int isFloat = !type.isGeneral ? 1 << LoadStoreFpFlagOffset : 0; + int memop = instr.encoding | transferSizeEncoding | is32Bit | isFloat | rt(reg); + switch (address.getAddressingMode()) { + case IMMEDIATE_SCALED: + emitInt(memop | LoadStoreScaledOp | address.getImmediate() << LoadStoreScaledImmOffset | rs1(address.getBase())); + break; + case IMMEDIATE_UNSCALED: + emitInt(memop | LoadStoreUnscaledOp | address.getImmediate() << LoadStoreUnscaledImmOffset | rs1(address.getBase())); + break; + case BASE_REGISTER_ONLY: + emitInt(memop | LoadStoreScaledOp | rs1(address.getBase())); + break; + case EXTENDED_REGISTER_OFFSET: + case REGISTER_OFFSET: + ExtendType extendType = address.getAddressingMode() == AddressingMode.EXTENDED_REGISTER_OFFSET ? address.getExtendType() : ExtendType.UXTX; + boolean shouldScale = address.isScaled() && log2TransferSize != 0; + emitInt(memop | LoadStoreRegisterOp | rs2(address.getOffset()) | extendType.encoding << ExtendTypeOffset | (shouldScale ? 1 : 0) << LoadStoreScaledRegOffset | rs1(address.getBase())); + break; + case PC_LITERAL: + assert log2TransferSize >= 2 : "PC literal loads only works for load/stores of 32-bit and larger"; + transferSizeEncoding = (log2TransferSize - 2) << LoadStoreTransferSizeOffset; + emitInt(transferSizeEncoding | isFloat | LoadLiteralOp | rd(reg) | address.getImmediate() << LoadLiteralImmeOffset); + break; + case IMMEDIATE_POST_INDEXED: + emitInt(memop | LoadStorePostIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset); + break; + case IMMEDIATE_PRE_INDEXED: + emitInt(memop | LoadStorePreIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset); + break; + default: + throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode()); + } + } + + /** + * + */ + public void ldp(int size, Register rt, Register rt2, AArch64Address address) { + assert size == 32 || size == 64; + loadStorePairInstruction(LDP, rt, rt2, address, generalFromSize(size)); + } + + /** + * Store Pair of Registers calculates an address from a base register value and an immediate + * offset, and stores two 32-bit words or two 64-bit doublewords to the calculated address, from + * two registers. + */ + public void stp(int size, Register rt, Register rt2, AArch64Address address) { + assert size == 32 || size == 64; + loadStorePairInstruction(STP, rt, rt2, address, generalFromSize(size)); + } + + private void loadStorePairInstruction(Instruction instr, Register rt, Register rt2, AArch64Address address, InstructionType type) { + int memop = type.encoding | instr.encoding | address.getImmediate() << LoadStorePairImm7Offset | rt2(rt2) | rn(address.getBase()) | rt(rt); + switch (address.getAddressingMode()) { + case IMMEDIATE_UNSCALED: + emitInt(memop | LoadStorePairOp); + break; + default: + throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode()); + } + } + + /* Load-Store Exclusive (5.3.6) */ + + /** + * Load address exclusive. Natural alignment of address is required. + * + * @param size size of memory read in bits. Must be 8, 16, 32 or 64. + * @param rt general purpose register. May not be null or stackpointer. + * @param rn general purpose register. + */ + protected void ldxr(int size, Register rt, Register rn) { + assert size == 8 || size == 16 || size == 32 || size == 64; + int transferSize = NumUtil.log2Ceil(size / 8); + exclusiveLoadInstruction(LDXR, rt, rn, transferSize); + } + + /** + * Store address exclusive. Natural alignment of address is required. rs and rt may not point to + * the same register. + * + * @param size size of bits written to memory. Must be 8, 16, 32 or 64. + * @param rs general purpose register. Set to exclusive access status. 0 means success, + * everything else failure. May not be null, or stackpointer. + * @param rt general purpose register. May not be null or stackpointer. + * @param rn general purpose register. + */ + protected void stxr(int size, Register rs, Register rt, Register rn) { + assert size == 8 || size == 16 || size == 32 || size == 64; + int transferSize = NumUtil.log2Ceil(size / 8); + exclusiveStoreInstruction(STXR, rs, rt, rn, transferSize); + } + + /* Load-Acquire/Store-Release (5.3.7) */ + + /* non exclusive access */ + /** + * Load acquire. Natural alignment of address is required. + * + * @param size size of memory read in bits. Must be 8, 16, 32 or 64. + * @param rt general purpose register. May not be null or stackpointer. + * @param rn general purpose register. + */ + protected void ldar(int size, Register rt, Register rn) { + assert size == 8 || size == 16 || size == 32 || size == 64; + int transferSize = NumUtil.log2Ceil(size / 8); + exclusiveLoadInstruction(LDAR, rt, rn, transferSize); + } + + /** + * Store-release. Natural alignment of address is required. + * + * @param size size of bits written to memory. Must be 8, 16, 32 or 64. + * @param rt general purpose register. May not be null or stackpointer. + * @param rn general purpose register. + */ + protected void stlr(int size, Register rt, Register rn) { + assert size == 8 || size == 16 || size == 32 || size == 64; + int transferSize = NumUtil.log2Ceil(size / 8); + // Hack: Passing the zero-register means it is ignored when building the encoding. + exclusiveStoreInstruction(STLR, r0, rt, rn, transferSize); + } + + /* exclusive access */ + /** + * Load acquire exclusive. Natural alignment of address is required. + * + * @param size size of memory read in bits. Must be 8, 16, 32 or 64. + * @param rt general purpose register. May not be null or stackpointer. + * @param rn general purpose register. + */ + public void ldaxr(int size, Register rt, Register rn) { + assert size == 8 || size == 16 || size == 32 || size == 64; + int transferSize = NumUtil.log2Ceil(size / 8); + exclusiveLoadInstruction(LDAXR, rt, rn, transferSize); + } + + /** + * Store-release exclusive. Natural alignment of address is required. rs and rt may not point to + * the same register. + * + * @param size size of bits written to memory. Must be 8, 16, 32 or 64. + * @param rs general purpose register. Set to exclusive access status. 0 means success, + * everything else failure. May not be null, or stackpointer. + * @param rt general purpose register. May not be null or stackpointer. + * @param rn general purpose register. + */ + public void stlxr(int size, Register rs, Register rt, Register rn) { + assert size == 8 || size == 16 || size == 32 || size == 64; + int transferSize = NumUtil.log2Ceil(size / 8); + exclusiveStoreInstruction(STLXR, rs, rt, rn, transferSize); + } + + private void exclusiveLoadInstruction(Instruction instr, Register reg, Register rn, int log2TransferSize) { + assert log2TransferSize >= 0 && log2TransferSize < 4; + assert reg.getRegisterCategory().equals(CPU); + int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; + emitInt(transferSizeEncoding | instr.encoding | 1 << ImmediateSizeOffset | rn(rn) | rt(reg)); + } + + /** + * Stores data from rt into address and sets rs to the returned exclusive access status. + * + * @param rs general purpose register into which the exclusive access status is written. May not + * be null. + * @param rt general purpose register containing data to be written to memory at address. May + * not be null + * @param rn general purpose register containing the address specifying where rt is written to. + * @param log2TransferSize log2Ceil of memory transfer size. + */ + private void exclusiveStoreInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize) { + assert log2TransferSize >= 0 && log2TransferSize < 4; + assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt); + int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; + emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt)); + } + + /* PC-relative Address Calculation (5.4.4) */ + + /** + * Address of page: sign extends 21-bit offset, shifts if left by 12 and adds it to the value of + * the PC with its bottom 12-bits cleared, writing the result to dst. + * + * @param dst general purpose register. May not be null, zero-register or stackpointer. + * @param imm Signed 33-bit offset with lower 12bits clear. + */ + // protected void adrp(Register dst, long imm) { + // assert (imm & NumUtil.getNbitNumberInt(12)) == 0 : "Lower 12-bit of immediate must be zero."; + // assert NumUtil.isSignedNbit(33, imm); + // addressCalculationInstruction(dst, (int) (imm >>> 12), Instruction.ADRP); + // } + + /** + * Adds a 21-bit signed offset to the program counter and writes the result to dst. + * + * @param dst general purpose register. May not be null, zero-register or stackpointer. + * @param imm21 Signed 21-bit offset. + */ + public void adr(Register dst, int imm21) { + emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21)); + } + + public void adr(Register dst, int imm21, int pos) { + emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21), pos); + } + + private static int getPcRelativeImmEncoding(int imm21) { + assert NumUtil.isSignedNbit(21, imm21); + int imm = imm21 & NumUtil.getNbitNumberInt(21); + // higher 19 bit + int immHi = (imm >> 2) << PcRelImmHiOffset; + // lower 2 bit + int immLo = (imm & 0x3) << PcRelImmLoOffset; + return immHi | immLo; + } + + /* Arithmetic (Immediate) (5.4.1) */ + + /** + * dst = src + aimm. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or zero-register. + * @param src general purpose register. May not be null or zero-register. + * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with + * the lower 12-bit cleared. + */ + protected void add(int size, Register dst, Register src, int aimm) { + assert !dst.equals(zr); + assert !src.equals(zr); + addSubImmInstruction(ADD, dst, src, aimm, generalFromSize(size)); + } + + /** + * dst = src + aimm and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or zero-register. + * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with + * the lower 12-bit cleared. + */ + protected void adds(int size, Register dst, Register src, int aimm) { + assert !dst.equals(sp); + assert !src.equals(zr); + addSubImmInstruction(ADDS, dst, src, aimm, generalFromSize(size)); + } + + /** + * dst = src - aimm. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or zero-register. + * @param src general purpose register. May not be null or zero-register. + * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with + * the lower 12-bit cleared. + */ + protected void sub(int size, Register dst, Register src, int aimm) { + assert !dst.equals(zr); + assert !src.equals(zr); + addSubImmInstruction(SUB, dst, src, aimm, generalFromSize(size)); + } + + /** + * dst = src - aimm and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or zero-register. + * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with + * the lower 12-bit cleared. + */ + protected void subs(int size, Register dst, Register src, int aimm) { + assert !dst.equals(sp); + assert !src.equals(zr); + addSubImmInstruction(SUBS, dst, src, aimm, generalFromSize(size)); + } + + private void addSubImmInstruction(Instruction instr, Register dst, Register src, int aimm, InstructionType type) { + emitInt(type.encoding | instr.encoding | AddSubImmOp | encodeAimm(aimm) | rd(dst) | rs1(src)); + } + + /** + * Encodes arithmetic immediate. + * + * @param imm Immediate has to be either an unsigned 12-bit value or an unsigned 24-bit value + * with the lower 12 bits zero. + * @return Representation of immediate for use with arithmetic instructions. + */ + private static int encodeAimm(int imm) { + assert isAimm(imm) : "Immediate has to be legal arithmetic immediate value " + imm; + if (NumUtil.isUnsignedNbit(12, imm)) { + return imm << ImmediateOffset; + } else { + // First 12-bit are zero, so shift immediate 12-bit and set flag to indicate + // shifted immediate value. + return (imm >>> 12 << ImmediateOffset) | AddSubShift12; + } + } + + /** + * Checks whether immediate can be encoded as an arithmetic immediate. + * + * @param imm Immediate has to be either an unsigned 12bit value or un unsigned 24bit value with + * the lower 12 bits 0. + * @return true if valid arithmetic immediate, false otherwise. + */ + protected static boolean isAimm(int imm) { + return NumUtil.isUnsignedNbit(12, imm) || NumUtil.isUnsignedNbit(12, imm >>> 12) && (imm & 0xfff) == 0; + } + + /* Logical (immediate) (5.4.2) */ + + /** + * dst = src & bimm. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or zero-register. + * @param src general purpose register. May not be null or stack-pointer. + * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. + */ + public void and(int size, Register dst, Register src, long bimm) { + assert !dst.equals(zr); + assert !src.equals(sp); + logicalImmInstruction(AND, dst, src, bimm, generalFromSize(size)); + } + + /** + * dst = src & bimm and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stack-pointer. + * @param src general purpose register. May not be null or stack-pointer. + * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. + */ + public void ands(int size, Register dst, Register src, long bimm) { + assert !dst.equals(sp); + assert !src.equals(sp); + logicalImmInstruction(ANDS, dst, src, bimm, generalFromSize(size)); + } + + /** + * dst = src ^ bimm. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or zero-register. + * @param src general purpose register. May not be null or stack-pointer. + * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. + */ + public void eor(int size, Register dst, Register src, long bimm) { + assert !dst.equals(zr); + assert !src.equals(sp); + logicalImmInstruction(EOR, dst, src, bimm, generalFromSize(size)); + } + + /** + * dst = src | bimm. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or zero-register. + * @param src general purpose register. May not be null or stack-pointer. + * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition. + */ + protected void orr(int size, Register dst, Register src, long bimm) { + assert !dst.equals(zr); + assert !src.equals(sp); + logicalImmInstruction(ORR, dst, src, bimm, generalFromSize(size)); + } + + private void logicalImmInstruction(Instruction instr, Register dst, Register src, long bimm, InstructionType type) { + // Mask higher bits off, since we always pass longs around even for the 32-bit instruction. + long bimmValue; + if (type == General32) { + assert (bimm >> 32) == 0 || (bimm >> 32) == -1L : "Higher order bits for 32-bit instruction must either all be 0 or 1."; + bimmValue = bimm & NumUtil.getNbitNumberLong(32); + } else { + bimmValue = bimm; + } + int immEncoding = LogicalImmediateTable.getLogicalImmEncoding(type == General64, bimmValue); + emitInt(type.encoding | instr.encoding | LogicalImmOp | immEncoding | rd(dst) | rs1(src)); + } + + /* Move (wide immediate) (5.4.3) */ + + /** + * dst = uimm16 << shiftAmt. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param uimm16 16-bit unsigned immediate + * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller + * than size. + */ + protected void movz(int size, Register dst, int uimm16, int shiftAmt) { + moveWideImmInstruction(MOVZ, dst, uimm16, shiftAmt, generalFromSize(size)); + } + + /** + * dst = ~(uimm16 << shiftAmt). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param uimm16 16-bit unsigned immediate + * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller + * than size. + */ + protected void movn(int size, Register dst, int uimm16, int shiftAmt) { + moveWideImmInstruction(MOVN, dst, uimm16, shiftAmt, generalFromSize(size)); + } + + /** + * dst = uimm16. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param uimm16 16-bit unsigned immediate + * @param pos position into which uimm16 is inserted. Can be any multiple of 16 smaller than + * size. + */ + protected void movk(int size, Register dst, int uimm16, int pos) { + moveWideImmInstruction(MOVK, dst, uimm16, pos, generalFromSize(size)); + } + + private void moveWideImmInstruction(Instruction instr, Register dst, int uimm16, int shiftAmt, InstructionType type) { + assert dst.getRegisterCategory().equals(CPU); + assert NumUtil.isUnsignedNbit(16, uimm16) : "Immediate has to be unsigned 16bit"; + assert shiftAmt == 0 || shiftAmt == 16 || (type == InstructionType.General64 && (shiftAmt == 32 || shiftAmt == 48)) : "Invalid shift amount: " + shiftAmt; + int shiftValue = shiftAmt >> 4; + emitInt(type.encoding | instr.encoding | MoveWideImmOp | rd(dst) | uimm16 << MoveWideImmOffset | shiftValue << MoveWideShiftOffset); + } + + /* Bitfield Operations (5.4.5) */ + + /** + * Bitfield move. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param src general purpose register. May not be null, stackpointer or zero-register. + * @param r must be in the range 0 to size - 1 + * @param s must be in the range 0 to size - 1 + */ + protected void bfm(int size, Register dst, Register src, int r, int s) { + bitfieldInstruction(BFM, dst, src, r, s, generalFromSize(size)); + } + + /** + * Unsigned bitfield move. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param src general purpose register. May not be null, stackpointer or zero-register. + * @param r must be in the range 0 to size - 1 + * @param s must be in the range 0 to size - 1 + */ + protected void ubfm(int size, Register dst, Register src, int r, int s) { + bitfieldInstruction(UBFM, dst, src, r, s, generalFromSize(size)); + } + + /** + * Signed bitfield move. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param src general purpose register. May not be null, stackpointer or zero-register. + * @param r must be in the range 0 to size - 1 + * @param s must be in the range 0 to size - 1 + */ + protected void sbfm(int size, Register dst, Register src, int r, int s) { + bitfieldInstruction(SBFM, dst, src, r, s, generalFromSize(size)); + } + + private void bitfieldInstruction(Instruction instr, Register dst, Register src, int r, int s, InstructionType type) { + assert !dst.equals(sp) && !dst.equals(zr); + assert !src.equals(sp) && !src.equals(zr); + assert s >= 0 && s < type.width && r >= 0 && r < type.width; + int sf = type == General64 ? 1 << ImmediateSizeOffset : 0; + emitInt(type.encoding | instr.encoding | BitfieldImmOp | sf | r << ImmediateRotateOffset | s << ImmediateOffset | rd(dst) | rs1(src)); + } + + /* Extract (Immediate) (5.4.6) */ + + /** + * Extract. dst = src1:src2 + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param lsb must be in range 0 to size - 1. + */ + protected void extr(int size, Register dst, Register src1, Register src2, int lsb) { + assert !dst.equals(sp); + assert !src1.equals(sp); + assert !src2.equals(sp); + InstructionType type = generalFromSize(size); + assert lsb >= 0 && lsb < type.width; + int sf = type == General64 ? 1 << ImmediateSizeOffset : 0; + emitInt(type.encoding | EXTR.encoding | sf | lsb << ImmediateOffset | rd(dst) | rs1(src1) | rs2(src2)); + } + + /* Arithmetic (shifted register) (5.5.1) */ + + /** + * dst = src1 + shiftType(src2, imm). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType any type but ROR. + * @param imm must be in range 0 to size - 1. + */ + protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { + addSubShiftedInstruction(ADD, dst, src1, src2, shiftType, imm, generalFromSize(size)); + } + + /** + * dst = src1 + shiftType(src2, imm) and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType any type but ROR. + * @param imm must be in range 0 to size - 1. + */ + protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { + addSubShiftedInstruction(ADDS, dst, src1, src2, shiftType, imm, generalFromSize(size)); + } + + /** + * dst = src1 - shiftType(src2, imm). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType any type but ROR. + * @param imm must be in range 0 to size - 1. + */ + protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { + addSubShiftedInstruction(SUB, dst, src1, src2, shiftType, imm, generalFromSize(size)); + } + + /** + * dst = src1 - shiftType(src2, imm) and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType any type but ROR. + * @param imm must be in range 0 to size - 1. + */ + protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) { + addSubShiftedInstruction(SUBS, dst, src1, src2, shiftType, imm, generalFromSize(size)); + } + + private void addSubShiftedInstruction(Instruction instr, Register dst, Register src1, Register src2, ShiftType shiftType, int imm, InstructionType type) { + assert shiftType != ShiftType.ROR; + assert imm >= 0 && imm < type.width; + emitInt(type.encoding | instr.encoding | AddSubShiftedOp | imm << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); + } + + /* Arithmetic (extended register) (5.5.2) */ + /** + * dst = src1 + extendType(src2) << imm. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or zero-register.. + * @param src1 general purpose register. May not be null or zero-register. + * @param src2 general purpose register. May not be null or stackpointer. + * @param extendType defines how src2 is extended to the same size as src1. + * @param shiftAmt must be in range 0 to 4. + */ + public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { + assert !dst.equals(zr); + assert !src1.equals(zr); + assert !src2.equals(sp); + addSubExtendedInstruction(ADD, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); + } + + /** + * dst = src1 + extendType(src2) << imm and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer.. + * @param src1 general purpose register. May not be null or zero-register. + * @param src2 general purpose register. May not be null or stackpointer. + * @param extendType defines how src2 is extended to the same size as src1. + * @param shiftAmt must be in range 0 to 4. + */ + protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { + assert !dst.equals(sp); + assert !src1.equals(zr); + assert !src2.equals(sp); + addSubExtendedInstruction(ADDS, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); + } + + /** + * dst = src1 - extendType(src2) << imm. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or zero-register.. + * @param src1 general purpose register. May not be null or zero-register. + * @param src2 general purpose register. May not be null or stackpointer. + * @param extendType defines how src2 is extended to the same size as src1. + * @param shiftAmt must be in range 0 to 4. + */ + protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { + assert !dst.equals(zr); + assert !src1.equals(zr); + assert !src2.equals(sp); + addSubExtendedInstruction(SUB, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); + } + + /** + * dst = src1 - extendType(src2) << imm and sets flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer.. + * @param src1 general purpose register. May not be null or zero-register. + * @param src2 general purpose register. May not be null or stackpointer. + * @param extendType defines how src2 is extended to the same size as src1. + * @param shiftAmt must be in range 0 to 4. + */ + protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) { + assert !dst.equals(sp); + assert !src1.equals(zr); + assert !src2.equals(sp); + addSubExtendedInstruction(SUBS, dst, src1, src2, extendType, shiftAmt, generalFromSize(size)); + } + + private void addSubExtendedInstruction(Instruction instr, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt, InstructionType type) { + assert shiftAmt >= 0 && shiftAmt <= 4; + emitInt(type.encoding | instr.encoding | AddSubExtendedOp | shiftAmt << ImmediateOffset | extendType.encoding << ExtendTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); + } + + /* Logical (shifted register) (5.5.3) */ + /** + * dst = src1 & shiftType(src2, imm). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType all types allowed, may not be null. + * @param shiftAmt must be in range 0 to size - 1. + */ + protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { + logicalRegInstruction(AND, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); + } + + /** + * dst = src1 & shiftType(src2, imm) and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType all types allowed, may not be null. + * @param shiftAmt must be in range 0 to size - 1. + */ + protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { + logicalRegInstruction(ANDS, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); + } + + /** + * dst = src1 & ~(shiftType(src2, imm)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType all types allowed, may not be null. + * @param shiftAmt must be in range 0 to size - 1. + */ + protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { + logicalRegInstruction(BIC, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); + } + + /** + * dst = src1 & ~(shiftType(src2, imm)) and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType all types allowed, may not be null. + * @param shiftAmt must be in range 0 to size - 1. + */ + protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { + logicalRegInstruction(BICS, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); + } + + /** + * dst = src1 ^ ~(shiftType(src2, imm)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType all types allowed, may not be null. + * @param shiftAmt must be in range 0 to size - 1. + */ + protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { + logicalRegInstruction(EON, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); + } + + /** + * dst = src1 ^ shiftType(src2, imm). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType all types allowed, may not be null. + * @param shiftAmt must be in range 0 to size - 1. + */ + protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { + logicalRegInstruction(EOR, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); + } + + /** + * dst = src1 | shiftType(src2, imm). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType all types allowed, may not be null. + * @param shiftAmt must be in range 0 to size - 1. + */ + protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { + logicalRegInstruction(ORR, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); + } + + /** + * dst = src1 | ~(shiftType(src2, imm)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType all types allowed, may not be null. + * @param shiftAmt must be in range 0 to size - 1. + */ + protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { + logicalRegInstruction(ORN, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size)); + } + + private void logicalRegInstruction(Instruction instr, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt, InstructionType type) { + assert !dst.equals(sp); + assert !src1.equals(sp); + assert !src2.equals(sp); + assert shiftAmt >= 0 && shiftAmt < type.width; + emitInt(type.encoding | instr.encoding | LogicalShiftOp | shiftAmt << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2)); + } + + /* Variable Shift (5.5.4) */ + /** + * dst = src1 >> (src2 & log2(size)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + */ + protected void asr(int size, Register dst, Register src1, Register src2) { + dataProcessing2SourceOp(ASRV, dst, src1, src2, generalFromSize(size)); + } + + /** + * dst = src1 << (src2 & log2(size)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + */ + protected void lsl(int size, Register dst, Register src1, Register src2) { + dataProcessing2SourceOp(LSLV, dst, src1, src2, generalFromSize(size)); + } + + /** + * dst = src1 >>> (src2 & log2(size)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + */ + protected void lsr(int size, Register dst, Register src1, Register src2) { + dataProcessing2SourceOp(LSRV, dst, src1, src2, generalFromSize(size)); + } + + /** + * dst = rotateRight(src1, (src2 & log2(size))). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + */ + protected void ror(int size, Register dst, Register src1, Register src2) { + dataProcessing2SourceOp(RORV, dst, src1, src2, generalFromSize(size)); + } + + /* Bit Operations (5.5.5) */ + + /** + * Counts leading sign bits. Sets Wd to the number of consecutive bits following the topmost bit + * in dst, that are the same as the topmost bit. The count does not include the topmost bit + * itself , so the result will be in the range 0 to size-1 inclusive. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, zero-register or the stackpointer. + * @param src source register. May not be null, zero-register or the stackpointer. + */ + protected void cls(int size, Register dst, Register src) { + dataProcessing1SourceOp(CLS, dst, src, generalFromSize(size)); + } + + /** + * Counts leading zeros. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, zero-register or the stackpointer. + * @param src source register. May not be null, zero-register or the stackpointer. + */ + public void clz(int size, Register dst, Register src) { + dataProcessing1SourceOp(CLZ, dst, src, generalFromSize(size)); + } + + /** + * Reverses bits. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, zero-register or the stackpointer. + * @param src source register. May not be null, zero-register or the stackpointer. + */ + protected void rbit(int size, Register dst, Register src) { + dataProcessing1SourceOp(RBIT, dst, src, generalFromSize(size)); + } + + /** + * Reverses bytes. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src source register. May not be null or the stackpointer. + */ + public void rev(int size, Register dst, Register src) { + if (size == 64) { + dataProcessing1SourceOp(REVX, dst, src, generalFromSize(size)); + } else { + assert size == 32; + dataProcessing1SourceOp(REVW, dst, src, generalFromSize(size)); + } + } + + /* Conditional Data Processing (5.5.6) */ + + /** + * Conditional select. dst = src1 if condition else src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + * @param condition any condition flag. May not be null. + */ + protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { + conditionalSelectInstruction(CSEL, dst, src1, src2, condition, generalFromSize(size)); + } + + /** + * Conditional select negate. dst = src1 if condition else -src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + * @param condition any condition flag. May not be null. + */ + protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { + conditionalSelectInstruction(CSNEG, dst, src1, src2, condition, generalFromSize(size)); + } + + /** + * Conditional increase. dst = src1 if condition else src2 + 1. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + * @param condition any condition flag. May not be null. + */ + protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { + conditionalSelectInstruction(CSINC, dst, src1, src2, condition, generalFromSize(size)); + } + + private void conditionalSelectInstruction(Instruction instr, Register dst, Register src1, Register src2, ConditionFlag condition, InstructionType type) { + assert !dst.equals(sp); + assert !src1.equals(sp); + assert !src2.equals(sp); + emitInt(type.encoding | instr.encoding | ConditionalSelectOp | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset); + } + + /* Integer Multiply/Divide (5.6) */ + + /** + * dst = src1 * src2 + src3. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + * @param src3 general purpose register. May not be null or the stackpointer. + */ + protected void madd(int size, Register dst, Register src1, Register src2, Register src3) { + mulInstruction(MADD, dst, src1, src2, src3, generalFromSize(size)); + } + + /** + * dst = src3 - src1 * src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + * @param src3 general purpose register. May not be null or the stackpointer. + */ + protected void msub(int size, Register dst, Register src1, Register src2, Register src3) { + mulInstruction(MSUB, dst, src1, src2, src3, generalFromSize(size)); + } + + /** + * Signed multiply high. dst = (src1 * src2)[127:64] + * + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + */ + protected void smulh(Register dst, Register src1, Register src2) { + assert !dst.equals(sp); + assert !src1.equals(sp); + assert !src2.equals(sp); + emitInt(0b10011011010 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); + } + + /** + * unsigned multiply high. dst = (src1 * src2)[127:64] + * + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + */ + protected void umulh(Register dst, Register src1, Register src2) { + assert !dst.equals(sp); + assert !src1.equals(sp); + assert !src2.equals(sp); + emitInt(0b10011011110 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); + } + + /** + * unsigned multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2) + * + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + * @param src3 general purpose register. May not be null or the stackpointer. + */ + protected void umaddl(Register dst, Register src1, Register src2, Register src3) { + assert !dst.equals(sp); + assert !src1.equals(sp); + assert !src2.equals(sp); + assert !src3.equals(sp); + emitInt(0b10011011101 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset); + } + + /** + * signed multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2) + * + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + * @param src3 general purpose register. May not be null or the stackpointer. + */ + protected void smaddl(Register dst, Register src1, Register src2, Register src3) { + assert !dst.equals(sp); + assert !src1.equals(sp); + assert !src2.equals(sp); + assert !src3.equals(sp); + emitInt(0b10011011001 << 21 | dst.encoding | rs1(src1) | rs2(src2) | rs3(src3)); + } + + private void mulInstruction(Instruction instr, Register dst, Register src1, Register src2, Register src3, InstructionType type) { + assert !dst.equals(sp); + assert !src1.equals(sp); + assert !src2.equals(sp); + assert !src3.equals(sp); + emitInt(type.encoding | instr.encoding | MulOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3)); + } + + /** + * Signed divide. dst = src1 / src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + */ + public void sdiv(int size, Register dst, Register src1, Register src2) { + dataProcessing2SourceOp(SDIV, dst, src1, src2, generalFromSize(size)); + } + + /** + * Unsigned divide. dst = src1 / src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + */ + public void udiv(int size, Register dst, Register src1, Register src2) { + dataProcessing2SourceOp(UDIV, dst, src1, src2, generalFromSize(size)); + } + + private void dataProcessing1SourceOp(Instruction instr, Register dst, Register src, InstructionType type) { + emitInt(type.encoding | instr.encoding | DataProcessing1SourceOp | rd(dst) | rs1(src)); + } + + private void dataProcessing2SourceOp(Instruction instr, Register dst, Register src1, Register src2, InstructionType type) { + assert !dst.equals(sp); + assert !src1.equals(sp); + assert !src2.equals(sp); + emitInt(type.encoding | instr.encoding | DataProcessing2SourceOp | rd(dst) | rs1(src1) | rs2(src2)); + } + + /* Floating point operations */ + + /* Load-Store Single FP register (5.7.1.1) */ + /** + * Floating point load. + * + * @param size number of bits read from memory into rt. Must be 32 or 64. + * @param rt floating point register. May not be null. + * @param address all addressing modes allowed. May not be null. + */ + public void fldr(int size, Register rt, AArch64Address address) { + assert rt.getRegisterCategory().equals(SIMD); + assert size == 32 || size == 64; + int transferSize = NumUtil.log2Ceil(size / 8); + loadStoreInstruction(LDR, rt, address, InstructionType.FP32, transferSize); + } + + /** + * Floating point store. + * + * @param size number of bits read from memory into rt. Must be 32 or 64. + * @param rt floating point register. May not be null. + * @param address all addressing modes allowed. May not be null. + */ + public void fstr(int size, Register rt, AArch64Address address) { + assert rt.getRegisterCategory().equals(SIMD); + assert size == 32 || size == 64; + int transferSize = NumUtil.log2Ceil(size / 8); + loadStoreInstruction(STR, rt, address, InstructionType.FP64, transferSize); + } + + /* Floating-point Move (register) (5.7.2) */ + + /** + * Floating point move. + * + * @param size register size. Has to be 32 or 64. + * @param dst floating point register. May not be null. + * @param src floating point register. May not be null. + */ + protected void fmov(int size, Register dst, Register src) { + fpDataProcessing1Source(FMOV, dst, src, floatFromSize(size)); + } + + /** + * Move size bits from floating point register unchanged to general purpose register. + * + * @param size number of bits read from memory into rt. Must be 32 or 64. + * @param dst general purpose register. May not be null, stack-pointer or zero-register + * @param src floating point register. May not be null. + */ + protected void fmovFpu2Cpu(int size, Register dst, Register src) { + assert dst.getRegisterCategory().equals(CPU); + assert src.getRegisterCategory().equals(SIMD); + fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVFPU2CPU); + } + + /** + * Move size bits from general purpose register unchanged to floating point register. + * + * @param size register size. Has to be 32 or 64. + * @param dst floating point register. May not be null. + * @param src general purpose register. May not be null or stack-pointer. + */ + protected void fmovCpu2Fpu(int size, Register dst, Register src) { + assert dst.getRegisterCategory().equals(SIMD); + assert src.getRegisterCategory().equals(CPU); + fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVCPU2FPU); + } + + private void fmovCpuFpuInstruction(Register dst, Register src, boolean is64bit, Instruction instr) { + int sf = is64bit ? FP64.encoding | General64.encoding : FP32.encoding | General32.encoding; + emitInt(sf | instr.encoding | FpConvertOp | rd(dst) | rs1(src)); + } + + /* Floating-point Move (immediate) (5.7.3) */ + + /** + * Move immediate into register. + * + * @param size register size. Has to be 32 or 64. + * @param dst floating point register. May not be null. + * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be + * loaded, i.e. (float) imm == imm must be true. In all cases + * {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true + * depending on size. + */ + protected void fmov(int size, Register dst, double imm) { + assert dst.getRegisterCategory().equals(SIMD); + InstructionType type = floatFromSize(size); + int immEncoding; + if (type == FP64) { + immEncoding = getDoubleImmediate(imm); + } else { + assert imm == (float) imm : "float mov must use an immediate that can be represented using a float."; + immEncoding = getFloatImmediate((float) imm); + } + emitInt(type.encoding | FMOV.encoding | FpImmOp | immEncoding | rd(dst)); + } + + private static int getDoubleImmediate(double imm) { + assert isDoubleImmediate(imm); + // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 + // 0000.0000.0000.0000.0000.0000.0000.0000 + long repr = Double.doubleToRawLongBits(imm); + int a = (int) (repr >>> 63) << 7; + int b = (int) ((repr >>> 61) & 0x1) << 6; + int cToH = (int) (repr >>> 48) & 0x3f; + return (a | b | cToH) << FpImmOffset; + } + + protected static boolean isDoubleImmediate(double imm) { + // Valid values will have the form: + // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 + // 0000.0000.0000.0000.0000.0000.0000.0000 + long bits = Double.doubleToRawLongBits(imm); + // lower 48 bits are cleared + if ((bits & NumUtil.getNbitNumberLong(48)) != 0) { + return false; + } + // bits[61..54] are all set or all cleared. + long pattern = (bits >> 54) & NumUtil.getNbitNumberLong(7); + if (pattern != 0 && pattern != NumUtil.getNbitNumberLong(7)) { + return false; + } + // bits[62] and bits[61] are opposites. + return ((bits ^ (bits << 1)) & (1L << 62)) != 0; + } + + private static int getFloatImmediate(float imm) { + assert isFloatImmediate(imm); + // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000 + int repr = Float.floatToRawIntBits(imm); + int a = (repr >>> 31) << 7; + int b = ((repr >>> 29) & 0x1) << 6; + int cToH = (repr >>> 19) & NumUtil.getNbitNumberInt(6); + return (a | b | cToH) << FpImmOffset; + } + + protected static boolean isFloatImmediate(float imm) { + // Valid values will have the form: + // aBbb.bbbc.defg.h000.0000.0000.0000.0000 + int bits = Float.floatToRawIntBits(imm); + // lower 20 bits are cleared. + if ((bits & NumUtil.getNbitNumberInt(19)) != 0) { + return false; + } + // bits[29..25] are all set or all cleared + int pattern = (bits >> 25) & NumUtil.getNbitNumberInt(5); + if (pattern != 0 && pattern != NumUtil.getNbitNumberInt(5)) { + return false; + } + // bits[29] and bits[30] have to be opposite + return ((bits ^ (bits << 1)) & (1 << 30)) != 0; + } + + /* Convert Floating-point Precision (5.7.4.1) */ + /* Converts float to double and vice-versa */ + + /** + * Convert float to double and vice-versa. + * + * @param srcSize size of source register in bits. + * @param dst floating point register. May not be null. + * @param src floating point register. May not be null. + */ + public void fcvt(int srcSize, Register dst, Register src) { + if (srcSize == 32) { + fpDataProcessing1Source(FCVTDS, dst, src, floatFromSize(srcSize)); + } else { + fpDataProcessing1Source(FCVTSD, dst, src, floatFromSize(srcSize)); + } + } + + /* Convert to Integer (5.7.4.2) */ + + /** + * Convert floating point to integer. Rounds towards zero. + * + * @param targetSize size of integer register. 32 or 64. + * @param srcSize size of floating point register. 32 or 64. + * @param dst general purpose register. May not be null, the zero-register or the stackpointer. + * @param src floating point register. May not be null. + */ + public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) { + assert !dst.equals(zr) && !dst.equals(sp); + assert src.getRegisterCategory().equals(SIMD); + fcvtCpuFpuInstruction(FCVTZS, dst, src, generalFromSize(targetSize), floatFromSize(srcSize)); + } + + /* Convert from Integer (5.7.4.2) */ + /** + * Converts integer to floating point. Uses rounding mode defined by FCPR. + * + * @param targetSize size of floating point register. 32 or 64. + * @param srcSize size of integer register. 32 or 64. + * @param dst floating point register. May not be null. + * @param src general purpose register. May not be null or the stackpointer. + */ + public void scvtf(int targetSize, int srcSize, Register dst, Register src) { + assert dst.getRegisterCategory().equals(SIMD); + assert !src.equals(sp); + fcvtCpuFpuInstruction(SCVTF, dst, src, floatFromSize(targetSize), generalFromSize(srcSize)); + } + + private void fcvtCpuFpuInstruction(Instruction instr, Register dst, Register src, InstructionType type1, InstructionType type2) { + emitInt(type1.encoding | type2.encoding | instr.encoding | FpConvertOp | rd(dst) | rs1(src)); + } + + /* Floating-point Round to Integral (5.7.5) */ + + /** + * Rounds floating-point to integral. Rounds towards zero. + * + * @param size register size. + * @param dst floating point register. May not be null. + * @param src floating point register. May not be null. + */ + protected void frintz(int size, Register dst, Register src) { + fpDataProcessing1Source(FRINTZ, dst, src, floatFromSize(size)); + } + + /* Floating-point Arithmetic (1 source) (5.7.6) */ + + /** + * dst = |src|. + * + * @param size register size. + * @param dst floating point register. May not be null. + * @param src floating point register. May not be null. + */ + public void fabs(int size, Register dst, Register src) { + fpDataProcessing1Source(FABS, dst, src, floatFromSize(size)); + } + + /** + * dst = -neg. + * + * @param size register size. + * @param dst floating point register. May not be null. + * @param src floating point register. May not be null. + */ + public void fneg(int size, Register dst, Register src) { + fpDataProcessing1Source(FNEG, dst, src, floatFromSize(size)); + } + + /** + * dst = Sqrt(src). + * + * @param size register size. + * @param dst floating point register. May not be null. + * @param src floating point register. May not be null. + */ + public void fsqrt(int size, Register dst, Register src) { + fpDataProcessing1Source(FSQRT, dst, src, floatFromSize(size)); + } + + private void fpDataProcessing1Source(Instruction instr, Register dst, Register src, InstructionType type) { + assert dst.getRegisterCategory().equals(SIMD); + assert src.getRegisterCategory().equals(SIMD); + emitInt(type.encoding | instr.encoding | Fp1SourceOp | rd(dst) | rs1(src)); + } + + /* Floating-point Arithmetic (2 source) (5.7.7) */ + + /** + * dst = src1 + src2. + * + * @param size register size. + * @param dst floating point register. May not be null. + * @param src1 floating point register. May not be null. + * @param src2 floating point register. May not be null. + */ + public void fadd(int size, Register dst, Register src1, Register src2) { + fpDataProcessing2Source(FADD, dst, src1, src2, floatFromSize(size)); + } + + /** + * dst = src1 - src2. + * + * @param size register size. + * @param dst floating point register. May not be null. + * @param src1 floating point register. May not be null. + * @param src2 floating point register. May not be null. + */ + public void fsub(int size, Register dst, Register src1, Register src2) { + fpDataProcessing2Source(FSUB, dst, src1, src2, floatFromSize(size)); + } + + /** + * dst = src1 * src2. + * + * @param size register size. + * @param dst floating point register. May not be null. + * @param src1 floating point register. May not be null. + * @param src2 floating point register. May not be null. + */ + public void fmul(int size, Register dst, Register src1, Register src2) { + fpDataProcessing2Source(FMUL, dst, src1, src2, floatFromSize(size)); + } + + /** + * dst = src1 / src2. + * + * @param size register size. + * @param dst floating point register. May not be null. + * @param src1 floating point register. May not be null. + * @param src2 floating point register. May not be null. + */ + public void fdiv(int size, Register dst, Register src1, Register src2) { + fpDataProcessing2Source(FDIV, dst, src1, src2, floatFromSize(size)); + } + + private void fpDataProcessing2Source(Instruction instr, Register dst, Register src1, Register src2, InstructionType type) { + assert dst.getRegisterCategory().equals(SIMD); + assert src1.getRegisterCategory().equals(SIMD); + assert src2.getRegisterCategory().equals(SIMD); + emitInt(type.encoding | instr.encoding | Fp2SourceOp | rd(dst) | rs1(src1) | rs2(src2)); + } + + /* Floating-point Multiply-Add (5.7.9) */ + + /** + * dst = src1 * src2 + src3. + * + * @param size register size. + * @param dst floating point register. May not be null. + * @param src1 floating point register. May not be null. + * @param src2 floating point register. May not be null. + * @param src3 floating point register. May not be null. + */ + protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) { + fpDataProcessing3Source(FMADD, dst, src1, src2, src3, floatFromSize(size)); + } + + /** + * dst = src3 - src1 * src2. + * + * @param size register size. + * @param dst floating point register. May not be null. + * @param src1 floating point register. May not be null. + * @param src2 floating point register. May not be null. + * @param src3 floating point register. May not be null. + */ + protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) { + fpDataProcessing3Source(FMSUB, dst, src1, src2, src3, floatFromSize(size)); + } + + private void fpDataProcessing3Source(Instruction instr, Register dst, Register src1, Register src2, Register src3, InstructionType type) { + assert dst.getRegisterCategory().equals(SIMD); + assert src1.getRegisterCategory().equals(SIMD); + assert src2.getRegisterCategory().equals(SIMD); + assert src3.getRegisterCategory().equals(SIMD); + emitInt(type.encoding | instr.encoding | Fp3SourceOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3)); + } + + /* Floating-point Comparison (5.7.10) */ + + /** + * Compares src1 to src2. + * + * @param size register size. + * @param src1 floating point register. May not be null. + * @param src2 floating point register. May not be null. + */ + public void fcmp(int size, Register src1, Register src2) { + assert src1.getRegisterCategory().equals(SIMD); + assert src2.getRegisterCategory().equals(SIMD); + InstructionType type = floatFromSize(size); + emitInt(type.encoding | FCMP.encoding | FpCmpOp | rs1(src1) | rs2(src2)); + } + + /** + * Conditional compare. NZCV = fcmp(src1, src2) if condition else uimm4. + * + * @param size register size. + * @param src1 floating point register. May not be null. + * @param src2 floating point register. May not be null. + * @param uimm4 condition flags that are used if condition is false. + * @param condition every condition allowed. May not be null. + */ + public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) { + assert NumUtil.isUnsignedNbit(4, uimm4); + assert src1.getRegisterCategory().equals(SIMD); + assert src2.getRegisterCategory().equals(SIMD); + InstructionType type = floatFromSize(size); + emitInt(type.encoding | FCCMP.encoding | uimm4 | condition.encoding << ConditionalConditionOffset | rs1(src1) | rs2(src2)); + } + + /** + * Compare register to 0.0 . + * + * @param size register size. + * @param src floating point register. May not be null. + */ + public void fcmpZero(int size, Register src) { + assert src.getRegisterCategory().equals(SIMD); + InstructionType type = floatFromSize(size); + emitInt(type.encoding | FCMPZERO.encoding | FpCmpOp | rs1(src)); + } + + /* Floating-point Conditional Select (5.7.11) */ + + /** + * Conditional select. dst = src1 if condition else src2. + * + * @param size register size. + * @param dst floating point register. May not be null. + * @param src1 floating point register. May not be null. + * @param src2 floating point register. May not be null. + * @param condition every condition allowed. May not be null. + */ + protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) { + assert dst.getRegisterCategory().equals(SIMD); + assert src1.getRegisterCategory().equals(SIMD); + assert src2.getRegisterCategory().equals(SIMD); + InstructionType type = floatFromSize(size); + emitInt(type.encoding | FCSEL.encoding | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset); + } + + /* Debug exceptions (5.9.1.2) */ + + /** + * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as + * UNALLOCATED instruction. + * + * @param uimm16 Arbitrary 16-bit unsigned payload. + */ + protected void hlt(int uimm16) { + exceptionInstruction(HLT, uimm16); + } + + /** + * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher + * exception level. + * + * @param uimm16 Arbitrary 16-bit unsigned payload. + */ + protected void brk(int uimm16) { + exceptionInstruction(BRK, uimm16); + } + + private void exceptionInstruction(Instruction instr, int uimm16) { + assert NumUtil.isUnsignedNbit(16, uimm16); + emitInt(instr.encoding | ExceptionOp | uimm16 << SystemImmediateOffset); + } + + /* Architectural hints (5.9.4) */ + public enum SystemHint { + NOP(0x0), + YIELD(0x1), + WFE(0x2), + WFI(0x3), + SEV(0x4), + SEVL(0x5); + + private final int encoding; + + SystemHint(int encoding) { + this.encoding = encoding; + } + } + + /** + * Architectural hints. + * + * @param hint Can be any of the defined hints. May not be null. + */ + protected void hint(SystemHint hint) { + emitInt(HINT.encoding | hint.encoding << SystemImmediateOffset); + } + + /** + * Clear Exclusive: clears the local record of the executing processor that an address has had a + * request for an exclusive access. + */ + protected void clrex() { + emitInt(CLREX.encoding); + } + + /** + * Possible barrier definitions for Aarch64. LOAD_LOAD and LOAD_STORE map to the same underlying + * barrier. + * + * We only need synchronization across the inner shareable domain (see B2-90 in the Reference + * documentation). + */ + public enum BarrierKind { + LOAD_LOAD(0x9, "ISHLD"), + LOAD_STORE(0x9, "ISHLD"), + STORE_STORE(0xA, "ISHST"), + ANY_ANY(0xB, "ISH"); + + public final int encoding; + public final String optionName; + + BarrierKind(int encoding, String optionName) { + this.encoding = encoding; + this.optionName = optionName; + } + } + + /** + * Data Memory Barrier. + * + * @param barrierKind barrier that is issued. May not be null. + */ + public void dmb(BarrierKind barrierKind) { + emitInt(DMB.encoding | BarrierOp | barrierKind.encoding << BarrierKindOffset); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java 2016-12-07 13:47:32.131288349 -0800 @@ -0,0 +1,1407 @@ +/* + * Copyright (c) 2013, 2016, 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 org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.BASE_REGISTER_ONLY; +import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET; +import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_SCALED; +import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_UNSCALED; +import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.REGISTER_OFFSET; +import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_BASE; +import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_INDEX; +import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.NO_WORK; +import static jdk.vm.ci.aarch64.AArch64.CPU; +import static jdk.vm.ci.aarch64.AArch64.r8; +import static jdk.vm.ci.aarch64.AArch64.r9; +import static jdk.vm.ci.aarch64.AArch64.sp; +import static jdk.vm.ci.aarch64.AArch64.zr; + +import org.graalvm.compiler.asm.AbstractAddress; +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; + +public class AArch64MacroAssembler extends AArch64Assembler { + + private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(r8), new ScratchRegister(r9)}; + + // Points to the next free scratch register + private int nextFreeScratchRegister = 0; + + public AArch64MacroAssembler(TargetDescription target) { + super(target); + } + + public class ScratchRegister implements AutoCloseable { + private final Register register; + + public ScratchRegister(Register register) { + this.register = register; + } + + public Register getRegister() { + return register; + } + + @Override + public void close() { + assert nextFreeScratchRegister > 0 : "Close called too often"; + nextFreeScratchRegister--; + } + } + + public ScratchRegister getScratchRegister() { + return scratchRegister[nextFreeScratchRegister++]; + } + + /** + * Specifies what actions have to be taken to turn an arbitrary address of the form + * {@code base + displacement [+ index [<< scale]]} into a valid AArch64Address. + */ + public static class AddressGenerationPlan { + public final WorkPlan workPlan; + public final AArch64Address.AddressingMode addressingMode; + public final boolean needsScratch; + + public enum WorkPlan { + /** + * Can be used as-is without extra work. + */ + NO_WORK, + /** + * Add scaled displacement to index register. + */ + ADD_TO_INDEX, + /** + * Add unscaled displacement to base register. + */ + ADD_TO_BASE, + } + + /** + * @param workPlan Work necessary to generate a valid address. + * @param addressingMode Addressing mode of generated address. + * @param needsScratch True if generating address needs a scatch register, false otherwise. + */ + public AddressGenerationPlan(WorkPlan workPlan, AArch64Address.AddressingMode addressingMode, boolean needsScratch) { + this.workPlan = workPlan; + this.addressingMode = addressingMode; + this.needsScratch = needsScratch; + } + } + + /** + * Generates an addressplan for an address of the form + * {@code base + displacement [+ index [<< log2(transferSize)]]} with the index register and + * scaling being optional. + * + * @param displacement an arbitrary displacement. + * @param hasIndexRegister true if the address uses an index register, false otherwise. non null + * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much + * the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8. + * @return AddressGenerationPlan that specifies the actions necessary to generate a valid + * AArch64Address for the given parameters. + */ + public static AddressGenerationPlan generateAddressPlan(long displacement, boolean hasIndexRegister, int transferSize) { + assert transferSize == 0 || transferSize == 1 || transferSize == 2 || transferSize == 4 || transferSize == 8; + boolean indexScaled = transferSize != 0; + int log2Scale = NumUtil.log2Ceil(transferSize); + long scaledDisplacement = displacement >> log2Scale; + boolean displacementScalable = indexScaled && (displacement & (transferSize - 1)) == 0; + if (displacement == 0) { + // register offset without any work beforehand. + return new AddressGenerationPlan(NO_WORK, REGISTER_OFFSET, false); + } else { + if (hasIndexRegister) { + if (displacementScalable) { + boolean needsScratch = !isArithmeticImmediate(scaledDisplacement); + return new AddressGenerationPlan(ADD_TO_INDEX, REGISTER_OFFSET, needsScratch); + } else { + boolean needsScratch = !isArithmeticImmediate(displacement); + return new AddressGenerationPlan(ADD_TO_BASE, REGISTER_OFFSET, needsScratch); + } + } else { + if (NumUtil.isSignedNbit(9, displacement)) { + return new AddressGenerationPlan(NO_WORK, IMMEDIATE_UNSCALED, false); + } else if (displacementScalable && NumUtil.isUnsignedNbit(12, scaledDisplacement)) { + return new AddressGenerationPlan(NO_WORK, IMMEDIATE_SCALED, false); + } else { + boolean needsScratch = !isArithmeticImmediate(displacement); + return new AddressGenerationPlan(ADD_TO_BASE, REGISTER_OFFSET, needsScratch); + } + } + } + } + + /** + * Returns an AArch64Address pointing to + * {@code base + displacement + index << log2(transferSize)}. + * + * @param base general purpose register. May not be null or the zero register. + * @param displacement arbitrary displacement added to base. + * @param index general purpose register. May not be null or the stack pointer. + * @param signExtendIndex if true consider index register a word register that should be + * sign-extended before being added. + * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much + * the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8. + * @param additionalReg additional register used either as a scratch register or as part of the + * final address, depending on whether allowOverwrite is true or not. May not be null + * or stackpointer. + * @param allowOverwrite if true allows to change value of base or index register to generate + * address. + * @return AArch64Address pointing to memory at + * {@code base + displacement + index << log2(transferSize)}. + */ + public AArch64Address makeAddress(Register base, long displacement, Register index, boolean signExtendIndex, int transferSize, Register additionalReg, boolean allowOverwrite) { + AddressGenerationPlan plan = generateAddressPlan(displacement, !index.equals(zr), transferSize); + assert allowOverwrite || !zr.equals(additionalReg) || plan.workPlan == NO_WORK; + assert !plan.needsScratch || !zr.equals(additionalReg); + int log2Scale = NumUtil.log2Ceil(transferSize); + long scaledDisplacement = displacement >> log2Scale; + Register newIndex = index; + Register newBase = base; + int immediate; + switch (plan.workPlan) { + case NO_WORK: + if (plan.addressingMode == IMMEDIATE_SCALED) { + immediate = (int) scaledDisplacement; + } else { + immediate = (int) displacement; + } + break; + case ADD_TO_INDEX: + newIndex = allowOverwrite ? index : additionalReg; + if (plan.needsScratch) { + mov(additionalReg, scaledDisplacement); + add(signExtendIndex ? 32 : 64, newIndex, index, additionalReg); + } else { + add(signExtendIndex ? 32 : 64, newIndex, index, (int) scaledDisplacement); + } + immediate = 0; + break; + case ADD_TO_BASE: + newBase = allowOverwrite ? base : additionalReg; + if (plan.needsScratch) { + mov(additionalReg, displacement); + add(64, newBase, base, additionalReg); + } else { + add(64, newBase, base, (int) displacement); + } + immediate = 0; + break; + default: + throw GraalError.shouldNotReachHere(); + } + AArch64Address.AddressingMode addressingMode = plan.addressingMode; + ExtendType extendType = null; + if (addressingMode == REGISTER_OFFSET) { + if (newIndex.equals(zr)) { + addressingMode = BASE_REGISTER_ONLY; + } else if (signExtendIndex) { + addressingMode = EXTENDED_REGISTER_OFFSET; + extendType = ExtendType.SXTW; + } + } + return AArch64Address.createAddress(addressingMode, newBase, newIndex, immediate, transferSize != 0, extendType); + } + + /** + * Returns an AArch64Address pointing to {@code base + displacement}. Specifies the memory + * transfer size to allow some optimizations when building the address. + * + * @param base general purpose register. May not be null or the zero register. + * @param displacement arbitrary displacement added to base. + * @param transferSize the memory transfer size in bytes. + * @param additionalReg additional register used either as a scratch register or as part of the + * final address, depending on whether allowOverwrite is true or not. May not be + * null, zero register or stackpointer. + * @param allowOverwrite if true allows to change value of base or index register to generate + * address. + * @return AArch64Address pointing to memory at {@code base + displacement}. + */ + public AArch64Address makeAddress(Register base, long displacement, Register additionalReg, int transferSize, boolean allowOverwrite) { + assert additionalReg.getRegisterCategory().equals(CPU); + return makeAddress(base, displacement, zr, /* sign-extend */false, transferSize, additionalReg, allowOverwrite); + } + + /** + * Returns an AArch64Address pointing to {@code base + displacement}. Fails if address cannot be + * represented without overwriting base register or using a scratch register. + * + * @param base general purpose register. May not be null or the zero register. + * @param displacement arbitrary displacement added to base. + * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much + * the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8. + * @return AArch64Address pointing to memory at {@code base + displacement}. + */ + public AArch64Address makeAddress(Register base, long displacement, int transferSize) { + return makeAddress(base, displacement, zr, /* signExtend */false, transferSize, zr, /* allowOverwrite */false); + } + + /** + * Loads memory address into register. + * + * @param dst general purpose register. May not be null, zero-register or stackpointer. + * @param address address whose value is loaded into dst. May not be null, + * {@link org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode#IMMEDIATE_POST_INDEXED + * POST_INDEXED} or + * {@link org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode#IMMEDIATE_PRE_INDEXED + * IMMEDIATE_PRE_INDEXED} + * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much + * the index register is scaled. Can be 1, 2, 4 or 8. + */ + public void loadAddress(Register dst, AArch64Address address, int transferSize) { + assert transferSize == 1 || transferSize == 2 || transferSize == 4 || transferSize == 8; + assert dst.getRegisterCategory().equals(CPU); + int shiftAmt = NumUtil.log2Ceil(transferSize); + switch (address.getAddressingMode()) { + case IMMEDIATE_SCALED: + int scaledImmediate = address.getImmediateRaw() << shiftAmt; + int lowerBits = scaledImmediate & NumUtil.getNbitNumberInt(12); + int higherBits = scaledImmediate & ~NumUtil.getNbitNumberInt(12); + boolean firstAdd = true; + if (lowerBits != 0) { + add(64, dst, address.getBase(), lowerBits); + firstAdd = false; + } + if (higherBits != 0) { + Register src = firstAdd ? address.getBase() : dst; + add(64, dst, src, higherBits); + } + break; + case IMMEDIATE_UNSCALED: + int immediate = address.getImmediateRaw(); + add(64, dst, address.getBase(), immediate); + break; + case REGISTER_OFFSET: + add(64, dst, address.getBase(), address.getOffset(), ShiftType.LSL, address.isScaled() ? shiftAmt : 0); + break; + case EXTENDED_REGISTER_OFFSET: + add(64, dst, address.getBase(), address.getOffset(), address.getExtendType(), address.isScaled() ? shiftAmt : 0); + break; + case PC_LITERAL: + super.adr(dst, address.getImmediateRaw()); + break; + case BASE_REGISTER_ONLY: + movx(dst, address.getBase()); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + + public void movx(Register dst, Register src) { + mov(64, dst, src); + } + + public void mov(int size, Register dst, Register src) { + if (dst.equals(sp) || src.equals(sp)) { + add(size, dst, src, 0); + } else { + or(size, dst, zr, src); + } + } + + /** + * Generates a 64-bit immediate move code sequence. + * + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param imm + */ + private void mov64(Register dst, long imm) { + // We have to move all non zero parts of the immediate in 16-bit chunks + boolean firstMove = true; + for (int offset = 0; offset < 64; offset += 16) { + int chunk = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16); + if (chunk == 0) { + continue; + } + if (firstMove) { + movz(64, dst, chunk, offset); + firstMove = false; + } else { + movk(64, dst, chunk, offset); + } + } + assert !firstMove; + } + + /** + * Loads immediate into register. + * + * @param dst general purpose register. May not be null, zero-register or stackpointer. + * @param imm immediate loaded into register. + */ + public void mov(Register dst, long imm) { + assert dst.getRegisterCategory().equals(CPU); + if (imm == 0L) { + movx(dst, zr); + } else if (LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) { + or(64, dst, zr, imm); + } else if (imm >> 32 == -1L && (int) imm < 0 && LogicalImmediateTable.isRepresentable((int) imm) != LogicalImmediateTable.Representable.NO) { + // If the higher 32-bit are 1s and the sign bit of the lower 32-bits is set *and* we can + // represent the lower 32 bits as a logical immediate we can create the lower 32-bit and + // then sign extend + // them. This allows us to cover immediates like ~1L with 2 instructions. + mov(dst, (int) imm); + sxt(64, 32, dst, dst); + } else { + mov64(dst, imm); + } + } + + /** + * Loads immediate into register. + * + * @param dst general purpose register. May not be null, zero-register or stackpointer. + * @param imm immediate loaded into register. + */ + public void mov(Register dst, int imm) { + mov(dst, imm & 0xFFFF_FFFFL); + } + + /** + * Generates a 48-bit immediate move code sequence. The immediate may later be updated by + * HotSpot. + * + * In AArch64 mode the virtual address space is 48-bits in size, so we only need three + * instructions to create a patchable instruction sequence that can reach anywhere. + * + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param imm + */ + public void movNativeAddress(Register dst, long imm) { + assert (imm & 0xFFFF_0000_0000_0000L) == 0; + // We have to move all non zero parts of the immediate in 16-bit chunks + boolean firstMove = true; + for (int offset = 0; offset < 48; offset += 16) { + int chunk = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16); + if (firstMove) { + movz(64, dst, chunk, offset); + firstMove = false; + } else { + movk(64, dst, chunk, offset); + } + } + assert !firstMove; + } + + /** + * @return Number of instructions necessary to load immediate into register. + */ + public static int nrInstructionsToMoveImmediate(long imm) { + if (imm == 0L || LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) { + return 1; + } + if (imm >> 32 == -1L && (int) imm < 0 && LogicalImmediateTable.isRepresentable((int) imm) != LogicalImmediateTable.Representable.NO) { + // If the higher 32-bit are 1s and the sign bit of the lower 32-bits is set *and* we can + // represent the lower 32 bits as a logical immediate we can create the lower 32-bit and + // then sign extend + // them. This allows us to cover immediates like ~1L with 2 instructions. + return 2; + } + int nrInstructions = 0; + for (int offset = 0; offset < 64; offset += 16) { + int part = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16); + if (part != 0) { + nrInstructions++; + } + } + return nrInstructions; + } + + /** + * Loads a srcSize value from address into rt sign-extending it if necessary. + * + * @param targetSize size of target register in bits. Must be 32 or 64. + * @param srcSize size of memory read in bits. Must be 8, 16 or 32 and smaller or equal to + * targetSize. + * @param rt general purpose register. May not be null or stackpointer. + * @param address all addressing modes allowed. May not be null. + */ + @Override + public void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) { + assert targetSize == 32 || targetSize == 64; + assert srcSize <= targetSize; + if (targetSize == srcSize) { + super.ldr(srcSize, rt, address); + } else { + super.ldrs(targetSize, srcSize, rt, address); + } + } + + /** + * Conditional move. dst = src1 if condition else src2. + * + * @param size register size. Has to be 32 or 64. + * @param result general purpose register. May not be null or the stackpointer. + * @param trueValue general purpose register. May not be null or the stackpointer. + * @param falseValue general purpose register. May not be null or the stackpointer. + * @param cond any condition flag. May not be null. + */ + public void cmov(int size, Register result, Register trueValue, Register falseValue, ConditionFlag cond) { + super.csel(size, result, trueValue, falseValue, cond); + } + + /** + * Conditional set. dst = 1 if condition else 0. + * + * @param dst general purpose register. May not be null or stackpointer. + * @param condition any condition. May not be null. + */ + public void cset(Register dst, ConditionFlag condition) { + super.csinc(32, dst, zr, zr, condition.negate()); + } + + /** + * dst = src1 + src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + */ + public void add(int size, Register dst, Register src1, Register src2) { + super.add(size, dst, src1, src2, ShiftType.LSL, 0); + } + + /** + * dst = src1 + src2 and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + */ + public void adds(int size, Register dst, Register src1, Register src2) { + super.adds(size, dst, src1, src2, getNopExtendType(size), 0); + } + + /** + * dst = src1 - src2 and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + */ + public void subs(int size, Register dst, Register src1, Register src2) { + super.subs(size, dst, src1, src2, getNopExtendType(size), 0); + } + + /** + * Returns the ExtendType for the given size that corresponds to a no-op. + * + * I.e. when doing add X0, X1, X2, the actual instruction has the form add X0, X1, X2 UXTX. + * + * @param size + */ + private static ExtendType getNopExtendType(int size) { + if (size == 64) { + return ExtendType.UXTX; + } else if (size == 32) { + return ExtendType.UXTW; + } else { + throw GraalError.shouldNotReachHere("No-op "); + } + } + + /** + * dst = src1 - src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + */ + public void sub(int size, Register dst, Register src1, Register src2) { + super.sub(size, dst, src1, src2, ShiftType.LSL, 0); + } + + /** + * dst = src1 + shiftType(src2, shiftAmt & (size - 1)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType any type but ROR. + * @param shiftAmt arbitrary shift amount. + */ + @Override + public void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { + int shift = clampShiftAmt(size, shiftAmt); + super.add(size, dst, src1, src2, shiftType, shift); + } + + /** + * dst = src1 + shiftType(src2, shiftAmt & (size-1)) and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + * @param shiftType any type but ROR. + * @param shiftAmt arbitrary shift amount. + */ + @Override + public void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) { + int shift = clampShiftAmt(size, shiftAmt); + super.sub(size, dst, src1, src2, shiftType, shift); + } + + /** + * dst = -src1. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or stackpointer. + */ + public void neg(int size, Register dst, Register src) { + sub(size, dst, zr, src); + } + + /** + * dst = src + immediate. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or stackpointer. + * @param immediate arithmetic immediate + */ + @Override + public void add(int size, Register dst, Register src, int immediate) { + if (immediate < 0) { + sub(size, dst, src, -immediate); + } else if (!(dst.equals(src) && immediate == 0)) { + super.add(size, dst, src, immediate); + } + } + + /** + * dst = src + aimm and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or zero-register. + * @param immediate arithmetic immediate. + */ + @Override + public void adds(int size, Register dst, Register src, int immediate) { + if (immediate < 0) { + subs(size, dst, src, -immediate); + } else if (!(dst.equals(src) && immediate == 0)) { + super.adds(size, dst, src, immediate); + } + } + + /** + * dst = src - immediate. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or stackpointer. + * @param immediate arithmetic immediate + */ + @Override + public void sub(int size, Register dst, Register src, int immediate) { + if (immediate < 0) { + add(size, dst, src, -immediate); + } else if (!dst.equals(src) || immediate != 0) { + super.sub(size, dst, src, immediate); + } + } + + /** + * dst = src - aimm and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or zero-register. + * @param immediate arithmetic immediate. + */ + @Override + public void subs(int size, Register dst, Register src, int immediate) { + if (immediate < 0) { + adds(size, dst, src, -immediate); + } else if (!dst.equals(src) || immediate != 0) { + super.sub(size, dst, src, immediate); + } + } + + /** + * dst = src1 * src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + */ + public void mul(int size, Register dst, Register src1, Register src2) { + super.madd(size, dst, src1, src2, zr); + } + + /** + * unsigned multiply high. dst = (src1 * src2) >> size + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + */ + public void umulh(int size, Register dst, Register src1, Register src2) { + assert size == 32 || size == 64; + if (size == 64) { + super.umulh(dst, src1, src2); + } else { + // xDst = wSrc1 * wSrc2 + super.umaddl(dst, src1, src2, zr); + // xDst = xDst >> 32 + lshr(64, dst, dst, 32); + } + } + + /** + * signed multiply high. dst = (src1 * src2) >> size + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src1 general purpose register. May not be null or the stackpointer. + * @param src2 general purpose register. May not be null or the stackpointer. + */ + public void smulh(int size, Register dst, Register src1, Register src2) { + assert size == 32 || size == 64; + if (size == 64) { + super.smulh(dst, src1, src2); + } else { + // xDst = wSrc1 * wSrc2 + super.smaddl(dst, src1, src2, zr); + // xDst = xDst >> 32 + lshr(64, dst, dst, 32); + } + } + + /** + * dst = src1 % src2. Signed. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param n numerator. General purpose register. May not be null or the stackpointer. + * @param d denominator. General purpose register. Divisor May not be null or the stackpointer. + */ + public void rem(int size, Register dst, Register n, Register d) { + // There is no irem or similar instruction. Instead we use the relation: + // n % d = n - Floor(n / d) * d if nd >= 0 + // n % d = n - Ceil(n / d) * d else + // Which is equivalent to n - TruncatingDivision(n, d) * d + super.sdiv(size, dst, n, d); + super.msub(size, dst, dst, d, n); + } + + /** + * dst = src1 % src2. Unsigned. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param n numerator. General purpose register. May not be null or the stackpointer. + * @param d denominator. General purpose register. Divisor May not be null or the stackpointer. + */ + public void urem(int size, Register dst, Register n, Register d) { + // There is no irem or similar instruction. Instead we use the relation: + // n % d = n - Floor(n / d) * d + // Which is equivalent to n - TruncatingDivision(n, d) * d + super.udiv(size, dst, n, d); + super.msub(size, dst, dst, d, n); + } + + /** + * Add/subtract instruction encoding supports 12-bit immediate values. + * + * @param imm immediate value to be tested. + * @return true if immediate can be used directly for arithmetic instructions (add/sub), false + * otherwise. + */ + public static boolean isArithmeticImmediate(long imm) { + // If we have a negative immediate we just use the opposite operator. I.e.: x - (-5) == x + + // 5. + return NumUtil.isInt(Math.abs(imm)) && isAimm((int) Math.abs(imm)); + } + + /** + * Compare instructions are add/subtract instructions and so support 12-bit immediate values. + * + * @param imm immediate value to be tested. + * @return true if immediate can be used directly with comparison instructions, false otherwise. + */ + public static boolean isComparisonImmediate(long imm) { + return isArithmeticImmediate(imm); + } + + /** + * Move wide immediate instruction encoding supports 16-bit immediate values which can be + * optionally-shifted by multiples of 16 (i.e. 0, 16, 32, 48). + * + * @return true if immediate can be moved directly into a register, false otherwise. + */ + public static boolean isMovableImmediate(long imm) { + // // Positions of first, respectively last set bit. + // int start = Long.numberOfTrailingZeros(imm); + // int end = 64 - Long.numberOfLeadingZeros(imm); + // int length = end - start; + // if (length > 16) { + // return false; + // } + // // We can shift the necessary part of the immediate (i.e. everything between the first + // and + // // last set bit) by as much as 16 - length around to arrive at a valid shift amount + // int tolerance = 16 - length; + // int prevMultiple = NumUtil.roundDown(start, 16); + // int nextMultiple = NumUtil.roundUp(start, 16); + // return start - prevMultiple <= tolerance || nextMultiple - start <= tolerance; + /* + * This is a bit optimistic because the constant could also be for an arithmetic instruction + * which only supports 12-bits. That case needs to be handled in the backend. + */ + return NumUtil.isInt(Math.abs(imm)) && NumUtil.isUnsignedNbit(16, (int) Math.abs(imm)); + } + + /** + * dst = src << (shiftAmt & (size - 1)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param src general purpose register. May not be null, stackpointer or zero-register. + * @param shiftAmt amount by which src is shifted. + */ + public void shl(int size, Register dst, Register src, long shiftAmt) { + int shift = clampShiftAmt(size, shiftAmt); + super.ubfm(size, dst, src, (size - shift) & (size - 1), size - 1 - shift); + } + + /** + * dst = src1 << (src2 & (size - 1)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or stackpointer. + * @param shift general purpose register. May not be null or stackpointer. + */ + public void shl(int size, Register dst, Register src, Register shift) { + super.lsl(size, dst, src, shift); + } + + /** + * dst = src >>> (shiftAmt & (size - 1)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param src general purpose register. May not be null, stackpointer or zero-register. + * @param shiftAmt amount by which src is shifted. + */ + public void lshr(int size, Register dst, Register src, long shiftAmt) { + int shift = clampShiftAmt(size, shiftAmt); + super.ubfm(size, dst, src, shift, size - 1); + } + + /** + * dst = src1 >>> (src2 & (size - 1)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or stackpointer. + * @param shift general purpose register. May not be null or stackpointer. + */ + public void lshr(int size, Register dst, Register src, Register shift) { + super.lsr(size, dst, src, shift); + } + + /** + * dst = src >> (shiftAmt & log2(size)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param src general purpose register. May not be null, stackpointer or zero-register. + * @param shiftAmt amount by which src is shifted. + */ + public void ashr(int size, Register dst, Register src, long shiftAmt) { + int shift = clampShiftAmt(size, shiftAmt); + super.sbfm(size, dst, src, shift, size - 1); + } + + /** + * dst = src1 >> (src2 & log2(size)). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or stackpointer. + * @param shift general purpose register. May not be null or stackpointer. + */ + public void ashr(int size, Register dst, Register src, Register shift) { + super.asr(size, dst, src, shift); + } + + /** + * Clamps shiftAmt into range 0 <= shiftamt < size according to JLS. + * + * @param size size of operation. + * @param shiftAmt arbitrary shift amount. + * @return value between 0 and size - 1 inclusive that is equivalent to shiftAmt according to + * JLS. + */ + private static int clampShiftAmt(int size, long shiftAmt) { + return (int) (shiftAmt & (size - 1)); + } + + /** + * dst = src1 & src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + */ + public void and(int size, Register dst, Register src1, Register src2) { + super.and(size, dst, src1, src2, ShiftType.LSL, 0); + } + + /** + * dst = src1 ^ src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + */ + public void eor(int size, Register dst, Register src1, Register src2) { + super.eor(size, dst, src1, src2, ShiftType.LSL, 0); + } + + /** + * dst = src1 | src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src1 general purpose register. May not be null or stackpointer. + * @param src2 general purpose register. May not be null or stackpointer. + */ + public void or(int size, Register dst, Register src1, Register src2) { + super.orr(size, dst, src1, src2, ShiftType.LSL, 0); + } + + /** + * dst = src | bimm. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or zero-register. + * @param src general purpose register. May not be null or stack-pointer. + * @param bimm logical immediate. See {@link AArch64Assembler.LogicalImmediateTable} for exact + * definition. + */ + public void or(int size, Register dst, Register src, long bimm) { + super.orr(size, dst, src, bimm); + } + + /** + * dst = ~src. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or stackpointer. + */ + public void not(int size, Register dst, Register src) { + super.orn(size, dst, zr, src, ShiftType.LSL, 0); + } + + /** + * Sign-extend value from src into dst. + * + * @param destSize destination register size. Has to be 32 or 64. + * @param srcSize source register size. May be 8, 16 or 32 and smaller than destSize. + * @param dst general purpose register. May not be null, stackpointer or zero-register. + * @param src general purpose register. May not be null, stackpointer or zero-register. + */ + public void sxt(int destSize, int srcSize, Register dst, Register src) { + assert (destSize == 32 || destSize == 64) && srcSize < destSize; + assert srcSize == 8 || srcSize == 16 || srcSize == 32; + int[] srcSizeValues = {7, 15, 31}; + super.sbfm(destSize, dst, src, 0, srcSizeValues[NumUtil.log2Ceil(srcSize / 8)]); + } + + /** + * dst = src if condition else -src. + * + * @param size register size. Must be 32 or 64. + * @param dst general purpose register. May not be null or the stackpointer. + * @param src general purpose register. May not be null or the stackpointer. + * @param condition any condition except AV or NV. May not be null. + */ + public void csneg(int size, Register dst, Register src, ConditionFlag condition) { + super.csneg(size, dst, src, src, condition.negate()); + } + + /** + * @return True if the immediate can be used directly for logical 64-bit instructions. + */ + public static boolean isLogicalImmediate(long imm) { + return LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO; + } + + /** + * @return True if the immediate can be used directly for logical 32-bit instructions. + */ + public static boolean isLogicalImmediate(int imm) { + return LogicalImmediateTable.isRepresentable(imm) == LogicalImmediateTable.Representable.YES; + } + + /* Float instructions */ + + /** + * Moves integer to float, float to integer, or float to float. Does not support integer to + * integer moves. + * + * @param size register size. Has to be 32 or 64. + * @param dst Either floating-point or general-purpose register. If general-purpose register may + * not be stackpointer or zero register. Cannot be null in any case. + * @param src Either floating-point or general-purpose register. If general-purpose register may + * not be stackpointer. Cannot be null in any case. + */ + @Override + public void fmov(int size, Register dst, Register src) { + assert !(dst.getRegisterCategory().equals(CPU) && src.getRegisterCategory().equals(CPU)) : "src and dst cannot both be integer registers."; + if (dst.getRegisterCategory().equals(CPU)) { + super.fmovFpu2Cpu(size, dst, src); + } else if (src.getRegisterCategory().equals(CPU)) { + super.fmovCpu2Fpu(size, dst, src); + } else { + super.fmov(size, dst, src); + } + } + + /** + * + * @param size register size. Has to be 32 or 64. + * @param dst floating point register. May not be null. + * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be + * loaded, i.e. (float) imm == imm must be true. In all cases + * {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true + * depending on size. + */ + @Override + public void fmov(int size, Register dst, double imm) { + if (imm == 0.0) { + assert Double.doubleToRawLongBits(imm) == 0L : "-0.0 is no valid immediate."; + super.fmovCpu2Fpu(size, dst, zr); + } else { + super.fmov(size, dst, imm); + } + } + + /** + * + * @return true if immediate can be loaded directly into floating-point register, false + * otherwise. + */ + public static boolean isDoubleImmediate(double imm) { + return Double.doubleToRawLongBits(imm) == 0L || AArch64Assembler.isDoubleImmediate(imm); + } + + /** + * + * @return true if immediate can be loaded directly into floating-point register, false + * otherwise. + */ + public static boolean isFloatImmediate(float imm) { + return Float.floatToRawIntBits(imm) == 0 || AArch64Assembler.isFloatImmediate(imm); + } + + /** + * Conditional move. dst = src1 if condition else src2. + * + * @param size register size. + * @param result floating point register. May not be null. + * @param trueValue floating point register. May not be null. + * @param falseValue floating point register. May not be null. + * @param condition every condition allowed. May not be null. + */ + public void fcmov(int size, Register result, Register trueValue, Register falseValue, ConditionFlag condition) { + super.fcsel(size, result, trueValue, falseValue, condition); + } + + /** + * dst = src1 % src2. + * + * @param size register size. Has to be 32 or 64. + * @param dst floating-point register. May not be null. + * @param n numerator. Floating-point register. May not be null. + * @param d denominator. Floating-point register. May not be null. + */ + public void frem(int size, Register dst, Register n, Register d) { + // There is no frem instruction, instead we compute the remainder using the relation: + // rem = n - Truncating(n / d) * d + super.fdiv(size, dst, n, d); + super.frintz(size, dst, dst); + super.fmsub(size, dst, dst, d, n); + } + + /* Branches */ + + /** + * Compares x and y and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param x general purpose register. May not be null or stackpointer. + * @param y general purpose register. May not be null or stackpointer. + */ + public void cmp(int size, Register x, Register y) { + super.subs(size, zr, x, y, ShiftType.LSL, 0); + } + + /** + * Compares x to y and sets condition flags. + * + * @param size register size. Has to be 32 or 64. + * @param x general purpose register. May not be null or stackpointer. + * @param y comparison immediate, {@link #isComparisonImmediate(long)} has to be true for it. + */ + public void cmp(int size, Register x, int y) { + if (y < 0) { + super.adds(size, zr, x, -y); + } else { + super.subs(size, zr, x, y); + } + } + + /** + * Sets condition flags according to result of x & y. + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stack-pointer. + * @param x general purpose register. May not be null or stackpointer. + * @param y general purpose register. May not be null or stackpointer. + */ + public void ands(int size, Register dst, Register x, Register y) { + super.ands(size, dst, x, y, ShiftType.LSL, 0); + } + + /** + * When patching up Labels we have to know what kind of code to generate. + */ + public enum PatchLabelKind { + BRANCH_CONDITIONALLY(0x0), + BRANCH_UNCONDITIONALLY(0x1), + BRANCH_NONZERO(0x2), + BRANCH_ZERO(0x3), + JUMP_ADDRESS(0x4), + ADR(0x5); + + /** + * Offset by which additional information for branch conditionally, branch zero and branch + * non zero has to be shifted. + */ + public static final int INFORMATION_OFFSET = 5; + + public final int encoding; + + PatchLabelKind(int encoding) { + this.encoding = encoding; + } + + /** + * @return PatchLabelKind with given encoding. + */ + private static PatchLabelKind fromEncoding(int encoding) { + return values()[encoding & NumUtil.getNbitNumberInt(INFORMATION_OFFSET)]; + } + + } + + public void adr(Register dst, Label label) { + // TODO Handle case where offset is too large for a single jump instruction + if (label.isBound()) { + int offset = label.position() - position(); + super.adr(dst, offset); + } else { + label.addPatchAt(position()); + // Encode condition flag so that we know how to patch the instruction later + emitInt(PatchLabelKind.ADR.encoding | dst.encoding << PatchLabelKind.INFORMATION_OFFSET); + } + } + + /** + * Compare register and branch if non-zero. + * + * @param size Instruction size in bits. Should be either 32 or 64. + * @param cmp general purpose register. May not be null, zero-register or stackpointer. + * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null. + */ + public void cbnz(int size, Register cmp, Label label) { + // TODO Handle case where offset is too large for a single jump instruction + if (label.isBound()) { + int offset = label.position() - position(); + super.cbnz(size, cmp, offset); + } else { + label.addPatchAt(position()); + int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 1); + int sizeEncoding = (size == 64 ? 1 : 0) << PatchLabelKind.INFORMATION_OFFSET; + // Encode condition flag so that we know how to patch the instruction later + emitInt(PatchLabelKind.BRANCH_NONZERO.encoding | regEncoding | sizeEncoding); + } + } + + /** + * Compare register and branch if zero. + * + * @param size Instruction size in bits. Should be either 32 or 64. + * @param cmp general purpose register. May not be null, zero-register or stackpointer. + * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null. + */ + public void cbz(int size, Register cmp, Label label) { + // TODO Handle case where offset is too large for a single jump instruction + if (label.isBound()) { + int offset = label.position() - position(); + super.cbz(size, cmp, offset); + } else { + label.addPatchAt(position()); + int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 1); + int sizeEncoding = (size == 64 ? 1 : 0) << PatchLabelKind.INFORMATION_OFFSET; + // Encode condition flag so that we know how to patch the instruction later + emitInt(PatchLabelKind.BRANCH_ZERO.encoding | regEncoding | sizeEncoding); + } + } + + /** + * Branches to label if condition is true. + * + * @param condition any condition value allowed. Non null. + * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null. + */ + public void branchConditionally(ConditionFlag condition, Label label) { + // TODO Handle case where offset is too large for a single jump instruction + if (label.isBound()) { + int offset = label.position() - position(); + super.b(condition, offset); + } else { + label.addPatchAt(position()); + // Encode condition flag so that we know how to patch the instruction later + emitInt(PatchLabelKind.BRANCH_CONDITIONALLY.encoding | condition.encoding << PatchLabelKind.INFORMATION_OFFSET); + } + } + + /** + * Branches if condition is true. Address of jump is patched up by HotSpot c++ code. + * + * @param condition any condition value allowed. Non null. + */ + public void branchConditionally(ConditionFlag condition) { + // Correct offset is fixed up by HotSpot later. + super.b(condition, 0); + } + + /** + * Jumps to label. + * + * param label Can only handle signed 28-bit offsets. May be unbound. Non null. + */ + @Override + public void jmp(Label label) { + // TODO Handle case where offset is too large for a single jump instruction + if (label.isBound()) { + int offset = label.position() - position(); + super.b(offset); + } else { + label.addPatchAt(position()); + emitInt(PatchLabelKind.BRANCH_UNCONDITIONALLY.encoding); + } + } + + /** + * Jump to address in dest. + * + * @param dest General purpose register. May not be null, zero-register or stackpointer. + */ + public void jmp(Register dest) { + super.br(dest); + } + + /** + * Immediate jump instruction fixed up by HotSpot c++ code. + */ + public void jmp() { + // Offset has to be fixed up by c++ code. + super.b(0); + } + + /** + * + * @return true if immediate offset can be used in a single branch instruction. + */ + public static boolean isBranchImmediateOffset(long imm) { + return NumUtil.isSignedNbit(28, imm); + } + + /* system instructions */ + + /** + * Exception codes used when calling hlt instruction. + */ + public enum AArch64ExceptionCode { + NO_SWITCH_TARGET(0x0), + BREAKPOINT(0x1); + + public final int encoding; + + AArch64ExceptionCode(int encoding) { + this.encoding = encoding; + } + } + + /** + * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as + * UNALLOCATED instruction. + * + * @param exceptionCode exception code specifying why halt was called. Non null. + */ + public void hlt(AArch64ExceptionCode exceptionCode) { + super.hlt(exceptionCode.encoding); + } + + /** + * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher + * exception level. + * + * @param exceptionCode exception code specifying why break was called. Non null. + */ + public void brk(AArch64ExceptionCode exceptionCode) { + super.brk(exceptionCode.encoding); + } + + public void pause() { + throw GraalError.unimplemented(); + } + + /** + * Executes no-op instruction. No registers or flags are updated, except for PC. + */ + public void nop() { + super.hint(SystemHint.NOP); + } + + /** + * Same as {@link #nop()}. + */ + @Override + public void ensureUniquePC() { + nop(); + } + + /** + * Aligns PC. + * + * @param modulus Has to be positive multiple of 4. + */ + @Override + public void align(int modulus) { + assert modulus > 0 && (modulus & 0x3) == 0 : "Modulus has to be a positive multiple of 4."; + if (position() % modulus == 0) { + return; + } + int offset = modulus - position() % modulus; + for (int i = 0; i < offset; i += 4) { + nop(); + } + } + + /** + * Patches jump targets when label gets bound. + */ + @Override + protected void patchJumpTarget(int branch, int jumpTarget) { + int instruction = getInt(branch); + int branchOffset = jumpTarget - branch; + PatchLabelKind type = PatchLabelKind.fromEncoding(instruction); + switch (type) { + case BRANCH_CONDITIONALLY: + ConditionFlag cf = ConditionFlag.fromEncoding(instruction >>> PatchLabelKind.INFORMATION_OFFSET); + super.b(cf, branchOffset, branch); + break; + case BRANCH_UNCONDITIONALLY: + super.b(branchOffset, branch); + break; + case JUMP_ADDRESS: + emitInt(jumpTarget, branch); + break; + case BRANCH_NONZERO: + case BRANCH_ZERO: { + int information = instruction >>> PatchLabelKind.INFORMATION_OFFSET; + int sizeEncoding = information & 1; + int regEncoding = information >>> 1; + Register reg = AArch64.cpuRegisters.get(regEncoding); + // 1 => 64; 0 => 32 + int size = sizeEncoding * 32 + 32; + switch (type) { + case BRANCH_NONZERO: + super.cbnz(size, reg, branchOffset, branch); + break; + case BRANCH_ZERO: + super.cbz(size, reg, branchOffset, branch); + break; + } + break; + } + case ADR: { + int information = instruction >>> PatchLabelKind.INFORMATION_OFFSET; + int regEncoding = information; + Register reg = AArch64.cpuRegisters.get(regEncoding); + super.adr(reg, branchOffset, branch); + break; + } + default: + throw GraalError.shouldNotReachHere(); + } + } + + /** + * Generates an address of the form {@code base + displacement}. + * + * Does not change base register to fulfill this requirement. Will fail if displacement cannot + * be represented directly as address. + * + * @param base general purpose register. May not be null or the zero register. + * @param displacement arbitrary displacement added to base. + * @return AArch64Address referencing memory at {@code base + displacement}. + */ + @Override + public AArch64Address makeAddress(Register base, int displacement) { + return makeAddress(base, displacement, zr, /* signExtend */false, /* transferSize */0, zr, /* allowOverwrite */false); + } + + @Override + public AbstractAddress getPlaceholder(int instructionStartPosition) { + return AArch64Address.PLACEHOLDER; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/BitOpsTest.java 2016-12-07 13:47:32.400300169 -0800 @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2013, 2016, 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.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.LZCNT; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TZCNT; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static org.junit.Assume.assumeTrue; + +import java.lang.reflect.Field; +import java.util.EnumSet; + +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; + +import org.junit.Before; +import org.junit.Test; + +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; + +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 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; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/IncrementDecrementMacroTest.java 2016-12-07 13:47:32.665311813 -0800 @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2015, 2016, 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); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/SimpleAssemblerTest.java 2016-12-07 13:47:32.931323502 -0800 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2013, 2016, 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 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; + +import org.junit.Before; +import org.junit.Test; + +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; + +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; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Address.java 2016-12-07 13:47:33.196335146 -0800 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2010, 2015, 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 jdk.vm.ci.code.Register; + +import org.graalvm.compiler.asm.AbstractAddress; + +/** + * 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 + * 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; + + 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: + return null; + } + } + + 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: + return null; + } + } + } + + @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; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64AsmOptions.java 2016-12-07 13:47:33.461346791 -0800 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2012, 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 UseIncDec = true; + public static final boolean UseXmmLoadAndClearUpper = true; + public static final boolean UseXmmRegToRegMoveAll = true; +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java 2016-12-07 13:47:33.726358435 -0800 @@ -0,0 +1,3750 @@ +/* + * Copyright (c) 2009, 2016, 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.NumUtil.isByte; +import static org.graalvm.compiler.asm.NumUtil.isInt; +import static org.graalvm.compiler.asm.NumUtil.isShiftCount; +import static org.graalvm.compiler.asm.NumUtil.isUByte; +import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseAddressNop; +import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseNormalNop; +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.OR; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SBB; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SUB; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR; +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.AMD64Assembler.AMD64MOp.NEG; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.NOT; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.BYTE; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PS; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SS; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD; +import static jdk.vm.ci.amd64.AMD64.CPU; +import static jdk.vm.ci.amd64.AMD64.XMM; +import static jdk.vm.ci.amd64.AMD64.r12; +import static jdk.vm.ci.amd64.AMD64.r13; +import static jdk.vm.ci.amd64.AMD64.rbp; +import static jdk.vm.ci.amd64.AMD64.rip; +import static jdk.vm.ci.amd64.AMD64.rsp; +import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD; + +import org.graalvm.compiler.asm.Assembler; +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.Register.RegisterCategory; +import jdk.vm.ci.code.TargetDescription; + +/** + * This class implements an assembler that can encode most X86 instructions. + */ +public class AMD64Assembler extends Assembler { + + private static final int MinEncodingNeedsRex = 8; + + /** + * The x86 condition codes used for conditional jumps/moves. + */ + public enum ConditionFlag { + Zero(0x4, "|zero|"), + NotZero(0x5, "|nzero|"), + Equal(0x4, "="), + NotEqual(0x5, "!="), + Less(0xc, "<"), + LessEqual(0xe, "<="), + Greater(0xf, ">"), + GreaterEqual(0xd, ">="), + Below(0x2, "|<|"), + BelowEqual(0x6, "|<=|"), + Above(0x7, "|>|"), + AboveEqual(0x3, "|>=|"), + Overflow(0x0, "|of|"), + NoOverflow(0x1, "|nof|"), + CarrySet(0x2, "|carry|"), + CarryClear(0x3, "|ncarry|"), + Negative(0x8, "|neg|"), + Positive(0x9, "|pos|"), + Parity(0xa, "|par|"), + NoParity(0xb, "|npar|"); + + private final int value; + private final String operator; + + ConditionFlag(int value, String operator) { + this.value = value; + this.operator = operator; + } + + public ConditionFlag negate() { + switch (this) { + case Zero: + return NotZero; + case NotZero: + return Zero; + case Equal: + return NotEqual; + case NotEqual: + return Equal; + case Less: + return GreaterEqual; + case LessEqual: + return Greater; + case Greater: + return LessEqual; + case GreaterEqual: + return Less; + case Below: + return AboveEqual; + case BelowEqual: + return Above; + case Above: + return BelowEqual; + case AboveEqual: + return Below; + case Overflow: + return NoOverflow; + case NoOverflow: + return Overflow; + case CarrySet: + return CarryClear; + case CarryClear: + return CarrySet; + case Negative: + return Positive; + case Positive: + return Negative; + case Parity: + return NoParity; + case NoParity: + return Parity; + } + throw new IllegalArgumentException(); + } + + public int getValue() { + return value; + } + + @Override + public String toString() { + return operator; + } + } + + /** + * Constants for X86 prefix bytes. + */ + private static class Prefix { + private static final int REX = 0x40; + private static final int REXB = 0x41; + private static final int REXX = 0x42; + private static final int REXXB = 0x43; + private static final int REXR = 0x44; + private static final int REXRB = 0x45; + private static final int REXRX = 0x46; + private static final int REXRXB = 0x47; + private static final int REXW = 0x48; + private static final int REXWB = 0x49; + private static final int REXWX = 0x4A; + private static final int REXWXB = 0x4B; + private static final int REXWR = 0x4C; + private static final int REXWRB = 0x4D; + private static final int REXWRX = 0x4E; + private static final int REXWRXB = 0x4F; + private static final int VEX_3BYTES = 0xC4; + private static final int VEX_2BYTES = 0xC5; + } + + private static class VexPrefix { + private static final int VEX_R = 0x80; + private static final int VEX_W = 0x80; + } + + private static class AvxVectorLen { + private static final int AVX_128bit = 0x0; + private static final int AVX_256bit = 0x1; + } + + private static class VexSimdPrefix { + private static final int VEX_SIMD_NONE = 0x0; + private static final int VEX_SIMD_66 = 0x1; + private static final int VEX_SIMD_F3 = 0x2; + private static final int VEX_SIMD_F2 = 0x3; + } + + private static class VexOpcode { + private static final int VEX_OPCODE_NONE = 0x0; + private static final int VEX_OPCODE_0F = 0x1; + private static final int VEX_OPCODE_0F_38 = 0x2; + private static final int VEX_OPCODE_0F_3A = 0x3; + } + + private AMD64InstructionAttr curAttributes; + + AMD64InstructionAttr getCurAttributes() { + return curAttributes; + } + + void setCurAttributes(AMD64InstructionAttr attributes) { + curAttributes = attributes; + } + + /** + * The x86 operand sizes. + */ + public enum OperandSize { + BYTE(1) { + @Override + protected void emitImmediate(AMD64Assembler asm, int imm) { + assert imm == (byte) imm; + asm.emitByte(imm); + } + + @Override + protected int immediateSize() { + return 1; + } + }, + + WORD(2, 0x66) { + @Override + protected void emitImmediate(AMD64Assembler asm, int imm) { + assert imm == (short) imm; + asm.emitShort(imm); + } + + @Override + protected int immediateSize() { + return 2; + } + }, + + DWORD(4) { + @Override + protected void emitImmediate(AMD64Assembler asm, int imm) { + asm.emitInt(imm); + } + + @Override + protected int immediateSize() { + return 4; + } + }, + + QWORD(8) { + @Override + protected void emitImmediate(AMD64Assembler asm, int imm) { + asm.emitInt(imm); + } + + @Override + protected int immediateSize() { + return 4; + } + }, + + SS(4, 0xF3, true), + + SD(8, 0xF2, true), + + PS(16, true), + + PD(16, 0x66, true); + + private final int sizePrefix; + + private final int bytes; + private final boolean xmm; + + OperandSize(int bytes) { + this(bytes, 0); + } + + OperandSize(int bytes, int sizePrefix) { + this(bytes, sizePrefix, false); + } + + OperandSize(int bytes, boolean xmm) { + this(bytes, 0, xmm); + } + + OperandSize(int bytes, int sizePrefix, boolean xmm) { + this.sizePrefix = sizePrefix; + this.bytes = bytes; + this.xmm = xmm; + } + + public int getBytes() { + return bytes; + } + + public boolean isXmmType() { + return xmm; + } + + /** + * Emit an immediate of this size. Note that immediate {@link #QWORD} operands are encoded + * as sign-extended 32-bit values. + * + * @param asm + * @param imm + */ + protected void emitImmediate(AMD64Assembler asm, int imm) { + throw new UnsupportedOperationException(); + } + + protected int immediateSize() { + throw new UnsupportedOperationException(); + } + } + + /** + * Operand size and register type constraints. + */ + private enum OpAssertion { + ByteAssertion(CPU, CPU, BYTE), + IntegerAssertion(CPU, CPU, WORD, DWORD, QWORD), + No16BitAssertion(CPU, CPU, DWORD, QWORD), + No32BitAssertion(CPU, CPU, WORD, QWORD), + QwordOnlyAssertion(CPU, CPU, QWORD), + FloatingAssertion(XMM, XMM, SS, SD, PS, PD), + PackedFloatingAssertion(XMM, XMM, PS, PD), + SingleAssertion(XMM, XMM, SS), + DoubleAssertion(XMM, XMM, SD), + PackedDoubleAssertion(XMM, XMM, PD), + IntToFloatingAssertion(XMM, CPU, DWORD, QWORD), + FloatingToIntAssertion(CPU, XMM, DWORD, QWORD); + + private final RegisterCategory resultCategory; + private final RegisterCategory inputCategory; + private final OperandSize[] allowedSizes; + + OpAssertion(RegisterCategory resultCategory, RegisterCategory inputCategory, OperandSize... allowedSizes) { + this.resultCategory = resultCategory; + this.inputCategory = inputCategory; + this.allowedSizes = allowedSizes; + } + + protected boolean checkOperands(AMD64Op op, OperandSize size, Register resultReg, Register inputReg) { + assert resultReg == null || resultCategory.equals(resultReg.getRegisterCategory()) : "invalid result register " + resultReg + " used in " + op; + assert inputReg == null || inputCategory.equals(inputReg.getRegisterCategory()) : "invalid input register " + inputReg + " used in " + op; + + for (OperandSize s : allowedSizes) { + if (size == s) { + return true; + } + } + + assert false : "invalid operand size " + size + " used in " + op; + return false; + } + } + + public abstract static class OperandDataAnnotation extends CodeAnnotation { + /** + * The position (bytes from the beginning of the method) of the operand. + */ + public final int operandPosition; + /** + * The size of the operand, in bytes. + */ + public final int operandSize; + /** + * The position (bytes from the beginning of the method) of the next instruction. On AMD64, + * RIP-relative operands are relative to this position. + */ + public final int nextInstructionPosition; + + OperandDataAnnotation(int instructionPosition, int operandPosition, int operandSize, int nextInstructionPosition) { + super(instructionPosition); + + this.operandPosition = operandPosition; + this.operandSize = operandSize; + this.nextInstructionPosition = nextInstructionPosition; + } + + @Override + public String toString() { + return getClass().getSimpleName() + " instruction [" + instructionPosition + ", " + nextInstructionPosition + "[ operand at " + operandPosition + " size " + operandSize; + } + } + + /** + * Annotation that stores additional information about the displacement of a + * {@link Assembler#getPlaceholder placeholder address} that needs patching. + */ + public static class AddressDisplacementAnnotation extends OperandDataAnnotation { + AddressDisplacementAnnotation(int instructionPosition, int operandPosition, int operndSize, int nextInstructionPosition) { + super(instructionPosition, operandPosition, operndSize, nextInstructionPosition); + } + } + + /** + * Annotation that stores additional information about the immediate operand, e.g., of a call + * instruction, that needs patching. + */ + public static class ImmediateOperandAnnotation extends OperandDataAnnotation { + ImmediateOperandAnnotation(int instructionPosition, int operandPosition, int operndSize, int nextInstructionPosition) { + super(instructionPosition, operandPosition, operndSize, nextInstructionPosition); + } + } + + /** + * Constructs an assembler for the AMD64 architecture. + */ + public AMD64Assembler(TargetDescription target) { + super(target); + } + + public boolean supports(CPUFeature feature) { + return ((AMD64) target.arch).getFeatures().contains(feature); + } + + private static int encode(Register r) { + assert r.encoding < 16 && r.encoding >= 0 : "encoding out of range: " + r.encoding; + return r.encoding & 0x7; + } + + /** + * Get RXB bits for register-register instruction. In that encoding, ModRM.rm contains a + * register index. The R bit extends the ModRM.reg field and the B bit extends the ModRM.rm + * field. The X bit must be 0. + */ + protected static int getRXB(Register reg, Register rm) { + int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1; + rxb |= (rm == null ? 0 : rm.encoding & 0x08) >> 3; + return rxb; + } + + /** + * Get RXB bits for register-memory instruction. The R bit extends the ModRM.reg field. There + * are two cases for the memory operand:
+ * ModRM.rm contains the base register: In that case, B extends the ModRM.rm field and X = 0. + *
+ * There is an SIB byte: In that case, X extends SIB.index and B extends SIB.base. + */ + protected static int getRXB(Register reg, AMD64Address rm) { + int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1; + if (!rm.getIndex().equals(Register.None)) { + rxb |= (rm.getIndex().encoding & 0x08) >> 2; + } + if (!rm.getBase().equals(Register.None)) { + rxb |= (rm.getBase().encoding & 0x08) >> 3; + } + return rxb; + } + + /** + * Emit the ModR/M byte for one register operand and an opcode extension in the R field. + *

+ * Format: [ 11 reg r/m ] + */ + protected void emitModRM(int reg, Register rm) { + assert (reg & 0x07) == reg; + emitByte(0xC0 | (reg << 3) | (rm.encoding & 0x07)); + } + + /** + * Emit the ModR/M byte for two register operands. + *

+ * Format: [ 11 reg r/m ] + */ + protected void emitModRM(Register reg, Register rm) { + emitModRM(reg.encoding & 0x07, rm); + } + + protected void emitOperandHelper(Register reg, AMD64Address addr, int additionalInstructionSize) { + assert !reg.equals(Register.None); + emitOperandHelper(encode(reg), addr, false, additionalInstructionSize); + } + + /** + * Emits the ModR/M byte and optionally the SIB byte for one register and one memory operand. + * + * @param force4Byte use 4 byte encoding for displacements that would normally fit in a byte + */ + protected void emitOperandHelper(Register reg, AMD64Address addr, boolean force4Byte, int additionalInstructionSize) { + assert !reg.equals(Register.None); + emitOperandHelper(encode(reg), addr, force4Byte, additionalInstructionSize); + } + + protected void emitOperandHelper(int reg, AMD64Address addr, int additionalInstructionSize) { + emitOperandHelper(reg, addr, false, additionalInstructionSize); + } + + /** + * Emits the ModR/M byte and optionally the SIB byte for one memory operand and an opcode + * extension in the R field. + * + * @param force4Byte use 4 byte encoding for displacements that would normally fit in a byte + * @param additionalInstructionSize the number of bytes that will be emitted after the operand, + * so that the start position of the next instruction can be computed even though + * this instruction has not been completely emitted yet. + */ + protected void emitOperandHelper(int reg, AMD64Address addr, boolean force4Byte, int additionalInstructionSize) { + assert (reg & 0x07) == reg; + int regenc = reg << 3; + + Register base = addr.getBase(); + Register index = addr.getIndex(); + + AMD64Address.Scale scale = addr.getScale(); + int disp = addr.getDisplacement(); + + if (base.equals(AMD64.rip)) { // also matches addresses returned by getPlaceholder() + // [00 000 101] disp32 + assert index.equals(Register.None) : "cannot use RIP relative addressing with index register"; + emitByte(0x05 | regenc); + if (codePatchingAnnotationConsumer != null && addr.instructionStartPosition >= 0) { + codePatchingAnnotationConsumer.accept(new AddressDisplacementAnnotation(addr.instructionStartPosition, position(), 4, position() + 4 + additionalInstructionSize)); + } + emitInt(disp); + } else if (base.isValid()) { + int baseenc = base.isValid() ? encode(base) : 0; + if (index.isValid()) { + int indexenc = encode(index) << 3; + // [base + indexscale + disp] + if (disp == 0 && !base.equals(rbp) && !base.equals(r13)) { + // [base + indexscale] + // [00 reg 100][ss index base] + assert !index.equals(rsp) : "illegal addressing mode"; + emitByte(0x04 | regenc); + emitByte(scale.log2 << 6 | indexenc | baseenc); + } else if (isByte(disp) && !force4Byte) { + // [base + indexscale + imm8] + // [01 reg 100][ss index base] imm8 + assert !index.equals(rsp) : "illegal addressing mode"; + emitByte(0x44 | regenc); + emitByte(scale.log2 << 6 | indexenc | baseenc); + emitByte(disp & 0xFF); + } else { + // [base + indexscale + disp32] + // [10 reg 100][ss index base] disp32 + assert !index.equals(rsp) : "illegal addressing mode"; + emitByte(0x84 | regenc); + emitByte(scale.log2 << 6 | indexenc | baseenc); + emitInt(disp); + } + } else if (base.equals(rsp) || base.equals(r12)) { + // [rsp + disp] + if (disp == 0) { + // [rsp] + // [00 reg 100][00 100 100] + emitByte(0x04 | regenc); + emitByte(0x24); + } else if (isByte(disp) && !force4Byte) { + // [rsp + imm8] + // [01 reg 100][00 100 100] disp8 + emitByte(0x44 | regenc); + emitByte(0x24); + emitByte(disp & 0xFF); + } else { + // [rsp + imm32] + // [10 reg 100][00 100 100] disp32 + emitByte(0x84 | regenc); + emitByte(0x24); + emitInt(disp); + } + } else { + // [base + disp] + assert !base.equals(rsp) && !base.equals(r12) : "illegal addressing mode"; + if (disp == 0 && !base.equals(rbp) && !base.equals(r13)) { + // [base] + // [00 reg base] + emitByte(0x00 | regenc | baseenc); + } else if (isByte(disp) && !force4Byte) { + // [base + disp8] + // [01 reg base] disp8 + emitByte(0x40 | regenc | baseenc); + emitByte(disp & 0xFF); + } else { + // [base + disp32] + // [10 reg base] disp32 + emitByte(0x80 | regenc | baseenc); + emitInt(disp); + } + } + } else { + if (index.isValid()) { + int indexenc = encode(index) << 3; + // [indexscale + disp] + // [00 reg 100][ss index 101] disp32 + assert !index.equals(rsp) : "illegal addressing mode"; + emitByte(0x04 | regenc); + emitByte(scale.log2 << 6 | indexenc | 0x05); + emitInt(disp); + } else { + // [disp] ABSOLUTE + // [00 reg 100][00 100 101] disp32 + emitByte(0x04 | regenc); + emitByte(0x25); + emitInt(disp); + } + } + setCurAttributes(null); + } + + /** + * Base class for AMD64 opcodes. + */ + public static class AMD64Op { + + protected static final int P_0F = 0x0F; + protected static final int P_0F38 = 0x380F; + protected static final int P_0F3A = 0x3A0F; + + private final String opcode; + + protected final int prefix1; + protected final int prefix2; + protected final int op; + + private final boolean dstIsByte; + private final boolean srcIsByte; + + private final OpAssertion assertion; + private final CPUFeature feature; + + protected AMD64Op(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) { + this(opcode, prefix1, prefix2, op, assertion == OpAssertion.ByteAssertion, assertion == OpAssertion.ByteAssertion, assertion, feature); + } + + protected AMD64Op(String opcode, int prefix1, int prefix2, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion, CPUFeature feature) { + this.opcode = opcode; + this.prefix1 = prefix1; + this.prefix2 = prefix2; + this.op = op; + + this.dstIsByte = dstIsByte; + this.srcIsByte = srcIsByte; + + this.assertion = assertion; + this.feature = feature; + } + + protected final void emitOpcode(AMD64Assembler asm, OperandSize size, int rxb, int dstEnc, int srcEnc) { + if (prefix1 != 0) { + asm.emitByte(prefix1); + } + if (size.sizePrefix != 0) { + asm.emitByte(size.sizePrefix); + } + int rexPrefix = 0x40 | rxb; + if (size == QWORD) { + rexPrefix |= 0x08; + } + if (rexPrefix != 0x40 || (dstIsByte && dstEnc >= 4) || (srcIsByte && srcEnc >= 4)) { + asm.emitByte(rexPrefix); + } + if (prefix2 > 0xFF) { + asm.emitShort(prefix2); + } else if (prefix2 > 0) { + asm.emitByte(prefix2); + } + asm.emitByte(op); + } + + protected final boolean verify(AMD64Assembler asm, OperandSize size, Register resultReg, Register inputReg) { + assert feature == null || asm.supports(feature) : String.format("unsupported feature %s required for %s", feature, opcode); + assert assertion.checkOperands(this, size, resultReg, inputReg); + return true; + } + + @Override + public String toString() { + return opcode; + } + } + + /** + * Base class for AMD64 opcodes with immediate operands. + */ + public static class AMD64ImmOp extends AMD64Op { + + private final boolean immIsByte; + + protected AMD64ImmOp(String opcode, boolean immIsByte, int prefix, int op, OpAssertion assertion) { + super(opcode, 0, prefix, op, assertion, null); + this.immIsByte = immIsByte; + } + + protected final void emitImmediate(AMD64Assembler asm, OperandSize size, int imm) { + if (immIsByte) { + assert imm == (byte) imm; + asm.emitByte(imm); + } else { + size.emitImmediate(asm, imm); + } + } + + protected final int immediateSize(OperandSize size) { + if (immIsByte) { + return 1; + } else { + return size.bytes; + } + } + } + + /** + * Opcode with operand order of either RM or MR for 2 address forms. + */ + public abstract static class AMD64RROp extends AMD64Op { + + protected AMD64RROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) { + super(opcode, prefix1, prefix2, op, assertion, feature); + } + + protected AMD64RROp(String opcode, int prefix1, int prefix2, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion, CPUFeature feature) { + super(opcode, prefix1, prefix2, op, dstIsByte, srcIsByte, assertion, feature); + } + + public abstract void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src); + } + + /** + * Opcode with operand order of either RM or MR for 3 address forms. + */ + public abstract static class AMD64RRROp extends AMD64Op { + + protected AMD64RRROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) { + super(opcode, prefix1, prefix2, op, assertion, feature); + } + + protected AMD64RRROp(String opcode, int prefix1, int prefix2, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion, CPUFeature feature) { + super(opcode, prefix1, prefix2, op, dstIsByte, srcIsByte, assertion, feature); + } + + public abstract void emit(AMD64Assembler asm, OperandSize size, Register dst, Register nds, Register src); + } + + /** + * Opcode with operand order of RM. + */ + public static class AMD64RMOp extends AMD64RROp { + // @formatter:off + public static final AMD64RMOp IMUL = new AMD64RMOp("IMUL", P_0F, 0xAF); + public static final AMD64RMOp BSF = new AMD64RMOp("BSF", P_0F, 0xBC); + public static final AMD64RMOp BSR = new AMD64RMOp("BSR", P_0F, 0xBD); + public static final AMD64RMOp POPCNT = new AMD64RMOp("POPCNT", 0xF3, P_0F, 0xB8, CPUFeature.POPCNT); + public static final AMD64RMOp TZCNT = new AMD64RMOp("TZCNT", 0xF3, P_0F, 0xBC, CPUFeature.BMI1); + public static final AMD64RMOp LZCNT = new AMD64RMOp("LZCNT", 0xF3, P_0F, 0xBD, CPUFeature.LZCNT); + public static final AMD64RMOp MOVZXB = new AMD64RMOp("MOVZXB", P_0F, 0xB6, false, true, OpAssertion.IntegerAssertion); + public static final AMD64RMOp MOVZX = new AMD64RMOp("MOVZX", P_0F, 0xB7, OpAssertion.No16BitAssertion); + public static final AMD64RMOp MOVSXB = new AMD64RMOp("MOVSXB", P_0F, 0xBE, false, true, OpAssertion.IntegerAssertion); + public static final AMD64RMOp MOVSX = new AMD64RMOp("MOVSX", P_0F, 0xBF, OpAssertion.No16BitAssertion); + public static final AMD64RMOp MOVSXD = new AMD64RMOp("MOVSXD", 0x63, OpAssertion.QwordOnlyAssertion); + public static final AMD64RMOp MOVB = new AMD64RMOp("MOVB", 0x8A, OpAssertion.ByteAssertion); + public static final AMD64RMOp MOV = new AMD64RMOp("MOV", 0x8B); + + // MOVD/MOVQ and MOVSS/MOVSD are the same opcode, just with different operand size prefix + public static final AMD64RMOp MOVD = new AMD64RMOp("MOVD", 0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); + public static final AMD64RMOp MOVQ = new AMD64RMOp("MOVQ", 0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); + public static final AMD64RMOp MOVSS = new AMD64RMOp("MOVSS", P_0F, 0x10, OpAssertion.FloatingAssertion, CPUFeature.SSE); + public static final AMD64RMOp MOVSD = new AMD64RMOp("MOVSD", P_0F, 0x10, OpAssertion.FloatingAssertion, CPUFeature.SSE); + + // TEST is documented as MR operation, but it's symmetric, and using it as RM operation is more convenient. + public static final AMD64RMOp TESTB = new AMD64RMOp("TEST", 0x84, OpAssertion.ByteAssertion); + public static final AMD64RMOp TEST = new AMD64RMOp("TEST", 0x85); + // @formatter:on + + protected AMD64RMOp(String opcode, int op) { + this(opcode, 0, op); + } + + protected AMD64RMOp(String opcode, int op, OpAssertion assertion) { + this(opcode, 0, op, assertion); + } + + protected AMD64RMOp(String opcode, int prefix, int op) { + this(opcode, 0, prefix, op, null); + } + + protected AMD64RMOp(String opcode, int prefix, int op, OpAssertion assertion) { + this(opcode, 0, prefix, op, assertion, null); + } + + protected AMD64RMOp(String opcode, int prefix, int op, OpAssertion assertion, CPUFeature feature) { + this(opcode, 0, prefix, op, assertion, feature); + } + + protected AMD64RMOp(String opcode, int prefix, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion) { + super(opcode, 0, prefix, op, dstIsByte, srcIsByte, assertion, null); + } + + protected AMD64RMOp(String opcode, int prefix1, int prefix2, int op, CPUFeature feature) { + this(opcode, prefix1, prefix2, op, OpAssertion.IntegerAssertion, feature); + } + + protected AMD64RMOp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) { + super(opcode, prefix1, prefix2, op, assertion, feature); + } + + @Override + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src) { + assert verify(asm, size, dst, src); + boolean isSimd = false; + boolean noNds = false; + + switch (op) { + case 0x2A: + case 0x2C: + case 0x2E: + case 0x5A: + case 0x6E: + isSimd = true; + noNds = true; + break; + case 0x10: + case 0x51: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + isSimd = true; + break; + } + + if (isSimd) { + int pre; + int opc; + boolean rexVexW = (size == QWORD) ? true : false; + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); + int curPrefix = size.sizePrefix | prefix1; + switch (curPrefix) { + case 0x66: + pre = VexSimdPrefix.VEX_SIMD_66; + break; + case 0xF2: + pre = VexSimdPrefix.VEX_SIMD_F2; + break; + case 0xF3: + pre = VexSimdPrefix.VEX_SIMD_F3; + break; + default: + pre = VexSimdPrefix.VEX_SIMD_NONE; + break; + } + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + opc = VexOpcode.VEX_OPCODE_NONE; + break; + } + int encode; + if (noNds) { + encode = asm.simdPrefixAndEncode(dst, Register.None, src, pre, opc, attributes); + } else { + encode = asm.simdPrefixAndEncode(dst, dst, src, pre, opc, attributes); + } + asm.emitByte(op); + asm.emitByte(0xC0 | encode); + } else { + emitOpcode(asm, size, getRXB(dst, src), dst.encoding, src.encoding); + asm.emitModRM(dst, src); + } + } + + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, AMD64Address src) { + assert verify(asm, size, dst, null); + boolean isSimd = false; + boolean noNds = false; + + switch (op) { + case 0x10: + case 0x2A: + case 0x2C: + case 0x2E: + case 0x6E: + isSimd = true; + noNds = true; + break; + case 0x51: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + isSimd = true; + break; + } + + if (isSimd) { + int pre; + int opc; + boolean rexVexW = (size == QWORD) ? true : false; + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); + int curPrefix = size.sizePrefix | prefix1; + switch (curPrefix) { + case 0x66: + pre = VexSimdPrefix.VEX_SIMD_66; + break; + case 0xF2: + pre = VexSimdPrefix.VEX_SIMD_F2; + break; + case 0xF3: + pre = VexSimdPrefix.VEX_SIMD_F3; + break; + default: + pre = VexSimdPrefix.VEX_SIMD_NONE; + break; + } + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + opc = VexOpcode.VEX_OPCODE_NONE; + break; + } + if (noNds) { + asm.simdPrefix(dst, Register.None, src, pre, opc, attributes); + } else { + asm.simdPrefix(dst, dst, src, pre, opc, attributes); + } + asm.emitByte(op); + asm.emitOperandHelper(dst, src, 0); + } else { + emitOpcode(asm, size, getRXB(dst, src), dst.encoding, 0); + asm.emitOperandHelper(dst, src, 0); + } + } + } + + /** + * Opcode with operand order of RM. + */ + public static class AMD64RRMOp extends AMD64RRROp { + protected AMD64RRMOp(String opcode, int op) { + this(opcode, 0, op); + } + + protected AMD64RRMOp(String opcode, int op, OpAssertion assertion) { + this(opcode, 0, op, assertion); + } + + protected AMD64RRMOp(String opcode, int prefix, int op) { + this(opcode, 0, prefix, op, null); + } + + protected AMD64RRMOp(String opcode, int prefix, int op, OpAssertion assertion) { + this(opcode, 0, prefix, op, assertion, null); + } + + protected AMD64RRMOp(String opcode, int prefix, int op, OpAssertion assertion, CPUFeature feature) { + this(opcode, 0, prefix, op, assertion, feature); + } + + protected AMD64RRMOp(String opcode, int prefix, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion) { + super(opcode, 0, prefix, op, dstIsByte, srcIsByte, assertion, null); + } + + protected AMD64RRMOp(String opcode, int prefix1, int prefix2, int op, CPUFeature feature) { + this(opcode, prefix1, prefix2, op, OpAssertion.IntegerAssertion, feature); + } + + protected AMD64RRMOp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) { + super(opcode, prefix1, prefix2, op, assertion, feature); + } + + @Override + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register nds, Register src) { + assert verify(asm, size, dst, src); + int pre; + int opc; + boolean rexVexW = (size == QWORD) ? true : false; + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); + int curPrefix = size.sizePrefix | prefix1; + switch (curPrefix) { + case 0x66: + pre = VexSimdPrefix.VEX_SIMD_66; + break; + case 0xF2: + pre = VexSimdPrefix.VEX_SIMD_F2; + break; + case 0xF3: + pre = VexSimdPrefix.VEX_SIMD_F3; + break; + default: + pre = VexSimdPrefix.VEX_SIMD_NONE; + break; + } + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + opc = VexOpcode.VEX_OPCODE_NONE; + break; + } + int encode; + encode = asm.simdPrefixAndEncode(dst, nds, src, pre, opc, attributes); + asm.emitByte(op); + asm.emitByte(0xC0 | encode); + } + + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register nds, AMD64Address src) { + assert verify(asm, size, dst, null); + int pre; + int opc; + boolean rexVexW = (size == QWORD) ? true : false; + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); + int curPrefix = size.sizePrefix | prefix1; + switch (curPrefix) { + case 0x66: + pre = VexSimdPrefix.VEX_SIMD_66; + break; + case 0xF2: + pre = VexSimdPrefix.VEX_SIMD_F2; + break; + case 0xF3: + pre = VexSimdPrefix.VEX_SIMD_F3; + break; + default: + pre = VexSimdPrefix.VEX_SIMD_NONE; + break; + } + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + opc = VexOpcode.VEX_OPCODE_NONE; + break; + } + asm.simdPrefix(dst, nds, src, pre, opc, attributes); + asm.emitByte(op); + asm.emitOperandHelper(dst, src, 0); + } + } + + /** + * Opcode with operand order of MR. + */ + public static class AMD64MROp extends AMD64RROp { + // @formatter:off + public static final AMD64MROp MOVB = new AMD64MROp("MOVB", 0x88, OpAssertion.ByteAssertion); + public static final AMD64MROp MOV = new AMD64MROp("MOV", 0x89); + + // MOVD and MOVQ are the same opcode, just with different operand size prefix + // Note that as MR opcodes, they have reverse operand order, so the IntToFloatingAssertion must be used. + public static final AMD64MROp MOVD = new AMD64MROp("MOVD", 0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); + public static final AMD64MROp MOVQ = new AMD64MROp("MOVQ", 0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); + + // MOVSS and MOVSD are the same opcode, just with different operand size prefix + public static final AMD64MROp MOVSS = new AMD64MROp("MOVSS", P_0F, 0x11, OpAssertion.FloatingAssertion, CPUFeature.SSE); + public static final AMD64MROp MOVSD = new AMD64MROp("MOVSD", P_0F, 0x11, OpAssertion.FloatingAssertion, CPUFeature.SSE); + // @formatter:on + + protected AMD64MROp(String opcode, int op) { + this(opcode, 0, op); + } + + protected AMD64MROp(String opcode, int op, OpAssertion assertion) { + this(opcode, 0, op, assertion); + } + + protected AMD64MROp(String opcode, int prefix, int op) { + this(opcode, prefix, op, OpAssertion.IntegerAssertion); + } + + protected AMD64MROp(String opcode, int prefix, int op, OpAssertion assertion) { + this(opcode, prefix, op, assertion, null); + } + + protected AMD64MROp(String opcode, int prefix, int op, OpAssertion assertion, CPUFeature feature) { + this(opcode, 0, prefix, op, assertion, feature); + } + + protected AMD64MROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) { + super(opcode, prefix1, prefix2, op, assertion, feature); + } + + @Override + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src) { + assert verify(asm, size, src, dst); + boolean isSimd = false; + boolean noNds = false; + + switch (op) { + case 0x7E: + isSimd = true; + noNds = true; + break; + case 0x11: + isSimd = true; + break; + } + + if (isSimd) { + int pre; + int opc; + boolean rexVexW = (size == QWORD) ? true : false; + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); + int curPrefix = size.sizePrefix | prefix1; + switch (curPrefix) { + case 0x66: + pre = VexSimdPrefix.VEX_SIMD_66; + break; + case 0xF2: + pre = VexSimdPrefix.VEX_SIMD_F2; + break; + case 0xF3: + pre = VexSimdPrefix.VEX_SIMD_F3; + break; + default: + pre = VexSimdPrefix.VEX_SIMD_NONE; + break; + } + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + opc = VexOpcode.VEX_OPCODE_NONE; + break; + } + int encode; + if (noNds) { + encode = asm.simdPrefixAndEncode(src, Register.None, dst, pre, opc, attributes); + } else { + encode = asm.simdPrefixAndEncode(src, src, dst, pre, opc, attributes); + } + asm.emitByte(op); + asm.emitByte(0xC0 | encode); + } else { + emitOpcode(asm, size, getRXB(src, dst), src.encoding, dst.encoding); + asm.emitModRM(src, dst); + } + } + + public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst, Register src) { + assert verify(asm, size, null, src); + boolean isSimd = false; + + switch (op) { + case 0x7E: + case 0x11: + isSimd = true; + break; + } + + if (isSimd) { + int pre; + int opc; + boolean rexVexW = (size == QWORD) ? true : false; + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); + int curPrefix = size.sizePrefix | prefix1; + switch (curPrefix) { + case 0x66: + pre = VexSimdPrefix.VEX_SIMD_66; + break; + case 0xF2: + pre = VexSimdPrefix.VEX_SIMD_F2; + break; + case 0xF3: + pre = VexSimdPrefix.VEX_SIMD_F3; + break; + default: + pre = VexSimdPrefix.VEX_SIMD_NONE; + break; + } + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + opc = VexOpcode.VEX_OPCODE_NONE; + break; + } + asm.simdPrefix(src, Register.None, dst, pre, opc, attributes); + asm.emitByte(op); + asm.emitOperandHelper(src, dst, 0); + } else { + emitOpcode(asm, size, getRXB(src, dst), src.encoding, 0); + asm.emitOperandHelper(src, dst, 0); + } + } + } + + /** + * Opcodes with operand order of M. + */ + public static class AMD64MOp extends AMD64Op { + // @formatter:off + public static final AMD64MOp NOT = new AMD64MOp("NOT", 0xF7, 2); + public static final AMD64MOp NEG = new AMD64MOp("NEG", 0xF7, 3); + public static final AMD64MOp MUL = new AMD64MOp("MUL", 0xF7, 4); + public static final AMD64MOp IMUL = new AMD64MOp("IMUL", 0xF7, 5); + public static final AMD64MOp DIV = new AMD64MOp("DIV", 0xF7, 6); + public static final AMD64MOp IDIV = new AMD64MOp("IDIV", 0xF7, 7); + public static final AMD64MOp INC = new AMD64MOp("INC", 0xFF, 0); + public static final AMD64MOp DEC = new AMD64MOp("DEC", 0xFF, 1); + public static final AMD64MOp PUSH = new AMD64MOp("PUSH", 0xFF, 6); + public static final AMD64MOp POP = new AMD64MOp("POP", 0x8F, 0, OpAssertion.No32BitAssertion); + // @formatter:on + + private final int ext; + + protected AMD64MOp(String opcode, int op, int ext) { + this(opcode, 0, op, ext); + } + + protected AMD64MOp(String opcode, int prefix, int op, int ext) { + this(opcode, prefix, op, ext, OpAssertion.IntegerAssertion); + } + + protected AMD64MOp(String opcode, int op, int ext, OpAssertion assertion) { + this(opcode, 0, op, ext, assertion); + } + + protected AMD64MOp(String opcode, int prefix, int op, int ext, OpAssertion assertion) { + super(opcode, 0, prefix, op, assertion, null); + this.ext = ext; + } + + public final void emit(AMD64Assembler asm, OperandSize size, Register dst) { + assert verify(asm, size, dst, null); + emitOpcode(asm, size, getRXB(null, dst), 0, dst.encoding); + asm.emitModRM(ext, dst); + } + + public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst) { + assert verify(asm, size, null, null); + emitOpcode(asm, size, getRXB(null, dst), 0, 0); + asm.emitOperandHelper(ext, dst, 0); + } + } + + /** + * Opcodes with operand order of MI. + */ + public static class AMD64MIOp extends AMD64ImmOp { + // @formatter:off + public static final AMD64MIOp MOVB = new AMD64MIOp("MOVB", true, 0xC6, 0, OpAssertion.ByteAssertion); + public static final AMD64MIOp MOV = new AMD64MIOp("MOV", false, 0xC7, 0); + public static final AMD64MIOp TEST = new AMD64MIOp("TEST", false, 0xF7, 0); + // @formatter:on + + private final int ext; + + protected AMD64MIOp(String opcode, boolean immIsByte, int op, int ext) { + this(opcode, immIsByte, op, ext, OpAssertion.IntegerAssertion); + } + + protected AMD64MIOp(String opcode, boolean immIsByte, int op, int ext, OpAssertion assertion) { + this(opcode, immIsByte, 0, op, ext, assertion); + } + + protected AMD64MIOp(String opcode, boolean immIsByte, int prefix, int op, int ext, OpAssertion assertion) { + super(opcode, immIsByte, prefix, op, assertion); + this.ext = ext; + } + + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, int imm) { + assert verify(asm, size, dst, null); + emitOpcode(asm, size, getRXB(null, dst), 0, dst.encoding); + asm.emitModRM(ext, dst); + emitImmediate(asm, size, imm); + } + + public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst, int imm) { + assert verify(asm, size, null, null); + emitOpcode(asm, size, getRXB(null, dst), 0, 0); + asm.emitOperandHelper(ext, dst, immediateSize(size)); + emitImmediate(asm, size, imm); + } + } + + /** + * Opcodes with operand order of RMI. + * + * We only have one form of round as the operation is always treated with single variant input, + * making its extension to 3 address forms redundant. + */ + public static class AMD64RMIOp extends AMD64ImmOp { + // @formatter:off + public static final AMD64RMIOp IMUL = new AMD64RMIOp("IMUL", false, 0x69); + public static final AMD64RMIOp IMUL_SX = new AMD64RMIOp("IMUL", true, 0x6B); + public static final AMD64RMIOp ROUNDSS = new AMD64RMIOp("ROUNDSS", true, P_0F3A, 0x0A, OpAssertion.PackedDoubleAssertion); + public static final AMD64RMIOp ROUNDSD = new AMD64RMIOp("ROUNDSD", true, P_0F3A, 0x0B, OpAssertion.PackedDoubleAssertion); + // @formatter:on + + protected AMD64RMIOp(String opcode, boolean immIsByte, int op) { + this(opcode, immIsByte, 0, op, OpAssertion.IntegerAssertion); + } + + protected AMD64RMIOp(String opcode, boolean immIsByte, int prefix, int op, OpAssertion assertion) { + super(opcode, immIsByte, prefix, op, assertion); + } + + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src, int imm) { + assert verify(asm, size, dst, src); + boolean isSimd = false; + boolean noNds = false; + + switch (op) { + case 0x0A: + case 0x0B: + isSimd = true; + noNds = true; + break; + } + + if (isSimd) { + int pre; + int opc; + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); + int curPrefix = size.sizePrefix | prefix1; + switch (curPrefix) { + case 0x66: + pre = VexSimdPrefix.VEX_SIMD_66; + break; + case 0xF2: + pre = VexSimdPrefix.VEX_SIMD_F2; + break; + case 0xF3: + pre = VexSimdPrefix.VEX_SIMD_F3; + break; + default: + pre = VexSimdPrefix.VEX_SIMD_NONE; + break; + } + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + opc = VexOpcode.VEX_OPCODE_NONE; + break; + } + int encode; + if (noNds) { + encode = asm.simdPrefixAndEncode(dst, Register.None, src, pre, opc, attributes); + } else { + encode = asm.simdPrefixAndEncode(dst, dst, src, pre, opc, attributes); + } + asm.emitByte(op); + asm.emitByte(0xC0 | encode); + emitImmediate(asm, size, imm); + } else { + emitOpcode(asm, size, getRXB(dst, src), dst.encoding, src.encoding); + asm.emitModRM(dst, src); + emitImmediate(asm, size, imm); + } + } + + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, AMD64Address src, int imm) { + assert verify(asm, size, dst, null); + + boolean isSimd = false; + boolean noNds = false; + + switch (op) { + case 0x0A: + case 0x0B: + isSimd = true; + noNds = true; + break; + } + + if (isSimd) { + int pre; + int opc; + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); + int curPrefix = size.sizePrefix | prefix1; + switch (curPrefix) { + case 0x66: + pre = VexSimdPrefix.VEX_SIMD_66; + break; + case 0xF2: + pre = VexSimdPrefix.VEX_SIMD_F2; + break; + case 0xF3: + pre = VexSimdPrefix.VEX_SIMD_F3; + break; + default: + pre = VexSimdPrefix.VEX_SIMD_NONE; + break; + } + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + opc = VexOpcode.VEX_OPCODE_NONE; + break; + } + + if (noNds) { + asm.simdPrefix(dst, Register.None, src, pre, opc, attributes); + } else { + asm.simdPrefix(dst, dst, src, pre, opc, attributes); + } + asm.emitByte(op); + asm.emitOperandHelper(dst, src, immediateSize(size)); + emitImmediate(asm, size, imm); + } else { + emitOpcode(asm, size, getRXB(dst, src), dst.encoding, 0); + asm.emitOperandHelper(dst, src, immediateSize(size)); + emitImmediate(asm, size, imm); + } + } + } + + public static class SSEOp extends AMD64RMOp { + // @formatter:off + public static final SSEOp CVTSI2SS = new SSEOp("CVTSI2SS", 0xF3, P_0F, 0x2A, OpAssertion.IntToFloatingAssertion); + public static final SSEOp CVTSI2SD = new SSEOp("CVTSI2SS", 0xF2, P_0F, 0x2A, OpAssertion.IntToFloatingAssertion); + public static final SSEOp CVTTSS2SI = new SSEOp("CVTTSS2SI", 0xF3, P_0F, 0x2C, OpAssertion.FloatingToIntAssertion); + public static final SSEOp CVTTSD2SI = new SSEOp("CVTTSD2SI", 0xF2, P_0F, 0x2C, OpAssertion.FloatingToIntAssertion); + public static final SSEOp UCOMIS = new SSEOp("UCOMIS", P_0F, 0x2E, OpAssertion.PackedFloatingAssertion); + public static final SSEOp SQRT = new SSEOp("SQRT", P_0F, 0x51); + public static final SSEOp AND = new SSEOp("AND", P_0F, 0x54, OpAssertion.PackedFloatingAssertion); + public static final SSEOp ANDN = new SSEOp("ANDN", P_0F, 0x55, OpAssertion.PackedFloatingAssertion); + public static final SSEOp OR = new SSEOp("OR", P_0F, 0x56, OpAssertion.PackedFloatingAssertion); + public static final SSEOp XOR = new SSEOp("XOR", P_0F, 0x57, OpAssertion.PackedFloatingAssertion); + public static final SSEOp ADD = new SSEOp("ADD", P_0F, 0x58); + public static final SSEOp MUL = new SSEOp("MUL", P_0F, 0x59); + public static final SSEOp CVTSS2SD = new SSEOp("CVTSS2SD", P_0F, 0x5A, OpAssertion.SingleAssertion); + public static final SSEOp CVTSD2SS = new SSEOp("CVTSD2SS", P_0F, 0x5A, OpAssertion.DoubleAssertion); + public static final SSEOp SUB = new SSEOp("SUB", P_0F, 0x5C); + public static final SSEOp MIN = new SSEOp("MIN", P_0F, 0x5D); + public static final SSEOp DIV = new SSEOp("DIV", P_0F, 0x5E); + public static final SSEOp MAX = new SSEOp("MAX", P_0F, 0x5F); + // @formatter:on + + protected SSEOp(String opcode, int prefix, int op) { + this(opcode, prefix, op, OpAssertion.FloatingAssertion); + } + + protected SSEOp(String opcode, int prefix, int op, OpAssertion assertion) { + this(opcode, 0, prefix, op, assertion); + } + + protected SSEOp(String opcode, int mandatoryPrefix, int prefix, int op, OpAssertion assertion) { + super(opcode, mandatoryPrefix, prefix, op, assertion, CPUFeature.SSE2); + } + } + + public static class AVXOp extends AMD64RRMOp { + // @formatter:off + public static final AVXOp AND = new AVXOp("AND", P_0F, 0x54, OpAssertion.PackedFloatingAssertion); + public static final AVXOp ANDN = new AVXOp("ANDN", P_0F, 0x55, OpAssertion.PackedFloatingAssertion); + public static final AVXOp OR = new AVXOp("OR", P_0F, 0x56, OpAssertion.PackedFloatingAssertion); + public static final AVXOp XOR = new AVXOp("XOR", P_0F, 0x57, OpAssertion.PackedFloatingAssertion); + public static final AVXOp ADD = new AVXOp("ADD", P_0F, 0x58); + public static final AVXOp MUL = new AVXOp("MUL", P_0F, 0x59); + public static final AVXOp SUB = new AVXOp("SUB", P_0F, 0x5C); + public static final AVXOp MIN = new AVXOp("MIN", P_0F, 0x5D); + public static final AVXOp DIV = new AVXOp("DIV", P_0F, 0x5E); + public static final AVXOp MAX = new AVXOp("MAX", P_0F, 0x5F); + // @formatter:on + + protected AVXOp(String opcode, int prefix, int op) { + this(opcode, prefix, op, OpAssertion.FloatingAssertion); + } + + protected AVXOp(String opcode, int prefix, int op, OpAssertion assertion) { + this(opcode, 0, prefix, op, assertion); + } + + protected AVXOp(String opcode, int mandatoryPrefix, int prefix, int op, OpAssertion assertion) { + super(opcode, mandatoryPrefix, prefix, op, assertion, CPUFeature.AVX); + } + } + + /** + * Arithmetic operation with operand order of RM, MR or MI. + */ + public static final class AMD64BinaryArithmetic { + // @formatter:off + public static final AMD64BinaryArithmetic ADD = new AMD64BinaryArithmetic("ADD", 0); + public static final AMD64BinaryArithmetic OR = new AMD64BinaryArithmetic("OR", 1); + public static final AMD64BinaryArithmetic ADC = new AMD64BinaryArithmetic("ADC", 2); + public static final AMD64BinaryArithmetic SBB = new AMD64BinaryArithmetic("SBB", 3); + public static final AMD64BinaryArithmetic AND = new AMD64BinaryArithmetic("AND", 4); + public static final AMD64BinaryArithmetic SUB = new AMD64BinaryArithmetic("SUB", 5); + public static final AMD64BinaryArithmetic XOR = new AMD64BinaryArithmetic("XOR", 6); + public static final AMD64BinaryArithmetic CMP = new AMD64BinaryArithmetic("CMP", 7); + // @formatter:on + + private final AMD64MIOp byteImmOp; + private final AMD64MROp byteMrOp; + private final AMD64RMOp byteRmOp; + + private final AMD64MIOp immOp; + private final AMD64MIOp immSxOp; + private final AMD64MROp mrOp; + private final AMD64RMOp rmOp; + + private AMD64BinaryArithmetic(String opcode, int code) { + int baseOp = code << 3; + + byteImmOp = new AMD64MIOp(opcode, true, 0, 0x80, code, OpAssertion.ByteAssertion); + byteMrOp = new AMD64MROp(opcode, 0, baseOp, OpAssertion.ByteAssertion); + byteRmOp = new AMD64RMOp(opcode, 0, baseOp | 0x02, OpAssertion.ByteAssertion); + + immOp = new AMD64MIOp(opcode, false, 0, 0x81, code, OpAssertion.IntegerAssertion); + immSxOp = new AMD64MIOp(opcode, true, 0, 0x83, code, OpAssertion.IntegerAssertion); + mrOp = new AMD64MROp(opcode, 0, baseOp | 0x01, OpAssertion.IntegerAssertion); + rmOp = new AMD64RMOp(opcode, 0, baseOp | 0x03, OpAssertion.IntegerAssertion); + } + + public AMD64MIOp getMIOpcode(OperandSize size, boolean sx) { + if (size == BYTE) { + return byteImmOp; + } else if (sx) { + return immSxOp; + } else { + return immOp; + } + } + + public AMD64MROp getMROpcode(OperandSize size) { + if (size == BYTE) { + return byteMrOp; + } else { + return mrOp; + } + } + + public AMD64RMOp getRMOpcode(OperandSize size) { + if (size == BYTE) { + return byteRmOp; + } else { + return rmOp; + } + } + } + + /** + * Shift operation with operand order of M1, MC or MI. + */ + public static final class AMD64Shift { + // @formatter:off + public static final AMD64Shift ROL = new AMD64Shift("ROL", 0); + public static final AMD64Shift ROR = new AMD64Shift("ROR", 1); + public static final AMD64Shift RCL = new AMD64Shift("RCL", 2); + public static final AMD64Shift RCR = new AMD64Shift("RCR", 3); + public static final AMD64Shift SHL = new AMD64Shift("SHL", 4); + public static final AMD64Shift SHR = new AMD64Shift("SHR", 5); + public static final AMD64Shift SAR = new AMD64Shift("SAR", 7); + // @formatter:on + + public final AMD64MOp m1Op; + public final AMD64MOp mcOp; + public final AMD64MIOp miOp; + + private AMD64Shift(String opcode, int code) { + m1Op = new AMD64MOp(opcode, 0, 0xD1, code, OpAssertion.IntegerAssertion); + mcOp = new AMD64MOp(opcode, 0, 0xD3, code, OpAssertion.IntegerAssertion); + miOp = new AMD64MIOp(opcode, true, 0, 0xC1, code, OpAssertion.IntegerAssertion); + } + } + + public final void addl(AMD64Address dst, int imm32) { + ADD.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); + } + + public final void addl(Register dst, int imm32) { + ADD.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); + } + + public final void addl(Register dst, Register src) { + ADD.rmOp.emit(this, DWORD, dst, src); + } + + public final void addpd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x58); + emitByte(0xC0 | encode); + } + + public final void addpd(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x58); + emitOperandHelper(dst, src, 0); + } + + public final void addsd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x58); + emitByte(0xC0 | encode); + } + + public final void addsd(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x58); + emitOperandHelper(dst, src, 0); + } + + private void addrNop4() { + // 4 bytes: NOP DWORD PTR [EAX+0] + emitByte(0x0F); + emitByte(0x1F); + emitByte(0x40); // emitRm(cbuf, 0x1, EAXEnc, EAXEnc); + emitByte(0); // 8-bits offset (1 byte) + } + + private void addrNop5() { + // 5 bytes: NOP DWORD PTR [EAX+EAX*0+0] 8-bits offset + emitByte(0x0F); + emitByte(0x1F); + emitByte(0x44); // emitRm(cbuf, 0x1, EAXEnc, 0x4); + emitByte(0x00); // emitRm(cbuf, 0x0, EAXEnc, EAXEnc); + emitByte(0); // 8-bits offset (1 byte) + } + + private void addrNop7() { + // 7 bytes: NOP DWORD PTR [EAX+0] 32-bits offset + emitByte(0x0F); + emitByte(0x1F); + emitByte(0x80); // emitRm(cbuf, 0x2, EAXEnc, EAXEnc); + emitInt(0); // 32-bits offset (4 bytes) + } + + private void addrNop8() { + // 8 bytes: NOP DWORD PTR [EAX+EAX*0+0] 32-bits offset + emitByte(0x0F); + emitByte(0x1F); + emitByte(0x84); // emitRm(cbuf, 0x2, EAXEnc, 0x4); + emitByte(0x00); // emitRm(cbuf, 0x0, EAXEnc, EAXEnc); + emitInt(0); // 32-bits offset (4 bytes) + } + + public final void andl(Register dst, int imm32) { + AND.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); + } + + public final void andl(Register dst, Register src) { + AND.rmOp.emit(this, DWORD, dst, src); + } + + public final void andpd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x54); + emitByte(0xC0 | encode); + } + + public final void andpd(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x54); + emitOperandHelper(dst, src, 0); + } + + public final void bsrl(Register dst, Register src) { + int encode = prefixAndEncode(dst.encoding(), src.encoding()); + emitByte(0x0F); + emitByte(0xBD); + emitByte(0xC0 | encode); + } + + public final void bswapl(Register reg) { + int encode = prefixAndEncode(reg.encoding); + emitByte(0x0F); + emitByte(0xC8 | encode); + } + + public final void cdql() { + emitByte(0x99); + } + + public final void cmovl(ConditionFlag cc, Register dst, Register src) { + int encode = prefixAndEncode(dst.encoding, src.encoding); + emitByte(0x0F); + emitByte(0x40 | cc.getValue()); + emitByte(0xC0 | encode); + } + + public final void cmovl(ConditionFlag cc, Register dst, AMD64Address src) { + prefix(src, dst); + emitByte(0x0F); + emitByte(0x40 | cc.getValue()); + emitOperandHelper(dst, src, 0); + } + + public final void cmpl(Register dst, int imm32) { + CMP.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); + } + + public final void cmpl(Register dst, Register src) { + CMP.rmOp.emit(this, DWORD, dst, src); + } + + public final void cmpl(Register dst, AMD64Address src) { + CMP.rmOp.emit(this, DWORD, dst, src); + } + + public final void cmpl(AMD64Address dst, int imm32) { + CMP.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); + } + + // The 32-bit cmpxchg compares the value at adr with the contents of X86.rax, + // and stores reg into adr if so; otherwise, the value at adr is loaded into X86.rax,. + // The ZF is set if the compared values were equal, and cleared otherwise. + public final void cmpxchgl(Register reg, AMD64Address adr) { // cmpxchg + prefix(adr, reg); + emitByte(0x0F); + emitByte(0xB1); + emitOperandHelper(reg, adr, 0); + } + + public final void cvtsi2sdl(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.CPU); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x2A); + emitByte(0xC0 | encode); + } + + public final void cvttsd2sil(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.CPU) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x2C); + emitByte(0xC0 | encode); + } + + protected final void decl(AMD64Address dst) { + prefix(dst); + emitByte(0xFF); + emitOperandHelper(1, dst, 0); + } + + public final void divsd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x5E); + emitByte(0xC0 | encode); + } + + public final void hlt() { + emitByte(0xF4); + } + + public final void imull(Register dst, Register src, int value) { + if (isByte(value)) { + AMD64RMIOp.IMUL_SX.emit(this, DWORD, dst, src, value); + } else { + AMD64RMIOp.IMUL.emit(this, DWORD, dst, src, value); + } + } + + protected final void incl(AMD64Address dst) { + prefix(dst); + emitByte(0xFF); + emitOperandHelper(0, dst, 0); + } + + public void jcc(ConditionFlag cc, int jumpTarget, boolean forceDisp32) { + int shortSize = 2; + int longSize = 6; + long disp = jumpTarget - position(); + if (!forceDisp32 && isByte(disp - shortSize)) { + // 0111 tttn #8-bit disp + emitByte(0x70 | cc.getValue()); + emitByte((int) ((disp - shortSize) & 0xFF)); + } else { + // 0000 1111 1000 tttn #32-bit disp + assert isInt(disp - longSize) : "must be 32bit offset (call4)"; + emitByte(0x0F); + emitByte(0x80 | cc.getValue()); + emitInt((int) (disp - longSize)); + } + } + + public final void jcc(ConditionFlag cc, Label l) { + assert (0 <= cc.getValue()) && (cc.getValue() < 16) : "illegal cc"; + if (l.isBound()) { + jcc(cc, l.position(), false); + } else { + // Note: could eliminate cond. jumps to this jump if condition + // is the same however, seems to be rather unlikely case. + // Note: use jccb() if label to be bound is very close to get + // an 8-bit displacement + l.addPatchAt(position()); + emitByte(0x0F); + emitByte(0x80 | cc.getValue()); + emitInt(0); + } + + } + + public final void jccb(ConditionFlag cc, Label l) { + if (l.isBound()) { + int shortSize = 2; + int entry = l.position(); + assert isByte(entry - (position() + shortSize)) : "Dispacement too large for a short jmp"; + long disp = entry - position(); + // 0111 tttn #8-bit disp + emitByte(0x70 | cc.getValue()); + emitByte((int) ((disp - shortSize) & 0xFF)); + } else { + l.addPatchAt(position()); + emitByte(0x70 | cc.getValue()); + emitByte(0); + } + } + + public final void jmp(int jumpTarget, boolean forceDisp32) { + int shortSize = 2; + int longSize = 5; + long disp = jumpTarget - position(); + if (!forceDisp32 && isByte(disp - shortSize)) { + emitByte(0xEB); + emitByte((int) ((disp - shortSize) & 0xFF)); + } else { + emitByte(0xE9); + emitInt((int) (disp - longSize)); + } + } + + @Override + public final void jmp(Label l) { + if (l.isBound()) { + jmp(l.position(), false); + } else { + // By default, forward jumps are always 32-bit displacements, since + // we can't yet know where the label will be bound. If you're sure that + // the forward jump will not run beyond 256 bytes, use jmpb to + // force an 8-bit displacement. + + l.addPatchAt(position()); + emitByte(0xE9); + emitInt(0); + } + } + + public final void jmp(Register entry) { + int encode = prefixAndEncode(entry.encoding); + emitByte(0xFF); + emitByte(0xE0 | encode); + } + + public final void jmp(AMD64Address adr) { + prefix(adr); + emitByte(0xFF); + emitOperandHelper(rsp, adr, 0); + } + + public final void jmpb(Label l) { + if (l.isBound()) { + int shortSize = 2; + int entry = l.position(); + assert isByte((entry - position()) + shortSize) : "Dispacement too large for a short jmp"; + long offs = entry - position(); + emitByte(0xEB); + emitByte((int) ((offs - shortSize) & 0xFF)); + } else { + + l.addPatchAt(position()); + emitByte(0xEB); + emitByte(0); + } + } + + public final void leaq(Register dst, AMD64Address src) { + prefixq(src, dst); + emitByte(0x8D); + emitOperandHelper(dst, src, 0); + } + + public final void leave() { + emitByte(0xC9); + } + + public final void lock() { + emitByte(0xF0); + } + + public final void movapd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x28); + emitByte(0xC0 | encode); + } + + public final void movaps(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x28); + emitByte(0xC0 | encode); + } + + public final void movb(AMD64Address dst, int imm8) { + prefix(dst); + emitByte(0xC6); + emitOperandHelper(0, dst, 1); + emitByte(imm8); + } + + public final void movb(AMD64Address dst, Register src) { + assert src.getRegisterCategory().equals(AMD64.CPU) : "must have byte register"; + prefix(dst, src, true); + emitByte(0x88); + emitOperandHelper(src, dst, 0); + } + + public final void movl(Register dst, int imm32) { + int encode = prefixAndEncode(dst.encoding); + emitByte(0xB8 | encode); + emitInt(imm32); + } + + public final void movl(Register dst, Register src) { + int encode = prefixAndEncode(dst.encoding, src.encoding); + emitByte(0x8B); + emitByte(0xC0 | encode); + } + + public final void movl(Register dst, AMD64Address src) { + prefix(src, dst); + emitByte(0x8B); + emitOperandHelper(dst, src, 0); + } + + public final void movl(AMD64Address dst, int imm32) { + prefix(dst); + emitByte(0xC7); + emitOperandHelper(0, dst, 4); + emitInt(imm32); + } + + public final void movl(AMD64Address dst, Register src) { + prefix(dst, src); + emitByte(0x89); + emitOperandHelper(src, dst, 0); + } + + /** + * New CPUs require use of movsd and movss to avoid partial register stall when loading from + * memory. But for old Opteron use movlpd instead of movsd. The selection is done in + * {@link AMD64MacroAssembler#movdbl(Register, AMD64Address)} and + * {@link AMD64MacroAssembler#movflt(Register, Register)}. + */ + public final void movlpd(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x12); + emitOperandHelper(dst, src, 0); + } + + public final void movlhps(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, src, src, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x16); + emitByte(0xC0 | encode); + } + + public final void movq(Register dst, AMD64Address src) { + movq(dst, src, false); + } + + public final void movq(Register dst, AMD64Address src, boolean wide) { + if (dst.getRegisterCategory().equals(AMD64.XMM)) { + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ wide, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x7E); + emitOperandHelper(dst, src, wide, 0); + } else { + // gpr version of movq + prefixq(src, dst); + emitByte(0x8B); + emitOperandHelper(dst, src, wide, 0); + } + } + + public final void movq(Register dst, Register src) { + int encode = prefixqAndEncode(dst.encoding, src.encoding); + emitByte(0x8B); + emitByte(0xC0 | encode); + } + + public final void movq(AMD64Address dst, Register src) { + if (src.getRegisterCategory().equals(AMD64.XMM)) { + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xD6); + emitOperandHelper(src, dst, 0); + } else { + // gpr version of movq + prefixq(dst, src); + emitByte(0x89); + emitOperandHelper(src, dst, 0); + } + } + + public final void movsbl(Register dst, AMD64Address src) { + prefix(src, dst); + emitByte(0x0F); + emitByte(0xBE); + emitOperandHelper(dst, src, 0); + } + + public final void movsbl(Register dst, Register src) { + int encode = prefixAndEncode(dst.encoding, false, src.encoding, true); + emitByte(0x0F); + emitByte(0xBE); + emitByte(0xC0 | encode); + } + + public final void movsbq(Register dst, AMD64Address src) { + prefixq(src, dst); + emitByte(0x0F); + emitByte(0xBE); + emitOperandHelper(dst, src, 0); + } + + public final void movsbq(Register dst, Register src) { + int encode = prefixqAndEncode(dst.encoding, src.encoding); + emitByte(0x0F); + emitByte(0xBE); + emitByte(0xC0 | encode); + } + + public final void movsd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x10); + emitByte(0xC0 | encode); + } + + public final void movsd(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x10); + emitOperandHelper(dst, src, 0); + } + + public final void movsd(AMD64Address dst, Register src) { + assert src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x11); + emitOperandHelper(src, dst, 0); + } + + public final void movss(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x10); + emitByte(0xC0 | encode); + } + + public final void movss(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x10); + emitOperandHelper(dst, src, 0); + } + + public final void movss(AMD64Address dst, Register src) { + assert src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x11); + emitOperandHelper(src, dst, 0); + } + + public final void mulpd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x59); + emitByte(0xC0 | encode); + } + + public final void mulpd(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x59); + emitOperandHelper(dst, src, 0); + } + + public final void mulsd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x59); + emitByte(0xC0 | encode); + } + + public final void mulsd(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x59); + emitOperandHelper(dst, src, 0); + } + + public final void mulss(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x59); + emitByte(0xC0 | encode); + } + + public final void movswl(Register dst, AMD64Address src) { + prefix(src, dst); + emitByte(0x0F); + emitByte(0xBF); + emitOperandHelper(dst, src, 0); + } + + public final void movw(AMD64Address dst, int imm16) { + emitByte(0x66); // switch to 16-bit mode + prefix(dst); + emitByte(0xC7); + emitOperandHelper(0, dst, 2); + emitShort(imm16); + } + + public final void movw(AMD64Address dst, Register src) { + emitByte(0x66); + prefix(dst, src); + emitByte(0x89); + emitOperandHelper(src, dst, 0); + } + + public final void movzbl(Register dst, AMD64Address src) { + prefix(src, dst); + emitByte(0x0F); + emitByte(0xB6); + emitOperandHelper(dst, src, 0); + } + + public final void movzwl(Register dst, AMD64Address src) { + prefix(src, dst); + emitByte(0x0F); + emitByte(0xB7); + emitOperandHelper(dst, src, 0); + } + + public final void negl(Register dst) { + NEG.emit(this, DWORD, dst); + } + + public final void notl(Register dst) { + NOT.emit(this, DWORD, dst); + } + + @Override + public final void ensureUniquePC() { + nop(); + } + + public final void nop() { + nop(1); + } + + public void nop(int count) { + int i = count; + if (UseNormalNop) { + assert i > 0 : " "; + // The fancy nops aren't currently recognized by debuggers making it a + // pain to disassemble code while debugging. If assert are on clearly + // speed is not an issue so simply use the single byte traditional nop + // to do alignment. + + for (; i > 0; i--) { + emitByte(0x90); + } + return; + } + + if (UseAddressNop) { + // + // Using multi-bytes nops "0x0F 0x1F [Address]" for AMD. + // 1: 0x90 + // 2: 0x66 0x90 + // 3: 0x66 0x66 0x90 (don't use "0x0F 0x1F 0x00" - need patching safe padding) + // 4: 0x0F 0x1F 0x40 0x00 + // 5: 0x0F 0x1F 0x44 0x00 0x00 + // 6: 0x66 0x0F 0x1F 0x44 0x00 0x00 + // 7: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00 + // 8: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 + // 9: 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 + // 10: 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 + // 11: 0x66 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 + + // The rest coding is AMD specific - use consecutive Address nops + + // 12: 0x66 0x0F 0x1F 0x44 0x00 0x00 0x66 0x0F 0x1F 0x44 0x00 0x00 + // 13: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00 0x66 0x0F 0x1F 0x44 0x00 0x00 + // 14: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00 + // 15: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00 + // 16: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 + // Size prefixes (0x66) are added for larger sizes + + while (i >= 22) { + i -= 11; + emitByte(0x66); // size prefix + emitByte(0x66); // size prefix + emitByte(0x66); // size prefix + addrNop8(); + } + // Generate first nop for size between 21-12 + switch (i) { + case 21: + i -= 11; + emitByte(0x66); // size prefix + emitByte(0x66); // size prefix + emitByte(0x66); // size prefix + addrNop8(); + break; + case 20: + case 19: + i -= 10; + emitByte(0x66); // size prefix + emitByte(0x66); // size prefix + addrNop8(); + break; + case 18: + case 17: + i -= 9; + emitByte(0x66); // size prefix + addrNop8(); + break; + case 16: + case 15: + i -= 8; + addrNop8(); + break; + case 14: + case 13: + i -= 7; + addrNop7(); + break; + case 12: + i -= 6; + emitByte(0x66); // size prefix + addrNop5(); + break; + default: + assert i < 12; + } + + // Generate second nop for size between 11-1 + switch (i) { + case 11: + emitByte(0x66); // size prefix + emitByte(0x66); // size prefix + emitByte(0x66); // size prefix + addrNop8(); + break; + case 10: + emitByte(0x66); // size prefix + emitByte(0x66); // size prefix + addrNop8(); + break; + case 9: + emitByte(0x66); // size prefix + addrNop8(); + break; + case 8: + addrNop8(); + break; + case 7: + addrNop7(); + break; + case 6: + emitByte(0x66); // size prefix + addrNop5(); + break; + case 5: + addrNop5(); + break; + case 4: + addrNop4(); + break; + case 3: + // Don't use "0x0F 0x1F 0x00" - need patching safe padding + emitByte(0x66); // size prefix + emitByte(0x66); // size prefix + emitByte(0x90); // nop + break; + case 2: + emitByte(0x66); // size prefix + emitByte(0x90); // nop + break; + case 1: + emitByte(0x90); // nop + break; + default: + assert i == 0; + } + return; + } + + // Using nops with size prefixes "0x66 0x90". + // From AMD Optimization Guide: + // 1: 0x90 + // 2: 0x66 0x90 + // 3: 0x66 0x66 0x90 + // 4: 0x66 0x66 0x66 0x90 + // 5: 0x66 0x66 0x90 0x66 0x90 + // 6: 0x66 0x66 0x90 0x66 0x66 0x90 + // 7: 0x66 0x66 0x66 0x90 0x66 0x66 0x90 + // 8: 0x66 0x66 0x66 0x90 0x66 0x66 0x66 0x90 + // 9: 0x66 0x66 0x90 0x66 0x66 0x90 0x66 0x66 0x90 + // 10: 0x66 0x66 0x66 0x90 0x66 0x66 0x90 0x66 0x66 0x90 + // + while (i > 12) { + i -= 4; + emitByte(0x66); // size prefix + emitByte(0x66); + emitByte(0x66); + emitByte(0x90); // nop + } + // 1 - 12 nops + if (i > 8) { + if (i > 9) { + i -= 1; + emitByte(0x66); + } + i -= 3; + emitByte(0x66); + emitByte(0x66); + emitByte(0x90); + } + // 1 - 8 nops + if (i > 4) { + if (i > 6) { + i -= 1; + emitByte(0x66); + } + i -= 3; + emitByte(0x66); + emitByte(0x66); + emitByte(0x90); + } + switch (i) { + case 4: + emitByte(0x66); + emitByte(0x66); + emitByte(0x66); + emitByte(0x90); + break; + case 3: + emitByte(0x66); + emitByte(0x66); + emitByte(0x90); + break; + case 2: + emitByte(0x66); + emitByte(0x90); + break; + case 1: + emitByte(0x90); + break; + default: + assert i == 0; + } + } + + public final void orl(Register dst, Register src) { + OR.rmOp.emit(this, DWORD, dst, src); + } + + public final void orl(Register dst, int imm32) { + OR.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); + } + + public final void pop(Register dst) { + int encode = prefixAndEncode(dst.encoding); + emitByte(0x58 | encode); + } + + public void popfq() { + emitByte(0x9D); + } + + public final void ptest(Register dst, Register src) { + assert supports(CPUFeature.SSE4_1); + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_38, attributes); + emitByte(0x17); + emitByte(0xC0 | encode); + } + + public final void vptest(Register dst, Register src) { + assert supports(CPUFeature.AVX); + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_256bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = vexPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_38, attributes); + emitByte(0x17); + emitByte(0xC0 | encode); + } + + public final void push(Register src) { + int encode = prefixAndEncode(src.encoding); + emitByte(0x50 | encode); + } + + public void pushfq() { + emitByte(0x9c); + } + + public final void paddd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xFE); + emitByte(0xC0 | encode); + } + + public final void paddq(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xD4); + emitByte(0xC0 | encode); + } + + public final void pextrw(Register dst, Register src, int imm8) { + assert dst.getRegisterCategory().equals(AMD64.CPU) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xC5); + emitByte(0xC0 | encode); + emitByte(imm8); + } + + public final void pinsrw(Register dst, Register src, int imm8) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.CPU); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xC4); + emitByte(0xC0 | encode); + emitByte(imm8); + } + + public final void por(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xEB); + emitByte(0xC0 | encode); + } + + public final void pand(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xDB); + emitByte(0xC0 | encode); + } + + public final void pxor(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xEF); + emitByte(0xC0 | encode); + } + + public final void vpxor(Register dst, Register nds, Register src) { + assert supports(CPUFeature.AVX); + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_256bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = vexPrefixAndEncode(dst, nds, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xEF); + emitByte(0xC0 | encode); + } + + public final void pslld(Register dst, int imm8) { + assert isUByte(imm8) : "invalid value"; + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + // XMM6 is for /6 encoding: 66 0F 72 /6 ib + int encode = simdPrefixAndEncode(AMD64.xmm6, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x72); + emitByte(0xC0 | encode); + emitByte(imm8 & 0xFF); + } + + public final void psllq(Register dst, Register shift) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && shift.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, shift, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xF3); + emitByte(0xC0 | encode); + } + + public final void psllq(Register dst, int imm8) { + assert isUByte(imm8) : "invalid value"; + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + // XMM6 is for /6 encoding: 66 0F 73 /6 ib + int encode = simdPrefixAndEncode(AMD64.xmm6, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x73); + emitByte(0xC0 | encode); + emitByte(imm8); + } + + public final void psrad(Register dst, int imm8) { + assert isUByte(imm8) : "invalid value"; + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + // XMM4 is for /2 encoding: 66 0F 72 /4 ib + int encode = simdPrefixAndEncode(AMD64.xmm4, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x72); + emitByte(0xC0 | encode); + emitByte(imm8); + } + + public final void psrld(Register dst, int imm8) { + assert isUByte(imm8) : "invalid value"; + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + // XMM2 is for /2 encoding: 66 0F 72 /2 ib + int encode = simdPrefixAndEncode(AMD64.xmm2, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x72); + emitByte(0xC0 | encode); + emitByte(imm8); + } + + public final void psrlq(Register dst, int imm8) { + assert isUByte(imm8) : "invalid value"; + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + // XMM2 is for /2 encoding: 66 0F 73 /2 ib + int encode = simdPrefixAndEncode(AMD64.xmm2, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x73); + emitByte(0xC0 | encode); + emitByte(imm8); + } + + public final void pshufd(Register dst, Register src, int imm8) { + assert isUByte(imm8) : "invalid value"; + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x70); + emitByte(0xC0 | encode); + emitByte(imm8); + } + + public final void psubd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xFA); + emitByte(0xC0 | encode); + } + + public final void rcpps(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ true, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x53); + emitByte(0xC0 | encode); + } + + public final void ret(int imm16) { + if (imm16 == 0) { + emitByte(0xC3); + } else { + emitByte(0xC2); + emitShort(imm16); + } + } + + public final void sarl(Register dst, int imm8) { + int encode = prefixAndEncode(dst.encoding); + assert isShiftCount(imm8 >> 1) : "illegal shift count"; + if (imm8 == 1) { + emitByte(0xD1); + emitByte(0xF8 | encode); + } else { + emitByte(0xC1); + emitByte(0xF8 | encode); + emitByte(imm8); + } + } + + public final void shll(Register dst, int imm8) { + assert isShiftCount(imm8 >> 1) : "illegal shift count"; + int encode = prefixAndEncode(dst.encoding); + if (imm8 == 1) { + emitByte(0xD1); + emitByte(0xE0 | encode); + } else { + emitByte(0xC1); + emitByte(0xE0 | encode); + emitByte(imm8); + } + } + + public final void shll(Register dst) { + int encode = prefixAndEncode(dst.encoding); + emitByte(0xD3); + emitByte(0xE0 | encode); + } + + public final void shrl(Register dst, int imm8) { + assert isShiftCount(imm8 >> 1) : "illegal shift count"; + int encode = prefixAndEncode(dst.encoding); + emitByte(0xC1); + emitByte(0xE8 | encode); + emitByte(imm8); + } + + public final void shrl(Register dst) { + int encode = prefixAndEncode(dst.encoding); + emitByte(0xD3); + emitByte(0xE8 | encode); + } + + public final void subl(AMD64Address dst, int imm32) { + SUB.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); + } + + public final void subl(Register dst, int imm32) { + SUB.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); + } + + public final void subl(Register dst, Register src) { + SUB.rmOp.emit(this, DWORD, dst, src); + } + + public final void subpd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x5C); + emitByte(0xC0 | encode); + } + + public final void subsd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x5C); + emitByte(0xC0 | encode); + } + + public final void subsd(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x5C); + emitOperandHelper(dst, src, 0); + } + + public final void testl(Register dst, int imm32) { + // not using emitArith because test + // doesn't support sign-extension of + // 8bit operands + int encode = dst.encoding; + if (encode == 0) { + emitByte(0xA9); + } else { + encode = prefixAndEncode(encode); + emitByte(0xF7); + emitByte(0xC0 | encode); + } + emitInt(imm32); + } + + public final void testl(Register dst, Register src) { + int encode = prefixAndEncode(dst.encoding, src.encoding); + emitByte(0x85); + emitByte(0xC0 | encode); + } + + public final void testl(Register dst, AMD64Address src) { + prefix(src, dst); + emitByte(0x85); + emitOperandHelper(dst, src, 0); + } + + public final void unpckhpd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x15); + emitByte(0xC0 | encode); + } + + public final void unpcklpd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x14); + emitByte(0xC0 | encode); + } + + public final void xorl(Register dst, Register src) { + XOR.rmOp.emit(this, DWORD, dst, src); + } + + public final void xorpd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x57); + emitByte(0xC0 | encode); + } + + public final void xorps(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x57); + emitByte(0xC0 | encode); + } + + protected final void decl(Register dst) { + // Use two-byte form (one-byte form is a REX prefix in 64-bit mode) + int encode = prefixAndEncode(dst.encoding); + emitByte(0xFF); + emitByte(0xC8 | encode); + } + + protected final void incl(Register dst) { + // Use two-byte form (one-byte from is a REX prefix in 64-bit mode) + int encode = prefixAndEncode(dst.encoding); + emitByte(0xFF); + emitByte(0xC0 | encode); + } + + private int prefixAndEncode(int regEnc) { + return prefixAndEncode(regEnc, false); + } + + private int prefixAndEncode(int regEnc, boolean byteinst) { + if (regEnc >= 8) { + emitByte(Prefix.REXB); + return regEnc - 8; + } else if (byteinst && regEnc >= 4) { + emitByte(Prefix.REX); + } + return regEnc; + } + + private int prefixqAndEncode(int regEnc) { + if (regEnc < 8) { + emitByte(Prefix.REXW); + return regEnc; + } else { + emitByte(Prefix.REXWB); + return regEnc - 8; + } + } + + private int prefixAndEncode(int dstEnc, int srcEnc) { + return prefixAndEncode(dstEnc, false, srcEnc, false); + } + + private int prefixAndEncode(int dstEncoding, boolean dstIsByte, int srcEncoding, boolean srcIsByte) { + int srcEnc = srcEncoding; + int dstEnc = dstEncoding; + if (dstEnc < 8) { + if (srcEnc >= 8) { + emitByte(Prefix.REXB); + srcEnc -= 8; + } else if ((srcIsByte && srcEnc >= 4) || (dstIsByte && dstEnc >= 4)) { + emitByte(Prefix.REX); + } + } else { + if (srcEnc < 8) { + emitByte(Prefix.REXR); + } else { + emitByte(Prefix.REXRB); + srcEnc -= 8; + } + dstEnc -= 8; + } + return dstEnc << 3 | srcEnc; + } + + /** + * Creates prefix and the encoding of the lower 6 bits of the ModRM-Byte. It emits an operand + * prefix. If the given operands exceed 3 bits, the 4th bit is encoded in the prefix. + * + * @param regEncoding the encoding of the register part of the ModRM-Byte + * @param rmEncoding the encoding of the r/m part of the ModRM-Byte + * @return the lower 6 bits of the ModRM-Byte that should be emitted + */ + private int prefixqAndEncode(int regEncoding, int rmEncoding) { + int rmEnc = rmEncoding; + int regEnc = regEncoding; + if (regEnc < 8) { + if (rmEnc < 8) { + emitByte(Prefix.REXW); + } else { + emitByte(Prefix.REXWB); + rmEnc -= 8; + } + } else { + if (rmEnc < 8) { + emitByte(Prefix.REXWR); + } else { + emitByte(Prefix.REXWRB); + rmEnc -= 8; + } + regEnc -= 8; + } + return regEnc << 3 | rmEnc; + } + + private void vexPrefix(int rxb, int ndsEncoding, int pre, int opc, AMD64InstructionAttr attributes) { + int vectorLen = attributes.getVectorLen(); + boolean vexW = attributes.isRexVexW(); + boolean isXorB = ((rxb & 0x3) > 0); + if (isXorB || vexW || (opc == VexOpcode.VEX_OPCODE_0F_38) || (opc == VexOpcode.VEX_OPCODE_0F_3A)) { + emitByte(Prefix.VEX_3BYTES); + + int byte1 = (rxb << 5); + byte1 = ((~byte1) & 0xE0) | opc; + emitByte(byte1); + + int byte2 = ((~ndsEncoding) & 0xf) << 3; + byte2 |= (vexW ? VexPrefix.VEX_W : 0) | ((vectorLen > 0) ? 4 : 0) | pre; + emitByte(byte2); + } else { + emitByte(Prefix.VEX_2BYTES); + + int byte1 = ((rxb & 0x4) > 0) ? VexPrefix.VEX_R : 0; + byte1 = (~byte1) & 0x80; + byte1 |= ((~ndsEncoding) & 0xf) << 3; + byte1 |= ((vectorLen > 0) ? 4 : 0) | pre; + emitByte(byte1); + } + } + + private void vexPrefix(AMD64Address adr, Register nds, Register src, int pre, int opc, AMD64InstructionAttr attributes) { + int rxb = getRXB(src, adr); + int ndsEncoding = nds.isValid() ? nds.encoding : 0; + vexPrefix(rxb, ndsEncoding, pre, opc, attributes); + setCurAttributes(attributes); + } + + private int vexPrefixAndEncode(Register dst, Register nds, Register src, int pre, int opc, AMD64InstructionAttr attributes) { + int rxb = getRXB(dst, src); + int ndsEncoding = nds.isValid() ? nds.encoding : 0; + vexPrefix(rxb, ndsEncoding, pre, opc, attributes); + // return modrm byte components for operands + return (((dst.encoding & 7) << 3) | (src.encoding & 7)); + } + + private void simdPrefix(Register xreg, Register nds, AMD64Address adr, int pre, int opc, AMD64InstructionAttr attributes) { + if (supports(CPUFeature.AVX)) { + vexPrefix(adr, nds, xreg, pre, opc, attributes); + } else { + switch (pre) { + case VexSimdPrefix.VEX_SIMD_66: + emitByte(0x66); + break; + case VexSimdPrefix.VEX_SIMD_F2: + emitByte(0xF2); + break; + case VexSimdPrefix.VEX_SIMD_F3: + emitByte(0xF3); + break; + } + if (attributes.isRexVexW()) { + prefixq(adr, xreg); + } else { + prefix(adr, xreg); + } + switch (opc) { + case VexOpcode.VEX_OPCODE_0F: + emitByte(0x0F); + break; + case VexOpcode.VEX_OPCODE_0F_38: + emitByte(0x0F); + emitByte(0x38); + break; + case VexOpcode.VEX_OPCODE_0F_3A: + emitByte(0x0F); + emitByte(0x3A); + break; + } + } + } + + private int simdPrefixAndEncode(Register dst, Register nds, Register src, int pre, int opc, AMD64InstructionAttr attributes) { + if (supports(CPUFeature.AVX)) { + return vexPrefixAndEncode(dst, nds, src, pre, opc, attributes); + } else { + switch (pre) { + case VexSimdPrefix.VEX_SIMD_66: + emitByte(0x66); + break; + case VexSimdPrefix.VEX_SIMD_F2: + emitByte(0xF2); + break; + case VexSimdPrefix.VEX_SIMD_F3: + emitByte(0xF3); + break; + } + int encode; + int dstEncoding = dst.encoding; + int srcEncoding = src.encoding; + if (attributes.isRexVexW()) { + encode = prefixqAndEncode(dstEncoding, srcEncoding); + } else { + encode = prefixAndEncode(dstEncoding, srcEncoding); + } + switch (opc) { + case VexOpcode.VEX_OPCODE_0F: + emitByte(0x0F); + break; + case VexOpcode.VEX_OPCODE_0F_38: + emitByte(0x0F); + emitByte(0x38); + break; + case VexOpcode.VEX_OPCODE_0F_3A: + emitByte(0x0F); + emitByte(0x3A); + break; + } + return encode; + } + } + + private static boolean needsRex(Register reg) { + return reg.encoding >= MinEncodingNeedsRex; + } + + private void prefix(AMD64Address adr) { + if (needsRex(adr.getBase())) { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXXB); + } else { + emitByte(Prefix.REXB); + } + } else { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXX); + } + } + } + + private void prefixq(AMD64Address adr) { + if (needsRex(adr.getBase())) { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXWXB); + } else { + emitByte(Prefix.REXWB); + } + } else { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXWX); + } else { + emitByte(Prefix.REXW); + } + } + } + + private void prefix(AMD64Address adr, Register reg) { + prefix(adr, reg, false); + } + + private void prefix(AMD64Address adr, Register reg, boolean byteinst) { + if (reg.encoding < 8) { + if (needsRex(adr.getBase())) { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXXB); + } else { + emitByte(Prefix.REXB); + } + } else { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXX); + } else if (byteinst && reg.encoding >= 4) { + emitByte(Prefix.REX); + } + } + } else { + if (needsRex(adr.getBase())) { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXRXB); + } else { + emitByte(Prefix.REXRB); + } + } else { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXRX); + } else { + emitByte(Prefix.REXR); + } + } + } + } + + private void prefixq(AMD64Address adr, Register src) { + if (src.encoding < 8) { + if (needsRex(adr.getBase())) { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXWXB); + } else { + emitByte(Prefix.REXWB); + } + } else { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXWX); + } else { + emitByte(Prefix.REXW); + } + } + } else { + if (needsRex(adr.getBase())) { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXWRXB); + } else { + emitByte(Prefix.REXWRB); + } + } else { + if (needsRex(adr.getIndex())) { + emitByte(Prefix.REXWRX); + } else { + emitByte(Prefix.REXWR); + } + } + } + } + + public final void addq(Register dst, int imm32) { + ADD.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32); + } + + public final void addq(AMD64Address dst, int imm32) { + ADD.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32); + } + + public final void addq(Register dst, Register src) { + ADD.rmOp.emit(this, QWORD, dst, src); + } + + public final void addq(AMD64Address dst, Register src) { + ADD.mrOp.emit(this, QWORD, dst, src); + } + + public final void andq(Register dst, int imm32) { + AND.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32); + } + + public final void bsrq(Register dst, Register src) { + int encode = prefixqAndEncode(dst.encoding(), src.encoding()); + emitByte(0x0F); + emitByte(0xBD); + emitByte(0xC0 | encode); + } + + public final void bswapq(Register reg) { + int encode = prefixqAndEncode(reg.encoding); + emitByte(0x0F); + emitByte(0xC8 | encode); + } + + public final void cdqq() { + emitByte(Prefix.REXW); + emitByte(0x99); + } + + public final void cmovq(ConditionFlag cc, Register dst, Register src) { + int encode = prefixqAndEncode(dst.encoding, src.encoding); + emitByte(0x0F); + emitByte(0x40 | cc.getValue()); + emitByte(0xC0 | encode); + } + + public final void cmovq(ConditionFlag cc, Register dst, AMD64Address src) { + prefixq(src, dst); + emitByte(0x0F); + emitByte(0x40 | cc.getValue()); + emitOperandHelper(dst, src, 0); + } + + public final void cmpq(Register dst, int imm32) { + CMP.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32); + } + + public final void cmpq(Register dst, Register src) { + CMP.rmOp.emit(this, QWORD, dst, src); + } + + public final void cmpq(Register dst, AMD64Address src) { + CMP.rmOp.emit(this, QWORD, dst, src); + } + + public final void cmpxchgq(Register reg, AMD64Address adr) { + prefixq(adr, reg); + emitByte(0x0F); + emitByte(0xB1); + emitOperandHelper(reg, adr, 0); + } + + public final void cvtdq2pd(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xE6); + emitByte(0xC0 | encode); + } + + public final void cvtsi2sdq(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.CPU); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x2A); + emitByte(0xC0 | encode); + } + + public final void cvttsd2siq(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.CPU) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x2C); + emitByte(0xC0 | encode); + } + + public final void cvttpd2dq(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0xE6); + emitByte(0xC0 | encode); + } + + protected final void decq(Register dst) { + // Use two-byte form (one-byte from is a REX prefix in 64-bit mode) + int encode = prefixqAndEncode(dst.encoding); + emitByte(0xFF); + emitByte(0xC8 | encode); + } + + public final void decq(AMD64Address dst) { + DEC.emit(this, QWORD, dst); + } + + public final void imulq(Register dst, Register src) { + int encode = prefixqAndEncode(dst.encoding, src.encoding); + emitByte(0x0F); + emitByte(0xAF); + emitByte(0xC0 | encode); + } + + public final void incq(Register dst) { + // Don't use it directly. Use Macroincrementq() instead. + // Use two-byte form (one-byte from is a REX prefix in 64-bit mode) + int encode = prefixqAndEncode(dst.encoding); + emitByte(0xFF); + emitByte(0xC0 | encode); + } + + public final void incq(AMD64Address dst) { + INC.emit(this, QWORD, dst); + } + + public final void movq(Register dst, long imm64) { + int encode = prefixqAndEncode(dst.encoding); + emitByte(0xB8 | encode); + emitLong(imm64); + } + + public final void movslq(Register dst, int imm32) { + int encode = prefixqAndEncode(dst.encoding); + emitByte(0xC7); + emitByte(0xC0 | encode); + emitInt(imm32); + } + + public final void movdq(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x6E); + emitOperandHelper(dst, src, 0); + } + + public final void movdq(AMD64Address dst, Register src) { + assert src.getRegisterCategory().equals(AMD64.XMM); + // swap src/dst to get correct prefix + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x7E); + emitOperandHelper(src, dst, 0); + } + + public final void movdq(Register dst, Register src) { + if (dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.CPU)) { + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x6E); + emitByte(0xC0 | encode); + } else if (src.getRegisterCategory().equals(AMD64.XMM) && dst.getRegisterCategory().equals(AMD64.CPU)) { + // swap src/dst to get correct prefix + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x7E); + emitByte(0xC0 | encode); + } else { + throw new InternalError("should not reach here"); + } + } + + public final void movdl(Register dst, Register src) { + if (dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.CPU)) { + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x6E); + emitByte(0xC0 | encode); + } else if (src.getRegisterCategory().equals(AMD64.XMM) && dst.getRegisterCategory().equals(AMD64.CPU)) { + // swap src/dst to get correct prefix + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x7E); + emitByte(0xC0 | encode); + } else { + throw new InternalError("should not reach here"); + } + } + + public final void movddup(Register dst, Register src) { + assert supports(CPUFeature.SSE3); + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x12); + emitByte(0xC0 | encode); + } + + public final void movdqu(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x6F); + emitOperandHelper(dst, src, 0); + } + + public final void movdqu(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x6F); + emitByte(0xC0 | encode); + } + + public final void vmovdqu(Register dst, AMD64Address src) { + assert supports(CPUFeature.AVX); + assert dst.getRegisterCategory().equals(AMD64.XMM); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_256bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + vexPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x6F); + emitOperandHelper(dst, src, 0); + } + + public final void vzeroupper() { + assert supports(CPUFeature.AVX); + AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); + vexPrefixAndEncode(AMD64.xmm0, AMD64.xmm0, AMD64.xmm0, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes); + emitByte(0x77); + } + + public final void movslq(AMD64Address dst, int imm32) { + prefixq(dst); + emitByte(0xC7); + emitOperandHelper(0, dst, 4); + emitInt(imm32); + } + + public final void movslq(Register dst, AMD64Address src) { + prefixq(src, dst); + emitByte(0x63); + emitOperandHelper(dst, src, 0); + } + + public final void movslq(Register dst, Register src) { + int encode = prefixqAndEncode(dst.encoding, src.encoding); + emitByte(0x63); + emitByte(0xC0 | encode); + } + + public final void negq(Register dst) { + int encode = prefixqAndEncode(dst.encoding); + emitByte(0xF7); + emitByte(0xD8 | encode); + } + + public final void orq(Register dst, Register src) { + OR.rmOp.emit(this, QWORD, dst, src); + } + + public final void shlq(Register dst, int imm8) { + assert isShiftCount(imm8 >> 1) : "illegal shift count"; + int encode = prefixqAndEncode(dst.encoding); + if (imm8 == 1) { + emitByte(0xD1); + emitByte(0xE0 | encode); + } else { + emitByte(0xC1); + emitByte(0xE0 | encode); + emitByte(imm8); + } + } + + public final void shlq(Register dst) { + int encode = prefixqAndEncode(dst.encoding); + emitByte(0xD3); + emitByte(0xE0 | encode); + } + + public final void shrq(Register dst, int imm8) { + assert isShiftCount(imm8 >> 1) : "illegal shift count"; + int encode = prefixqAndEncode(dst.encoding); + if (imm8 == 1) { + emitByte(0xD1); + emitByte(0xE8 | encode); + } else { + emitByte(0xC1); + emitByte(0xE8 | encode); + emitByte(imm8); + } + } + + public final void shrq(Register dst) { + int encode = prefixqAndEncode(dst.encoding); + emitByte(0xD3); + emitByte(0xE8 | encode); + } + + public final void sbbq(Register dst, Register src) { + SBB.rmOp.emit(this, QWORD, dst, src); + } + + public final void subq(Register dst, int imm32) { + SUB.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32); + } + + public final void subq(AMD64Address dst, int imm32) { + SUB.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32); + } + + public final void subqWide(Register dst, int imm32) { + // don't use the sign-extending version, forcing a 32-bit immediate + SUB.getMIOpcode(QWORD, false).emit(this, QWORD, dst, imm32); + } + + public final void subq(Register dst, Register src) { + SUB.rmOp.emit(this, QWORD, dst, src); + } + + public final void testq(Register dst, Register src) { + int encode = prefixqAndEncode(dst.encoding, src.encoding); + emitByte(0x85); + emitByte(0xC0 | encode); + } + + public final void xaddl(AMD64Address dst, Register src) { + prefix(dst, src); + emitByte(0x0F); + emitByte(0xC1); + emitOperandHelper(src, dst, 0); + } + + public final void xaddq(AMD64Address dst, Register src) { + prefixq(dst, src); + emitByte(0x0F); + emitByte(0xC1); + emitOperandHelper(src, dst, 0); + } + + public final void xchgl(Register dst, AMD64Address src) { + prefix(src, dst); + emitByte(0x87); + emitOperandHelper(dst, src, 0); + } + + public final void xchgq(Register dst, AMD64Address src) { + prefixq(src, dst); + emitByte(0x87); + emitOperandHelper(dst, src, 0); + } + + public final void membar(int barriers) { + if (target.isMP) { + // We only have to handle StoreLoad + if ((barriers & STORE_LOAD) != 0) { + // All usable chips support "locked" instructions which suffice + // as barriers, and are much faster than the alternative of + // using cpuid instruction. We use here a locked add [rsp],0. + // This is conveniently otherwise a no-op except for blowing + // flags. + // Any change to this code may need to revisit other places in + // the code where this idiom is used, in particular the + // orderAccess code. + lock(); + addl(new AMD64Address(rsp, 0), 0); // Assert the lock# signal here + } + } + } + + @Override + protected final void patchJumpTarget(int branch, int branchTarget) { + int op = getByte(branch); + assert op == 0xE8 // call + || + op == 0x00 // jump table entry + || op == 0xE9 // jmp + || op == 0xEB // short jmp + || (op & 0xF0) == 0x70 // short jcc + || op == 0x0F && (getByte(branch + 1) & 0xF0) == 0x80 // jcc + : "Invalid opcode at patch point branch=" + branch + ", branchTarget=" + branchTarget + ", op=" + op; + + if (op == 0x00) { + int offsetToJumpTableBase = getShort(branch + 1); + int jumpTableBase = branch - offsetToJumpTableBase; + int imm32 = branchTarget - jumpTableBase; + emitInt(imm32, branch); + } else if (op == 0xEB || (op & 0xF0) == 0x70) { + + // short offset operators (jmp and jcc) + final int imm8 = branchTarget - (branch + 2); + /* + * Since a wrongly patched short branch can potentially lead to working but really bad + * behaving code we should always fail with an exception instead of having an assert. + */ + if (!NumUtil.isByte(imm8)) { + throw new InternalError("branch displacement out of range: " + imm8); + } + emitByte(imm8, branch + 1); + + } else { + + int off = 1; + if (op == 0x0F) { + off = 2; + } + + int imm32 = branchTarget - (branch + 4 + off); + emitInt(imm32, branch + off); + } + } + + public void nullCheck(AMD64Address address) { + testl(AMD64.rax, address); + } + + @Override + public void align(int modulus) { + if (position() % modulus != 0) { + nop(modulus - (position() % modulus)); + } + } + + /** + * Emits a direct call instruction. Note that the actual call target is not specified, because + * all calls need patching anyway. Therefore, 0 is emitted as the call target, and the user is + * responsible to add the call address to the appropriate patching tables. + */ + public final void call() { + if (codePatchingAnnotationConsumer != null) { + int pos = position(); + codePatchingAnnotationConsumer.accept(new ImmediateOperandAnnotation(pos, pos + 1, 4, pos + 5)); + } + emitByte(0xE8); + emitInt(0); + } + + public final void call(Register src) { + int encode = prefixAndEncode(src.encoding); + emitByte(0xFF); + emitByte(0xD0 | encode); + } + + public final void int3() { + emitByte(0xCC); + } + + public final void pause() { + emitByte(0xF3); + emitByte(0x90); + } + + private void emitx87(int b1, int b2, int i) { + assert 0 <= i && i < 8 : "illegal stack offset"; + emitByte(b1); + emitByte(b2 + i); + } + + public final void fldd(AMD64Address src) { + emitByte(0xDD); + emitOperandHelper(0, src, 0); + } + + public final void flds(AMD64Address src) { + emitByte(0xD9); + emitOperandHelper(0, src, 0); + } + + public final void fldln2() { + emitByte(0xD9); + emitByte(0xED); + } + + public final void fldlg2() { + emitByte(0xD9); + emitByte(0xEC); + } + + public final void fyl2x() { + emitByte(0xD9); + emitByte(0xF1); + } + + public final void fstps(AMD64Address src) { + emitByte(0xD9); + emitOperandHelper(3, src, 0); + } + + public final void fstpd(AMD64Address src) { + emitByte(0xDD); + emitOperandHelper(3, src, 0); + } + + private void emitFPUArith(int b1, int b2, int i) { + assert 0 <= i && i < 8 : "illegal FPU register: " + i; + emitByte(b1); + emitByte(b2 + i); + } + + public void ffree(int i) { + emitFPUArith(0xDD, 0xC0, i); + } + + public void fincstp() { + emitByte(0xD9); + emitByte(0xF7); + } + + public void fxch(int i) { + emitFPUArith(0xD9, 0xC8, i); + } + + public void fnstswAX() { + emitByte(0xDF); + emitByte(0xE0); + } + + public void fwait() { + emitByte(0x9B); + } + + public void fprem() { + emitByte(0xD9); + emitByte(0xF8); + } + + public final void fsin() { + emitByte(0xD9); + emitByte(0xFE); + } + + public final void fcos() { + emitByte(0xD9); + emitByte(0xFF); + } + + public final void fptan() { + emitByte(0xD9); + emitByte(0xF2); + } + + public final void fstp(int i) { + emitx87(0xDD, 0xD8, i); + } + + @Override + public AMD64Address makeAddress(Register base, int displacement) { + return new AMD64Address(base, displacement); + } + + @Override + public AMD64Address getPlaceholder(int instructionStartPosition) { + return new AMD64Address(rip, Register.None, Scale.Times1, 0, instructionStartPosition); + } + + private void prefetchPrefix(AMD64Address src) { + prefix(src); + emitByte(0x0F); + } + + public void prefetchnta(AMD64Address src) { + prefetchPrefix(src); + emitByte(0x18); + emitOperandHelper(0, src, 0); + } + + void prefetchr(AMD64Address src) { + assert supports(CPUFeature.AMD_3DNOW_PREFETCH); + prefetchPrefix(src); + emitByte(0x0D); + emitOperandHelper(0, src, 0); + } + + public void prefetcht0(AMD64Address src) { + assert supports(CPUFeature.SSE); + prefetchPrefix(src); + emitByte(0x18); + emitOperandHelper(1, src, 0); + } + + public void prefetcht1(AMD64Address src) { + assert supports(CPUFeature.SSE); + prefetchPrefix(src); + emitByte(0x18); + emitOperandHelper(2, src, 0); + } + + public void prefetcht2(AMD64Address src) { + assert supports(CPUFeature.SSE); + prefix(src); + emitByte(0x0f); + emitByte(0x18); + emitOperandHelper(3, src, 0); + } + + public void prefetchw(AMD64Address src) { + assert supports(CPUFeature.AMD_3DNOW_PREFETCH); + prefix(src); + emitByte(0x0f); + emitByte(0x0D); + emitOperandHelper(1, src, 0); + } + + public void rdtsc() { + emitByte(0x0F); + emitByte(0x31); + } + + /** + * Emits an instruction which is considered to be illegal. This is used if we deliberately want + * to crash the program (debugging etc.). + */ + public void illegal() { + emitByte(0x0f); + emitByte(0x0b); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64InstructionAttr.java 2016-12-07 13:47:33.997370343 -0800 @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2012, 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 jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.code.TargetDescription; + +/** + * Attributes for instructions for SSE through EVEX, also including address components. + */ +public class AMD64InstructionAttr { + AMD64InstructionAttr( + int inVectorLen, + boolean inRexVexW, + boolean inLegacyMode, + boolean inNoRegMask, + boolean inUsesVl, + TargetDescription target) { + avxVectorLen = inVectorLen; + rexVexW = inRexVexW; + this.target = target; + legacyMode = (!supports(CPUFeature.AVX512F)) ? true : inLegacyMode; + noRegMask = inNoRegMask; + usesVl = inUsesVl; + rexVexWReverted = false; + tupleType = 0; + inputSizeInBits = 0; + isEvexInstruction = false; + evexEncoding = 0; + isClearContext = false; + isExtendedContext = false; + } + + private TargetDescription target; + private int avxVectorLen; + private boolean rexVexW; + private boolean rexVexWReverted; + private boolean legacyMode; + private boolean noRegMask; + private boolean usesVl; + private int tupleType; + private int inputSizeInBits; + private boolean isEvexInstruction; + private int evexEncoding; + private boolean isClearContext; + private boolean isExtendedContext; + + public int getVectorLen() { + return avxVectorLen; + } + + public boolean isRexVexW() { + return rexVexW; + } + + public boolean isRexVexWReverted() { + return rexVexWReverted; + } + + public boolean isLegacyMode() { + return legacyMode; + } + + public boolean isNoRegMask() { + return noRegMask; + } + + public boolean usesVl() { + return usesVl; + } + + public int getTupleType() { + return tupleType; + } + + public int getInputSize() { + return inputSizeInBits; + } + + public boolean isEvexInstruction() { + return isEvexInstruction; + } + + public int getEvexEncoding() { + return evexEncoding; + } + + public boolean isClearContext() { + return isClearContext; + } + + public boolean isExtendedContext() { + return isExtendedContext; + } + + /** + * Set the vector length of a given instruction. + * + * @param vectorLen + */ + public void setVectorLen(int vectorLen) { + avxVectorLen = vectorLen; + } + + /** + * In EVEX it is possible in blended code generation to revert the encoding width for AVX. + */ + public void setRexVexWReverted() { + rexVexWReverted = true; + } + + /** + * Alter the current encoding width. + * + * @param state + */ + public void setRexVexW(boolean state) { + rexVexW = state; + } + + /** + * Alter the current instructions legacy mode. Blended code generation will use this. + */ + public void setLegacyMode() { + legacyMode = true; + } + + /** + * During emit or during definition of an instruction, mark if it is EVEX. + */ + public void setIsEvexInstruction() { + isEvexInstruction = true; + } + + /** + * Set the current encoding attributes to be used in address calculations for EVEX. + * + * @param value + */ + public void setEvexEncoding(int value) { + evexEncoding = value; + } + + /** + * Use clear context for this instruction in EVEX, defaults is merge(false). + */ + public void setIsClearContext() { + isClearContext = true; + } + + /** + * Set the address attributes for configuring displacement calculations in EVEX. + */ + public void setAddressAttributes(int inTupleType, int inInputSizeInBits) { + if (supports(CPUFeature.AVX512F)) { + tupleType = inTupleType; + inputSizeInBits = inInputSizeInBits; + } + } + + private boolean supports(CPUFeature feature) { + return ((AMD64) target.arch).getFeatures().contains(feature); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64MacroAssembler.java 2016-12-07 13:47:34.261381944 -0800 @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2009, 2015, 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 org.graalvm.compiler.asm.NumUtil; + +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 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 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, 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) { + movaps(dst, src); + } else { + movss(dst, src); + } + } + + public void movflt(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + movss(dst, src); + } + + public void movflt(AMD64Address dst, Register src) { + assert src.getRegisterCategory().equals(AMD64.XMM); + movss(dst, src); + } + + public void movdbl(Register dst, Register src) { + assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); + if (UseXmmRegToRegMoveAll) { + movapd(dst, src); + } else { + movsd(dst, src); + } + } + + public void movdbl(Register dst, AMD64Address src) { + assert dst.getRegisterCategory().equals(AMD64.XMM); + if (UseXmmLoadAndClearUpper) { + movsd(dst, src); + } else { + movlpd(dst, src); + } + } + + public void movdbl(AMD64Address dst, Register src) { + assert src.getRegisterCategory().equals(AMD64.XMM); + 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 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()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/BitSpecTest.java 2016-12-07 13:47:34.529393720 -0800 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016, 2016, 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.sparc.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import org.graalvm.compiler.asm.sparc.SPARCAssembler.BitSpec; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.CompositeBitSpec; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.ContinousBitSpec; + +public class BitSpecTest { + + private static final BitSpec d4hi = new ContinousBitSpec(23, 20, true, "d4hi"); + private static final BitSpec d4lo = new ContinousBitSpec(7, 4, false, "d4lo"); + private static final BitSpec d8 = new CompositeBitSpec(d4hi, d4lo); + + @Test + public void testContinousSignExtend() { + testSetGet(d4hi, 0x00700000, 0x00000007); + testSetGet(d4hi, 0x00800000, 0xFFFFFFF8); + } + + @Test + public void testContinousZeroExtend() { + testSetGet(d4lo, 0x000000F0, 0x0000000F); + testSetGet(d4lo, 0x00000070, 0x00000007); + } + + public void testSetGet(BitSpec bs, int encoded, int decoded) { + assertTrue(bs.valueFits(decoded)); + assertEquals(encoded, bs.setBits(0, decoded)); + assertEquals(decoded, bs.getBits(encoded)); + } + + @Test + public void testContinousSignExtendValueFits() { + assertFalse(d4hi.valueFits(0xf)); + assertFalse(d4hi.valueFits(0x10)); + assertFalse(d4hi.valueFits(0x17)); + } + + @Test + public void testContinousZeroExtendValueFits() { + assertFalse(d4lo.valueFits(0x10)); + } + + @Test(expected = AssertionError.class) + public void testContinousSignExtendSetFail1() { + d4hi.setBits(0, 0xf); + } + + @Test(expected = AssertionError.class) + public void testContinousSignExtendSetFail2() { + d4hi.setBits(0, 0xFFFFFFF0); + } + + @Test(expected = AssertionError.class) + public void testContinousZeroExtendSetFail1() { + d4lo.setBits(0, 0x10); + } + + @Test + public void testCompositeSignExtended() { + testSetGet(d8, 0x00f000c0, 0xfffffffc); + testSetGet(d8, 0x008000c0, 0xffffff8c); + testSetGet(d8, 0x007000c0, 0x7c); + } + + @Test(expected = AssertionError.class) + public void testCompositeSignExtendedFail1() { + d8.setBits(0, 0x00000080); + } + + @Test(expected = AssertionError.class) + public void testCompositeSignExtendedFail2() { + d8.setBits(0, 0xEFFFFF80); + } + + @Test + public void testCompositeValueFits() { + assertTrue(d8.valueFits(0xfffffffc)); + assertTrue(d8.valueFits(0xffffff8c)); + assertTrue(d8.valueFits(0x7c)); + assertFalse(d8.valueFits(0x8c)); + assertFalse(d8.valueFits(0xEFFFFF80)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/SPARCAssemblerTest.java 2016-12-07 13:47:34.793405321 -0800 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2016, 2016, 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.sparc.test; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPR; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BR; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.CarryClear; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z; +import static jdk.vm.ci.sparc.SPARC.g0; + +import java.util.EnumSet; +import java.util.function.Consumer; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.sparc.SPARC; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.ControlTransferOp; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.SPARCOp; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.test.GraalTest; + +public class SPARCAssemblerTest extends GraalTest { + private SPARCMacroAssembler masm; + + private static EnumSet computeFeatures() { + EnumSet features = EnumSet.noneOf(SPARC.CPUFeature.class); + features.add(SPARC.CPUFeature.CBCOND); + return features; + } + + private static TargetDescription createTarget() { + final int stackFrameAlignment = 16; + final int implicitNullCheckLimit = 4096; + final boolean inlineObjects = true; + Architecture arch = new SPARC(computeFeatures()); + return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); + } + + @Before + public void setup() { + TargetDescription target = createTarget(); + masm = new SPARCMacroAssembler(target); + } + + @Test + public void testPatchCbcod() { + testControlTransferOp(l -> CBCOND.emit(masm, CarryClear, false, g0, 3, l), -512, 511); + } + + @Test + public void testPatchBpcc() { + int maxDisp = 1 << 18; + testControlTransferOp(l -> BPCC.emit(masm, Xcc, Equal, ANNUL, PREDICT_NOT_TAKEN, l), -maxDisp, + maxDisp - 1); + } + + @Test + public void testPatchBpr() { + int maxDisp = 1 << 15; + testControlTransferOp(l -> BPR.emit(masm, Rc_z, ANNUL, PREDICT_NOT_TAKEN, g0, l), -maxDisp, + maxDisp - 1); + } + + @Test + public void testPatchBr() { + int maxDisp = 1 << 21; + testControlTransferOp(l -> BR.emit(masm, Equal, ANNUL, l), -maxDisp, + maxDisp - 1); + } + + @Test(expected = BailoutException.class) + public void testControlTransferInvalidDisp() { + int cbcondInstruction = 0x12f83f60; + CBCOND.setDisp(cbcondInstruction, 0x2ff); + } + + public void testControlTransferOp(Consumer

+     * | 00  |    a   | op2 |               b                         |
+     * |31 30|29    25|24 22|21                                      0|
+     * 
+ */ + // @formatter:on + protected void fmt00(int a, int op2, int b) { + assert isImm(a, 5) && isImm(op2, 3) && isImm(b, 22) : String.format("a: 0x%x op2: 0x%x b: 0x%x", a, op2, b); + int word = 0; + BitSpec.op.setBits(word, 0); + BitSpec.rd.setBits(word, a); + BitSpec.op2.setBits(word, op2); + BitSpec.imm22.setBits(word, b); + emitInt(a << 25 | op2 << 22 | b); + } + + private void op3(Op3s op3, Opfs opf, Register rs1, Register rs2, Register rd) { + int b = opf.value << 5 | (rs2 == null ? 0 : rs2.encoding); + fmt(op3.op.value, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b); + } + + protected void op3(Op3s op3, Register rs1, Register rs2, Register rd) { + int b = rs2 == null ? 0 : rs2.encoding; + int xBit = getXBit(op3); + fmt(op3.op.value, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b | xBit); + } + + protected void op3(Op3s op3, Register rs1, int simm13, Register rd) { + assert isSimm13(simm13) : simm13; + int i = 1 << 13; + int simm13WithX = simm13 | getXBit(op3); + fmt(op3.op.value, rd.encoding, op3.value, rs1.encoding, i | simm13WithX & ((1 << 13) - 1)); + } + + public void insertNopAfterCBCond() { + int pos = position() - INSTRUCTION_SIZE; + if (pos == 0) { + return; + } + int inst = getInt(pos); + if (CBCOND.match(inst)) { + nop(); + } + } + + protected int patchUnbound(Label label) { + label.addPatchAt(position()); + return 0; + } + + // @formatter:off + /** + * NOP. + *
+     * | 00  |00000| 100 |                0                    |
+     * |31 30|29 25|24 22|21                                  0|
+     * 
+ */ + // @formatter:on + public void nop() { + emitInt(1 << 24); + } + + public void sethi(int imm22, Register dst) { + fmt00(dst.encoding, Op2s.Sethi.value, imm22); + } + + // @formatter:off + /** + * Instruction format for calls. + *
+     * | 01  |                      disp30                             |
+     * |31 30|29                                                      0|
+     * 
+ * + * @return Position of the call instruction + */ + // @formatter:on + public int call(int disp30) { + assert isImm(disp30, 30); + insertNopAfterCBCond(); + int before = position(); + int instr = 1 << 30; + instr |= disp30; + emitInt(instr); + return before; + } + + public void add(Register rs1, Register rs2, Register rd) { + op3(Add, rs1, rs2, rd); + } + + public void add(Register rs1, int simm13, Register rd) { + op3(Add, rs1, simm13, rd); + } + + public void addc(Register rs1, Register rs2, Register rd) { + op3(Addc, rs1, rs2, rd); + } + + public void addc(Register rs1, int simm13, Register rd) { + op3(Addc, rs1, simm13, rd); + } + + public void addcc(Register rs1, Register rs2, Register rd) { + op3(Addcc, rs1, rs2, rd); + } + + public void addcc(Register rs1, int simm13, Register rd) { + op3(Addcc, rs1, simm13, rd); + } + + public void and(Register rs1, Register rs2, Register rd) { + op3(And, rs1, rs2, rd); + } + + public void and(Register rs1, int simm13, Register rd) { + op3(And, rs1, simm13, rd); + } + + public void andcc(Register rs1, Register rs2, Register rd) { + op3(Andcc, rs1, rs2, rd); + } + + public void andcc(Register rs1, int simm13, Register rd) { + op3(Andcc, rs1, simm13, rd); + } + + public void andn(Register rs1, Register rs2, Register rd) { + op3(Andn, rs1, rs2, rd); + } + + public void andn(Register rs1, int simm13, Register rd) { + op3(Andn, rs1, simm13, rd); + } + + public void andncc(Register rs1, Register rs2, Register rd) { + op3(Andncc, rs1, rs2, rd); + } + + public void andncc(Register rs1, int simm13, Register rd) { + op3(Andncc, rs1, simm13, rd); + } + + public void movwtos(Register rs2, Register rd) { + assert isSingleFloatRegister(rd) && isCPURegister(rs2) : String.format("%s %s", rs2, rd); + op3(Impdep1, Movwtos, null, rs2, rd); + } + + public void umulxhi(Register rs1, Register rs2, Register rd) { + op3(Impdep1, UMulxhi, rs1, rs2, rd); + } + + public void fdtos(Register rs2, Register rd) { + assert isSingleFloatRegister(rd) && isDoubleFloatRegister(rs2) : String.format("%s %s", rs2, rd); + op3(Fpop1, Fdtos, null, rs2, rd); + } + + public void movstouw(Register rs2, Register rd) { + assert isSingleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd); + op3(Impdep1, Movstosw, null, rs2, rd); + } + + public void movstosw(Register rs2, Register rd) { + assert isSingleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd); + op3(Impdep1, Movstosw, null, rs2, rd); + } + + public void movdtox(Register rs2, Register rd) { + assert isDoubleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd); + op3(Impdep1, Movdtox, null, rs2, rd); + } + + public void movxtod(Register rs2, Register rd) { + assert isCPURegister(rs2) && isDoubleFloatRegister(rd) : String.format("%s %s", rs2, rd); + op3(Impdep1, Movxtod, null, rs2, rd); + } + + public void fadds(Register rs1, Register rs2, Register rd) { + op3(Fpop1, Fadds, rs1, rs2, rd); + } + + public void faddd(Register rs1, Register rs2, Register rd) { + op3(Fpop1, Faddd, rs1, rs2, rd); + } + + public void fdivs(Register rs1, Register rs2, Register rd) { + op3(Fpop1, Fdivs, rs1, rs2, rd); + } + + public void fdivd(Register rs1, Register rs2, Register rd) { + op3(Fpop1, Fdivd, rs1, rs2, rd); + } + + public void fmovs(Register rs2, Register rd) { + op3(Fpop1, Fmovs, null, rs2, rd); + } + + public void fmovd(Register rs2, Register rd) { + op3(Fpop1, Fmovd, null, rs2, rd); + } + + public void fsrc2s(Register rs2, Register rd) { + op3(Impdep1, Fsrc2s, null, rs2, rd); + } + + public void fsrc2d(Register rs2, Register rd) { + op3(Impdep1, Fsrc2d, null, rs2, rd); + } + + public void fmuls(Register rs1, Register rs2, Register rd) { + op3(Fpop1, Fmuls, rs1, rs2, rd); + } + + public void fsmuld(Register rs1, Register rs2, Register rd) { + op3(Fpop1, Fsmuld, rs1, rs2, rd); + } + + public void fmuld(Register rs1, Register rs2, Register rd) { + op3(Fpop1, Fmuld, rs1, rs2, rd); + } + + public void fnegs(Register rs2, Register rd) { + op3(Fpop1, Fnegs, null, rs2, rd); + } + + public void fnegd(Register rs2, Register rd) { + op3(Fpop1, Fnegd, null, rs2, rd); + } + + /** + * Helper method to determine if the instruction needs the X bit set. + */ + private static int getXBit(Op3s op3) { + switch (op3) { + case Sllx: + case Srax: + case Srlx: + return 1 << 12; + default: + return 0; + } + } + + public void fstoi(Register rs2, Register rd) { + op3(Fpop1, Fstoi, null, rs2, rd); + } + + public void fstox(Register rs2, Register rd) { + op3(Fpop1, Fstox, null, rs2, rd); + } + + public void fdtox(Register rs2, Register rd) { + op3(Fpop1, Fdtox, null, rs2, rd); + } + + public void fstod(Register rs2, Register rd) { + op3(Fpop1, Fstod, null, rs2, rd); + } + + public void fdtoi(Register rs2, Register rd) { + op3(Fpop1, Fdtoi, null, rs2, rd); + } + + public void fitos(Register rs2, Register rd) { + op3(Fpop1, Fitos, null, rs2, rd); + } + + public void fitod(Register rs2, Register rd) { + op3(Fpop1, Fitod, null, rs2, rd); + } + + public void fxtos(Register rs2, Register rd) { + op3(Fpop1, Fxtos, null, rs2, rd); + } + + public void fxtod(Register rs2, Register rd) { + op3(Fpop1, Fxtod, null, rs2, rd); + } + + public void fzeros(Register rd) { + op3(Impdep1, Fzeros, null, null, rd); + } + + public void fzerod(Register rd) { + op3(Impdep1, Fzerod, null, null, rd); + } + + public void flushw() { + op3(Flushw, g0, g0, g0); + } + + public void fsqrtd(Register rs2, Register rd) { + op3(Fpop1, Fsqrtd, null, rs2, rd); + } + + public void fsqrts(Register rs2, Register rd) { + op3(Fpop1, Fsqrts, null, rs2, rd); + } + + public void fabss(Register rs2, Register rd) { + op3(Fpop1, Fabss, null, rs2, rd); + } + + public void fabsd(Register rs2, Register rd) { + op3(Fpop1, Fabsd, null, rs2, rd); + } + + public void fsubs(Register rs1, Register rs2, Register rd) { + op3(Fpop1, Fsubs, rs1, rs2, rd); + } + + public void fsubd(Register rs1, Register rs2, Register rd) { + op3(Fpop1, Fsubd, rs1, rs2, rd); + } + + // @formatter:off + /** + * Instruction format for fcmp. + *
+     * | 10  | --- |cc1|cc0|desc |   rs1   |   opf  | rs2 |
+     * |31 30|29 27|26 |25 |24 19|18     14|13     5|4   0|
+     * 
+ */ + // @formatter:on + public void fcmp(CC cc, Opfs opf, Register rs1, Register rs2) { + int a = cc.value; + int b = opf.value << 5 | rs2.encoding; + delaySlotOptimizationPoints.add(position()); + fmt10(a, Fpop2.value, rs1.encoding, b); + } + + // @formatter:off + /** + * Instruction format for most arithmetic stuff. + *
+     * |  10 | rd  | op3 | rs1 |   b   |
+     * |31 30|29 25|24 19|18 14|13    0|
+     * 
+ */ + // @formatter:on + protected void fmt10(int rd, int op3, int rs1, int b) { + fmt(0b10, rd, op3, rs1, b); + } + + // @formatter:off + /** + * Instruction format for most arithmetic stuff. + *
+     * |  op | rd  | op3 | rs1 |   b   |
+     * |31 30|29 25|24 19|18 14|13    0|
+     * 
+ */ + // @formatter:on + protected void fmt(int op, int rd, int op3, int rs1, int b) { + assert isImm(rd, 5) && isImm(op3, 6) && isImm(b, 14) : String.format("rd: 0x%x op3: 0x%x b: 0x%x", rd, op3, b); + int instr = op << 30 | rd << 25 | op3 << 19 | rs1 << 14 | b; + emitInt(instr); + } + + public void illtrap(int const22) { + fmt00(0, Op2s.Illtrap.value, const22); + } + + public void jmpl(Register rs1, Register rs2, Register rd) { + insertNopAfterCBCond(); + op3(Jmpl, rs1, rs2, rd); + } + + /** + * @return Position of the jmpl instruction + */ + public int jmpl(Register rs1, int simm13, Register rd) { + insertNopAfterCBCond(); + int before = position(); + op3(Jmpl, rs1, simm13, rd); + return before; + } + + public void fmovdcc(ConditionFlag cond, CC cc, Register rs2, Register rd) { + fmovcc(cond, cc, rs2, rd, OpfLow.Fmovdcc.value); + } + + public void fmovscc(ConditionFlag cond, CC cc, Register rs2, Register rd) { + fmovcc(cond, cc, rs2, rd, OpfLow.Fmovscc.value); + } + + private void fmovcc(ConditionFlag cond, CC cc, Register rs2, Register rd, int opfLow) { + int opfCC = cc.value; + int a = opfCC << 11 | opfLow << 5 | rs2.encoding; + fmt10(rd.encoding, Fpop2.value, cond.value, a); + } + + public void movcc(ConditionFlag conditionFlag, CC cc, Register rs2, Register rd) { + movcc(conditionFlag, cc, 0, rs2.encoding, rd); + } + + public void movcc(ConditionFlag conditionFlag, CC cc, int simm11, Register rd) { + assert isSimm11(simm11); + movcc(conditionFlag, cc, 1, simm11 & ((1 << 11) - 1), rd); + } + + private void movcc(ConditionFlag conditionFlag, CC cc, int i, int imm, Register rd) { + int cc01 = 0b11 & cc.value; + int cc2 = cc.isFloat ? 0 : 1; + int a = cc2 << 4 | conditionFlag.value; + int b = cc01 << 11 | i << 13 | imm; + fmt10(rd.encoding, Movcc.value, a, b); + } + + public void mulx(Register rs1, Register rs2, Register rd) { + op3(Mulx, rs1, rs2, rd); + } + + public void mulx(Register rs1, int simm13, Register rd) { + op3(Mulx, rs1, simm13, rd); + } + + public void or(Register rs1, Register rs2, Register rd) { + assert isCPURegister(rs1, rs2, rd) : String.format("%s %s %s", rs1, rs2, rd); + op3(Or, rs1, rs2, rd); + } + + public void or(Register rs1, int simm13, Register rd) { + assert isCPURegister(rs1, rd) : String.format("%s %s", rs1, rd); + op3(Or, rs1, simm13, rd); + } + + public void popc(Register rs2, Register rd) { + op3(Popc, g0, rs2, rd); + } + + public void popc(int simm13, Register rd) { + op3(Popc, g0, simm13, rd); + } + + public void prefetch(SPARCAddress addr, Fcn fcn) { + Register rs1 = addr.getBase(); + if (addr.getIndex().equals(Register.None)) { + int dis = addr.getDisplacement(); + assert isSimm13(dis); + fmt(Prefetch.op.value, fcn.value, Prefetch.value, rs1.encoding, 1 << 13 | dis & ((1 << 13) - 1)); + } else { + Register rs2 = addr.getIndex(); + fmt(Prefetch.op.value, fcn.value, Prefetch.value, rs1.encoding, rs2.encoding); + } + } + + // A.44 Read State Register + + public void rdpc(Register rd) { + op3(Rd, g5, g0, rd); + } + + public void restore(Register rs1, Register rs2, Register rd) { + op3(Restore, rs1, rs2, rd); + } + + public static final int PC_RETURN_OFFSET = 8; + + public void save(Register rs1, Register rs2, Register rd) { + op3(Save, rs1, rs2, rd); + } + + public void save(Register rs1, int simm13, Register rd) { + op3(Save, rs1, simm13, rd); + } + + public void sdivx(Register rs1, Register rs2, Register rd) { + op3(Sdivx, rs1, rs2, rd); + } + + public void sdivx(Register rs1, int simm13, Register rd) { + op3(Sdivx, rs1, simm13, rd); + } + + public void udivx(Register rs1, Register rs2, Register rd) { + op3(Udivx, rs1, rs2, rd); + } + + public void udivx(Register rs1, int simm13, Register rd) { + op3(Udivx, rs1, simm13, rd); + } + + public void sll(Register rs1, Register rs2, Register rd) { + op3(Sll, rs1, rs2, rd); + } + + public void sll(Register rs1, int shcnt32, Register rd) { + assert isImm(shcnt32, 5); + op3(Sll, rs1, shcnt32, rd); + } + + public void sllx(Register rs1, Register rs2, Register rd) { + op3(Sllx, rs1, rs2, rd); + } + + public void sllx(Register rs1, int shcnt64, Register rd) { + assert isImm(shcnt64, 6); + op3(Sllx, rs1, shcnt64, rd); + } + + public void sra(Register rs1, Register rs2, Register rd) { + op3(Sra, rs1, rs2, rd); + } + + public void sra(Register rs1, int simm13, Register rd) { + op3(Sra, rs1, simm13, rd); + } + + public void srax(Register rs1, Register rs2, Register rd) { + op3(Srax, rs1, rs2, rd); + } + + public void srax(Register rs1, int shcnt64, Register rd) { + assert isImm(shcnt64, 6); + op3(Srax, rs1, shcnt64, rd); + } + + public void srl(Register rs1, Register rs2, Register rd) { + op3(Srl, rs1, rs2, rd); + } + + public void srl(Register rs1, int simm13, Register rd) { + op3(Srl, rs1, simm13, rd); + } + + public void srlx(Register rs1, Register rs2, Register rd) { + op3(Srlx, rs1, rs2, rd); + } + + public void srlx(Register rs1, int shcnt64, Register rd) { + assert isImm(shcnt64, 6); + op3(Srlx, rs1, shcnt64, rd); + } + + public void sub(Register rs1, Register rs2, Register rd) { + op3(Sub, rs1, rs2, rd); + } + + public void sub(Register rs1, int simm13, Register rd) { + op3(Sub, rs1, simm13, rd); + } + + public void subcc(Register rs1, Register rs2, Register rd) { + op3(Subcc, rs1, rs2, rd); + } + + public void subcc(Register rs1, int simm13, Register rd) { + op3(Subcc, rs1, simm13, rd); + } + + public void ta(int trap) { + tcc(Icc, Always, trap); + } + + public void pause() { + // Maybe fmt10(rd=0b1_1011, op3=0b11_0000, rs1=0, i=1, simm13=1), or + // maybe op3(Wr, g0, 1, %pause). + // What should the count be? + GraalError.unimplemented("The SPARC pause instruction is not yet implemented."); + } + + public void tcc(CC cc, ConditionFlag flag, int trap) { + assert isImm(trap, 8); + int b = cc.value << 11; + b |= 1 << 13; + b |= trap; + fmt10(flag.value, Op3s.Tcc.getValue(), 0, b); + } + + public void wrccr(Register rs1, Register rs2) { + op3(Wr, rs1, rs2, g2); + } + + public void wrccr(Register rs1, int simm13) { + op3(Wr, rs1, simm13, g2); + } + + public void xor(Register rs1, Register rs2, Register rd) { + op3(Xor, rs1, rs2, rd); + } + + public void xor(Register rs1, int simm13, Register rd) { + op3(Xor, rs1, simm13, rd); + } + + public void xorcc(Register rs1, Register rs2, Register rd) { + op3(Xorcc, rs1, rs2, rd); + } + + public void xorcc(Register rs1, int simm13, Register rd) { + op3(Xorcc, rs1, simm13, rd); + } + + public void xnor(Register rs1, Register rs2, Register rd) { + op3(Xnor, rs1, rs2, rd); + } + + public void xnor(Register rs1, int simm13, Register rd) { + op3(Xnor, rs1, simm13, rd); + } + + /* + * Load/Store + */ + protected void ld(Op3s op3, SPARCAddress addr, Register rd, Asi asi) { + Register rs1 = addr.getBase(); + if (!addr.getIndex().equals(Register.None)) { + Register rs2 = addr.getIndex(); + if (asi != null) { + int b = rs2.encoding; + b |= asi.value << 5; + fmt(op3.op.value, rd.encoding, op3.value, rs1.encoding, b); + } else { + op3(op3, rs1, rs2, rd); + } + } else { + int imm = addr.getDisplacement(); + op3(op3, rs1, imm, rd); + } + } + + protected void ld(Op3s op3, SPARCAddress addr, Register rd) { + ld(op3, addr, rd, null); + } + + public void lddf(SPARCAddress src, Register dst) { + assert isDoubleFloatRegister(dst) : dst; + ld(Lddf, src, dst); + } + + public void ldf(SPARCAddress src, Register dst) { + assert isSingleFloatRegister(dst) : dst; + ld(Ldf, src, dst); + } + + public void lduh(SPARCAddress src, Register dst) { + assert isCPURegister(dst) : dst; + ld(Lduh, src, dst); + } + + public void ldsh(SPARCAddress src, Register dst) { + assert isCPURegister(dst) : dst; + ld(Ldsh, src, dst); + } + + public void ld(SPARCAddress src, Register dst, int bytes, boolean signExtend) { + if (isCPURegister(dst)) { + if (signExtend) { + switch (bytes) { + case 1: + ld(Ldsb, src, dst); + break; + case 2: + ld(Ldsh, src, dst); + break; + case 4: + ld(Ldsw, src, dst); + break; + case 8: + ld(Ldx, src, dst); + break; + default: + throw new InternalError(); + } + } else { + switch (bytes) { + case 1: + ld(Ldub, src, dst); + break; + case 2: + ld(Lduh, src, dst); + break; + case 4: + ld(Lduw, src, dst); + break; + case 8: + ld(Ldx, src, dst); + break; + default: + throw new InternalError(); + } + } + } else if (isDoubleFloatRegister(dst) && bytes == 8) { + assert !signExtend; + ld(Lddf, src, dst); + } else if (isSingleFloatRegister(dst) && bytes == 4) { + assert !signExtend; + ld(Ldf, src, dst); + } else { + throw new InternalError(String.format("src: %s dst: %s bytes: %d signExtend: %b", src, dst, bytes, signExtend)); + } + } + + public void st(Register src, SPARCAddress dst, int bytes) { + if (isCPURegister(src)) { + switch (bytes) { + case 1: + st(Stb, src, dst); + break; + case 2: + st(Sth, src, dst); + break; + case 4: + st(Stw, src, dst); + break; + case 8: + st(Stx, src, dst); + break; + default: + throw new InternalError(Integer.toString(bytes)); + } + } else if (isDoubleFloatRegister(src) && bytes == 8) { + st(Stdf, src, dst); + } else if (isSingleFloatRegister(src) && bytes == 4) { + st(Stf, src, dst); + } else { + throw new InternalError(String.format("src: %s dst: %s bytes: %d", src, dst, bytes)); + } + } + + public void ldub(SPARCAddress src, Register dst) { + assert isCPURegister(dst) : dst; + ld(Ldub, src, dst); + } + + public void ldsb(SPARCAddress src, Register dst) { + assert isCPURegister(dst) : dst; + ld(Ldsb, src, dst); + } + + public void lduw(SPARCAddress src, Register dst) { + assert isCPURegister(dst) : dst; + ld(Lduw, src, dst); + } + + public void ldsw(SPARCAddress src, Register dst) { + assert isCPURegister(dst) : dst; + ld(Ldsw, src, dst); + } + + public void ldx(SPARCAddress src, Register dst) { + assert isCPURegister(dst) : dst; + ld(Ldx, src, dst); + } + + public void ldxa(Register rs1, Register rs2, Register rd, Asi asi) { + assert isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd); + ld(Ldxa, new SPARCAddress(rs1, rs2), rd, asi); + } + + public void lduwa(Register rs1, Register rs2, Register rd, Asi asi) { + assert isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd); + ld(Lduwa, new SPARCAddress(rs1, rs2), rd, asi); + } + + public void stxa(Register rd, Register rs1, Register rs2, Asi asi) { + assert isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd); + ld(Stxa, new SPARCAddress(rs1, rs2), rd, asi); + } + + protected void st(Op3s op3, Register rs1, SPARCAddress dest) { + ld(op3, dest, rs1); + } + + public void stdf(Register rd, SPARCAddress addr) { + assert isDoubleFloatRegister(rd) : rd; + st(Stdf, rd, addr); + } + + public void stf(Register rd, SPARCAddress addr) { + assert isSingleFloatRegister(rd) : rd; + st(Stf, rd, addr); + } + + public void stb(Register rd, SPARCAddress addr) { + assert isCPURegister(rd) : rd; + st(Stb, rd, addr); + } + + public void sth(Register rd, SPARCAddress addr) { + assert isCPURegister(rd) : rd; + st(Sth, rd, addr); + } + + public void stw(Register rd, SPARCAddress addr) { + assert isCPURegister(rd) : rd; + st(Stw, rd, addr); + } + + public void stx(Register rd, SPARCAddress addr) { + assert isCPURegister(rd) : rd; + st(Stx, rd, addr); + } + + public void membar(int barriers) { + op3(Membar, o7, barriers, g0); + } + + public void casa(Register rs1, Register rs2, Register rd, Asi asi) { + ld(Casa, new SPARCAddress(rs1, rs2), rd, asi); + } + + public void casxa(Register rs1, Register rs2, Register rd, Asi asi) { + ld(Casxa, new SPARCAddress(rs1, rs2), rd, asi); + } + + @Override + public InstructionCounter getInstructionCounter() { + return new SPARCInstructionCounter(this); + } + + public void patchAddImmediate(int position, int simm13) { + int inst = getInt(position); + assert SPARCAssembler.isSimm13(simm13) : simm13; + assert (inst >>> 30) == 0b10 : String.format("0x%x", inst); + assert ((inst >>> 18) & 0b11_1111) == 0 : String.format("0x%x", inst); + assert (inst & (1 << 13)) != 0 : String.format("0x%x", inst); + inst = inst & (~((1 << 13) - 1)); + inst |= simm13 & ((1 << 12) - 1); + emitInt(inst, position); + } + + public void fpadd32(Register rs1, Register rs2, Register rd) { + op3(Impdep1, Fpadd32, rs1, rs2, rd); + } + + /** + * Does peephole optimization on code generated by this assembler. This method should be called + * at the end of code generation. + *

+ * It searches for conditional branch instructions which has nop in the delay slot then looks at + * the instruction at branch target; if it is an arithmetic instruction, which does not throw an + * exception (e.g. division), it pulls this instruction into the delay slot and increments the + * displacement by 1. + */ + public void peephole() { + for (int i : delaySlotOptimizationPoints) { + optimizeDelaySlot(i); + } + } + + /** + * Optimizes branch instruction b which has a nop in the delay slot. It tries to stuff + * the instruction at bs branch target into the delay slot of b, set the annul + * flag and increments bs disp field by 1; + *

+ * If bs branch target instruction is an unconditional branch t, then it tries to + * put ts delayed instruction into the delay slot of b and add the ts disp + * field to bs disp field. + */ + private void optimizeDelaySlot(int i) { + int delaySlotAbsolute = i + INSTRUCTION_SIZE; + int nextInst = getInt(delaySlotAbsolute); + SPARCOp nextOp = getSPARCOp(nextInst); + if (nextOp instanceof Sethi && Sethi.isNop(nextInst)) { + int inst = getInt(i); + SPARCOp op = getSPARCOp(inst); + if (op instanceof ControlTransferOp && ((ControlTransferOp) op).hasDelaySlot() && ((ControlTransferOp) op).isAnnulable(inst)) { + ControlTransferOp ctOp = (ControlTransferOp) op; + int disp = ctOp.getDisp(inst); + int branchTargetAbsolute = i + disp * INSTRUCTION_SIZE; + int branchTargetInst = getInt(branchTargetAbsolute); + SPARCOp branchTargetOp = getSPARCOp(branchTargetInst); + if (branchTargetOp instanceof Op3Op) { + Op3s op3 = ((Op3Op) branchTargetOp).getOp3(branchTargetInst); + if (!op3.throwsException()) { + inst = ctOp.setDisp(inst, disp + 1); // Increment the offset + inst = ctOp.setAnnul(inst, true); + emitInt(inst, i); + emitInt(branchTargetInst, delaySlotAbsolute); + } + } else if (branchTargetOp instanceof ControlTransferOp && !((ControlTransferOp) branchTargetOp).isConditional(branchTargetInst)) { + // If branchtarget is a unconditional branch + ControlTransferOp branchTargetOpBranch = (ControlTransferOp) branchTargetOp; + int btDisp = branchTargetOpBranch.getDisp(branchTargetInst); + int newDisp = disp + btDisp; + if (ctOp.isValidDisp(newDisp)) { // Test if we don't exceed field size + int instAfter = ctOp.setDisp(inst, newDisp); + instAfter = ctOp.setAnnul(instAfter, true); + branchTargetInst = getInt(branchTargetAbsolute + INSTRUCTION_SIZE); + branchTargetOp = getSPARCOp(branchTargetInst); + if (branchTargetOp instanceof Op3Op && !((Op3Op) branchTargetOp).getOp3(branchTargetInst).throwsException()) { + emitInt(instAfter, i); + emitInt(branchTargetInst, delaySlotAbsolute); + } + } + } + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCInstructionCounter.java 2016-12-07 13:47:35.593440474 -0800 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2009, 2015, 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.sparc; + +import java.util.TreeMap; + +import org.graalvm.compiler.asm.Assembler.InstructionCounter; + +public class SPARCInstructionCounter implements InstructionCounter { + // Use a treemap to keep the order in the output + private static final TreeMap INSTRUCTION_MATCHER = new TreeMap<>(); + + static { + // @formatter:off + INSTRUCTION_MATCHER.put("nop", new SPARCInstructionMatch(0xFFFF_FFFF, 0x0100_0000)); + INSTRUCTION_MATCHER.put("st", new OP3LowBitsMatcher(0b11, 0x4, 0x5, 0x6, 0x7, 0xe, 0xf)); + INSTRUCTION_MATCHER.put("ld", new OP3LowBitsMatcher(0b11, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd)); + INSTRUCTION_MATCHER.put("all", new SPARCInstructionMatch(0x0, 0x0)); + // @formatter:on + } + + private final SPARCAssembler asm; + + public SPARCInstructionCounter(SPARCAssembler asm) { + super(); + this.asm = asm; + } + + @Override + public int[] countInstructions(String[] instructionTypes, int beginPc, int endPc) { + SPARCInstructionMatch[] matchers = new SPARCInstructionMatch[instructionTypes.length]; + for (int i = 0; i < instructionTypes.length; i++) { + String typeName = instructionTypes[i]; + matchers[i] = INSTRUCTION_MATCHER.get(typeName); + if (matchers[i] == null) { + throw new IllegalArgumentException(String.format("Unknown instruction class %s, supported types are: %s", typeName, INSTRUCTION_MATCHER.keySet())); + } + } + return countBetween(matchers, beginPc, endPc); + } + + private int[] countBetween(SPARCInstructionMatch[] matchers, int startPc, int endPc) { + int[] counts = new int[matchers.length]; + for (int p = startPc; p < endPc; p += 4) { + int instr = asm.getInt(p); + for (int i = 0; i < matchers.length; i++) { + SPARCInstructionMatch matcher = matchers[i]; + if (matcher.matches(instr)) { + counts[i]++; + } + } + } + return counts; + } + + @Override + public String[] getSupportedInstructionTypes() { + return INSTRUCTION_MATCHER.keySet().toArray(new String[0]); + } + + /** + * Tests the lower 3 bits of the op3 field. + */ + private static class OP3LowBitsMatcher extends SPARCInstructionMatch { + private final int[] op3b03; + private final int op; + + OP3LowBitsMatcher(int op, int... op3b03) { + super(0, 0); + this.op = op; + this.op3b03 = op3b03; + } + + @Override + public boolean matches(int instruction) { + if (instruction >>> 30 != op) { + return false; + } + int op3lo = (instruction >> 19) & ((1 << 4) - 1); + for (int op3Part : op3b03) { + if (op3Part == op3lo) { + return true; + } + } + return false; + } + } + + private static class SPARCInstructionMatch { + private final int mask; + private final int[] patterns; + + SPARCInstructionMatch(int mask, int... patterns) { + super(); + this.mask = mask; + this.patterns = patterns; + } + + public boolean matches(int instruction) { + for (int pattern : patterns) { + if ((instruction & mask) == pattern) { + return true; + } + } + return false; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCMacroAssembler.java 2016-12-07 13:47:35.857452074 -0800 @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2013, 2016, 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.sparc; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Icc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Always; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARC.g3; +import static jdk.vm.ci.sparc.SPARC.i7; +import static jdk.vm.ci.sparc.SPARC.o7; + +import org.graalvm.compiler.asm.AbstractAddress; +import org.graalvm.compiler.asm.Label; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.sparc.SPARC.CPUFeature; + +public class SPARCMacroAssembler extends SPARCAssembler { + + /** + * A sentinel value used as a place holder in an instruction stream for an address that will be + * patched. + */ + private static final SPARCAddress Placeholder = new SPARCAddress(g0, 0); + private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(g3), new ScratchRegister(o7)}; + // Points to the next free scratch register + private int nextFreeScratchRegister = 0; + /** + * Use ld [reg+simm13], reg for loading constants (User has to make sure, that the size of the + * constant table does not exceed simm13). + */ + private boolean immediateConstantLoad; + + public SPARCMacroAssembler(TargetDescription target) { + super(target); + } + + /** + * @see #immediateConstantLoad + */ + public void setImmediateConstantLoad(boolean immediateConstantLoad) { + this.immediateConstantLoad = immediateConstantLoad; + } + + @Override + public void align(int modulus) { + while (position() % modulus != 0) { + nop(); + } + } + + @Override + public void jmp(Label l) { + BPCC.emit(this, Xcc, Always, NOT_ANNUL, PREDICT_NOT_TAKEN, l); + nop(); // delay slot + } + + @Override + protected final void patchJumpTarget(int branch, int branchTarget) { + final int disp = (branchTarget - branch) / 4; + final int inst = getInt(branch); + ControlTransferOp op = (ControlTransferOp) getSPARCOp(inst); + int newInst = op.setDisp(inst, disp); + emitInt(newInst, branch); + } + + @Override + public AbstractAddress makeAddress(Register base, int displacement) { + return new SPARCAddress(base, displacement); + } + + @Override + public AbstractAddress getPlaceholder(int instructionStartPosition) { + return Placeholder; + } + + @Override + public final void ensureUniquePC() { + nop(); + } + + public void cas(Register rs1, Register rs2, Register rd) { + casa(rs1, rs2, rd, Asi.ASI_PRIMARY); + } + + public void casx(Register rs1, Register rs2, Register rd) { + casxa(rs1, rs2, rd, Asi.ASI_PRIMARY); + } + + public void clr(Register dst) { + or(g0, g0, dst); + } + + public void clrb(SPARCAddress addr) { + stb(g0, addr); + } + + public void clrh(SPARCAddress addr) { + sth(g0, addr); + } + + public void clrx(SPARCAddress addr) { + stx(g0, addr); + } + + public void cmp(Register rs1, Register rs2) { + subcc(rs1, rs2, g0); + } + + public void cmp(Register rs1, int simm13) { + subcc(rs1, simm13, g0); + } + + public void dec(Register rd) { + sub(rd, 1, rd); + } + + public void dec(int simm13, Register rd) { + sub(rd, simm13, rd); + } + + public void jmp(SPARCAddress address) { + jmpl(address.getBase(), address.getDisplacement(), g0); + } + + public void jmp(Register rd) { + jmpl(rd, 0, g0); + } + + public void neg(Register rs1, Register rd) { + sub(g0, rs1, rd); + } + + public void neg(Register rd) { + sub(g0, rd, rd); + } + + public void mov(Register rs, Register rd) { + or(g0, rs, rd); + } + + public void mov(int simm13, Register rd) { + or(g0, simm13, rd); + } + + public void not(Register rs1, Register rd) { + xnor(rs1, g0, rd); + } + + public void not(Register rd) { + xnor(rd, g0, rd); + } + + public void restoreWindow() { + restore(g0, g0, g0); + } + + public void ret() { + jmpl(i7, 8, g0); + } + + /** + * Generates sethi hi22(value), dst; or dst, lo10(value), dst; code. + */ + public void setw(int value, Register dst, boolean forceRelocatable) { + if (!forceRelocatable && isSimm13(value)) { + or(g0, value, dst); + } else { + sethi(hi22(value), dst); + or(dst, lo10(value), dst); + } + } + + public void setx(long value, Register dst, boolean forceRelocatable) { + int lo = (int) (value & ~0); + sethix(value, dst, forceRelocatable); + if (lo10(lo) != 0 || forceRelocatable) { + add(dst, lo10(lo), dst); + } + } + + public void sethix(long value, Register dst, boolean forceRelocatable) { + final int hi = (int) (value >> 32); + final int lo = (int) (value & ~0); + + // This is the same logic as MacroAssembler::internal_set. + final int startPc = position(); + if (hi == 0 && lo >= 0) { + sethi(hi22(lo), dst); + } else if (hi == -1) { + sethi(hi22(~lo), dst); + xor(dst, ~lo10(~0), dst); + } else { + final int shiftcnt; + final int shiftcnt2; + sethi(hi22(hi), dst); + if ((hi & 0x3ff) != 0) { // Any bits? + // msb 32-bits are now in lsb 32 + or(dst, hi & 0x3ff, dst); + } + if ((lo & 0xFFFFFC00) != 0) { // done? + if (((lo >> 20) & 0xfff) != 0) { // Any bits set? + // Make room for next 12 bits + sllx(dst, 12, dst); + // Or in next 12 + or(dst, (lo >> 20) & 0xfff, dst); + shiftcnt = 0; // We already shifted + } else { + shiftcnt = 12; + } + if (((lo >> 10) & 0x3ff) != 0) { + // Make room for last 10 bits + sllx(dst, shiftcnt + 10, dst); + // Or in next 10 + or(dst, (lo >> 10) & 0x3ff, dst); + shiftcnt2 = 0; + } else { + shiftcnt2 = 10; + } + // Shift leaving disp field 0'd + sllx(dst, shiftcnt2 + 10, dst); + } else { + sllx(dst, 32, dst); + } + } + // Pad out the instruction sequence so it can be patched later. + if (forceRelocatable) { + while (position() < (startPc + (INSTRUCTION_SIZE * 7))) { + nop(); + } + } + } + + public void signx(Register rs, Register rd) { + sra(rs, g0, rd); + } + + public void signx(Register rd) { + sra(rd, g0, rd); + } + + public boolean isImmediateConstantLoad() { + return immediateConstantLoad; + } + + public ScratchRegister getScratchRegister() { + return scratchRegister[nextFreeScratchRegister++]; + } + + public class ScratchRegister implements AutoCloseable { + private final Register register; + + public ScratchRegister(Register register) { + super(); + this.register = register; + } + + public Register getRegister() { + return register; + } + + @Override + public void close() { + assert nextFreeScratchRegister > 0 : "Close called too often"; + nextFreeScratchRegister--; + } + } + + public void compareBranch(Register rs1, Register rs2, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction) { + assert isCPURegister(rs1, rs2); + assert ccRegister == Icc || ccRegister == Xcc; + if (hasFeature(CPUFeature.CBCOND)) { + if (delaySlotInstruction != null) { + delaySlotInstruction.run(); + } + CBCOND.emit(this, cond, ccRegister == Xcc, rs1, rs2, label); + } else { + if (cond == Equal && rs1.equals(g0)) { + BPR.emit(this, Rc_z, NOT_ANNUL, predict, rs1, label); + } else { + cmp(rs1, rs2); + BPCC.emit(this, ccRegister, cond, NOT_ANNUL, predict, label); + } + if (delaySlotInstruction != null) { + int positionBefore = position(); + delaySlotInstruction.run(); + int positionAfter = position(); + assert positionBefore - positionAfter > INSTRUCTION_SIZE : "Emitted more than one instruction into delay slot"; + } else { + nop(); + } + } + } + + public void compareBranch(Register rs1, int simm, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction) { + assert isCPURegister(rs1); + assert ccRegister == Icc || ccRegister == Xcc; + if (hasFeature(CPUFeature.CBCOND)) { + if (delaySlotInstruction != null) { + delaySlotInstruction.run(); + } + CBCOND.emit(this, cond, ccRegister == Xcc, rs1, simm, label); + } else { + if (cond == Equal && simm == 0) { + BPR.emit(this, Rc_z, NOT_ANNUL, PREDICT_NOT_TAKEN, rs1, label); + } else { + cmp(rs1, simm); + BPCC.emit(this, ccRegister, cond, NOT_ANNUL, predict, label); + } + if (delaySlotInstruction != null) { + int positionBefore = position(); + delaySlotInstruction.run(); + int positionAfter = position(); + assert positionBefore - positionAfter > INSTRUCTION_SIZE : "Emitted more than one instruction into delay slot"; + } else { + nop(); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java 2016-12-07 13:47:36.122463719 -0800 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013, 2016, 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.junit.Assert; + +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.target.Backend; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.runtime.RuntimeProvider; +import org.graalvm.compiler.serviceprovider.GraalServices; +import org.graalvm.compiler.test.GraalTest; + +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); + } + + 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); + try (Scope s = Debug.scope("assembleMethod", method, codeCache)) { + RegisterConfig registerConfig = codeCache.getRegisterConfig(); + CompilationIdentifier compilationId = backend.getCompilationIdentifier(method); + CallingConvention cc = backend.newLIRGenerationResult(compilationId, null, null, new StructuredGraph(method, AllowAssumptions.NO, compilationId), null).getCallingConvention(); + + CompilationResult compResult = new CompilationResult(); + byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc); + compResult.setTargetCode(targetCode, targetCode.length); + compResult.setTotalFrameSize(0); + compResult.close(); + + InstalledCode code = backend.addInstalledCode(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); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/overview.html 2016-12-07 13:47:36.387475363 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the com.oracle.max.asm project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/AbstractAddress.java 2016-12-07 13:47:36.651486964 -0800 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013, 2015, 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 { +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/AsmOptions.java 2016-12-07 13:47:36.915498564 -0800 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011, 2011, 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 int InitialCodeBufferSize = 232; +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Assembler.java 2016-12-07 13:47:37.180510209 -0800 @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2009, 2015, 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 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 jumpDisplacementHints; + + /** + * Backing code buffer. + */ + private final Buffer codeBuffer; + + protected Consumer codePatchingAnnotationConsumer; + + public Assembler(TargetDescription target) { + this.target = target; + this.codeBuffer = new Buffer(target.arch.getByteOrder()); + } + + public void setCodePatchingAnnotationConsumer(Consumer 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.getProperty("line.separator"); + + /** + * 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) { + return codeBuffer.close(trimmedCopy); + } + + public void bind(Label l) { + assert !l.isBound() : "can bind label only once"; + l.bind(position()); + l.patchInstructions(this); + } + + public abstract void align(int modulus); + + public abstract void jmp(Label l); + + protected abstract void patchJumpTarget(int branch, int jumpTarget); + + private Map 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); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Buffer.java 2016-12-07 13:47:37.445521853 -0800 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2009, 2014, 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; + +/** + * 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(); + 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()); + 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() { + data.clear(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Label.java 2016-12-07 13:47:37.709533454 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009, 2011, 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; + +/** + * This class represents a label within assembly code. + */ +public final class Label { + + private int position = -1; + private int blockId = -1; + + /** + * References to instructions that jump to this unresolved label. These instructions need to be + * patched when the label is bound using the {@link #patchInstructions(Assembler)} method. + */ + private ArrayList patchPositions = null; + + /** + * 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 the specified position. + * + * @param pos the position + */ + protected void bind(int pos) { + this.position = pos; + assert isBound(); + } + + public boolean isBound() { + return position >= 0; + } + + public void addPatchAt(int branchLocation) { + assert !isBound() : "Label is already bound " + this + " " + branchLocation + " at position " + position; + if (patchPositions == null) { + patchPositions = new ArrayList<>(2); + } + patchPositions.add(branchLocation); + } + + protected void patchInstructions(Assembler masm) { + assert isBound() : "Label should be bound"; + if (patchPositions != null) { + int target = position; + for (int i = 0; i < patchPositions.size(); ++i) { + int pos = patchPositions.get(i); + masm.patchJumpTarget(pos, target); + } + } + } + + public void reset() { + if (this.patchPositions != null) { + this.patchPositions.clear(); + } + this.position = -1; + } + + @Override + public String toString() { + return isBound() ? String.valueOf(position()) : "?"; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/NumUtil.java 2016-12-07 13:47:37.974545098 -0800 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.asm; + +// JaCoCo Exclude + +/** + * A collection of static utility functions that check ranges of numbers. + */ +public class NumUtil { + + public static boolean isShiftCount(int x) { + return 0 <= x && x < 32; + } + + /** + * Determines if a given {@code int} value is the range of unsigned byte values. + */ + public static boolean isUByte(int x) { + return (x & 0xff) == x; + } + + /** + * Determines if a given {@code int} value is the range of signed byte values. + */ + public static boolean isByte(int x) { + return (byte) x == x; + } + + /** + * Determines if a given {@code long} value is the range of unsigned byte values. + */ + public static boolean isUByte(long x) { + return (x & 0xffL) == x; + } + + /** + * Determines if a given {@code long} value is the range of signed byte values. + */ + public static boolean isByte(long l) { + return (byte) l == l; + } + + /** + * Determines if a given {@code long} value is the range of unsigned int values. + */ + public static boolean isUInt(long x) { + return (x & 0xffffffffL) == x; + } + + /** + * Determines if a given {@code long} value is the range of signed int values. + */ + public static boolean isInt(long l) { + return (int) l == l; + } + + /** + * Determines if a given {@code int} value is the range of signed short values. + */ + public static boolean isShort(int x) { + return (short) x == x; + } + + /** + * Determines if a given {@code long} value is the range of signed short values. + */ + public static boolean isShort(long x) { + return (short) x == x; + } + + public static boolean isUShort(int s) { + return s == (s & 0xFFFF); + } + + public static boolean isUShort(long s) { + return s == (s & 0xFFFF); + } + + public static boolean is32bit(long x) { + return -0x80000000L <= x && x < 0x80000000L; + } + + public static short safeToShort(int v) { + assert isShort(v); + return (short) v; + } + + public static int roundUp(int number, int mod) { + return ((number + mod - 1) / mod) * mod; + } + + public static long roundUp(long number, long mod) { + return ((number + mod - 1L) / mod) * mod; + } + + public static int roundDown(int number, int mod) { + return number / mod * mod; + } + + public static long roundDown(long number, long mod) { + return number / mod * mod; + } + + public static int log2Ceil(int val) { + int x = 1; + int log2 = 0; + while (x < val) { + log2++; + x *= 2; + } + return log2; + } + + public static boolean isUnsignedNbit(int n, int value) { + assert n > 0 && n < 32; + return 32 - Integer.numberOfLeadingZeros(value) <= n; + } + + public static boolean isUnsignedNbit(int n, long value) { + assert n > 0 && n < 64; + return 64 - Long.numberOfLeadingZeros(value) <= n; + } + + public static boolean isSignedNbit(int n, int value) { + assert n > 0 && n < 32; + int min = -(1 << (n - 1)); + int max = (1 << (n - 1)) - 1; + return value >= min && value <= max; + } + + public static boolean isSignedNbit(int n, long value) { + assert n > 0 && n < 64; + long min = -(1L << (n - 1)); + long max = (1L << (n - 1)) - 1; + return value >= min && value <= max; + } + + /** + * + * @param n Number of bits that should be set to 1. Must be between 0 and 32 (inclusive). + * @return A number with n bits set to 1. + */ + public static int getNbitNumberInt(int n) { + assert n >= 0 && n <= 32 : "0 <= n <= 32; instead: " + n; + if (n < 32) { + return (1 << n) - 1; + } else { + return 0xFFFFFFFF; + } + } + + /** + * + * @param n Number of bits that should be set to 1. Must be between 0 and 64 (inclusive). + * @return A number with n bits set to 1. + */ + public static long getNbitNumberLong(int n) { + assert n >= 0 && n <= 64; + if (n < 64) { + return (1L << n) - 1; + } else { + return 0xFFFFFFFFFFFFFFFFL; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/overview.html 2016-12-07 13:47:38.238556699 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.bytecode project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BridgeMethodUtils.java 2016-12-07 13:47:38.502568299 -0800 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2016, 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 6695379 + * @see 495396 + * @see 427745 + */ +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("") && 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 getAnnotation(Class 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 getParameterAnnotation(Class 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; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecode.java 2016-12-07 13:47:38.766579900 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016, 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(); + + 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(']'); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeDisassembler.java 2016-12-07 13:47:39.031591544 -0800 @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2012, 2014, 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 (RuntimeException 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 + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeLookupSwitch.java 2016-12-07 13:47:39.297603233 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2009, 2011, 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; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeProvider.java 2016-12-07 13:47:39.560614789 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, 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.ResolvedJavaMethod; + +/** + * Provides a {@link Bytecode} object for interposing on the bytecode of a + * {@link ResolvedJavaMethod} (i.e., potentially getting bytecode different than + * {@link ResolvedJavaMethod#getCode()}). + */ +public interface BytecodeProvider { + + /** + * Gets a {@link Bytecode} object that supplies bytecode properties for {@code method}. + */ + Bytecode getBytecode(ResolvedJavaMethod method); + + /** + * Determines if this provider supports the INVOKEDYNAMIC bytecode. + */ + boolean supportsInvokedynamic(); + + /** + * Determines if methods parsed using this provider should be recorded so that method + * redefinition can invalidate the resulting code. + */ + boolean shouldRecordMethodDependencies(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeStream.java 2016-12-07 13:47:39.825626434 -0800 @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2009, 2011, 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 class that makes iterating over bytecodes and reading operands simpler and less error + * prone. For example, it handles the {@link Bytecodes#WIDE} instruction and wide variants of + * instructions internally. + */ +public final class BytecodeStream { + + private final byte[] code; + private int opcode; + private int curBCI; + private int nextBCI; + + /** + * Creates a new {@code BytecodeStream} for the specified bytecode. + * + * @param code the array of bytes that contains the bytecode + */ + public BytecodeStream(byte[] code) { + assert code != null; + this.code = code; + setBCI(0); + } + + /** + * Advances to the next bytecode. + */ + public void next() { + setBCI(nextBCI); + } + + /** + * Gets the next bytecode index (no side-effects). + * + * @return the next bytecode index + */ + public int nextBCI() { + return nextBCI; + } + + /** + * Gets the current bytecode index. + * + * @return the current bytecode index + */ + public int currentBCI() { + return curBCI; + } + + /** + * Gets the bytecode index of the end of the code. + * + * @return the index of the end of the code + */ + public int endBCI() { + return code.length; + } + + /** + * Gets the current opcode. This method will never return the {@link Bytecodes#WIDE WIDE} + * opcode, but will instead return the opcode that is modified by the {@code WIDE} opcode. + * + * @return the current opcode; {@link Bytecodes#END} if at or beyond the end of the code + */ + public int currentBC() { + if (opcode == Bytecodes.WIDE) { + return Bytes.beU1(code, curBCI + 1); + } else { + return opcode; + } + } + + /** + * Reads the index of a local variable for one of the load or store instructions. The WIDE + * modifier is handled internally. + * + * @return the index of the local variable + */ + public int readLocalIndex() { + // read local variable index for load/store + if (opcode == Bytecodes.WIDE) { + return Bytes.beU2(code, curBCI + 2); + } + return Bytes.beU1(code, curBCI + 1); + } + + /** + * Read the delta for an {@link Bytecodes#IINC} bytecode. + * + * @return the delta for the {@code IINC} + */ + public int readIncrement() { + // read the delta for the iinc bytecode + if (opcode == Bytecodes.WIDE) { + return Bytes.beS2(code, curBCI + 4); + } + return Bytes.beS1(code, curBCI + 2); + } + + /** + * Read the destination of a {@link Bytecodes#GOTO} or {@code IF} instructions. + * + * @return the destination bytecode index + */ + public int readBranchDest() { + // reads the destination for a branch bytecode + if (opcode == Bytecodes.GOTO_W || opcode == Bytecodes.JSR_W) { + return curBCI + Bytes.beS4(code, curBCI + 1); + } else { + return curBCI + Bytes.beS2(code, curBCI + 1); + } + } + + /** + * Read a signed 4-byte integer from the bytecode stream at the specified bytecode index. + * + * @param bci the bytecode index + * @return the integer value + */ + public int readInt(int bci) { + // reads a 4-byte signed value + return Bytes.beS4(code, bci); + } + + /** + * Reads an unsigned, 1-byte value from the bytecode stream at the specified bytecode index. + * + * @param bci the bytecode index + * @return the byte + */ + public int readUByte(int bci) { + return Bytes.beU1(code, bci); + } + + /** + * Reads a constant pool index for the current instruction. + * + * @return the constant pool index + */ + public char readCPI() { + if (opcode == Bytecodes.LDC) { + return (char) Bytes.beU1(code, curBCI + 1); + } + return (char) Bytes.beU2(code, curBCI + 1); + } + + /** + * Reads a constant pool index for an invokedynamic instruction. + * + * @return the constant pool index + */ + public int readCPI4() { + assert opcode == Bytecodes.INVOKEDYNAMIC; + return Bytes.beS4(code, curBCI + 1); + } + + /** + * Reads a signed, 1-byte value for the current instruction (e.g. BIPUSH). + * + * @return the byte + */ + public byte readByte() { + return code[curBCI + 1]; + } + + /** + * Reads a signed, 2-byte short for the current instruction (e.g. SIPUSH). + * + * @return the short value + */ + public short readShort() { + return (short) Bytes.beS2(code, curBCI + 1); + } + + /** + * Sets the bytecode index to the specified value. If {@code bci} is beyond the end of the + * array, {@link #currentBC} will return {@link Bytecodes#END} and other methods may throw + * {@link ArrayIndexOutOfBoundsException}. + * + * @param bci the new bytecode index + */ + public void setBCI(int bci) { + curBCI = bci; + if (curBCI < code.length) { + opcode = Bytes.beU1(code, bci); + assert opcode < Bytecodes.BREAKPOINT : "illegal bytecode"; + nextBCI = bci + lengthOf(); + } else { + opcode = Bytecodes.END; + nextBCI = curBCI; + } + } + + /** + * Gets the length of the current bytecode. + */ + private int lengthOf() { + int length = Bytecodes.lengthOf(opcode); + if (length == 0) { + switch (opcode) { + case Bytecodes.TABLESWITCH: { + return new BytecodeTableSwitch(this, curBCI).size(); + } + case Bytecodes.LOOKUPSWITCH: { + return new BytecodeLookupSwitch(this, curBCI).size(); + } + case Bytecodes.WIDE: { + int opc = Bytes.beU1(code, curBCI + 1); + if (opc == Bytecodes.RET) { + return 4; + } else if (opc == Bytecodes.IINC) { + return 6; + } else { + return 4; // a load or store bytecode + } + } + default: + throw new Error("unknown variable-length bytecode: " + opcode); + } + } + return length; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeSwitch.java 2016-12-07 13:47:40.090638078 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2009, 2011, 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; + +/** + * An abstract class that provides the state and methods common to {@link Bytecodes#LOOKUPSWITCH} + * and {@link Bytecodes#TABLESWITCH} instructions. + */ +public abstract class BytecodeSwitch { + + /** + * The {@link BytecodeStream} containing the bytecode array. + */ + protected final BytecodeStream stream; + /** + * Index of start of switch instruction. + */ + protected final int bci; + /** + * Index of the start of the additional data for the switch instruction, aligned to a multiple + * of four from the method start. + */ + protected final int alignedBci; + + /** + * 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 BytecodeSwitch(BytecodeStream stream, int bci) { + this.stream = stream; + this.bci = bci; + this.alignedBci = (bci + 4) & 0xfffffffc; + } + + /** + * Gets the current bytecode index. + * + * @return the current bytecode index + */ + public int bci() { + return bci; + } + + /** + * Gets the index of the instruction denoted by the {@code i}'th switch target. + * + * @param i index of the switch target + * @return the index of the instruction denoted by the {@code i}'th switch target + */ + public int targetAt(int i) { + return bci + offsetAt(i); + } + + /** + * Gets the index of the instruction for the default switch target. + * + * @return the index of the instruction for the default switch target + */ + public int defaultTarget() { + return bci + defaultOffset(); + } + + /** + * Gets the offset from the start of the switch instruction to the default switch target. + * + * @return the offset to the default switch target + */ + public int defaultOffset() { + return stream.readInt(alignedBci); + } + + /** + * Gets the key at {@code i}'th switch target index. + * + * @param i the switch target index + * @return the key at {@code i}'th switch target index + */ + public abstract int keyAt(int i); + + /** + * Gets the offset from the start of the switch instruction for the {@code i}'th switch target. + * + * @param i the switch target index + * @return the offset to the {@code i}'th switch target + */ + public abstract int offsetAt(int i); + + /** + * Gets the number of switch targets. + * + * @return the number of switch targets + */ + public abstract int numberOfCases(); + + /** + * Gets the total size in bytes of the switch instruction. + * + * @return the total size in bytes of the switch instruction + */ + public abstract int size(); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeTableSwitch.java 2016-12-07 13:47:40.356649767 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009, 2011, 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#TABLESWITCH} bytecodes. + */ +public class BytecodeTableSwitch extends BytecodeSwitch { + + private static final int OFFSET_TO_LOW_KEY = 4; + private static final int OFFSET_TO_HIGH_KEY = 8; + private static final int OFFSET_TO_FIRST_JUMP_OFFSET = 12; + private static final int JUMP_OFFSET_SIZE = 4; + + /** + * 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 BytecodeTableSwitch(BytecodeStream stream, int bci) { + super(stream, bci); + } + + /** + * Gets the low key of the table switch. + * + * @return the low key + */ + public int lowKey() { + return stream.readInt(alignedBci + OFFSET_TO_LOW_KEY); + } + + /** + * Gets the high key of the table switch. + * + * @return the high key + */ + public int highKey() { + return stream.readInt(alignedBci + OFFSET_TO_HIGH_KEY); + } + + @Override + public int keyAt(int i) { + return lowKey() + i; + } + + @Override + public int offsetAt(int i) { + return stream.readInt(alignedBci + OFFSET_TO_FIRST_JUMP_OFFSET + JUMP_OFFSET_SIZE * i); + } + + @Override + public int numberOfCases() { + return highKey() - lowKey() + 1; + } + + @Override + public int size() { + return alignedBci + OFFSET_TO_FIRST_JUMP_OFFSET + JUMP_OFFSET_SIZE * numberOfCases() - bci; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecodes.java 2016-12-07 13:47:40.621661411 -0800 @@ -0,0 +1,840 @@ +/* + * Copyright (c) 2009, 2011, 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.Flags.ASSOCIATIVE; +import static org.graalvm.compiler.bytecode.Bytecodes.Flags.BRANCH; +import static org.graalvm.compiler.bytecode.Bytecodes.Flags.COMMUTATIVE; +import static org.graalvm.compiler.bytecode.Bytecodes.Flags.FALL_THROUGH; +import static org.graalvm.compiler.bytecode.Bytecodes.Flags.FIELD_READ; +import static org.graalvm.compiler.bytecode.Bytecodes.Flags.FIELD_WRITE; +import static org.graalvm.compiler.bytecode.Bytecodes.Flags.INVOKE; +import static org.graalvm.compiler.bytecode.Bytecodes.Flags.LOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.Flags.STOP; +import static org.graalvm.compiler.bytecode.Bytecodes.Flags.STORE; +import static org.graalvm.compiler.bytecode.Bytecodes.Flags.TRAP; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +/** + * Definitions of the standard Java bytecodes defined by + * Java + * Virtual Machine Specification. + */ +public class Bytecodes { + + // @formatter:off + public static final int NOP = 0; // 0x00 + public static final int ACONST_NULL = 1; // 0x01 + public static final int ICONST_M1 = 2; // 0x02 + public static final int ICONST_0 = 3; // 0x03 + public static final int ICONST_1 = 4; // 0x04 + public static final int ICONST_2 = 5; // 0x05 + public static final int ICONST_3 = 6; // 0x06 + public static final int ICONST_4 = 7; // 0x07 + public static final int ICONST_5 = 8; // 0x08 + public static final int LCONST_0 = 9; // 0x09 + public static final int LCONST_1 = 10; // 0x0A + public static final int FCONST_0 = 11; // 0x0B + public static final int FCONST_1 = 12; // 0x0C + public static final int FCONST_2 = 13; // 0x0D + public static final int DCONST_0 = 14; // 0x0E + public static final int DCONST_1 = 15; // 0x0F + public static final int BIPUSH = 16; // 0x10 + public static final int SIPUSH = 17; // 0x11 + public static final int LDC = 18; // 0x12 + public static final int LDC_W = 19; // 0x13 + public static final int LDC2_W = 20; // 0x14 + public static final int ILOAD = 21; // 0x15 + public static final int LLOAD = 22; // 0x16 + public static final int FLOAD = 23; // 0x17 + public static final int DLOAD = 24; // 0x18 + public static final int ALOAD = 25; // 0x19 + public static final int ILOAD_0 = 26; // 0x1A + public static final int ILOAD_1 = 27; // 0x1B + public static final int ILOAD_2 = 28; // 0x1C + public static final int ILOAD_3 = 29; // 0x1D + public static final int LLOAD_0 = 30; // 0x1E + public static final int LLOAD_1 = 31; // 0x1F + public static final int LLOAD_2 = 32; // 0x20 + public static final int LLOAD_3 = 33; // 0x21 + public static final int FLOAD_0 = 34; // 0x22 + public static final int FLOAD_1 = 35; // 0x23 + public static final int FLOAD_2 = 36; // 0x24 + public static final int FLOAD_3 = 37; // 0x25 + public static final int DLOAD_0 = 38; // 0x26 + public static final int DLOAD_1 = 39; // 0x27 + public static final int DLOAD_2 = 40; // 0x28 + public static final int DLOAD_3 = 41; // 0x29 + public static final int ALOAD_0 = 42; // 0x2A + public static final int ALOAD_1 = 43; // 0x2B + public static final int ALOAD_2 = 44; // 0x2C + public static final int ALOAD_3 = 45; // 0x2D + public static final int IALOAD = 46; // 0x2E + public static final int LALOAD = 47; // 0x2F + public static final int FALOAD = 48; // 0x30 + public static final int DALOAD = 49; // 0x31 + public static final int AALOAD = 50; // 0x32 + public static final int BALOAD = 51; // 0x33 + public static final int CALOAD = 52; // 0x34 + public static final int SALOAD = 53; // 0x35 + public static final int ISTORE = 54; // 0x36 + public static final int LSTORE = 55; // 0x37 + public static final int FSTORE = 56; // 0x38 + public static final int DSTORE = 57; // 0x39 + public static final int ASTORE = 58; // 0x3A + public static final int ISTORE_0 = 59; // 0x3B + public static final int ISTORE_1 = 60; // 0x3C + public static final int ISTORE_2 = 61; // 0x3D + public static final int ISTORE_3 = 62; // 0x3E + public static final int LSTORE_0 = 63; // 0x3F + public static final int LSTORE_1 = 64; // 0x40 + public static final int LSTORE_2 = 65; // 0x41 + public static final int LSTORE_3 = 66; // 0x42 + public static final int FSTORE_0 = 67; // 0x43 + public static final int FSTORE_1 = 68; // 0x44 + public static final int FSTORE_2 = 69; // 0x45 + public static final int FSTORE_3 = 70; // 0x46 + public static final int DSTORE_0 = 71; // 0x47 + public static final int DSTORE_1 = 72; // 0x48 + public static final int DSTORE_2 = 73; // 0x49 + public static final int DSTORE_3 = 74; // 0x4A + public static final int ASTORE_0 = 75; // 0x4B + public static final int ASTORE_1 = 76; // 0x4C + public static final int ASTORE_2 = 77; // 0x4D + public static final int ASTORE_3 = 78; // 0x4E + public static final int IASTORE = 79; // 0x4F + public static final int LASTORE = 80; // 0x50 + public static final int FASTORE = 81; // 0x51 + public static final int DASTORE = 82; // 0x52 + public static final int AASTORE = 83; // 0x53 + public static final int BASTORE = 84; // 0x54 + public static final int CASTORE = 85; // 0x55 + public static final int SASTORE = 86; // 0x56 + public static final int POP = 87; // 0x57 + public static final int POP2 = 88; // 0x58 + public static final int DUP = 89; // 0x59 + public static final int DUP_X1 = 90; // 0x5A + public static final int DUP_X2 = 91; // 0x5B + public static final int DUP2 = 92; // 0x5C + public static final int DUP2_X1 = 93; // 0x5D + public static final int DUP2_X2 = 94; // 0x5E + public static final int SWAP = 95; // 0x5F + public static final int IADD = 96; // 0x60 + public static final int LADD = 97; // 0x61 + public static final int FADD = 98; // 0x62 + public static final int DADD = 99; // 0x63 + public static final int ISUB = 100; // 0x64 + public static final int LSUB = 101; // 0x65 + public static final int FSUB = 102; // 0x66 + public static final int DSUB = 103; // 0x67 + public static final int IMUL = 104; // 0x68 + public static final int LMUL = 105; // 0x69 + public static final int FMUL = 106; // 0x6A + public static final int DMUL = 107; // 0x6B + public static final int IDIV = 108; // 0x6C + public static final int LDIV = 109; // 0x6D + public static final int FDIV = 110; // 0x6E + public static final int DDIV = 111; // 0x6F + public static final int IREM = 112; // 0x70 + public static final int LREM = 113; // 0x71 + public static final int FREM = 114; // 0x72 + public static final int DREM = 115; // 0x73 + public static final int INEG = 116; // 0x74 + public static final int LNEG = 117; // 0x75 + public static final int FNEG = 118; // 0x76 + public static final int DNEG = 119; // 0x77 + public static final int ISHL = 120; // 0x78 + public static final int LSHL = 121; // 0x79 + public static final int ISHR = 122; // 0x7A + public static final int LSHR = 123; // 0x7B + public static final int IUSHR = 124; // 0x7C + public static final int LUSHR = 125; // 0x7D + public static final int IAND = 126; // 0x7E + public static final int LAND = 127; // 0x7F + public static final int IOR = 128; // 0x80 + public static final int LOR = 129; // 0x81 + public static final int IXOR = 130; // 0x82 + public static final int LXOR = 131; // 0x83 + public static final int IINC = 132; // 0x84 + public static final int I2L = 133; // 0x85 + public static final int I2F = 134; // 0x86 + public static final int I2D = 135; // 0x87 + public static final int L2I = 136; // 0x88 + public static final int L2F = 137; // 0x89 + public static final int L2D = 138; // 0x8A + public static final int F2I = 139; // 0x8B + public static final int F2L = 140; // 0x8C + public static final int F2D = 141; // 0x8D + public static final int D2I = 142; // 0x8E + public static final int D2L = 143; // 0x8F + public static final int D2F = 144; // 0x90 + public static final int I2B = 145; // 0x91 + public static final int I2C = 146; // 0x92 + public static final int I2S = 147; // 0x93 + public static final int LCMP = 148; // 0x94 + public static final int FCMPL = 149; // 0x95 + public static final int FCMPG = 150; // 0x96 + public static final int DCMPL = 151; // 0x97 + public static final int DCMPG = 152; // 0x98 + public static final int IFEQ = 153; // 0x99 + public static final int IFNE = 154; // 0x9A + public static final int IFLT = 155; // 0x9B + public static final int IFGE = 156; // 0x9C + public static final int IFGT = 157; // 0x9D + public static final int IFLE = 158; // 0x9E + public static final int IF_ICMPEQ = 159; // 0x9F + public static final int IF_ICMPNE = 160; // 0xA0 + public static final int IF_ICMPLT = 161; // 0xA1 + public static final int IF_ICMPGE = 162; // 0xA2 + public static final int IF_ICMPGT = 163; // 0xA3 + public static final int IF_ICMPLE = 164; // 0xA4 + public static final int IF_ACMPEQ = 165; // 0xA5 + public static final int IF_ACMPNE = 166; // 0xA6 + public static final int GOTO = 167; // 0xA7 + public static final int JSR = 168; // 0xA8 + public static final int RET = 169; // 0xA9 + public static final int TABLESWITCH = 170; // 0xAA + public static final int LOOKUPSWITCH = 171; // 0xAB + public static final int IRETURN = 172; // 0xAC + public static final int LRETURN = 173; // 0xAD + public static final int FRETURN = 174; // 0xAE + public static final int DRETURN = 175; // 0xAF + public static final int ARETURN = 176; // 0xB0 + public static final int RETURN = 177; // 0xB1 + public static final int GETSTATIC = 178; // 0xB2 + public static final int PUTSTATIC = 179; // 0xB3 + public static final int GETFIELD = 180; // 0xB4 + public static final int PUTFIELD = 181; // 0xB5 + public static final int INVOKEVIRTUAL = 182; // 0xB6 + public static final int INVOKESPECIAL = 183; // 0xB7 + public static final int INVOKESTATIC = 184; // 0xB8 + public static final int INVOKEINTERFACE = 185; // 0xB9 + public static final int INVOKEDYNAMIC = 186; // 0xBA + public static final int NEW = 187; // 0xBB + public static final int NEWARRAY = 188; // 0xBC + public static final int ANEWARRAY = 189; // 0xBD + public static final int ARRAYLENGTH = 190; // 0xBE + public static final int ATHROW = 191; // 0xBF + public static final int CHECKCAST = 192; // 0xC0 + public static final int INSTANCEOF = 193; // 0xC1 + public static final int MONITORENTER = 194; // 0xC2 + public static final int MONITOREXIT = 195; // 0xC3 + public static final int WIDE = 196; // 0xC4 + public static final int MULTIANEWARRAY = 197; // 0xC5 + public static final int IFNULL = 198; // 0xC6 + public static final int IFNONNULL = 199; // 0xC7 + public static final int GOTO_W = 200; // 0xC8 + public static final int JSR_W = 201; // 0xC9 + public static final int BREAKPOINT = 202; // 0xCA + + public static final int ILLEGAL = 255; + public static final int END = 256; + // @formatter:on + + /** + * The last opcode defined by the JVM specification. To iterate over all JVM bytecodes: + * + *

+     * for (int opcode = 0; opcode <= Bytecodes.LAST_JVM_OPCODE; ++opcode) {
+     *     //
+     * }
+     * 
+ */ + public static final int LAST_JVM_OPCODE = JSR_W; + + /** + * A collection of flags describing various bytecode attributes. + */ + static class Flags { + + /** + * Denotes an instruction that ends a basic block and does not let control flow fall through + * to its lexical successor. + */ + static final int STOP = 0x00000001; + + /** + * Denotes an instruction that ends a basic block and may let control flow fall through to + * its lexical successor. In practice this means it is a conditional branch. + */ + static final int FALL_THROUGH = 0x00000002; + + /** + * Denotes an instruction that has a 2 or 4 byte operand that is an offset to another + * instruction in the same method. This does not include the {@link Bytecodes#TABLESWITCH} + * or {@link Bytecodes#LOOKUPSWITCH} instructions. + */ + static final int BRANCH = 0x00000004; + + /** + * Denotes an instruction that reads the value of a static or instance field. + */ + static final int FIELD_READ = 0x00000008; + + /** + * Denotes an instruction that writes the value of a static or instance field. + */ + static final int FIELD_WRITE = 0x00000010; + + /** + * Denotes an instruction that can cause a trap. + */ + static final int TRAP = 0x00000080; + /** + * Denotes an instruction that is commutative. + */ + static final int COMMUTATIVE = 0x00000100; + /** + * Denotes an instruction that is associative. + */ + static final int ASSOCIATIVE = 0x00000200; + /** + * Denotes an instruction that loads an operand. + */ + static final int LOAD = 0x00000400; + /** + * Denotes an instruction that stores an operand. + */ + static final int STORE = 0x00000800; + /** + * Denotes the 4 INVOKE* instructions. + */ + static final int INVOKE = 0x00001000; + } + + // Performs a sanity check that none of the flags overlap. + static { + int allFlags = 0; + try { + for (Field field : Flags.class.getDeclaredFields()) { + int flagsFilter = Modifier.FINAL | Modifier.STATIC; + if ((field.getModifiers() & flagsFilter) == flagsFilter && !field.isSynthetic()) { + assert field.getType() == int.class : "Field is not int : " + field; + final int flag = field.getInt(null); + assert flag != 0; + assert (flag & allFlags) == 0 : field.getName() + " has a value conflicting with another flag"; + allFlags |= flag; + } + } + } catch (Exception e) { + throw new InternalError(e.toString()); + } + } + + /** + * An array that maps from a bytecode value to a {@link String} for the corresponding + * instruction mnemonic. + */ + private static final String[] nameArray = new String[256]; + + /** + * An array that maps from a bytecode value to the set of {@link Flags} for the corresponding + * instruction. + */ + private static final int[] flagsArray = new int[256]; + + /** + * An array that maps from a bytecode value to the length in bytes for the corresponding + * instruction. + */ + private static final int[] lengthArray = new int[256]; + + /** + * An array that maps from a bytecode value to the number of slots pushed on the stack by the + * corresponding instruction. + */ + private static final int[] stackEffectArray = new int[256]; + + // Checkstyle: stop + // @formatter:off + static { + def(NOP , "nop" , "b" , 0); + def(ACONST_NULL , "aconst_null" , "b" , 1); + def(ICONST_M1 , "iconst_m1" , "b" , 1); + def(ICONST_0 , "iconst_0" , "b" , 1); + def(ICONST_1 , "iconst_1" , "b" , 1); + def(ICONST_2 , "iconst_2" , "b" , 1); + def(ICONST_3 , "iconst_3" , "b" , 1); + def(ICONST_4 , "iconst_4" , "b" , 1); + def(ICONST_5 , "iconst_5" , "b" , 1); + def(LCONST_0 , "lconst_0" , "b" , 2); + def(LCONST_1 , "lconst_1" , "b" , 2); + def(FCONST_0 , "fconst_0" , "b" , 1); + def(FCONST_1 , "fconst_1" , "b" , 1); + def(FCONST_2 , "fconst_2" , "b" , 1); + def(DCONST_0 , "dconst_0" , "b" , 2); + def(DCONST_1 , "dconst_1" , "b" , 2); + def(BIPUSH , "bipush" , "bc" , 1); + def(SIPUSH , "sipush" , "bcc" , 1); + def(LDC , "ldc" , "bi" , 1, TRAP); + def(LDC_W , "ldc_w" , "bii" , 1, TRAP); + def(LDC2_W , "ldc2_w" , "bii" , 2, TRAP); + def(ILOAD , "iload" , "bi" , 1, LOAD); + def(LLOAD , "lload" , "bi" , 2, LOAD); + def(FLOAD , "fload" , "bi" , 1, LOAD); + def(DLOAD , "dload" , "bi" , 2, LOAD); + def(ALOAD , "aload" , "bi" , 1, LOAD); + def(ILOAD_0 , "iload_0" , "b" , 1, LOAD); + def(ILOAD_1 , "iload_1" , "b" , 1, LOAD); + def(ILOAD_2 , "iload_2" , "b" , 1, LOAD); + def(ILOAD_3 , "iload_3" , "b" , 1, LOAD); + def(LLOAD_0 , "lload_0" , "b" , 2, LOAD); + def(LLOAD_1 , "lload_1" , "b" , 2, LOAD); + def(LLOAD_2 , "lload_2" , "b" , 2, LOAD); + def(LLOAD_3 , "lload_3" , "b" , 2, LOAD); + def(FLOAD_0 , "fload_0" , "b" , 1, LOAD); + def(FLOAD_1 , "fload_1" , "b" , 1, LOAD); + def(FLOAD_2 , "fload_2" , "b" , 1, LOAD); + def(FLOAD_3 , "fload_3" , "b" , 1, LOAD); + def(DLOAD_0 , "dload_0" , "b" , 2, LOAD); + def(DLOAD_1 , "dload_1" , "b" , 2, LOAD); + def(DLOAD_2 , "dload_2" , "b" , 2, LOAD); + def(DLOAD_3 , "dload_3" , "b" , 2, LOAD); + def(ALOAD_0 , "aload_0" , "b" , 1, LOAD); + def(ALOAD_1 , "aload_1" , "b" , 1, LOAD); + def(ALOAD_2 , "aload_2" , "b" , 1, LOAD); + def(ALOAD_3 , "aload_3" , "b" , 1, LOAD); + def(IALOAD , "iaload" , "b" , -1, TRAP); + def(LALOAD , "laload" , "b" , 0, TRAP); + def(FALOAD , "faload" , "b" , -1, TRAP); + def(DALOAD , "daload" , "b" , 0, TRAP); + def(AALOAD , "aaload" , "b" , -1, TRAP); + def(BALOAD , "baload" , "b" , -1, TRAP); + def(CALOAD , "caload" , "b" , -1, TRAP); + def(SALOAD , "saload" , "b" , -1, TRAP); + def(ISTORE , "istore" , "bi" , -1, STORE); + def(LSTORE , "lstore" , "bi" , -2, STORE); + def(FSTORE , "fstore" , "bi" , -1, STORE); + def(DSTORE , "dstore" , "bi" , -2, STORE); + def(ASTORE , "astore" , "bi" , -1, STORE); + def(ISTORE_0 , "istore_0" , "b" , -1, STORE); + def(ISTORE_1 , "istore_1" , "b" , -1, STORE); + def(ISTORE_2 , "istore_2" , "b" , -1, STORE); + def(ISTORE_3 , "istore_3" , "b" , -1, STORE); + def(LSTORE_0 , "lstore_0" , "b" , -2, STORE); + def(LSTORE_1 , "lstore_1" , "b" , -2, STORE); + def(LSTORE_2 , "lstore_2" , "b" , -2, STORE); + def(LSTORE_3 , "lstore_3" , "b" , -2, STORE); + def(FSTORE_0 , "fstore_0" , "b" , -1, STORE); + def(FSTORE_1 , "fstore_1" , "b" , -1, STORE); + def(FSTORE_2 , "fstore_2" , "b" , -1, STORE); + def(FSTORE_3 , "fstore_3" , "b" , -1, STORE); + def(DSTORE_0 , "dstore_0" , "b" , -2, STORE); + def(DSTORE_1 , "dstore_1" , "b" , -2, STORE); + def(DSTORE_2 , "dstore_2" , "b" , -2, STORE); + def(DSTORE_3 , "dstore_3" , "b" , -2, STORE); + def(ASTORE_0 , "astore_0" , "b" , -1, STORE); + def(ASTORE_1 , "astore_1" , "b" , -1, STORE); + def(ASTORE_2 , "astore_2" , "b" , -1, STORE); + def(ASTORE_3 , "astore_3" , "b" , -1, STORE); + def(IASTORE , "iastore" , "b" , -3, TRAP); + def(LASTORE , "lastore" , "b" , -4, TRAP); + def(FASTORE , "fastore" , "b" , -3, TRAP); + def(DASTORE , "dastore" , "b" , -4, TRAP); + def(AASTORE , "aastore" , "b" , -3, TRAP); + def(BASTORE , "bastore" , "b" , -3, TRAP); + def(CASTORE , "castore" , "b" , -3, TRAP); + def(SASTORE , "sastore" , "b" , -3, TRAP); + def(POP , "pop" , "b" , -1); + def(POP2 , "pop2" , "b" , -2); + def(DUP , "dup" , "b" , 1); + def(DUP_X1 , "dup_x1" , "b" , 1); + def(DUP_X2 , "dup_x2" , "b" , 1); + def(DUP2 , "dup2" , "b" , 2); + def(DUP2_X1 , "dup2_x1" , "b" , 2); + def(DUP2_X2 , "dup2_x2" , "b" , 2); + def(SWAP , "swap" , "b" , 0); + def(IADD , "iadd" , "b" , -1, COMMUTATIVE | ASSOCIATIVE); + def(LADD , "ladd" , "b" , -2, COMMUTATIVE | ASSOCIATIVE); + def(FADD , "fadd" , "b" , -1, COMMUTATIVE | ASSOCIATIVE); + def(DADD , "dadd" , "b" , -2, COMMUTATIVE | ASSOCIATIVE); + def(ISUB , "isub" , "b" , -1); + def(LSUB , "lsub" , "b" , -2); + def(FSUB , "fsub" , "b" , -1); + def(DSUB , "dsub" , "b" , -2); + def(IMUL , "imul" , "b" , -1, COMMUTATIVE | ASSOCIATIVE); + def(LMUL , "lmul" , "b" , -2, COMMUTATIVE | ASSOCIATIVE); + def(FMUL , "fmul" , "b" , -1, COMMUTATIVE | ASSOCIATIVE); + def(DMUL , "dmul" , "b" , -2, COMMUTATIVE | ASSOCIATIVE); + def(IDIV , "idiv" , "b" , -1, TRAP); + def(LDIV , "ldiv" , "b" , -2, TRAP); + def(FDIV , "fdiv" , "b" , -1); + def(DDIV , "ddiv" , "b" , -2); + def(IREM , "irem" , "b" , -1, TRAP); + def(LREM , "lrem" , "b" , -2, TRAP); + def(FREM , "frem" , "b" , -1); + def(DREM , "drem" , "b" , -2); + def(INEG , "ineg" , "b" , 0); + def(LNEG , "lneg" , "b" , 0); + def(FNEG , "fneg" , "b" , 0); + def(DNEG , "dneg" , "b" , 0); + def(ISHL , "ishl" , "b" , -1); + def(LSHL , "lshl" , "b" , -1); + def(ISHR , "ishr" , "b" , -1); + def(LSHR , "lshr" , "b" , -1); + def(IUSHR , "iushr" , "b" , -1); + def(LUSHR , "lushr" , "b" , -1); + def(IAND , "iand" , "b" , -1, COMMUTATIVE | ASSOCIATIVE); + def(LAND , "land" , "b" , -2, COMMUTATIVE | ASSOCIATIVE); + def(IOR , "ior" , "b" , -1, COMMUTATIVE | ASSOCIATIVE); + def(LOR , "lor" , "b" , -2, COMMUTATIVE | ASSOCIATIVE); + def(IXOR , "ixor" , "b" , -1, COMMUTATIVE | ASSOCIATIVE); + def(LXOR , "lxor" , "b" , -2, COMMUTATIVE | ASSOCIATIVE); + def(IINC , "iinc" , "bic" , 0, LOAD | STORE); + def(I2L , "i2l" , "b" , 1); + def(I2F , "i2f" , "b" , 0); + def(I2D , "i2d" , "b" , 1); + def(L2I , "l2i" , "b" , -1); + def(L2F , "l2f" , "b" , -1); + def(L2D , "l2d" , "b" , 0); + def(F2I , "f2i" , "b" , 0); + def(F2L , "f2l" , "b" , 1); + def(F2D , "f2d" , "b" , 1); + def(D2I , "d2i" , "b" , -1); + def(D2L , "d2l" , "b" , 0); + def(D2F , "d2f" , "b" , -1); + def(I2B , "i2b" , "b" , 0); + def(I2C , "i2c" , "b" , 0); + def(I2S , "i2s" , "b" , 0); + def(LCMP , "lcmp" , "b" , -3); + def(FCMPL , "fcmpl" , "b" , -1); + def(FCMPG , "fcmpg" , "b" , -1); + def(DCMPL , "dcmpl" , "b" , -3); + def(DCMPG , "dcmpg" , "b" , -3); + def(IFEQ , "ifeq" , "boo" , -1, FALL_THROUGH | BRANCH); + def(IFNE , "ifne" , "boo" , -1, FALL_THROUGH | BRANCH); + def(IFLT , "iflt" , "boo" , -1, FALL_THROUGH | BRANCH); + def(IFGE , "ifge" , "boo" , -1, FALL_THROUGH | BRANCH); + def(IFGT , "ifgt" , "boo" , -1, FALL_THROUGH | BRANCH); + def(IFLE , "ifle" , "boo" , -1, FALL_THROUGH | BRANCH); + def(IF_ICMPEQ , "if_icmpeq" , "boo" , -2, COMMUTATIVE | FALL_THROUGH | BRANCH); + def(IF_ICMPNE , "if_icmpne" , "boo" , -2, COMMUTATIVE | FALL_THROUGH | BRANCH); + def(IF_ICMPLT , "if_icmplt" , "boo" , -2, FALL_THROUGH | BRANCH); + def(IF_ICMPGE , "if_icmpge" , "boo" , -2, FALL_THROUGH | BRANCH); + def(IF_ICMPGT , "if_icmpgt" , "boo" , -2, FALL_THROUGH | BRANCH); + def(IF_ICMPLE , "if_icmple" , "boo" , -2, FALL_THROUGH | BRANCH); + def(IF_ACMPEQ , "if_acmpeq" , "boo" , -2, COMMUTATIVE | FALL_THROUGH | BRANCH); + def(IF_ACMPNE , "if_acmpne" , "boo" , -2, COMMUTATIVE | FALL_THROUGH | BRANCH); + def(GOTO , "goto" , "boo" , 0, STOP | BRANCH); + def(JSR , "jsr" , "boo" , 0, STOP | BRANCH); + def(RET , "ret" , "bi" , 0, STOP); + def(TABLESWITCH , "tableswitch" , "" , -1, STOP); + def(LOOKUPSWITCH , "lookupswitch" , "" , -1, STOP); + def(IRETURN , "ireturn" , "b" , -1, TRAP | STOP); + def(LRETURN , "lreturn" , "b" , -2, TRAP | STOP); + def(FRETURN , "freturn" , "b" , -1, TRAP | STOP); + def(DRETURN , "dreturn" , "b" , -2, TRAP | STOP); + def(ARETURN , "areturn" , "b" , -1, TRAP | STOP); + def(RETURN , "return" , "b" , 0, TRAP | STOP); + def(GETSTATIC , "getstatic" , "bjj" , 1, TRAP | FIELD_READ); + def(PUTSTATIC , "putstatic" , "bjj" , -1, TRAP | FIELD_WRITE); + def(GETFIELD , "getfield" , "bjj" , 0, TRAP | FIELD_READ); + def(PUTFIELD , "putfield" , "bjj" , -2, TRAP | FIELD_WRITE); + def(INVOKEVIRTUAL , "invokevirtual" , "bjj" , -1, TRAP | INVOKE); + def(INVOKESPECIAL , "invokespecial" , "bjj" , -1, TRAP | INVOKE); + def(INVOKESTATIC , "invokestatic" , "bjj" , 0, TRAP | INVOKE); + def(INVOKEINTERFACE , "invokeinterface" , "bjja_", -1, TRAP | INVOKE); + def(INVOKEDYNAMIC , "invokedynamic" , "bjjjj", 0, TRAP | INVOKE); + def(NEW , "new" , "bii" , 1, TRAP); + def(NEWARRAY , "newarray" , "bc" , 0, TRAP); + def(ANEWARRAY , "anewarray" , "bii" , 0, TRAP); + def(ARRAYLENGTH , "arraylength" , "b" , 0, TRAP); + def(ATHROW , "athrow" , "b" , -1, TRAP | STOP); + def(CHECKCAST , "checkcast" , "bii" , 0, TRAP); + def(INSTANCEOF , "instanceof" , "bii" , 0, TRAP); + def(MONITORENTER , "monitorenter" , "b" , -1, TRAP); + def(MONITOREXIT , "monitorexit" , "b" , -1, TRAP); + def(WIDE , "wide" , "" , 0); + def(MULTIANEWARRAY , "multianewarray" , "biic" , 1, TRAP); + def(IFNULL , "ifnull" , "boo" , -1, FALL_THROUGH | BRANCH); + def(IFNONNULL , "ifnonnull" , "boo" , -1, FALL_THROUGH | BRANCH); + def(GOTO_W , "goto_w" , "boooo", 0, STOP | BRANCH); + def(JSR_W , "jsr_w" , "boooo", 0, STOP | BRANCH); + def(BREAKPOINT , "breakpoint" , "b" , 0, TRAP); + } + // @formatter:on + // Checkstyle: resume + + /** + * Determines if an opcode is commutative. + * + * @param opcode the opcode to check + * @return {@code true} iff commutative + */ + public static boolean isCommutative(int opcode) { + return (flagsArray[opcode & 0xff] & COMMUTATIVE) != 0; + } + + /** + * Gets the length of an instruction denoted by a given opcode. + * + * @param opcode an instruction opcode + * @return the length of the instruction denoted by {@code opcode}. If {@code opcode} is an + * illegal instruction or denotes a variable length instruction (e.g. + * {@link #TABLESWITCH}), then 0 is returned. + */ + public static int lengthOf(int opcode) { + return lengthArray[opcode & 0xff]; + } + + /** + * Gets the effect on the depth of the expression stack of an instruction denoted by a given + * opcode. + * + * @param opcode an instruction opcode + * @return the change in the stack caused by the instruction denoted by {@code opcode}. If + * {@code opcode} is an illegal instruction then 0 is returned. Note that invoke + * instructions may pop more arguments so this value is a minimum stack effect. + */ + public static int stackEffectOf(int opcode) { + return stackEffectArray[opcode & 0xff]; + } + + /** + * Gets the lower-case mnemonic for a given opcode. + * + * @param opcode an opcode + * @return the mnemonic for {@code opcode} or {@code ""} if + * {@code opcode} is not a legal opcode + */ + public static String nameOf(int opcode) throws IllegalArgumentException { + String name = nameArray[opcode & 0xff]; + if (name == null) { + return ""; + } + return name; + } + + /** + * Allocation-free version of {@linkplain #nameOf(int)}. + * + * @param opcode an opcode. + * @return the mnemonic for {@code opcode} or {@code ""} if {@code opcode} is + * not a legal opcode. + */ + public static String baseNameOf(int opcode) { + String name = nameArray[opcode & 0xff]; + if (name == null) { + return ""; + } + return name; + } + + /** + * Gets the opcode corresponding to a given mnemonic. + * + * @param name an opcode mnemonic + * @return the opcode corresponding to {@code mnemonic} + * @throws IllegalArgumentException if {@code name} does not denote a valid opcode + */ + public static int valueOf(String name) { + for (int opcode = 0; opcode < nameArray.length; ++opcode) { + if (name.equalsIgnoreCase(nameArray[opcode])) { + return opcode; + } + } + throw new IllegalArgumentException("No opcode for " + name); + } + + /** + * Determines if a given opcode denotes an instruction that can cause an implicit exception. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} can cause an implicit exception, {@code false} + * otherwise + */ + public static boolean canTrap(int opcode) { + return (flagsArray[opcode & 0xff] & TRAP) != 0; + } + + /** + * Determines if a given opcode denotes an instruction that loads a local variable to the + * operand stack. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} loads a local variable to the operand stack, + * {@code false} otherwise + */ + public static boolean isLoad(int opcode) { + return (flagsArray[opcode & 0xff] & LOAD) != 0; + } + + /** + * Determines if a given opcode denotes an instruction that ends a basic block and does not let + * control flow fall through to its lexical successor. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} properly ends a basic block + */ + public static boolean isStop(int opcode) { + return (flagsArray[opcode & 0xff] & STOP) != 0; + } + + /** + * Determines if a given opcode denotes an instruction that stores a value to a local variable + * after popping it from the operand stack. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} stores a value to a local variable, {@code false} + * otherwise + */ + public static boolean isInvoke(int opcode) { + return (flagsArray[opcode & 0xff] & INVOKE) != 0; + } + + /** + * Determines if a given opcode denotes an instruction that stores a value to a local variable + * after popping it from the operand stack. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} stores a value to a local variable, {@code false} + * otherwise + */ + public static boolean isStore(int opcode) { + return (flagsArray[opcode & 0xff] & STORE) != 0; + } + + /** + * Determines if a given opcode is an instruction that delimits a basic block. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} delimits a basic block + */ + public static boolean isBlockEnd(int opcode) { + return (flagsArray[opcode & 0xff] & (STOP | FALL_THROUGH)) != 0; + } + + /** + * Determines if a given opcode is an instruction that has a 2 or 4 byte operand that is an + * offset to another instruction in the same method. This does not include the + * {@linkplain #TABLESWITCH switch} instructions. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} is a branch instruction with a single operand + */ + public static boolean isBranch(int opcode) { + return (flagsArray[opcode & 0xff] & BRANCH) != 0; + } + + /** + * Determines if a given opcode denotes a conditional branch. + * + * @param opcode + * @return {@code true} iff {@code opcode} is a conditional branch + */ + public static boolean isConditionalBranch(int opcode) { + return (flagsArray[opcode & 0xff] & FALL_THROUGH) != 0; + } + + /** + * Gets the arithmetic operator name for a given opcode. If {@code opcode} does not denote an + * arithmetic instruction, then the {@linkplain #nameOf(int) name} of the opcode is returned + * instead. + * + * @param op an opcode + * @return the arithmetic operator name + */ + public static String operator(int op) { + // Checkstyle: stop + switch (op) { + // arithmetic ops + case IADD: // fall through + case LADD: // fall through + case FADD: // fall through + case DADD: + return "+"; + case ISUB: // fall through + case LSUB: // fall through + case FSUB: // fall through + case DSUB: + return "-"; + case IMUL: // fall through + case LMUL: // fall through + case FMUL: // fall through + case DMUL: + return "*"; + case IDIV: // fall through + case LDIV: // fall through + case FDIV: // fall through + case DDIV: + return "/"; + case IREM: // fall through + case LREM: // fall through + case FREM: // fall through + case DREM: + return "%"; + // shift ops + case ISHL: // fall through + case LSHL: + return "<<"; + case ISHR: // fall through + case LSHR: + return ">>"; + case IUSHR: // fall through + case LUSHR: + return ">>>"; + // logic ops + case IAND: // fall through + case LAND: + return "&"; + case IOR: // fall through + case LOR: + return "|"; + case IXOR: // fall through + case LXOR: + return "^"; + } + // Checkstyle: resume + return nameOf(op); + } + + /** + * Defines a bytecode by entering it into the arrays that record its name, length and flags. + * + * @param name instruction name (should be lower case) + * @param format encodes the length of the instruction + */ + private static void def(int opcode, String name, String format, int stackEffect) { + def(opcode, name, format, stackEffect, 0); + } + + /** + * Defines a bytecode by entering it into the arrays that record its name, length and flags. + * + * @param name instruction name (lower case) + * @param format encodes the length of the instruction + * @param flags the set of {@link Flags} associated with the instruction + */ + private static void def(int opcode, String name, String format, int stackEffect, int flags) { + assert nameArray[opcode] == null : "opcode " + opcode + " is already bound to name " + nameArray[opcode]; + nameArray[opcode] = name; + int instructionLength = format.length(); + lengthArray[opcode] = instructionLength; + stackEffectArray[opcode] = stackEffect; + Bytecodes.flagsArray[opcode] = flags; + + assert !isConditionalBranch(opcode) || isBranch(opcode) : "a conditional branch must also be a branch"; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytes.java 2016-12-07 13:47:40.886673056 -0800 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2009, 2011, 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 collection of utility methods for dealing with bytes, particularly in byte arrays. + */ +public class Bytes { + + /** + * Gets a signed 1-byte value. + * + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @return the signed 1-byte value at index {@code bci} in array {@code data} + */ + public static int beS1(byte[] data, int bci) { + return data[bci]; + } + + /** + * Gets a signed 2-byte big-endian value. + * + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @return the signed 2-byte, big-endian, value at index {@code bci} in array {@code data} + */ + public static int beS2(byte[] data, int bci) { + return (data[bci] << 8) | (data[bci + 1] & 0xff); + } + + /** + * Gets an unsigned 1-byte value. + * + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @return the unsigned 1-byte value at index {@code bci} in array {@code data} + */ + public static int beU1(byte[] data, int bci) { + return data[bci] & 0xff; + } + + /** + * Gets an unsigned 2-byte big-endian value. + * + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @return the unsigned 2-byte, big-endian, value at index {@code bci} in array {@code data} + */ + public static int beU2(byte[] data, int bci) { + return ((data[bci] & 0xff) << 8) | (data[bci + 1] & 0xff); + } + + /** + * Gets a signed 4-byte big-endian value. + * + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @return the signed 4-byte, big-endian, value at index {@code bci} in array {@code data} + */ + public static int beS4(byte[] data, int bci) { + return (data[bci] << 24) | ((data[bci + 1] & 0xff) << 16) | ((data[bci + 2] & 0xff) << 8) | (data[bci + 3] & 0xff); + } + + /** + * Gets either a signed 2-byte or a signed 4-byte big-endian value. + * + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @param fourByte if true, this method will return a 4-byte value + * @return the signed 2 or 4-byte, big-endian, value at index {@code bci} in array {@code data} + */ + public static int beSVar(byte[] data, int bci, boolean fourByte) { + if (fourByte) { + return beS4(data, bci); + } else { + return beS2(data, bci); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecode.java 2016-12-07 13:47:41.149684612 -0800 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016, 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; + +/** + * Direct access to the bytecode of a {@link ResolvedJavaMethod} that will reflect any + * instrumentation and rewriting performed on the {@link ResolvedJavaMethod}. + */ +public class ResolvedJavaMethodBytecode implements Bytecode { + + private final ResolvedJavaMethod method; + + public ResolvedJavaMethodBytecode(ResolvedJavaMethod method) { + this.method = method; + } + + @Override + public ResolvedJavaMethod getMethod() { + return method; + } + + @Override + public byte[] getCode() { + return method.getCode(); + } + + @Override + public int getCodeSize() { + return method.getCodeSize(); + } + + @Override + public int getMaxStackSize() { + return method.getMaxStackSize(); + } + + @Override + public int getMaxLocals() { + return method.getMaxLocals(); + } + + @Override + public ConstantPool getConstantPool() { + return method.getConstantPool(); + } + + @Override + public LineNumberTable getLineNumberTable() { + return method.getLineNumberTable(); + } + + @Override + public LocalVariableTable getLocalVariableTable() { + return method.getLocalVariableTable(); + } + + @Override + public ExceptionHandler[] getExceptionHandlers() { + return method.getExceptionHandlers(); + } + + @Override + public StackTraceElement asStackTraceElement(int bci) { + return method.asStackTraceElement(bci); + } + + @Override + public ProfilingInfo getProfilingInfo() { + return method.getProfilingInfo(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + method.format("<%h.%n(%p)>"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecodeProvider.java 2016-12-07 13:47:41.414696257 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, 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.ResolvedJavaMethod; + +/** + * {@link BytecodeProvider} that returns {@link ResolvedJavaMethodBytecode} objects. + */ +public class ResolvedJavaMethodBytecodeProvider implements BytecodeProvider { + + @Override + public Bytecode getBytecode(ResolvedJavaMethod method) { + return new ResolvedJavaMethodBytecode(method); + } + + @Override + public boolean supportsInvokedynamic() { + return true; + } + + @Override + public boolean shouldRecordMethodDependencies() { + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java 2016-12-07 13:47:41.678707857 -0800 @@ -0,0 +1,716 @@ +/* + * Copyright (c) 2009, 2016, 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.code; + +import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableList; +import static jdk.vm.ci.meta.MetaUtil.identityHashCodeString; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import org.graalvm.compiler.graph.NodeSourcePosition; + +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.code.site.ConstantReference; +import jdk.vm.ci.code.site.DataPatch; +import jdk.vm.ci.code.site.DataSectionReference; +import jdk.vm.ci.code.site.ExceptionHandler; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.code.site.InfopointReason; +import jdk.vm.ci.code.site.Mark; +import jdk.vm.ci.code.site.Reference; +import jdk.vm.ci.code.site.Site; +import jdk.vm.ci.meta.Assumptions.Assumption; +import jdk.vm.ci.meta.InvokeTarget; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Represents the output from compiling a method, including the compiled machine code, associated + * data and references, relocation information, deoptimization information, etc. + */ +public class CompilationResult { + + /** + * Provides extra information about instructions or data at specific positions in + * {@link CompilationResult#getTargetCode()}. This is optional information that can be used to + * enhance a disassembly of the code. + */ + public abstract static class CodeAnnotation { + + public final int position; + + public CodeAnnotation(int position) { + this.position = position; + } + + @Override + public final int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public abstract boolean equals(Object obj); + } + + /** + * A string comment about one or more instructions at a specific position in the code. + */ + public static final class CodeComment extends CodeAnnotation { + + public final String value; + + public CodeComment(int position, String comment) { + super(position); + this.value = comment; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof CodeComment) { + CodeComment that = (CodeComment) obj; + if (this.position == that.position && this.value.equals(that.value)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "@" + position + ": " + value; + } + } + + /** + * Describes a table of signed offsets embedded in the code. The offsets are relative to the + * starting address of the table. This type of table maybe generated when translating a + * multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch} + * JVM instruction). + * + * The table is indexed by the contiguous range of integers from {@link #low} to {@link #high} + * inclusive. + */ + public static final class JumpTable extends CodeAnnotation { + + /** + * The low value in the key range (inclusive). + */ + public final int low; + + /** + * The high value in the key range (inclusive). + */ + public final int high; + + /** + * The size (in bytes) of each table entry. + */ + public final int entrySize; + + public JumpTable(int position, int low, int high, int entrySize) { + super(position); + this.low = low; + this.high = high; + this.entrySize = entrySize; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof JumpTable) { + JumpTable that = (JumpTable) obj; + if (this.position == that.position && this.entrySize == that.entrySize && this.low == that.low && this.high == that.high) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "@" + position + ": [" + low + " .. " + high + "]"; + } + } + + private boolean closed; + + private int entryBCI = -1; + + private final DataSection dataSection = new DataSection(); + + private final List infopoints = new ArrayList<>(); + private final List sourceMapping = new ArrayList<>(); + private final List dataPatches = new ArrayList<>(); + private final List exceptionHandlers = new ArrayList<>(); + private final List marks = new ArrayList<>(); + + private int totalFrameSize = -1; + private int maxInterpreterFrameSize = -1; + + private StackSlot customStackArea = null; + + private final String name; + + /** + * The buffer containing the emitted machine code. + */ + private byte[] targetCode; + + /** + * The leading number of bytes in {@link #targetCode} containing the emitted machine code. + */ + private int targetCodeSize; + + private ArrayList annotations; + + private Assumption[] assumptions; + + /** + * The list of the methods whose bytecodes were used as input to the compilation. If + * {@code null}, then the compilation did not record method dependencies. Otherwise, the first + * element of this array is the root method of the compilation. + */ + private ResolvedJavaMethod[] methods; + + /** + * The list of fields that were accessed from the bytecodes. + */ + private ResolvedJavaField[] fields; + + private int bytecodeSize; + + private boolean hasUnsafeAccess; + + private boolean isImmutablePIC; + + public CompilationResult() { + this(null, false); + } + + public CompilationResult(String name) { + this(name, false); + } + + public CompilationResult(boolean isImmutablePIC) { + this(null, isImmutablePIC); + } + + public CompilationResult(String name, boolean isImmutablePIC) { + this.name = name; + this.isImmutablePIC = isImmutablePIC; + } + + @Override + public int hashCode() { + // CompilationResult instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + if (methods != null) { + return getClass().getName() + "[" + methods[0].format("%H.%n(%p)%r") + "]"; + } + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj != null && obj.getClass() == getClass()) { + CompilationResult that = (CompilationResult) obj; + // @formatter:off + if (this.entryBCI == that.entryBCI && + Objects.equals(this.customStackArea, that.customStackArea) && + this.totalFrameSize == that.totalFrameSize && + this.targetCodeSize == that.targetCodeSize && + Objects.equals(this.name, that.name) && + Objects.equals(this.annotations, that.annotations) && + Objects.equals(this.dataSection, that.dataSection) && + Objects.equals(this.exceptionHandlers, that.exceptionHandlers) && + Objects.equals(this.dataPatches, that.dataPatches) && + Objects.equals(this.infopoints, that.infopoints) && + Objects.equals(this.marks, that.marks) && + Arrays.equals(this.assumptions, that.assumptions) && + Arrays.equals(targetCode, that.targetCode)) { + return true; + } + // @formatter:on + } + return false; + } + + /** + * @return the entryBCI + */ + public int getEntryBCI() { + return entryBCI; + } + + /** + * @param entryBCI the entryBCI to set + */ + public void setEntryBCI(int entryBCI) { + checkOpen(); + this.entryBCI = entryBCI; + } + + /** + * Sets the assumptions made during compilation. + */ + public void setAssumptions(Assumption[] assumptions) { + checkOpen(); + this.assumptions = assumptions; + } + + /** + * Gets the assumptions made during compilation. + * + * The caller must not modify the contents of the returned array. + */ + public Assumption[] getAssumptions() { + return assumptions; + } + + /** + * Sets the methods whose bytecodes were used as input to the compilation. + * + * @param rootMethod the root method of the compilation + * @param inlinedMethods the methods inlined during compilation + */ + public void setMethods(ResolvedJavaMethod rootMethod, Collection inlinedMethods) { + checkOpen(); + assert rootMethod != null; + assert inlinedMethods != null; + if (inlinedMethods.contains(rootMethod)) { + methods = inlinedMethods.toArray(new ResolvedJavaMethod[inlinedMethods.size()]); + for (int i = 0; i < methods.length; i++) { + if (methods[i].equals(rootMethod)) { + if (i != 0) { + ResolvedJavaMethod tmp = methods[0]; + methods[0] = methods[i]; + methods[i] = tmp; + } + break; + } + } + } else { + methods = new ResolvedJavaMethod[1 + inlinedMethods.size()]; + methods[0] = rootMethod; + int i = 1; + for (ResolvedJavaMethod m : inlinedMethods) { + methods[i++] = m; + } + } + } + + /** + * Gets the methods whose bytecodes were used as input to the compilation. + * + * The caller must not modify the contents of the returned array. + * + * @return {@code null} if the compilation did not record method dependencies otherwise the + * methods whose bytecodes were used as input to the compilation with the first element + * being the root method of the compilation + */ + public ResolvedJavaMethod[] getMethods() { + return methods; + } + + /** + * Sets the fields that were referenced from the bytecodes that were used as input to the + * compilation. + * + * @param accessedFields the collected set of fields accessed during compilation + */ + public void setFields(Collection accessedFields) { + assert accessedFields != null; + fields = accessedFields.toArray(new ResolvedJavaField[accessedFields.size()]); + } + + /** + * Gets the fields that were referenced from bytecodes that were used as input to the + * compilation. + * + * The caller must not modify the contents of the returned array. + * + * @return {@code null} if the compilation did not record fields dependencies otherwise the + * fields that were accessed from bytecodes were used as input to the compilation. + */ + public ResolvedJavaField[] getFields() { + return fields; + } + + public void setBytecodeSize(int bytecodeSize) { + checkOpen(); + this.bytecodeSize = bytecodeSize; + } + + public int getBytecodeSize() { + return bytecodeSize; + } + + public DataSection getDataSection() { + return dataSection; + } + + /** + * The total frame size of the method in bytes. This includes the return address pushed onto the + * stack, if any. + * + * @return the frame size + */ + public int getTotalFrameSize() { + assert totalFrameSize != -1 : "frame size not yet initialized!"; + return totalFrameSize; + } + + /** + * Sets the total frame size in bytes. This includes the return address pushed onto the stack, + * if any. + * + * @param size the size of the frame in bytes + */ + public void setTotalFrameSize(int size) { + checkOpen(); + totalFrameSize = size; + } + + public int getMaxInterpreterFrameSize() { + return maxInterpreterFrameSize; + } + + public void setMaxInterpreterFrameSize(int maxInterpreterFrameSize) { + checkOpen(); + this.maxInterpreterFrameSize = maxInterpreterFrameSize; + } + + public boolean isImmutablePIC() { + return this.isImmutablePIC; + } + + /** + * Sets the machine that has been generated by the compiler. + * + * @param code the machine code generated + * @param size the size of the machine code + */ + public void setTargetCode(byte[] code, int size) { + checkOpen(); + targetCode = code; + targetCodeSize = size; + } + + /** + * Records a data patch in the code section. The data patch can refer to something in the + * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined + * constant}. + * + * @param codePos the position in the code that needs to be patched + * @param ref the reference that should be inserted in the code + */ + public void recordDataPatch(int codePos, Reference ref) { + checkOpen(); + assert codePos >= 0 && ref != null; + dataPatches.add(new DataPatch(codePos, ref)); + } + + /** + * Records a data patch in the code section. The data patch can refer to something in the + * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined + * constant}. + * + * @param codePos the position in the code that needs to be patched + * @param ref the reference that should be inserted in the code + * @param note a note attached to data patch for use by post-processing tools + */ + public void recordDataPatchWithNote(int codePos, Reference ref, Object note) { + assert codePos >= 0 && ref != null; + dataPatches.add(new DataPatch(codePos, ref, note)); + } + + /** + * Records a call in the code array. + * + * @param codePos the position of the call in the code array + * @param size the size of the call instruction + * @param target the being called + * @param debugInfo the debug info for the call + * @param direct specifies if this is a {@linkplain Call#direct direct} call + */ + public void recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) { + checkOpen(); + final Call call = new Call(target, codePos, size, direct, debugInfo); + addInfopoint(call); + } + + /** + * Records an exception handler for this method. + * + * @param codePos the position in the code that is covered by the handler + * @param handlerPos the position of the handler + */ + public void recordExceptionHandler(int codePos, int handlerPos) { + checkOpen(); + assert validateExceptionHandlerAdd(codePos, handlerPos) : String.format("Duplicate exception handler for pc 0x%x handlerPos 0x%x", codePos, handlerPos); + exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos)); + } + + /** + * Validate if the exception handler for codePos already exists and handlerPos is different. + * + * @param codePos + * @param handlerPos + * @return true if the validation is successful + */ + private boolean validateExceptionHandlerAdd(int codePos, int handlerPos) { + ExceptionHandler exHandler = getExceptionHandlerForCodePos(codePos); + return exHandler == null || exHandler.handlerPos == handlerPos; + } + + /** + * Returns the first ExceptionHandler which matches codePos. + * + * @param codePos position to search for + * @return first matching ExceptionHandler + */ + private ExceptionHandler getExceptionHandlerForCodePos(int codePos) { + for (ExceptionHandler h : exceptionHandlers) { + if (h.pcOffset == codePos) { + return h; + } + } + return null; + } + + /** + * Records an infopoint in the code array. + * + * @param codePos the position of the infopoint in the code array + * @param debugInfo the debug info for the infopoint + */ + public void recordInfopoint(int codePos, DebugInfo debugInfo, InfopointReason reason) { + addInfopoint(new Infopoint(codePos, debugInfo, reason)); + } + + /** + * Records a custom infopoint in the code section. + * + * Compiler implementations can use this method to record non-standard infopoints, which are not + * handled by dedicated methods like {@link #recordCall}. + * + * @param infopoint the infopoint to record, usually a derived class from {@link Infopoint} + */ + public void addInfopoint(Infopoint infopoint) { + checkOpen(); + infopoints.add(infopoint); + } + + public void recordSourceMapping(int startOffset, int endOffset, NodeSourcePosition sourcePosition) { + checkOpen(); + sourceMapping.add(new SourceMapping(startOffset, endOffset, sourcePosition)); + } + + /** + * Records an instruction mark within this method. + * + * @param codePos the position in the code that is covered by the handler + * @param markId the identifier for this mark + */ + public Mark recordMark(int codePos, Object markId) { + checkOpen(); + Mark mark = new Mark(codePos, markId); + marks.add(mark); + return mark; + } + + /** + * Start of the custom stack area. + * + * @return the first stack slot of the custom stack area + */ + public StackSlot getCustomStackArea() { + return customStackArea; + } + + /** + * @see #getCustomStackArea() + * @param slot + */ + public void setCustomStackAreaOffset(StackSlot slot) { + checkOpen(); + customStackArea = slot; + } + + /** + * @return the machine code generated for this method + */ + public byte[] getTargetCode() { + return targetCode; + } + + /** + * @return the size of the machine code generated for this method + */ + public int getTargetCodeSize() { + return targetCodeSize; + } + + /** + * @return the code annotations or {@code null} if there are none + */ + public List getAnnotations() { + if (annotations == null) { + return Collections.emptyList(); + } + return annotations; + } + + public void addAnnotation(CodeAnnotation annotation) { + checkOpen(); + assert annotation != null; + if (annotations == null) { + annotations = new ArrayList<>(); + } + annotations.add(annotation); + } + + /** + * @return the list of infopoints, sorted by {@link Site#pcOffset} + */ + public List getInfopoints() { + if (infopoints.isEmpty()) { + return emptyList(); + } + return unmodifiableList(infopoints); + } + + /** + * @return the list of data references + */ + public List getDataPatches() { + if (dataPatches.isEmpty()) { + return emptyList(); + } + return unmodifiableList(dataPatches); + } + + /** + * @return the list of exception handlers + */ + public List getExceptionHandlers() { + if (exceptionHandlers.isEmpty()) { + return emptyList(); + } + return unmodifiableList(exceptionHandlers); + } + + /** + * @return the list of marks + */ + public List getMarks() { + if (marks.isEmpty()) { + return emptyList(); + } + return unmodifiableList(marks); + } + + /** + * @return the list of {@link SourceMapping}s + */ + public List getSourceMappings() { + if (sourceMapping.isEmpty()) { + return emptyList(); + } + return unmodifiableList(sourceMapping); + } + + public String getName() { + return name; + } + + public void setHasUnsafeAccess(boolean hasUnsafeAccess) { + checkOpen(); + this.hasUnsafeAccess = hasUnsafeAccess; + } + + public boolean hasUnsafeAccess() { + return hasUnsafeAccess; + } + + /** + * Clears the information in this object pertaining to generating code. That is, the + * {@linkplain #getMarks() marks}, {@linkplain #getInfopoints() infopoints}, + * {@linkplain #getExceptionHandlers() exception handlers}, {@linkplain #getDataPatches() data + * patches} and {@linkplain #getAnnotations() annotations} recorded in this object are cleared. + */ + public void resetForEmittingCode() { + checkOpen(); + infopoints.clear(); + sourceMapping.clear(); + dataPatches.clear(); + exceptionHandlers.clear(); + marks.clear(); + dataSection.clear(); + if (annotations != null) { + annotations.clear(); + } + } + + private void checkOpen() { + if (closed) { + throw new IllegalStateException(); + } + } + + /** + * Closes this compilation result to future updates. + */ + public void close() { + if (closed) { + throw new IllegalStateException("Cannot re-close compilation result " + this); + } + dataSection.close(); + closed = true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DataSection.java 2016-12-07 13:47:41.944719545 -0800 @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2014, 2016, 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.code; + +import static jdk.vm.ci.meta.MetaUtil.identityHashCodeString; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Objects; +import java.util.function.BiConsumer; + +import org.graalvm.compiler.code.DataSection.Data; + +import jdk.vm.ci.code.site.DataSectionReference; +import jdk.vm.ci.meta.SerializableConstant; +import jdk.vm.ci.meta.VMConstant; + +public final class DataSection implements Iterable { + + public interface Patches { + + void registerPatch(VMConstant c); + } + + public abstract static class Data { + + private int alignment; + private final int size; + + private DataSectionReference ref; + + protected Data(int alignment, int size) { + this.alignment = alignment; + this.size = size; + + // initialized in DataSection.insertData(Data) + ref = null; + } + + protected abstract void emit(ByteBuffer buffer, Patches patches); + + public void updateAlignment(int newAlignment) { + if (newAlignment == alignment) { + return; + } + alignment = lcm(alignment, newAlignment); + } + + public int getAlignment() { + return alignment; + } + + public int getSize() { + return size; + } + + @Override + public int hashCode() { + // Data instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + assert ref != null; + if (obj == this) { + return true; + } + if (obj instanceof Data) { + Data that = (Data) obj; + if (this.alignment == that.alignment && this.size == that.size && this.ref.equals(that.ref)) { + return true; + } + } + return false; + } + } + + public static final class RawData extends Data { + + private final byte[] data; + + public RawData(byte[] data, int alignment) { + super(alignment, data.length); + this.data = data; + } + + @Override + protected void emit(ByteBuffer buffer, Patches patches) { + buffer.put(data); + } + } + + public static final class SerializableData extends Data { + + private final SerializableConstant constant; + + public SerializableData(SerializableConstant constant) { + this(constant, 1); + } + + public SerializableData(SerializableConstant constant, int alignment) { + super(alignment, constant.getSerializedSize()); + this.constant = constant; + } + + @Override + protected void emit(ByteBuffer buffer, Patches patches) { + int position = buffer.position(); + constant.serialize(buffer); + assert buffer.position() - position == constant.getSerializedSize() : "wrong number of bytes written"; + } + } + + public static class ZeroData extends Data { + + protected ZeroData(int alignment, int size) { + super(alignment, size); + } + + public static ZeroData create(int alignment, int size) { + switch (size) { + case 1: + return new ZeroData(alignment, size) { + @Override + protected void emit(ByteBuffer buffer, Patches patches) { + buffer.put((byte) 0); + } + }; + + case 2: + return new ZeroData(alignment, size) { + @Override + protected void emit(ByteBuffer buffer, Patches patches) { + buffer.putShort((short) 0); + } + }; + + case 4: + return new ZeroData(alignment, size) { + @Override + protected void emit(ByteBuffer buffer, Patches patches) { + buffer.putInt(0); + } + }; + + case 8: + return new ZeroData(alignment, size) { + @Override + protected void emit(ByteBuffer buffer, Patches patches) { + buffer.putLong(0); + } + }; + + default: + return new ZeroData(alignment, size); + } + } + + @Override + protected void emit(ByteBuffer buffer, Patches patches) { + int rest = getSize(); + while (rest > 8) { + buffer.putLong(0L); + rest -= 8; + } + while (rest > 0) { + buffer.put((byte) 0); + rest--; + } + } + } + + public static final class PackedData extends Data { + + private final Data[] nested; + + private PackedData(int alignment, int size, Data[] nested) { + super(alignment, size); + this.nested = nested; + } + + public static PackedData create(Data[] nested) { + int size = 0; + int alignment = 1; + for (int i = 0; i < nested.length; i++) { + assert size % nested[i].getAlignment() == 0 : "invalid alignment in packed constants"; + alignment = DataSection.lcm(alignment, nested[i].getAlignment()); + size += nested[i].getSize(); + } + return new PackedData(alignment, size, nested); + } + + @Override + protected void emit(ByteBuffer buffer, Patches patches) { + for (Data data : nested) { + data.emit(buffer, patches); + } + } + } + + private final ArrayList dataItems = new ArrayList<>(); + + private boolean closed; + private int sectionAlignment; + private int sectionSize; + + @Override + public int hashCode() { + // DataSection instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DataSection) { + DataSection that = (DataSection) obj; + if (this.closed == that.closed && this.sectionAlignment == that.sectionAlignment && this.sectionSize == that.sectionSize && Objects.equals(this.dataItems, that.dataItems)) { + return true; + } + } + return false; + } + + /** + * Inserts a {@link Data} item into the data section. If the item is already in the data + * section, the same {@link DataSectionReference} is returned. + * + * @param data the {@link Data} item to be inserted + * @return a unique {@link DataSectionReference} identifying the {@link Data} item + */ + public DataSectionReference insertData(Data data) { + checkOpen(); + synchronized (data) { + if (data.ref == null) { + data.ref = new DataSectionReference(); + dataItems.add(data); + } + return data.ref; + } + } + + /** + * Transfers all {@link Data} from the provided other {@link DataSection} to this + * {@link DataSection}, and empties the other section. + */ + public void addAll(DataSection other) { + checkOpen(); + other.checkOpen(); + + for (Data data : other.dataItems) { + assert data.ref != null; + dataItems.add(data); + } + other.dataItems.clear(); + } + + /** + * Determines if this object has been {@link #close() closed}. + */ + public boolean closed() { + return closed; + } + + /** + * Computes the layout of the data section and closes this object to further updates. + * + * This must be called exactly once. + */ + public void close() { + checkOpen(); + closed = true; + + // simple heuristic: put items with larger alignment requirement first + dataItems.sort((a, b) -> a.alignment - b.alignment); + + int position = 0; + int alignment = 1; + for (Data d : dataItems) { + alignment = lcm(alignment, d.alignment); + position = align(position, d.alignment); + + d.ref.setOffset(position); + position += d.size; + } + + sectionAlignment = alignment; + sectionSize = position; + } + + /** + * Gets the size of the data section. + * + * This must only be called once this object has been {@linkplain #closed() closed}. + */ + public int getSectionSize() { + checkClosed(); + return sectionSize; + } + + /** + * Gets the minimum alignment requirement of the data section. + * + * This must only be called once this object has been {@linkplain #closed() closed}. + */ + public int getSectionAlignment() { + checkClosed(); + return sectionAlignment; + } + + /** + * Builds the data section into a given buffer. + * + * This must only be called once this object has been {@linkplain #closed() closed}. + * + * @param buffer the {@link ByteBuffer} where the data section should be built. The buffer must + * hold at least {@link #getSectionSize()} bytes. + * @param patch a {@link Patches} instance to receive {@link VMConstant constants} for + * relocations in the data section + */ + public void buildDataSection(ByteBuffer buffer, Patches patch) { + buildDataSection(buffer, patch, (r, s) -> { + }); + } + + /** + * Builds the data section into a given buffer. + * + * This must only be called once this object has been {@linkplain #closed() closed}. When this + * method returns, the buffers' position is just after the last data item. + * + * @param buffer the {@link ByteBuffer} where the data section should be built. The buffer must + * hold at least {@link #getSectionSize()} bytes. + * @param patch a {@link Patches} instance to receive {@link VMConstant constants} for + * @param onEmit a function that is called before emitting each data item with the + * {@link DataSectionReference} and the size of the data. + */ + public void buildDataSection(ByteBuffer buffer, Patches patch, BiConsumer onEmit) { + checkClosed(); + assert buffer.remaining() >= sectionSize; + int start = buffer.position(); + for (Data d : dataItems) { + buffer.position(start + d.ref.getOffset()); + onEmit.accept(d.ref, d.getSize()); + d.emit(buffer, patch); + } + buffer.position(start + sectionSize); + } + + public Data findData(DataSectionReference ref) { + for (Data d : dataItems) { + if (d.ref == ref) { + return d; + } + } + return null; + } + + public static void emit(ByteBuffer buffer, Data data, Patches patch) { + data.emit(buffer, patch); + } + + @Override + public Iterator iterator() { + return dataItems.iterator(); + } + + private static int lcm(int x, int y) { + if (x == 0) { + return y; + } else if (y == 0) { + return x; + } + + int a = Math.max(x, y); + int b = Math.min(x, y); + while (b > 0) { + int tmp = a % b; + a = b; + b = tmp; + } + + int gcd = a; + return x * y / gcd; + } + + private static int align(int position, int alignment) { + return ((position + alignment - 1) / alignment) * alignment; + } + + private void checkClosed() { + if (!closed) { + throw new IllegalStateException(); + } + } + + private void checkOpen() { + if (closed) { + throw new IllegalStateException(); + } + } + + public void clear() { + checkOpen(); + this.dataItems.clear(); + this.sectionAlignment = 0; + this.sectionSize = 0; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DisassemblerProvider.java 2016-12-07 13:47:42.210731234 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2013, 2016, 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.code; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.InstalledCode; + +/** + * Interface providing capability for disassembling machine code. + */ +public interface DisassemblerProvider { + + /** + * Gets a textual disassembly of a given compilation result. + * + * @param codeCache the object used for code {@link CodeCacheProvider#addCode code installation} + * @param compResult a compilation result + * @return a non-zero length string containing a disassembly of {@code compResult} or null it + * could not be disassembled + */ + default String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) { + return null; + } + + /** + * Gets a textual disassembly of a given installed code. + * + * @param codeCache the object used for code {@link CodeCacheProvider#addCode code installation} + * @param compResult a compiled code that was installed to produce {@code installedCode}. This + * will be null if not available. + * @param installedCode + * @return a non-zero length string containing a disassembly of {@code installedCode} or null if + * {@code installedCode} is {@link InstalledCode#isValid() invalid} or it could not be + * disassembled for some other reason + */ + default String disassembleInstalledCode(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) { + return null; + } + + /** + * Gets the name denoting the format of the disassmembly return by this object. + */ + String getName(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFile.java 2016-12-07 13:47:42.475742878 -0800 @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2009, 2016, 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.code; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.graalvm.compiler.code.CompilationResult.CodeAnnotation; +import org.graalvm.compiler.code.CompilationResult.CodeComment; +import org.graalvm.compiler.code.CompilationResult.JumpTable; + +import jdk.vm.ci.code.CodeUtil; + +/** + * A HexCodeFile is a textual format for representing a chunk of machine code along with extra + * information that can be used to enhance a disassembly of the code. + * + * A pseudo grammar for a HexCodeFile is given below. + * + *
+ *     HexCodeFile ::= Platform Delim HexCode Delim (OptionalSection Delim)*
+ *
+ *     OptionalSection ::= Comment | OperandComment | JumpTable | LookupTable
+ *
+ *     Platform ::= "Platform" ISA WordWidth
+ *
+ *     HexCode ::= "HexCode" StartAddress HexDigits
+ *
+ *     Comment ::= "Comment" Position String
+ *
+ *     OperandComment ::= "OperandComment" Position String
+ *
+ *     JumpTable ::= "JumpTable" Position EntrySize Low High
+ *
+ *     LookupTable ::= "LookupTable" Position NPairs KeySize OffsetSize
+ *
+ *     Position, EntrySize, Low, High, NPairs KeySize OffsetSize ::= int
+ *
+ *     Delim := "<||@"
+ * 
+ * + * There must be exactly one HexCode and Platform part in a HexCodeFile. The length of HexDigits + * must be even as each pair of digits represents a single byte. + *

+ * Below is an example of a valid Code input: + * + *

+ *
+ *  Platform AMD64 64  <||@
+ *  HexCode 0 e8000000009090904883ec084889842410d0ffff48893c24e800000000488b3c24488bf0e8000000004883c408c3  <||@
+ *  Comment 24 frame-ref-map: +0 {0}
+ *  at java.lang.String.toLowerCase(String.java:2496) [bci: 1]
+ *              |0
+ *     locals:  |stack:0:a
+ *     stack:   |stack:0:a
+ *    <||@
+ *  OperandComment 24 {java.util.Locale.getDefault()}  <||@
+ *  Comment 36 frame-ref-map: +0 {0}
+ *  at java.lang.String.toLowerCase(String.java:2496) [bci: 4]
+ *              |0
+ *     locals:  |stack:0:a
+ *    <||@
+ *  OperandComment 36 {java.lang.String.toLowerCase(Locale)}  lt;||@
+ *
+ * 
+ */ +public class HexCodeFile { + + public static final String NEW_LINE = CodeUtil.NEW_LINE; + public static final String SECTION_DELIM = " <||@"; + public static final String COLUMN_END = " <|@"; + public static final Pattern SECTION = Pattern.compile("(\\S+)\\s+(.*)", Pattern.DOTALL); + public static final Pattern COMMENT = Pattern.compile("(\\d+)\\s+(.*)", Pattern.DOTALL); + public static final Pattern OPERAND_COMMENT = COMMENT; + public static final Pattern JUMP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(-{0,1}\\d+)\\s+(-{0,1}\\d+)\\s*"); + public static final Pattern LOOKUP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s*"); + public static final Pattern HEX_CODE = Pattern.compile("(\\p{XDigit}+)(?:\\s+(\\p{XDigit}*))?"); + public static final Pattern PLATFORM = Pattern.compile("(\\S+)\\s+(\\S+)", Pattern.DOTALL); + + /** + * Delimiter placed before a HexCodeFile when embedded in a string/stream. + */ + public static final String EMBEDDED_HCF_OPEN = "<<> comments = new TreeMap<>(); + + /** + * Map from a machine code position to a comment for the operands of the instruction at the + * position. + */ + public final Map> operandComments = new TreeMap<>(); + + public final byte[] code; + + public final ArrayList jumpTables = new ArrayList<>(); + + public final String isa; + + public final int wordWidth; + + public final long startAddress; + + public HexCodeFile(byte[] code, long startAddress, String isa, int wordWidth) { + this.code = code; + this.startAddress = startAddress; + this.isa = isa; + this.wordWidth = wordWidth; + } + + /** + * Parses a string in the format produced by {@link #toString()} to produce a + * {@link HexCodeFile} object. + */ + public static HexCodeFile parse(String input, int sourceOffset, String source, String sourceName) { + return new Parser(input, sourceOffset, source, sourceName).hcf; + } + + /** + * Formats this HexCodeFile as a string that can be parsed with + * {@link #parse(String, int, String, String)}. + */ + @Override + public String toString() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + writeTo(baos); + return baos.toString(); + } + + public String toEmbeddedString() { + return EMBEDDED_HCF_OPEN + NEW_LINE + toString() + EMBEDDED_HCF_CLOSE; + } + + public void writeTo(OutputStream out) { + PrintStream ps = out instanceof PrintStream ? (PrintStream) out : new PrintStream(out); + ps.printf("Platform %s %d %s%n", isa, wordWidth, SECTION_DELIM); + ps.printf("HexCode %x %s %s%n", startAddress, HexCodeFile.hexCodeString(code), SECTION_DELIM); + + for (JumpTable table : jumpTables) { + ps.printf("JumpTable %d %d %d %d %s%n", table.position, table.entrySize, table.low, table.high, SECTION_DELIM); + } + + for (Map.Entry> e : comments.entrySet()) { + int pos = e.getKey(); + for (String comment : e.getValue()) { + ps.printf("Comment %d %s %s%n", pos, comment, SECTION_DELIM); + } + } + + for (Map.Entry> e : operandComments.entrySet()) { + for (String c : e.getValue()) { + ps.printf("OperandComment %d %s %s%n", e.getKey(), c, SECTION_DELIM); + } + } + ps.flush(); + } + + /** + * Formats a byte array as a string of hex digits. + */ + public static String hexCodeString(byte[] code) { + if (code == null) { + return ""; + } else { + StringBuilder sb = new StringBuilder(code.length * 2); + for (int b : code) { + String hex = Integer.toHexString(b & 0xff); + if (hex.length() == 1) { + sb.append('0'); + } + sb.append(hex); + } + return sb.toString(); + } + } + + /** + * Adds a comment to the list of comments for a given position. + */ + public void addComment(int pos, String comment) { + List list = comments.get(pos); + if (list == null) { + list = new ArrayList<>(); + comments.put(pos, list); + } + list.add(encodeString(comment)); + } + + /** + * Adds an operand comment for a given position. + */ + public void addOperandComment(int pos, String comment) { + List list = comments.get(pos); + if (list == null) { + list = new ArrayList<>(1); + comments.put(pos, list); + } + list.add(encodeString(comment)); + } + + /** + * Adds any jump tables, lookup tables or code comments from a list of code annotations. + */ + public static void addAnnotations(HexCodeFile hcf, List annotations) { + if (annotations == null || annotations.isEmpty()) { + return; + } + for (CodeAnnotation a : annotations) { + if (a instanceof JumpTable) { + JumpTable table = (JumpTable) a; + hcf.jumpTables.add(table); + } else if (a instanceof CodeComment) { + CodeComment comment = (CodeComment) a; + hcf.addComment(comment.position, comment.value); + } + } + } + + /** + * Modifies a string to mangle any substrings matching {@link #SECTION_DELIM} and + * {@link #COLUMN_END}. + */ + public static String encodeString(String input) { + int index; + String s = input; + while ((index = s.indexOf(SECTION_DELIM)) != -1) { + s = s.substring(0, index) + " < |@" + s.substring(index + SECTION_DELIM.length()); + } + while ((index = s.indexOf(COLUMN_END)) != -1) { + s = s.substring(0, index) + " < @" + s.substring(index + COLUMN_END.length()); + } + return s; + } + + /** + * Helper class to parse a string in the format produced by {@link HexCodeFile#toString()} and + * produce a {@link HexCodeFile} object. + */ + static class Parser { + + final String input; + final String inputSource; + String isa; + int wordWidth; + byte[] code; + long startAddress; + HexCodeFile hcf; + + Parser(String input, int sourceOffset, String source, String sourceName) { + this.input = input; + this.inputSource = sourceName; + parseSections(sourceOffset, source); + } + + void makeHCF() { + if (hcf == null) { + if (isa != null && wordWidth != 0 && code != null) { + hcf = new HexCodeFile(code, startAddress, isa, wordWidth); + } + } + } + + void checkHCF(String section, int offset) { + check(hcf != null, offset, section + " section must be after Platform and HexCode section"); + } + + void check(boolean condition, int offset, String message) { + if (!condition) { + error(offset, message); + } + } + + Error error(int offset, String message) { + throw new Error(errorMessage(offset, message)); + } + + void warning(int offset, String message) { + PrintStream err = System.err; + err.println("Warning: " + errorMessage(offset, message)); + } + + String errorMessage(int offset, String message) { + assert offset < input.length(); + InputPos inputPos = filePos(offset); + int lineEnd = input.indexOf(HexCodeFile.NEW_LINE, offset); + int lineStart = offset - inputPos.col; + String line = lineEnd == -1 ? input.substring(lineStart) : input.substring(lineStart, lineEnd); + return String.format("%s:%d: %s%n%s%n%" + (inputPos.col + 1) + "s", inputSource, inputPos.line, message, line, "^"); + } + + static class InputPos { + + final int line; + final int col; + + InputPos(int line, int col) { + this.line = line; + this.col = col; + } + } + + InputPos filePos(int index) { + assert input != null; + int lineStart = input.lastIndexOf(HexCodeFile.NEW_LINE, index) + 1; + + String l = input.substring(lineStart, lineStart + 10); + PrintStream out = System.out; + out.println("YYY" + input.substring(index, index + 10) + "..."); + out.println("XXX" + l + "..."); + + int pos = input.indexOf(HexCodeFile.NEW_LINE, 0); + int line = 1; + while (pos > 0 && pos < index) { + line++; + pos = input.indexOf(HexCodeFile.NEW_LINE, pos + 1); + } + return new InputPos(line, index - lineStart); + } + + void parseSections(int offset, String source) { + assert input.startsWith(source, offset); + int index = 0; + int endIndex = source.indexOf(SECTION_DELIM); + while (endIndex != -1) { + while (source.charAt(index) <= ' ') { + index++; + } + String section = source.substring(index, endIndex).trim(); + parseSection(offset + index, section); + index = endIndex + SECTION_DELIM.length(); + endIndex = source.indexOf(SECTION_DELIM, index); + } + } + + int parseInt(int offset, String value) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw error(offset, "Not a valid integer: " + value); + } + } + + void parseSection(int offset, String section) { + if (section.isEmpty()) { + return; + } + assert input.startsWith(section, offset); + Matcher m = HexCodeFile.SECTION.matcher(section); + check(m.matches(), offset, "Section does not match pattern " + HexCodeFile.SECTION); + + String header = m.group(1); + String body = m.group(2); + int headerOffset = offset + m.start(1); + int bodyOffset = offset + m.start(2); + + if (header.equals("Platform")) { + check(isa == null, bodyOffset, "Duplicate Platform section found"); + m = HexCodeFile.PLATFORM.matcher(body); + check(m.matches(), bodyOffset, "Platform does not match pattern " + HexCodeFile.PLATFORM); + isa = m.group(1); + wordWidth = parseInt(bodyOffset + m.start(2), m.group(2)); + makeHCF(); + } else if (header.equals("HexCode")) { + check(code == null, bodyOffset, "Duplicate Code section found"); + m = HexCodeFile.HEX_CODE.matcher(body); + check(m.matches(), bodyOffset, "Code does not match pattern " + HexCodeFile.HEX_CODE); + String hexAddress = m.group(1); + startAddress = Long.valueOf(hexAddress, 16); + String hexCode = m.group(2); + if (hexCode == null) { + code = new byte[0]; + } else { + check((hexCode.length() % 2) == 0, bodyOffset, "Hex code length must be even"); + code = new byte[hexCode.length() / 2]; + for (int i = 0; i < code.length; i++) { + String hexByte = hexCode.substring(i * 2, (i + 1) * 2); + code[i] = (byte) Integer.parseInt(hexByte, 16); + } + } + makeHCF(); + } else if (header.equals("Comment")) { + checkHCF("Comment", headerOffset); + m = HexCodeFile.COMMENT.matcher(body); + check(m.matches(), bodyOffset, "Comment does not match pattern " + HexCodeFile.COMMENT); + int pos = parseInt(bodyOffset + m.start(1), m.group(1)); + String comment = m.group(2); + hcf.addComment(pos, comment); + } else if (header.equals("OperandComment")) { + checkHCF("OperandComment", headerOffset); + m = HexCodeFile.OPERAND_COMMENT.matcher(body); + check(m.matches(), bodyOffset, "OperandComment does not match pattern " + HexCodeFile.OPERAND_COMMENT); + int pos = parseInt(bodyOffset + m.start(1), m.group(1)); + String comment = m.group(2); + hcf.addOperandComment(pos, comment); + } else if (header.equals("JumpTable")) { + checkHCF("JumpTable", headerOffset); + m = HexCodeFile.JUMP_TABLE.matcher(body); + check(m.matches(), bodyOffset, "JumpTable does not match pattern " + HexCodeFile.JUMP_TABLE); + int pos = parseInt(bodyOffset + m.start(1), m.group(1)); + int entrySize = parseInt(bodyOffset + m.start(2), m.group(2)); + int low = parseInt(bodyOffset + m.start(3), m.group(3)); + int high = parseInt(bodyOffset + m.start(4), m.group(4)); + hcf.jumpTables.add(new JumpTable(pos, low, high, entrySize)); + } else { + error(offset, "Unknown section header: " + header); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFileDisassemblerProvider.java 2016-12-07 13:47:42.740754523 -0800 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2013, 2016, 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.code; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.code.CodeUtil.DefaultRefMapFormatter; +import jdk.vm.ci.code.CodeUtil.RefMapFormatter; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.code.site.DataPatch; +import jdk.vm.ci.code.site.ExceptionHandler; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.code.site.Mark; + +import org.graalvm.compiler.serviceprovider.ServiceProvider; + +/** + * {@link HexCodeFile} based implementation of {@link DisassemblerProvider}. + */ +@ServiceProvider(DisassemblerProvider.class) +public class HexCodeFileDisassemblerProvider implements DisassemblerProvider { + + @Override + public String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) { + assert compResult != null; + return disassemble(codeCache, compResult, null); + } + + @Override + public String getName() { + return "hcf"; + } + + @Override + public String disassembleInstalledCode(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) { + assert installedCode != null; + return installedCode.isValid() ? disassemble(codeCache, compResult, installedCode) : null; + } + + private static String disassemble(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) { + TargetDescription target = codeCache.getTarget(); + RegisterConfig regConfig = codeCache.getRegisterConfig(); + byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode(); + if (code == null) { + // Method was deoptimized/invalidated + return ""; + } + long start = installedCode == null ? 0L : installedCode.getStart(); + HexCodeFile hcf = new HexCodeFile(code, start, target.arch.getName(), target.wordSize * 8); + if (compResult != null) { + HexCodeFile.addAnnotations(hcf, compResult.getAnnotations()); + addExceptionHandlersComment(compResult, hcf); + Register fp = regConfig.getFrameRegister(); + RefMapFormatter slotFormatter = new DefaultRefMapFormatter(target.wordSize, fp, 0); + for (Infopoint infopoint : compResult.getInfopoints()) { + if (infopoint instanceof Call) { + Call call = (Call) infopoint; + if (call.debugInfo != null) { + hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString()); + } + addOperandComment(hcf, call.pcOffset, "{" + codeCache.getTargetName(call) + "}"); + } else { + if (infopoint.debugInfo != null) { + hcf.addComment(infopoint.pcOffset, CodeUtil.append(new StringBuilder(100), infopoint.debugInfo, slotFormatter).toString()); + } + addOperandComment(hcf, infopoint.pcOffset, "{infopoint: " + infopoint.reason + "}"); + } + } + for (DataPatch site : compResult.getDataPatches()) { + hcf.addOperandComment(site.pcOffset, "{" + site.reference.toString() + "}"); + } + for (Mark mark : compResult.getMarks()) { + hcf.addComment(mark.pcOffset, codeCache.getMarkName(mark)); + } + } + String hcfEmbeddedString = hcf.toEmbeddedString(); + return HexCodeFileDisTool.tryDisassemble(hcfEmbeddedString); + } + + private static void addExceptionHandlersComment(CompilationResult compResult, HexCodeFile hcf) { + if (!compResult.getExceptionHandlers().isEmpty()) { + String nl = HexCodeFile.NEW_LINE; + StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl); + for (ExceptionHandler e : compResult.getExceptionHandlers()) { + buf.append(" ").append(e.pcOffset).append(" -> ").append(e.handlerPos).append(nl); + hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]"); + hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]"); + } + hcf.addComment(0, buf.toString()); + } + } + + private static void addOperandComment(HexCodeFile hcf, int pos, String comment) { + hcf.addOperandComment(pos, comment); + } + + /** + * Interface to the tool for disassembling an {@link HexCodeFile#toEmbeddedString() embedded} + * {@link HexCodeFile}. + */ + static class HexCodeFileDisTool { + static final MethodHandle processMethod; + + static { + MethodHandle toolMethod = null; + try { + Class toolClass = Class.forName("com.oracle.max.hcfdis.HexCodeFileDis", true, ClassLoader.getSystemClassLoader()); + toolMethod = MethodHandles.lookup().unreflect(toolClass.getDeclaredMethod("processEmbeddedString", String.class)); + } catch (Exception e) { + // Tool not available on the class path + } + processMethod = toolMethod; + } + + public static String tryDisassemble(String hcfEmbeddedString) { + if (processMethod != null) { + try { + return (String) processMethod.invokeExact(hcfEmbeddedString); + } catch (Throwable e) { + // If the tool is available, for now let's be noisy when it fails + throw new InternalError(e); + } + } + return hcfEmbeddedString; + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceMapping.java 2016-12-07 13:47:43.005766167 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016, 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.code; + +import static jdk.vm.ci.meta.MetaUtil.identityHashCodeString; + +import org.graalvm.compiler.graph.NodeSourcePosition; + +/** + * This provides a mapping between a half-open range of PCs in the generated code and a + * {@link NodeSourcePosition} in the original program. Depending on the backend this information may + * be represented in different ways or not at all. + */ +public final class SourceMapping { + + private final int startOffset; + + private final int endOffset; + + private final NodeSourcePosition sourcePosition; + + public SourceMapping(int startOffset, int endOffset, NodeSourcePosition sourcePosition) { + this.startOffset = startOffset; + this.endOffset = endOffset; + this.sourcePosition = sourcePosition; + } + + public int getStartOffset() { + return startOffset; + } + + public int getEndOffset() { + return endOffset; + } + + public NodeSourcePosition getSourcePosition() { + return sourcePosition; + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof SourceMapping) { + SourceMapping other = (SourceMapping) obj; + return other.startOffset == startOffset && other.endOffset == endOffset && other.sourcePosition.equals(sourcePosition); + } + return false; + } + + public boolean contains(int offset) { + return startOffset <= offset && offset < endOffset; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceStackTraceBailoutException.java 2016-12-07 13:47:43.268777724 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, 2015, 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.code; + +import org.graalvm.compiler.common.PermanentBailoutException; + +/** + * Represents a bailout exception with a stack trace in terms of the Java source being compiled + * instead of the stack trace of the compiler. The exception of the compiler is saved as the cause + * of this exception. + */ +public abstract class SourceStackTraceBailoutException extends PermanentBailoutException { + private static final long serialVersionUID = 2144811793442316776L; + + public static SourceStackTraceBailoutException create(Throwable cause, String format, StackTraceElement[] elements) { + return new SourceStackTraceBailoutException(cause, format) { + + private static final long serialVersionUID = 6279381376051787907L; + + @Override + public synchronized Throwable fillInStackTrace() { + assert elements != null; + setStackTrace(elements); + return this; + } + }; + } + + private SourceStackTraceBailoutException(Throwable cause, String format) { + super(cause, format); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.common/src/org/graalvm/compiler/common/PermanentBailoutException.java 2016-12-07 13:47:43.536789500 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016, 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.common; + +import jdk.vm.ci.code.BailoutException; + +public class PermanentBailoutException extends BailoutException { + + private static final long serialVersionUID = -2683649650135362549L; + + public PermanentBailoutException(String format, Object... args) { + super(true, format, args); + } + + public PermanentBailoutException(String reason) { + super(true, reason); + } + + public PermanentBailoutException(Throwable cause, String format, Object... args) { + super(cause, format, args); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.common/src/org/graalvm/compiler/common/RetryableBailoutException.java 2016-12-07 13:47:43.800801101 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, 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.common; + +import jdk.vm.ci.code.BailoutException; + +public class RetryableBailoutException extends BailoutException { + + private static final long serialVersionUID = -7145365025679144525L; + + public RetryableBailoutException(String format, Object... args) { + super(false, format, args); + } + + public RetryableBailoutException(String reason) { + super(false, reason); + } + + public RetryableBailoutException(Throwable cause, String format) { + super(cause, format); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64AddressLowering.java 2016-12-07 13:47:44.066812789 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, 2016, 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.core.aarch64; + +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering; + +public class AArch64AddressLowering extends AddressLowering { + + @Override + public AddressNode lower(ValueNode address) { + return lower(address, null); + } + + @Override + public AddressNode lower(ValueNode base, ValueNode offset) { + AArch64AddressNode ret = new AArch64AddressNode(base, offset); + // TODO improve + return base.graph().unique(ret); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64AddressNode.java 2016-12-07 13:47:44.331824434 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2016, 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.core.aarch64; + +import org.graalvm.compiler.asm.aarch64.AArch64Address; +import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; + +/** + * Represents an address of the form... TODO. + */ +@NodeInfo +public class AArch64AddressNode extends AddressNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(AArch64AddressNode.class); + + @OptionalInput private ValueNode base; + + @OptionalInput private ValueNode index; + private AArch64Address.AddressingMode addressingMode; + + private int displacement; + + public AArch64AddressNode(ValueNode base) { + this(base, null); + } + + public AArch64AddressNode(ValueNode base, ValueNode index) { + super(TYPE); + this.base = base; + this.index = index; + this.addressingMode = AddressingMode.REGISTER_OFFSET; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + LIRGeneratorTool tool = gen.getLIRGeneratorTool(); + + AllocatableValue baseValue = base == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(base)); + AllocatableValue indexValue = index == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(index)); + + AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue); + AllocatableValue indexReference; + if (addressingMode.equals(AddressingMode.IMMEDIATE_UNSCALED)) { + indexReference = LIRKind.derivedBaseFromValue(indexValue); + throw GraalError.unimplemented(); + } else { + if (LIRKind.isValue(indexValue.getValueKind())) { + indexReference = null; + } else { + indexReference = Value.ILLEGAL; + } + } + + LIRKind kind = LIRKind.combineDerived(tool.getLIRKind(stamp()), baseReference, indexReference); + final boolean scaled = false; + gen.setResult(this, new AArch64AddressValue(kind, baseValue, indexValue, displacement, scaled, addressingMode)); + } + + public ValueNode getBase() { + return base; + } + + public void setBase(ValueNode base) { + // allow modification before inserting into the graph + if (isAlive()) { + updateUsages(this.base, base); + } + this.base = base; + } + + public ValueNode getIndex() { + return index; + } + + public void setIndex(ValueNode index) { + // allow modification before inserting into the graph + if (isAlive()) { + updateUsages(this.index, index); + } + this.index = index; + } + + public int getDisplacement() { + return displacement; + } + + public void setDisplacement(int displacement) { + this.displacement = displacement; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java 2016-12-07 13:47:44.596836078 -0800 @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2015, 2015, 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.core.aarch64; + +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static jdk.vm.ci.aarch64.AArch64.sp; +import static jdk.vm.ci.aarch64.AArch64Kind.DWORD; +import static jdk.vm.ci.aarch64.AArch64Kind.QWORD; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.FloatConvert; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.ConstantValue; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; +import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticLIRGeneratorTool; +import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp; +import org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp; +import org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode; +import org.graalvm.compiler.lir.aarch64.AArch64Move.LoadOp; +import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreConstantOp; +import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp; +import org.graalvm.compiler.lir.aarch64.AArch64ReinterpretOp; +import org.graalvm.compiler.lir.aarch64.AArch64SignExtendOp; +import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator; + +import jdk.vm.ci.aarch64.AArch64Kind; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; + +public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implements AArch64ArithmeticLIRGeneratorTool { + + @Override + public AArch64LIRGenerator getLIRGen() { + return (AArch64LIRGenerator) super.getLIRGen(); + } + + @Override + protected boolean isNumericInteger(PlatformKind kind) { + return ((AArch64Kind) kind).isInteger(); + } + + @Override + protected Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) { + if (isNumericInteger(a.getPlatformKind())) { + AArch64ArithmeticOp op = setFlags ? AArch64ArithmeticOp.ADDS : AArch64ArithmeticOp.ADD; + return emitBinary(resultKind, op, true, a, b); + } else { + assert !setFlags : "Cannot set flags on floating point arithmetic"; + return emitBinary(resultKind, AArch64ArithmeticOp.FADD, true, a, b); + } + } + + @Override + protected Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) { + if (isNumericInteger(a.getPlatformKind())) { + AArch64ArithmeticOp op = setFlags ? AArch64ArithmeticOp.SUBS : AArch64ArithmeticOp.SUB; + return emitBinary(resultKind, op, false, a, b); + } else { + assert !setFlags : "Cannot set flags on floating point arithmetic"; + return emitBinary(resultKind, AArch64ArithmeticOp.FSUB, false, a, b); + } + } + + @Override + public Value emitMul(Value a, Value b, boolean setFlags) { + // TODO (das) setFlags handling - should be handled higher up. Ask for ideas at mailing list + assert !setFlags : "Set flags on multiplication is not supported"; + return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.MUL, AArch64ArithmeticOp.FMUL), true, a, b); + } + + @Override + public Value emitMulHigh(Value a, Value b) { + assert isNumericInteger(a.getPlatformKind()); + return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.SMULH, true, a, b); + } + + @Override + public Value emitUMulHigh(Value a, Value b) { + assert isNumericInteger(a.getPlatformKind()); + return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UMULH, true, a, b); + } + + @Override + public Value emitDiv(Value a, Value b, LIRFrameState state) { + return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.DIV, AArch64ArithmeticOp.FDIV), false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b)); + } + + @Override + public Value emitRem(Value a, Value b, LIRFrameState state) { + return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.REM, AArch64ArithmeticOp.FREM), false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b)); + } + + @Override + public Value emitUDiv(Value a, Value b, LIRFrameState state) { + assert isNumericInteger(a.getPlatformKind()); + return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UDIV, false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b)); + } + + @Override + public Value emitURem(Value a, Value b, LIRFrameState state) { + assert isNumericInteger(a.getPlatformKind()); + return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UREM, false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b)); + } + + @Override + public Value emitAnd(Value a, Value b) { + assert isNumericInteger(a.getPlatformKind()); + return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.AND, true, a, b); + } + + @Override + public Value emitOr(Value a, Value b) { + assert isNumericInteger(a.getPlatformKind()); + return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.OR, true, a, b); + } + + @Override + public Value emitXor(Value a, Value b) { + assert isNumericInteger(a.getPlatformKind()); + return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.XOR, true, a, b); + } + + @Override + public Value emitShl(Value a, Value b) { + assert isNumericInteger(a.getPlatformKind()); + return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.SHL, false, a, b); + } + + @Override + public Value emitShr(Value a, Value b) { + assert isNumericInteger(a.getPlatformKind()); + return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.ASHR, false, a, b); + } + + @Override + public Value emitUShr(Value a, Value b) { + assert isNumericInteger(a.getPlatformKind()); + return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.LSHR, false, a, b); + } + + @Override + public Value emitFloatConvert(FloatConvert op, Value inputVal) { + PlatformKind resultPlatformKind = getFloatConvertResultKind(op); + LIRKind resultLirKind = LIRKind.combine(inputVal).changeType(resultPlatformKind); + Variable result = getLIRGen().newVariable(resultLirKind); + getLIRGen().append(new AArch64FloatConvertOp(op, result, getLIRGen().asAllocatable(inputVal))); + return result; + } + + private static PlatformKind getFloatConvertResultKind(FloatConvert op) { + switch (op) { + case F2I: + case D2I: + return AArch64Kind.DWORD; + case F2L: + case D2L: + return AArch64Kind.QWORD; + case I2F: + case L2F: + case D2F: + return AArch64Kind.SINGLE; + case I2D: + case L2D: + case F2D: + return AArch64Kind.DOUBLE; + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Value emitReinterpret(LIRKind to, Value inputVal) { + ValueKind from = inputVal.getValueKind(); + if (to.equals(from)) { + return inputVal; + } + Variable result = getLIRGen().newVariable(to); + getLIRGen().append(new AArch64ReinterpretOp(result, getLIRGen().asAllocatable(inputVal))); + return result; + } + + @Override + public Value emitNarrow(Value inputVal, int bits) { + if (inputVal.getPlatformKind() == AArch64Kind.QWORD && bits <= 32) { + LIRKind resultKind = getResultLirKind(bits, inputVal); + long mask = NumUtil.getNbitNumberLong(bits); + Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask)); + return emitBinary(resultKind, AArch64ArithmeticOp.AND, true, inputVal, maskValue); + } else { + return inputVal; + } + } + + @Override + public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && (toBits == 32 || toBits == 64); + if (fromBits == toBits) { + return inputVal; + } + LIRKind resultKind = getResultLirKind(toBits, inputVal); + long mask = NumUtil.getNbitNumberLong(fromBits); + Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask)); + return emitBinary(resultKind, AArch64ArithmeticOp.AND, true, inputVal, maskValue); + } + + @Override + public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && (toBits == 32 || toBits == 64); + if (fromBits == toBits) { + return inputVal; + } + LIRKind resultKind = getResultLirKind(toBits, inputVal); + Variable result = getLIRGen().newVariable(resultKind); + getLIRGen().append(new AArch64SignExtendOp(result, getLIRGen().asAllocatable(inputVal), fromBits, toBits)); + return result; + } + + private static LIRKind getResultLirKind(int resultBitSize, Value... inputValues) { + if (resultBitSize == 64) { + return LIRKind.combine(inputValues).changeType(QWORD); + } else { + assert resultBitSize == 32; + return LIRKind.combine(inputValues).changeType(DWORD); + } + } + + protected Variable emitBinary(ValueKind resultKind, AArch64ArithmeticOp op, boolean commutative, Value a, Value b) { + Variable result = getLIRGen().newVariable(resultKind); + if (isValidBinaryConstant(op, a, b)) { + emitBinaryConst(result, op, getLIRGen().asAllocatable(a), asJavaConstant(b)); + } else if (commutative && isValidBinaryConstant(op, b, a)) { + emitBinaryConst(result, op, getLIRGen().asAllocatable(b), asJavaConstant(a)); + } else { + emitBinaryVar(result, op, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b)); + } + return result; + } + + private void emitBinaryVar(Variable result, AArch64ArithmeticOp op, AllocatableValue a, AllocatableValue b) { + AllocatableValue x = moveSp(a); + AllocatableValue y = moveSp(b); + switch (op) { + case FREM: + case REM: + case UREM: + getLIRGen().append(new AArch64ArithmeticOp.BinaryCompositeOp(op, result, x, y)); + break; + default: + getLIRGen().append(new AArch64ArithmeticOp.BinaryOp(op, result, x, y)); + break; + } + } + + private void emitBinaryConst(Variable result, AArch64ArithmeticOp op, AllocatableValue a, JavaConstant b) { + AllocatableValue x = moveSp(a); + getLIRGen().append(new AArch64ArithmeticOp.BinaryConstOp(op, result, x, b)); + } + + private static boolean isValidBinaryConstant(AArch64ArithmeticOp op, Value a, Value b) { + if (!isJavaConstant(b)) { + return false; + } + JavaConstant constValue = asJavaConstant(b); + switch (op.category) { + case LOGICAL: + return isLogicalConstant(constValue); + case ARITHMETIC: + return isArithmeticConstant(constValue); + case SHIFT: + assert constValue.asLong() >= 0 && constValue.asLong() < a.getPlatformKind().getSizeInBytes() * Byte.SIZE; + return true; + case NONE: + return false; + default: + throw GraalError.shouldNotReachHere(); + } + } + + private static boolean isLogicalConstant(JavaConstant constValue) { + switch (constValue.getJavaKind()) { + case Int: + return AArch64MacroAssembler.isLogicalImmediate(constValue.asInt()); + case Long: + return AArch64MacroAssembler.isLogicalImmediate(constValue.asLong()); + default: + return false; + } + } + + protected static boolean isArithmeticConstant(JavaConstant constValue) { + switch (constValue.getJavaKind()) { + case Int: + case Long: + return AArch64MacroAssembler.isArithmeticImmediate(constValue.asLong()); + case Object: + return constValue.isNull(); + default: + return false; + } + } + + @Override + public Value emitNegate(Value inputVal) { + return emitUnary(getOpCode(inputVal, AArch64ArithmeticOp.NEG, AArch64ArithmeticOp.FNEG), inputVal); + } + + @Override + public Value emitNot(Value input) { + assert isNumericInteger(input.getPlatformKind()); + return emitUnary(AArch64ArithmeticOp.NOT, input); + } + + @Override + public Value emitMathAbs(Value input) { + return emitUnary(getOpCode(input, AArch64ArithmeticOp.ABS, AArch64ArithmeticOp.FABS), input); + } + + @Override + public Value emitMathSqrt(Value input) { + assert input.getPlatformKind() == AArch64Kind.DOUBLE; + return emitUnary(AArch64ArithmeticOp.SQRT, input); + } + + @Override + public Value emitBitScanForward(Value inputVal) { + return emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode.BSF, inputVal); + } + + @Override + public Value emitBitCount(Value operand) { + throw GraalError.unimplemented("AArch64 ISA does not offer way to implement this more efficiently than a simple Java algorithm."); + } + + @Override + public Value emitBitScanReverse(Value inputVal) { + // TODO (das) old implementation said to use emitCountLeadingZeros instead - need extra node + // for that though + return emitBitManipulation(BitManipulationOpCode.BSR, inputVal); + } + + @Override + public Value emitCountLeadingZeros(Value value) { + return emitBitManipulation(BitManipulationOpCode.CLZ, value); + } + + @Override + public Value emitCountTrailingZeros(Value value) { + throw GraalError.unimplemented(); + } + + private Variable emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode op, Value inputVal) { + assert isNumericInteger(inputVal.getPlatformKind()); + AllocatableValue input = getLIRGen().asAllocatable(inputVal); + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + getLIRGen().append(new AArch64BitManipulationOp(op, result, input)); + return result; + } + + private Variable emitUnary(AArch64ArithmeticOp op, Value inputVal) { + AllocatableValue input = getLIRGen().asAllocatable(inputVal); + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + getLIRGen().append(new AArch64ArithmeticOp.UnaryOp(op, result, input)); + return result; + } + + /** + * If val denotes the stackpointer, move it to another location. This is necessary since most + * ops cannot handle the stackpointer as input or output. + */ + private AllocatableValue moveSp(AllocatableValue val) { + if (val instanceof RegisterValue && ((RegisterValue) val).getRegister().equals(sp)) { + assert val.getPlatformKind() == AArch64Kind.QWORD : "Stackpointer must be long"; + return getLIRGen().emitMove(val); + } + return val; + } + + /** + * Returns the opcode depending on the platform kind of val. + */ + private AArch64ArithmeticOp getOpCode(Value val, AArch64ArithmeticOp intOp, AArch64ArithmeticOp floatOp) { + return isNumericInteger(val.getPlatformKind()) ? intOp : floatOp; + } + + @Override + public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { + AArch64AddressValue loadAddress = getLIRGen().asAddressValue(address); + Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind)); + getLIRGen().append(new LoadOp((AArch64Kind) kind.getPlatformKind(), result, loadAddress, state)); + return result; + } + + @Override + public void emitStore(ValueKind lirKind, Value address, Value inputVal, LIRFrameState state) { + AArch64AddressValue storeAddress = getLIRGen().asAddressValue(address); + AArch64Kind kind = (AArch64Kind) lirKind.getPlatformKind(); + + if (isJavaConstant(inputVal) && kind.isInteger()) { + JavaConstant c = asJavaConstant(inputVal); + if (c.isDefaultForKind()) { + // We can load 0 directly into integer registers + getLIRGen().append(new StoreConstantOp(kind, storeAddress, c, state)); + return; + } + } + AllocatableValue input = getLIRGen().asAllocatable(inputVal); + getLIRGen().append(new StoreOp(kind, storeAddress, input, state)); + } + + @Override + public Value emitMathLog(Value input, boolean base10) { + throw GraalError.unimplemented(); + } + + @Override + public Value emitMathCos(Value input) { + throw GraalError.unimplemented(); + } + + @Override + public Value emitMathSin(Value input) { + throw GraalError.unimplemented(); + } + + @Override + public Value emitMathTan(Value input) { + throw GraalError.unimplemented(); + } + + @Override + public void emitCompareOp(AArch64Kind cmpKind, Variable left, Value right) { + throw GraalError.unimplemented(); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64FloatConvertOp.java 2016-12-07 13:47:44.862847766 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013, 2015, 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.core.aarch64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.core.common.calc.FloatConvert; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +public final class AArch64FloatConvertOp extends AArch64LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64FloatConvertOp.class); + + private final FloatConvert op; + @Def protected AllocatableValue resultValue; + @Use protected AllocatableValue inputValue; + + protected AArch64FloatConvertOp(FloatConvert op, AllocatableValue resultValue, AllocatableValue inputValue) { + super(TYPE); + this.op = op; + this.resultValue = resultValue; + this.inputValue = inputValue; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + int fromSize = inputValue.getPlatformKind().getSizeInBytes() * Byte.SIZE; + int toSize = resultValue.getPlatformKind().getSizeInBytes() * Byte.SIZE; + + Register result = asRegister(resultValue); + Register input = asRegister(inputValue); + switch (op) { + case F2I: + case D2I: + case F2L: + case D2L: + masm.fcvtzs(toSize, fromSize, result, input); + break; + case I2F: + case I2D: + case L2F: + case L2D: + masm.scvtf(toSize, fromSize, result, input); + break; + case D2F: + case F2D: + masm.fcvt(fromSize, result, input); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java 2016-12-07 13:47:45.127859411 -0800 @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2013, 2016, 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.core.aarch64; + +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; + +import java.util.function.Function; + +import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRValueUtil; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.StandardOp; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; +import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp; +import org.graalvm.compiler.lir.aarch64.AArch64Compare; +import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow; +import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.BranchOp; +import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.CondMoveOp; +import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp; +import org.graalvm.compiler.lir.aarch64.AArch64Move; +import org.graalvm.compiler.lir.aarch64.AArch64Move.CompareAndSwapOp; +import org.graalvm.compiler.lir.aarch64.AArch64Move.MembarOp; +import org.graalvm.compiler.lir.aarch64.AArch64PauseOp; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.gen.LIRGenerator; +import org.graalvm.compiler.phases.util.Providers; + +import jdk.vm.ci.aarch64.AArch64Kind; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.PrimitiveConstant; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; + +public abstract class AArch64LIRGenerator extends LIRGenerator { + + public AArch64LIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes) { + super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes); + } + + /** + * Checks whether the supplied constant can be used without loading it into a register for store + * operations, i.e., on the right hand side of a memory access. + * + * @param c The constant to check. + * @return True if the constant can be used directly, false if the constant needs to be in a + * register. + */ + protected static final boolean canStoreConstant(JavaConstant c) { + // Our own code never calls this since we can't make a definite statement about whether or + // not we can inline a constant without knowing what kind of operation we execute. Let's be + // optimistic here and fix up mistakes later. + return true; + } + + /** + * AArch64 cannot use anything smaller than a word in any instruction other than load and store. + */ + @Override + public > K toRegisterKind(K kind) { + switch ((AArch64Kind) kind.getPlatformKind()) { + case BYTE: + case WORD: + return kind.changeType(AArch64Kind.DWORD); + default: + return kind; + } + } + + @Override + public void emitNullCheck(Value address, LIRFrameState state) { + append(new AArch64Move.NullCheckOp(asAddressValue(address), state)); + } + + @Override + public Variable emitAddress(AllocatableValue stackslot) { + Variable result = newVariable(LIRKind.value(target().arch.getWordKind())); + append(new AArch64Move.StackLoadAddressOp(result, stackslot)); + return result; + } + + public AArch64AddressValue asAddressValue(Value address) { + if (address instanceof AArch64AddressValue) { + return (AArch64AddressValue) address; + } else { + return new AArch64AddressValue(address.getValueKind(), asAllocatable(address), Value.ILLEGAL, 0, false, AddressingMode.BASE_REGISTER_ONLY); + } + } + + @Override + public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { + Variable result = newVariable(trueValue.getValueKind()); + Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD)); + append(new CompareAndSwapOp(result, loadNonCompareConst(expectedValue), loadReg(newValue), asAllocatable(address), scratch)); + return result; + } + + @Override + public void emitMembar(int barriers) { + int necessaryBarriers = target().arch.requiredBarriers(barriers); + if (target().isMP && necessaryBarriers != 0) { + append(new MembarOp(necessaryBarriers)); + } + } + + @Override + public void emitJump(LabelRef label) { + assert label != null; + append(new StandardOp.JumpOp(label)); + } + + @Override + public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability) { + append(new AArch64ControlFlow.BranchOp(ConditionFlag.VS, overflow, noOverflow, overflowProbability)); + } + + /** + * Branches to label if (left & right) == 0. If negated is true branchse on non-zero instead. + * + * @param left Integer kind. Non null. + * @param right Integer kind. Non null. + * @param trueDestination destination if left & right == 0. Non null. + * @param falseDestination destination if left & right != 0. Non null + * @param trueSuccessorProbability hoistoric probability that comparison is true + */ + @Override + public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability) { + assert ((AArch64Kind) left.getPlatformKind()).isInteger() && left.getPlatformKind() == right.getPlatformKind(); + ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(LIRKind.combine(left, right), AArch64ArithmeticOp.ANDS, true, left, right); + append(new AArch64ControlFlow.BranchOp(ConditionFlag.EQ, trueDestination, falseDestination, trueSuccessorProbability)); + } + + /** + * Conditionally move trueValue into new variable if cond + unorderedIsTrue is true, else + * falseValue. + * + * @param left Arbitrary value. Has to have same type as right. Non null. + * @param right Arbitrary value. Has to have same type as left. Non null. + * @param cond condition that decides whether to move trueValue or falseValue into result. Non + * null. + * @param unorderedIsTrue defines whether floating-point comparisons consider unordered true or + * not. Ignored for integer comparisons. + * @param trueValue arbitrary value same type as falseValue. Non null. + * @param falseValue arbitrary value same type as trueValue. Non null. + * @return value containing trueValue if cond + unorderedIsTrue is true, else falseValue. Non + * null. + */ + @Override + public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { + boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue); + Condition finalCondition = mirrored ? cond.mirror() : cond; + boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue; + ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue); + Variable result = newVariable(trueValue.getValueKind()); + append(new CondMoveOp(result, cmpCondition, loadReg(trueValue), loadReg(falseValue))); + return result; + } + + @Override + public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, + double trueDestinationProbability) { + boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue); + Condition finalCondition = mirrored ? cond.mirror() : cond; + boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue; + ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue); + append(new BranchOp(cmpCondition, trueDestination, falseDestination, trueDestinationProbability)); + } + + private static ConditionFlag toConditionFlag(boolean isInt, Condition cond, boolean unorderedIsTrue) { + return isInt ? toIntConditionFlag(cond) : toFloatConditionFlag(cond, unorderedIsTrue); + } + + /** + * Takes a Condition and unorderedIsTrue flag and returns the correct Aarch64 specific + * ConditionFlag. Note: This is only correct if the emitCompare code for floats has correctly + * handled the case of 'EQ && unorderedIsTrue', respectively 'NE && !unorderedIsTrue'! + */ + private static ConditionFlag toFloatConditionFlag(Condition cond, boolean unorderedIsTrue) { + switch (cond) { + case LT: + return unorderedIsTrue ? ConditionFlag.LT : ConditionFlag.LO; + case LE: + return unorderedIsTrue ? ConditionFlag.LE : ConditionFlag.LS; + case GE: + return unorderedIsTrue ? ConditionFlag.PL : ConditionFlag.GE; + case GT: + return unorderedIsTrue ? ConditionFlag.HI : ConditionFlag.GT; + case EQ: + return ConditionFlag.EQ; + case NE: + return ConditionFlag.NE; + default: + throw GraalError.shouldNotReachHere(); + } + } + + /** + * Takes a Condition and returns the correct Aarch64 specific ConditionFlag. + */ + private static ConditionFlag toIntConditionFlag(Condition cond) { + switch (cond) { + case EQ: + return ConditionFlag.EQ; + case NE: + return ConditionFlag.NE; + case LT: + return ConditionFlag.LT; + case LE: + return ConditionFlag.LE; + case GT: + return ConditionFlag.GT; + case GE: + return ConditionFlag.GE; + case AE: + return ConditionFlag.HS; + case BE: + return ConditionFlag.LS; + case AT: + return ConditionFlag.HI; + case BT: + return ConditionFlag.LO; + default: + throw GraalError.shouldNotReachHere(); + } + } + + /** + * This method emits the compare instruction, and may reorder the operands. It returns true if + * it did so. + * + * @param a the left operand of the comparison. Has to have same type as b. Non null. + * @param b the right operand of the comparison. Has to have same type as a. Non null. + * @return true if mirrored (i.e. "b cmp a" instead of "a cmp b" was done). + */ + protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue) { + Value left; + Value right; + boolean mirrored; + AArch64Kind kind = (AArch64Kind) cmpKind; + if (kind.isInteger()) { + if (LIRValueUtil.isVariable(b)) { + left = load(b); + right = loadNonConst(a); + mirrored = true; + } else { + left = load(a); + right = loadNonConst(b); + mirrored = false; + } + append(new AArch64Compare.CompareOp(left, loadNonCompareConst(right))); + } else if (kind.isSIMD()) { + if (AArch64Compare.FloatCompareOp.isFloatCmpConstant(a, condition, unorderedIsTrue)) { + left = load(b); + right = a; + mirrored = true; + } else if (AArch64Compare.FloatCompareOp.isFloatCmpConstant(b, condition, unorderedIsTrue)) { + left = load(a); + right = b; + mirrored = false; + } else { + left = load(a); + right = loadReg(b); + mirrored = false; + } + append(new AArch64Compare.FloatCompareOp(left, asAllocatable(right), condition, unorderedIsTrue)); + } else { + throw GraalError.shouldNotReachHere(); + } + return mirrored; + } + + /** + * If value is a constant that cannot be used directly with a gpCompare instruction load it into + * a register and return the register, otherwise return constant value unchanged. + */ + protected Value loadNonCompareConst(Value value) { + if (!isCompareConstant(value)) { + return loadReg(value); + } + return value; + } + + /** + * Checks whether value can be used directly with a gpCompare instruction. This is not + * the same as {@link AArch64ArithmeticLIRGenerator#isArithmeticConstant(JavaConstant)}, because + * 0.0 is a valid compare constant for floats, while there are no arithmetic constants for + * floats. + * + * @param value any type. Non null. + * @return true if value can be used directly in comparison instruction, false otherwise. + */ + public boolean isCompareConstant(Value value) { + if (isJavaConstant(value)) { + JavaConstant constant = asJavaConstant(value); + if (constant instanceof PrimitiveConstant) { + final long longValue = constant.asLong(); + long maskedValue; + switch (constant.getJavaKind()) { + case Boolean: + case Byte: + maskedValue = longValue & 0xFF; + break; + case Char: + case Short: + maskedValue = longValue & 0xFFFF; + break; + case Int: + maskedValue = longValue & 0xFFFF_FFFF; + break; + case Long: + maskedValue = longValue; + break; + default: + throw GraalError.shouldNotReachHere(); + } + return AArch64MacroAssembler.isArithmeticImmediate(maskedValue); + } else { + return constant.isDefaultForKind(); + } + } + return false; + } + + /** + * Moves trueValue into result if (left & right) == 0, else falseValue. + * + * @param left Integer kind. Non null. + * @param right Integer kind. Non null. + * @param trueValue Integer kind. Non null. + * @param falseValue Integer kind. Non null. + * @return virtual register containing trueValue if (left & right) == 0, else falseValue. + */ + @Override + public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) { + assert ((AArch64Kind) left.getPlatformKind()).isInteger() && ((AArch64Kind) right.getPlatformKind()).isInteger(); + assert ((AArch64Kind) trueValue.getPlatformKind()).isInteger() && ((AArch64Kind) falseValue.getPlatformKind()).isInteger(); + ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(trueValue.getValueKind(), AArch64ArithmeticOp.ANDS, true, left, right); + Variable result = newVariable(trueValue.getValueKind()); + append(new CondMoveOp(result, ConditionFlag.EQ, load(trueValue), load(falseValue))); + return result; + } + + @Override + public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { + append(createStrategySwitchOp(strategy, keyTargets, defaultTarget, key, newVariable(key.getValueKind()), AArch64LIRGenerator::toIntConditionFlag)); + } + + protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue, + Function converter) { + return new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter); + } + + @Override + protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) { + // Make copy of key since the TableSwitch destroys its input. + Variable tmp = emitMove(key); + Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD)); + append(new AArch64ControlFlow.TableSwitchOp(lowKey, defaultTarget, targets, tmp, scratch)); + } + + @Override + public Variable emitByteSwap(Value operand) { + // TODO (das) Do not generate until we support vector instructions + throw GraalError.unimplemented("Do not generate until we support vector instructions"); + } + + @Override + public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) { + // TODO (das) Do not generate until we support vector instructions + throw GraalError.unimplemented("Do not generate until we support vector instructions"); + } + + @Override + protected JavaConstant zapValueForKind(PlatformKind kind) { + long dead = 0xDEADDEADDEADDEADL; + switch ((AArch64Kind) kind) { + case BYTE: + return JavaConstant.forByte((byte) dead); + case WORD: + return JavaConstant.forShort((short) dead); + case DWORD: + return JavaConstant.forInt((int) dead); + case QWORD: + return JavaConstant.forLong(dead); + case SINGLE: + return JavaConstant.forFloat(Float.intBitsToFloat((int) dead)); + case DOUBLE: + return JavaConstant.forDouble(Double.longBitsToDouble(dead)); + default: + throw GraalError.shouldNotReachHere(); + } + } + + /** + * Loads value into virtual register. Contrary to {@link #load(Value)} this handles + * RegisterValues (i.e. values corresponding to fixed physical registers) correctly, by not + * creating an unnecessary move into a virtual register. + * + * This avoids generating the following code: mov x0, x19 # x19 is fixed thread register ldr x0, + * [x0] instead of: ldr x0, [x19]. + */ + protected AllocatableValue loadReg(Value val) { + if (!(val instanceof Variable || val instanceof RegisterValue)) { + return emitMove(val); + } + return (AllocatableValue) val; + } + + @Override + public void emitPause() { + append(new AArch64PauseOp()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRKindTool.java 2016-12-07 13:47:45.393871099 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015, 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.core.aarch64; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.aarch64.AArch64Kind; + +public class AArch64LIRKindTool implements LIRKindTool { + + @Override + public LIRKind getIntegerKind(int bits) { + if (bits <= 8) { + return LIRKind.value(AArch64Kind.BYTE); + } else if (bits <= 16) { + return LIRKind.value(AArch64Kind.WORD); + } else if (bits <= 32) { + return LIRKind.value(AArch64Kind.DWORD); + } else { + assert bits <= 64; + return LIRKind.value(AArch64Kind.QWORD); + } + } + + @Override + public LIRKind getFloatingKind(int bits) { + switch (bits) { + case 32: + return LIRKind.value(AArch64Kind.SINGLE); + case 64: + return LIRKind.value(AArch64Kind.DOUBLE); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public LIRKind getObjectKind() { + return LIRKind.reference(AArch64Kind.QWORD); + } + + @Override + public LIRKind getWordKind() { + return LIRKind.value(AArch64Kind.QWORD); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java 2016-12-07 13:47:45.658882744 -0800 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, 2016, 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.core.aarch64; + +import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; +import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.core.common.type.DataPointerConstant; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; +import org.graalvm.compiler.lir.aarch64.AArch64Move; +import org.graalvm.compiler.lir.aarch64.AArch64Move.LoadAddressOp; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; + +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.Value; + +public class AArch64MoveFactory implements MoveFactory { + + @Override + public LIRInstruction createMove(AllocatableValue dst, Value src) { + boolean srcIsSlot = isStackSlotValue(src); + boolean dstIsSlot = isStackSlotValue(dst); + if (isConstantValue(src)) { + return createLoad(dst, asConstant(src)); + } else if (src instanceof AArch64AddressValue) { + return new LoadAddressOp(dst, (AArch64AddressValue) src); + } else { + assert src instanceof AllocatableValue; + if (srcIsSlot && dstIsSlot) { + throw GraalError.shouldNotReachHere(src.getClass() + " " + dst.getClass()); + } else { + return new AArch64Move.Move(dst, (AllocatableValue) src); + } + } + } + + @Override + public LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) { + return new AArch64Move.Move(result, input); + } + + @Override + public LIRInstruction createLoad(AllocatableValue dst, Constant src) { + if (src instanceof JavaConstant) { + JavaConstant javaConstant = (JavaConstant) src; + if (canInlineConstant(javaConstant)) { + return new AArch64Move.LoadInlineConstant(javaConstant, dst); + } else { + // return new AArch64Move.LoadConstantFromTable(javaConstant, + // constantTableBaseProvider.getConstantTableBase(), dst); + return new AArch64Move.LoadInlineConstant(javaConstant, dst); + } + } else if (src instanceof DataPointerConstant) { + return new AArch64Move.LoadDataOp(dst, (DataPointerConstant) src); + } else { + // throw GraalError.shouldNotReachHere(src.getClass().toString()); + throw GraalError.unimplemented(); + } + } + + @Override + public boolean canInlineConstant(JavaConstant c) { + switch (c.getJavaKind()) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + return AArch64MacroAssembler.isMovableImmediate(c.asInt()); + case Long: + return AArch64MacroAssembler.isMovableImmediate(c.asLong()); + case Object: + return c.isNull(); + default: + return false; + } + } + + @Override + public boolean allowConstantToStackMove(Constant value) { + return false; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeLIRBuilder.java 2016-12-07 13:47:45.923894388 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, 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.core.aarch64; + +import org.graalvm.compiler.core.gen.NodeLIRBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; + +/** + * This class implements the AArch64 specific portion of the LIR generator. + */ +public abstract class AArch64NodeLIRBuilder extends NodeLIRBuilder { + + public AArch64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, AArch64NodeMatchRules nodeMatchRules) { + super(graph, lirGen, nodeMatchRules); + } + + @Override + protected boolean peephole(ValueNode valueNode) { + // No peephole optimizations for now + return false; + } + + @Override + public AArch64LIRGenerator getLIRGeneratorTool() { + return (AArch64LIRGenerator) super.getLIRGeneratorTool(); + } + + @Override + protected void emitPrologue(StructuredGraph graph) { + // XXX Maybe we need something like this. + // getLIRGeneratorTool().emitLoadConstantTableBase(); + super.emitPrologue(graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java 2016-12-07 13:47:46.188906033 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 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.core.aarch64; + +import org.graalvm.compiler.core.gen.NodeMatchRules; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.DeoptimizingNode; +import org.graalvm.compiler.nodes.memory.Access; + +import jdk.vm.ci.aarch64.AArch64Kind; + +public class AArch64NodeMatchRules extends NodeMatchRules { + + public AArch64NodeMatchRules(LIRGeneratorTool gen) { + super(gen); + } + + protected LIRFrameState getState(Access access) { + if (access instanceof DeoptimizingNode) { + return state((DeoptimizingNode) access); + } + return null; + } + + protected AArch64Kind getMemoryKind(Access access) { + return (AArch64Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind(); + } + + @Override + public AArch64LIRGenerator getLIRGeneratorTool() { + return (AArch64LIRGenerator) gen; + } + + protected AArch64ArithmeticLIRGenerator getArithmeticLIRGenerator() { + return (AArch64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesProvider.java 2016-12-07 13:47:46.451917589 -0800 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, 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.core.aarch64; + +import org.graalvm.compiler.java.DefaultSuitesProvider; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; + +public class AArch64SuitesProvider extends DefaultSuitesProvider { + + public AArch64SuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) { + super(compilerConfiguration, plugins); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/AMD64AllocatorTest.java 2016-12-07 13:47:46.716929234 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.amd64.test; + +import static org.graalvm.compiler.core.common.GraalOptions.TraceRA; +import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure; +import static org.junit.Assume.assumeTrue; +import jdk.vm.ci.amd64.AMD64; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.core.test.backend.AllocatorTest; + +public class AMD64AllocatorTest extends AllocatorTest { + + @Before + public void checkAMD64() { + assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue() == null); + assumeTrue("TraceRA is set -> skip", !TraceRA.getValue()); + } + + @Test + public void test1() { + testAllocation("test1snippet", 3, 1, 0); + } + + public static long test1snippet(long x) { + return x + 5; + } + + @Test + public void test2() { + testAllocation("test2snippet", 3, 0, 0); + } + + public static long test2snippet(long x) { + return x * 5; + } + + @Ignore + @Test + public void test3() { + testAllocation("test3snippet", 4, 1, 0); + } + + public static long test3snippet(long x) { + return x / 3 + x % 3; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/ConstantStackMoveTest.java 2016-12-07 13:47:46.980940834 -0800 @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2015, 2015, 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.core.amd64.test; + +import static org.junit.Assume.assumeTrue; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.jtt.LIRTest; +import org.graalvm.compiler.lir.jtt.LIRTestSpecification; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.PrimitiveConstant; + +public class ConstantStackMoveTest extends LIRTest { + @Before + public void checkAMD64() { + assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + } + + private static class LoadConstantStackSpec extends LIRTestSpecification { + protected final Object primitive; + + LoadConstantStackSpec(Object primitive) { + this.primitive = primitive; + } + + @Override + public void generate(LIRGeneratorTool gen) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + // create slots + PrimitiveConstant constantValue = JavaConstant.forBoxedPrimitive(primitive); + VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(LIRKind.fromJavaKind(gen.target().arch, constantValue.getJavaKind())); + // move stuff around + gen.emitMoveConstant(s1, constantValue); + gen.emitBlackhole(s1); + setResult(gen.emitMove(s1)); + } + } + + private static final class LoadConstantStackSpecByte extends LoadConstantStackSpec { + LoadConstantStackSpecByte(byte primitive) { + super(primitive); + } + + byte get() { + return (Byte) primitive; + } + } + + private static final class LoadConstantStackSpecShort extends LoadConstantStackSpec { + LoadConstantStackSpecShort(short primitive) { + super(primitive); + } + + short get() { + return (Short) primitive; + } + } + + private static final class LoadConstantStackSpecInteger extends LoadConstantStackSpec { + LoadConstantStackSpecInteger(int primitive) { + super(primitive); + } + + int get() { + return (Integer) primitive; + } + } + + private static final class LoadConstantStackSpecLong extends LoadConstantStackSpec { + LoadConstantStackSpecLong(long primitive) { + super(primitive); + } + + long get() { + return (Long) primitive; + } + } + + private static final class LoadConstantStackSpecFloat extends LoadConstantStackSpec { + LoadConstantStackSpecFloat(float primitive) { + super(primitive); + } + + float get() { + return (Float) primitive; + } + } + + private static final class LoadConstantStackSpecDouble extends LoadConstantStackSpec { + LoadConstantStackSpecDouble(double primitive) { + super(primitive); + } + + double get() { + return (Double) primitive; + } + } + + private static final LoadConstantStackSpecByte stackCopyByte = new LoadConstantStackSpecByte(Byte.MAX_VALUE); + private static final LoadConstantStackSpecShort stackCopyShort = new LoadConstantStackSpecShort(Short.MAX_VALUE); + private static final LoadConstantStackSpecInteger stackCopyInt = new LoadConstantStackSpecInteger(Integer.MAX_VALUE); + private static final LoadConstantStackSpecLong stackCopyLong = new LoadConstantStackSpecLong(Long.MAX_VALUE); + private static final LoadConstantStackSpecFloat stackCopyFloat = new LoadConstantStackSpecFloat(Float.MAX_VALUE); + private static final LoadConstantStackSpecDouble stackCopyDouble = new LoadConstantStackSpecDouble(Double.MAX_VALUE); + + @LIRIntrinsic + public static byte testCopyByte(LoadConstantStackSpecByte spec) { + return spec.get(); + } + + public byte testByte() { + return testCopyByte(stackCopyByte); + } + + @Test + public void runByte() throws Throwable { + runTest("testByte"); + } + + @LIRIntrinsic + public static short testCopyShort(LoadConstantStackSpecShort spec) { + return spec.get(); + } + + public short testShort() { + return testCopyShort(stackCopyShort); + } + + @Test + public void runShort() throws Throwable { + runTest("testShort"); + } + + @LIRIntrinsic + public static int testCopyInt(LoadConstantStackSpecInteger spec) { + return spec.get(); + } + + public int testInt() { + return testCopyInt(stackCopyInt); + } + + @Test + public void runInt() throws Throwable { + runTest("testInt"); + } + + @LIRIntrinsic + public static long testCopyLong(LoadConstantStackSpecLong spec) { + return spec.get(); + } + + public long testLong() { + return testCopyLong(stackCopyLong); + } + + @Test + public void runLong() throws Throwable { + runTest("testLong"); + } + + @LIRIntrinsic + public static float testCopyFloat(LoadConstantStackSpecFloat spec) { + return spec.get(); + } + + public float testFloat() { + return testCopyFloat(stackCopyFloat); + } + + @Test + public void runFloat() throws Throwable { + runTest("testFloat"); + } + + @LIRIntrinsic + public static double testCopyDouble(LoadConstantStackSpecDouble spec) { + return spec.get(); + } + + public double testDouble() { + return testCopyDouble(stackCopyDouble); + } + + @Test + public void runDouble() throws Throwable { + runTest("testDouble"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/MatchRuleTest.java 2016-12-07 13:47:47.243952390 -0800 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, 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.core.amd64.test; + +import static org.junit.Assume.assumeTrue; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer.MemoryConstOp; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.jtt.LIRTest; +import org.graalvm.compiler.lir.phases.LIRPhase; +import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.TargetDescription; + +public class MatchRuleTest extends LIRTest { + private static LIR lir; + + @Before + public void checkAMD64() { + assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + } + + public static int test1Snippet(TestClass o, TestClass b, TestClass c) { + if (o.x == 42) { + return b.z; + } else { + return c.y; + } + } + + /** + * Verifies, if the match rules in AMD64NodeMatchRules do work on the graphs by compiling and + * checking if the expected LIR instruction show up. + */ + @Test + public void test1() { + getLIRSuites().getPreAllocationOptimizationStage().appendPhase(new CheckPhase()); + compile(getResolvedJavaMethod("test1Snippet"), null); + boolean found = false; + for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) { + if (ins instanceof MemoryConstOp && ((MemoryConstOp) ins).getOpcode().toString().equals("CMP")) { + assertFalse("MemoryConstOp expected only once in first block", found); + found = true; + } + } + assertTrue("Memory compare must be in the LIR", found); + } + + public static class TestClass { + public int x; + public int y; + public int z; + + public TestClass(int x) { + super(); + this.x = x; + } + } + + public static class CheckPhase extends LIRPhase { + @Override + protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) { + lir = lirGenRes.getLIR(); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/StackStoreTest.java 2016-12-07 13:47:47.509964080 -0800 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015, 2015, 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.core.amd64.test; + +import static org.junit.Assume.assumeTrue; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.jtt.LIRTest; +import org.graalvm.compiler.lir.jtt.LIRTestSpecification; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.Value; + +public class StackStoreTest extends LIRTest { + @Before + public void checkAMD64() { + assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + } + + private static final LIRTestSpecification stackCopy0 = new LIRTestSpecification() { + @Override + public void generate(LIRGeneratorTool gen, Value a) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + // create slots + VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(a.getValueKind()); + VirtualStackSlot s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(AMD64Kind.WORD)); + // move stuff around + gen.emitMove(s1, a); + gen.emitMoveConstant(s2, JavaConstant.forShort(Short.MIN_VALUE)); + setResult(gen.emitMove(s1)); + gen.emitBlackhole(s1); + gen.emitBlackhole(s2); + } + }; + + private static final LIRTestSpecification stackCopy1 = new LIRTestSpecification() { + @Override + public void generate(LIRGeneratorTool gen, Value a) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + // create slots + VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(a.getValueKind()); + VirtualStackSlot s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(AMD64Kind.WORD)); + // move stuff around + gen.emitMove(s1, a); + Value v = gen.emitLoadConstant(LIRKind.value(AMD64Kind.WORD), JavaConstant.forShort(Short.MIN_VALUE)); + gen.emitMove(s2, v); + setResult(gen.emitMove(s1)); + gen.emitBlackhole(s1); + gen.emitBlackhole(s2); + } + }; + + private static final LIRTestSpecification stackCopy2 = new LIRTestSpecification() { + @Override + public void generate(LIRGeneratorTool gen, Value a) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + // create slots + VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(a.getValueKind()); + VirtualStackSlot s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(AMD64Kind.WORD)); + // move stuff around + gen.emitMoveConstant(s2, JavaConstant.forShort(Short.MIN_VALUE)); + gen.emitMove(s1, a); + setResult(gen.emitMove(s2)); + gen.emitBlackhole(s1); + gen.emitBlackhole(s2); + } + }; + + @SuppressWarnings("unused") + @LIRIntrinsic + public static int testShortStackSlot(LIRTestSpecification spec, int a) { + return a; + } + + @SuppressWarnings("unused") + @LIRIntrinsic + public static short testShortStackSlot2(LIRTestSpecification spec, int a) { + return Short.MIN_VALUE; + } + + public int test0(int a) { + return testShortStackSlot(stackCopy0, a); + } + + @Test + public void run0() throws Throwable { + runTest("test0", 0xDEADDEAD); + } + + public int test1(int a) { + return testShortStackSlot(stackCopy1, a); + } + + @Test + public void run1() throws Throwable { + runTest("test1", 0xDEADDEAD); + } + + public int test2(int a) { + return testShortStackSlot2(stackCopy2, a); + } + + @Test + public void run2() throws Throwable { + runTest("test2", 0xDEADDEAD); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressLowering.java 2016-12-07 13:47:47.774975723 -0800 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2015, 2016, 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.core.amd64; + +import jdk.vm.ci.meta.JavaConstant; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.LeftShiftNode; +import org.graalvm.compiler.nodes.calc.ZeroExtendNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering; + +public class AMD64AddressLowering extends AddressLowering { + + @Override + public AddressNode lower(ValueNode address) { + return lower(address, null); + } + + @Override + public AddressNode lower(ValueNode base, ValueNode offset) { + AMD64AddressNode ret = new AMD64AddressNode(base, offset); + boolean changed; + do { + changed = improve(ret); + } while (changed); + return base.graph().unique(ret); + } + + protected boolean improve(AMD64AddressNode ret) { + ValueNode newBase = improveInput(ret, ret.getBase(), 0); + if (newBase != ret.getBase()) { + ret.setBase(newBase); + return true; + } + + ValueNode newIdx = improveInput(ret, ret.getIndex(), ret.getScale().log2); + if (newIdx != ret.getIndex()) { + ret.setIndex(newIdx); + return true; + } + + if (ret.getIndex() instanceof LeftShiftNode) { + LeftShiftNode shift = (LeftShiftNode) ret.getIndex(); + if (shift.getY().isConstant()) { + int amount = ret.getScale().log2 + shift.getY().asJavaConstant().asInt(); + Scale scale = Scale.fromShift(amount); + if (scale != null) { + ret.setIndex(shift.getX()); + ret.setScale(scale); + return true; + } + } + } + + if (ret.getScale() == Scale.Times1) { + if (ret.getBase() == null || ret.getIndex() == null) { + if (ret.getBase() instanceof AddNode) { + AddNode add = (AddNode) ret.getBase(); + ret.setBase(add.getX()); + ret.setIndex(add.getY()); + return true; + } else if (ret.getIndex() instanceof AddNode) { + AddNode add = (AddNode) ret.getIndex(); + ret.setBase(add.getX()); + ret.setIndex(add.getY()); + return true; + } + } + + if (ret.getBase() instanceof LeftShiftNode && !(ret.getIndex() instanceof LeftShiftNode)) { + ValueNode tmp = ret.getBase(); + ret.setBase(ret.getIndex()); + ret.setIndex(tmp); + return true; + } + } + + return false; + } + + private static ValueNode improveInput(AMD64AddressNode address, ValueNode node, int shift) { + if (node == null) { + return null; + } + + JavaConstant c = node.asJavaConstant(); + if (c != null) { + return improveConstDisp(address, node, c, null, shift); + } else { + if (node.stamp() instanceof IntegerStamp && ((IntegerStamp) node.stamp()).getBits() == 64) { + if (node instanceof ZeroExtendNode) { + if (((ZeroExtendNode) node).getInputBits() == 32) { + /* + * We can just swallow a zero-extend from 32 bit to 64 bit because the upper + * half of the register will always be zero. + */ + return ((ZeroExtendNode) node).getValue(); + } + } else if (node instanceof AddNode) { + AddNode add = (AddNode) node; + if (add.getX().isConstant()) { + return improveConstDisp(address, node, add.getX().asJavaConstant(), add.getY(), shift); + } else if (add.getY().isConstant()) { + return improveConstDisp(address, node, add.getY().asJavaConstant(), add.getX(), shift); + } + } + } + } + + return node; + } + + private static ValueNode improveConstDisp(AMD64AddressNode address, ValueNode original, JavaConstant c, ValueNode other, int shift) { + if (c.getJavaKind().isNumericInteger()) { + long disp = address.getDisplacement(); + disp += c.asLong() << shift; + if (NumUtil.isInt(disp)) { + address.setDisplacement((int) disp); + return other; + } + } + return original; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java 2016-12-07 13:47:48.039987368 -0800 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015, 2015, 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.core.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.lir.amd64.AMD64AddressValue; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; + +/** + * Represents an address of the form [base + index*scale + displacement]. Both base and index are + * optional. + */ +@NodeInfo +public class AMD64AddressNode extends AddressNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(AMD64AddressNode.class); + + @OptionalInput private ValueNode base; + + @OptionalInput private ValueNode index; + private Scale scale; + + private int displacement; + + public AMD64AddressNode(ValueNode base) { + this(base, null); + } + + public AMD64AddressNode(ValueNode base, ValueNode index) { + super(TYPE); + this.base = base; + this.index = index; + this.scale = Scale.Times1; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + LIRGeneratorTool tool = gen.getLIRGeneratorTool(); + + AllocatableValue baseValue = base == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(base)); + AllocatableValue indexValue = index == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(index)); + + AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue); + AllocatableValue indexReference; + if (scale.equals(Scale.Times1)) { + indexReference = LIRKind.derivedBaseFromValue(indexValue); + } else { + if (LIRKind.isValue(indexValue)) { + indexReference = null; + } else { + indexReference = Value.ILLEGAL; + } + } + + LIRKind kind = LIRKind.combineDerived(tool.getLIRKind(stamp()), baseReference, indexReference); + gen.setResult(this, new AMD64AddressValue(kind, baseValue, indexValue, scale, displacement)); + } + + public ValueNode getBase() { + return base; + } + + public void setBase(ValueNode base) { + // allow modification before inserting into the graph + if (isAlive()) { + updateUsages(this.base, base); + } + this.base = base; + } + + public ValueNode getIndex() { + return index; + } + + public void setIndex(ValueNode index) { + // allow modification before inserting into the graph + if (isAlive()) { + updateUsages(this.index, index); + } + this.index = index; + } + + public Scale getScale() { + return scale; + } + + public void setScale(Scale scale) { + this.scale = scale; + } + + public int getDisplacement() { + return displacement; + } + + public void setDisplacement(int displacement) { + this.displacement = displacement; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java 2016-12-07 13:47:48.303998969 -0800 @@ -0,0 +1,1271 @@ +/* + * Copyright (c) 2009, 2016, 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.core.amd64; + +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.OR; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SUB; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.NEG; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.NOT; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.BSF; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.BSR; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.LZCNT; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOV; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSS; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSX; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXB; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVZX; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVZXB; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.POPCNT; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TEST; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TESTB; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TZCNT; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.ROL; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.ROR; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.SAR; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.SHL; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.SHR; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.BYTE; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PS; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SS; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue; +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.DREM; +import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.FREM; +import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.COS; +import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG; +import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG10; +import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.SIN; +import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.TAN; +import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.EXP; +import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp.BinaryIntrinsicOpcode.POW; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MROp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.FloatConvert; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.ConstantValue; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRValueUtil; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.amd64.AMD64AddressValue; +import org.graalvm.compiler.lir.amd64.AMD64Arithmetic.FPDivRemOp; +import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool; +import org.graalvm.compiler.lir.amd64.AMD64Binary; +import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer; +import org.graalvm.compiler.lir.amd64.AMD64ClearRegisterOp; +import org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp; +import org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp; +import org.graalvm.compiler.lir.amd64.AMD64MulDivOp; +import org.graalvm.compiler.lir.amd64.AMD64ShiftOp; +import org.graalvm.compiler.lir.amd64.AMD64SignExtendOp; +import org.graalvm.compiler.lir.amd64.AMD64Unary; +import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.VMConstant; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; +import jdk.vm.ci.code.TargetDescription; + +/** + * This class implements the AMD64 specific portion of the LIR generator. + */ +public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implements AMD64ArithmeticLIRGeneratorTool { + + private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(AMD64Kind.DWORD)); + + @Override + public Variable emitNegate(Value inputVal) { + AllocatableValue input = getLIRGen().asAllocatable(inputVal); + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + TargetDescription target = getLIRGen().target(); + boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX); + switch ((AMD64Kind) input.getPlatformKind()) { + case DWORD: + getLIRGen().append(new AMD64Unary.MOp(NEG, DWORD, result, input)); + break; + case QWORD: + getLIRGen().append(new AMD64Unary.MOp(NEG, QWORD, result, input)); + break; + case SINGLE: + if (isAvx) { + getLIRGen().append(new AMD64Binary.DataThreeOp(AVXOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16)); + } else { + getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16)); + } + break; + case DOUBLE: + if (isAvx) { + getLIRGen().append(new AMD64Binary.DataThreeOp(AVXOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16)); + } else { + getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16)); + } + break; + default: + throw GraalError.shouldNotReachHere(); + } + return result; + } + + @Override + public Variable emitNot(Value inputVal) { + AllocatableValue input = getLIRGen().asAllocatable(inputVal); + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + switch ((AMD64Kind) input.getPlatformKind()) { + case DWORD: + getLIRGen().append(new AMD64Unary.MOp(NOT, DWORD, result, input)); + break; + case QWORD: + getLIRGen().append(new AMD64Unary.MOp(NOT, QWORD, result, input)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + return result; + } + + private Variable emitBinary(LIRKind resultKind, AMD64BinaryArithmetic op, OperandSize size, boolean commutative, Value a, Value b, boolean setFlags) { + if (isJavaConstant(b)) { + return emitBinaryConst(resultKind, op, size, commutative, getLIRGen().asAllocatable(a), asConstantValue(b), setFlags); + } else if (commutative && isJavaConstant(a)) { + return emitBinaryConst(resultKind, op, size, commutative, getLIRGen().asAllocatable(b), asConstantValue(a), setFlags); + } else { + return emitBinaryVar(resultKind, op.getRMOpcode(size), size, commutative, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b)); + } + } + + private Variable emitBinary(LIRKind resultKind, AMD64RMOp op, OperandSize size, boolean commutative, Value a, Value b) { + if (isJavaConstant(b)) { + return emitBinaryConst(resultKind, op, size, getLIRGen().asAllocatable(a), asJavaConstant(b)); + } else if (commutative && isJavaConstant(a)) { + return emitBinaryConst(resultKind, op, size, getLIRGen().asAllocatable(b), asJavaConstant(a)); + } else { + return emitBinaryVar(resultKind, op, size, commutative, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b)); + } + } + + private Variable emitBinary(LIRKind resultKind, AMD64RRMOp op, OperandSize size, boolean commutative, Value a, Value b) { + if (isJavaConstant(b)) { + return emitBinaryConst(resultKind, op, size, getLIRGen().asAllocatable(a), asJavaConstant(b)); + } else if (commutative && isJavaConstant(a)) { + return emitBinaryConst(resultKind, op, size, getLIRGen().asAllocatable(b), asJavaConstant(a)); + } else { + return emitBinaryVar(resultKind, op, size, commutative, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b)); + } + } + + private Variable emitBinaryConst(LIRKind resultKind, AMD64BinaryArithmetic op, OperandSize size, boolean commutative, AllocatableValue a, ConstantValue b, boolean setFlags) { + long value = b.getJavaConstant().asLong(); + if (NumUtil.isInt(value)) { + Variable result = getLIRGen().newVariable(resultKind); + int constant = (int) value; + + if (!setFlags) { + AMD64MOp mop = getMOp(op, constant); + if (mop != null) { + getLIRGen().append(new AMD64Unary.MOp(mop, size, result, a)); + return result; + } + } + + getLIRGen().append(new AMD64Binary.ConstOp(op, size, result, a, constant)); + return result; + } else { + return emitBinaryVar(resultKind, op.getRMOpcode(size), size, commutative, a, getLIRGen().asAllocatable(b)); + } + } + + private static AMD64MOp getMOp(AMD64BinaryArithmetic op, int constant) { + if (constant == 1) { + if (op.equals(AMD64BinaryArithmetic.ADD)) { + return AMD64MOp.INC; + } + if (op.equals(AMD64BinaryArithmetic.SUB)) { + return AMD64MOp.DEC; + } + } else if (constant == -1) { + if (op.equals(AMD64BinaryArithmetic.ADD)) { + return AMD64MOp.DEC; + } + if (op.equals(AMD64BinaryArithmetic.SUB)) { + return AMD64MOp.INC; + } + } + return null; + } + + private Variable emitBinaryConst(LIRKind resultKind, AMD64RMOp op, OperandSize size, AllocatableValue a, JavaConstant b) { + Variable result = getLIRGen().newVariable(resultKind); + getLIRGen().append(new AMD64Binary.DataTwoOp(op, size, result, a, b)); + return result; + } + + private Variable emitBinaryConst(LIRKind resultKind, AMD64RRMOp op, OperandSize size, AllocatableValue a, JavaConstant b) { + Variable result = getLIRGen().newVariable(resultKind); + getLIRGen().append(new AMD64Binary.DataThreeOp(op, size, result, a, b)); + return result; + } + + private Variable emitBinaryVar(LIRKind resultKind, AMD64RMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) { + Variable result = getLIRGen().newVariable(resultKind); + if (commutative) { + getLIRGen().append(new AMD64Binary.CommutativeTwoOp(op, size, result, a, b)); + } else { + getLIRGen().append(new AMD64Binary.TwoOp(op, size, result, a, b)); + } + return result; + } + + private Variable emitBinaryVar(LIRKind resultKind, AMD64RRMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) { + Variable result = getLIRGen().newVariable(resultKind); + if (commutative) { + getLIRGen().append(new AMD64Binary.CommutativeThreeOp(op, size, result, a, b)); + } else { + getLIRGen().append(new AMD64Binary.ThreeOp(op, size, result, a, b)); + } + return result; + } + + @Override + protected boolean isNumericInteger(PlatformKind kind) { + return ((AMD64Kind) kind).isInteger(); + } + + @Override + public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) { + TargetDescription target = getLIRGen().target(); + boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX); + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitBinary(resultKind, ADD, DWORD, true, a, b, setFlags); + case QWORD: + return emitBinary(resultKind, ADD, QWORD, true, a, b, setFlags); + case SINGLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.ADD, SS, true, a, b); + } else { + return emitBinary(resultKind, SSEOp.ADD, SS, true, a, b); + } + case DOUBLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.ADD, SD, true, a, b); + } else { + return emitBinary(resultKind, SSEOp.ADD, SD, true, a, b); + } + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) { + TargetDescription target = getLIRGen().target(); + boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX); + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitBinary(resultKind, SUB, DWORD, false, a, b, setFlags); + case QWORD: + return emitBinary(resultKind, SUB, QWORD, false, a, b, setFlags); + case SINGLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.SUB, SS, false, a, b); + } else { + return emitBinary(resultKind, SSEOp.SUB, SS, false, a, b); + } + case DOUBLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.SUB, SD, false, a, b); + } else { + return emitBinary(resultKind, SSEOp.SUB, SD, false, a, b); + } + default: + throw GraalError.shouldNotReachHere(); + } + } + + private Variable emitIMULConst(OperandSize size, AllocatableValue a, ConstantValue b) { + long value = b.getJavaConstant().asLong(); + if (NumUtil.isInt(value)) { + int imm = (int) value; + AMD64RMIOp op; + if (NumUtil.isByte(imm)) { + op = AMD64RMIOp.IMUL_SX; + } else { + op = AMD64RMIOp.IMUL; + } + + Variable ret = getLIRGen().newVariable(LIRKind.combine(a, b)); + getLIRGen().append(new AMD64Binary.RMIOp(op, size, ret, a, imm)); + return ret; + } else { + return emitBinaryVar(LIRKind.combine(a, b), AMD64RMOp.IMUL, size, true, a, getLIRGen().asAllocatable(b)); + } + } + + private Variable emitIMUL(OperandSize size, Value a, Value b) { + if (isJavaConstant(b)) { + return emitIMULConst(size, getLIRGen().asAllocatable(a), asConstantValue(b)); + } else if (isJavaConstant(a)) { + return emitIMULConst(size, getLIRGen().asAllocatable(b), asConstantValue(a)); + } else { + return emitBinaryVar(LIRKind.combine(a, b), AMD64RMOp.IMUL, size, true, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b)); + } + } + + @Override + public Variable emitMul(Value a, Value b, boolean setFlags) { + LIRKind resultKind = LIRKind.combine(a, b); + TargetDescription target = getLIRGen().target(); + boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX); + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitIMUL(DWORD, a, b); + case QWORD: + return emitIMUL(QWORD, a, b); + case SINGLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.MUL, SS, true, a, b); + } else { + return emitBinary(resultKind, SSEOp.MUL, SS, true, a, b); + } + case DOUBLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.MUL, SD, true, a, b); + } else { + return emitBinary(resultKind, SSEOp.MUL, SD, true, a, b); + } + default: + throw GraalError.shouldNotReachHere(); + } + } + + private RegisterValue moveToReg(Register reg, Value v) { + RegisterValue ret = reg.asValue(v.getValueKind()); + getLIRGen().emitMove(ret, v); + return ret; + } + + private Value emitMulHigh(AMD64MOp opcode, OperandSize size, Value a, Value b) { + AMD64MulDivOp mulHigh = getLIRGen().append(new AMD64MulDivOp(opcode, size, LIRKind.combine(a, b), moveToReg(AMD64.rax, a), getLIRGen().asAllocatable(b))); + return getLIRGen().emitMove(mulHigh.getHighResult()); + } + + @Override + public Value emitMulHigh(Value a, Value b) { + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitMulHigh(AMD64MOp.IMUL, DWORD, a, b); + case QWORD: + return emitMulHigh(AMD64MOp.IMUL, QWORD, a, b); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Value emitUMulHigh(Value a, Value b) { + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitMulHigh(AMD64MOp.MUL, DWORD, a, b); + case QWORD: + return emitMulHigh(AMD64MOp.MUL, QWORD, a, b); + default: + throw GraalError.shouldNotReachHere(); + } + } + + public Value emitBinaryMemory(AMD64RMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) { + Variable result = getLIRGen().newVariable(LIRKind.combine(a)); + getLIRGen().append(new AMD64Binary.MemoryTwoOp(op, size, result, a, location, state)); + return result; + } + + public Value emitBinaryMemory(AMD64RRMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) { + Variable result = getLIRGen().newVariable(LIRKind.combine(a)); + getLIRGen().append(new AMD64Binary.MemoryThreeOp(op, size, result, a, location, state)); + return result; + } + + protected Value emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, AMD64AddressValue address, LIRFrameState state) { + Variable result = getLIRGen().newVariable(LIRKind.value(kind)); + getLIRGen().append(new AMD64Unary.MemoryOp(op, size, result, address, state)); + return result; + } + + protected Value emitZeroExtendMemory(AMD64Kind memoryKind, int resultBits, AMD64AddressValue address, LIRFrameState state) { + // Issue a zero extending load of the proper bit size and set the result to + // the proper kind. + Variable result = getLIRGen().newVariable(LIRKind.value(resultBits == 32 ? AMD64Kind.DWORD : AMD64Kind.QWORD)); + switch (memoryKind) { + case BYTE: + getLIRGen().append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, address, state)); + break; + case WORD: + getLIRGen().append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, address, state)); + break; + case DWORD: + getLIRGen().append(new AMD64Unary.MemoryOp(MOV, DWORD, result, address, state)); + break; + case QWORD: + getLIRGen().append(new AMD64Unary.MemoryOp(MOV, QWORD, result, address, state)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + return result; + } + + private AMD64MulDivOp emitIDIV(OperandSize size, Value a, Value b, LIRFrameState state) { + LIRKind kind = LIRKind.combine(a, b); + + AMD64SignExtendOp sx = getLIRGen().append(new AMD64SignExtendOp(size, kind, moveToReg(AMD64.rax, a))); + return getLIRGen().append(new AMD64MulDivOp(AMD64MOp.IDIV, size, kind, sx.getHighResult(), sx.getLowResult(), getLIRGen().asAllocatable(b), state)); + } + + private AMD64MulDivOp emitDIV(OperandSize size, Value a, Value b, LIRFrameState state) { + LIRKind kind = LIRKind.combine(a, b); + + RegisterValue rax = moveToReg(AMD64.rax, a); + RegisterValue rdx = AMD64.rdx.asValue(kind); + getLIRGen().append(new AMD64ClearRegisterOp(size, rdx)); + return getLIRGen().append(new AMD64MulDivOp(AMD64MOp.DIV, size, kind, rdx, rax, getLIRGen().asAllocatable(b), state)); + } + + public Value[] emitSignedDivRem(Value a, Value b, LIRFrameState state) { + AMD64MulDivOp op; + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + op = emitIDIV(DWORD, a, b, state); + break; + case QWORD: + op = emitIDIV(QWORD, a, b, state); + break; + default: + throw GraalError.shouldNotReachHere(); + } + return new Value[]{getLIRGen().emitMove(op.getQuotient()), getLIRGen().emitMove(op.getRemainder())}; + } + + public Value[] emitUnsignedDivRem(Value a, Value b, LIRFrameState state) { + AMD64MulDivOp op; + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + op = emitDIV(DWORD, a, b, state); + break; + case QWORD: + op = emitDIV(QWORD, a, b, state); + break; + default: + throw GraalError.shouldNotReachHere(); + } + return new Value[]{getLIRGen().emitMove(op.getQuotient()), getLIRGen().emitMove(op.getRemainder())}; + } + + @Override + public Value emitDiv(Value a, Value b, LIRFrameState state) { + TargetDescription target = getLIRGen().target(); + boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX); + LIRKind resultKind = LIRKind.combine(a, b); + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + AMD64MulDivOp op = emitIDIV(DWORD, a, b, state); + return getLIRGen().emitMove(op.getQuotient()); + case QWORD: + AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state); + return getLIRGen().emitMove(lop.getQuotient()); + case SINGLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.DIV, SS, false, a, b); + } else { + return emitBinary(resultKind, SSEOp.DIV, SS, false, a, b); + } + case DOUBLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.DIV, SD, false, a, b); + } else { + return emitBinary(resultKind, SSEOp.DIV, SD, false, a, b); + } + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Value emitRem(Value a, Value b, LIRFrameState state) { + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + AMD64MulDivOp op = emitIDIV(DWORD, a, b, state); + return getLIRGen().emitMove(op.getRemainder()); + case QWORD: + AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state); + return getLIRGen().emitMove(lop.getRemainder()); + case SINGLE: { + Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); + getLIRGen().append(new FPDivRemOp(FREM, result, getLIRGen().load(a), getLIRGen().load(b))); + return result; + } + case DOUBLE: { + Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); + getLIRGen().append(new FPDivRemOp(DREM, result, getLIRGen().load(a), getLIRGen().load(b))); + return result; + } + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Variable emitUDiv(Value a, Value b, LIRFrameState state) { + AMD64MulDivOp op; + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + op = emitDIV(DWORD, a, b, state); + break; + case QWORD: + op = emitDIV(QWORD, a, b, state); + break; + default: + throw GraalError.shouldNotReachHere(); + } + return getLIRGen().emitMove(op.getQuotient()); + } + + @Override + public Variable emitURem(Value a, Value b, LIRFrameState state) { + AMD64MulDivOp op; + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + op = emitDIV(DWORD, a, b, state); + break; + case QWORD: + op = emitDIV(QWORD, a, b, state); + break; + default: + throw GraalError.shouldNotReachHere(); + } + return getLIRGen().emitMove(op.getRemainder()); + } + + @Override + public Variable emitAnd(Value a, Value b) { + LIRKind resultKind = LIRKind.combine(a, b); + TargetDescription target = getLIRGen().target(); + boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX); + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitBinary(resultKind, AND, DWORD, true, a, b, false); + case QWORD: + return emitBinary(resultKind, AND, QWORD, true, a, b, false); + case SINGLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.AND, PS, true, a, b); + } else { + return emitBinary(resultKind, SSEOp.AND, PS, true, a, b); + } + case DOUBLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.AND, PD, true, a, b); + } else { + return emitBinary(resultKind, SSEOp.AND, PD, true, a, b); + } + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Variable emitOr(Value a, Value b) { + LIRKind resultKind = LIRKind.combine(a, b); + TargetDescription target = getLIRGen().target(); + boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX); + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitBinary(resultKind, OR, DWORD, true, a, b, false); + case QWORD: + return emitBinary(resultKind, OR, QWORD, true, a, b, false); + case SINGLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.OR, PS, true, a, b); + } else { + return emitBinary(resultKind, SSEOp.OR, PS, true, a, b); + } + case DOUBLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.OR, PD, true, a, b); + } else { + return emitBinary(resultKind, SSEOp.OR, PD, true, a, b); + } + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Variable emitXor(Value a, Value b) { + LIRKind resultKind = LIRKind.combine(a, b); + TargetDescription target = getLIRGen().target(); + boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX); + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitBinary(resultKind, XOR, DWORD, true, a, b, false); + case QWORD: + return emitBinary(resultKind, XOR, QWORD, true, a, b, false); + case SINGLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.XOR, PS, true, a, b); + } else { + return emitBinary(resultKind, SSEOp.XOR, PS, true, a, b); + } + case DOUBLE: + if (isAvx) { + return emitBinary(resultKind, AVXOp.XOR, PD, true, a, b); + } else { + return emitBinary(resultKind, SSEOp.XOR, PD, true, a, b); + } + default: + throw GraalError.shouldNotReachHere(); + } + } + + private Variable emitShift(AMD64Shift op, OperandSize size, Value a, Value b) { + Variable result = getLIRGen().newVariable(LIRKind.combine(a, b).changeType(a.getPlatformKind())); + AllocatableValue input = getLIRGen().asAllocatable(a); + if (isJavaConstant(b)) { + JavaConstant c = asJavaConstant(b); + if (c.asLong() == 1) { + getLIRGen().append(new AMD64Unary.MOp(op.m1Op, size, result, input)); + } else { + /* + * c is implicitly masked to 5 or 6 bits by the CPU, so casting it to (int) is + * always correct, even without the NumUtil.is32bit() test. + */ + getLIRGen().append(new AMD64Binary.ConstOp(op.miOp, size, result, input, (int) c.asLong())); + } + } else { + getLIRGen().emitMove(RCX_I, b); + getLIRGen().append(new AMD64ShiftOp(op.mcOp, size, result, input, RCX_I)); + } + return result; + } + + @Override + public Variable emitShl(Value a, Value b) { + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitShift(SHL, DWORD, a, b); + case QWORD: + return emitShift(SHL, QWORD, a, b); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Variable emitShr(Value a, Value b) { + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitShift(SAR, DWORD, a, b); + case QWORD: + return emitShift(SAR, QWORD, a, b); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Variable emitUShr(Value a, Value b) { + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitShift(SHR, DWORD, a, b); + case QWORD: + return emitShift(SHR, QWORD, a, b); + default: + throw GraalError.shouldNotReachHere(); + } + } + + public Variable emitRol(Value a, Value b) { + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitShift(ROL, DWORD, a, b); + case QWORD: + return emitShift(ROL, QWORD, a, b); + default: + throw GraalError.shouldNotReachHere(); + } + } + + public Variable emitRor(Value a, Value b) { + switch ((AMD64Kind) a.getPlatformKind()) { + case DWORD: + return emitShift(ROR, DWORD, a, b); + case QWORD: + return emitShift(ROR, QWORD, a, b); + default: + throw GraalError.shouldNotReachHere(); + } + } + + private AllocatableValue emitConvertOp(LIRKind kind, AMD64RMOp op, OperandSize size, Value input) { + Variable result = getLIRGen().newVariable(kind); + getLIRGen().append(new AMD64Unary.RMOp(op, size, result, getLIRGen().asAllocatable(input))); + return result; + } + + private AllocatableValue emitConvertOp(LIRKind kind, AMD64MROp op, OperandSize size, Value input) { + Variable result = getLIRGen().newVariable(kind); + getLIRGen().append(new AMD64Unary.MROp(op, size, result, getLIRGen().asAllocatable(input))); + return result; + } + + @Override + public Value emitReinterpret(LIRKind to, Value inputVal) { + ValueKind from = inputVal.getValueKind(); + if (to.equals(from)) { + return inputVal; + } + + AllocatableValue input = getLIRGen().asAllocatable(inputVal); + /* + * Conversions between integer to floating point types require moves between CPU and FPU + * registers. + */ + AMD64Kind fromKind = (AMD64Kind) from.getPlatformKind(); + switch ((AMD64Kind) to.getPlatformKind()) { + case DWORD: + switch (fromKind) { + case SINGLE: + return emitConvertOp(to, AMD64MROp.MOVD, DWORD, input); + } + break; + case QWORD: + switch (fromKind) { + case DOUBLE: + return emitConvertOp(to, AMD64MROp.MOVQ, QWORD, input); + } + break; + case SINGLE: + switch (fromKind) { + case DWORD: + return emitConvertOp(to, AMD64RMOp.MOVD, DWORD, input); + } + break; + case DOUBLE: + switch (fromKind) { + case QWORD: + return emitConvertOp(to, AMD64RMOp.MOVQ, QWORD, input); + } + break; + } + throw GraalError.shouldNotReachHere(); + } + + @Override + public Value emitFloatConvert(FloatConvert op, Value input) { + switch (op) { + case D2F: + return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.SINGLE), SSEOp.CVTSD2SS, SD, input); + case D2I: + return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DWORD), SSEOp.CVTTSD2SI, DWORD, input); + case D2L: + return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.QWORD), SSEOp.CVTTSD2SI, QWORD, input); + case F2D: + return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DOUBLE), SSEOp.CVTSS2SD, SS, input); + case F2I: + return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DWORD), SSEOp.CVTTSS2SI, DWORD, input); + case F2L: + return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.QWORD), SSEOp.CVTTSS2SI, QWORD, input); + case I2D: + return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DOUBLE), SSEOp.CVTSI2SD, DWORD, input); + case I2F: + return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.SINGLE), SSEOp.CVTSI2SS, DWORD, input); + case L2D: + return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DOUBLE), SSEOp.CVTSI2SD, QWORD, input); + case L2F: + return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.SINGLE), SSEOp.CVTSI2SS, QWORD, input); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Value emitNarrow(Value inputVal, int bits) { + if (inputVal.getPlatformKind() == AMD64Kind.QWORD && bits <= 32) { + // TODO make it possible to reinterpret Long as Int in LIR without move + return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.DWORD), AMD64RMOp.MOV, DWORD, inputVal); + } else { + return inputVal; + } + } + + @Override + public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + if (fromBits == toBits) { + return inputVal; + } else if (toBits > 32) { + // sign extend to 64 bits + switch (fromBits) { + case 8: + return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.QWORD), MOVSXB, QWORD, inputVal); + case 16: + return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.QWORD), MOVSX, QWORD, inputVal); + case 32: + return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.QWORD), MOVSXD, QWORD, inputVal); + default: + throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } else { + // sign extend to 32 bits (smaller values are internally represented as 32 bit values) + switch (fromBits) { + case 8: + return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.DWORD), MOVSXB, DWORD, inputVal); + case 16: + return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.DWORD), MOVSX, DWORD, inputVal); + case 32: + return inputVal; + default: + throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } + } + + @Override + public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + if (fromBits == toBits) { + return inputVal; + } else if (fromBits > 32) { + assert inputVal.getPlatformKind() == AMD64Kind.QWORD; + Variable result = getLIRGen().newVariable(LIRKind.combine(inputVal)); + long mask = CodeUtil.mask(fromBits); + getLIRGen().append(new AMD64Binary.DataTwoOp(AND.getRMOpcode(QWORD), QWORD, result, getLIRGen().asAllocatable(inputVal), JavaConstant.forLong(mask))); + return result; + } else { + LIRKind resultKind = LIRKind.combine(inputVal); + if (toBits > 32) { + resultKind = resultKind.changeType(AMD64Kind.QWORD); + } else { + resultKind = resultKind.changeType(AMD64Kind.DWORD); + } + + /* + * Always emit DWORD operations, even if the resultKind is Long. On AMD64, all DWORD + * operations implicitly set the upper half of the register to 0, which is what we want + * anyway. Compared to the QWORD oparations, the encoding of the DWORD operations is + * sometimes one byte shorter. + */ + switch (fromBits) { + case 8: + return emitConvertOp(resultKind, MOVZXB, DWORD, inputVal); + case 16: + return emitConvertOp(resultKind, MOVZX, DWORD, inputVal); + case 32: + return emitConvertOp(resultKind, MOV, DWORD, inputVal); + } + + // odd bit count, fall back on manual masking + Variable result = getLIRGen().newVariable(resultKind); + JavaConstant mask; + if (toBits > 32) { + mask = JavaConstant.forLong(CodeUtil.mask(fromBits)); + } else { + mask = JavaConstant.forInt((int) CodeUtil.mask(fromBits)); + } + getLIRGen().append(new AMD64Binary.DataTwoOp(AND.getRMOpcode(DWORD), DWORD, result, getLIRGen().asAllocatable(inputVal), mask)); + return result; + } + } + + @Override + public Variable emitBitCount(Value value) { + Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD)); + assert ((AMD64Kind) value.getPlatformKind()).isInteger(); + if (value.getPlatformKind() == AMD64Kind.QWORD) { + getLIRGen().append(new AMD64Unary.RMOp(POPCNT, QWORD, result, getLIRGen().asAllocatable(value))); + } else { + getLIRGen().append(new AMD64Unary.RMOp(POPCNT, DWORD, result, getLIRGen().asAllocatable(value))); + } + return result; + } + + @Override + public Variable emitBitScanForward(Value value) { + Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD)); + getLIRGen().append(new AMD64Unary.RMOp(BSF, QWORD, result, getLIRGen().asAllocatable(value))); + return result; + } + + @Override + public Variable emitBitScanReverse(Value value) { + Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD)); + assert ((AMD64Kind) value.getPlatformKind()).isInteger(); + if (value.getPlatformKind() == AMD64Kind.QWORD) { + getLIRGen().append(new AMD64Unary.RMOp(BSR, QWORD, result, getLIRGen().asAllocatable(value))); + } else { + getLIRGen().append(new AMD64Unary.RMOp(BSR, DWORD, result, getLIRGen().asAllocatable(value))); + } + return result; + } + + @Override + public Value emitCountLeadingZeros(Value value) { + Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD)); + assert ((AMD64Kind) value.getPlatformKind()).isInteger(); + if (value.getPlatformKind() == AMD64Kind.QWORD) { + getLIRGen().append(new AMD64Unary.RMOp(LZCNT, QWORD, result, getLIRGen().asAllocatable(value))); + } else { + getLIRGen().append(new AMD64Unary.RMOp(LZCNT, DWORD, result, getLIRGen().asAllocatable(value))); + } + return result; + } + + @Override + public Value emitCountTrailingZeros(Value value) { + Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD)); + assert ((AMD64Kind) value.getPlatformKind()).isInteger(); + if (value.getPlatformKind() == AMD64Kind.QWORD) { + getLIRGen().append(new AMD64Unary.RMOp(TZCNT, QWORD, result, getLIRGen().asAllocatable(value))); + } else { + getLIRGen().append(new AMD64Unary.RMOp(TZCNT, DWORD, result, getLIRGen().asAllocatable(value))); + } + return result; + } + + @Override + public Value emitMathAbs(Value input) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + switch ((AMD64Kind) input.getPlatformKind()) { + case SINGLE: + getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.AND, PS, result, getLIRGen().asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)), 16)); + break; + case DOUBLE: + getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.AND, PD, result, getLIRGen().asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)), 16)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + return result; + } + + @Override + public Value emitMathSqrt(Value input) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + switch ((AMD64Kind) input.getPlatformKind()) { + case SINGLE: + getLIRGen().append(new AMD64Unary.RMOp(SSEOp.SQRT, SS, result, getLIRGen().asAllocatable(input))); + break; + case DOUBLE: + getLIRGen().append(new AMD64Unary.RMOp(SSEOp.SQRT, SD, result, getLIRGen().asAllocatable(input))); + break; + default: + throw GraalError.shouldNotReachHere(); + } + return result; + } + + @Override + public Value emitMathLog(Value input, boolean base10) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input), stackSlot)); + return result; + } + + @Override + public Value emitMathCos(Value input) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), COS, result, getLIRGen().asAllocatable(input), stackSlot)); + return result; + } + + @Override + public Value emitMathSin(Value input) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), SIN, result, getLIRGen().asAllocatable(input), stackSlot)); + return result; + } + + @Override + public Value emitMathTan(Value input) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), TAN, result, getLIRGen().asAllocatable(input), stackSlot)); + return result; + } + + @Override + public Value emitMathExp(Value input) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), EXP, result, getLIRGen().asAllocatable(input), stackSlot)); + return result; + } + + @Override + public Value emitMathPow(Value input1, Value input2) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input1)); + getLIRGen().append(new AMD64MathIntrinsicBinaryOp(getAMD64LIRGen(), POW, result, getLIRGen().asAllocatable(input1), getLIRGen().asAllocatable(input2))); + return result; + } + + protected AMD64LIRGenerator getAMD64LIRGen() { + return (AMD64LIRGenerator) getLIRGen(); + } + + @Override + public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { + AMD64AddressValue loadAddress = getAMD64LIRGen().asAddressValue(address); + Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind)); + switch ((AMD64Kind) kind.getPlatformKind()) { + case BYTE: + getLIRGen().append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state)); + break; + case WORD: + getLIRGen().append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state)); + break; + case DWORD: + getLIRGen().append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state)); + break; + case QWORD: + getLIRGen().append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state)); + break; + case SINGLE: + getLIRGen().append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state)); + break; + case DOUBLE: + getLIRGen().append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + return result; + } + + protected void emitStoreConst(AMD64Kind kind, AMD64AddressValue address, ConstantValue value, LIRFrameState state) { + Constant c = value.getConstant(); + if (JavaConstant.isNull(c)) { + assert kind == AMD64Kind.DWORD || kind == AMD64Kind.QWORD; + OperandSize size = kind == AMD64Kind.DWORD ? DWORD : QWORD; + getLIRGen().append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state)); + return; + } else if (c instanceof VMConstant) { + // only 32-bit constants can be patched + if (kind == AMD64Kind.DWORD) { + if (getLIRGen().target().inlineObjects || !(c instanceof JavaConstant)) { + // if c is a JavaConstant, it's an oop, otherwise it's a metaspace constant + assert !(c instanceof JavaConstant) || ((JavaConstant) c).getJavaKind() == JavaKind.Object; + getLIRGen().append(new AMD64BinaryConsumer.MemoryVMConstOp(AMD64MIOp.MOV, address, (VMConstant) c, state)); + return; + } + } + } else { + JavaConstant jc = (JavaConstant) c; + assert jc.getJavaKind().isPrimitive(); + + AMD64MIOp op = AMD64MIOp.MOV; + OperandSize size; + long imm; + + switch (kind) { + case BYTE: + op = AMD64MIOp.MOVB; + size = BYTE; + imm = jc.asInt(); + break; + case WORD: + size = WORD; + imm = jc.asInt(); + break; + case DWORD: + size = DWORD; + imm = jc.asInt(); + break; + case QWORD: + size = QWORD; + imm = jc.asLong(); + break; + case SINGLE: + size = DWORD; + imm = Float.floatToRawIntBits(jc.asFloat()); + break; + case DOUBLE: + size = QWORD; + imm = Double.doubleToRawLongBits(jc.asDouble()); + break; + default: + throw GraalError.shouldNotReachHere("unexpected kind " + kind); + } + + if (NumUtil.isInt(imm)) { + getLIRGen().append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state)); + return; + } + } + + // fallback: load, then store + emitStore(kind, address, getLIRGen().asAllocatable(value), state); + } + + protected void emitStore(AMD64Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) { + switch (kind) { + case BYTE: + getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state)); + break; + case WORD: + getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state)); + break; + case DWORD: + getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state)); + break; + case QWORD: + getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state)); + break; + case SINGLE: + getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state)); + break; + case DOUBLE: + getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public void emitStore(ValueKind lirKind, Value address, Value input, LIRFrameState state) { + AMD64AddressValue storeAddress = getAMD64LIRGen().asAddressValue(address); + AMD64Kind kind = (AMD64Kind) lirKind.getPlatformKind(); + if (isConstantValue(input)) { + emitStoreConst(kind, storeAddress, asConstantValue(input), state); + } else { + emitStore(kind, storeAddress, getLIRGen().asAllocatable(input), state); + } + } + + @Override + public void emitCompareOp(AMD64Kind cmpKind, Variable left, Value right) { + OperandSize size; + switch (cmpKind) { + case BYTE: + size = BYTE; + break; + case WORD: + size = WORD; + break; + case DWORD: + size = DWORD; + break; + case QWORD: + size = QWORD; + break; + case SINGLE: + getLIRGen().append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PS, left, getLIRGen().asAllocatable(right))); + return; + case DOUBLE: + getLIRGen().append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PD, left, getLIRGen().asAllocatable(right))); + return; + default: + throw GraalError.shouldNotReachHere("unexpected kind: " + cmpKind); + } + + if (isConstantValue(right)) { + Constant c = LIRValueUtil.asConstant(right); + if (JavaConstant.isNull(c)) { + getLIRGen().append(new AMD64BinaryConsumer.Op(TEST, size, left, left)); + return; + } else if (c instanceof VMConstant) { + VMConstant vc = (VMConstant) c; + if (size == DWORD && !GeneratePIC.getValue()) { + getLIRGen().append(new AMD64BinaryConsumer.VMConstOp(CMP.getMIOpcode(DWORD, false), left, vc)); + } else { + getLIRGen().append(new AMD64BinaryConsumer.DataOp(CMP.getRMOpcode(size), size, left, vc)); + } + return; + } else if (c instanceof JavaConstant) { + JavaConstant jc = (JavaConstant) c; + if (jc.isDefaultForKind()) { + AMD64RMOp op = size == BYTE ? TESTB : TEST; + getLIRGen().append(new AMD64BinaryConsumer.Op(op, size, left, left)); + return; + } else if (NumUtil.is32bit(jc.asLong())) { + getLIRGen().append(new AMD64BinaryConsumer.ConstOp(CMP, size, left, (int) jc.asLong())); + return; + } + } + } + + // fallback: load, then compare + getLIRGen().append(new AMD64BinaryConsumer.Op(CMP.getRMOpcode(size), size, left, getLIRGen().asAllocatable(right))); + } + + @Override + public Value emitRound(Value value, RoundingMode mode) { + Variable result = getLIRGen().newVariable(LIRKind.combine(value)); + assert ((AMD64Kind) value.getPlatformKind()).isXMM(); + if (value.getPlatformKind() == AMD64Kind.SINGLE) { + getLIRGen().append(new AMD64Binary.RMIOp(AMD64RMIOp.ROUNDSS, OperandSize.PD, result, getLIRGen().asAllocatable(value), mode.encoding)); + } else { + getLIRGen().append(new AMD64Binary.RMIOp(AMD64RMIOp.ROUNDSD, OperandSize.PD, result, getLIRGen().asAllocatable(value), mode.encoding)); + } + return result; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java 2016-12-07 13:47:48.571010701 -0800 @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2009, 2016, 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.core.amd64; + +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.CMP; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PS; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue; +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static jdk.vm.ci.code.ValueUtil.isAllocatableValue; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.ConstantValue; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRValueUtil; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.StandardOp.JumpOp; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.amd64.AMD64AddressValue; +import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool; +import org.graalvm.compiler.lir.amd64.AMD64ArrayEqualsOp; +import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer; +import org.graalvm.compiler.lir.amd64.AMD64ByteSwapOp; +import org.graalvm.compiler.lir.amd64.AMD64Call; +import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.BranchOp; +import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.CondMoveOp; +import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatBranchOp; +import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatCondMoveOp; +import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.ReturnOp; +import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp; +import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.TableSwitchOp; +import org.graalvm.compiler.lir.amd64.AMD64Move; +import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp; +import org.graalvm.compiler.lir.amd64.AMD64Move.MembarOp; +import org.graalvm.compiler.lir.amd64.AMD64Move.StackLeaOp; +import org.graalvm.compiler.lir.amd64.AMD64PauseOp; +import org.graalvm.compiler.lir.amd64.AMD64ZapRegistersOp; +import org.graalvm.compiler.lir.amd64.AMD64ZapStackOp; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.gen.LIRGenerator; +import org.graalvm.compiler.phases.util.Providers; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.VMConstant; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; + +/** + * This class implements the AMD64 specific portion of the LIR generator. + */ +public abstract class AMD64LIRGenerator extends LIRGenerator { + + public AMD64LIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes) { + super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes); + } + + /** + * Checks whether the supplied constant can be used without loading it into a register for store + * operations, i.e., on the right hand side of a memory access. + * + * @param c The constant to check. + * @return True if the constant can be used directly, false if the constant needs to be in a + * register. + */ + protected static final boolean canStoreConstant(JavaConstant c) { + // there is no immediate move of 64-bit constants on Intel + switch (c.getJavaKind()) { + case Long: { + long l = c.asLong(); + return (int) l == l; + } + case Double: + return false; + case Object: + return c.isNull(); + default: + return true; + } + } + + @Override + protected JavaConstant zapValueForKind(PlatformKind kind) { + long dead = 0xDEADDEADDEADDEADL; + switch ((AMD64Kind) kind) { + case BYTE: + return JavaConstant.forByte((byte) dead); + case WORD: + return JavaConstant.forShort((short) dead); + case DWORD: + return JavaConstant.forInt((int) dead); + case QWORD: + return JavaConstant.forLong(dead); + case SINGLE: + return JavaConstant.forFloat(Float.intBitsToFloat((int) dead)); + default: + // we don't support vector types, so just zap with double for all of them + return JavaConstant.forDouble(Double.longBitsToDouble(dead)); + } + } + + public AMD64AddressValue asAddressValue(Value address) { + if (address instanceof AMD64AddressValue) { + return (AMD64AddressValue) address; + } else { + if (address instanceof JavaConstant) { + long displacement = ((JavaConstant) address).asLong(); + if (NumUtil.isInt(displacement)) { + return new AMD64AddressValue(address.getValueKind(), Value.ILLEGAL, (int) displacement); + } + } + return new AMD64AddressValue(address.getValueKind(), asAllocatable(address), 0); + } + } + + @Override + public Variable emitAddress(AllocatableValue stackslot) { + Variable result = newVariable(LIRKind.value(target().arch.getWordKind())); + append(new StackLeaOp(result, stackslot)); + return result; + } + + /** + * The AMD64 backend only uses DWORD and QWORD values in registers because of a performance + * penalty when accessing WORD or BYTE registers. This function converts small integer kinds to + * DWORD. + */ + @Override + public > K toRegisterKind(K kind) { + switch ((AMD64Kind) kind.getPlatformKind()) { + case BYTE: + case WORD: + return kind.changeType(AMD64Kind.DWORD); + default: + return kind; + } + } + + @Override + public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { + ValueKind kind = newValue.getValueKind(); + assert kind.equals(expectedValue.getValueKind()); + AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind(); + + AMD64AddressValue addressValue = asAddressValue(address); + RegisterValue raxRes = AMD64.rax.asValue(kind); + emitMove(raxRes, expectedValue); + append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue))); + + assert trueValue.getValueKind().equals(falseValue.getValueKind()); + Variable result = newVariable(trueValue.getValueKind()); + append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue)); + return result; + } + + @Override + public Value emitAtomicReadAndAdd(Value address, Value delta) { + ValueKind kind = delta.getValueKind(); + Variable result = newVariable(kind); + AMD64AddressValue addressValue = asAddressValue(address); + append(new AMD64Move.AtomicReadAndAddOp((AMD64Kind) kind.getPlatformKind(), result, addressValue, asAllocatable(delta))); + return result; + } + + @Override + public Value emitAtomicReadAndWrite(Value address, Value newValue) { + ValueKind kind = newValue.getValueKind(); + Variable result = newVariable(kind); + AMD64AddressValue addressValue = asAddressValue(address); + append(new AMD64Move.AtomicReadAndWriteOp((AMD64Kind) kind.getPlatformKind(), result, addressValue, asAllocatable(newValue))); + return result; + } + + @Override + public void emitNullCheck(Value address, LIRFrameState state) { + append(new AMD64Move.NullCheckOp(asAddressValue(address), state)); + } + + @Override + public void emitJump(LabelRef label) { + assert label != null; + append(new JumpOp(label)); + } + + @Override + public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) { + boolean mirrored = emitCompare(cmpKind, left, right); + Condition finalCondition = mirrored ? cond.mirror() : cond; + if (cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE) { + append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability)); + } else { + append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); + } + } + + public void emitCompareBranchMemory(AMD64Kind cmpKind, Value left, AMD64AddressValue right, LIRFrameState state, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, + double trueLabelProbability) { + boolean mirrored = emitCompareMemory(cmpKind, left, right, state); + Condition finalCondition = mirrored ? cond.mirror() : cond; + if (cmpKind.isXMM()) { + append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability)); + } else { + append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); + } + } + + @Override + public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability) { + append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow, overflowProbability)); + } + + @Override + public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { + emitIntegerTest(left, right); + append(new BranchOp(Condition.EQ, trueDestination, falseDestination, trueDestinationProbability)); + } + + @Override + public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { + boolean mirrored = emitCompare(cmpKind, left, right); + Condition finalCondition = mirrored ? cond.mirror() : cond; + + Variable result = newVariable(trueValue.getValueKind()); + if (cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE) { + append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue))); + } else { + append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue))); + } + return result; + } + + @Override + public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) { + emitIntegerTest(left, right); + Variable result = newVariable(trueValue.getValueKind()); + append(new CondMoveOp(result, Condition.EQ, load(trueValue), loadNonConst(falseValue))); + return result; + } + + private void emitIntegerTest(Value a, Value b) { + assert ((AMD64Kind) a.getPlatformKind()).isInteger(); + OperandSize size = a.getPlatformKind() == AMD64Kind.QWORD ? QWORD : DWORD; + if (isJavaConstant(b) && NumUtil.is32bit(asJavaConstant(b).asLong())) { + append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(a), (int) asJavaConstant(b).asLong())); + } else if (isJavaConstant(a) && NumUtil.is32bit(asJavaConstant(a).asLong())) { + append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(b), (int) asJavaConstant(a).asLong())); + } else if (isAllocatableValue(b)) { + append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(b), asAllocatable(a))); + } else { + append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(a), asAllocatable(b))); + } + } + + /** + * This method emits the compare against memory instruction, and may reorder the operands. It + * returns true if it did so. + * + * @param b the right operand of the comparison + * @return true if the left and right operands were switched, false otherwise + */ + private boolean emitCompareMemory(AMD64Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state) { + OperandSize size; + switch (cmpKind) { + case BYTE: + size = OperandSize.BYTE; + break; + case WORD: + size = OperandSize.WORD; + break; + case DWORD: + size = OperandSize.DWORD; + break; + case QWORD: + size = OperandSize.QWORD; + break; + case SINGLE: + append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PS, asAllocatable(a), b, state)); + return false; + case DOUBLE: + append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PD, asAllocatable(a), b, state)); + return false; + default: + throw GraalError.shouldNotReachHere("unexpected kind: " + cmpKind); + } + + if (isJavaConstant(a)) { + return emitCompareMemoryConOp(size, asConstantValue(a), b, state); + } else { + return emitCompareRegMemoryOp(size, asAllocatable(a), b, state); + } + } + + protected boolean emitCompareMemoryConOp(OperandSize size, ConstantValue a, AMD64AddressValue b, LIRFrameState state) { + if (JavaConstant.isNull(a.getConstant())) { + append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, 0, state)); + return true; + } else if (a.getConstant() instanceof VMConstant && size == DWORD) { + VMConstant vc = (VMConstant) a.getConstant(); + append(new AMD64BinaryConsumer.MemoryVMConstOp(CMP.getMIOpcode(size, false), b, vc, state)); + return true; + } else { + long value = a.getJavaConstant().asLong(); + if (NumUtil.is32bit(value)) { + append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, (int) value, state)); + return true; + } else { + return emitCompareRegMemoryOp(size, asAllocatable(a), b, state); + } + } + } + + private boolean emitCompareRegMemoryOp(OperandSize size, AllocatableValue a, AMD64AddressValue b, LIRFrameState state) { + AMD64RMOp op = CMP.getRMOpcode(size); + append(new AMD64BinaryConsumer.MemoryRMOp(op, size, a, b, state)); + return false; + } + + /** + * This method emits the compare instruction, and may reorder the operands. It returns true if + * it did so. + * + * @param a the left operand of the comparison + * @param b the right operand of the comparison + * @return true if the left and right operands were switched, false otherwise + */ + private boolean emitCompare(PlatformKind cmpKind, Value a, Value b) { + Variable left; + Value right; + boolean mirrored; + if (LIRValueUtil.isVariable(b)) { + left = load(b); + right = loadNonConst(a); + mirrored = true; + } else { + left = load(a); + right = loadNonConst(b); + mirrored = false; + } + ((AMD64ArithmeticLIRGeneratorTool) arithmeticLIRGen).emitCompareOp((AMD64Kind) cmpKind, left, right); + return mirrored; + } + + @Override + public void emitMembar(int barriers) { + int necessaryBarriers = target().arch.requiredBarriers(barriers); + if (target().isMP && necessaryBarriers != 0) { + append(new MembarOp(necessaryBarriers)); + } + } + + public abstract void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments); + + @Override + protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + long maxOffset = linkage.getMaxCallTargetOffset(); + if (maxOffset != (int) maxOffset && !GeneratePIC.getValue()) { + append(new AMD64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info)); + } else { + append(new AMD64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info)); + } + } + + @Override + public Variable emitByteSwap(Value input) { + Variable result = newVariable(LIRKind.combine(input)); + append(new AMD64ByteSwapOp(result, input)); + return result; + } + + @Override + public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) { + Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD)); + append(new AMD64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length))); + return result; + } + + @Override + public void emitReturn(JavaKind kind, Value input) { + AllocatableValue operand = Value.ILLEGAL; + if (input != null) { + operand = resultOperandFor(kind, input.getValueKind()); + emitMove(operand, input); + } + append(new ReturnOp(operand)); + } + + protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue temp) { + return new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, temp); + } + + @Override + public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { + // a temp is needed for loading object constants + boolean needsTemp = !LIRKind.isValue(key); + append(createStrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getValueKind()) : Value.ILLEGAL)); + } + + @Override + protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) { + append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().arch.getWordKind())), newVariable(key.getValueKind()))); + } + + @Override + public void emitPause() { + append(new AMD64PauseOp()); + } + + @Override + public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) { + return new AMD64ZapRegistersOp(zappedRegisters, zapValues); + } + + @Override + public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) { + return new AMD64ZapStackOp(zappedStack, zapValues); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRKindTool.java 2016-12-07 13:47:48.837022390 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015, 2015, 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.core.amd64; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.amd64.AMD64Kind; + +public class AMD64LIRKindTool implements LIRKindTool { + + @Override + public LIRKind getIntegerKind(int bits) { + if (bits <= 8) { + return LIRKind.value(AMD64Kind.BYTE); + } else if (bits <= 16) { + return LIRKind.value(AMD64Kind.WORD); + } else if (bits <= 32) { + return LIRKind.value(AMD64Kind.DWORD); + } else { + assert bits <= 64; + return LIRKind.value(AMD64Kind.QWORD); + } + } + + @Override + public LIRKind getFloatingKind(int bits) { + switch (bits) { + case 32: + return LIRKind.value(AMD64Kind.SINGLE); + case 64: + return LIRKind.value(AMD64Kind.DOUBLE); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public LIRKind getObjectKind() { + return LIRKind.reference(AMD64Kind.QWORD); + } + + @Override + public LIRKind getWordKind() { + return LIRKind.value(AMD64Kind.QWORD); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactory.java 2016-12-07 13:47:49.102034034 -0800 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, 2016, 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.core.amd64; + +import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; +import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; +import static jdk.vm.ci.code.ValueUtil.isRegister; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.core.common.type.DataPointerConstant; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.amd64.AMD64AddressValue; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64StackMove; +import org.graalvm.compiler.lir.amd64.AMD64Move.LeaDataOp; +import org.graalvm.compiler.lir.amd64.AMD64Move.LeaOp; +import org.graalvm.compiler.lir.amd64.AMD64Move.MoveFromConstOp; +import org.graalvm.compiler.lir.amd64.AMD64Move.MoveFromRegOp; +import org.graalvm.compiler.lir.amd64.AMD64Move.MoveToRegOp; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.Value; + +public abstract class AMD64MoveFactory extends AMD64MoveFactoryBase { + + public AMD64MoveFactory(BackupSlotProvider backupSlotProvider) { + super(backupSlotProvider); + } + + @Override + public boolean canInlineConstant(JavaConstant c) { + switch (c.getJavaKind()) { + case Long: + return NumUtil.isInt(c.asLong()); + case Object: + return c.isNull(); + default: + return true; + } + } + + @Override + public AMD64LIRInstruction createMove(AllocatableValue dst, Value src) { + if (src instanceof AMD64AddressValue) { + return new LeaOp(dst, (AMD64AddressValue) src); + } else if (isConstantValue(src)) { + return createLoad(dst, asConstant(src)); + } else if (isRegister(src) || isStackSlotValue(dst)) { + return new MoveFromRegOp((AMD64Kind) dst.getPlatformKind(), dst, (AllocatableValue) src); + } else { + return new MoveToRegOp((AMD64Kind) dst.getPlatformKind(), dst, (AllocatableValue) src); + } + } + + @Override + public AMD64LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input, Register scratchRegister, AllocatableValue backupSlot) { + return new AMD64StackMove(result, input, scratchRegister, backupSlot); + } + + @Override + public AMD64LIRInstruction createLoad(AllocatableValue dst, Constant src) { + if (src instanceof JavaConstant) { + return new MoveFromConstOp(dst, (JavaConstant) src); + } else if (src instanceof DataPointerConstant) { + return new LeaDataOp(dst, (DataPointerConstant) src); + } else { + throw GraalError.shouldNotReachHere(String.format("unsupported constant: %s", src)); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java 2016-12-07 13:47:49.372045898 -0800 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015, 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.core.amd64; + +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD; + +import java.util.HashMap; +import java.util.Map; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64PushPopStackMove; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.PlatformKind; + +public abstract class AMD64MoveFactoryBase implements MoveFactory { + + private final BackupSlotProvider backupSlotProvider; + + private static class RegisterBackupPair { + public final Register register; + public final VirtualStackSlot backupSlot; + + RegisterBackupPair(Register register, VirtualStackSlot backupSlot) { + this.register = register; + this.backupSlot = backupSlot; + } + } + + public static final class BackupSlotProvider { + + private final FrameMapBuilder frameMapBuilder; + private Map categorized; + + public BackupSlotProvider(FrameMapBuilder frameMapBuilder) { + this.frameMapBuilder = frameMapBuilder; + } + + protected RegisterBackupPair getScratchRegister(PlatformKind kind) { + PlatformKind.Key key = kind.getKey(); + if (categorized == null) { + categorized = new HashMap<>(); + } else if (categorized.containsKey(key)) { + return categorized.get(key); + } + + RegisterConfig registerConfig = frameMapBuilder.getRegisterConfig(); + + RegisterArray availableRegister = registerConfig.filterAllocatableRegisters(kind, registerConfig.getAllocatableRegisters()); + assert availableRegister != null && availableRegister.size() > 1; + Register scratchRegister = availableRegister.get(0); + + Architecture arch = frameMapBuilder.getCodeCache().getTarget().arch; + LIRKind largestKind = LIRKind.value(arch.getLargestStorableKind(scratchRegister.getRegisterCategory())); + VirtualStackSlot backupSlot = frameMapBuilder.allocateSpillSlot(largestKind); + + RegisterBackupPair value = new RegisterBackupPair(scratchRegister, backupSlot); + categorized.put(key, value); + + return value; + } + } + + public AMD64MoveFactoryBase(BackupSlotProvider backupSlotProvider) { + this.backupSlotProvider = backupSlotProvider; + } + + @Override + public final AMD64LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) { + AMD64Kind kind = (AMD64Kind) result.getPlatformKind(); + switch (kind.getSizeInBytes()) { + case 2: + return new AMD64PushPopStackMove(WORD, result, input); + case 8: + return new AMD64PushPopStackMove(QWORD, result, input); + default: + RegisterBackupPair backup = backupSlotProvider.getScratchRegister(input.getPlatformKind()); + Register scratchRegister = backup.register; + VirtualStackSlot backupSlot = backup.backupSlot; + return createStackMove(result, input, scratchRegister, backupSlot); + } + } + + public abstract AMD64LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input, Register scratchRegister, AllocatableValue backupSlot); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java 2016-12-07 13:47:49.637057543 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2009, 2016, 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.core.amd64; + +import org.graalvm.compiler.core.gen.NodeLIRBuilder; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.amd64.AMD64Call; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.DeoptimizingNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.IndirectCallTargetNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.IntegerDivRemNode; +import org.graalvm.compiler.nodes.calc.IntegerDivRemNode.Op; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; + +public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder { + + public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) { + super(graph, gen, nodeMatchRules); + } + + @Override + protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + Value targetAddressSrc = operand(callTarget.computedAddress()); + AllocatableValue targetAddress = AMD64.rax.asValue(targetAddressSrc.getValueKind()); + gen.emitMove(targetAddress, targetAddressSrc); + append(new AMD64Call.IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, targetAddress, callState)); + } + + @Override + protected boolean peephole(ValueNode valueNode) { + if (valueNode instanceof IntegerDivRemNode) { + AMD64ArithmeticLIRGenerator arithmeticGen = (AMD64ArithmeticLIRGenerator) gen.getArithmetic(); + IntegerDivRemNode divRem = (IntegerDivRemNode) valueNode; + FixedNode node = divRem.next(); + while (true) { + if (node instanceof IfNode) { + IfNode ifNode = (IfNode) node; + double probability = ifNode.getTrueSuccessorProbability(); + if (probability == 1.0) { + node = ifNode.trueSuccessor(); + } else if (probability == 0.0) { + node = ifNode.falseSuccessor(); + } else { + break; + } + } else if (!(node instanceof FixedWithNextNode)) { + break; + } + + FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node; + if (fixedWithNextNode instanceof IntegerDivRemNode) { + IntegerDivRemNode otherDivRem = (IntegerDivRemNode) fixedWithNextNode; + if (divRem.getOp() != otherDivRem.getOp() && divRem.getType() == otherDivRem.getType()) { + if (otherDivRem.getX() == divRem.getX() && otherDivRem.getY() == divRem.getY() && !hasOperand(otherDivRem)) { + Value[] results; + switch (divRem.getType()) { + case SIGNED: + results = arithmeticGen.emitSignedDivRem(operand(divRem.getX()), operand(divRem.getY()), state((DeoptimizingNode) valueNode)); + break; + case UNSIGNED: + results = arithmeticGen.emitUnsignedDivRem(operand(divRem.getX()), operand(divRem.getY()), state((DeoptimizingNode) valueNode)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + switch (divRem.getOp()) { + case DIV: + assert otherDivRem.getOp() == Op.REM; + setResult(divRem, results[0]); + setResult(otherDivRem, results[1]); + break; + case REM: + assert otherDivRem.getOp() == Op.DIV; + setResult(divRem, results[1]); + setResult(otherDivRem, results[0]); + break; + default: + throw GraalError.shouldNotReachHere(); + } + return true; + } + } + } + node = fixedWithNextNode.next(); + } + } + return false; + } + + @Override + public AMD64LIRGenerator getLIRGeneratorTool() { + return (AMD64LIRGenerator) gen; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java 2016-12-07 13:47:49.902069187 -0800 @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2009, 2016, 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.core.amd64; + +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.OR; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SUB; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSX; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXB; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SS; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.gen.NodeLIRBuilder; +import org.graalvm.compiler.core.gen.NodeMatchRules; +import org.graalvm.compiler.core.match.ComplexMatchResult; +import org.graalvm.compiler.core.match.MatchRule; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.amd64.AMD64AddressValue; +import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer; +import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.BranchOp; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.DeoptimizingNode; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.CompareNode; +import org.graalvm.compiler.nodes.calc.FloatConvertNode; +import org.graalvm.compiler.nodes.calc.LeftShiftNode; +import org.graalvm.compiler.nodes.calc.NarrowNode; +import org.graalvm.compiler.nodes.calc.ReinterpretNode; +import org.graalvm.compiler.nodes.calc.SignExtendNode; +import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode; +import org.graalvm.compiler.nodes.calc.ZeroExtendNode; +import org.graalvm.compiler.nodes.memory.Access; +import org.graalvm.compiler.nodes.memory.WriteNode; +import org.graalvm.compiler.nodes.util.GraphUtil; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +public class AMD64NodeMatchRules extends NodeMatchRules { + + public AMD64NodeMatchRules(LIRGeneratorTool gen) { + super(gen); + } + + protected LIRFrameState getState(Access access) { + if (access instanceof DeoptimizingNode) { + return state((DeoptimizingNode) access); + } + return null; + } + + protected AMD64Kind getMemoryKind(Access access) { + return (AMD64Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind(); + } + + protected OperandSize getMemorySize(Access access) { + switch (getMemoryKind(access)) { + case BYTE: + return OperandSize.BYTE; + case WORD: + return OperandSize.WORD; + case DWORD: + return OperandSize.DWORD; + case QWORD: + return OperandSize.QWORD; + case SINGLE: + return OperandSize.SS; + case DOUBLE: + return OperandSize.SD; + default: + throw GraalError.shouldNotReachHere("unsupported memory access type " + getMemoryKind(access)); + } + } + + protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, Access access) { + Condition cond = compare.condition(); + AMD64Kind kind = getMemoryKind(access); + + if (value.isConstant()) { + JavaConstant constant = value.asJavaConstant(); + if (constant != null && kind == AMD64Kind.QWORD && !constant.getJavaKind().isObject() && !NumUtil.isInt(constant.asLong())) { + // Only imm32 as long + return null; + } + if (kind.isXMM()) { + Debug.log("Skipping constant compares for float kinds"); + return null; + } + } + + // emitCompareBranchMemory expects the memory on the right, so mirror the condition if + // that's not true. It might be mirrored again the actual compare is emitted but that's + // ok. + Condition finalCondition = GraphUtil.unproxify(compare.getX()) == access ? cond.mirror() : cond; + return new ComplexMatchResult() { + @Override + public Value evaluate(NodeLIRBuilder builder) { + LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor()); + LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor()); + boolean unorderedIsTrue = compare.unorderedIsTrue(); + double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor()); + Value other = operand(value); + AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress()); + getLIRGeneratorTool().emitCompareBranchMemory(kind, other, address, getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability); + return null; + } + }; + } + + private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, Access access) { + LabelRef trueLabel = getLIRBlock(x.trueSuccessor()); + LabelRef falseLabel = getLIRBlock(x.falseSuccessor()); + double trueLabelProbability = x.probability(x.trueSuccessor()); + AMD64Kind kind = getMemoryKind(access); + OperandSize size = kind == AMD64Kind.QWORD ? QWORD : DWORD; + if (value.isConstant()) { + JavaConstant constant = value.asJavaConstant(); + if (constant != null && kind == AMD64Kind.QWORD && !NumUtil.isInt(constant.asLong())) { + // Only imm32 as long + return null; + } + return builder -> { + AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress()); + gen.append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.TEST, size, address, (int) constant.asLong(), getState(access))); + gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); + return null; + }; + } else { + return builder -> { + AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress()); + gen.append(new AMD64BinaryConsumer.MemoryRMOp(AMD64RMOp.TEST, size, gen.asAllocatable(operand(value)), address, getState(access))); + gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); + return null; + }; + } + } + + protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access) { + return builder -> { + AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress()); + LIRFrameState state = getState(access); + return getArithmeticLIRGenerator().emitConvertMemoryOp(kind, op, size, address, state); + }; + } + + private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + AMD64Kind kind = null; + AMD64RMOp op; + OperandSize size; + if (fromBits == toBits) { + return null; + } else if (toBits > 32) { + kind = AMD64Kind.QWORD; + size = OperandSize.QWORD; + // sign extend to 64 bits + switch (fromBits) { + case 8: + op = MOVSXB; + break; + case 16: + op = MOVSX; + break; + case 32: + op = MOVSXD; + break; + default: + throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } else { + kind = AMD64Kind.DWORD; + size = OperandSize.DWORD; + // sign extend to 32 bits (smaller values are internally represented as 32 bit values) + switch (fromBits) { + case 8: + op = MOVSXB; + break; + case 16: + op = MOVSX; + break; + case 32: + return null; + default: + throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } + if (kind != null && op != null) { + return emitConvertMemoryOp(kind, op, size, access); + } + return null; + } + + private Value emitReinterpretMemory(LIRKind to, Access access) { + AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress()); + LIRFrameState state = getState(access); + return getArithmeticLIRGenerator().emitLoad(to, address, state); + } + + @MatchRule("(If (IntegerTest Read=access value))") + @MatchRule("(If (IntegerTest FloatingRead=access value))") + public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) { + return emitIntegerTestBranchMemory(root, value, access); + } + + @MatchRule("(If (IntegerEquals=compare value Read=access))") + @MatchRule("(If (IntegerLessThan=compare value Read=access))") + @MatchRule("(If (IntegerBelow=compare value Read=access))") + @MatchRule("(If (IntegerEquals=compare value FloatingRead=access))") + @MatchRule("(If (IntegerLessThan=compare value FloatingRead=access))") + @MatchRule("(If (IntegerBelow=compare value FloatingRead=access))") + @MatchRule("(If (FloatEquals=compare value Read=access))") + @MatchRule("(If (FloatEquals=compare value FloatingRead=access))") + @MatchRule("(If (FloatLessThan=compare value Read=access))") + @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))") + @MatchRule("(If (PointerEquals=compare value Read=access))") + @MatchRule("(If (PointerEquals=compare value FloatingRead=access))") + @MatchRule("(If (ObjectEquals=compare value Read=access))") + @MatchRule("(If (ObjectEquals=compare value FloatingRead=access))") + public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) { + return emitCompareBranchMemory(root, compare, value, access); + } + + @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))") + public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) { + if ((lshift.getShiftAmountMask() & (lshift.getY().asJavaConstant().asInt() + rshift.getY().asJavaConstant().asInt())) == 0) { + return builder -> getArithmeticLIRGenerator().emitRol(operand(lshift.getX()), operand(lshift.getY())); + } + return null; + } + + @MatchRule("(Or (LeftShift value (Sub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))") + public ComplexMatchResult rotateRightVariable(ValueNode value, ConstantNode delta, ValueNode shiftAmount) { + if (delta.asJavaConstant().asLong() == 0 || delta.asJavaConstant().asLong() == 32) { + return builder -> getArithmeticLIRGenerator().emitRor(operand(value), operand(shiftAmount)); + } + return null; + } + + @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (Sub Constant=delta shiftAmount)))") + public ComplexMatchResult rotateLeftVariable(ValueNode value, ValueNode shiftAmount, ConstantNode delta) { + if (delta.asJavaConstant().asLong() == 0 || delta.asJavaConstant().asLong() == 32) { + return builder -> getArithmeticLIRGenerator().emitRol(operand(value), operand(shiftAmount)); + } + return null; + } + + private ComplexMatchResult binaryRead(AMD64RMOp op, OperandSize size, ValueNode value, Access access) { + return builder -> getArithmeticLIRGenerator().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()), + getState(access)); + } + + private ComplexMatchResult binaryRead(AMD64RRMOp op, OperandSize size, ValueNode value, Access access) { + return builder -> getArithmeticLIRGenerator().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()), + getState(access)); + } + + @MatchRule("(Add value Read=access)") + @MatchRule("(Add value FloatingRead=access)") + public ComplexMatchResult addMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + TargetDescription target = getLIRGeneratorTool().target(); + boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX); + if (isAvx) { + return binaryRead(AVXOp.ADD, size, value, access); + } else { + return binaryRead(SSEOp.ADD, size, value, access); + } + } else { + return binaryRead(ADD.getRMOpcode(size), size, value, access); + } + } + + @MatchRule("(Sub value Read=access)") + @MatchRule("(Sub value FloatingRead=access)") + public ComplexMatchResult subMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + TargetDescription target = getLIRGeneratorTool().target(); + boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX); + if (isAvx) { + return binaryRead(AVXOp.SUB, size, value, access); + } else { + return binaryRead(SSEOp.SUB, size, value, access); + } + } else { + return binaryRead(SUB.getRMOpcode(size), size, value, access); + } + } + + @MatchRule("(Mul value Read=access)") + @MatchRule("(Mul value FloatingRead=access)") + public ComplexMatchResult mulMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + TargetDescription target = getLIRGeneratorTool().target(); + boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX); + if (isAvx) { + return binaryRead(AVXOp.MUL, size, value, access); + } else { + return binaryRead(SSEOp.MUL, size, value, access); + } + } else { + return binaryRead(AMD64RMOp.IMUL, size, value, access); + } + } + + @MatchRule("(And value Read=access)") + @MatchRule("(And value FloatingRead=access)") + public ComplexMatchResult andMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return null; + } else { + return binaryRead(AND.getRMOpcode(size), size, value, access); + } + } + + @MatchRule("(Or value Read=access)") + @MatchRule("(Or value FloatingRead=access)") + public ComplexMatchResult orMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return null; + } else { + return binaryRead(OR.getRMOpcode(size), size, value, access); + } + } + + @MatchRule("(Xor value Read=access)") + @MatchRule("(Xor value FloatingRead=access)") + public ComplexMatchResult xorMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return null; + } else { + return binaryRead(XOR.getRMOpcode(size), size, value, access); + } + } + + @MatchRule("(Write object Narrow=narrow)") + public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) { + return builder -> { + LIRKind writeKind = getLIRGeneratorTool().getLIRKind(root.value().stamp()); + getArithmeticLIRGenerator().emitStore(writeKind, operand(root.getAddress()), operand(narrow.getValue()), state(root)); + return null; + }; + } + + @MatchRule("(SignExtend Read=access)") + @MatchRule("(SignExtend FloatingRead=access)") + public ComplexMatchResult signExtend(SignExtendNode root, Access access) { + return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits()); + } + + @MatchRule("(ZeroExtend Read=access)") + @MatchRule("(ZeroExtend FloatingRead=access)") + public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) { + AMD64Kind memoryKind = getMemoryKind(access); + return builder -> getArithmeticLIRGenerator().emitZeroExtendMemory(memoryKind, root.getResultBits(), (AMD64AddressValue) operand(access.getAddress()), getState(access)); + } + + @MatchRule("(FloatConvert Read=access)") + @MatchRule("(FloatConvert FloatingRead=access)") + public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) { + switch (root.getFloatConvert()) { + case D2F: + return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSD2SS, SD, access); + case D2I: + return emitConvertMemoryOp(AMD64Kind.DWORD, SSEOp.CVTTSD2SI, DWORD, access); + case D2L: + return emitConvertMemoryOp(AMD64Kind.QWORD, SSEOp.CVTTSD2SI, QWORD, access); + case F2D: + return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSS2SD, SS, access); + case F2I: + return emitConvertMemoryOp(AMD64Kind.DWORD, SSEOp.CVTTSS2SI, DWORD, access); + case F2L: + return emitConvertMemoryOp(AMD64Kind.QWORD, SSEOp.CVTTSS2SI, QWORD, access); + case I2D: + return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSI2SD, DWORD, access); + case I2F: + return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSI2SS, DWORD, access); + case L2D: + return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSI2SD, QWORD, access); + case L2F: + return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSI2SS, QWORD, access); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @MatchRule("(Reinterpret Read=access)") + @MatchRule("(Reinterpret FloatingRead=access)") + public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) { + return builder -> { + LIRKind kind = getLIRGeneratorTool().getLIRKind(root.stamp()); + return emitReinterpretMemory(kind, access); + }; + + } + + @MatchRule("(Write object Reinterpret=reinterpret)") + public ComplexMatchResult writeReinterpret(WriteNode root, ReinterpretNode reinterpret) { + return builder -> { + LIRKind kind = getLIRGeneratorTool().getLIRKind(reinterpret.getValue().stamp()); + AllocatableValue value = getLIRGeneratorTool().asAllocatable(operand(reinterpret.getValue())); + + AMD64AddressValue address = (AMD64AddressValue) operand(root.getAddress()); + getArithmeticLIRGenerator().emitStore((AMD64Kind) kind.getPlatformKind(), address, value, getState(root)); + return null; + }; + } + + @Override + public AMD64LIRGenerator getLIRGeneratorTool() { + return (AMD64LIRGenerator) gen; + } + + protected AMD64ArithmeticLIRGenerator getArithmeticLIRGenerator() { + return (AMD64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64SuitesProvider.java 2016-12-07 13:47:50.168080875 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015, 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.core.amd64; + +import org.graalvm.compiler.java.DefaultSuitesProvider; +import org.graalvm.compiler.lir.amd64.phases.StackMoveOptimizationPhase; +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; + +public class AMD64SuitesProvider extends DefaultSuitesProvider { + + public AMD64SuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) { + super(compilerConfiguration, plugins); + } + + @Override + public LIRSuites createLIRSuites() { + LIRSuites lirSuites = super.createLIRSuites(); + if (StackMoveOptimizationPhase.Options.LIROptStackMoveOptimizer.getValue()) { + /* Note: this phase must be inserted after RedundantMoveElimination */ + lirSuites.getPostAllocationOptimizationStage().appendPhase(new StackMoveOptimizationPhase()); + } + return lirSuites; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CollectionsFactory.java 2016-12-07 13:47:50.434092564 -0800 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2014, 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.core.common; + +import static org.graalvm.compiler.core.common.CollectionsFactory.Mode.STANDARD; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +/** + * Factory for creating collection objects used during compilation. + */ +public class CollectionsFactory { + + private static final ThreadLocal tl = new ThreadLocal<>(); + + public static class ModeScope implements AutoCloseable { + private final Mode previousMode; + + public ModeScope(Mode previousMode) { + this.previousMode = previousMode; + } + + @Override + public void close() { + tl.set(previousMode); + } + } + + /** + * Constants denoting what type of collections are {@link CollectionsFactory#getMode() + * currently} returned by the factory. + */ + public enum Mode { + /** + * Denotes standard collections such as {@link HashSet} and {@link HashMap}. + */ + STANDARD, + + /** + * Denotes collections that have a deterministic iteration order over their keys/entries. + */ + DETERMINISTIC_ITERATION_ORDER; + } + + /** + * Gets the current mode determining the type of collection objects created by this factory. + */ + public static Mode getMode() { + Mode mode = tl.get(); + return mode == null ? Mode.STANDARD : mode; + } + + /** + * Updates the mode for the current thread. + * + * @return an object which when {@linkplain ModeScope#close() closed} will revert the mode of + * the current thread to the state before calling this method + */ + public static ModeScope changeMode(Mode mode) { + Mode previousMode = tl.get(); + tl.set(mode); + return new ModeScope(previousMode); + } + + public static HashMap newMap() { + return getMode() == STANDARD ? new HashMap<>() : new LinkedHashMap<>(); + } + + public static HashMap newMap(Map m) { + return getMode() == STANDARD ? new HashMap<>(m) : new LinkedHashMap<>(m); + } + + public static HashMap newMap(int initialCapacity) { + return getMode() == STANDARD ? new HashMap<>(initialCapacity) : new LinkedHashMap<>(initialCapacity); + } + + public static Map newIdentityMap() { + return getMode() == STANDARD ? new IdentityHashMap<>() : new LinkedIdentityHashMap<>(); + } + + public static Map newIdentityMap(int expectedMaxSize) { + return getMode() == STANDARD ? new IdentityHashMap<>(expectedMaxSize) : new LinkedIdentityHashMap<>(); + } + + public static Map newIdentityMap(Map m) { + return getMode() == STANDARD ? new IdentityHashMap<>(m) : new LinkedIdentityHashMap<>(m); + } + + /** + * Creates a set. If the current thread is {@linkplain CollectionsFactory#getMode() using} + * {@link Mode#DETERMINISTIC_ITERATION_ORDER} collections, the returned set will have an + * iteration order determined by the order in which elements are inserted in the set. + */ + public static Set newSet() { + return CollectionsFactory.getMode() == Mode.STANDARD ? new HashSet<>() : new LinkedHashSet<>(); + } + + /** + * @see #newSet() + */ + public static Set newSet(Collection c) { + return CollectionsFactory.getMode() == Mode.STANDARD ? new HashSet<>(c) : new LinkedHashSet<>(c); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CompilationIdentifier.java 2016-12-07 13:47:50.699104208 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016, 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.core.common; + +import jdk.vm.ci.code.CompilationRequest; + +/** + * A unique identifier for a compilation. Compiled code can be mapped to a single compilation id. + * The reverse is not true since the compiler might bailout in which case no code is installed. + */ +public interface CompilationIdentifier { + + enum Verbosity { + /** + * Only the unique identifier of the compilation. + */ + ID, + /** + * Only the name of the compilation unit. + */ + NAME, + /** + * {@link #ID} + a readable description. + */ + DETAILED + } + + CompilationRequestIdentifier INVALID_COMPILATION_ID = new CompilationRequestIdentifier() { + + @Override + public String toString() { + return toString(Verbosity.DETAILED); + } + + @Override + public String toString(Verbosity verbosity) { + return "InvalidCompilationID"; + } + + @Override + public CompilationRequest getRequest() { + return null; + } + + }; + + /** + * This method is a shortcut for {@link #toString(Verbosity)} with {@link Verbosity#DETAILED}. + */ + @Override + String toString(); + + /** + * Creates a String representation for this compilation identifier with a given + * {@link Verbosity}. + */ + String toString(Verbosity verbosity); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CompilationRequestIdentifier.java 2016-12-07 13:47:50.963115809 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016, 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.core.common; + +import jdk.vm.ci.code.CompilationRequest; + +/** + * A {@link CompilationIdentifier} based on a {@link CompilationRequest}. + */ +public interface CompilationRequestIdentifier extends CompilationIdentifier { + + CompilationRequest getRequest(); + + /** + * Returns the {@link CompilationRequestIdentifier#getRequest() request} from a + * {@link CompilationRequestIdentifier}. Returns {@code null} if the + * {@link CompilationIdentifier identifier} does not have one. + */ + static CompilationRequest asCompilationRequest(CompilationIdentifier compilationId) { + if (compilationId instanceof CompilationRequestIdentifier) { + return ((CompilationRequestIdentifier) compilationId).getRequest(); + } + return null; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/FieldIntrospection.java 2016-12-07 13:47:51.227127409 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 2012, 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.core.common; + +public abstract class FieldIntrospection { + + private final Class clazz; + + /** + * The set of fields in {@link #clazz} that do long belong to a more specific category. + */ + protected Fields data; + + public FieldIntrospection(Class clazz) { + this.clazz = clazz; + } + + public Class getClazz() { + return clazz; + } + + /** + * Gets the fields in {@link #getClazz()} that do long belong to specific category. + */ + public Fields getData() { + return data; + } + + public abstract Fields[] getAllFields(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/Fields.java 2016-12-07 13:47:51.492139054 -0800 @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2014, 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.core.common; + +import static org.graalvm.compiler.core.common.UnsafeAccess.UNSAFE; + +import java.util.ArrayList; +import java.util.Collections; + +import org.graalvm.compiler.debug.GraalError; + +import sun.misc.Unsafe; + +/** + * Describes fields in a class, primarily for access via {@link Unsafe}. + */ +public class Fields { + + /** + * Offsets used with {@link Unsafe} to access the fields. + */ + protected final long[] offsets; + + /** + * The names of the fields. + */ + private final String[] names; + + /** + * The types of the fields. + */ + private final Class[] types; + + private final Class[] declaringClasses; + + public static Fields forClass(Class clazz, Class endClazz, boolean includeTransient, FieldsScanner.CalcOffset calcOffset) { + FieldsScanner scanner = new FieldsScanner(calcOffset == null ? new FieldsScanner.DefaultCalcOffset() : calcOffset); + scanner.scan(clazz, endClazz, includeTransient); + return new Fields(scanner.data); + } + + public Fields(ArrayList fields) { + Collections.sort(fields); + this.offsets = new long[fields.size()]; + this.names = new String[offsets.length]; + this.types = new Class[offsets.length]; + this.declaringClasses = new Class[offsets.length]; + int index = 0; + for (FieldsScanner.FieldInfo f : fields) { + offsets[index] = f.offset; + names[index] = f.name; + types[index] = f.type; + declaringClasses[index] = f.declaringClass; + index++; + } + } + + /** + * Gets the number of fields represented by this object. + */ + public int getCount() { + return offsets.length; + } + + public static void translateInto(Fields fields, ArrayList infos) { + for (int index = 0; index < fields.getCount(); index++) { + infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index], fields.declaringClasses[index])); + } + } + + /** + * Function enabling an object field value to be replaced with another value when being copied + * within {@link Fields#copy(Object, Object, ObjectTransformer)}. + */ + @FunctionalInterface + public interface ObjectTransformer { + Object apply(int index, Object from); + } + + /** + * Copies fields from {@code from} to {@code to}, both of which must be of the same type. + * + * @param from the object from which the fields should be copied + * @param to the object to which the fields should be copied + */ + public void copy(Object from, Object to) { + copy(from, to, null); + } + + /** + * Copies fields from {@code from} to {@code to}, both of which must be of the same type. + * + * @param from the object from which the fields should be copied + * @param to the object to which the fields should be copied + * @param trans function to applied to object field values as they are copied. If {@code null}, + * the value is copied unchanged. + */ + public void copy(Object from, Object to, ObjectTransformer trans) { + assert from.getClass() == to.getClass(); + for (int index = 0; index < offsets.length; index++) { + long offset = offsets[index]; + Class type = types[index]; + if (type.isPrimitive()) { + if (type == Integer.TYPE) { + UNSAFE.putInt(to, offset, UNSAFE.getInt(from, offset)); + } else if (type == Long.TYPE) { + UNSAFE.putLong(to, offset, UNSAFE.getLong(from, offset)); + } else if (type == Boolean.TYPE) { + UNSAFE.putBoolean(to, offset, UNSAFE.getBoolean(from, offset)); + } else if (type == Float.TYPE) { + UNSAFE.putFloat(to, offset, UNSAFE.getFloat(from, offset)); + } else if (type == Double.TYPE) { + UNSAFE.putDouble(to, offset, UNSAFE.getDouble(from, offset)); + } else if (type == Short.TYPE) { + UNSAFE.putShort(to, offset, UNSAFE.getShort(from, offset)); + } else if (type == Character.TYPE) { + UNSAFE.putChar(to, offset, UNSAFE.getChar(from, offset)); + } else if (type == Byte.TYPE) { + UNSAFE.putByte(to, offset, UNSAFE.getByte(from, offset)); + } else { + assert false : "unhandled property type: " + type; + } + } else { + Object obj = UNSAFE.getObject(from, offset); + UNSAFE.putObject(to, offset, trans == null ? obj : trans.apply(index, obj)); + } + } + } + + /** + * Gets the value of a field for a given object. + * + * @param object the object whose field is to be read + * @param index the index of the field (between 0 and {@link #getCount()}) + * @return the value of the specified field which will be boxed if the field type is primitive + */ + public Object get(Object object, int index) { + long offset = offsets[index]; + Class type = types[index]; + Object value = null; + if (type.isPrimitive()) { + if (type == Integer.TYPE) { + value = UNSAFE.getInt(object, offset); + } else if (type == Long.TYPE) { + value = UNSAFE.getLong(object, offset); + } else if (type == Boolean.TYPE) { + value = UNSAFE.getBoolean(object, offset); + } else if (type == Float.TYPE) { + value = UNSAFE.getFloat(object, offset); + } else if (type == Double.TYPE) { + value = UNSAFE.getDouble(object, offset); + } else if (type == Short.TYPE) { + value = UNSAFE.getShort(object, offset); + } else if (type == Character.TYPE) { + value = UNSAFE.getChar(object, offset); + } else if (type == Byte.TYPE) { + value = UNSAFE.getByte(object, offset); + } else { + assert false : "unhandled property type: " + type; + } + } else { + value = UNSAFE.getObject(object, offset); + } + return value; + } + + /** + * Gets the value of a field for a given object. + * + * @param object the object whose field is to be read + * @param index the index of the field (between 0 and {@link #getCount()}) + * @return the value of the specified field which will be boxed if the field type is primitive + */ + public long getRawPrimitive(Object object, int index) { + long offset = offsets[index]; + Class type = types[index]; + + if (type == Integer.TYPE) { + return UNSAFE.getInt(object, offset); + } else if (type == Long.TYPE) { + return UNSAFE.getLong(object, offset); + } else if (type == Boolean.TYPE) { + return UNSAFE.getBoolean(object, offset) ? 1 : 0; + } else if (type == Float.TYPE) { + return Float.floatToRawIntBits(UNSAFE.getFloat(object, offset)); + } else if (type == Double.TYPE) { + return Double.doubleToRawLongBits(UNSAFE.getDouble(object, offset)); + } else if (type == Short.TYPE) { + return UNSAFE.getShort(object, offset); + } else if (type == Character.TYPE) { + return UNSAFE.getChar(object, offset); + } else if (type == Byte.TYPE) { + return UNSAFE.getByte(object, offset); + } else { + throw GraalError.shouldNotReachHere(); + } + } + + /** + * Determines if a field in the domain of this object is the same as the field denoted by the + * same index in another {@link Fields} object. + */ + public boolean isSame(Fields other, int index) { + return other.offsets[index] == offsets[index]; + } + + public long[] getOffsets() { + return offsets; + } + + /** + * Gets the name of a field. + * + * @param index index of a field + */ + public String getName(int index) { + return names[index]; + } + + /** + * Gets the type of a field. + * + * @param index index of a field + */ + public Class getType(int index) { + return types[index]; + } + + public Class getDeclaringClass(int index) { + return declaringClasses[index]; + } + + /** + * Checks that a given field is assignable from a given value. + * + * @param index the index of the field to check + * @param value a value that will be assigned to the field + */ + private boolean checkAssignableFrom(Object object, int index, Object value) { + assert value == null || getType(index).isAssignableFrom(value.getClass()) : String.format("Field %s.%s of type %s is not assignable from %s", object.getClass().getSimpleName(), + getName(index), getType(index).getSimpleName(), value.getClass().getSimpleName()); + return true; + } + + public void set(Object object, int index, Object value) { + long offset = offsets[index]; + Class type = types[index]; + if (type.isPrimitive()) { + if (type == Integer.TYPE) { + UNSAFE.putInt(object, offset, (Integer) value); + } else if (type == Long.TYPE) { + UNSAFE.putLong(object, offset, (Long) value); + } else if (type == Boolean.TYPE) { + UNSAFE.putBoolean(object, offset, (Boolean) value); + } else if (type == Float.TYPE) { + UNSAFE.putFloat(object, offset, (Float) value); + } else if (type == Double.TYPE) { + UNSAFE.putDouble(object, offset, (Double) value); + } else if (type == Short.TYPE) { + UNSAFE.putShort(object, offset, (Short) value); + } else if (type == Character.TYPE) { + UNSAFE.putChar(object, offset, (Character) value); + } else if (type == Byte.TYPE) { + UNSAFE.putByte(object, offset, (Byte) value); + } else { + assert false : "unhandled property type: " + type; + } + } else { + assert checkAssignableFrom(object, index, value); + UNSAFE.putObject(object, offset, value); + } + } + + public void setRawPrimitive(Object object, int index, long value) { + long offset = offsets[index]; + Class type = types[index]; + if (type == Integer.TYPE) { + UNSAFE.putInt(object, offset, (int) value); + } else if (type == Long.TYPE) { + UNSAFE.putLong(object, offset, value); + } else if (type == Boolean.TYPE) { + UNSAFE.putBoolean(object, offset, value != 0); + } else if (type == Float.TYPE) { + UNSAFE.putFloat(object, offset, Float.intBitsToFloat((int) value)); + } else if (type == Double.TYPE) { + UNSAFE.putDouble(object, offset, Double.longBitsToDouble(value)); + } else if (type == Short.TYPE) { + UNSAFE.putShort(object, offset, (short) value); + } else if (type == Character.TYPE) { + UNSAFE.putChar(object, offset, (char) value); + } else if (type == Byte.TYPE) { + UNSAFE.putByte(object, offset, (byte) value); + } else { + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('['); + appendFields(sb); + return sb.append(']').toString(); + } + + public void appendFields(StringBuilder sb) { + for (int i = 0; i < offsets.length; i++) { + sb.append(i == 0 ? "" : ", ").append(getName(i)).append('@').append(offsets[i]); + } + } + + public boolean getBoolean(Object n, int i) { + assert types[i] == boolean.class; + return UNSAFE.getBoolean(n, offsets[i]); + } + + public byte getByte(Object n, int i) { + assert types[i] == byte.class; + return UNSAFE.getByte(n, offsets[i]); + } + + public short getShort(Object n, int i) { + assert types[i] == short.class; + return UNSAFE.getShort(n, offsets[i]); + } + + public char getChar(Object n, int i) { + assert types[i] == char.class; + return UNSAFE.getChar(n, offsets[i]); + } + + public int getInt(Object n, int i) { + assert types[i] == int.class; + return UNSAFE.getInt(n, offsets[i]); + } + + public long getLong(Object n, int i) { + assert types[i] == long.class; + return UNSAFE.getLong(n, offsets[i]); + } + + public float getFloat(Object n, int i) { + assert types[i] == float.class; + return UNSAFE.getFloat(n, offsets[i]); + } + + public double getDouble(Object n, int i) { + assert types[i] == double.class; + return UNSAFE.getDouble(n, offsets[i]); + } + + public Object getObject(Object object, int i) { + assert !types[i].isPrimitive(); + return UNSAFE.getObject(object, offsets[i]); + } + + public void putObject(Object object, int i, Object value) { + assert checkAssignableFrom(object, i, value); + UNSAFE.putObject(object, offsets[i], value); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/FieldsScanner.java 2016-12-07 13:47:51.758150742 -0800 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2014, 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.core.common; + +import static org.graalvm.compiler.core.common.UnsafeAccess.UNSAFE; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; + +import sun.misc.Unsafe; + +/** + * Scans the fields in a class hierarchy. + */ +public class FieldsScanner { + + /** + * Determines the offset (in bytes) of a field. + */ + public interface CalcOffset { + + long getOffset(Field field); + } + + /** + * Determines the offset (in bytes) of a field using {@link Unsafe#objectFieldOffset(Field)}. + */ + public static class DefaultCalcOffset implements CalcOffset { + + @Override + public long getOffset(Field field) { + return UNSAFE.objectFieldOffset(field); + } + } + + /** + * Describes a field in a class during {@linkplain FieldsScanner scanning}. + */ + public static class FieldInfo implements Comparable { + public final long offset; + public final String name; + public final Class type; + public final Class declaringClass; + + public FieldInfo(long offset, String name, Class type, Class declaringClass) { + this.offset = offset; + this.name = name; + this.type = type; + this.declaringClass = declaringClass; + } + + /** + * Sorts fields in ascending order by their {@link #offset}s. + */ + @Override + public int compareTo(FieldInfo o) { + return offset < o.offset ? -1 : (offset > o.offset ? 1 : 0); + } + + @Override + public String toString() { + return "[" + offset + "]" + name + ":" + type.getSimpleName(); + } + } + + private final FieldsScanner.CalcOffset calc; + + /** + * Fields not belonging to a more specific category defined by scanner subclasses are added to + * this list. + */ + public final ArrayList data = new ArrayList<>(); + + public FieldsScanner(FieldsScanner.CalcOffset calc) { + this.calc = calc; + } + + /** + * Scans the fields in a class hierarchy. + * + * @param clazz the class at which to start scanning + * @param endClazz scanning stops when this class is encountered (i.e. {@code endClazz} is not + * scanned) + */ + public void scan(Class clazz, Class endClazz, boolean includeTransient) { + Class currentClazz = clazz; + while (currentClazz != endClazz) { + for (Field field : currentClazz.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (!includeTransient && Modifier.isTransient(field.getModifiers())) { + continue; + } + long offset = calc.getOffset(field); + scanField(field, offset); + } + currentClazz = currentClazz.getSuperclass(); + } + } + + protected void scanField(Field field, long offset) { + data.add(new FieldsScanner.FieldInfo(offset, field.getName(), field.getType(), field.getDeclaringClass())); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java 2016-12-07 13:47:52.022162343 -0800 @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2009, 2016, 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.core.common; + +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.StableOptionValue; + +/** + * This class encapsulates options that control the behavior of the Graal compiler. + */ +// @formatter:off +public final class GraalOptions { + + @Option(help = "Use compiler intrinsifications.", type = OptionType.Debug) + public static final OptionValue Intrinsify = new OptionValue<>(true); + + @Option(help = "Inline calls with monomorphic type profile.", type = OptionType.Expert) + public static final OptionValue InlineMonomorphicCalls = new OptionValue<>(true); + + @Option(help = "Inline calls with polymorphic type profile.", type = OptionType.Expert) + public static final OptionValue InlinePolymorphicCalls = new OptionValue<>(true); + + @Option(help = "Inline calls with megamorphic type profile (i.e., not all types could be recorded).", type = OptionType.Expert) + public static final OptionValue InlineMegamorphicCalls = new OptionValue<>(true); + + @Option(help = "Maximum desired size of the compiler graph in nodes.", type = OptionType.User) + public static final OptionValue MaximumDesiredSize = new OptionValue<>(20000); + + @Option(help = "Minimum probability for methods to be inlined for megamorphic type profiles.", type = OptionType.Expert) + public static final OptionValue MegamorphicInliningMinMethodProbability = new OptionValue<>(0.33D); + + @Option(help = "Maximum level of recursive inlining.", type = OptionType.Expert) + public static final OptionValue MaximumRecursiveInlining = new OptionValue<>(5); + + @Option(help = "Graphs with less than this number of nodes are trivial and therefore always inlined.", type = OptionType.Expert) + public static final OptionValue TrivialInliningSize = new OptionValue<>(10); + + @Option(help = "Inlining is explored up to this number of nodes in the graph for each call site.", type = OptionType.Expert) + public static final OptionValue MaximumInliningSize = new OptionValue<>(300); + + @Option(help = "If the previous low-level graph size of the method exceeds the threshold, it is not inlined.", type = OptionType.Expert) + public static final OptionValue SmallCompiledLowLevelGraphSize = new OptionValue<>(300); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue LimitInlinedInvokes = new OptionValue<>(5.0); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue InlineEverything = new OptionValue<>(false); + + // escape analysis settings + @Option(help = "", type = OptionType.Debug) + public static final OptionValue PartialEscapeAnalysis = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue EscapeAnalysisIterations = new OptionValue<>(2); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue EscapeAnalysisLoopCutoff = new OptionValue<>(20); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue EscapeAnalyzeOnly = new OptionValue<>(null); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue MaximumEscapeAnalysisArrayLength = new OptionValue<>(32); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue PEAInliningHints = new OptionValue<>(false); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue TailDuplicationProbability = new OptionValue<>(0.5); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue TailDuplicationTrivialSize = new OptionValue<>(1); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue DeoptsToDisableOptimisticOptimization = new OptionValue<>(40); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue LoopPeeling = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue ReassociateInvariants = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue FullUnroll = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue LoopUnswitch = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue MinimumPeelProbability = new OptionValue<>(0.35f); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue LoopMaxUnswitch = new OptionValue<>(3); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue UseLoopLimitChecks = new OptionValue<>(true); + + // debugging settings + @Option(help = "", type = OptionType.Debug) + public static final OptionValue ZapStackOnMethodEntry = new OptionValue<>(false); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue DeoptALot = new OptionValue<>(false); + + @Option(help = "Stress the code emitting explicit exception throwing code.", type = OptionType.Debug) + public static final OptionValue StressExplicitExceptionCode = new OptionValue<>(false); + + @Option(help = "Stress the code emitting invokes with explicit exception edges.", type = OptionType.Debug) + public static final OptionValue StressInvokeWithExceptionNode = new OptionValue<>(false); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue VerifyPhases = new OptionValue<>(false); + + // Debug settings: + @Option(help = "", type = OptionType.Debug) + public static final OptionValue GCDebugStartCycle = new OptionValue<>(-1); + + @Option(help = "Perform platform dependent validation of the Java heap at returns", type = OptionType.Debug) + public static final OptionValue VerifyHeapAtReturn = new OptionValue<>(false); + + // Other printing settings + @Option(help = "Print profiling information when parsing a method's bytecode", type = OptionType.Debug) + public static final OptionValue PrintProfilingInformation = new OptionValue<>(false); + + @Option(help = "", type = OptionType.Debug) + public static final StableOptionValue TraceEscapeAnalysis = new StableOptionValue<>(false); + + // HotSpot command line options + @Option(help = "Print inlining optimizations", type = OptionType.Debug) + public static final OptionValue HotSpotPrintInlining = new OptionValue<>(false); + + // Register allocator debugging + @Option(help = "Comma separated list of registers that register allocation is limited to.", type = OptionType.Debug) + public static final OptionValue RegisterPressure = new OptionValue<>(null); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue ConditionalElimination = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue RemoveNeverExecutedCode = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue UseExceptionProbability = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue UseExceptionProbabilityForOperations = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OmitHotExceptionStacktrace = new OptionValue<>(false); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue GenSafepoints = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue GenLoopSafepoints = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue UseTypeCheckHints = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue InlineVTableStubs = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue AlwaysInlineVTableStubs = new OptionValue<>(false); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue ResolveClassBeforeStaticInvoke = new OptionValue<>(false); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue CanOmitFrame = new OptionValue<>(true); + + // Ahead of time compilation + @Option(help = "Try to avoid emitting code where patching is required", type = OptionType.Expert) + public static final OptionValue ImmutableCode = new OptionValue<>(false); + + @Option(help = "Generate position independent code", type = OptionType.Expert) + public static final OptionValue GeneratePIC = new OptionValue<>(false); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue CallArrayCopy = new OptionValue<>(true); + + // Runtime settings + @Option(help = "", type = OptionType.Expert) + public static final OptionValue SupportJsrBytecodes = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Expert) + public static final OptionValue OptAssumptions = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptConvertDeoptsToGuards = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptReadElimination = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue ReadEliminationMaxLoopVisits = new OptionValue<>(5); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptDeoptimizationGrouping = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptScheduleOutOfLoops = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptEliminateGuards = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptImplicitNullChecks = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptClearNonLiveLocals = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptLoopTransform = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptFloatingReads = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptEliminatePartiallyRedundantGuards = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptFilterProfiledTypes = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptDevirtualizeInvokesOptimistically = new OptionValue<>(true); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue OptPushThroughPi = new OptionValue<>(true); + + @Option(help = "Allow backend to match complex expressions.", type = OptionType.Debug) + public static final OptionValue MatchExpressions = new OptionValue<>(true); + + @Option(help = "Enable counters for various paths in snippets.", type = OptionType.Debug) + public static final OptionValue SnippetCounters = new OptionValue<>(false); + + @Option(help = "Eagerly construct extra snippet info.", type = OptionType.Debug) + public static final OptionValue EagerSnippets = new OptionValue<>(false); + + @Option(help = "Use a cache for snippet graphs.", type = OptionType.Debug) + public static final OptionValue UseSnippetGraphCache = new OptionValue<>(true); + + @Option(help = "Enable expensive assertions", type = OptionType.Debug) + public static final OptionValue DetailedAsserts = new StableOptionValue() { + @Override + protected Boolean defaultValue() { + boolean enabled = false; + // turn detailed assertions on when the general assertions are on (misusing the assert keyword for this) + assert (enabled = true) == true; + return enabled; + } + }; + + @Option(help = "Enable Graal instrumentation") + public static final OptionValue UseGraalInstrumentation = new OptionValue<>(false); + + @Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug) + public static final OptionValue TraceRA = new OptionValue<>(false); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java 2016-12-07 13:47:52.287173987 -0800 @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2014, 2015, 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.core.common; + +import java.util.ArrayList; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; + +/** + * Represents the type of values in the LIR. It is composed of a {@link PlatformKind} that gives the + * low level representation of the value, and a {@link #referenceMask} that describes the location + * of object references in the value, and optionally a {@link #derivedReferenceBase}. + * + *

Constructing {@link LIRKind} instances

+ * + * During LIR generation, every new {@link Value} should get a {@link LIRKind} of the correct + * {@link PlatformKind} that also contains the correct reference information. {@linkplain LIRKind + * LIRKinds} should be created as follows: + * + *

+ * If the result value is created from one or more input values, the {@link LIRKind} should be + * created with {@link LIRKind#combine}(inputs). If the result has a different {@link PlatformKind} + * than the inputs, {@link LIRKind#combine}(inputs).{@link #changeType}(resultKind) should be used. + *

+ * If the result is an exact copy of one of the inputs, {@link Value#getValueKind()} can be used. + * Note that this is only correct for move-like operations, like conditional move or + * compare-and-swap. For convert operations, {@link LIRKind#combine} should be used. + *

+ * If it is known that the result will be a reference (e.g. pointer arithmetic where the end result + * is a valid oop), {@link LIRKind#reference} should be used. + *

+ * If it is known that the result will neither be a reference nor be derived from a reference, + * {@link LIRKind#value} can be used. If the operation producing this value has inputs, this is very + * likely wrong, and {@link LIRKind#combine} should be used instead. + *

+ * If it is known that the result is derived from a reference in a way that the garbage collector + * can not track, {@link LIRKind#unknownReference} can be used. In most cases, + * {@link LIRKind#combine} should be used instead, since it is able to detect this automatically. + */ +public final class LIRKind extends ValueKind { + + private final int referenceMask; + + private AllocatableValue derivedReferenceBase; + + private static final int UNKNOWN_REFERENCE = -1; + + public static final LIRKind Illegal = unknownReference(ValueKind.Illegal.getPlatformKind()); + + private LIRKind(PlatformKind platformKind, int referenceMask, AllocatableValue derivedReferenceBase) { + super(platformKind); + this.referenceMask = referenceMask; + this.derivedReferenceBase = derivedReferenceBase; + + assert derivedReferenceBase == null || !derivedReferenceBase.getValueKind(LIRKind.class).isDerivedReference() : "derived reference can't have another derived reference as base"; + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a primitive value. Should + * be only used when it's guaranteed that the value is not even indirectly derived from a + * reference. Otherwise, {@link #combine(Value...)} should be used instead. + */ + public static LIRKind value(PlatformKind platformKind) { + return new LIRKind(platformKind, 0, null); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a single tracked oop + * reference. + */ + public static LIRKind reference(PlatformKind platformKind) { + return derivedReference(platformKind, null); + } + + /** + * Create the correct {@link LIRKind} for a given {@link Architecture} and {@link JavaKind}. + */ + public static LIRKind fromJavaKind(Architecture arch, JavaKind javaKind) { + PlatformKind platformKind = arch.getPlatformKind(javaKind); + if (javaKind.isObject()) { + return LIRKind.reference(platformKind); + } else { + return LIRKind.value(platformKind); + } + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a derived reference. + */ + public static LIRKind derivedReference(PlatformKind platformKind, AllocatableValue base) { + int length = platformKind.getVectorLength(); + assert 0 < length && length < 32 : "vector of " + length + " references not supported"; + return new LIRKind(platformKind, (1 << length) - 1, base); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a value that is derived + * from a reference in a non-linear way. Values of this {@link LIRKind} can not be live at + * safepoints. In most cases, this should not be called directly. {@link #combine} should be + * used instead to automatically propagate this information. + */ + public static LIRKind unknownReference(PlatformKind platformKind) { + return new LIRKind(platformKind, UNKNOWN_REFERENCE, null); + } + + /** + * Create a derived reference. + * + * @param base An {@link AllocatableValue} containing the base pointer of the derived reference. + */ + public LIRKind makeDerivedReference(AllocatableValue base) { + assert !isUnknownReference() && derivedReferenceBase == null; + if (Value.ILLEGAL.equals(base)) { + return makeUnknownReference(); + } else { + if (isValue()) { + return derivedReference(getPlatformKind(), base); + } else { + return new LIRKind(getPlatformKind(), referenceMask, base); + } + } + } + + /** + * Derive a new type from inputs. The result will have the {@link PlatformKind} of one of the + * inputs. If all inputs are values, the result is a value. Otherwise, the result is an unknown + * reference. + * + * This method should be used to construct the result {@link LIRKind} of any operation that + * modifies values (e.g. arithmetics). + */ + public static LIRKind combine(Value... inputs) { + assert inputs.length > 0; + for (Value input : inputs) { + LIRKind kind = input.getValueKind(LIRKind.class); + if (kind.isUnknownReference()) { + return kind; + } else if (!kind.isValue()) { + return kind.makeUnknownReference(); + } + } + + // all inputs are values, just return one of them + return inputs[0].getValueKind(LIRKind.class); + } + + /** + * Merge the types of the inputs. The result will have the {@link PlatformKind} of one of the + * inputs. If all inputs are values (references), the result is a value (reference). Otherwise, + * the result is an unknown reference. + * + * This method should be used to construct the result {@link LIRKind} of merge operation that + * does not modify values (e.g. phis). + */ + public static LIRKind merge(Value... inputs) { + assert inputs.length > 0; + ArrayList kinds = new ArrayList<>(inputs.length); + for (int i = 0; i < inputs.length; i++) { + kinds.add(inputs[i].getValueKind(LIRKind.class)); + } + return merge(kinds); + } + + /** + * Helper method to construct derived reference kinds. Returns the base value of a reference or + * derived reference. For values it returns {@code null}, and for unknown references it returns + * {@link Value#ILLEGAL}. + */ + public static AllocatableValue derivedBaseFromValue(AllocatableValue value) { + ValueKind valueKind = value.getValueKind(); + if (valueKind instanceof LIRKind) { + LIRKind kind = value.getValueKind(LIRKind.class); + if (kind.isValue()) { + return null; + } else if (kind.isDerivedReference()) { + return kind.getDerivedReferenceBase(); + } else if (kind.isUnknownReference()) { + return Value.ILLEGAL; + } else { + // kind is a reference + return value; + } + } else { + return Value.ILLEGAL; + } + } + + /** + * Helper method to construct derived reference kinds. If one of {@code base1} or {@code base2} + * are set, it creates a derived reference using it as the base. If both are set, the result is + * an unknown reference. + */ + public static LIRKind combineDerived(LIRKind kind, AllocatableValue base1, AllocatableValue base2) { + if (base1 == null && base2 == null) { + return kind; + } else if (base1 == null) { + return kind.makeDerivedReference(base2); + } else if (base2 == null) { + return kind.makeDerivedReference(base1); + } else { + return kind.makeUnknownReference(); + } + } + + /** + * @see #merge(Value...) + */ + public static LIRKind merge(Iterable kinds) { + LIRKind mergeKind = null; + + for (LIRKind kind : kinds) { + + if (kind.isUnknownReference()) { + /** + * Kind is an unknown reference, therefore the result can only be also an unknown + * reference. + */ + mergeKind = kind; + break; + } + if (mergeKind == null) { + mergeKind = kind; + continue; + } + + if (kind.isValue()) { + /* Kind is a value. */ + if (mergeKind.referenceMask != 0) { + /* + * Inputs consists of values and references. Make the result an unknown + * reference. + */ + mergeKind = mergeKind.makeUnknownReference(); + break; + } + /* Check that other inputs are also values. */ + } else { + /* Kind is a reference. */ + if (mergeKind.referenceMask != kind.referenceMask) { + /* + * Reference maps do not match so the result can only be an unknown reference. + */ + mergeKind = mergeKind.makeUnknownReference(); + break; + } + } + + } + assert mergeKind != null && verifyMerge(mergeKind, kinds); + + // all inputs are values or references, just return one of them + return mergeKind; + } + + private static boolean verifyMerge(LIRKind mergeKind, Iterable kinds) { + for (LIRKind kind : kinds) { + assert mergeKind == null || verifyMoveKinds(mergeKind, kind) : String.format("Input kinds do not match %s vs. %s", mergeKind, kind); + } + return true; + } + + /** + * Create a new {@link LIRKind} with the same reference information and a new + * {@linkplain #getPlatformKind platform kind}. If the new kind is a longer vector than this, + * the new elements are marked as untracked values. + */ + @Override + public LIRKind changeType(PlatformKind newPlatformKind) { + if (newPlatformKind == getPlatformKind()) { + return this; + } else if (isUnknownReference()) { + return unknownReference(newPlatformKind); + } else if (referenceMask == 0) { + // value type + return LIRKind.value(newPlatformKind); + } else { + // reference type + int newLength = Math.min(32, newPlatformKind.getVectorLength()); + int newReferenceMask = referenceMask & (0xFFFFFFFF >>> (32 - newLength)); + assert newReferenceMask != UNKNOWN_REFERENCE; + return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase); + } + } + + /** + * Create a new {@link LIRKind} with a new {@linkplain #getPlatformKind platform kind}. If the + * new kind is longer than this, the reference positions are repeated to fill the vector. + */ + public LIRKind repeat(PlatformKind newPlatformKind) { + if (isUnknownReference()) { + return unknownReference(newPlatformKind); + } else if (referenceMask == 0) { + // value type + return LIRKind.value(newPlatformKind); + } else { + // reference type + int oldLength = getPlatformKind().getVectorLength(); + int newLength = newPlatformKind.getVectorLength(); + assert oldLength <= newLength && newLength < 32 && (newLength % oldLength) == 0; + + // repeat reference mask to fill new kind + int newReferenceMask = 0; + for (int i = 0; i < newLength; i += getPlatformKind().getVectorLength()) { + newReferenceMask |= referenceMask << i; + } + + assert newReferenceMask != UNKNOWN_REFERENCE; + return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase); + } + } + + /** + * Create a new {@link LIRKind} with the same type, but marked as containing an + * {@link LIRKind#unknownReference}. + */ + public LIRKind makeUnknownReference() { + return new LIRKind(getPlatformKind(), UNKNOWN_REFERENCE, null); + } + + /** + * Check whether this value is a derived reference. + */ + public boolean isDerivedReference() { + return getDerivedReferenceBase() != null; + } + + /** + * Get the base value of a derived reference. + */ + public AllocatableValue getDerivedReferenceBase() { + return derivedReferenceBase; + } + + /** + * Change the base value of a derived reference. This must be called on derived references only. + */ + public void setDerivedReferenceBase(AllocatableValue derivedReferenceBase) { + assert isDerivedReference(); + this.derivedReferenceBase = derivedReferenceBase; + } + + /** + * Check whether this value is derived from a reference in a non-linear way. If this returns + * {@code true}, this value must not be live at safepoints. + */ + public boolean isUnknownReference() { + return referenceMask == UNKNOWN_REFERENCE; + } + + public static boolean isUnknownReference(ValueKind kind) { + if (kind instanceof LIRKind) { + return ((LIRKind) kind).isUnknownReference(); + } else { + return true; + } + } + + public static boolean isUnknownReference(Value value) { + return isUnknownReference(value.getValueKind()); + } + + public int getReferenceCount() { + assert !isUnknownReference(); + return Integer.bitCount(referenceMask); + } + + /** + * Check whether the {@code idx}th part of this value is a reference that must be tracked at + * safepoints. + * + * @param idx The index into the vector if this is a vector kind. Must be 0 if this is a scalar + * kind. + */ + public boolean isReference(int idx) { + assert 0 <= idx && idx < getPlatformKind().getVectorLength() : "invalid index " + idx + " in " + this; + return !isUnknownReference() && (referenceMask & 1 << idx) != 0; + } + + /** + * Check whether this kind is a value type that doesn't need to be tracked at safepoints. + */ + public boolean isValue() { + return referenceMask == 0; + } + + public static boolean isValue(ValueKind kind) { + if (kind instanceof LIRKind) { + return ((LIRKind) kind).isValue(); + } else { + return false; + } + } + + public static boolean isValue(Value value) { + return isValue(value.getValueKind()); + } + + @Override + public String toString() { + if (isValue()) { + return getPlatformKind().name(); + } else if (isUnknownReference()) { + return getPlatformKind().name() + "[*]"; + } else { + StringBuilder ret = new StringBuilder(); + ret.append(getPlatformKind().name()); + ret.append('['); + for (int i = 0; i < getPlatformKind().getVectorLength(); i++) { + if (isReference(i)) { + ret.append('.'); + } else { + ret.append(' '); + } + } + ret.append(']'); + return ret.toString(); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getPlatformKind() == null) ? 0 : getPlatformKind().hashCode()); + result = prime * result + referenceMask; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof LIRKind)) { + return false; + } + + LIRKind other = (LIRKind) obj; + return getPlatformKind() == other.getPlatformKind() && referenceMask == other.referenceMask; + } + + public static boolean verifyMoveKinds(ValueKind dst, ValueKind src) { + if (src.equals(dst)) { + return true; + } + if (src.getPlatformKind().equals(dst.getPlatformKind())) { + return !isUnknownReference(src) || isUnknownReference(dst); + } + return false; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LinkedIdentityHashMap.java 2016-12-07 13:47:52.553185676 -0800 @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2014, 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.core.common; + +import java.util.AbstractSet; +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.Consumer; + +/** + * A map that combines {@link IdentityHashMap} with {@link LinkedHashMap} for the purpose of + * ensuring a deterministic execution order during a capturing compilation. + */ +final class LinkedIdentityHashMap implements Map { + + private final LinkedHashMap, V> map; + + LinkedIdentityHashMap() { + map = new LinkedHashMap<>(); + } + + LinkedIdentityHashMap(Map m) { + map = new LinkedHashMap<>(m.size()); + putAll(m); + } + + LinkedIdentityHashMap(int expectedMaxSize) { + map = new LinkedHashMap<>(expectedMaxSize); + } + + /** + * Wrapper for an object that gives uses the object's identity for the purpose of equality + * comparisons and computing a hash code. + */ + static final class Id { + final T object; + + Id(T object) { + assert object != null; + this.object = object; + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object obj) { + return obj instanceof Id && ((Id) obj).object == object; + } + + @Override + public int hashCode() { + return System.identityHashCode(object); + } + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return map.containsKey(id(key)); + } + + @SuppressWarnings("unchecked") + private Id id(Object key) { + if (key == null) { + return null; + } + return new Id<>((K) key); + } + + @Override + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + @Override + public V get(Object key) { + return map.get(id(key)); + } + + @Override + public V put(K key, V value) { + return map.put(id(key), value); + } + + @Override + public V remove(Object key) { + return map.remove(id(key)); + } + + @Override + @SuppressWarnings("unchecked") + public void putAll(Map m) { + if (m == null) { + throw new NullPointerException(); + } + if (m.getClass() == getClass()) { + LinkedIdentityHashMap that = (LinkedIdentityHashMap) m; + map.putAll(that.map); + + } else { + for (K key : m.keySet()) { + map.put(id(key), m.get(key)); + } + } + } + + @Override + public void clear() { + map.clear(); + } + + final class KeySet extends AbstractSet { + @Override + public int size() { + return map.size(); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public Iterator iterator() { + return new Iterator() { + final Iterator> i = map.keySet().iterator(); + + @Override + public boolean hasNext() { + return i.hasNext(); + } + + @Override + public K next() { + return i.next().object; + } + + @Override + public void remove() { + i.remove(); + } + }; + } + + @Override + public boolean contains(Object o) { + return containsKey(o); + } + + @Override + public boolean remove(Object o) { + return LinkedIdentityHashMap.this.remove(o) != null; + } + + @Override + public Spliterator spliterator() { + return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT); + } + + @Override + public void forEach(Consumer action) { + throw new UnsupportedOperationException(); + } + } + + @Override + public Set keySet() { + return new KeySet(); + } + + @Override + public Collection values() { + return map.values(); + } + + final class EntrySet extends AbstractSet> { + @Override + public int size() { + return map.size(); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public Iterator> iterator() { + return new Iterator>() { + final Iterator, V>> i = map.entrySet().iterator(); + + @Override + public boolean hasNext() { + return i.hasNext(); + } + + @Override + public Map.Entry next() { + Map.Entry, V> e = i.next(); + return new Map.Entry() { + + @Override + public K getKey() { + return e.getKey().object; + } + + @Override + public V getValue() { + return e.getValue(); + } + + @Override + public V setValue(V value) { + return e.setValue(value); + } + }; + } + + @Override + public void remove() { + i.remove(); + } + }; + } + + @Override + public boolean contains(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public Spliterator> spliterator() { + throw new UnsupportedOperationException(); + } + + @Override + public void forEach(Consumer> action) { + throw new UnsupportedOperationException(); + } + } + + @Override + public Set> entrySet() { + return new EntrySet(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LocationIdentity.java 2016-12-07 13:47:52.818197320 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011, 2016, 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.core.common; + +import java.util.IdentityHashMap; + +// JaCoCo Exclude + +/** + * Marker interface for location identities. A different location identity of two memory accesses + * guarantees that the two accesses do not interfere. + * + * 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 IdentityHashMap}s with {@link LocationIdentity} values as keys. + */ +public abstract class LocationIdentity { + + private static final class AnyLocationIdentity extends LocationIdentity { + @Override + public boolean isImmutable() { + return false; + } + + @Override + public String toString() { + return "ANY_LOCATION"; + } + } + + public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity(); + + public static LocationIdentity any() { + return ANY_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. + */ + public abstract boolean isImmutable(); + + public final boolean isMutable() { + return !isImmutable(); + } + + public final boolean isAny() { + return this == ANY_LOCATION; + } + + public final boolean isSingle() { + return this != ANY_LOCATION; + } + + public final boolean overlaps(LocationIdentity other) { + return isAny() || other.isAny() || this.equals(other); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/SuppressFBWarnings.java 2016-12-07 13:47:53.082208921 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, 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.core.common; + +/** + * Used to suppress FindBugs warnings. + */ +public @interface SuppressFBWarnings { + /** + * The set of FindBugs + * warnings that are to be + * suppressed in annotated element. The value can be a bug category, kind or pattern. + */ + String[] value(); + + /** + * Reason why the warning is suppressed. + */ + String justification(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/UnsafeAccess.java 2016-12-07 13:47:53.346220521 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2012, 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.core.common; + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + +/** + * Package private access to the {@link Unsafe} capability. + */ +class UnsafeAccess { + + static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + // Fast path when we are trusted. + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + // Slow path when we are not trusted. + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java 2016-12-07 13:47:53.612232210 -0800 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016, 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.core.common.alloc; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Collection; +import java.util.Deque; + +import org.graalvm.compiler.core.common.alloc.TraceBuilderResult.TrivialTracePredicate; +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Indent; + +/** + * Computes traces by selecting the unhandled block with the highest execution frequency and going + * in both directions, up and down, as long as possible. + */ +public final class BiDirectionalTraceBuilder { + + public static TraceBuilderResult computeTraces(AbstractBlockBase startBlock, AbstractBlockBase[] blocks, TrivialTracePredicate pred) { + return new BiDirectionalTraceBuilder(blocks).build(startBlock, blocks, pred); + } + + private final Deque> worklist; + private final BitSet processed; + private final Trace[] blockToTrace; + + private BiDirectionalTraceBuilder(AbstractBlockBase[] blocks) { + processed = new BitSet(blocks.length); + worklist = createQueue(blocks); + blockToTrace = new Trace[blocks.length]; + } + + private static Deque> createQueue(AbstractBlockBase[] blocks) { + ArrayList> queue = new ArrayList<>(Arrays.asList(blocks)); + queue.sort(BiDirectionalTraceBuilder::compare); + return new ArrayDeque<>(queue); + } + + private static int compare(AbstractBlockBase a, AbstractBlockBase b) { + return Double.compare(b.probability(), a.probability()); + } + + private boolean processed(AbstractBlockBase b) { + return processed.get(b.getId()); + } + + @SuppressWarnings("try") + private TraceBuilderResult build(AbstractBlockBase startBlock, AbstractBlockBase[] blocks, TrivialTracePredicate pred) { + try (Indent indent = Debug.logAndIndent("BiDirectionalTraceBuilder: start trace building")) { + ArrayList traces = buildTraces(); + assert traces.get(0).getBlocks()[0].equals(startBlock) : "The first traces always contains the start block"; + return TraceBuilderResult.create(blocks, traces, blockToTrace, pred); + } + } + + protected ArrayList buildTraces() { + ArrayList traces = new ArrayList<>(); + // process worklist + while (!worklist.isEmpty()) { + AbstractBlockBase block = worklist.pollFirst(); + assert block != null; + if (!processed(block)) { + Trace trace = new Trace(startTrace(block)); + for (AbstractBlockBase traceBlock : trace.getBlocks()) { + blockToTrace[traceBlock.getId()] = trace; + } + trace.setId(traces.size()); + traces.add(trace); + } + } + return traces; + } + + /** + * Build a new trace starting at {@code block}. + */ + @SuppressWarnings("try") + private Collection> startTrace(AbstractBlockBase block) { + ArrayDeque> trace = new ArrayDeque<>(); + try (Indent i = Debug.logAndIndent("StartTrace: %s", block)) { + try (Indent indentFront = Debug.logAndIndent("Head:")) { + for (AbstractBlockBase currentBlock = block; currentBlock != null; currentBlock = selectPredecessor(currentBlock)) { + addBlockToTrace(currentBlock); + trace.addFirst(currentBlock); + } + } + /* Number head blocks. Can not do this in the loop as we go backwards. */ + int blockNr = 0; + for (AbstractBlockBase b : trace) { + b.setLinearScanNumber(blockNr++); + } + + try (Indent indentBack = Debug.logAndIndent("Tail:")) { + for (AbstractBlockBase currentBlock = selectSuccessor(block); currentBlock != null; currentBlock = selectSuccessor(currentBlock)) { + addBlockToTrace(currentBlock); + trace.addLast(currentBlock); + /* This time we can number the blocks immediately as we go forwards. */ + currentBlock.setLinearScanNumber(blockNr++); + } + } + } + Debug.log("Trace: %s", trace); + return trace; + } + + private void addBlockToTrace(AbstractBlockBase currentBlock) { + Debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability()); + processed.set(currentBlock.getId()); + } + + /** + * @return The unprocessed predecessor with the highest probability, or {@code null}. + */ + private AbstractBlockBase selectPredecessor(AbstractBlockBase currentBlock) { + AbstractBlockBase next = null; + for (AbstractBlockBase pred : currentBlock.getPredecessors()) { + if (!processed(pred) && !isBackEdge(pred, currentBlock) && (next == null || pred.probability() > next.probability())) { + next = pred; + } + } + return next; + } + + private static boolean isBackEdge(AbstractBlockBase from, AbstractBlockBase to) { + assert Arrays.asList(from.getSuccessors()).contains(to) : "No edge from " + from + " to " + to; + return from.isLoopEnd() && to.isLoopHeader() && from.getLoop().equals(to.getLoop()); + } + + /** + * @return The unprocessed successor with the highest probability, or {@code null}. + */ + private AbstractBlockBase selectSuccessor(AbstractBlockBase currentBlock) { + AbstractBlockBase next = null; + for (AbstractBlockBase succ : currentBlock.getSuccessors()) { + if (!processed(succ) && (next == null || succ.probability() > next.probability())) { + next = succ; + } + } + return next; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java 2016-12-07 13:47:53.876243810 -0800 @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2009, 2011, 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.core.common.alloc; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Comparator; +import java.util.List; +import java.util.PriorityQueue; + +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.core.common.cfg.Loop; + +/** + * Computes an ordering of the block that can be used by the linear scan register allocator and the + * machine code generator. The machine code generation order will start with the first block and + * produce a straight sequence always following the most likely successor. Then it will continue + * with the most likely path that was left out during this process. The process iteratively + * continues until all blocks are scheduled. Additionally, it is guaranteed that all blocks of a + * loop are scheduled before any block following the loop is scheduled. + * + * The machine code generator order includes reordering of loop headers such that the backward jump + * is a conditional jump if there is only one loop end block. Additionally, the target of loop + * backward jumps are always marked as aligned. Aligning the target of conditional jumps does not + * bring a measurable benefit and is therefore avoided to keep the code size small. + * + * The linear scan register allocator order has an additional mechanism that prevents merge nodes + * from being scheduled if there is at least one highly likely predecessor still unscheduled. This + * increases the probability that the merge node and the corresponding predecessor are more closely + * together in the schedule thus decreasing the probability for inserted phi moves. Also, the + * algorithm sets the linear scan order number of the block that corresponds to its index in the + * linear scan order. + */ +public final class ComputeBlockOrder { + + /** + * The initial capacities of the worklists used for iteratively finding the block order. + */ + private static final int INITIAL_WORKLIST_CAPACITY = 10; + + /** + * Divisor used for degrading the probability of the current path versus unscheduled paths at a + * merge node when calculating the linear scan order. A high value means that predecessors of + * merge nodes are more likely to be scheduled before the merge node. + */ + private static final int PENALTY_VERSUS_UNSCHEDULED = 10; + + /** + * Computes the block order used for the linear scan register allocator. + * + * @return sorted list of blocks + */ + public static > AbstractBlockBase[] computeLinearScanOrder(int blockCount, T startBlock) { + List order = new ArrayList<>(); + BitSet visitedBlocks = new BitSet(blockCount); + PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks); + computeLinearScanOrder(order, worklist, visitedBlocks); + assert checkOrder(order, blockCount); + return order.toArray(new AbstractBlockBase[0]); + } + + /** + * Computes the block order used for code emission. + * + * @return sorted list of blocks + */ + public static > AbstractBlockBase[] computeCodeEmittingOrder(int blockCount, T startBlock) { + List order = new ArrayList<>(); + BitSet visitedBlocks = new BitSet(blockCount); + PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks); + computeCodeEmittingOrder(order, worklist, visitedBlocks); + assert checkOrder(order, blockCount); + return order.toArray(new AbstractBlockBase[0]); + } + + /** + * Iteratively adds paths to the code emission block order. + */ + private static > void computeCodeEmittingOrder(List order, PriorityQueue worklist, BitSet visitedBlocks) { + while (!worklist.isEmpty()) { + T nextImportantPath = worklist.poll(); + addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks); + } + } + + /** + * Iteratively adds paths to the linear scan block order. + */ + private static > void computeLinearScanOrder(List order, PriorityQueue worklist, BitSet visitedBlocks) { + while (!worklist.isEmpty()) { + T nextImportantPath = worklist.poll(); + do { + nextImportantPath = addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks); + } while (nextImportantPath != null); + } + } + + /** + * Initializes the priority queue used for the work list of blocks and adds the start block. + */ + private static > PriorityQueue initializeWorklist(T startBlock, BitSet visitedBlocks) { + PriorityQueue result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator<>()); + result.add(startBlock); + visitedBlocks.set(startBlock.getId()); + return result; + } + + /** + * Add a linear path to the linear scan order greedily following the most likely successor. + */ + private static > T addPathToLinearScanOrder(T block, List order, PriorityQueue worklist, BitSet visitedBlocks) { + block.setLinearScanNumber(order.size()); + order.add(block); + T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks); + enqueueSuccessors(block, worklist, visitedBlocks); + if (mostLikelySuccessor != null) { + if (!mostLikelySuccessor.isLoopHeader() && mostLikelySuccessor.getPredecessorCount() > 1) { + // We are at a merge. Check probabilities of predecessors that are not yet + // scheduled. + double unscheduledSum = 0.0; + for (T pred : mostLikelySuccessor.getPredecessors()) { + if (pred.getLinearScanNumber() == -1) { + unscheduledSum += pred.probability(); + } + } + + if (unscheduledSum > block.probability() / PENALTY_VERSUS_UNSCHEDULED) { + // Add this merge only after at least one additional predecessor gets scheduled. + visitedBlocks.clear(mostLikelySuccessor.getId()); + return null; + } + } + return mostLikelySuccessor; + } + return null; + } + + /** + * Add a linear path to the code emission order greedily following the most likely successor. + */ + private static > void addPathToCodeEmittingOrder(T initialBlock, List order, PriorityQueue worklist, BitSet visitedBlocks) { + T block = initialBlock; + while (block != null) { + // Skip loop headers if there is only a single loop end block to + // make the backward jump be a conditional jump. + if (!skipLoopHeader(block)) { + + // Align unskipped loop headers as they are the target of the backward jump. + if (block.isLoopHeader()) { + block.setAlign(true); + } + addBlock(block, order); + } + + Loop loop = block.getLoop(); + if (block.isLoopEnd() && skipLoopHeader(loop.getHeader())) { + + // This is the only loop end of a skipped loop header. + // Add the header immediately afterwards. + addBlock(loop.getHeader(), order); + + // Make sure the loop successors of the loop header are aligned + // as they are the target + // of the backward jump. + for (T successor : loop.getHeader().getSuccessors()) { + if (successor.getLoopDepth() == block.getLoopDepth()) { + successor.setAlign(true); + } + } + } + + T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks); + enqueueSuccessors(block, worklist, visitedBlocks); + block = mostLikelySuccessor; + } + } + + /** + * Adds a block to the ordering. + */ + private static > void addBlock(T header, List order) { + assert !order.contains(header) : "Cannot insert block twice"; + order.add(header); + } + + /** + * Find the highest likely unvisited successor block of a given block. + */ + private static > T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks) { + T result = null; + for (T successor : block.getSuccessors()) { + assert successor.probability() >= 0.0 : "Probabilities must be positive"; + if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && (result == null || successor.probability() >= result.probability())) { + result = successor; + } + } + if (result != null) { + visitedBlocks.set(result.getId()); + } + return result; + } + + /** + * Add successor blocks into the given work list if they are not already marked as visited. + */ + private static > void enqueueSuccessors(T block, PriorityQueue worklist, BitSet visitedBlocks) { + for (T successor : block.getSuccessors()) { + if (!visitedBlocks.get(successor.getId())) { + visitedBlocks.set(successor.getId()); + worklist.add(successor); + } + } + } + + /** + * Skip the loop header block if the loop consists of more than one block and it has only a + * single loop end block. + */ + private static > boolean skipLoopHeader(AbstractBlockBase block) { + return (block.isLoopHeader() && !block.isLoopEnd() && block.getLoop().numBackedges() == 1); + } + + /** + * Checks that the ordering contains the expected number of blocks. + */ + private static boolean checkOrder(List> order, int expectedBlockCount) { + assert order.size() == expectedBlockCount : String.format("Number of blocks in ordering (%d) does not match expected block count (%d)", order.size(), expectedBlockCount); + return true; + } + + /** + * Comparator for sorting blocks based on loop depth and probability. + */ + private static class BlockOrderComparator> implements Comparator { + + @Override + public int compare(T a, T b) { + // Loop blocks before any loop exit block. + int diff = b.getLoopDepth() - a.getLoopDepth(); + if (diff != 0) { + return diff; + } + + // Blocks with high probability before blocks with low probability. + if (a.probability() > b.probability()) { + return -1; + } else { + return 1; + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java 2016-12-07 13:47:54.142255498 -0800 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2015, 2015, 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.core.common.alloc; + +import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure; + +import java.util.HashMap; +import java.util.Map; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.meta.PlatformKind; + +import org.graalvm.compiler.core.common.GraalOptions; + +/** + * Configuration for register allocation. This is different to {@link RegisterConfig} as it only + * returns registers specified by {@link GraalOptions#RegisterPressure}. + */ +public class RegisterAllocationConfig { + + public static final class AllocatableRegisters { + public final Register[] allocatableRegisters; + public final int minRegisterNumber; + public final int maxRegisterNumber; + + public AllocatableRegisters(RegisterArray allocatableRegisters, int minRegisterNumber, int maxRegisterNumber) { + this.allocatableRegisters = allocatableRegisters.toArray(); + this.minRegisterNumber = minRegisterNumber; + this.maxRegisterNumber = maxRegisterNumber; + assert verify(allocatableRegisters, minRegisterNumber, maxRegisterNumber); + } + + private static boolean verify(RegisterArray allocatableRegisters, int minRegisterNumber, int maxRegisterNumber) { + int min = Integer.MAX_VALUE; + int max = Integer.MIN_VALUE; + for (Register reg : allocatableRegisters) { + int number = reg.number; + if (number < min) { + min = number; + } + if (number > max) { + max = number; + } + } + assert minRegisterNumber == min; + assert maxRegisterNumber == max; + return true; + } + } + + public static final String ALL_REGISTERS = ""; + + private static Register findRegister(String name, RegisterArray all) { + for (Register reg : all) { + if (reg.name.equals(name)) { + return reg; + } + } + throw new IllegalArgumentException("register " + name + " is not allocatable"); + } + + protected RegisterArray initAllocatable(RegisterArray registers) { + if (RegisterPressure.getValue() != null && !RegisterPressure.getValue().equals(ALL_REGISTERS)) { + String[] names = RegisterPressure.getValue().split(","); + Register[] regs = new Register[names.length]; + for (int i = 0; i < names.length; i++) { + regs[i] = findRegister(names[i], registers); + } + return new RegisterArray(regs); + } + + return registers; + } + + protected final RegisterConfig registerConfig; + private final Map categorized = new HashMap<>(); + private RegisterArray cachedRegisters; + + public RegisterAllocationConfig(RegisterConfig registerConfig) { + assert registerConfig != null; + this.registerConfig = registerConfig; + } + + /** + * Gets the set of registers that can be used by the register allocator for a value of a + * particular kind. + */ + public AllocatableRegisters getAllocatableRegisters(PlatformKind kind) { + PlatformKind.Key key = kind.getKey(); + if (categorized.containsKey(key)) { + AllocatableRegisters val = categorized.get(key); + return val; + } + AllocatableRegisters ret = createAllocatableRegisters(registerConfig.filterAllocatableRegisters(kind, getAllocatableRegisters())); + categorized.put(key, ret); + return ret; + } + + protected AllocatableRegisters createAllocatableRegisters(RegisterArray registers) { + int min = Integer.MAX_VALUE; + int max = Integer.MIN_VALUE; + for (Register reg : registers) { + int number = reg.number; + if (number < min) { + min = number; + } + if (number > max) { + max = number; + } + } + assert min < max; + return new AllocatableRegisters(registers, min, max); + + } + + /** + * Gets the set of registers that can be used by the register allocator. + */ + public RegisterArray getAllocatableRegisters() { + if (cachedRegisters == null) { + cachedRegisters = initAllocatable(registerConfig.getAllocatableRegisters()); + } + assert cachedRegisters != null; + return cachedRegisters; + } + + public RegisterConfig getRegisterConfig() { + return registerConfig; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/SingleBlockTraceBuilder.java 2016-12-07 13:47:54.408267187 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, 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.core.common.alloc; + +import java.util.ArrayList; + +import org.graalvm.compiler.core.common.alloc.TraceBuilderResult.TrivialTracePredicate; +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; + +/** + * Builds traces consisting of a single basic block. + */ +public final class SingleBlockTraceBuilder { + + public static TraceBuilderResult computeTraces(AbstractBlockBase startBlock, AbstractBlockBase[] blocks, TrivialTracePredicate pred) { + return build(startBlock, blocks, pred); + } + + private static TraceBuilderResult build(AbstractBlockBase startBlock, AbstractBlockBase[] blocks, TrivialTracePredicate pred) { + Trace[] blockToTrace = new Trace[blocks.length]; + ArrayList traces = new ArrayList<>(blocks.length); + + for (AbstractBlockBase block : blocks) { + Trace trace = new Trace(new AbstractBlockBase[]{block}); + blockToTrace[block.getId()] = trace; + block.setLinearScanNumber(0); + trace.setId(traces.size()); + traces.add(trace); + } + + assert traces.get(0).getBlocks()[0].equals(startBlock) : "The first traces always contains the start block"; + return TraceBuilderResult.create(blocks, traces, blockToTrace, pred); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/Trace.java 2016-12-07 13:47:54.672278787 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016, 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.core.common.alloc; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; + +/** + * Represents a list of sequentially executed {@code AbstractBlockBase blocks}. + */ +public class Trace { + private final AbstractBlockBase[] blocks; + private final ArrayList successors; + private int id = -1; + + public Trace(Collection> blocks) { + this(blocks.toArray(new AbstractBlockBase[0])); + } + + public Trace(AbstractBlockBase[] blocks) { + this.blocks = blocks; + this.successors = new ArrayList<>(); + } + + public AbstractBlockBase[] getBlocks() { + return blocks; + } + + public ArrayList getSuccessors() { + return successors; + } + + public int size() { + return getBlocks().length; + } + + @Override + public String toString() { + return "Trace" + Arrays.toString(blocks); + } + + public int getId() { + assert id != -1 : "id not initialized!"; + return id; + } + + void setId(int id) { + this.id = id; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceBuilderResult.java 2016-12-07 13:47:54.937290432 -0800 @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2016, 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.core.common.alloc; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; + +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Indent; + +public final class TraceBuilderResult { + + public abstract static class TrivialTracePredicate { + public abstract boolean isTrivialTrace(Trace trace); + } + + private final ArrayList traces; + private final Trace[] blockToTrace; + + static TraceBuilderResult create(AbstractBlockBase[] blocks, ArrayList traces, Trace[] blockToTrace, TrivialTracePredicate pred) { + connect(traces, blockToTrace); + ArrayList newTraces = reorderTraces(traces, pred); + TraceBuilderResult traceBuilderResult = new TraceBuilderResult(newTraces, blockToTrace); + traceBuilderResult.numberTraces(); + assert verify(traceBuilderResult, blocks.length); + return traceBuilderResult; + } + + private TraceBuilderResult(ArrayList traces, Trace[] blockToTrace) { + this.traces = traces; + this.blockToTrace = blockToTrace; + } + + public Trace getTraceForBlock(AbstractBlockBase block) { + return blockToTrace[block.getId()]; + } + + public ArrayList getTraces() { + return traces; + } + + public boolean incomingEdges(Trace trace) { + return incomingEdges(trace.getId(), trace.getBlocks(), 0); + } + + public boolean incomingSideEdges(Trace trace) { + AbstractBlockBase[] traceArr = trace.getBlocks(); + if (traceArr.length <= 0) { + return false; + } + return incomingEdges(trace.getId(), traceArr, 1); + } + + private boolean incomingEdges(int traceNr, AbstractBlockBase[] trace, int index) { + /* TODO (je): not efficient. find better solution. */ + for (int i = index; i < trace.length; i++) { + AbstractBlockBase block = trace[1]; + for (AbstractBlockBase pred : block.getPredecessors()) { + if (getTraceForBlock(pred).getId() != traceNr) { + return true; + } + } + } + return false; + } + + public static boolean verify(TraceBuilderResult traceBuilderResult, int expectedLength) { + ArrayList traces = traceBuilderResult.getTraces(); + assert verifyAllBlocksScheduled(traceBuilderResult, expectedLength) : "Not all blocks assigned to traces!"; + for (int i = 0; i < traces.size(); i++) { + Trace trace = traces.get(i); + assert trace.getId() == i : "Trace number mismatch: " + trace.getId() + " vs. " + i; + + BitSet suxTraces = new BitSet(traces.size()); + for (Trace suxTrace : trace.getSuccessors()) { + assert !suxTraces.get(suxTrace.getId()) : "Trace twice successors " + suxTrace; + suxTraces.set(suxTrace.getId()); + } + + AbstractBlockBase last = null; + int blockNumber = 0; + for (AbstractBlockBase current : trace.getBlocks()) { + AbstractBlockBase block = current; + assert traceBuilderResult.getTraceForBlock(block).getId() == i : "Trace number mismatch for block " + block + ": " + traceBuilderResult.getTraceForBlock(block) + " vs. " + i; + assert last == null || Arrays.asList(current.getPredecessors()).contains(last) : "Last block (" + last + ") not a predecessor of " + current; + assert current.getLinearScanNumber() == blockNumber : "Blocks not numbered correctly: " + current.getLinearScanNumber() + " vs. " + blockNumber; + last = current; + blockNumber++; + for (AbstractBlockBase sux : block.getSuccessors()) { + Trace suxTrace = traceBuilderResult.getTraceForBlock(sux); + assert suxTraces.get(suxTrace.getId()) : "Successor Trace " + suxTrace + " for block " + sux + " not in successor traces of " + trace; + } + } + } + return true; + } + + private static boolean verifyAllBlocksScheduled(TraceBuilderResult traceBuilderResult, int expectedLength) { + ArrayList traces = traceBuilderResult.getTraces(); + BitSet handled = new BitSet(expectedLength); + for (Trace trace : traces) { + for (AbstractBlockBase block : trace.getBlocks()) { + assert !handled.get(block.getId()) : "Block added twice: " + block; + handled.set(block.getId()); + } + } + return handled.cardinality() == expectedLength; + } + + private void numberTraces() { + for (int i = 0; i < traces.size(); i++) { + Trace trace = traces.get(i); + trace.setId(i); + } + } + + private static void connect(ArrayList traces, Trace[] blockToTrace) { + int numTraces = traces.size(); + for (Trace trace : traces) { + BitSet added = new BitSet(numTraces); + ArrayList successors = trace.getSuccessors(); + assert successors.size() == 0 : "Can only connect traces once!"; + + for (AbstractBlockBase block : trace.getBlocks()) { + for (AbstractBlockBase succ : block.getSuccessors()) { + Trace succTrace = blockToTrace[succ.getId()]; + int succId = succTrace.getId(); + if (!added.get(succId)) { + added.set(succId); + successors.add(succTrace); + } + } + } + } + } + + @SuppressWarnings("try") + private static ArrayList reorderTraces(ArrayList oldTraces, TrivialTracePredicate pred) { + if (pred == null) { + return oldTraces; + } + try (Indent indent = Debug.logAndIndent("ReorderTrace")) { + ArrayList newTraces = new ArrayList<>(oldTraces.size()); + for (int oldTraceIdx = 0; oldTraceIdx < oldTraces.size(); oldTraceIdx++) { + Trace currentTrace = oldTraces.get(oldTraceIdx); + if (!alreadyProcessed(newTraces, currentTrace)) { + assert currentTrace.getId() == oldTraceIdx : "Index mismatch"; + // add current trace + addTrace(newTraces, currentTrace); + for (Trace succTrace : currentTrace.getSuccessors()) { + if (pred.isTrivialTrace(succTrace) && !alreadyProcessed(newTraces, succTrace)) { + Debug.log("Moving trivial trace from %d to %d", succTrace.getId(), newTraces.size()); + // add trivial successor trace + addTrace(newTraces, succTrace); + } + } + } + } + assert newTraces.size() == oldTraces.size() : "Lost traces? " + oldTraces.size() + " vs. " + newTraces.size(); + return newTraces; + } + } + + private static boolean alreadyProcessed(ArrayList newTraces, Trace currentTrace) { + int currentTraceId = currentTrace.getId(); + return currentTraceId < newTraces.size() && currentTrace == newTraces.get(currentTraceId); + } + + private static void addTrace(ArrayList newTraces, Trace currentTrace) { + currentTrace.setId(newTraces.size()); + newTraces.add(currentTrace); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceMap.java 2016-12-07 13:47:55.202302076 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, 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.core.common.alloc; + +public class TraceMap { + + private final T[] data; + + @SuppressWarnings("unchecked") + public TraceMap(TraceBuilderResult traceBuilderResult) { + data = (T[]) new Object[traceBuilderResult.getTraces().size()]; + } + + public T get(Trace trace) { + return data[trace.getId()]; + } + + public void put(Trace trace, T value) { + data[trace.getId()] = value; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java 2016-12-07 13:47:55.467313721 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, 2015, 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.core.common.alloc; + +import java.util.List; + +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.Indent; + +public final class TraceStatisticsPrinter { + private static final String SEP = ";"; + + @SuppressWarnings("try") + public static void printTraceStatistics(TraceBuilderResult result, String compilationUnitName) { + try (Scope s = Debug.scope("DumpTraceStatistics")) { + if (Debug.isLogEnabled(Debug.VERBOSE_LOG_LEVEL)) { + print(result, compilationUnitName); + } + } catch (Throwable e) { + Debug.handle(e); + } + } + + @SuppressWarnings("try") + protected static void print(TraceBuilderResult result, String compilationUnitName) { + List traces = result.getTraces(); + int numTraces = traces.size(); + + try (Indent indent0 = Debug.logAndIndent(Debug.VERBOSE_LOG_LEVEL, "")) { + Debug.log(Debug.VERBOSE_LOG_LEVEL, "%s", compilationUnitName != null ? compilationUnitName : "null"); + try (Indent indent1 = Debug.logAndIndent(Debug.VERBOSE_LOG_LEVEL, "")) { + printRawLine("tracenumber", "total", "min", "max", "numBlocks"); + for (int i = 0; i < numTraces; i++) { + AbstractBlockBase[] t = traces.get(i).getBlocks(); + double total = 0; + double max = Double.NEGATIVE_INFINITY; + double min = Double.POSITIVE_INFINITY; + for (AbstractBlockBase block : t) { + double probability = block.probability(); + total += probability; + if (probability < min) { + min = probability; + } + if (probability > max) { + max = probability; + } + } + printLine(i, total, min, max, t.length); + } + } + Debug.log(Debug.VERBOSE_LOG_LEVEL, ""); + } + Debug.log(Debug.VERBOSE_LOG_LEVEL, ""); + + } + + private static void printRawLine(Object tracenr, Object totalTime, Object minProb, Object maxProb, Object numBlocks) { + Debug.log(Debug.VERBOSE_LOG_LEVEL, "%s", String.join(SEP, tracenr.toString(), totalTime.toString(), minProb.toString(), maxProb.toString(), numBlocks.toString())); + } + + private static void printLine(int tracenr, double totalTime, double minProb, double maxProb, int numBlocks) { + printRawLine(tracenr, totalTime, minProb, maxProb, numBlocks); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java 2016-12-07 13:47:55.732325365 -0800 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2015, 2015, 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.core.common.alloc; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; +import java.util.PriorityQueue; + +import org.graalvm.compiler.core.common.alloc.TraceBuilderResult.TrivialTracePredicate; +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Indent; + +/** + * Computes traces by starting at a trace head and keep adding predecessors as long as possible. + */ +public final class UniDirectionalTraceBuilder { + + public static TraceBuilderResult computeTraces(AbstractBlockBase startBlock, AbstractBlockBase[] blocks, TrivialTracePredicate pred) { + return new UniDirectionalTraceBuilder(blocks).build(startBlock, blocks, pred); + } + + private final PriorityQueue> worklist; + private final BitSet processed; + /** + * Contains the number of unprocessed predecessors for every {@link AbstractBlockBase#getId() + * block}. + */ + private final int[] blocked; + private final Trace[] blockToTrace; + + private UniDirectionalTraceBuilder(AbstractBlockBase[] blocks) { + processed = new BitSet(blocks.length); + worklist = new PriorityQueue<>(UniDirectionalTraceBuilder::compare); + assert (worklist != null); + + blocked = new int[blocks.length]; + blockToTrace = new Trace[blocks.length]; + for (AbstractBlockBase block : blocks) { + blocked[block.getId()] = block.getPredecessorCount(); + } + } + + private static int compare(AbstractBlockBase a, AbstractBlockBase b) { + return Double.compare(b.probability(), a.probability()); + } + + private boolean processed(AbstractBlockBase b) { + return processed.get(b.getId()); + } + + @SuppressWarnings("try") + private TraceBuilderResult build(AbstractBlockBase startBlock, AbstractBlockBase[] blocks, TrivialTracePredicate pred) { + try (Indent indent = Debug.logAndIndent("UniDirectionalTraceBuilder: start trace building: %s", startBlock)) { + ArrayList traces = buildTraces(startBlock); + return TraceBuilderResult.create(blocks, traces, blockToTrace, pred); + } + } + + protected ArrayList buildTraces(AbstractBlockBase startBlock) { + ArrayList traces = new ArrayList<>(); + // add start block + worklist.add(startBlock); + // process worklist + while (!worklist.isEmpty()) { + AbstractBlockBase block = worklist.poll(); + assert block != null; + if (!processed(block)) { + Trace trace = new Trace(startTrace(block)); + for (AbstractBlockBase traceBlock : trace.getBlocks()) { + blockToTrace[traceBlock.getId()] = trace; + } + trace.setId(traces.size()); + traces.add(trace); + } + } + return traces; + } + + /** + * Build a new trace starting at {@code block}. + */ + @SuppressWarnings("try") + private List> startTrace(AbstractBlockBase block) { + assert checkPredecessorsProcessed(block); + ArrayList> trace = new ArrayList<>(); + int blockNumber = 0; + try (Indent i = Debug.logAndIndent("StartTrace: %s", block)) { + for (AbstractBlockBase currentBlock = block; currentBlock != null; currentBlock = selectNext(currentBlock)) { + Debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability()); + processed.set(currentBlock.getId()); + trace.add(currentBlock); + unblock(currentBlock); + currentBlock.setLinearScanNumber(blockNumber++); + } + } + return trace; + } + + private boolean checkPredecessorsProcessed(AbstractBlockBase block) { + for (AbstractBlockBase pred : block.getPredecessors()) { + if (!processed(pred)) { + assert false : "Predecessor unscheduled: " + pred; + return false; + } + + } + return true; + } + + /** + * Decrease the {@link #blocked} count for all predecessors and add them to the worklist once + * the count reaches 0. + */ + private void unblock(AbstractBlockBase currentBlock) { + for (AbstractBlockBase successor : currentBlock.getSuccessors()) { + if (!processed(successor)) { + int blockCount = --blocked[successor.getId()]; + assert blockCount >= 0; + if (blockCount == 0) { + worklist.add(successor); + } + } + } + } + + /** + * @return The unprocessed predecessor with the highest probability, or {@code null}. + */ + private AbstractBlockBase selectNext(AbstractBlockBase currentBlock) { + AbstractBlockBase next = null; + for (AbstractBlockBase succ : currentBlock.getSuccessors()) { + if (!processed(succ) && (next == null || succ.probability() > next.probability())) { + next = succ; + } + } + return next; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java 2016-12-07 13:47:55.997337010 -0800 @@ -0,0 +1,641 @@ +/* + * Copyright (c) 2009, 2015, 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.core.common.calc; + +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.PrimitiveConstant; + +/** + * Condition codes used in conditionals. + */ +public enum Condition { + /** + * Equal. + */ + EQ("=="), + + /** + * Not equal. + */ + NE("!="), + + /** + * Signed less than. + */ + LT("<"), + + /** + * Signed less than or equal. + */ + LE("<="), + + /** + * Signed greater than. + */ + GT(">"), + + /** + * Signed greater than or equal. + */ + GE(">="), + + /** + * Unsigned greater than or equal ("above than or equal"). + */ + AE("|>=|"), + + /** + * Unsigned less than or equal ("below than or equal"). + */ + BE("|<=|"), + + /** + * Unsigned greater than ("above than"). + */ + AT("|>|"), + + /** + * Unsigned less than ("below than"). + */ + BT("|<|"); + + public final String operator; + + Condition(String operator) { + this.operator = operator; + } + + public boolean check(int left, int right) { + switch (this) { + case EQ: + return left == right; + case NE: + return left != right; + case LT: + return left < right; + case LE: + return left <= right; + case GT: + return left > right; + case GE: + return left >= right; + case AE: + return UnsignedMath.aboveOrEqual(left, right); + case BE: + return UnsignedMath.belowOrEqual(left, right); + case AT: + return UnsignedMath.aboveThan(left, right); + case BT: + return UnsignedMath.belowThan(left, right); + } + throw new IllegalArgumentException(this.toString()); + } + + /** + * Given a condition and its negation, this method returns true for one of the two and false for + * the other one. This can be used to keep comparisons in a canonical form. + * + * @return true if this condition is considered to be the canonical form, false otherwise. + */ + public boolean isCanonical() { + switch (this) { + case EQ: + return true; + case NE: + return false; + case LT: + return true; + case LE: + return false; + case GT: + return false; + case GE: + return false; + case BT: + return true; + case BE: + return false; + case AT: + return false; + case AE: + return false; + } + throw new IllegalArgumentException(this.toString()); + } + + /** + * Returns true if the condition needs to be mirrored to get to a canonical condition. The + * result of the mirroring operation might still need to be negated to achieve a canonical form. + */ + public boolean canonicalMirror() { + switch (this) { + case EQ: + return false; + case NE: + return false; + case LT: + return false; + case LE: + return true; + case GT: + return true; + case GE: + return false; + case BT: + return false; + case BE: + return true; + case AT: + return true; + case AE: + return false; + } + throw new IllegalArgumentException(this.toString()); + } + + /** + * Returns true if the condition needs to be negated to get to a canonical condition. The result + * of the negation might still need to be mirrored to achieve a canonical form. + */ + public boolean canonicalNegate() { + switch (this) { + case EQ: + return false; + case NE: + return true; + case LT: + return false; + case LE: + return true; + case GT: + return false; + case GE: + return true; + case BT: + return false; + case BE: + return true; + case AT: + return false; + case AE: + return true; + } + throw new IllegalArgumentException(this.toString()); + } + + /** + * Negate this conditional. + * + * @return the condition that represents the negation + */ + public final Condition negate() { + switch (this) { + case EQ: + return NE; + case NE: + return EQ; + case LT: + return GE; + case LE: + return GT; + case GT: + return LE; + case GE: + return LT; + case BT: + return AE; + case BE: + return AT; + case AT: + return BE; + case AE: + return BT; + } + throw new IllegalArgumentException(this.toString()); + } + + public boolean implies(Condition other) { + if (other == this) { + return true; + } + switch (this) { + case EQ: + return other == LE || other == GE || other == BE || other == AE; + case NE: + return false; + case LT: + return other == LE || other == NE; + case LE: + return false; + case GT: + return other == GE || other == NE; + case GE: + return false; + case BT: + return other == BE || other == NE; + case BE: + return false; + case AT: + return other == AE || other == NE; + case AE: + return false; + } + throw new IllegalArgumentException(this.toString()); + } + + /** + * Mirror this conditional (i.e. commute "a op b" to "b op' a") + * + * @return the condition representing the equivalent commuted operation + */ + public final Condition mirror() { + switch (this) { + case EQ: + return EQ; + case NE: + return NE; + case LT: + return GT; + case LE: + return GE; + case GT: + return LT; + case GE: + return LE; + case BT: + return AT; + case BE: + return AE; + case AT: + return BT; + case AE: + return BE; + } + throw new IllegalArgumentException(); + } + + /** + * Returns true if this condition represents an unsigned comparison. EQ and NE are not + * considered to be unsigned. + */ + public final boolean isUnsigned() { + return this == Condition.BT || this == Condition.BE || this == Condition.AT || this == Condition.AE; + } + + /** + * Checks if this conditional operation is commutative. + * + * @return {@code true} if this operation is commutative + */ + public final boolean isCommutative() { + return this == EQ || this == NE; + } + + /** + * Attempts to fold a comparison between two constants and return the result. + * + * @param lt the constant on the left side of the comparison + * @param rt the constant on the right side of the comparison + * @param constantReflection needed to compare constants + * @return {@link Boolean#TRUE} if the comparison is known to be true, {@link Boolean#FALSE} if + * the comparison is known to be false + */ + public boolean foldCondition(JavaConstant lt, JavaConstant rt, ConstantReflectionProvider constantReflection) { + assert !lt.getJavaKind().isNumericFloat() && !rt.getJavaKind().isNumericFloat(); + return foldCondition(lt, rt, constantReflection, false); + } + + /** + * Attempts to fold a comparison between two constants and return the result. + * + * @param lt the constant on the left side of the comparison + * @param rt the constant on the right side of the comparison + * @param constantReflection needed to compare constants + * @param unorderedIsTrue true if an undecided float comparison should result in "true" + * @return true if the comparison is known to be true, false if the comparison is known to be + * false + */ + public boolean foldCondition(Constant lt, Constant rt, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) { + if (lt instanceof PrimitiveConstant) { + PrimitiveConstant lp = (PrimitiveConstant) lt; + PrimitiveConstant rp = (PrimitiveConstant) rt; + switch (lp.getJavaKind()) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: { + int x = lp.asInt(); + int y = rp.asInt(); + switch (this) { + case EQ: + return x == y; + case NE: + return x != y; + case LT: + return x < y; + case LE: + return x <= y; + case GT: + return x > y; + case GE: + return x >= y; + case AE: + return UnsignedMath.aboveOrEqual(x, y); + case BE: + return UnsignedMath.belowOrEqual(x, y); + case AT: + return UnsignedMath.aboveThan(x, y); + case BT: + return UnsignedMath.belowThan(x, y); + default: + throw new GraalError("expected condition: %s", this); + } + } + case Long: { + long x = lp.asLong(); + long y = rp.asLong(); + switch (this) { + case EQ: + return x == y; + case NE: + return x != y; + case LT: + return x < y; + case LE: + return x <= y; + case GT: + return x > y; + case GE: + return x >= y; + case AE: + return UnsignedMath.aboveOrEqual(x, y); + case BE: + return UnsignedMath.belowOrEqual(x, y); + case AT: + return UnsignedMath.aboveThan(x, y); + case BT: + return UnsignedMath.belowThan(x, y); + default: + throw new GraalError("expected condition: %s", this); + } + } + case Float: { + float x = lp.asFloat(); + float y = rp.asFloat(); + if (Float.isNaN(x) || Float.isNaN(y)) { + return unorderedIsTrue; + } + switch (this) { + case EQ: + return x == y; + case NE: + return x != y; + case LT: + return x < y; + case LE: + return x <= y; + case GT: + return x > y; + case GE: + return x >= y; + default: + throw new GraalError("expected condition: %s", this); + } + } + case Double: { + double x = lp.asDouble(); + double y = rp.asDouble(); + if (Double.isNaN(x) || Double.isNaN(y)) { + return unorderedIsTrue; + } + switch (this) { + case EQ: + return x == y; + case NE: + return x != y; + case LT: + return x < y; + case LE: + return x <= y; + case GT: + return x > y; + case GE: + return x >= y; + default: + throw new GraalError("expected condition: %s", this); + } + } + default: + throw new GraalError("expected value kind %s while folding condition: %s", lp.getJavaKind(), this); + } + } else { + Boolean equal = constantReflection.constantEquals(lt, rt); + if (equal == null) { + throw new GraalError("could not fold %s %s %s", lt, this, rt); + } + switch (this) { + case EQ: + return equal.booleanValue(); + case NE: + return !equal.booleanValue(); + default: + throw new GraalError("expected condition: %s", this); + } + } + } + + public Condition join(Condition other) { + if (other == this) { + return this; + } + switch (this) { + case EQ: + if (other == LE || other == GE || other == BE || other == AE) { + return EQ; + } else { + return null; + } + case NE: + if (other == LT || other == GT || other == BT || other == AT) { + return other; + } else if (other == LE) { + return LT; + } else if (other == GE) { + return GT; + } else if (other == BE) { + return BT; + } else if (other == AE) { + return AT; + } else { + return null; + } + case LE: + if (other == GE || other == EQ) { + return EQ; + } else if (other == NE || other == LT) { + return LT; + } else { + return null; + } + case LT: + if (other == NE || other == LE) { + return LT; + } else { + return null; + } + case GE: + if (other == LE || other == EQ) { + return EQ; + } else if (other == NE || other == GT) { + return GT; + } else { + return null; + } + case GT: + if (other == NE || other == GE) { + return GT; + } else { + return null; + } + case BE: + if (other == AE || other == EQ) { + return EQ; + } else if (other == NE || other == BT) { + return BT; + } else { + return null; + } + case BT: + if (other == NE || other == BE) { + return BT; + } else { + return null; + } + case AE: + if (other == BE || other == EQ) { + return EQ; + } else if (other == NE || other == AT) { + return AT; + } else { + return null; + } + case AT: + if (other == NE || other == AE) { + return AT; + } else { + return null; + } + } + throw new IllegalArgumentException(this.toString()); + } + + public Condition meet(Condition other) { + if (other == this) { + return this; + } + switch (this) { + case EQ: + if (other == LE || other == GE || other == BE || other == AE) { + return other; + } else if (other == LT) { + return LE; + } else if (other == GT) { + return GE; + } else if (other == BT) { + return BE; + } else if (other == AT) { + return AE; + } else { + return null; + } + case NE: + if (other == LT || other == GT || other == BT || other == AT) { + return NE; + } else { + return null; + } + case LE: + if (other == EQ || other == LT) { + return LE; + } else { + return null; + } + case LT: + if (other == EQ || other == LE) { + return LE; + } else if (other == NE || other == GT) { + return NE; + } else { + return null; + } + case GE: + if (other == EQ || other == GT) { + return GE; + } else { + return null; + } + case GT: + if (other == EQ || other == GE) { + return GE; + } else if (other == NE || other == LT) { + return NE; + } else { + return null; + } + case BE: + if (other == EQ || other == BT) { + return BE; + } else { + return null; + } + case BT: + if (other == EQ || other == BE) { + return BE; + } else if (other == NE || other == AT) { + return NE; + } else { + return null; + } + case AE: + if (other == EQ || other == AT) { + return AE; + } else { + return null; + } + case AT: + if (other == EQ || other == AE) { + return AE; + } else if (other == NE || other == BT) { + return NE; + } else { + return null; + } + } + throw new IllegalArgumentException(this.toString()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvert.java 2016-12-07 13:47:56.265348786 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014, 2014, 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.core.common.calc; + +import org.graalvm.compiler.debug.GraalError; + +public enum FloatConvert { + F2I, + D2I, + F2L, + D2L, + I2F, + L2F, + D2F, + I2D, + L2D, + F2D; + + public FloatConvert reverse() { + switch (this) { + case D2F: + return F2D; + case D2I: + return I2D; + case D2L: + return L2D; + case F2D: + return D2F; + case F2I: + return I2F; + case F2L: + return L2F; + case I2D: + return D2I; + case I2F: + return F2I; + case L2D: + return D2L; + case L2F: + return F2L; + default: + throw GraalError.shouldNotReachHere(); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/UnsignedMath.java 2016-12-07 13:47:56.532360518 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2015, 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.core.common.calc; + +//JaCoCo Exclude + +/** + * Utilities for unsigned comparisons. All methods have correct, but slow, standard Java + * implementations so that they can be used with compilers not supporting the intrinsics. + */ +public class UnsignedMath { + + /** + * Unsigned comparison aboveThan for two numbers. + */ + public static boolean aboveThan(int a, int b) { + return Integer.compareUnsigned(a, b) > 0; + } + + /** + * Unsigned comparison aboveOrEqual for two numbers. + */ + public static boolean aboveOrEqual(int a, int b) { + return Integer.compareUnsigned(a, b) >= 0; + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + public static boolean belowThan(int a, int b) { + return Integer.compareUnsigned(a, b) < 0; + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + public static boolean belowOrEqual(int a, int b) { + return Integer.compareUnsigned(a, b) <= 0; + } + + /** + * Unsigned comparison aboveThan for two numbers. + */ + public static boolean aboveThan(long a, long b) { + return Long.compareUnsigned(a, b) > 0; + } + + /** + * Unsigned comparison aboveOrEqual for two numbers. + */ + public static boolean aboveOrEqual(long a, long b) { + return Long.compareUnsigned(a, b) >= 0; + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + public static boolean belowThan(long a, long b) { + return Long.compareUnsigned(a, b) < 0; + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + public static boolean belowOrEqual(long a, long b) { + return Long.compareUnsigned(a, b) <= 0; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractBlockBase.java 2016-12-07 13:47:56.797372163 -0800 @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2009, 2012, 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.core.common.cfg; + +import java.util.Collections; +import java.util.List; + +public abstract class AbstractBlockBase> { + + protected int id; + protected int domDepth; + + protected T[] predecessors; + protected T[] successors; + + private T dominator; + private List dominated; + private int domNumber; + private int maxChildDomNumber; + + private boolean align; + private int linearScanNumber; + + protected AbstractBlockBase() { + this.id = AbstractControlFlowGraph.BLOCK_ID_INITIAL; + this.linearScanNumber = -1; + this.domNumber = -1; + this.maxChildDomNumber = -1; + } + + public void setDominatorNumber(int domNumber) { + this.domNumber = domNumber; + } + + public void setMaxChildDomNumber(int maxChildDomNumber) { + this.maxChildDomNumber = maxChildDomNumber; + } + + public int getDominatorNumber() { + return domNumber; + } + + public int getMaxChildDominatorNumber() { + return this.maxChildDomNumber; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public T[] getPredecessors() { + return predecessors; + } + + public void setPredecessors(T[] predecessors) { + this.predecessors = predecessors; + } + + public T[] getSuccessors() { + return successors; + } + + public void setSuccessors(T[] successors) { + this.successors = successors; + } + + public T getDominator() { + return dominator; + } + + public void setDominator(T dominator) { + this.dominator = dominator; + this.domDepth = dominator.domDepth + 1; + } + + public int getDominatorDepth() { + return domDepth; + } + + public List getDominated() { + if (dominated == null) { + return Collections.emptyList(); + } + return dominated; + } + + public void setDominated(List blocks) { + dominated = blocks; + } + + @Override + public String toString() { + return "B" + id; + } + + public int getPredecessorCount() { + return getPredecessors().length; + } + + public int getSuccessorCount() { + return getSuccessors().length; + } + + public int getLinearScanNumber() { + return linearScanNumber; + } + + public void setLinearScanNumber(int linearScanNumber) { + this.linearScanNumber = linearScanNumber; + } + + public boolean isAligned() { + return align; + } + + public void setAlign(boolean align) { + this.align = align; + } + + public abstract boolean isExceptionEntry(); + + public abstract Loop getLoop(); + + public abstract int getLoopDepth(); + + public abstract void delete(); + + public abstract boolean isLoopEnd(); + + public abstract boolean isLoopHeader(); + + public abstract T getPostdominator(); + + public abstract double probability(); + + public abstract T getDominator(int distance); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractControlFlowGraph.java 2016-12-07 13:47:57.061383763 -0800 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014, 2014, 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.core.common.cfg; + +import java.util.Collection; + +public interface AbstractControlFlowGraph> { + + int BLOCK_ID_INITIAL = -1; + int BLOCK_ID_VISITED = -2; + + /** + * Returns the list blocks contained in this control flow graph. + * + * It is {@linkplain CFGVerifier guaranteed} that the blocks are numbered and ordered according + * to a reverse post order traversal of the control flow graph. + * + * @see CFGVerifier + */ + T[] getBlocks(); + + Collection> getLoops(); + + T getStartBlock(); + + /** + * True if block {@code a} is dominated by block {@code b}. + */ + static boolean isDominatedBy(AbstractBlockBase a, AbstractBlockBase b) { + int domNumberA = a.getDominatorNumber(); + int domNumberB = b.getDominatorNumber(); + return domNumberA >= domNumberB && domNumberA <= b.getMaxChildDominatorNumber(); + } + + /** + * True if block {@code a} dominates block {@code b} and {@code a} is not identical block to + * {@code b}. + */ + static boolean strictlyDominates(AbstractBlockBase a, AbstractBlockBase b) { + return a != b && dominates(a, b); + } + + /** + * True if block {@code a} dominates block {@code b}. + */ + static boolean dominates(AbstractBlockBase a, AbstractBlockBase b) { + assert a != null && b != null; + return isDominatedBy(b, a); + } + + /** + * Calculates the common dominator of two blocks. + * + * Note that this algorithm makes use of special properties regarding the numbering of blocks. + * + * @see #getBlocks() + * @see CFGVerifier + */ + static AbstractBlockBase commonDominator(AbstractBlockBase a, AbstractBlockBase b) { + if (a == null) { + return b; + } else if (b == null) { + return a; + } else { + int aDomDepth = a.getDominatorDepth(); + int bDomDepth = b.getDominatorDepth(); + AbstractBlockBase aTemp; + AbstractBlockBase bTemp; + if (aDomDepth > bDomDepth) { + aTemp = a; + bTemp = b; + } else { + aTemp = b; + bTemp = a; + } + return commonDominatorHelper(aTemp, bTemp); + } + } + + static AbstractBlockBase commonDominatorHelper(AbstractBlockBase a, AbstractBlockBase b) { + int domNumberA = a.getDominatorNumber(); + AbstractBlockBase result = b; + while (domNumberA < result.getDominatorNumber()) { + result = result.getDominator(); + } + while (domNumberA > result.getMaxChildDominatorNumber()) { + result = result.getDominator(); + } + return result; + } + + /** + * @see AbstractControlFlowGraph#commonDominator(AbstractBlockBase, AbstractBlockBase) + */ + @SuppressWarnings("unchecked") + static > T commonDominatorTyped(T a, T b) { + return (T) commonDominator(a, b); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/BlockMap.java 2016-12-07 13:47:57.326395408 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012, 2012, 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.core.common.cfg; + +public class BlockMap { + + private final T[] data; + + @SuppressWarnings("unchecked") + public BlockMap(AbstractControlFlowGraph cfg) { + data = (T[]) new Object[cfg.getBlocks().length]; + } + + public T get(AbstractBlockBase block) { + return data[block.getId()]; + } + + public void put(AbstractBlockBase block, T value) { + data[block.getId()] = value; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/CFGVerifier.java 2016-12-07 13:47:57.589406964 -0800 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2012, 2014, 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.core.common.cfg; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Deque; + +public class CFGVerifier { + + public static , C extends AbstractControlFlowGraph> boolean verify(C cfg) { + for (T block : cfg.getBlocks()) { + assert block.getId() >= 0; + assert cfg.getBlocks()[block.getId()] == block; + + for (T pred : block.getPredecessors()) { + assert Arrays.asList(pred.getSuccessors()).contains(block); + assert pred.getId() < block.getId() || pred.isLoopEnd(); + } + + for (T sux : block.getSuccessors()) { + assert Arrays.asList(sux.getPredecessors()).contains(block); + assert sux.getId() > block.getId() || sux.isLoopHeader(); + } + + if (block.getDominator() != null) { + assert block.getDominator().getId() < block.getId(); + assert block.getDominator().getDominated().contains(block); + } + for (T dominated : block.getDominated()) { + assert dominated.getId() > block.getId(); + assert dominated.getDominator() == block; + } + + T postDominatorBlock = block.getPostdominator(); + if (postDominatorBlock != null) { + assert block.getSuccessorCount() > 0 : "block has post-dominator block, but no successors"; + + BlockMap visitedBlocks = new BlockMap<>(cfg); + visitedBlocks.put(block, true); + + Deque stack = new ArrayDeque<>(); + for (T sux : block.getSuccessors()) { + visitedBlocks.put(sux, true); + stack.push(sux); + } + + while (stack.size() > 0) { + T tos = stack.pop(); + assert tos.getId() <= postDominatorBlock.getId(); + if (tos == postDominatorBlock) { + continue; // found a valid path + } + assert tos.getSuccessorCount() > 0 : "no path found"; + + for (T sux : tos.getSuccessors()) { + if (visitedBlocks.get(sux) == null) { + visitedBlocks.put(sux, true); + stack.push(sux); + } + } + } + } + + assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().getHeader() == block; + } + + if (cfg.getLoops() != null) { + for (Loop loop : cfg.getLoops()) { + assert loop.getHeader().isLoopHeader(); + + for (T block : loop.getBlocks()) { + assert block.getId() >= loop.getHeader().getId(); + + Loop blockLoop = block.getLoop(); + while (blockLoop != loop) { + assert blockLoop != null; + blockLoop = blockLoop.getParent(); + } + + if (!(block.isLoopHeader() && block.getLoop() == loop)) { + for (T pred : block.getPredecessors()) { + if (!loop.getBlocks().contains(pred)) { + assert false : "Loop " + loop + " does not contain " + pred; + return false; + } + } + } + } + + for (T block : loop.getExits()) { + assert block.getId() >= loop.getHeader().getId(); + + Loop blockLoop = block.getLoop(); + while (blockLoop != null) { + blockLoop = blockLoop.getParent(); + assert blockLoop != loop; + } + } + } + } + + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/DominatorOptimizationProblem.java 2016-12-07 13:47:57.855418653 -0800 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2014, 2014, 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.core.common.cfg; + +import java.util.Arrays; +import java.util.BitSet; +import java.util.EnumMap; +import java.util.Set; +import java.util.stream.Stream; + +/** + * This class represents a dominator tree problem, i.e. a problem which can be solved by traversing + * the dominator (sub-)tree. + * + * @param An enum that describes the flags that can be associated with a block. + * @param An arbitrary cost type that is associated with a block. It is intended to carry + * information needed to calculate the solution. Note that {@code C} should not contain + * boolean flags. Use an enum entry in {@code E} instead. + */ +public abstract class DominatorOptimizationProblem, C> { + + private AbstractBlockBase[] blocks; + private EnumMap flags; + private BlockMap costs; + + protected DominatorOptimizationProblem(Class flagType, AbstractControlFlowGraph cfg) { + this.blocks = cfg.getBlocks(); + flags = new EnumMap<>(flagType); + costs = new BlockMap<>(cfg); + assert verify(blocks); + } + + private static boolean verify(AbstractBlockBase[] blocks) { + for (int i = 0; i < blocks.length; i++) { + AbstractBlockBase block = blocks[i]; + if (i != block.getId()) { + assert false : String.format("Id index mismatch @ %d vs. %s.getId()==%d", i, block, block.getId()); + return false; + } + } + return true; + } + + public final AbstractBlockBase[] getBlocks() { + return blocks; + } + + public final AbstractBlockBase getBlockForId(int id) { + AbstractBlockBase block = blocks[id]; + assert block.getId() == id : "wrong block-to-id mapping"; + return block; + } + + /** + * Sets a flag for a block. + */ + public final void set(E flag, AbstractBlockBase block) { + BitSet bitSet = flags.get(flag); + if (bitSet == null) { + bitSet = new BitSet(blocks.length); + flags.put(flag, bitSet); + } + bitSet.set(block.getId()); + } + + /** + * Checks whether a flag is set for a block. + */ + public final boolean get(E flag, AbstractBlockBase block) { + BitSet bitSet = flags.get(flag); + return bitSet == null ? false : bitSet.get(block.getId()); + } + + /** + * Returns a {@linkplain Stream} of blocks for which {@code flag} is set. + */ + public final Stream> stream(E flag) { + return Arrays.asList(getBlocks()).stream().filter(block -> get(flag, block)); + } + + /** + * Returns the cost object associated with {@code block}. Might return {@code null} if not set. + */ + public final C getCost(AbstractBlockBase block) { + C cost = costs.get(block); + return cost; + } + + /** + * Sets the cost for a {@code block}. + */ + public final void setCost(AbstractBlockBase block, C cost) { + costs.put(block, cost); + } + + /** + * Sets {@code flag} for all blocks along the dominator path from {@code block} to the root + * until a block it finds a block where {@code flag} is already set. + */ + public final void setDominatorPath(E flag, AbstractBlockBase block) { + BitSet bitSet = flags.get(flag); + if (bitSet == null) { + bitSet = new BitSet(blocks.length); + flags.put(flag, bitSet); + } + for (AbstractBlockBase b = block; b != null && !bitSet.get(b.getId()); b = b.getDominator()) { + // mark block + bitSet.set(b.getId()); + } + } + + /** + * Returns a {@link Stream} of flags associated with {@code block}. + */ + public final Stream getFlagsForBlock(AbstractBlockBase block) { + return getFlags().stream().filter(flag -> get(flag, block)); + } + + /** + * Returns the {@link Set} of flags that can be set for this + * {@linkplain DominatorOptimizationProblem problem}. + */ + public final Set getFlags() { + return flags.keySet(); + } + + /** + * Returns the name of a flag. + */ + public String getName(E flag) { + return flag.toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/Loop.java 2016-12-07 13:47:58.120430297 -0800 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2012, 2012, 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.core.common.cfg; + +import java.util.ArrayList; +import java.util.List; + +public abstract class Loop> { + + private final Loop parent; + private final List> children; + + private final int depth; + private final int index; + private final T header; + private final List blocks; + private final List exits; + + protected Loop(Loop parent, int index, T header) { + this.parent = parent; + if (parent != null) { + this.depth = parent.getDepth() + 1; + parent.getChildren().add(this); + } else { + this.depth = 1; + } + this.index = index; + this.header = header; + this.blocks = new ArrayList<>(); + this.children = new ArrayList<>(); + this.exits = new ArrayList<>(); + } + + public abstract long numBackedges(); + + @Override + public String toString() { + return "loop " + index + " depth " + getDepth() + (parent != null ? " outer " + parent.index : ""); + } + + public Loop getParent() { + return parent; + } + + public List> getChildren() { + return children; + } + + public int getDepth() { + return depth; + } + + public int getIndex() { + return index; + } + + public T getHeader() { + return header; + } + + public List getBlocks() { + return blocks; + } + + public List getExits() { + return exits; + } + + /** + * Determines if one loop is a transitive parent of another loop. + * + * @param childLoop The loop for which parentLoop might be a transitive parent loop. + * @param parentLoop The loop which might be a transitive parent loop of child loop. + * @return {@code true} if parentLoop is a (transitive) parent loop of childLoop, {@code false} + * otherwise + */ + public static > boolean transitiveParentLoop(Loop childLoop, Loop parentLoop) { + Loop curr = childLoop; + while (curr != null) { + if (curr == parentLoop) { + return true; + } + curr = curr.getParent(); + } + return false; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PrintableCFG.java 2016-12-07 13:47:58.383441854 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, 2014, 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.core.common.cfg; + +import java.util.function.BiConsumer; + +/** + * Represents a control-flow graph where each node can be annotated with arbitrary property pairs of + * the form ({@linkplain String name}, {@linkplain String value}). + */ +public interface PrintableCFG { + + AbstractBlockBase[] getBlocks(); + + /** + * Applies {@code action} to all extra property pairs (name, value) of {@code block}. + * + * @param block a block from {@link #getBlocks()}. + * @param action a {@link BiConsumer consumer}. + */ + default void forEachPropertyPair(AbstractBlockBase block, BiConsumer action) { + // no extra properties per default + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PrintableDominatorOptimizationProblem.java 2016-12-07 13:47:58.648453498 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014, 2014, 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.core.common.cfg; + +import java.util.function.BiConsumer; + +/** + * A {@linkplain PrintableCFG printable} {@link DominatorOptimizationProblem}. + */ +public abstract class PrintableDominatorOptimizationProblem, C extends PropertyConsumable> extends DominatorOptimizationProblem implements PrintableCFG { + + protected PrintableDominatorOptimizationProblem(Class keyType, AbstractControlFlowGraph cfg) { + super(keyType, cfg); + } + + @Override + public void forEachPropertyPair(AbstractBlockBase block, BiConsumer action) { + // for each flag + getFlags().forEach(flag -> ((BiConsumer) (name, value) -> action.accept(name, value ? "true" : "false")).accept(getName(flag), get(flag, block))); + // for each property + C cost = getCost(block); + if (cost != null) { + cost.forEachProperty((name, value) -> action.accept(name, value)); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PropertyConsumable.java 2016-12-07 13:47:58.913465143 -0800 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014, 2014, 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.core.common.cfg; + +import java.util.function.BiConsumer; + +public interface PropertyConsumable { + + void forEachProperty(BiConsumer action); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java 2016-12-07 13:47:59.177476743 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013, 2014, 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.core.common.spi; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; + +/** + * A set of providers which are required for LIR and/or code generation. Some may not be present + * (i.e., null). + */ +public interface CodeGenProviders { + + MetaAccessProvider getMetaAccess(); + + CodeCacheProvider getCodeCache(); + + ForeignCallsProvider getForeignCalls(); + + ConstantReflectionProvider getConstantReflection(); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java 2016-12-07 13:47:59.442488388 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, 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.core.common.spi; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaField; + +/** + * Implements the logic that decides whether a field read should be constant folded. + */ +public interface ConstantFieldProvider { + + public interface ConstantFieldTool { + + JavaConstant readValue(); + + JavaConstant getReceiver(); + + T foldConstant(JavaConstant ret); + + T foldStableArray(JavaConstant ret, int stableDimensions, boolean isDefaultStable); + } + + /** + * Decide whether a read from the {@code field} should be constant folded. This should return + * {@link ConstantFieldTool#foldConstant} or {@link ConstantFieldTool#foldStableArray} if the + * read should be constant folded, or {@code null} otherwise. + */ + T readConstantField(ResolvedJavaField field, ConstantFieldTool tool); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallDescriptor.java 2016-12-07 13:47:59.707500032 -0800 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.common.spi; + +import java.util.Arrays; + +/** + * The name and signature of a foreign call. A foreign call differs from a normal compiled Java call + * in at least one of these aspects: + *

    + *
  • The call is to C/C++/assembler code.
  • + *
  • The call uses different conventions for passing parameters or returning values.
  • + *
  • The callee has different register saving semantics. For example, the callee may save all + * registers (apart from some specified temporaries) in which case the register allocator doesn't + * not need to spill all live registers around the call site.
  • + *
  • The call does not occur at an INVOKE* bytecode. Such a call could be transformed into a + * standard Java call if the foreign routine is a normal Java method and the runtime supports + * linking Java calls at arbitrary bytecodes.
  • + *
+ */ +public class ForeignCallDescriptor { + + private final String name; + private final Class resultType; + private final Class[] argumentTypes; + + public ForeignCallDescriptor(String name, Class resultType, Class... argumentTypes) { + this.name = name; + this.resultType = resultType; + this.argumentTypes = argumentTypes; + } + + /** + * Gets the name of this foreign call. + */ + public String getName() { + return name; + } + + /** + * Gets the return type of this foreign call. + */ + public Class getResultType() { + return resultType; + } + + /** + * Gets the argument types of this foreign call. + */ + public Class[] getArgumentTypes() { + return argumentTypes.clone(); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ForeignCallDescriptor) { + ForeignCallDescriptor other = (ForeignCallDescriptor) obj; + return other.name.equals(name) && other.resultType.equals(resultType) && Arrays.equals(other.argumentTypes, argumentTypes); + } + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(name).append('('); + String sep = ""; + for (Class arg : argumentTypes) { + sb.append(sep).append(arg.getSimpleName()); + sep = ","; + } + return sb.append(')').append(resultType.getSimpleName()).toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallLinkage.java 2016-12-07 13:47:59.974511764 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2009, 2012, 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.core.common.spi; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.meta.InvokeTarget; +import jdk.vm.ci.meta.Value; + +/** + * The runtime specific details of a {@linkplain ForeignCallDescriptor foreign} call. + */ +public interface ForeignCallLinkage extends InvokeTarget { + + /** + * Gets the details of where parameters are passed and value(s) are returned from the caller's + * perspective. + */ + CallingConvention getOutgoingCallingConvention(); + + /** + * Gets the details of where parameters are passed and value(s) are returned from the callee's + * perspective. + */ + CallingConvention getIncomingCallingConvention(); + + /** + * Returns the maximum absolute offset of a PC relative call to this stub from any position in + * the code cache or -1 when not applicable. Intended for determining the required size of + * address/offset fields. + */ + long getMaxCallTargetOffset(); + + ForeignCallDescriptor getDescriptor(); + + /** + * Gets the values used/killed by this foreign call. + */ + Value[] getTemporaries(); + + /** + * Determines if the foreign call target destroys all registers. + * + * @return {@code true} if the register allocator must save all live registers around a call to + * this target + */ + boolean destroysRegisters(); + + /** + * Determines if debug info needs to be associated with this call. Debug info is required if the + * function can raise an exception, try to lock, trigger GC or do anything else that requires + * the VM to be able to inspect the thread's execution state. + */ + boolean needsDebugInfo(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallsProvider.java 2016-12-07 13:48:00.240523453 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013, 2016, 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.core.common.spi; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.LocationIdentity; + +import jdk.vm.ci.code.ValueKindFactory; + +/** + * Details about a set of supported {@link ForeignCallDescriptor foreign calls}. + */ +public interface ForeignCallsProvider extends ValueKindFactory { + + /** + * Determines if a given foreign call is side-effect free. Deoptimization cannot return + * execution to a point before a foreign call that has a side effect. + */ + boolean isReexecutable(ForeignCallDescriptor descriptor); + + /** + * Gets the set of memory locations killed by a given foreign call. Returning the special value + * {@link LocationIdentity#any()} denotes that the call kills all memory locations. Returning + * any empty array denotes that the call does not kill any memory locations. + */ + LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor); + + /** + * Determines if deoptimization can occur during a given foreign call. + */ + boolean canDeoptimize(ForeignCallDescriptor descriptor); + + /** + * Identifies foreign calls which are guaranteed to include a safepoint check. + */ + boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor); + + /** + * Gets the linkage for a foreign call. + */ + ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/JavaConstantFieldProvider.java 2016-12-07 13:48:00.506535141 -0800 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016, 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.core.common.spi; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionValue; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Utility for default constant folding semantics for Java fields. + */ +public abstract class JavaConstantFieldProvider implements ConstantFieldProvider { + + static class Options { + @Option(help = "Determines whether to treat final fields with default values as constant.")// + public static final OptionValue TrustFinalDefaultFields = new OptionValue<>(true); + } + + protected JavaConstantFieldProvider(MetaAccessProvider metaAccess) { + try { + this.stringValueField = metaAccess.lookupJavaField(String.class.getDeclaredField("value")); + this.stringHashField = metaAccess.lookupJavaField(String.class.getDeclaredField("hash")); + } catch (NoSuchFieldException | SecurityException e) { + throw new GraalError(e); + } + } + + @Override + public T readConstantField(ResolvedJavaField field, ConstantFieldTool tool) { + if (isStableField(field, tool)) { + JavaConstant value = tool.readValue(); + if (value != null && isStableFieldValueConstant(field, value, tool)) { + return foldStableArray(value, field, tool); + } + } + if (isFinalField(field, tool)) { + JavaConstant value = tool.readValue(); + if (value != null && isFinalFieldValueConstant(field, value, tool)) { + return tool.foldConstant(value); + } + } + return null; + } + + protected T foldStableArray(JavaConstant value, ResolvedJavaField field, ConstantFieldTool tool) { + return tool.foldStableArray(value, getArrayDimension(field.getType()), isDefaultStableField(field, tool)); + } + + private static int getArrayDimension(JavaType type) { + int dimensions = 0; + JavaType componentType = type; + while ((componentType = componentType.getComponentType()) != null) { + dimensions++; + } + return dimensions; + } + + private static boolean isArray(ResolvedJavaField field) { + JavaType fieldType = field.getType(); + return fieldType instanceof ResolvedJavaType && ((ResolvedJavaType) fieldType).isArray(); + } + + @SuppressWarnings("unused") + protected boolean isStableFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool tool) { + return !value.isDefaultForKind(); + } + + @SuppressWarnings("unused") + protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool tool) { + return !value.isDefaultForKind() || Options.TrustFinalDefaultFields.getValue(); + } + + @SuppressWarnings("unused") + protected boolean isStableField(ResolvedJavaField field, ConstantFieldTool tool) { + if (isSyntheticEnumSwitchMap(field)) { + return true; + } + if (isWellKnownImplicitStableField(field)) { + return true; + } + if (field == stringHashField) { + return true; + } + return false; + } + + protected boolean isDefaultStableField(ResolvedJavaField field, ConstantFieldTool tool) { + assert isStableField(field, tool); + if (isSyntheticEnumSwitchMap(field)) { + return true; + } + return false; + } + + @SuppressWarnings("unused") + protected boolean isFinalField(ResolvedJavaField field, ConstantFieldTool tool) { + return field.isFinal(); + } + + protected boolean isSyntheticEnumSwitchMap(ResolvedJavaField field) { + if (field.isSynthetic() && field.isStatic() && isArray(field)) { + String name = field.getName(); + if (field.isFinal() && name.equals("$VALUES") || name.equals("ENUM$VALUES")) { + // generated int[] field for EnumClass::values() + return true; + } else if (name.startsWith("$SwitchMap$") || name.startsWith("$SWITCH_TABLE$")) { + // javac and ecj generate a static field in an inner class for a switch on an enum + // named $SwitchMap$p$k$g$EnumClass and $SWITCH_TABLE$p$k$g$EnumClass, respectively + return true; + } + } + return false; + } + + private final ResolvedJavaField stringValueField; + private final ResolvedJavaField stringHashField; + + protected boolean isWellKnownImplicitStableField(ResolvedJavaField field) { + return field.equals(stringValueField); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/LIRKindTool.java 2016-12-07 13:48:00.772546830 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014, 2015, 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.core.common.spi; + +import org.graalvm.compiler.core.common.LIRKind; + +/** + * This interface can be used to access platform and VM specific kinds. + */ +public interface LIRKindTool { + + /** + * Get an architecture specific integer kind of a certain size. + */ + LIRKind getIntegerKind(int bits); + + /** + * Get an architecture specific floating point kind of a certain size. + */ + LIRKind getFloatingKind(int bits); + + /** + * Get the architecture specific kind used to represent Java objects. + */ + LIRKind getObjectKind(); + + /** + * Get the architecture specific kind pointer-sized integer kind. + */ + LIRKind getWordKind(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractObjectStamp.java 2016-12-07 13:48:01.038558518 -0800 @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2012, 2016, 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.core.common.type; + +import java.util.AbstractList; +import java.util.Objects; +import java.util.RandomAccess; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Type describing all pointers to Java objects. + */ +public abstract class AbstractObjectStamp extends AbstractPointerStamp { + + private final ResolvedJavaType type; + private final boolean exactType; + + protected AbstractObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) { + super(nonNull, alwaysNull); + this.type = type; + this.exactType = exactType; + } + + protected abstract AbstractObjectStamp copyWith(ResolvedJavaType newType, boolean newExactType, boolean newNonNull, boolean newAlwaysNull); + + @Override + protected final AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) { + return copyWith(type, exactType, newNonNull, newAlwaysNull); + } + + @Override + public Stamp unrestricted() { + return copyWith(null, false, false, false); + } + + @Override + public Stamp empty() { + return copyWith(null, true, true, false); + } + + @Override + public Stamp constant(Constant c, MetaAccessProvider meta) { + JavaConstant jc = (JavaConstant) c; + ResolvedJavaType constType = jc.isNull() ? null : meta.lookupJavaType(jc); + return copyWith(constType, jc.isNonNull(), jc.isNonNull(), jc.isNull()); + } + + @Override + public boolean hasValues() { + return !exactType || (type != null && (isConcreteType(type))); + } + + @Override + public JavaKind getStackKind() { + return JavaKind.Object; + } + + @Override + public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { + if (type != null) { + return type; + } + return metaAccess.lookupJavaType(Object.class); + } + + public ResolvedJavaType type() { + return type; + } + + public boolean isExactType() { + return exactType && type != null; + } + + protected void appendString(StringBuilder str) { + if (this.isEmpty()) { + str.append(" empty"); + } else { + str.append(nonNull() ? "!" : "").append(exactType ? "#" : "").append(' ').append(type == null ? "-" : type.getName()).append(alwaysNull() ? " NULL" : ""); + } + } + + @Override + public Stamp meet(Stamp otherStamp) { + if (this == otherStamp) { + return this; + } + AbstractObjectStamp other = (AbstractObjectStamp) otherStamp; + if (isEmpty()) { + return other; + } else if (other.isEmpty()) { + return this; + } + ResolvedJavaType meetType; + boolean meetExactType; + boolean meetNonNull; + boolean meetAlwaysNull; + if (other.alwaysNull()) { + meetType = type(); + meetExactType = exactType; + meetNonNull = false; + meetAlwaysNull = alwaysNull(); + } else if (alwaysNull()) { + meetType = other.type(); + meetExactType = other.exactType; + meetNonNull = false; + meetAlwaysNull = other.alwaysNull(); + } else { + meetType = meetTypes(type(), other.type()); + meetExactType = exactType && other.exactType; + if (meetExactType && type != null && other.type != null) { + // meeting two valid exact types may result in a non-exact type + meetExactType = Objects.equals(meetType, type) && Objects.equals(meetType, other.type); + } + meetNonNull = nonNull() && other.nonNull(); + meetAlwaysNull = false; + } + + if (Objects.equals(meetType, type) && meetExactType == exactType && meetNonNull == nonNull() && meetAlwaysNull == alwaysNull()) { + return this; + } else if (Objects.equals(meetType, other.type) && meetExactType == other.exactType && meetNonNull == other.nonNull() && meetAlwaysNull == other.alwaysNull()) { + return other; + } else { + return copyWith(meetType, meetExactType, meetNonNull, meetAlwaysNull); + } + } + + @Override + public Stamp join(Stamp otherStamp) { + return join0(otherStamp, false); + } + + /** + * Returns the stamp representing the type of this stamp after a cast to the type represented by + * the {@code to} stamp. While this is very similar to a {@link #join} operation, in the case + * where both types are not obviously related, the cast operation will prefer the type of the + * {@code to} stamp. This is necessary as long as ObjectStamps are not able to accurately + * represent intersection types. + * + * For example when joining the {@link RandomAccess} type with the {@link AbstractList} type, + * without intersection types, this would result in the most generic type ({@link Object} ). For + * this reason, in some cases a {@code castTo} operation is preferable in order to keep at least + * the {@link AbstractList} type. + * + * @param other the stamp this stamp should be casted to + * @return the new improved stamp or {@code null} if this stamp cannot be improved + */ + @Override + public Stamp improveWith(Stamp other) { + return join0(other, true); + } + + private Stamp join0(Stamp otherStamp, boolean improve) { + if (this == otherStamp) { + return this; + } + AbstractObjectStamp other = (AbstractObjectStamp) otherStamp; + if (isEmpty()) { + return this; + } else if (other.isEmpty()) { + return other; + } + + ResolvedJavaType joinType; + boolean joinAlwaysNull = alwaysNull() || other.alwaysNull(); + boolean joinNonNull = nonNull() || other.nonNull(); + boolean joinExactType = exactType || other.exactType; + if (Objects.equals(type, other.type)) { + joinType = type; + } else if (type == null && other.type == null) { + joinType = null; + } else if (type == null) { + joinType = other.type; + } else if (other.type == null) { + joinType = type; + } else { + // both types are != null and different + if (type.isAssignableFrom(other.type)) { + joinType = other.type; + if (exactType) { + joinAlwaysNull = true; + } + } else if (other.type.isAssignableFrom(type)) { + joinType = type; + if (other.exactType) { + joinAlwaysNull = true; + } + } else { + if (improve) { + joinType = type; + joinExactType = exactType; + } else { + joinType = null; + } + + if (joinExactType || (!isInterfaceOrArrayOfInterface(type) && !isInterfaceOrArrayOfInterface(other.type))) { + joinAlwaysNull = true; + } + } + } + if (joinAlwaysNull) { + joinType = null; + joinExactType = false; + } + if (joinExactType && joinType == null) { + return empty(); + } + if (joinAlwaysNull && joinNonNull) { + return empty(); + } else if (joinExactType && !isConcreteType(joinType)) { + return empty(); + } + if (Objects.equals(joinType, type) && joinExactType == exactType && joinNonNull == nonNull() && joinAlwaysNull == alwaysNull()) { + return this; + } else if (Objects.equals(joinType, other.type) && joinExactType == other.exactType && joinNonNull == other.nonNull() && joinAlwaysNull == other.alwaysNull()) { + return other; + } else { + return copyWith(joinType, joinExactType, joinNonNull, joinAlwaysNull); + } + } + + private static boolean isInterfaceOrArrayOfInterface(ResolvedJavaType t) { + return t.isInterface() || (t.isArray() && t.getElementalType().isInterface()); + } + + public static boolean isConcreteType(ResolvedJavaType type) { + return !(type.isAbstract() && !type.isArray()); + } + + private static ResolvedJavaType meetTypes(ResolvedJavaType a, ResolvedJavaType b) { + if (Objects.equals(a, b)) { + return a; + } else if (a == null || b == null) { + return null; + } else { + // The `meetTypes` operation must be commutative. One way to achieve this is to totally + // order the types and always call `meetOrderedNonNullTypes` in the same order. We + // establish the order by first comparing the hash-codes for performance reasons, and + // then comparing the internal names of the types. + int hashA = a.getName().hashCode(); + int hashB = b.getName().hashCode(); + if (hashA < hashB) { + return meetOrderedNonNullTypes(a, b); + } else if (hashB < hashA) { + return meetOrderedNonNullTypes(b, a); + } else { + int diff = a.getName().compareTo(b.getName()); + if (diff <= 0) { + return meetOrderedNonNullTypes(a, b); + } else { + return meetOrderedNonNullTypes(b, a); + } + } + } + } + + private static ResolvedJavaType meetOrderedNonNullTypes(ResolvedJavaType a, ResolvedJavaType b) { + ResolvedJavaType result = a.findLeastCommonAncestor(b); + if (result.isJavaLangObject() && a.isInterface() && b.isInterface()) { + // Both types are incompatible interfaces => search for first possible common + // ancestor match among super interfaces. + ResolvedJavaType[] interfacesA = a.getInterfaces(); + ResolvedJavaType[] interfacesB = b.getInterfaces(); + for (int i = 0; i < interfacesA.length; ++i) { + ResolvedJavaType interface1 = interfacesA[i]; + for (int j = 0; j < interfacesB.length; ++j) { + ResolvedJavaType interface2 = interfacesB[j]; + ResolvedJavaType leastCommon = meetTypes(interface1, interface2); + if (leastCommon.isInterface()) { + return leastCommon; + } + } + } + } + return result; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + super.hashCode(); + result = prime * result + (exactType ? 1231 : 1237); + result = prime * result + ((type == null || type.isJavaLangObject()) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + AbstractObjectStamp other = (AbstractObjectStamp) obj; + if (exactType != other.exactType) { + return false; + } + // null == java.lang.Object + if (type == null) { + if (other.type != null && !other.type.isJavaLangObject()) { + return false; + } + } else if (other.type == null) { + if (type != null && !type.isJavaLangObject()) { + return false; + } + } else if (!type.equals(other.type)) { + return false; + } + return super.equals(other); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractPointerStamp.java 2016-12-07 13:48:01.303570163 -0800 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2014, 2015, 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.core.common.type; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; + +/** + * Abstract base class of all pointer types. + */ +public abstract class AbstractPointerStamp extends Stamp { + + private final boolean nonNull; + private final boolean alwaysNull; + + protected AbstractPointerStamp(boolean nonNull, boolean alwaysNull) { + this.nonNull = nonNull; + this.alwaysNull = alwaysNull; + } + + public boolean nonNull() { + assert !this.isEmpty() || nonNull; + return nonNull; + } + + public boolean alwaysNull() { + return alwaysNull; + } + + protected abstract AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull); + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (alwaysNull ? 1231 : 1237); + result = prime * result + (nonNull ? 1231 : 1237); + return result; + } + + @Override + public Stamp join(Stamp stamp) { + AbstractPointerStamp other = (AbstractPointerStamp) stamp; + boolean joinNonNull = this.nonNull || other.nonNull; + boolean joinAlwaysNull = this.alwaysNull || other.alwaysNull; + if (joinNonNull && joinAlwaysNull) { + return empty(); + } else { + return copyWith(joinNonNull, joinAlwaysNull); + } + } + + @Override + public Stamp improveWith(Stamp other) { + return join(other); + } + + @Override + public Stamp meet(Stamp stamp) { + AbstractPointerStamp other = (AbstractPointerStamp) stamp; + boolean meetNonNull = this.nonNull && other.nonNull; + boolean meetAlwaysNull = this.alwaysNull && other.alwaysNull; + return copyWith(meetNonNull, meetAlwaysNull); + } + + @Override + public Stamp unrestricted() { + return copyWith(false, false); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + AbstractPointerStamp other = (AbstractPointerStamp) obj; + return this.alwaysNull == other.alwaysNull && this.nonNull == other.nonNull; + } + + @Override + public Constant asConstant() { + if (alwaysNull) { + return JavaConstant.NULL_POINTER; + } else { + return null; + } + } + + @Override + public JavaKind getStackKind() { + return JavaKind.Illegal; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java 2016-12-07 13:48:01.570581895 -0800 @@ -0,0 +1,759 @@ +/* + * Copyright (c) 2014, 2015, 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.core.common.type; + +import static jdk.vm.ci.meta.MetaUtil.getSimpleName; + +import java.util.Arrays; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaKind; + +import org.graalvm.compiler.core.common.calc.FloatConvert; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Div; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Mul; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Rem; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Sub; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Xor; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shl; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shr; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.UShr; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Abs; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Neg; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Not; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Sqrt; + +/** + * Information about arithmetic operations. + */ +public final class ArithmeticOpTable { + + private final UnaryOp neg; + private final BinaryOp add; + private final BinaryOp sub; + + private final BinaryOp mul; + private final BinaryOp
div; + private final BinaryOp rem; + + private final UnaryOp not; + private final BinaryOp and; + private final BinaryOp or; + private final BinaryOp xor; + + private final ShiftOp shl; + private final ShiftOp shr; + private final ShiftOp ushr; + + private final UnaryOp abs; + private final UnaryOp sqrt; + + private final IntegerConvertOp zeroExtend; + private final IntegerConvertOp signExtend; + private final IntegerConvertOp narrow; + + private final FloatConvertOp[] floatConvert; + private final int hash; + + public static ArithmeticOpTable forStamp(Stamp s) { + if (s instanceof ArithmeticStamp) { + return ((ArithmeticStamp) s).getOps(); + } else { + return EMPTY; + } + } + + public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); + + public ArithmeticOpTable(UnaryOp neg, BinaryOp add, BinaryOp sub, BinaryOp mul, BinaryOp
div, BinaryOp rem, UnaryOp not, BinaryOp and, BinaryOp or, + BinaryOp xor, ShiftOp shl, ShiftOp shr, ShiftOp ushr, UnaryOp abs, UnaryOp sqrt, IntegerConvertOp zeroExtend, + IntegerConvertOp signExtend, IntegerConvertOp narrow, FloatConvertOp... floatConvert) { + this(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, Stream.of(floatConvert)); + } + + public interface ArithmeticOpWrapper { + + UnaryOp wrapUnaryOp(UnaryOp op); + + BinaryOp wrapBinaryOp(BinaryOp op); + + ShiftOp wrapShiftOp(ShiftOp op); + + IntegerConvertOp wrapIntegerConvertOp(IntegerConvertOp op); + + FloatConvertOp wrapFloatConvertOp(FloatConvertOp op); + } + + private static T wrapIfNonNull(Function wrapper, T obj) { + if (obj == null) { + return null; + } else { + return wrapper.apply(obj); + } + } + + public static ArithmeticOpTable wrap(ArithmeticOpWrapper wrapper, ArithmeticOpTable inner) { + UnaryOp neg = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getNeg()); + BinaryOp add = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getAdd()); + BinaryOp sub = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getSub()); + + BinaryOp mul = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getMul()); + BinaryOp
div = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getDiv()); + BinaryOp rem = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getRem()); + + UnaryOp not = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getNot()); + BinaryOp and = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getAnd()); + BinaryOp or = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getOr()); + BinaryOp xor = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getXor()); + + ShiftOp shl = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShl()); + ShiftOp shr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShr()); + ShiftOp ushr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getUShr()); + + UnaryOp abs = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getAbs()); + UnaryOp sqrt = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getSqrt()); + + IntegerConvertOp zeroExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getZeroExtend()); + IntegerConvertOp signExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getSignExtend()); + IntegerConvertOp narrow = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getNarrow()); + + Stream floatConvert = Stream.of(inner.floatConvert).filter(Objects::nonNull).map(wrapper::wrapFloatConvertOp); + + return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert); + } + + private ArithmeticOpTable(UnaryOp neg, BinaryOp add, BinaryOp sub, BinaryOp mul, BinaryOp
div, BinaryOp rem, UnaryOp not, BinaryOp and, BinaryOp or, + BinaryOp xor, ShiftOp shl, ShiftOp shr, ShiftOp ushr, UnaryOp abs, UnaryOp sqrt, IntegerConvertOp zeroExtend, + IntegerConvertOp signExtend, IntegerConvertOp narrow, Stream floatConvert) { + this.neg = neg; + this.add = add; + this.sub = sub; + this.mul = mul; + this.div = div; + this.rem = rem; + this.not = not; + this.and = and; + this.or = or; + this.xor = xor; + this.shl = shl; + this.shr = shr; + this.ushr = ushr; + this.abs = abs; + this.sqrt = sqrt; + this.zeroExtend = zeroExtend; + this.signExtend = signExtend; + this.narrow = narrow; + this.floatConvert = new FloatConvertOp[FloatConvert.values().length]; + floatConvert.forEach(op -> this.floatConvert[op.getFloatConvert().ordinal()] = op); + + this.hash = Objects.hash(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow); + } + + @Override + public int hashCode() { + return hash; + } + + /** + * Describes the unary negation operation. + */ + public UnaryOp getNeg() { + return neg; + } + + /** + * Describes the addition operation. + */ + public BinaryOp getAdd() { + return add; + } + + /** + * Describes the subtraction operation. + */ + public BinaryOp getSub() { + return sub; + } + + /** + * Describes the multiplication operation. + */ + public BinaryOp getMul() { + return mul; + } + + /** + * Describes the division operation. + */ + public BinaryOp
getDiv() { + return div; + } + + /** + * Describes the remainder operation. + */ + public BinaryOp getRem() { + return rem; + } + + /** + * Describes the bitwise not operation. + */ + public UnaryOp getNot() { + return not; + } + + /** + * Describes the bitwise and operation. + */ + public BinaryOp getAnd() { + return and; + } + + /** + * Describes the bitwise or operation. + */ + public BinaryOp getOr() { + return or; + } + + /** + * Describes the bitwise xor operation. + */ + public BinaryOp getXor() { + return xor; + } + + /** + * Describes the shift left operation. + */ + public ShiftOp getShl() { + return shl; + } + + /** + * Describes the signed shift right operation. + */ + public ShiftOp getShr() { + return shr; + } + + /** + * Describes the unsigned shift right operation. + */ + public ShiftOp getUShr() { + return ushr; + } + + /** + * Describes the absolute value operation. + */ + public UnaryOp getAbs() { + return abs; + } + + /** + * Describes the square root operation. + */ + public UnaryOp getSqrt() { + return sqrt; + } + + /** + * Describes the zero extend conversion. + */ + public IntegerConvertOp getZeroExtend() { + return zeroExtend; + } + + /** + * Describes the sign extend conversion. + */ + public IntegerConvertOp getSignExtend() { + return signExtend; + } + + /** + * Describes the narrowing conversion. + */ + public IntegerConvertOp getNarrow() { + return narrow; + } + + /** + * Describes integer/float/double conversions. + */ + public FloatConvertOp getFloatConvert(FloatConvert op) { + return floatConvert[op.ordinal()]; + } + + public static String toString(Op... ops) { + return Arrays.asList(ops).stream().map(o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}").collect(Collectors.joining(",")); + } + + private boolean opsEquals(ArithmeticOpTable that) { + // @formatter:off + return Objects.equals(neg, that.neg) && + Objects.equals(add, that.add) && + Objects.equals(sub, that.sub) && + Objects.equals(mul, that.mul) && + Objects.equals(div, that.div) && + Objects.equals(rem, that.rem) && + Objects.equals(not, that.not) && + Objects.equals(and, that.and) && + Objects.equals(or, that.or) && + Objects.equals(xor, that.xor) && + Objects.equals(shl, that.shl) && + Objects.equals(shr, that.shr) && + Objects.equals(ushr, that.ushr) && + Objects.equals(abs, that.abs) && + Objects.equals(sqrt, that.sqrt) && + Objects.equals(zeroExtend, that.zeroExtend) && + Objects.equals(signExtend, that.signExtend) && + Objects.equals(narrow, that.narrow); + // @formatter:on + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ArithmeticOpTable that = (ArithmeticOpTable) obj; + if (opsEquals(that)) { + if (Arrays.equals(this.floatConvert, that.floatConvert)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow) + ",floatConvert[" + + toString(floatConvert) + "]]"; + } + + public abstract static class Op { + + private final String operator; + + protected Op(String operator) { + this.operator = operator; + } + + @Override + public String toString() { + return operator; + } + + @Override + public int hashCode() { + return operator.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Op that = (Op) obj; + if (operator.equals(that.operator)) { + return true; + } + return true; + } + } + + /** + * Describes a unary arithmetic operation. + */ + public abstract static class UnaryOp extends Op { + + public abstract static class Neg extends UnaryOp { + + protected Neg() { + super("-"); + } + } + + public abstract static class Not extends UnaryOp { + + protected Not() { + super("~"); + } + } + + public abstract static class Abs extends UnaryOp { + + protected Abs() { + super("ABS"); + } + } + + public abstract static class Sqrt extends UnaryOp { + + protected Sqrt() { + super("SQRT"); + } + } + + protected UnaryOp(String operation) { + super(operation); + } + + /** + * Apply the operation to a {@link Constant}. + */ + public abstract Constant foldConstant(Constant value); + + /** + * Apply the operation to a {@link Stamp}. + */ + public abstract Stamp foldStamp(Stamp stamp); + + public UnaryOp unwrap() { + return this; + } + } + + /** + * Describes a binary arithmetic operation. + */ + public abstract static class BinaryOp extends Op { + + public abstract static class Add extends BinaryOp { + + protected Add(boolean associative, boolean commutative) { + super("+", associative, commutative); + } + } + + public abstract static class Sub extends BinaryOp { + + protected Sub(boolean associative, boolean commutative) { + super("-", associative, commutative); + } + } + + public abstract static class Mul extends BinaryOp { + + protected Mul(boolean associative, boolean commutative) { + super("*", associative, commutative); + } + } + + public abstract static class Div extends BinaryOp
{ + + protected Div(boolean associative, boolean commutative) { + super("/", associative, commutative); + } + } + + public abstract static class Rem extends BinaryOp { + + protected Rem(boolean associative, boolean commutative) { + super("%", associative, commutative); + } + } + + public abstract static class And extends BinaryOp { + + protected And(boolean associative, boolean commutative) { + super("&", associative, commutative); + } + } + + public abstract static class Or extends BinaryOp { + + protected Or(boolean associative, boolean commutative) { + super("|", associative, commutative); + } + } + + public abstract static class Xor extends BinaryOp { + + protected Xor(boolean associative, boolean commutative) { + super("^", associative, commutative); + } + } + + private final boolean associative; + private final boolean commutative; + + protected BinaryOp(String operation, boolean associative, boolean commutative) { + super(operation); + this.associative = associative; + this.commutative = commutative; + } + + /** + * Apply the operation to two {@linkplain Constant Constants}. + */ + public abstract Constant foldConstant(Constant a, Constant b); + + /** + * Apply the operation to two {@linkplain Stamp Stamps}. + */ + public abstract Stamp foldStamp(Stamp a, Stamp b); + + /** + * Checks whether this operation is associative. An operation is associative when + * {@code (a . b) . c == a . (b . c)} for all a, b, c. Note that you still have to be + * careful with inverses. For example the integer subtraction operation will report + * {@code true} here, since you can still reassociate as long as the correct negations are + * inserted. + */ + public final boolean isAssociative() { + return associative; + } + + /** + * Checks whether this operation is commutative. An operation is commutative when + * {@code a . b == b . a} for all a, b. + */ + public final boolean isCommutative() { + return commutative; + } + + /** + * Check whether a {@link Constant} is a neutral element for this operation. A neutral + * element is any element {@code n} where {@code a . n == a} for all a. + * + * @param n the {@link Constant} that should be tested + * @return true iff for all {@code a}: {@code a . n == a} + */ + public boolean isNeutral(Constant n) { + return false; + } + + /** + * Check whether this operation has a zero {@code z == a . a} for each a. Examples of + * operations having such an element are subtraction and exclusive-or. Note that this may be + * different from the numbers tested by {@link #isNeutral}. + * + * @param stamp a {@link Stamp} + * @return a unique {@code z} such that {@code z == a . a} for each {@code a} in + * {@code stamp} if it exists, otherwise {@code null} + */ + public Constant getZero(Stamp stamp) { + return null; + } + + public BinaryOp unwrap() { + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (associative ? 1231 : 1237); + result = prime * result + (commutative ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + BinaryOp that = (BinaryOp) obj; + if (associative != that.associative) { + return false; + } + if (commutative != that.commutative) { + return false; + } + return true; + } + + @Override + public String toString() { + if (associative) { + if (commutative) { + return super.toString() + "[AC]"; + } else { + return super.toString() + "[A]"; + } + } else if (commutative) { + return super.toString() + "[C]"; + } + return super.toString(); + } + } + + /** + * Describes a shift operation. The right argument of a shift operation always has kind + * {@link JavaKind#Int}. + */ + public abstract static class ShiftOp extends Op { + + public abstract static class Shl extends ShiftOp { + + public Shl() { + super("<<"); + } + } + + public abstract static class Shr extends ShiftOp { + + public Shr() { + super(">>"); + } + } + + public abstract static class UShr extends ShiftOp { + + public UShr() { + super(">>>"); + } + } + + protected ShiftOp(String operation) { + super(operation); + } + + /** + * Apply the shift to a constant. + */ + public abstract Constant foldConstant(Constant c, int amount); + + /** + * Apply the shift to a stamp. + */ + public abstract Stamp foldStamp(Stamp s, IntegerStamp amount); + + /** + * Get the shift amount mask for a given result stamp. + */ + public abstract int getShiftAmountMask(Stamp s); + } + + public abstract static class FloatConvertOp extends UnaryOp { + + private final FloatConvert op; + + protected FloatConvertOp(FloatConvert op) { + super(op.name()); + this.op = op; + } + + public FloatConvert getFloatConvert() { + return op; + } + + @Override + public FloatConvertOp unwrap() { + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + return prime * super.hashCode() + op.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + FloatConvertOp that = (FloatConvertOp) obj; + if (op != that.op) { + return false; + } + return true; + } + } + + public abstract static class IntegerConvertOp extends Op { + + public abstract static class ZeroExtend extends IntegerConvertOp { + + protected ZeroExtend() { + super("ZeroExtend"); + } + } + + public abstract static class SignExtend extends IntegerConvertOp { + + protected SignExtend() { + super("SignExtend"); + } + } + + public abstract static class Narrow extends IntegerConvertOp { + + protected Narrow() { + super("Narrow"); + } + } + + protected IntegerConvertOp(String op) { + super(op); + } + + public abstract Constant foldConstant(int inputBits, int resultBits, Constant value); + + public abstract Stamp foldStamp(int inputBits, int resultBits, Stamp stamp); + + public IntegerConvertOp unwrap() { + return this; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticStamp.java 2016-12-07 13:48:01.837593627 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014, 2015, 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.core.common.type; + +import java.nio.ByteBuffer; +import java.util.Objects; + +import jdk.vm.ci.meta.SerializableConstant; + +/** + * Type describing values that support arithmetic operations. + */ +public abstract class ArithmeticStamp extends Stamp { + + private final ArithmeticOpTable ops; + + protected ArithmeticStamp(ArithmeticOpTable ops) { + this.ops = ops; + } + + public ArithmeticOpTable getOps() { + return ops; + } + + public abstract SerializableConstant deserialize(ByteBuffer buffer); + + @Override + public Stamp improveWith(Stamp other) { + return this.join(other); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ops.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ArithmeticStamp)) { + return false; + } + assert Objects.equals(ops, ((ArithmeticStamp) obj).ops); + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/DataPointerConstant.java 2016-12-07 13:48:02.102605272 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, 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.core.common.type; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.SerializableConstant; + +/** + * Base class for {@link Constant constants} that represent a pointer to the data section. + */ +public abstract class DataPointerConstant implements SerializableConstant { + + private final int alignment; + + protected DataPointerConstant(int alignment) { + this.alignment = alignment; + } + + /** + * Get the minimum alignment of the data in the data section. + */ + public final int getAlignment() { + return alignment; + } + + @Override + public boolean isDefaultForKind() { + return false; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java 2016-12-07 13:48:02.367616916 -0800 @@ -0,0 +1,832 @@ +/* + * Copyright (c) 2012, 2015, 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.core.common.type; + +import static org.graalvm.compiler.core.common.calc.FloatConvert.D2F; +import static org.graalvm.compiler.core.common.calc.FloatConvert.D2I; +import static org.graalvm.compiler.core.common.calc.FloatConvert.D2L; +import static org.graalvm.compiler.core.common.calc.FloatConvert.F2D; +import static org.graalvm.compiler.core.common.calc.FloatConvert.F2I; +import static org.graalvm.compiler.core.common.calc.FloatConvert.F2L; + +import java.nio.ByteBuffer; +import java.util.function.DoubleBinaryOperator; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.PrimitiveConstant; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.SerializableConstant; + +public class FloatStamp extends PrimitiveStamp { + + private final double lowerBound; + private final double upperBound; + private final boolean nonNaN; + + protected FloatStamp(int bits) { + this(bits, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false); + } + + public FloatStamp(int bits, double lowerBound, double upperBound, boolean nonNaN) { + super(bits, OPS); + assert bits == 64 || (bits == 32 && (Double.isNaN(lowerBound) || (float) lowerBound == lowerBound) && (Double.isNaN(upperBound) || (float) upperBound == upperBound)); + assert Double.isNaN(lowerBound) == Double.isNaN(upperBound); + this.lowerBound = lowerBound; + this.upperBound = upperBound; + this.nonNaN = nonNaN; + } + + @Override + public Stamp unrestricted() { + return new FloatStamp(getBits()); + } + + @Override + public Stamp empty() { + return new FloatStamp(getBits(), Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, true); + } + + @Override + public Stamp constant(Constant c, MetaAccessProvider meta) { + JavaConstant jc = (JavaConstant) c; + assert jc.getJavaKind().isNumericFloat() && jc.getJavaKind().getBitCount() == getBits(); + return StampFactory.forConstant(jc); + } + + @Override + public SerializableConstant deserialize(ByteBuffer buffer) { + switch (getBits()) { + case 32: + return JavaConstant.forFloat(buffer.getFloat()); + case 64: + return JavaConstant.forDouble(buffer.getDouble()); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public boolean hasValues() { + return lowerBound <= upperBound || !nonNaN; + } + + @Override + public JavaKind getStackKind() { + if (getBits() > 32) { + return JavaKind.Double; + } else { + return JavaKind.Float; + } + } + + @Override + public LIRKind getLIRKind(LIRKindTool tool) { + return tool.getFloatingKind(getBits()); + } + + @Override + public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { + switch (getBits()) { + case 32: + return metaAccess.lookupJavaType(Float.TYPE); + case 64: + return metaAccess.lookupJavaType(Double.TYPE); + default: + throw GraalError.shouldNotReachHere(); + } + } + + /** + * The (inclusive) lower bound on the value described by this stamp. + */ + public double lowerBound() { + return lowerBound; + } + + /** + * The (inclusive) upper bound on the value described by this stamp. + */ + public double upperBound() { + return upperBound; + } + + /** + * Returns true if NaN is non included in the value described by this stamp. + */ + public boolean isNonNaN() { + return nonNaN; + } + + /** + * Returns true if this stamp represents the NaN value. + */ + public boolean isNaN() { + return Double.isNaN(lowerBound); + } + + public boolean isUnrestricted() { + return lowerBound == Double.NEGATIVE_INFINITY && upperBound == Double.POSITIVE_INFINITY && !nonNaN; + } + + public boolean contains(double value) { + if (Double.isNaN(value)) { + return !nonNaN; + } else { + /* + * Don't use Double.compare for checking the bounds as -0.0 isn't correctly tracked, so + * the presence of 0.0 means -0.0 might also exist in the range. + */ + return value >= lowerBound && value <= upperBound; + } + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append('f'); + str.append(getBits()); + str.append(nonNaN ? "!" : ""); + if (lowerBound == upperBound) { + str.append(" [").append(lowerBound).append(']'); + } else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) { + str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']'); + } + return str.toString(); + } + + private static double meetBounds(double a, double b, DoubleBinaryOperator op) { + if (Double.isNaN(a)) { + return b; + } else if (Double.isNaN(b)) { + return a; + } else { + return op.applyAsDouble(a, b); + } + } + + @Override + public Stamp meet(Stamp otherStamp) { + if (otherStamp == this) { + return this; + } + FloatStamp other = (FloatStamp) otherStamp; + assert getBits() == other.getBits(); + double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max); + double meetLowerBound = meetBounds(lowerBound, other.lowerBound, Math::min); + boolean meetNonNaN = nonNaN && other.nonNaN; + if (Double.compare(meetLowerBound, lowerBound) == 0 && Double.compare(meetUpperBound, upperBound) == 0 && meetNonNaN == nonNaN) { + return this; + } else if (Double.compare(meetLowerBound, other.lowerBound) == 0 && Double.compare(meetUpperBound, other.upperBound) == 0 && meetNonNaN == other.nonNaN) { + return other; + } else { + return new FloatStamp(getBits(), meetLowerBound, meetUpperBound, meetNonNaN); + } + } + + @Override + public Stamp join(Stamp otherStamp) { + if (otherStamp == this) { + return this; + } + FloatStamp other = (FloatStamp) otherStamp; + assert getBits() == other.getBits(); + double joinUpperBound = Math.min(upperBound, other.upperBound); + double joinLowerBound = Math.max(lowerBound, other.lowerBound); + boolean joinNonNaN = nonNaN || other.nonNaN; + if (Double.compare(joinLowerBound, lowerBound) == 0 && Double.compare(joinUpperBound, upperBound) == 0 && joinNonNaN == nonNaN) { + return this; + } else if (Double.compare(joinLowerBound, other.lowerBound) == 0 && Double.compare(joinUpperBound, other.upperBound) == 0 && joinNonNaN == other.nonNaN) { + return other; + } else { + return new FloatStamp(getBits(), joinLowerBound, joinUpperBound, joinNonNaN); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + result = prime * result + super.hashCode(); + temp = Double.doubleToLongBits(lowerBound); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + (nonNaN ? 1231 : 1237); + temp = Double.doubleToLongBits(upperBound); + result = prime * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public boolean isCompatible(Stamp stamp) { + if (this == stamp) { + return true; + } + if (stamp instanceof FloatStamp) { + FloatStamp other = (FloatStamp) stamp; + return getBits() == other.getBits(); + } + return false; + } + + @Override + public boolean isCompatible(Constant constant) { + if (constant instanceof PrimitiveConstant) { + PrimitiveConstant prim = (PrimitiveConstant) constant; + return prim.getJavaKind().isNumericFloat(); + } + return false; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) { + return false; + } + FloatStamp other = (FloatStamp) obj; + if (Double.doubleToLongBits(lowerBound) != Double.doubleToLongBits(other.lowerBound)) { + return false; + } + if (Double.doubleToLongBits(upperBound) != Double.doubleToLongBits(other.upperBound)) { + return false; + } + if (nonNaN != other.nonNaN) { + return false; + } + return super.equals(other); + } + + @Override + public JavaConstant asConstant() { + if (nonNaN && Double.compare(lowerBound, upperBound) == 0) { + switch (getBits()) { + case 32: + return JavaConstant.forFloat((float) lowerBound); + case 64: + return JavaConstant.forDouble(lowerBound); + } + } + return null; + } + + public boolean isConstant() { + return (nonNaN && Double.compare(lowerBound, upperBound) == 0); + } + + private static final ArithmeticOpTable OPS = new ArithmeticOpTable( + + new UnaryOp.Neg() { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + switch (value.getJavaKind()) { + case Float: + return JavaConstant.forFloat(-value.asFloat()); + case Double: + return JavaConstant.forDouble(-value.asDouble()); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp s) { + FloatStamp stamp = (FloatStamp) s; + return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN()); + } + }, + + new BinaryOp.Add(false, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + switch (a.getJavaKind()) { + case Float: + return JavaConstant.forFloat(a.asFloat() + b.asFloat()); + case Double: + return JavaConstant.forDouble(a.asDouble() + b.asDouble()); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + // TODO + return stamp1.unrestricted(); + } + + @Override + public boolean isNeutral(Constant value) { + PrimitiveConstant n = (PrimitiveConstant) value; + switch (n.getJavaKind()) { + case Float: + return Float.compare(n.asFloat(), -0.0f) == 0; + case Double: + return Double.compare(n.asDouble(), -0.0) == 0; + default: + throw GraalError.shouldNotReachHere(); + } + } + }, + + new BinaryOp.Sub(false, false) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + switch (a.getJavaKind()) { + case Float: + return JavaConstant.forFloat(a.asFloat() - b.asFloat()); + case Double: + return JavaConstant.forDouble(a.asDouble() - b.asDouble()); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + // TODO + return stamp1.unrestricted(); + } + + @Override + public boolean isNeutral(Constant value) { + PrimitiveConstant n = (PrimitiveConstant) value; + switch (n.getJavaKind()) { + case Float: + return Float.compare(n.asFloat(), 0.0f) == 0; + case Double: + return Double.compare(n.asDouble(), 0.0) == 0; + default: + throw GraalError.shouldNotReachHere(); + } + } + }, + + new BinaryOp.Mul(false, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + switch (a.getJavaKind()) { + case Float: + return JavaConstant.forFloat(a.asFloat() * b.asFloat()); + case Double: + return JavaConstant.forDouble(a.asDouble() * b.asDouble()); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp a, Stamp b) { + // TODO + return a.unrestricted(); + } + + @Override + public boolean isNeutral(Constant value) { + PrimitiveConstant n = (PrimitiveConstant) value; + switch (n.getJavaKind()) { + case Float: + return Float.compare(n.asFloat(), 1.0f) == 0; + case Double: + return Double.compare(n.asDouble(), 1.0) == 0; + default: + throw GraalError.shouldNotReachHere(); + } + } + }, + + new BinaryOp.Div(false, false) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + switch (a.getJavaKind()) { + case Float: + return JavaConstant.forFloat(a.asFloat() / b.asFloat()); + case Double: + return JavaConstant.forDouble(a.asDouble() / b.asDouble()); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + // TODO + return stamp1.unrestricted(); + } + + @Override + public boolean isNeutral(Constant value) { + PrimitiveConstant n = (PrimitiveConstant) value; + switch (n.getJavaKind()) { + case Float: + return Float.compare(n.asFloat(), 1.0f) == 0; + case Double: + return Double.compare(n.asDouble(), 1.0) == 0; + default: + throw GraalError.shouldNotReachHere(); + } + } + }, + + new BinaryOp.Rem(false, false) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + switch (a.getJavaKind()) { + case Float: + return JavaConstant.forFloat(a.asFloat() % b.asFloat()); + case Double: + return JavaConstant.forDouble(a.asDouble() % b.asDouble()); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + // TODO + return stamp1.unrestricted(); + } + }, + + new UnaryOp.Not() { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + switch (value.getJavaKind()) { + case Float: + int f = Float.floatToRawIntBits(value.asFloat()); + return JavaConstant.forFloat(Float.intBitsToFloat(~f)); + case Double: + long d = Double.doubleToRawLongBits(value.asDouble()); + return JavaConstant.forDouble(Double.longBitsToDouble(~d)); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp s) { + return s.unrestricted(); + } + }, + + new BinaryOp.And(true, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + switch (a.getJavaKind()) { + case Float: + int fa = Float.floatToRawIntBits(a.asFloat()); + int fb = Float.floatToRawIntBits(b.asFloat()); + return JavaConstant.forFloat(Float.intBitsToFloat(fa & fb)); + case Double: + long da = Double.doubleToRawLongBits(a.asDouble()); + long db = Double.doubleToRawLongBits(b.asDouble()); + return JavaConstant.forDouble(Double.longBitsToDouble(da & db)); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + return stamp1.unrestricted(); + } + + @Override + public boolean isNeutral(Constant n) { + PrimitiveConstant value = (PrimitiveConstant) n; + switch (value.getJavaKind()) { + case Float: + return Float.floatToRawIntBits(value.asFloat()) == 0xFFFFFFFF; + case Double: + return Double.doubleToRawLongBits(value.asDouble()) == 0xFFFFFFFFFFFFFFFFL; + default: + throw GraalError.shouldNotReachHere(); + } + } + }, + + new BinaryOp.Or(true, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + switch (a.getJavaKind()) { + case Float: + int fa = Float.floatToRawIntBits(a.asFloat()); + int fb = Float.floatToRawIntBits(b.asFloat()); + return JavaConstant.forFloat(Float.intBitsToFloat(fa | fb)); + case Double: + long da = Double.doubleToRawLongBits(a.asDouble()); + long db = Double.doubleToRawLongBits(b.asDouble()); + return JavaConstant.forDouble(Double.longBitsToDouble(da | db)); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + return stamp1.unrestricted(); + } + + @Override + public boolean isNeutral(Constant n) { + PrimitiveConstant value = (PrimitiveConstant) n; + switch (value.getJavaKind()) { + case Float: + return Float.floatToRawIntBits(value.asFloat()) == 0; + case Double: + return Double.doubleToRawLongBits(value.asDouble()) == 0L; + default: + throw GraalError.shouldNotReachHere(); + } + } + }, + + new BinaryOp.Xor(true, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + switch (a.getJavaKind()) { + case Float: + int fa = Float.floatToRawIntBits(a.asFloat()); + int fb = Float.floatToRawIntBits(b.asFloat()); + return JavaConstant.forFloat(Float.intBitsToFloat(fa ^ fb)); + case Double: + long da = Double.doubleToRawLongBits(a.asDouble()); + long db = Double.doubleToRawLongBits(b.asDouble()); + return JavaConstant.forDouble(Double.longBitsToDouble(da ^ db)); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + return stamp1.unrestricted(); + } + + @Override + public boolean isNeutral(Constant n) { + PrimitiveConstant value = (PrimitiveConstant) n; + switch (value.getJavaKind()) { + case Float: + return Float.floatToRawIntBits(value.asFloat()) == 0; + case Double: + return Double.doubleToRawLongBits(value.asDouble()) == 0L; + default: + throw GraalError.shouldNotReachHere(); + } + } + }, + + null, null, null, + + new UnaryOp.Abs() { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + switch (value.getJavaKind()) { + case Float: + return JavaConstant.forFloat(Math.abs(value.asFloat())); + case Double: + return JavaConstant.forDouble(Math.abs(value.asDouble())); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp s) { + FloatStamp stamp = (FloatStamp) s; + if (stamp.isNaN()) { + return stamp; + } + return new FloatStamp(stamp.getBits(), 0, Math.max(-stamp.lowerBound(), stamp.upperBound()), stamp.isNonNaN()); + } + }, + + new UnaryOp.Sqrt() { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + switch (value.getJavaKind()) { + case Float: + return JavaConstant.forFloat((float) Math.sqrt(value.asFloat())); + case Double: + return JavaConstant.forDouble(Math.sqrt(value.asDouble())); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp s) { + return s.unrestricted(); + } + }, + + null, null, null, + + new FloatConvertOp(F2I) { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forInt((int) value.asFloat()); + } + + @Override + public Stamp foldStamp(Stamp stamp) { + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 32; + boolean mustHaveZero = !floatStamp.isNonNaN(); + int lowerBound = (int) floatStamp.lowerBound(); + int upperBound = (int) floatStamp.upperBound(); + if (mustHaveZero) { + if (lowerBound > 0) { + lowerBound = 0; + } else if (upperBound < 0) { + upperBound = 0; + } + } + return StampFactory.forInteger(JavaKind.Int, lowerBound, upperBound); + } + }, + + new FloatConvertOp(F2L) { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forLong((long) value.asFloat()); + } + + @Override + public Stamp foldStamp(Stamp stamp) { + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 32; + boolean mustHaveZero = !floatStamp.isNonNaN(); + long lowerBound = (long) floatStamp.lowerBound(); + long upperBound = (long) floatStamp.upperBound(); + if (mustHaveZero) { + if (lowerBound > 0) { + lowerBound = 0; + } else if (upperBound < 0) { + upperBound = 0; + } + } + return StampFactory.forInteger(JavaKind.Long, lowerBound, upperBound); + } + }, + + new FloatConvertOp(D2I) { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forInt((int) value.asDouble()); + } + + @Override + public Stamp foldStamp(Stamp stamp) { + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 64; + boolean mustHaveZero = !floatStamp.isNonNaN(); + int lowerBound = (int) floatStamp.lowerBound(); + int upperBound = (int) floatStamp.upperBound(); + if (mustHaveZero) { + if (lowerBound > 0) { + lowerBound = 0; + } else if (upperBound < 0) { + upperBound = 0; + } + } + return StampFactory.forInteger(JavaKind.Int, lowerBound, upperBound); + } + }, + + new FloatConvertOp(D2L) { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forLong((long) value.asDouble()); + } + + @Override + public Stamp foldStamp(Stamp stamp) { + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 64; + boolean mustHaveZero = !floatStamp.isNonNaN(); + long lowerBound = (long) floatStamp.lowerBound(); + long upperBound = (long) floatStamp.upperBound(); + if (mustHaveZero) { + if (lowerBound > 0) { + lowerBound = 0; + } else if (upperBound < 0) { + upperBound = 0; + } + } + return StampFactory.forInteger(JavaKind.Long, lowerBound, upperBound); + } + }, + + new FloatConvertOp(F2D) { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forDouble(value.asFloat()); + } + + @Override + public Stamp foldStamp(Stamp stamp) { + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 32; + return StampFactory.forFloat(JavaKind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN()); + } + }, + + new FloatConvertOp(D2F) { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forFloat((float) value.asDouble()); + } + + @Override + public Stamp foldStamp(Stamp stamp) { + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 64; + return StampFactory.forFloat(JavaKind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN()); + } + }); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IllegalStamp.java 2016-12-07 13:48:02.635628692 -0800 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2012, 2015, 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.core.common.type; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.PrimitiveConstant; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * This stamp represents the type of the {@link JavaKind#Illegal} value in the second slot of + * {@link JavaKind#Long} and {@link JavaKind#Double} values. It can only appear in framestates or + * virtual objects. + */ +public final class IllegalStamp extends Stamp { + + private IllegalStamp() { + } + + @Override + public JavaKind getStackKind() { + return JavaKind.Illegal; + } + + @Override + public LIRKind getLIRKind(LIRKindTool tool) { + return LIRKind.Illegal; + } + + @Override + public Stamp unrestricted() { + return this; + } + + @Override + public Stamp empty() { + return this; + } + + @Override + public Stamp constant(Constant c, MetaAccessProvider meta) { + assert ((PrimitiveConstant) c).getJavaKind() == JavaKind.Illegal; + return this; + } + + @Override + public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { + throw GraalError.shouldNotReachHere("illegal stamp has no Java type"); + } + + @Override + public Stamp meet(Stamp other) { + assert other instanceof IllegalStamp; + return this; + } + + @Override + public Stamp join(Stamp other) { + assert other instanceof IllegalStamp; + return this; + } + + @Override + public boolean isCompatible(Stamp stamp) { + return stamp instanceof IllegalStamp; + } + + @Override + public boolean isCompatible(Constant constant) { + if (constant instanceof PrimitiveConstant) { + PrimitiveConstant prim = (PrimitiveConstant) constant; + return prim.getJavaKind() == JavaKind.Illegal; + } + return false; + } + + @Override + public String toString() { + return "ILLEGAL"; + } + + @Override + public boolean hasValues() { + return true; + } + + @Override + public Stamp improveWith(Stamp other) { + assert other instanceof IllegalStamp; + return this; + } + + @Override + public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) { + throw GraalError.shouldNotReachHere("can't read values of illegal stamp"); + } + + private static final IllegalStamp instance = new IllegalStamp(); + + static IllegalStamp getInstance() { + return instance; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java 2016-12-07 13:48:02.900640337 -0800 @@ -0,0 +1,1237 @@ +/* + * Copyright (c) 2012, 2015, 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.core.common.type; + +import static org.graalvm.compiler.core.common.calc.FloatConvert.I2D; +import static org.graalvm.compiler.core.common.calc.FloatConvert.I2F; +import static org.graalvm.compiler.core.common.calc.FloatConvert.L2D; +import static org.graalvm.compiler.core.common.calc.FloatConvert.L2F; + +import java.nio.ByteBuffer; +import java.util.Formatter; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.PrimitiveConstant; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.SerializableConstant; + +/** + * Describes the possible values of a node that produces an int or long result. + * + * The description consists of (inclusive) lower and upper bounds and up (may be set) and down + * (always set) bit-masks. + */ +public class IntegerStamp extends PrimitiveStamp { + + private final long lowerBound; + private final long upperBound; + private final long downMask; + private final long upMask; + + public IntegerStamp(int bits, long lowerBound, long upperBound, long downMask, long upMask) { + super(bits, OPS); + this.lowerBound = lowerBound; + this.upperBound = upperBound; + this.downMask = downMask; + this.upMask = upMask; + assert lowerBound >= CodeUtil.minValue(bits) : this; + assert upperBound <= CodeUtil.maxValue(bits) : this; + assert (downMask & CodeUtil.mask(bits)) == downMask : this; + assert (upMask & CodeUtil.mask(bits)) == upMask : this; + } + + public static IntegerStamp stampForMask(int bits, long downMask, long upMask) { + long lowerBound; + long upperBound; + if (((upMask >>> (bits - 1)) & 1) == 0) { + lowerBound = downMask; + upperBound = upMask; + } else if (((downMask >>> (bits - 1)) & 1) == 1) { + lowerBound = downMask; + upperBound = upMask; + } else { + lowerBound = downMask | (-1L << (bits - 1)); + upperBound = CodeUtil.maxValue(bits) & upMask; + } + lowerBound = CodeUtil.convert(lowerBound, bits, false); + upperBound = CodeUtil.convert(upperBound, bits, false); + return new IntegerStamp(bits, lowerBound, upperBound, downMask, upMask); + } + + @Override + public IntegerStamp unrestricted() { + return new IntegerStamp(getBits(), CodeUtil.minValue(getBits()), CodeUtil.maxValue(getBits()), 0, CodeUtil.mask(getBits())); + } + + @Override + public Stamp empty() { + return new IntegerStamp(getBits(), CodeUtil.maxValue(getBits()), CodeUtil.minValue(getBits()), CodeUtil.mask(getBits()), 0); + } + + @Override + public Stamp constant(Constant c, MetaAccessProvider meta) { + if (c instanceof PrimitiveConstant) { + long value = ((PrimitiveConstant) c).asLong(); + return StampFactory.forInteger(getBits(), value, value); + } + return this; + } + + @Override + public SerializableConstant deserialize(ByteBuffer buffer) { + switch (getBits()) { + case 1: + return JavaConstant.forBoolean(buffer.get() != 0); + case 8: + return JavaConstant.forByte(buffer.get()); + case 16: + return JavaConstant.forShort(buffer.getShort()); + case 32: + return JavaConstant.forInt(buffer.getInt()); + case 64: + return JavaConstant.forLong(buffer.getLong()); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public boolean hasValues() { + return lowerBound <= upperBound; + } + + @Override + public JavaKind getStackKind() { + if (getBits() > 32) { + return JavaKind.Long; + } else { + return JavaKind.Int; + } + } + + @Override + public LIRKind getLIRKind(LIRKindTool tool) { + return tool.getIntegerKind(getBits()); + } + + @Override + public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { + switch (getBits()) { + case 1: + return metaAccess.lookupJavaType(Boolean.TYPE); + case 8: + return metaAccess.lookupJavaType(Byte.TYPE); + case 16: + return metaAccess.lookupJavaType(Short.TYPE); + case 32: + return metaAccess.lookupJavaType(Integer.TYPE); + case 64: + return metaAccess.lookupJavaType(Long.TYPE); + default: + throw GraalError.shouldNotReachHere(); + } + } + + /** + * The signed inclusive lower bound on the value described by this stamp. + */ + public long lowerBound() { + return lowerBound; + } + + /** + * The signed inclusive upper bound on the value described by this stamp. + */ + public long upperBound() { + return upperBound; + } + + /** + * This bit-mask describes the bits that are always set in the value described by this stamp. + */ + public long downMask() { + return downMask; + } + + /** + * This bit-mask describes the bits that can be set in the value described by this stamp. + */ + public long upMask() { + return upMask; + } + + public boolean isUnrestricted() { + return lowerBound == CodeUtil.minValue(getBits()) && upperBound == CodeUtil.maxValue(getBits()) && downMask == 0 && upMask == CodeUtil.mask(getBits()); + } + + public boolean contains(long value) { + return value >= lowerBound && value <= upperBound && (value & downMask) == downMask && (value & upMask) == (value & CodeUtil.mask(getBits())); + } + + public boolean isPositive() { + return lowerBound() >= 0; + } + + public boolean isNegative() { + return upperBound() <= 0; + } + + public boolean isStrictlyPositive() { + return lowerBound() > 0; + } + + public boolean isStrictlyNegative() { + return upperBound() < 0; + } + + public boolean canBePositive() { + return upperBound() > 0; + } + + public boolean canBeNegative() { + return lowerBound() < 0; + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append('i'); + str.append(getBits()); + if (lowerBound == upperBound) { + str.append(" [").append(lowerBound).append(']'); + } else if (lowerBound != CodeUtil.minValue(getBits()) || upperBound != CodeUtil.maxValue(getBits())) { + str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']'); + } + if (downMask != 0) { + str.append(" \u21ca"); + new Formatter(str).format("%016x", downMask); + } + if (upMask != CodeUtil.mask(getBits())) { + str.append(" \u21c8"); + new Formatter(str).format("%016x", upMask); + } + return str.toString(); + } + + private Stamp createStamp(IntegerStamp other, long newUpperBound, long newLowerBound, long newDownMask, long newUpMask) { + assert getBits() == other.getBits(); + if (newLowerBound > newUpperBound || (newDownMask & (~newUpMask)) != 0 || (newUpMask == 0 && (newLowerBound > 0 || newUpperBound < 0))) { + return empty(); + } else if (newLowerBound == lowerBound && newUpperBound == upperBound && newDownMask == downMask && newUpMask == upMask) { + return this; + } else if (newLowerBound == other.lowerBound && newUpperBound == other.upperBound && newDownMask == other.downMask && newUpMask == other.upMask) { + return other; + } else { + return new IntegerStamp(getBits(), newLowerBound, newUpperBound, newDownMask, newUpMask); + } + } + + @Override + public Stamp meet(Stamp otherStamp) { + if (otherStamp == this) { + return this; + } + IntegerStamp other = (IntegerStamp) otherStamp; + return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask); + } + + @Override + public Stamp join(Stamp otherStamp) { + if (otherStamp == this) { + return this; + } + IntegerStamp other = (IntegerStamp) otherStamp; + long newDownMask = downMask | other.downMask; + long newLowerBound = Math.max(lowerBound, other.lowerBound) | newDownMask; + long newUpperBound = Math.min(upperBound, other.upperBound); + long newUpMask = upMask & other.upMask; + IntegerStamp limit = StampFactory.forInteger(getBits(), newLowerBound, newUpperBound); + return createStamp(other, newUpperBound, newLowerBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask); + } + + @Override + public boolean isCompatible(Stamp stamp) { + if (this == stamp) { + return true; + } + if (stamp instanceof IntegerStamp) { + IntegerStamp other = (IntegerStamp) stamp; + return getBits() == other.getBits(); + } + return false; + } + + @Override + public boolean isCompatible(Constant constant) { + if (constant instanceof PrimitiveConstant) { + PrimitiveConstant prim = (PrimitiveConstant) constant; + return prim.getJavaKind().isNumericInteger(); + } + return false; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + super.hashCode(); + result = prime * result + (int) (lowerBound ^ (lowerBound >>> 32)); + result = prime * result + (int) (upperBound ^ (upperBound >>> 32)); + result = prime * result + (int) (downMask ^ (downMask >>> 32)); + result = prime * result + (int) (upMask ^ (upMask >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) { + return false; + } + IntegerStamp other = (IntegerStamp) obj; + if (lowerBound != other.lowerBound || upperBound != other.upperBound || downMask != other.downMask || upMask != other.upMask) { + return false; + } + return super.equals(other); + } + + public static long upMaskFor(int bits, long lowerBound, long upperBound) { + long mask = lowerBound | upperBound; + if (mask == 0) { + return 0; + } else { + return ((-1L) >>> Long.numberOfLeadingZeros(mask)) & CodeUtil.mask(bits); + } + } + + /** + * Checks if the 2 stamps represent values of the same sign. Returns true if the two stamps are + * both positive of null or if they are both strictly negative + * + * @return true if the two stamps are both positive of null or if they are both strictly + * negative + */ + public static boolean sameSign(IntegerStamp s1, IntegerStamp s2) { + return s1.isPositive() && s2.isPositive() || s1.isStrictlyNegative() && s2.isStrictlyNegative(); + } + + @Override + public JavaConstant asConstant() { + if (lowerBound == upperBound) { + switch (getBits()) { + case 1: + return JavaConstant.forBoolean(lowerBound != 0); + case 8: + return JavaConstant.forByte((byte) lowerBound); + case 16: + return JavaConstant.forShort((short) lowerBound); + case 32: + return JavaConstant.forInt((int) lowerBound); + case 64: + return JavaConstant.forLong(lowerBound); + } + } + return null; + } + + public static boolean addOverflowsPositively(long x, long y, int bits) { + long result = x + y; + if (bits == 64) { + return (~x & ~y & result) < 0; + } else { + return result > CodeUtil.maxValue(bits); + } + } + + public static boolean addOverflowsNegatively(long x, long y, int bits) { + long result = x + y; + if (bits == 64) { + return (x & y & ~result) < 0; + } else { + return result < CodeUtil.minValue(bits); + } + } + + public static long carryBits(long x, long y) { + return (x + y) ^ x ^ y; + } + + private static long saturate(long v, int bits) { + if (bits < 64) { + long max = CodeUtil.maxValue(bits); + if (v > max) { + return max; + } + long min = CodeUtil.minValue(bits); + if (v < min) { + return min; + } + } + return v; + } + + public static boolean multiplicationOverflows(long a, long b, int bits) { + assert bits <= 64 && bits >= 0; + long result = a * b; + // result is positive if the sign is the same + boolean positive = (a >= 0 && b >= 0) || (a < 0 && b < 0); + if (bits == 64) { + if (a > 0 && b > 0) { + return a > 0x7FFFFFFF_FFFFFFFFL / b; + } else if (a > 0 && b <= 0) { + return b < 0x80000000_00000000L / a; + } else if (a <= 0 && b > 0) { + return a < 0x80000000_00000000L / b; + } else { + // a<=0 && b <=0 + return a != 0 && b < 0x7FFFFFFF_FFFFFFFFL / a; + } + } else { + if (positive) { + return result > CodeUtil.maxValue(bits); + } else { + return result < CodeUtil.minValue(bits); + } + } + } + + public static boolean subtractionCanOverflow(IntegerStamp x, IntegerStamp y) { + assert x.getBits() == y.getBits(); + // Checkstyle: stop + long x_l = x.lowerBound(); + long x_h = x.upperBound(); + long y_l = y.lowerBound(); + long y_h = y.upperBound(); + // Checkstyle: resume + return subtractionOverflows(x_l, y_h, x.getBits()) || subtractionOverflows(x_h, y_l, x.getBits()); + } + + public static boolean subtractionOverflows(long x, long y, int bits) { + long result = x - y; + if (bits == 64) { + return (((x ^ y) & (x ^ result)) < 0); + } + return result < CodeUtil.minValue(bits) || result > CodeUtil.maxValue(bits); + } + + public static final ArithmeticOpTable OPS = new ArithmeticOpTable( + + new UnaryOp.Neg() { + + @Override + public Constant foldConstant(Constant value) { + PrimitiveConstant c = (PrimitiveConstant) value; + return JavaConstant.forIntegerKind(c.getJavaKind(), -c.asLong()); + } + + @Override + public Stamp foldStamp(Stamp s) { + IntegerStamp stamp = (IntegerStamp) s; + int bits = stamp.getBits(); + if (stamp.lowerBound() != CodeUtil.minValue(bits)) { + // TODO(ls) check if the mask calculation is correct... + return StampFactory.forInteger(bits, -stamp.upperBound(), -stamp.lowerBound()); + } else { + return stamp.unrestricted(); + } + } + }, + + new BinaryOp.Add(true, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() + b.asLong()); + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + IntegerStamp a = (IntegerStamp) stamp1; + IntegerStamp b = (IntegerStamp) stamp2; + + int bits = a.getBits(); + assert bits == b.getBits(); + + if (a.isUnrestricted()) { + return a; + } else if (b.isUnrestricted()) { + return b; + } + long defaultMask = CodeUtil.mask(bits); + long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask()); + long variableBitsWithCarry = variableBits | (carryBits(a.downMask(), b.downMask()) ^ carryBits(a.upMask(), b.upMask())); + long newDownMask = (a.downMask() + b.downMask()) & ~variableBitsWithCarry; + long newUpMask = (a.downMask() + b.downMask()) | variableBitsWithCarry; + + newDownMask &= defaultMask; + newUpMask &= defaultMask; + + long newLowerBound; + long newUpperBound; + boolean lowerOverflowsPositively = addOverflowsPositively(a.lowerBound(), b.lowerBound(), bits); + boolean upperOverflowsPositively = addOverflowsPositively(a.upperBound(), b.upperBound(), bits); + boolean lowerOverflowsNegatively = addOverflowsNegatively(a.lowerBound(), b.lowerBound(), bits); + boolean upperOverflowsNegatively = addOverflowsNegatively(a.upperBound(), b.upperBound(), bits); + if ((lowerOverflowsNegatively && !upperOverflowsNegatively) || (!lowerOverflowsPositively && upperOverflowsPositively)) { + newLowerBound = CodeUtil.minValue(bits); + newUpperBound = CodeUtil.maxValue(bits); + } else { + newLowerBound = CodeUtil.signExtend((a.lowerBound() + b.lowerBound()) & defaultMask, bits); + newUpperBound = CodeUtil.signExtend((a.upperBound() + b.upperBound()) & defaultMask, bits); + } + IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound); + newUpMask &= limit.upMask(); + newUpperBound = CodeUtil.signExtend(newUpperBound & newUpMask, bits); + newDownMask |= limit.downMask(); + newLowerBound |= newDownMask; + return new IntegerStamp(bits, newLowerBound, newUpperBound, newDownMask, newUpMask); + } + + @Override + public boolean isNeutral(Constant value) { + PrimitiveConstant n = (PrimitiveConstant) value; + return n.asLong() == 0; + } + }, + + new BinaryOp.Sub(true, false) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() - b.asLong()); + } + + @Override + public Stamp foldStamp(Stamp a, Stamp b) { + return OPS.getAdd().foldStamp(a, OPS.getNeg().foldStamp(b)); + } + + @Override + public boolean isNeutral(Constant value) { + PrimitiveConstant n = (PrimitiveConstant) value; + return n.asLong() == 0; + } + + @Override + public Constant getZero(Stamp s) { + IntegerStamp stamp = (IntegerStamp) s; + return JavaConstant.forPrimitiveInt(stamp.getBits(), 0); + } + }, + + new BinaryOp.Mul(true, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() * b.asLong()); + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + IntegerStamp a = (IntegerStamp) stamp1; + IntegerStamp b = (IntegerStamp) stamp2; + + int bits = a.getBits(); + assert bits == b.getBits(); + // if a==0 or b==0 result of a*b is always 0 + if (a.upMask() == 0) { + return a; + } else if (b.upMask() == 0) { + return b; + } else { + // if a has the full range or b, the result will also have it + if (a.isUnrestricted()) { + return a; + } else if (b.isUnrestricted()) { + return b; + } + // a!=0 && b !=0 holds + long newLowerBound = Long.MAX_VALUE; + long newUpperBound = Long.MIN_VALUE; + /* + * Based on the signs of the incoming stamps lower and upper bound + * of the result of the multiplication may be swapped. LowerBound + * can become upper bound if both signs are negative, and so on. To + * determine the new values for lower and upper bound we need to + * look at the max and min of the cases blow: + * + * @formatter:off + * + * a.lowerBound * b.lowerBound + * a.lowerBound * b.upperBound + * a.upperBound * b.lowerBound + * a.upperBound * b.upperBound + * + * @formatter:on + * + * We are only interested in those cases that are relevant due to + * the sign of the involved stamps (whether a stamp includes + * negative and / or positive values). Based on the signs, the maximum + * or minimum of the above multiplications form the new lower and + * upper bounds. + * + * The table below contains the interesting candidates for lower and + * upper bound after multiplication. + * + * For example if we consider two stamps a & b that both contain + * negative and positive values, the product of minN_a * minN_b + * (both the smallest negative value for each stamp) can only be the + * highest positive number. The other candidates can be computed in + * a similar fashion. Some of them can never be a new minimum or + * maximum and are therefore excluded. + * + * + * @formatter:off + * + * [x..........0..........y] + * ------------------------- + * [minN maxN minP maxP] + * where maxN = min(0,y) && minP = max(0,x) + * + * + * |minN_a maxN_a minP_a maxP_a + * _______|________________________________ + * minN_b |MAX / : / MIN + * maxN_b | / MIN : MAX / + * |---------------+---------------- + * minP_b | / MAX : MIN / + * maxP_b |MIN / : / MAX + * + * @formatter:on + */ + // We materialize all factors here. If they are needed, the signs of + // the stamp will ensure the correct value is used. + // Checkstyle: stop + long minN_a = a.lowerBound(); + long maxN_a = Math.min(0, a.upperBound()); + long minP_a = Math.max(0, a.lowerBound()); + long maxP_a = a.upperBound(); + + long minN_b = b.lowerBound(); + long maxN_b = Math.min(0, b.upperBound()); + long minP_b = Math.max(0, b.lowerBound()); + long maxP_b = b.upperBound(); + // Checkstyle: resume + + // multiplication has shift semantics + long newUpMask = ~CodeUtil.mask(Long.numberOfTrailingZeros(a.upMask) + Long.numberOfTrailingZeros(b.upMask)) & CodeUtil.mask(bits); + + if (a.canBePositive()) { + if (b.canBePositive()) { + if (multiplicationOverflows(maxP_a, maxP_b, bits)) { + return a.unrestricted(); + } + long maxCandidate = maxP_a * maxP_b; + if (multiplicationOverflows(minP_a, minP_b, bits)) { + return a.unrestricted(); + } + long minCandidate = minP_a * minP_b; + newLowerBound = Math.min(newLowerBound, minCandidate); + newUpperBound = Math.max(newUpperBound, maxCandidate); + } + if (b.canBeNegative()) { + if (multiplicationOverflows(minP_a, maxN_b, bits)) { + return a.unrestricted(); + } + long maxCandidate = minP_a * maxN_b; + if (multiplicationOverflows(maxP_a, minN_b, bits)) { + return a.unrestricted(); + } + long minCandidate = maxP_a * minN_b; + newLowerBound = Math.min(newLowerBound, minCandidate); + newUpperBound = Math.max(newUpperBound, maxCandidate); + } + } + if (a.canBeNegative()) { + if (b.canBePositive()) { + if (multiplicationOverflows(maxN_a, minP_b, bits)) { + return a.unrestricted(); + } + long maxCandidate = maxN_a * minP_b; + if (multiplicationOverflows(minN_a, maxP_b, bits)) { + return a.unrestricted(); + } + long minCandidate = minN_a * maxP_b; + newLowerBound = Math.min(newLowerBound, minCandidate); + newUpperBound = Math.max(newUpperBound, maxCandidate); + } + if (b.canBeNegative()) { + if (multiplicationOverflows(minN_a, minN_b, bits)) { + return a.unrestricted(); + } + long maxCandidate = minN_a * minN_b; + if (multiplicationOverflows(maxN_a, maxN_b, bits)) { + return a.unrestricted(); + } + long minCandidate = maxN_a * maxN_b; + newLowerBound = Math.min(newLowerBound, minCandidate); + newUpperBound = Math.max(newUpperBound, maxCandidate); + } + } + + assert newLowerBound <= newUpperBound; + return StampFactory.forIntegerWithMask(bits, newLowerBound, newUpperBound, 0, newUpMask); + } + } + + @Override + public boolean isNeutral(Constant value) { + PrimitiveConstant n = (PrimitiveConstant) value; + return n.asLong() == 1; + } + }, + + new BinaryOp.Div(true, false) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() / b.asLong()); + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + IntegerStamp a = (IntegerStamp) stamp1; + IntegerStamp b = (IntegerStamp) stamp2; + assert a.getBits() == b.getBits(); + if (b.isStrictlyPositive()) { + long newLowerBound = a.lowerBound() / b.upperBound(); + long newUpperBound = a.upperBound() / b.lowerBound(); + return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound); + } else { + return a.unrestricted(); + } + } + + @Override + public boolean isNeutral(Constant value) { + PrimitiveConstant n = (PrimitiveConstant) value; + return n.asLong() == 1; + } + }, + + new BinaryOp.Rem(false, false) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() % b.asLong()); + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + IntegerStamp a = (IntegerStamp) stamp1; + IntegerStamp b = (IntegerStamp) stamp2; + assert a.getBits() == b.getBits(); + // zero is always possible + long newLowerBound = Math.min(a.lowerBound(), 0); + long newUpperBound = Math.max(a.upperBound(), 0); + + /* the maximum absolute value of the result, derived from b */ + long magnitude; + if (b.lowerBound() == CodeUtil.minValue(b.getBits())) { + // Math.abs(...) - 1 does not work in a case + magnitude = CodeUtil.maxValue(b.getBits()); + } else { + magnitude = Math.max(Math.abs(b.lowerBound()), Math.abs(b.upperBound())) - 1; + } + newLowerBound = Math.max(newLowerBound, -magnitude); + newUpperBound = Math.min(newUpperBound, magnitude); + + return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound); + } + }, + + new UnaryOp.Not() { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forIntegerKind(value.getJavaKind(), ~value.asLong()); + } + + @Override + public Stamp foldStamp(Stamp stamp) { + IntegerStamp integerStamp = (IntegerStamp) stamp; + int bits = integerStamp.getBits(); + long defaultMask = CodeUtil.mask(bits); + return new IntegerStamp(bits, ~integerStamp.upperBound(), ~integerStamp.lowerBound(), (~integerStamp.upMask()) & defaultMask, (~integerStamp.downMask()) & defaultMask); + } + }, + + new BinaryOp.And(true, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() & b.asLong()); + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + IntegerStamp a = (IntegerStamp) stamp1; + IntegerStamp b = (IntegerStamp) stamp2; + assert a.getBits() == b.getBits(); + return stampForMask(a.getBits(), a.downMask() & b.downMask(), a.upMask() & b.upMask()); + } + + @Override + public boolean isNeutral(Constant value) { + PrimitiveConstant n = (PrimitiveConstant) value; + int bits = n.getJavaKind().getBitCount(); + long mask = CodeUtil.mask(bits); + return (n.asLong() & mask) == mask; + } + }, + + new BinaryOp.Or(true, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() | b.asLong()); + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + IntegerStamp a = (IntegerStamp) stamp1; + IntegerStamp b = (IntegerStamp) stamp2; + assert a.getBits() == b.getBits(); + return stampForMask(a.getBits(), a.downMask() | b.downMask(), a.upMask() | b.upMask()); + } + + @Override + public boolean isNeutral(Constant value) { + PrimitiveConstant n = (PrimitiveConstant) value; + return n.asLong() == 0; + } + }, + + new BinaryOp.Xor(true, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() ^ b.asLong()); + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + IntegerStamp a = (IntegerStamp) stamp1; + IntegerStamp b = (IntegerStamp) stamp2; + assert a.getBits() == b.getBits(); + + long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask()); + long newDownMask = (a.downMask() ^ b.downMask()) & ~variableBits; + long newUpMask = (a.downMask() ^ b.downMask()) | variableBits; + return stampForMask(a.getBits(), newDownMask, newUpMask); + } + + @Override + public boolean isNeutral(Constant value) { + PrimitiveConstant n = (PrimitiveConstant) value; + return n.asLong() == 0; + } + + @Override + public Constant getZero(Stamp s) { + IntegerStamp stamp = (IntegerStamp) s; + return JavaConstant.forPrimitiveInt(stamp.getBits(), 0); + } + }, + + new ShiftOp.Shl() { + + @Override + public Constant foldConstant(Constant value, int amount) { + PrimitiveConstant c = (PrimitiveConstant) value; + switch (c.getJavaKind()) { + case Int: + return JavaConstant.forInt(c.asInt() << amount); + case Long: + return JavaConstant.forLong(c.asLong() << amount); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp stamp, IntegerStamp shift) { + IntegerStamp value = (IntegerStamp) stamp; + int bits = value.getBits(); + long defaultMask = CodeUtil.mask(bits); + if (value.upMask() == 0) { + return value; + } + int shiftMask = getShiftAmountMask(stamp); + int shiftBits = Integer.bitCount(shiftMask); + if (shift.lowerBound() == shift.upperBound()) { + int shiftAmount = (int) (shift.lowerBound() & shiftMask); + if (shiftAmount == 0) { + return value; + } + // the mask of bits that will be lost or shifted into the sign bit + long removedBits = -1L << (bits - shiftAmount - 1); + if ((value.lowerBound() & removedBits) == 0 && (value.upperBound() & removedBits) == 0) { + /* + * use a better stamp if neither lower nor upper bound can lose + * bits + */ + return new IntegerStamp(bits, value.lowerBound() << shiftAmount, value.upperBound() << shiftAmount, value.downMask() << shiftAmount, value.upMask() << shiftAmount); + } + } + if ((shift.lowerBound() >>> shiftBits) == (shift.upperBound() >>> shiftBits)) { + long downMask = defaultMask; + long upMask = 0; + for (long i = shift.lowerBound(); i <= shift.upperBound(); i++) { + if (shift.contains(i)) { + downMask &= value.downMask() << (i & shiftMask); + upMask |= value.upMask() << (i & shiftMask); + } + } + Stamp result = IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask); + return result; + } + return value.unrestricted(); + } + + @Override + public int getShiftAmountMask(Stamp s) { + IntegerStamp stamp = (IntegerStamp) s; + assert CodeUtil.isPowerOf2(stamp.getBits()); + return stamp.getBits() - 1; + } + }, + + new ShiftOp.Shr() { + + @Override + public Constant foldConstant(Constant value, int amount) { + PrimitiveConstant c = (PrimitiveConstant) value; + switch (c.getJavaKind()) { + case Int: + return JavaConstant.forInt(c.asInt() >> amount); + case Long: + return JavaConstant.forLong(c.asLong() >> amount); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp stamp, IntegerStamp shift) { + IntegerStamp value = (IntegerStamp) stamp; + int bits = value.getBits(); + if (shift.lowerBound() == shift.upperBound()) { + long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp); + if (shiftCount == 0) { + return stamp; + } + + int extraBits = 64 - bits; + long defaultMask = CodeUtil.mask(bits); + // shifting back and forth performs sign extension + long downMask = (value.downMask() << extraBits) >> (shiftCount + extraBits) & defaultMask; + long upMask = (value.upMask() << extraBits) >> (shiftCount + extraBits) & defaultMask; + return new IntegerStamp(bits, value.lowerBound() >> shiftCount, value.upperBound() >> shiftCount, downMask, upMask); + } + long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound()); + return IntegerStamp.stampForMask(bits, 0, mask); + } + + @Override + public int getShiftAmountMask(Stamp s) { + IntegerStamp stamp = (IntegerStamp) s; + assert CodeUtil.isPowerOf2(stamp.getBits()); + return stamp.getBits() - 1; + } + }, + + new ShiftOp.UShr() { + + @Override + public Constant foldConstant(Constant value, int amount) { + PrimitiveConstant c = (PrimitiveConstant) value; + switch (c.getJavaKind()) { + case Int: + return JavaConstant.forInt(c.asInt() >>> amount); + case Long: + return JavaConstant.forLong(c.asLong() >>> amount); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Stamp foldStamp(Stamp stamp, IntegerStamp shift) { + IntegerStamp value = (IntegerStamp) stamp; + int bits = value.getBits(); + if (shift.lowerBound() == shift.upperBound()) { + long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp); + if (shiftCount == 0) { + return stamp; + } + + long downMask = value.downMask() >>> shiftCount; + long upMask = value.upMask() >>> shiftCount; + if (value.lowerBound() < 0) { + return new IntegerStamp(bits, downMask, upMask, downMask, upMask); + } else { + return new IntegerStamp(bits, value.lowerBound() >>> shiftCount, value.upperBound() >>> shiftCount, downMask, upMask); + } + } + long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound()); + return IntegerStamp.stampForMask(bits, 0, mask); + } + + @Override + public int getShiftAmountMask(Stamp s) { + IntegerStamp stamp = (IntegerStamp) s; + assert CodeUtil.isPowerOf2(stamp.getBits()); + return stamp.getBits() - 1; + } + }, + + new UnaryOp.Abs() { + + @Override + public Constant foldConstant(Constant value) { + PrimitiveConstant c = (PrimitiveConstant) value; + return JavaConstant.forIntegerKind(c.getJavaKind(), Math.abs(c.asLong())); + } + + @Override + public Stamp foldStamp(Stamp input) { + IntegerStamp stamp = (IntegerStamp) input; + int bits = stamp.getBits(); + if (stamp.lowerBound() == CodeUtil.minValue(bits)) { + return input.unrestricted(); + } else { + long limit = Math.max(-stamp.lowerBound(), stamp.upperBound()); + return StampFactory.forInteger(bits, 0, limit); + } + } + }, + + null, + + new IntegerConvertOp.ZeroExtend() { + + @Override + public Constant foldConstant(int inputBits, int resultBits, Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forPrimitiveInt(resultBits, CodeUtil.zeroExtend(value.asLong(), inputBits)); + } + + @Override + public Stamp foldStamp(int inputBits, int resultBits, Stamp input) { + IntegerStamp stamp = (IntegerStamp) input; + assert inputBits == stamp.getBits(); + assert inputBits <= resultBits; + + long downMask = CodeUtil.zeroExtend(stamp.downMask(), inputBits); + long upMask = CodeUtil.zeroExtend(stamp.upMask(), inputBits); + + if (stamp.lowerBound() < 0 && stamp.upperBound() >= 0) { + /* signed range including 0 and -1 */ + /* + * after sign extension, the whole range from 0 to MAX_INT is + * possible + */ + return IntegerStamp.stampForMask(resultBits, downMask, upMask); + } + + long lowerBound = CodeUtil.zeroExtend(stamp.lowerBound(), inputBits); + long upperBound = CodeUtil.zeroExtend(stamp.upperBound(), inputBits); + + return new IntegerStamp(resultBits, lowerBound, upperBound, downMask, upMask); + } + }, + + new IntegerConvertOp.SignExtend() { + + @Override + public Constant foldConstant(int inputBits, int resultBits, Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forPrimitiveInt(resultBits, CodeUtil.signExtend(value.asLong(), inputBits)); + } + + @Override + public Stamp foldStamp(int inputBits, int resultBits, Stamp input) { + IntegerStamp stamp = (IntegerStamp) input; + assert inputBits == stamp.getBits(); + assert inputBits <= resultBits; + + long defaultMask = CodeUtil.mask(resultBits); + long downMask = CodeUtil.signExtend(stamp.downMask(), inputBits) & defaultMask; + long upMask = CodeUtil.signExtend(stamp.upMask(), inputBits) & defaultMask; + + return new IntegerStamp(resultBits, stamp.lowerBound(), stamp.upperBound(), downMask, upMask); + } + }, + + new IntegerConvertOp.Narrow() { + + @Override + public Constant foldConstant(int inputBits, int resultBits, Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forPrimitiveInt(resultBits, CodeUtil.narrow(value.asLong(), resultBits)); + } + + @Override + public Stamp foldStamp(int inputBits, int resultBits, Stamp input) { + IntegerStamp stamp = (IntegerStamp) input; + assert inputBits == stamp.getBits(); + assert resultBits <= inputBits; + if (resultBits == inputBits) { + return stamp; + } + + final long upperBound; + if (stamp.lowerBound() < CodeUtil.minValue(resultBits)) { + upperBound = CodeUtil.maxValue(resultBits); + } else { + upperBound = saturate(stamp.upperBound(), resultBits); + } + final long lowerBound; + if (stamp.upperBound() > CodeUtil.maxValue(resultBits)) { + lowerBound = CodeUtil.minValue(resultBits); + } else { + lowerBound = saturate(stamp.lowerBound(), resultBits); + } + + long defaultMask = CodeUtil.mask(resultBits); + long newDownMask = stamp.downMask() & defaultMask; + long newUpMask = stamp.upMask() & defaultMask; + long newLowerBound = CodeUtil.signExtend((lowerBound | newDownMask) & newUpMask, resultBits); + long newUpperBound = CodeUtil.signExtend((upperBound | newDownMask) & newUpMask, resultBits); + return new IntegerStamp(resultBits, newLowerBound, newUpperBound, newDownMask, newUpMask); + } + }, + + new FloatConvertOp(I2F) { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forFloat(value.asInt()); + } + + @Override + public Stamp foldStamp(Stamp input) { + IntegerStamp stamp = (IntegerStamp) input; + assert stamp.getBits() == 32; + float lowerBound = stamp.lowerBound(); + float upperBound = stamp.upperBound(); + return StampFactory.forFloat(JavaKind.Float, lowerBound, upperBound, true); + } + }, + + new FloatConvertOp(L2F) { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forFloat(value.asLong()); + } + + @Override + public Stamp foldStamp(Stamp input) { + IntegerStamp stamp = (IntegerStamp) input; + assert stamp.getBits() == 64; + float lowerBound = stamp.lowerBound(); + float upperBound = stamp.upperBound(); + return StampFactory.forFloat(JavaKind.Float, lowerBound, upperBound, true); + } + }, + + new FloatConvertOp(I2D) { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forDouble(value.asInt()); + } + + @Override + public Stamp foldStamp(Stamp input) { + IntegerStamp stamp = (IntegerStamp) input; + assert stamp.getBits() == 32; + double lowerBound = stamp.lowerBound(); + double upperBound = stamp.upperBound(); + return StampFactory.forFloat(JavaKind.Double, lowerBound, upperBound, true); + } + }, + + new FloatConvertOp(L2D) { + + @Override + public Constant foldConstant(Constant c) { + PrimitiveConstant value = (PrimitiveConstant) c; + return JavaConstant.forDouble(value.asLong()); + } + + @Override + public Stamp foldStamp(Stamp input) { + IntegerStamp stamp = (IntegerStamp) input; + assert stamp.getBits() == 64; + double lowerBound = stamp.lowerBound(); + double upperBound = stamp.upperBound(); + return StampFactory.forFloat(JavaKind.Double, lowerBound, upperBound, true); + } + }); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ObjectStamp.java 2016-12-07 13:48:03.167652069 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012, 2014, 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.core.common.type; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +public class ObjectStamp extends AbstractObjectStamp { + + public ObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) { + super(type, exactType, nonNull, alwaysNull); + } + + @Override + protected ObjectStamp copyWith(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) { + return new ObjectStamp(type, exactType, nonNull, alwaysNull); + } + + @Override + public Stamp unrestricted() { + return StampFactory.object(); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append('a'); + appendString(str); + return str.toString(); + } + + @Override + public boolean isCompatible(Stamp other) { + if (this == other) { + return true; + } + if (other instanceof ObjectStamp) { + return true; + } + return false; + } + + @Override + public boolean isCompatible(Constant constant) { + if (constant instanceof JavaConstant) { + return ((JavaConstant) constant).getJavaKind().isObject(); + } + return false; + } + + @Override + public LIRKind getLIRKind(LIRKindTool tool) { + return tool.getObjectKind(); + } + + @Override + public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) { + return provider.readObjectConstant(base, displacement); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/PrimitiveStamp.java 2016-12-07 13:48:03.436663889 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2014, 2014, 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.core.common.type; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.MemoryAccessProvider; + +/** + * Type describing primitive values. + */ +public abstract class PrimitiveStamp extends ArithmeticStamp { + + private final int bits; + + protected PrimitiveStamp(int bits, ArithmeticOpTable ops) { + super(ops); + this.bits = bits; + } + + /** + * The width in bits of the value described by this stamp. + */ + public int getBits() { + return bits; + } + + public static int getBits(Stamp stamp) { + if (stamp instanceof PrimitiveStamp) { + return ((PrimitiveStamp) stamp).getBits(); + } else { + return 0; + } + } + + @Override + public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) { + return provider.readPrimitiveConstant(getStackKind(), base, displacement, getBits()); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + bits; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof PrimitiveStamp)) { + return false; + } + PrimitiveStamp other = (PrimitiveStamp) obj; + if (bits != other.bits) { + return false; + } + return super.equals(obj); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/RawPointerStamp.java 2016-12-07 13:48:03.701675534 -0800 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2015, 2016, 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.core.common.type; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.PrimitiveConstant; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Type describing pointers to raw memory. This stamp is used for example for direct pointers to + * fields or array elements. + */ +public class RawPointerStamp extends AbstractPointerStamp { + + protected RawPointerStamp() { + super(false, false); + } + + @Override + public LIRKind getLIRKind(LIRKindTool tool) { + return tool.getWordKind(); + } + + @Override + protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) { + // RawPointerStamp is a singleton + assert newNonNull == nonNull() && newAlwaysNull == alwaysNull(); + return this; + } + + @Override + public Stamp meet(Stamp other) { + assert isCompatible(other); + return this; + } + + @Override + public Stamp improveWith(Stamp other) { + return this; + } + + @Override + public Stamp join(Stamp other) { + assert isCompatible(other); + return this; + } + + @Override + public Stamp unrestricted() { + return this; + } + + @Override + public Stamp empty() { + // there is no empty pointer stamp + return this; + } + + @Override + public boolean hasValues() { + return true; + } + + @Override + public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { + throw GraalError.shouldNotReachHere("pointer has no Java type"); + } + + @Override + public Stamp constant(Constant c, MetaAccessProvider meta) { + return this; + } + + @Override + public boolean isCompatible(Stamp other) { + return other instanceof RawPointerStamp; + } + + @Override + public boolean isCompatible(Constant constant) { + if (constant instanceof PrimitiveConstant) { + return ((PrimitiveConstant) constant).getJavaKind().isNumericInteger(); + } else { + return constant instanceof DataPointerConstant; + } + } + + @Override + public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) { + throw GraalError.shouldNotReachHere("can't read raw pointer"); + } + + @Override + public String toString() { + return "void*"; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java 2016-12-07 13:48:03.966687178 -0800 @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2011, 2016, 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.core.common.type; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * A stamp is the basis for a type system. + */ +public abstract class Stamp { + + protected Stamp() { + } + + /** + * Returns the type of the stamp, guaranteed to be non-null. In some cases, this requires the + * lookup of class meta data, therefore the {@link MetaAccessProvider} is mandatory. + */ + public abstract ResolvedJavaType javaType(MetaAccessProvider metaAccess); + + public boolean alwaysDistinct(Stamp other) { + return join(other).isEmpty(); + } + + /** + * Gets a Java {@link JavaKind} that can be used to store a value of this stamp on the Java + * bytecode stack. Returns {@link JavaKind#Illegal} if a value of this stamp can not be stored + * on the bytecode stack. + */ + public abstract JavaKind getStackKind(); + + /** + * Gets a platform dependent {@link LIRKind} that can be used to store a value of this stamp. + */ + public abstract LIRKind getLIRKind(LIRKindTool tool); + + /** + * Returns the union of this stamp and the given stamp. Typically used to create stamps for phi + * nodes. + * + * @param other The stamp that will enlarge this stamp. + * @return The union of this stamp and the given stamp. + */ + public abstract Stamp meet(Stamp other); + + /** + * Returns the intersection of this stamp and the given stamp. + * + * @param other The stamp that will tighten this stamp. + * @return The intersection of this stamp and the given stamp. + */ + public abstract Stamp join(Stamp other); + + /** + * Returns a stamp of the same kind, but allowing the full value range of the kind. + * + * {@link #unrestricted()} is the neutral element of the {@link #join(Stamp)} operation. + */ + public abstract Stamp unrestricted(); + + /** + * Returns a stamp of the same kind, but with no allowed values. + * + * {@link #empty()} is the neutral element of the {@link #meet(Stamp)} operation. + */ + public abstract Stamp empty(); + + /** + * If it is possible to represent single value stamps of this kind, this method returns the + * stamp representing the single value c. stamp.constant(c).asConstant() should be equal to c. + *

+ * If it is not possible to represent single value stamps, this method returns a stamp that + * includes c, and is otherwise as narrow as possible. + */ + public abstract Stamp constant(Constant c, MetaAccessProvider meta); + + /** + * Test whether two stamps have the same base type. + */ + public abstract boolean isCompatible(Stamp other); + + /** + * Check that the constant {@code other} is compatible with this stamp. + * + * @param constant + */ + public abstract boolean isCompatible(Constant constant); + + /** + * Test whether this stamp has legal values. + */ + public abstract boolean hasValues(); + + /** + * Tests whether this stamp represents an illegal value. + */ + public final boolean isEmpty() { + return !hasValues(); + } + + /** + * If this stamp represents a single value, the methods returns this single value. It returns + * null otherwise. + * + * @return the constant corresponding to the single value of this stamp and null if this stamp + * can represent less or more than one value. + */ + public Constant asConstant() { + return null; + } + + /** + * Read a value of this stamp from memory. + */ + public abstract Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement); + + /** + * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new + * improved stamp. Otherwise, returns a stamp equal to this. + * + * @param other the stamp that should be used to improve this stamp + * @return the newly improved stamp or a stamp equal to {@code this} if an improvement was not + * possible + */ + public abstract Stamp improveWith(Stamp other); + + /** + * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new + * improved stamp. Otherwise, returns null. + * + * @param other the stamp that should be used to improve this stamp + * @return the newly improved stamp or {@code null} if an improvement was not possible + */ + public final Stamp tryImproveWith(Stamp other) { + Stamp improved = improveWith(other); + if (improved.equals(this)) { + return null; + } + return improved; + } + + public boolean neverDistinct(Stamp other) { + Constant constant = this.asConstant(); + if (constant != null) { + Constant otherConstant = other.asConstant(); + return otherConstant != null && constant.equals(otherConstant); + } + return false; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java 2016-12-07 13:48:04.232698867 -0800 @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2011, 2016, 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.core.common.type; + +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Signature; + +public class StampFactory { + + /* + * The marker stamp for node intrinsics must be its own class, so that it is never equal() to a + * regular ObjectStamp. + */ + static final class NodeIntrinsicStamp extends ObjectStamp { + protected static final Stamp SINGLETON = new NodeIntrinsicStamp(); + + private NodeIntrinsicStamp() { + super(null, false, false, false); + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(Object obj) { + return this == obj; + } + } + + // JaCoCo Exclude + + private static final Stamp[] stampCache = new Stamp[JavaKind.values().length]; + private static final Stamp[] emptyStampCache = new Stamp[JavaKind.values().length]; + private static final Stamp objectStamp = new ObjectStamp(null, false, false, false); + private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false); + private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true); + private static final Stamp positiveInt = forInteger(JavaKind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE); + private static final Stamp booleanTrue = forInteger(JavaKind.Boolean, -1, -1, 1, 1); + private static final Stamp booleanFalse = forInteger(JavaKind.Boolean, 0, 0, 0, 0); + private static final Stamp rawPointer = new RawPointerStamp(); + + private static void setCache(JavaKind kind, Stamp stamp) { + stampCache[kind.ordinal()] = stamp; + } + + private static void setIntCache(JavaKind kind) { + int bits = kind.getStackKind().getBitCount(); + long mask; + if (kind.isUnsigned()) { + mask = CodeUtil.mask(kind.getBitCount()); + } else { + mask = CodeUtil.mask(bits); + } + setCache(kind, new IntegerStamp(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask)); + } + + private static void setFloatCache(JavaKind kind) { + setCache(kind, new FloatStamp(kind.getBitCount())); + } + + static { + setIntCache(JavaKind.Boolean); + setIntCache(JavaKind.Byte); + setIntCache(JavaKind.Short); + setIntCache(JavaKind.Char); + setIntCache(JavaKind.Int); + setIntCache(JavaKind.Long); + + setFloatCache(JavaKind.Float); + setFloatCache(JavaKind.Double); + + setCache(JavaKind.Object, objectStamp); + setCache(JavaKind.Void, VoidStamp.getInstance()); + setCache(JavaKind.Illegal, IllegalStamp.getInstance()); + + for (JavaKind k : JavaKind.values()) { + if (stampCache[k.ordinal()] != null) { + emptyStampCache[k.ordinal()] = stampCache[k.ordinal()].empty(); + } + } + } + + public static Stamp tautology() { + return booleanTrue; + } + + public static Stamp contradiction() { + return booleanFalse; + } + + /** + * Return a stamp for a Java kind, as it would be represented on the bytecode stack. + */ + public static Stamp forKind(JavaKind kind) { + assert stampCache[kind.ordinal()] != null : "unexpected forKind(" + kind + ")"; + return stampCache[kind.ordinal()]; + } + + /** + * Return the stamp for the {@code void} type. This will return a singleton instance than can be + * compared using {@code ==}. + */ + public static Stamp forVoid() { + return VoidStamp.getInstance(); + } + + /** + * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by an + * actual stamp when the intrinsic is used, i.e., when the snippet template is instantiated. + */ + public static Stamp forNodeIntrinsic() { + return NodeIntrinsicStamp.SINGLETON; + } + + public static Stamp intValue() { + return forKind(JavaKind.Int); + } + + public static Stamp positiveInt() { + return positiveInt; + } + + public static Stamp empty(JavaKind kind) { + return emptyStampCache[kind.ordinal()]; + } + + public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound, long downMask, long upMask) { + return new IntegerStamp(kind.getBitCount(), lowerBound, upperBound, downMask, upMask); + } + + public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound) { + return forInteger(kind.getBitCount(), lowerBound, upperBound); + } + + /** + * Create a new stamp use {@code newLowerBound} and {@code newUpperBound} computing the + * appropriate {@link IntegerStamp#upMask} and {@link IntegerStamp#downMask} and incorporating + * any mask information from {@code maskStamp}. + * + * @param bits + * @param newLowerBound + * @param newUpperBound + * @param maskStamp + * @return a new stamp with the appropriate bounds and masks + */ + public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, IntegerStamp maskStamp) { + IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound); + return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | maskStamp.downMask(), limit.upMask() & maskStamp.upMask()); + } + + public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, long newDownMask, long newUpMask) { + IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound); + return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask); + } + + public static IntegerStamp forInteger(int bits) { + return new IntegerStamp(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits)); + } + + public static IntegerStamp forInteger(int bits, long lowerBound, long upperBound) { + long defaultMask = CodeUtil.mask(bits); + if (lowerBound == upperBound) { + return new IntegerStamp(bits, lowerBound, lowerBound, lowerBound & defaultMask, lowerBound & defaultMask); + } + final long downMask; + final long upMask; + if (lowerBound >= 0) { + int upperBoundLeadingZeros = Long.numberOfLeadingZeros(upperBound); + long differentBits = lowerBound ^ upperBound; + int sameBitCount = Long.numberOfLeadingZeros(differentBits << upperBoundLeadingZeros); + + upMask = upperBound | -1L >>> (upperBoundLeadingZeros + sameBitCount); + downMask = upperBound & ~(-1L >>> (upperBoundLeadingZeros + sameBitCount)); + } else { + if (upperBound >= 0) { + upMask = defaultMask; + downMask = 0; + } else { + int lowerBoundLeadingOnes = Long.numberOfLeadingZeros(~lowerBound); + long differentBits = lowerBound ^ upperBound; + int sameBitCount = Long.numberOfLeadingZeros(differentBits << lowerBoundLeadingOnes); + + upMask = lowerBound | -1L >>> (lowerBoundLeadingOnes + sameBitCount) | ~(-1L >>> lowerBoundLeadingOnes); + downMask = lowerBound & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes); + } + } + return new IntegerStamp(bits, lowerBound, upperBound, downMask & defaultMask, upMask & defaultMask); + } + + public static FloatStamp forFloat(JavaKind kind, double lowerBound, double upperBound, boolean nonNaN) { + assert kind.isNumericFloat(); + return new FloatStamp(kind.getBitCount(), lowerBound, upperBound, nonNaN); + } + + public static Stamp forConstant(JavaConstant value) { + JavaKind kind = value.getJavaKind(); + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + long mask = value.asLong() & CodeUtil.mask(kind.getBitCount()); + return forInteger(kind.getStackKind(), value.asLong(), value.asLong(), mask, mask); + case Float: + return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat())); + case Double: + return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble())); + case Illegal: + return forKind(JavaKind.Illegal); + case Object: + if (value.isNull()) { + return alwaysNull(); + } else { + return objectNonNull(); + } + default: + throw new GraalError("unexpected kind: %s", kind); + } + } + + public static Stamp forConstant(JavaConstant value, MetaAccessProvider metaAccess) { + if (value.getJavaKind() == JavaKind.Object) { + ResolvedJavaType type = value.isNull() ? null : metaAccess.lookupJavaType(value); + return new ObjectStamp(type, value.isNonNull(), value.isNonNull(), value.isNull()); + } else { + return forConstant(value); + } + } + + public static Stamp object() { + return objectStamp; + } + + public static Stamp objectNonNull() { + return objectNonNullStamp; + } + + public static Stamp alwaysNull() { + return objectAlwaysNullStamp; + } + + public static ObjectStamp object(TypeReference type) { + return object(type, false); + } + + public static ObjectStamp objectNonNull(TypeReference type) { + return object(type, true); + } + + public static ObjectStamp object(TypeReference type, boolean nonNull) { + if (type == null) { + return new ObjectStamp(null, false, nonNull, false); + } else { + return new ObjectStamp(type.getType(), type.isExact(), nonNull, false); + } + } + + public static Stamp[] createParameterStamps(Assumptions assumptions, ResolvedJavaMethod method) { + Signature sig = method.getSignature(); + Stamp[] result = new Stamp[sig.getParameterCount(!method.isStatic())]; + int index = 0; + + if (!method.isStatic()) { + result[index++] = StampFactory.objectNonNull(TypeReference.create(assumptions, method.getDeclaringClass())); + } + + int max = sig.getParameterCount(false); + ResolvedJavaType accessingClass = method.getDeclaringClass(); + for (int i = 0; i < max; i++) { + JavaType type = sig.getParameterType(i, accessingClass); + JavaKind kind = type.getJavaKind(); + Stamp stamp; + if (kind == JavaKind.Object && type instanceof ResolvedJavaType) { + stamp = StampFactory.object(TypeReference.create(assumptions, (ResolvedJavaType) type)); + } else { + stamp = StampFactory.forKind(kind); + } + result[index++] = stamp; + } + + return result; + } + + public static Stamp pointer() { + return rawPointer; + } + + public static StampPair forDeclaredType(Assumptions assumptions, JavaType returnType, boolean nonNull) { + if (returnType.getJavaKind() == JavaKind.Object && returnType instanceof ResolvedJavaType) { + ResolvedJavaType resolvedJavaType = (ResolvedJavaType) returnType; + TypeReference reference = TypeReference.create(assumptions, resolvedJavaType); + if (resolvedJavaType.isInterface()) { + ResolvedJavaType implementor = resolvedJavaType.getSingleImplementor(); + if (implementor != null && !resolvedJavaType.equals(implementor)) { + TypeReference uncheckedType = TypeReference.createTrusted(assumptions, implementor); + return StampPair.create(StampFactory.object(reference, nonNull), StampFactory.object(uncheckedType, nonNull)); + } + } + return StampPair.createSingle(StampFactory.object(reference, nonNull)); + } else { + return StampPair.createSingle(StampFactory.forKind(returnType.getJavaKind())); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampPair.java 2016-12-07 13:48:04.497710511 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016, 2016, 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.core.common.type; + +/** + * A pair of stamp with one being the stamp that can be trusted and the other one being a guess that + * needs a dynamic check to be used. + */ +public final class StampPair { + + private final Stamp trustedStamp; + private final Stamp uncheckedStamp; + + private StampPair(Stamp trustedStamp, Stamp uncheckedStamp) { + assert trustedStamp != null; + this.trustedStamp = trustedStamp; + this.uncheckedStamp = uncheckedStamp; + } + + public static StampPair create(Stamp trustedStamp, Stamp uncheckedStamp) { + return new StampPair(trustedStamp, uncheckedStamp); + } + + public static StampPair createSingle(Stamp stamp) { + return new StampPair(stamp, null); + } + + public Stamp getUncheckedStamp() { + return uncheckedStamp; + } + + public Stamp getTrustedStamp() { + return trustedStamp; + } + + @Override + public String toString() { + if (uncheckedStamp == null) { + return trustedStamp.toString(); + } else { + return trustedStamp + " (unchecked=" + uncheckedStamp + ")"; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/TypeReference.java 2016-12-07 13:48:04.762722156 -0800 @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2016, 2016, 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.core.common.type; + +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * This class represents a reference to a Java type and whether this reference is referring only to + * the represented type or also to its sub types in the class hierarchy. When creating a type + * reference, the following options have to be considered: + * + *

    + *
  • The reference should always only refer to the given concrete type. Use + * {@link #createExactTrusted(ResolvedJavaType)} for this purpose.
  • + *
  • The reference should be created without assumptions about the class hierarchy. The returned + * reference is exact only when the type is a leaf type (i.e., it cannot have subclasses). Depending + * on whether interface types can be trusted for this type reference use + * {@link #createWithoutAssumptions} or {@link #createTrustedWithoutAssumptions}.
  • + *
  • The reference should be created using assumptions about the class hierarchy. The returned + * reference is also exact, when there is only a single concrete sub type for the given type. + * Depending on whether interface types can be trusted for this type reference use {@link #create} + * or {@link #createTrusted}.
  • + *
+ * + * For the methods with untrusted interface types, a {@code null} reference will be constructed for + * untrusted interface types. Examples for interface types that cannot be trusted are types for + * parameters, fields, and return values. They are not checked by the Java verifier. + * + */ +public final class TypeReference { + private final ResolvedJavaType type; + private final boolean exactReference; + + private TypeReference(ResolvedJavaType type, boolean exactReference) { + this.type = type; + this.exactReference = exactReference; + } + + /** + * Creates an exact type reference using the given type. + */ + public static TypeReference createExactTrusted(ResolvedJavaType type) { + if (type == null) { + return null; + } + return new TypeReference(type, true); + } + + /** + * Creates a type reference using the given type without assumptions and without trusting + * interface types. + */ + public static TypeReference createWithoutAssumptions(ResolvedJavaType type) { + return create(null, type); + } + + /** + * Creates a type reference using the given type without assumptions and trusting interface + * types. + */ + public static TypeReference createTrustedWithoutAssumptions(ResolvedJavaType type) { + return createTrusted(null, type); + } + + /** + * Creates a type reference using the given type with assumptions and without trusting interface + * types. + */ + public static TypeReference create(Assumptions assumptions, ResolvedJavaType type) { + return createTrusted(assumptions, filterInterfaceTypesOut(type)); + } + + /** + * Create a type reference using the given type with assumptions and trusting interface types. + */ + public static TypeReference createTrusted(Assumptions assumptions, ResolvedJavaType type) { + if (type == null) { + return null; + } + ResolvedJavaType exactType = type.isLeaf() ? type : null; + if (exactType == null) { + Assumptions.AssumptionResult leafConcreteSubtype = type.findLeafConcreteSubtype(); + if (leafConcreteSubtype != null && leafConcreteSubtype.canRecordTo(assumptions)) { + leafConcreteSubtype.recordTo(assumptions); + exactType = leafConcreteSubtype.getResult(); + } + } + if (exactType == null) { + return new TypeReference(type, false); + } + return new TypeReference(exactType, true); + } + + /** + * The type this reference refers to. + */ + public ResolvedJavaType getType() { + return type; + } + + /** + * @return {@code true} if this reference is exact and only refers to the given type and + * {@code false} if it also refers to its sub types. + */ + public boolean isExact() { + return exactReference; + } + + /** + * @return A new reference that is guaranteed to be exact. + */ + public TypeReference asExactReference() { + if (isExact()) { + return this; + } + return new TypeReference(type, true); + } + + private static ResolvedJavaType filterInterfaceTypesOut(ResolvedJavaType type) { + if (type != null) { + if (type.isArray()) { + ResolvedJavaType componentType = filterInterfaceTypesOut(type.getComponentType()); + if (componentType != null) { + return componentType.getArrayClass(); + } + // Returns Object[].class + return type.getSuperclass().getArrayClass(); + } + if (type.isInterface()) { + return null; + } + } + return type; + } + + @Override + public String toString() { + return (isExact() ? "#" : "") + type; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/VoidStamp.java 2016-12-07 13:48:05.027733800 -0800 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2014, 2015, 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.core.common.type; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Singleton stamp representing the value of type {@code void}. + */ +public final class VoidStamp extends Stamp { + + private VoidStamp() { + } + + @Override + public Stamp unrestricted() { + return this; + } + + @Override + public JavaKind getStackKind() { + return JavaKind.Void; + } + + @Override + public Stamp improveWith(Stamp other) { + assert other instanceof VoidStamp; + return this; + } + + @Override + public LIRKind getLIRKind(LIRKindTool tool) { + throw GraalError.shouldNotReachHere("void stamp has no value"); + } + + @Override + public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { + return metaAccess.lookupJavaType(Void.TYPE); + } + + @Override + public String toString() { + return "void"; + } + + @Override + public boolean alwaysDistinct(Stamp other) { + return this != other; + } + + @Override + public Stamp meet(Stamp other) { + assert other instanceof VoidStamp; + return this; + } + + @Override + public Stamp join(Stamp other) { + assert other instanceof VoidStamp; + return this; + } + + @Override + public boolean isCompatible(Stamp stamp) { + return stamp instanceof VoidStamp; + } + + @Override + public boolean isCompatible(Constant constant) { + return false; + } + + @Override + public Stamp empty() { + // the void stamp is always empty + return this; + } + + @Override + public boolean hasValues() { + return false; + } + + @Override + public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) { + throw GraalError.shouldNotReachHere("can't read values of void stamp"); + } + + @Override + public Stamp constant(Constant c, MetaAccessProvider meta) { + throw GraalError.shouldNotReachHere("void stamp has no value"); + } + + private static final VoidStamp instance = new VoidStamp(); + + static VoidStamp getInstance() { + return instance; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ArrayMap.java 2016-12-07 13:48:05.292745444 -0800 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2009, 2011, 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.core.common.util; + +/** + * The {@code ArrayMap} class implements an efficient one-level map which is implemented as an + * array. Note that because of the one-level array inside, this data structure performs best when + * the range of integer keys is small and densely used. Note that the implementation can handle + * arbitrary intervals, including negative numbers, up to intervals of size 2^31 - 1. + */ +public class ArrayMap { + + private static final int INITIAL_SIZE = 5; // how big the initial array should be + private static final int EXTRA = 2; // how far on the left or right of a new element to grow + + Object[] map; + int low; + + /** + * Constructs a new {@code ArrayMap} with no initial assumptions. + */ + public ArrayMap() { + } + + /** + * Constructs a new {@code ArrayMap} that initially covers the specified interval. Note that + * this map will automatically expand if necessary later. + * + * @param low the low index, inclusive + * @param high the high index, exclusive + */ + public ArrayMap(int low, int high) { + this.low = low; + this.map = new Object[high - low + 1]; + } + + /** + * Puts a new value in the map at the specified index. + * + * @param i the index at which to store the value + * @param value the value to store at the specified index + */ + public void put(int i, T value) { + int index = i - low; + if (map == null) { + // no map yet + map = new Object[INITIAL_SIZE]; + low = index - 2; + map[INITIAL_SIZE / 2] = value; + } else if (index < 0) { + // grow backwards + growBackward(i, value); + } else if (index >= map.length) { + // grow forwards + growForward(i, value); + } else { + // no growth necessary + map[index] = value; + } + } + + /** + * Gets the value at the specified index in the map. + * + * @param i the index + * @return the value at the specified index; {@code null} if there is no value at the specified + * index, or if the index is out of the currently stored range + */ + public T get(int i) { + int index = i - low; + if (map == null || index < 0 || index >= map.length) { + return null; + } + Class type = null; + return Util.uncheckedCast(type, map[index]); + } + + public int length() { + return map.length; + } + + private void growBackward(int i, T value) { + int nlow = i - EXTRA; + Object[] nmap = new Object[low - nlow + map.length]; + System.arraycopy(map, 0, nmap, low - nlow, map.length); + map = nmap; + low = nlow; + map[i - low] = value; + } + + private void growForward(int i, T value) { + int nlen = i - low + 1 + EXTRA; + Object[] nmap = new Object[nlen]; + System.arraycopy(map, 0, nmap, 0, map.length); + map = nmap; + map[i - low] = value; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ArraySet.java 2016-12-07 13:48:05.557757089 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.common.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * Mimic a set implementation with an ArrayList. Beneficial for small sets (compared to + * {@link HashSet}). + */ +public class ArraySet extends ArrayList implements Set { + private static final long serialVersionUID = 4476957522387436654L; + + public ArraySet() { + super(); + } + + public ArraySet(int i) { + super(i); + } + + public ArraySet(Collection c) { + super(c); + } + + @Override + public boolean add(E e) { + // avoid duplicated entries + if (contains(e)) { + return false; + } + return super.add(e); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/BitMap2D.java 2016-12-07 13:48:05.822768733 -0800 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2009, 2011, 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.core.common.util; + +import java.util.BitSet; + +/** + * This class implements a two-dimensional bitmap. + */ +public final class BitMap2D { + + private BitSet map; + private final int bitsPerSlot; + + private int bitIndex(int slotIndex, int bitWithinSlotIndex) { + return slotIndex * bitsPerSlot + bitWithinSlotIndex; + } + + private boolean verifyBitWithinSlotIndex(int index) { + assert index < bitsPerSlot : "index " + index + " is out of bounds " + bitsPerSlot; + return true; + } + + public BitMap2D(int sizeInSlots, int bitsPerSlot) { + map = new BitSet(sizeInSlots * bitsPerSlot); + this.bitsPerSlot = bitsPerSlot; + } + + public int sizeInBits() { + return map.size(); + } + + // Returns number of full slots that have been allocated + public int sizeInSlots() { + return map.size() / bitsPerSlot; + } + + public boolean isValidIndex(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + return (bitIndex(slotIndex, bitWithinSlotIndex) < sizeInBits()); + } + + public boolean at(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + return map.get(bitIndex(slotIndex, bitWithinSlotIndex)); + } + + public void setBit(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + map.set(bitIndex(slotIndex, bitWithinSlotIndex)); + } + + public void clearBit(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + map.clear(bitIndex(slotIndex, bitWithinSlotIndex)); + } + + public void atPutGrow(int slotIndex, int bitWithinSlotIndex, boolean value) { + int size = sizeInSlots(); + if (size <= slotIndex) { + while (size <= slotIndex) { + size *= 2; + } + BitSet newBitMap = new BitSet(size * bitsPerSlot); + newBitMap.or(map); + map = newBitMap; + } + + if (value) { + setBit(slotIndex, bitWithinSlotIndex); + } else { + clearBit(slotIndex, bitWithinSlotIndex); + } + } + + public void clear() { + map.clear(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/CompilationAlarm.java 2016-12-07 13:48:06.088780422 -0800 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2016, 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.core.common.util; + +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +/** + * Utility class that allows the compiler to monitor compilations that take a very long time. + */ +public final class CompilationAlarm implements AutoCloseable { + + public static class Options { + // @formatter:off + @Option(help = "Time limit in seconds before a compilation expires (0 to disable the limit).", type = OptionType.Debug) + public static final OptionValue CompilationExpirationPeriod = new OptionValue<>(300); + // @formatter:on + } + + private CompilationAlarm() { + } + + private static boolean enabled() { + return Options.CompilationExpirationPeriod.getValue() > 0; + } + + /** + * Thread local storage for compilation start timestamps. Everytime a compiler thread calls + * {@link #trackCompilationPeriod()} it will save the start timestamp of the compilation. + */ + private static final ThreadLocal compilationStartedTimeStamps = new ThreadLocal<>(); + + private static boolean compilationStarted() { + if (enabled()) { + Long start = compilationStartedTimeStamps.get(); + if (start == null) { + compilationStartedTimeStamps.set(System.currentTimeMillis()); + return true; + } + } + return false; + } + + private static void compilationFinished() { + if (enabled()) { + assert compilationStartedTimeStamps.get() != null; + compilationStartedTimeStamps.set(null); + } + } + + /** + * Determines if the current compilation is expired. A compilation expires if it takes longer + * than {@linkplain CompilationAlarm.Options#CompilationExpirationPeriod}. + * + * @return {@code true} if the current compilation already takes longer than + * {@linkplain CompilationAlarm.Options#CompilationExpirationPeriod}, {@code false} + * otherwise + */ + public static boolean hasExpired() { + if (enabled()) { + Long start = compilationStartedTimeStamps.get(); + if (start != null) { + long time = System.currentTimeMillis(); + assert time >= start; + return time - start > Options.CompilationExpirationPeriod.getValue() * 1000; + } + } + return false; + } + + @Override + public void close() { + compilationFinished(); + } + + private static final CompilationAlarm INSTANCE = enabled() ? new CompilationAlarm() : null; + + /** + * Gets an object that can be used in a try-with-resource statement to set an time limit based + * alarm for a compilation. + * + * @return a {@link CompilationAlarm} instance if there is no current alarm for the calling + * thread otherwise {@code null} + */ + public static CompilationAlarm trackCompilationPeriod() { + if (compilationStarted()) { + return INSTANCE; + } + return null; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java 2016-12-07 13:48:06.354792110 -0800 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015, 2015, 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.core.common.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +/** + * Creates an array of T objects order by the occurrence frequency of each object. The most + * frequently used object is the first one, the least frequently used the last one. If {@code null} + * is added, it is always the first element. + * + * Either object {@link #createIdentityEncoder() identity} or object {@link #createEqualityEncoder() + * equality} can be used to build the array and count the frequency. + */ +public class FrequencyEncoder { + + static class Entry { + protected final T object; + protected int frequency; + protected int index; + + protected Entry(T object) { + this.object = object; + this.index = -1; + } + } + + protected final Map> map; + protected boolean containsNull; + + /** + * Creates an encoder that uses object identity. + */ + public static FrequencyEncoder createIdentityEncoder() { + return new FrequencyEncoder<>(new IdentityHashMap<>()); + } + + /** + * Creates an encoder that uses {@link Object#equals(Object) object equality}. + */ + public static FrequencyEncoder createEqualityEncoder() { + return new FrequencyEncoder<>(new HashMap<>()); + } + + protected FrequencyEncoder(Map> map) { + this.map = map; + } + + /** + * Adds an object to the array. + */ + public void addObject(T object) { + if (object == null) { + containsNull = true; + return; + } + + Entry entry = map.get(object); + if (entry == null) { + entry = new Entry<>(object); + map.put(object, entry); + } + entry.frequency++; + } + + /** + * Returns the index of an object in the array. The object must have been + * {@link #addObject(Object) added} before. + */ + public int getIndex(Object object) { + if (object == null) { + assert containsNull; + return 0; + } + Entry entry = map.get(object); + assert entry != null && entry.index >= 0; + return entry.index; + } + + /** + * Returns the number of distinct objects that have been added, i.e., the length of the array. + */ + public int getLength() { + return map.size() + (containsNull ? 1 : 0); + } + + /** + * Fills the provided array with the added objects. The array must have the {@link #getLength() + * correct length}. + */ + public T[] encodeAll(T[] allObjects) { + assert allObjects.length == getLength(); + List> sortedEntries = new ArrayList<>(map.values()); + sortedEntries.sort((e1, e2) -> -Integer.compare(e1.frequency, e2.frequency)); + + int offset = 0; + if (containsNull) { + allObjects[0] = null; + offset = 1; + } + for (int i = 0; i < sortedEntries.size(); i++) { + Entry entry = sortedEntries.get(i); + int index = i + offset; + entry.index = index; + allObjects[index] = entry.object; + assert entry.object != null; + } + return allObjects; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/IntList.java 2016-12-07 13:48:06.620803799 -0800 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2010, 2011, 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.core.common.util; + +import java.util.Arrays; + +/** + * An expandable and indexable list of {@code int}s. + * + * This class avoids the boxing/unboxing incurred by {@code ArrayList}. + */ +public final class IntList { + + private int[] array; + private int size; + + /** + * Creates an int list with a specified initial capacity. + * + * @param initialCapacity + */ + public IntList(int initialCapacity) { + array = new int[initialCapacity]; + } + + /** + * Creates an int list with a specified initial array. + * + * @param array the initial array used for the list (no copy is made) + * @param initialSize the initial {@linkplain #size() size} of the list (must be less than or + * equal to {@code array.length} + */ + public IntList(int[] array, int initialSize) { + assert initialSize <= array.length; + this.array = array; + this.size = initialSize; + } + + /** + * Makes a new int list by copying a range from a given int list. + * + * @param other the list from which a range of values is to be copied into the new list + * @param startIndex the index in {@code other} at which to start copying + * @param length the number of values to copy from {@code other} + * @return a new int list whose {@linkplain #size() size} and capacity is {@code length} + */ + public static IntList copy(IntList other, int startIndex, int length) { + return copy(other, startIndex, length, length); + } + + /** + * Makes a new int list by copying a range from a given int list. + * + * @param other the list from which a range of values is to be copied into the new list + * @param startIndex the index in {@code other} at which to start copying + * @param length the number of values to copy from {@code other} + * @param initialCapacity the initial capacity of the new int list (must be greater or equal to + * {@code length}) + * @return a new int list whose {@linkplain #size() size} is {@code length} + */ + public static IntList copy(IntList other, int startIndex, int length, int initialCapacity) { + assert initialCapacity >= length : "initialCapacity < length"; + int[] array = new int[initialCapacity]; + System.arraycopy(other.array, startIndex, array, 0, length); + return new IntList(array, length); + } + + public int size() { + return size; + } + + /** + * Appends a value to the end of this list, increasing its {@linkplain #size() size} by 1. + * + * @param value the value to append + */ + public void add(int value) { + if (size == array.length) { + int newSize = (size * 3) / 2 + 1; + array = Arrays.copyOf(array, newSize); + } + array[size++] = value; + } + + /** + * Gets the value in this list at a given index. + * + * @param index the index of the element to return + * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()} + */ + public int get(int index) { + if (index >= size) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + return array[index]; + } + + /** + * Sets the size of this list to 0. + */ + public void clear() { + size = 0; + } + + /** + * Sets a value at a given index in this list. + * + * @param index the index of the element to update + * @param value the new value of the element + * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()} + */ + public void set(int index, int value) { + if (index >= size) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + array[index] = value; + } + + /** + * Adjusts the {@linkplain #size() size} of this int list. + * + * If {@code newSize < size()}, the size is changed to {@code newSize}. If + * {@code newSize > size()}, sufficient 0 elements are {@linkplain #add(int) added} until + * {@code size() == newSize}. + * + * @param newSize the new size of this int list + */ + public void setSize(int newSize) { + if (newSize < size) { + size = newSize; + } else if (newSize > size) { + array = Arrays.copyOf(array, newSize); + } + } + + @Override + public String toString() { + if (array.length == size) { + return Arrays.toString(array); + } + return Arrays.toString(Arrays.copyOf(array, size)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ModuleAPI.java 2016-12-07 13:48:06.887815531 -0800 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2016, 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.core.common.util; + +import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Reflection based access to the Module API introduced by JDK 9. This allows the API to be used in + * code that must be compiled on a JDK prior to 9. Use of this class must be guarded by a test for + * JDK 9 or later. For example: + * + *
+ * if (Util.JAVA_SPECIFICATION_VERSION >= 9) {
+ *     // Use of ModuleAPI
+ * }
+ * 
+ */ +public final class ModuleAPI { + + private ModuleAPI(Method method) { + this.method = method; + } + + private final Method method; + + /** + * {@code Class.getModule()}. + */ + public static final ModuleAPI getModule; + + /** + * {@code jdk.internal.module.Modules.addExports(Module, String, Module)}. + */ + public static final ModuleAPI addExports; + + /** + * {@code java.lang.reflect.Module.getResourceAsStream(String)}. + */ + public static final ModuleAPI getResourceAsStream; + + /** + * {@code java.lang.reflect.Module.canRead(Module)}. + */ + public static final ModuleAPI canRead; + + /** + * {@code java.lang.reflect.Module.isExported(String)}. + */ + public static final ModuleAPI isExported; + + /** + * {@code java.lang.reflect.Module.isExported(String, Module)}. + */ + public static final ModuleAPI isExportedTo; + + /** + * Invokes the static Module API method represented by this object. + */ + @SuppressWarnings("unchecked") + public T invokeStatic(Object... args) { + checkAvailability(); + assert Modifier.isStatic(method.getModifiers()); + try { + return (T) method.invoke(null, args); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new InternalError(e); + } + } + + /** + * Invokes the non-static Module API method represented by this object. + */ + @SuppressWarnings("unchecked") + public T invoke(Object receiver, Object... args) { + checkAvailability(); + assert !Modifier.isStatic(method.getModifiers()); + try { + return (T) method.invoke(receiver, args); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new InternalError(e); + } + } + + private void checkAvailability() throws InternalError { + if (method == null) { + throw new InternalError("Cannot use Module API on JDK " + JAVA_SPECIFICATION_VERSION); + } + } + + static { + if (JAVA_SPECIFICATION_VERSION >= 9) { + try { + getModule = new ModuleAPI(Class.class.getMethod("getModule")); + Class moduleClass = getModule.method.getReturnType(); + Class modulesClass = Class.forName("jdk.internal.module.Modules"); + getResourceAsStream = new ModuleAPI(moduleClass.getMethod("getResourceAsStream", String.class)); + canRead = new ModuleAPI(moduleClass.getMethod("canRead", moduleClass)); + isExported = new ModuleAPI(moduleClass.getMethod("isExported", String.class)); + isExportedTo = new ModuleAPI(moduleClass.getMethod("isExported", String.class, moduleClass)); + addExports = new ModuleAPI(modulesClass.getDeclaredMethod("addExports", moduleClass, String.class, moduleClass)); + } catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) { + throw new InternalError(e); + } + } else { + ModuleAPI unavailable = new ModuleAPI(null); + getModule = unavailable; + getResourceAsStream = unavailable; + canRead = unavailable; + isExported = unavailable; + isExportedTo = unavailable; + addExports = unavailable; + } + + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeConversion.java 2016-12-07 13:48:07.152827175 -0800 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, 2015, 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.core.common.util; + +/** + * Provides low-level value checks and conversion for signed and unsigned values of size 1, 2, and 4 + * bytes. + */ +public class TypeConversion { + + public static boolean isS1(long value) { + return value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE; + } + + public static boolean isU1(long value) { + return value >= 0 && value <= 0xFF; + } + + public static boolean isS2(long value) { + return value >= Short.MIN_VALUE && value <= Short.MAX_VALUE; + } + + public static boolean isU2(long value) { + return value >= 0 && value <= 0xFFFF; + } + + public static boolean isS4(long value) { + return value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE; + } + + public static boolean isU4(long value) { + return value >= 0 && value <= 0xFFFFFFFFL; + } + + public static byte asS1(long value) { + assert isS1(value); + return (byte) value; + } + + public static byte asU1(long value) { + assert isU1(value); + return (byte) value; + } + + public static short asS2(long value) { + assert isS2(value); + return (short) value; + } + + public static short asU2(long value) { + assert isU2(value); + return (short) value; + } + + public static int asS4(long value) { + assert isS4(value); + return (int) value; + } + + public static int asU4(long value) { + assert isU4(value); + return (int) value; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeReader.java 2016-12-07 13:48:07.416838776 -0800 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, 2015, 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.core.common.util; + +/** + * Provides low-level read access for signed and unsigned values of size 1, 2, 4, and 8 bytes. + */ +public interface TypeReader { + + /** Returns the next byte index to be read. */ + long getByteIndex(); + + /** Sets the next byte index to be read. */ + void setByteIndex(long byteIndex); + + /** Reads a signed 1 byte value. */ + int getS1(); + + /** Reads an unsigned 1 byte value. */ + int getU1(); + + /** Reads a signed 2 byte value. */ + int getS2(); + + /** Reads an unsigned 2 byte value. */ + int getU2(); + + /** Reads a signed 4 byte value. */ + int getS4(); + + /** Reads an unsigned 4 byte value. */ + long getU4(); + + /** Reads a signed 4 byte value. */ + long getS8(); + + /** + * Reads a signed value that has been written using {@link TypeWriter#putSV variable byte size + * encoding}. + */ + default long getSV() { + long result = 0; + int shift = 0; + long b; + do { + b = getU1(); + result |= (b & 0x7f) << shift; + shift += 7; + } while ((b & 0x80) != 0); + + if ((b & 0x40) != 0 && shift < 64) { + result |= -1L << shift; + } + return result; + } + + /** + * Reads a signed variable byte size encoded value that is known to fit into the range of int. + */ + default int getSVInt() { + return TypeConversion.asS4(getSV()); + } + + /** + * Reads an unsigned value that has been written using {@link TypeWriter#putSV variable byte + * size encoding}. + */ + default long getUV() { + long result = 0; + int shift = 0; + long b; + do { + b = getU1(); + result |= (b & 0x7f) << shift; + shift += 7; + } while ((b & 0x80) != 0); + + return result; + } + + /** + * Reads an unsigned variable byte size encoded value that is known to fit into the range of + * int. + */ + default int getUVInt() { + return TypeConversion.asS4(getUV()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeWriter.java 2016-12-07 13:48:07.681850420 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, 2015, 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.core.common.util; + +/** + * Provides low-level sequential write access for signed and unsigned values of size 1, 2, 4, and 8 + * bytes. + */ +public interface TypeWriter { + + /** + * Returns the number of bytes that have been written, i.e., the byte index of the next byte to + * be written. + */ + long getBytesWritten(); + + /** Writes a signed 1 byte value. */ + void putS1(long value); + + /** Writes an unsigned 1 byte value. */ + void putU1(long value); + + /** Writes a signed 2 byte value. */ + void putS2(long value); + + /** Writes an unsigned 2 byte value. */ + void putU2(long value); + + /** Writes a signed 4 byte value. */ + void putS4(long value); + + /** Writes an unsigned 4 byte value. */ + void putU4(long value); + + /** Writes a signed 8 byte value. */ + void putS8(long value); + + /** + * Writes a signed value in a variable byte size encoding. + */ + default void putSV(long value) { + long cur = value; + while (true) { + if (cur >= -64 && cur < 64) { + putU1(cur & 0x7f); + return; + } + putU1(0x80 | (cur & 0x7f)); + cur = cur >> 7; + } + } + + /** + * Writes an unsigned value in a variable byte size encoding. + */ + default void putUV(long value) { + long cur = value; + while (true) { + assert cur >= 0; + if (cur < 128) { + putU1(cur & 0x7f); + return; + } + putU1(0x80 | (cur & 0x7f)); + cur = cur >> 7; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeAccess.java 2016-12-07 13:48:07.948862153 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2012, 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.core.common.util; + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + +/** + * Package private access to the {@link Unsafe} capability. + */ +class UnsafeAccess { + + static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + // Fast path when we are trusted. + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + // Slow path when we are not trusted. + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeReader.java 2016-12-07 13:48:08.214873841 -0800 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2015, 2015, 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.core.common.util; + +import static org.graalvm.compiler.core.common.util.UnsafeAccess.UNSAFE; +import sun.misc.Unsafe; + +/** + * Provides low-level read access from a byte[] array for signed and unsigned values of size 1, 2, + * 4, and 8 bytes. + * + * The class can either be instantiated for sequential access to the byte[] array; or static methods + * can be used to read values without the overhead of creating an instance. + * + * The flag {@code supportsUnalignedMemoryAccess} must be set according to the capabilities of the + * hardware architecture: the value {@code true} allows more efficient memory access on + * architectures that support unaligned memory accesses; the value {@code false} is the safe + * fallback that works on every hardware. + */ +public abstract class UnsafeArrayTypeReader implements TypeReader { + + public static int getS1(byte[] data, long byteIndex) { + return UNSAFE.getByte(data, readOffset(data, byteIndex, Byte.BYTES)); + } + + public static int getU1(byte[] data, long byteIndex) { + return UNSAFE.getByte(data, readOffset(data, byteIndex, Byte.BYTES)) & 0xFF; + } + + public static int getS2(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { + if (supportsUnalignedMemoryAccess) { + return UnalignedUnsafeArrayTypeReader.getS2(data, byteIndex); + } else { + return AlignedUnsafeArrayTypeReader.getS2(data, byteIndex); + } + } + + public static int getU2(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { + return getS2(data, byteIndex, supportsUnalignedMemoryAccess) & 0xFFFF; + } + + public static int getS4(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { + if (supportsUnalignedMemoryAccess) { + return UnalignedUnsafeArrayTypeReader.getS4(data, byteIndex); + } else { + return AlignedUnsafeArrayTypeReader.getS4(data, byteIndex); + } + } + + public static long getU4(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { + return getS4(data, byteIndex, supportsUnalignedMemoryAccess) & 0xFFFFFFFFL; + } + + public static long getS8(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { + if (supportsUnalignedMemoryAccess) { + return UnalignedUnsafeArrayTypeReader.getS8(data, byteIndex); + } else { + return AlignedUnsafeArrayTypeReader.getS8(data, byteIndex); + } + } + + protected static long readOffset(byte[] data, long byteIndex, int numBytes) { + assert byteIndex >= 0; + assert numBytes > 0; + assert byteIndex + numBytes <= data.length; + assert Unsafe.ARRAY_BYTE_INDEX_SCALE == 1; + + return byteIndex + Unsafe.ARRAY_BYTE_BASE_OFFSET; + } + + public static UnsafeArrayTypeReader create(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { + if (supportsUnalignedMemoryAccess) { + return new UnalignedUnsafeArrayTypeReader(data, byteIndex); + } else { + return new AlignedUnsafeArrayTypeReader(data, byteIndex); + } + } + + protected final byte[] data; + protected long byteIndex; + + protected UnsafeArrayTypeReader(byte[] data, long byteIndex) { + this.data = data; + this.byteIndex = byteIndex; + } + + @Override + public long getByteIndex() { + return byteIndex; + } + + @Override + public void setByteIndex(long byteIndex) { + this.byteIndex = byteIndex; + } + + @Override + public final int getS1() { + int result = getS1(data, byteIndex); + byteIndex += Byte.BYTES; + return result; + } + + @Override + public final int getU1() { + int result = getU1(data, byteIndex); + byteIndex += Byte.BYTES; + return result; + } + + @Override + public final int getU2() { + return getS2() & 0xFFFF; + } + + @Override + public final long getU4() { + return getS4() & 0xFFFFFFFFL; + } +} + +final class UnalignedUnsafeArrayTypeReader extends UnsafeArrayTypeReader { + protected static int getS2(byte[] data, long byteIndex) { + return UNSAFE.getShort(data, readOffset(data, byteIndex, Short.BYTES)); + } + + protected static int getS4(byte[] data, long byteIndex) { + return UNSAFE.getInt(data, readOffset(data, byteIndex, Integer.BYTES)); + } + + protected static long getS8(byte[] data, long byteIndex) { + return UNSAFE.getLong(data, readOffset(data, byteIndex, Long.BYTES)); + } + + protected UnalignedUnsafeArrayTypeReader(byte[] data, long byteIndex) { + super(data, byteIndex); + } + + @Override + public int getS2() { + int result = getS2(data, byteIndex); + byteIndex += Short.BYTES; + return result; + } + + @Override + public int getS4() { + int result = getS4(data, byteIndex); + byteIndex += Integer.BYTES; + return result; + } + + @Override + public long getS8() { + long result = getS8(data, byteIndex); + byteIndex += Long.BYTES; + return result; + } +} + +class AlignedUnsafeArrayTypeReader extends UnsafeArrayTypeReader { + protected static int getS2(byte[] data, long byteIndex) { + long offset = readOffset(data, byteIndex, Short.BYTES); + return ((UNSAFE.getByte(data, offset + 0) & 0xFF) << 0) | // + (UNSAFE.getByte(data, offset + 1) << 8); + } + + protected static int getS4(byte[] data, long byteIndex) { + long offset = readOffset(data, byteIndex, Integer.BYTES); + return ((UNSAFE.getByte(data, offset + 0) & 0xFF) << 0) | // + ((UNSAFE.getByte(data, offset + 1) & 0xFF) << 8) | // + ((UNSAFE.getByte(data, offset + 2) & 0xFF) << 16) | // + (UNSAFE.getByte(data, offset + 3) << 24); + } + + protected static long getS8(byte[] data, long byteIndex) { + long offset = readOffset(data, byteIndex, Long.BYTES); + return ((long) ((UNSAFE.getByte(data, offset + 0) & 0xFF)) << 0) | // + ((long) ((UNSAFE.getByte(data, offset + 1) & 0xFF)) << 8) | // + ((long) ((UNSAFE.getByte(data, offset + 2) & 0xFF)) << 16) | // + ((long) ((UNSAFE.getByte(data, offset + 3) & 0xFF)) << 24) | // + ((long) ((UNSAFE.getByte(data, offset + 4) & 0xFF)) << 32) | // + ((long) ((UNSAFE.getByte(data, offset + 5) & 0xFF)) << 40) | // + ((long) ((UNSAFE.getByte(data, offset + 6) & 0xFF)) << 48) | // + ((long) (UNSAFE.getByte(data, offset + 7)) << 56); + } + + protected AlignedUnsafeArrayTypeReader(byte[] data, long byteIndex) { + super(data, byteIndex); + } + + @Override + public int getS2() { + int result = getS2(data, byteIndex); + byteIndex += Short.BYTES; + return result; + } + + @Override + public int getS4() { + int result = getS4(data, byteIndex); + byteIndex += Integer.BYTES; + return result; + } + + @Override + public long getS8() { + long result = getS8(data, byteIndex); + byteIndex += Long.BYTES; + return result; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeWriter.java 2016-12-07 13:48:08.481885573 -0800 @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2015, 2015, 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.core.common.util; + +import static org.graalvm.compiler.core.common.util.TypeConversion.asS1; +import static org.graalvm.compiler.core.common.util.TypeConversion.asS2; +import static org.graalvm.compiler.core.common.util.TypeConversion.asS4; +import static org.graalvm.compiler.core.common.util.TypeConversion.asU1; +import static org.graalvm.compiler.core.common.util.TypeConversion.asU2; +import static org.graalvm.compiler.core.common.util.TypeConversion.asU4; +import sun.misc.Unsafe; + +/** + * Provides low-level sequential write access to a byte[] array for signed and unsigned values of + * size 1, 2, 4, and 8 bytes. To avoid copying an array when the buffer size is no longer + * sufficient, the buffer is split into chunks of a fixed size. + * + * The flag {@code supportsUnalignedMemoryAccess} must be set according to the capabilities of the + * hardware architecture: the value {@code true} allows more efficient memory access on + * architectures that support unaligned memory accesses; the value {@code false} is the safe + * fallback that works on every hardware. + */ +public abstract class UnsafeArrayTypeWriter implements TypeWriter { + + private static final int MIN_CHUNK_LENGTH = 200; + private static final int MAX_CHUNK_LENGTH = 16000; + + static class Chunk { + protected final byte[] data; + protected int size; + protected Chunk next; + + protected Chunk(int arrayLength) { + data = new byte[arrayLength]; + } + } + + protected final Chunk firstChunk; + protected Chunk writeChunk; + protected int totalSize; + + public static UnsafeArrayTypeWriter create(boolean supportsUnalignedMemoryAccess) { + if (supportsUnalignedMemoryAccess) { + return new UnalignedUnsafeArrayTypeWriter(); + } else { + return new AlignedUnsafeArrayTypeWriter(); + } + } + + protected UnsafeArrayTypeWriter() { + firstChunk = new Chunk(MIN_CHUNK_LENGTH); + writeChunk = firstChunk; + } + + @Override + public final long getBytesWritten() { + return totalSize; + } + + /** + * Copies the buffer into the provided byte[] array of length {@link #getBytesWritten()}. + */ + public final byte[] toArray(byte[] result) { + assert result.length == totalSize; + int resultIdx = 0; + for (Chunk cur = firstChunk; cur != null; cur = cur.next) { + System.arraycopy(cur.data, 0, result, resultIdx, cur.size); + resultIdx += cur.size; + } + assert resultIdx == totalSize; + return result; + } + + @Override + public final void putS1(long value) { + long offset = writeOffset(Byte.BYTES); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset, asS1(value)); + } + + @Override + public final void putU1(long value) { + long offset = writeOffset(Byte.BYTES); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset, asU1(value)); + } + + @Override + public final void putU2(long value) { + putS2(asU2(value)); + } + + @Override + public final void putU4(long value) { + putS4(asU4(value)); + } + + protected long writeOffset(int writeBytes) { + if (writeChunk.size + writeBytes >= writeChunk.data.length) { + Chunk newChunk = new Chunk(Math.min(writeChunk.data.length * 2, MAX_CHUNK_LENGTH)); + writeChunk.next = newChunk; + writeChunk = newChunk; + } + + assert Unsafe.ARRAY_BYTE_INDEX_SCALE == 1; + long result = writeChunk.size + Unsafe.ARRAY_BYTE_BASE_OFFSET; + + totalSize += writeBytes; + writeChunk.size += writeBytes; + assert writeChunk.size <= writeChunk.data.length; + + return result; + } +} + +final class UnalignedUnsafeArrayTypeWriter extends UnsafeArrayTypeWriter { + @Override + public void putS2(long value) { + long offset = writeOffset(Short.BYTES); + UnsafeAccess.UNSAFE.putShort(writeChunk.data, offset, asS2(value)); + } + + @Override + public void putS4(long value) { + long offset = writeOffset(Integer.BYTES); + UnsafeAccess.UNSAFE.putInt(writeChunk.data, offset, asS4(value)); + } + + @Override + public void putS8(long value) { + long offset = writeOffset(Long.BYTES); + UnsafeAccess.UNSAFE.putLong(writeChunk.data, offset, value); + } +} + +final class AlignedUnsafeArrayTypeWriter extends UnsafeArrayTypeWriter { + @Override + public void putS2(long value) { + long offset = writeOffset(Short.BYTES); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0)); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8)); + } + + @Override + public void putS4(long value) { + long offset = writeOffset(Integer.BYTES); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0)); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8)); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 2, (byte) (value >> 16)); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 3, (byte) (value >> 24)); + } + + @Override + public void putS8(long value) { + long offset = writeOffset(Long.BYTES); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0)); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8)); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 2, (byte) (value >> 16)); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 3, (byte) (value >> 24)); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 4, (byte) (value >> 32)); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 5, (byte) (value >> 40)); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 6, (byte) (value >> 48)); + UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 7, (byte) (value >> 56)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/Util.java 2016-12-07 13:48:08.747897262 -0800 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2009, 2011, 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.core.common.util; + +import static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining; + +import java.util.Collection; +import java.util.List; + +import org.graalvm.compiler.debug.TTY; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * The {@code Util} class contains a motley collection of utility methods used throughout the + * compiler. + */ +public class Util { + + private static int getJavaSpecificationVersion() { + String value = System.getProperty("java.specification.version"); + if (value.startsWith("1.")) { + value = value.substring(2); + } + return Integer.parseInt(value); + } + + /** + * The integer value corresponding to the value of the {@code java.specification.version} system + * property after any leading {@code "1."} has been stripped. + */ + public static final int JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion(); + + /** + * Determines if the Java runtime is version 8 or earlier. + */ + public static final boolean Java8OrEarlier = JAVA_SPECIFICATION_VERSION <= 8; + + /** + * Statically cast an object to an arbitrary Object type. Dynamically checked. + */ + @SuppressWarnings("unchecked") + public static T uncheckedCast(@SuppressWarnings("unused") Class type, Object object) { + return (T) object; + } + + /** + * Statically cast an object to an arbitrary Object type. Dynamically checked. + */ + @SuppressWarnings("unchecked") + public static T uncheckedCast(Object object) { + return (T) object; + } + + public interface Stringify { + String apply(Object o); + } + + public static String join(Collection c, String sep) { + return join(c, sep, "", "", null); + } + + public static String join(Collection c, String sep, String prefix, String suffix, Stringify stringify) { + StringBuilder buf = new StringBuilder(prefix); + boolean first = true; + for (Object e : c) { + if (!first) { + buf.append(sep); + } else { + first = false; + } + buf.append(stringify != null ? stringify.apply(e) : String.valueOf(e)); + } + buf.append(suffix); + return buf.toString(); + } + + /** + * Sets the element at a given position of a list and ensures that this position exists. If the + * list is current shorter than the position, intermediate positions are filled with a given + * value. + * + * @param list the list to put the element into + * @param pos the position at which to insert the element + * @param x the element that should be inserted + * @param filler the filler element that is used for the intermediate positions in case the list + * is shorter than pos + */ + public static void atPutGrow(List list, int pos, T x, T filler) { + if (list.size() < pos + 1) { + while (list.size() < pos + 1) { + list.add(filler); + } + assert list.size() == pos + 1; + } + + assert list.size() >= pos + 1; + list.set(pos, x); + } + + /** + * Prepends the String {@code indentation} to every line in String {@code lines}, including a + * possibly non-empty line following the final newline. + */ + public static String indent(String lines, String indentation) { + if (lines.length() == 0) { + return lines; + } + final String newLine = "\n"; + if (lines.endsWith(newLine)) { + return indentation + (lines.substring(0, lines.length() - 1)).replace(newLine, newLine + indentation) + newLine; + } + return indentation + lines.replace(newLine, newLine + indentation); + } + + /** + * Returns the zero value for a given numeric kind. + */ + public static JavaConstant zero(JavaKind kind) { + switch (kind) { + case Boolean: + return JavaConstant.FALSE; + case Byte: + return JavaConstant.forByte((byte) 0); + case Char: + return JavaConstant.forChar((char) 0); + case Double: + return JavaConstant.DOUBLE_0; + case Float: + return JavaConstant.FLOAT_0; + case Int: + return JavaConstant.INT_0; + case Long: + return JavaConstant.LONG_0; + case Short: + return JavaConstant.forShort((short) 0); + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * Returns the one value for a given numeric kind. + */ + public static JavaConstant one(JavaKind kind) { + switch (kind) { + case Boolean: + return JavaConstant.TRUE; + case Byte: + return JavaConstant.forByte((byte) 1); + case Char: + return JavaConstant.forChar((char) 1); + case Double: + return JavaConstant.DOUBLE_1; + case Float: + return JavaConstant.FLOAT_1; + case Int: + return JavaConstant.INT_1; + case Long: + return JavaConstant.LONG_1; + case Short: + return JavaConstant.forShort((short) 1); + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * Print a HotSpot-style inlining message to the console. + */ + public static void printInlining(final ResolvedJavaMethod method, final int bci, final int inliningDepth, final boolean success, final String msg, final Object... args) { + if (HotSpotPrintInlining.getValue()) { + StringBuilder sb = new StringBuilder(); + // 1234567 + sb.append(" "); // print timestamp + // 1234 + sb.append(" "); // print compilation number + // % s ! b n + sb.append(String.format("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' ')); + sb.append(" "); // more indent + sb.append(" "); // initial inlining indent + for (int i = 0; i < inliningDepth; i++) { + sb.append(" "); + } + sb.append(String.format("@ %d %s %s%s", bci, methodName(method), success ? "" : "not inlining ", String.format(msg, args))); + TTY.println(sb.toString()); + } + } + + private static String methodName(ResolvedJavaMethod method) { + return method.format("%H.%n(%p):%r") + " (" + method.getCodeSize() + " bytes)"; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/META-INF/services/javax.annotation.processing.Processor 2016-12-07 13:48:09.014908994 -0800 @@ -0,0 +1 @@ +org.graalvm.compiler.core.match.processor.MatchProcessor --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java 2016-12-07 13:48:09.279920639 -0800 @@ -0,0 +1,1132 @@ +/* + * Copyright (c) 2014, 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.core.match.processor; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Filer; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.Name; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.MirroredTypeException; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.AbstractAnnotationValueVisitor7; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Types; +import javax.tools.Diagnostic.Kind; +import javax.tools.FileObject; +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; + +import org.graalvm.compiler.core.gen.NodeMatchRules; +import org.graalvm.compiler.core.match.ComplexMatchResult; +import org.graalvm.compiler.core.match.MatchRule; +import org.graalvm.compiler.core.match.MatchRules; +import org.graalvm.compiler.core.match.MatchStatement; +import org.graalvm.compiler.core.match.MatchStatementSet; +import org.graalvm.compiler.core.match.MatchableNode; +import org.graalvm.compiler.core.match.MatchableNodes; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Position; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.serviceprovider.ServiceProvider; + +/** + * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is + * generated for each top level class containing at least one such field. These service objects can + * be retrieved as follows: + * + *
+ *     Iterable sl = GraalServices.load(MatchStatementSet.class);
+ *     for (MatchStatementSet rules : sl) {
+ *         ...
+ *     }
+ * 
+ */ +@SupportedAnnotationTypes({"org.graalvm.compiler.core.match.MatchRule", "org.graalvm.compiler.core.match.MatchRules", "org.graalvm.compiler.core.match.MatchableNode", + "org.graalvm.compiler.core.match.MatchableNodes"}) +public class MatchProcessor extends AbstractProcessor { + + public MatchProcessor() { + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + private final Set processedMatchRule = new HashSet<>(); + private final Set processedMatchableNode = new HashSet<>(); + + private static class RuleParseError extends RuntimeException { + private static final long serialVersionUID = 6456128283609257490L; + + RuleParseError(String format, Object... args) { + super(String.format(format, args)); + } + } + + private static final Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*"); + + private class RuleParser { + private ArrayList capturedTypes = new ArrayList<>(); + + private ArrayList capturedNames = new ArrayList<>(); + + private final String[] tokens; + + private int current; + + private MatchDescriptor matchDescriptor; + + private final Set originatingElements = new HashSet<>(); + + private Set requiredPackages = new HashSet<>(); + + RuleParser(String rule) { + Matcher m = tokenizer.matcher(rule); + List list = new ArrayList<>(); + int end = 0; + while (m.lookingAt()) { + list.add(m.group(1)); + end = m.end(); + m.region(m.end(), m.regionEnd()); + } + if (end != m.regionEnd()) { + throw new RuleParseError("Unexpected tokens :" + rule.substring(m.end(), m.regionEnd())); + } + tokens = list.toArray(new String[0]); + + matchDescriptor = parseExpression(); + if (!done()) { + throw new RuleParseError("didn't consume all tokens"); + } + capturedNames.add(0, "root"); + capturedTypes.add(0, matchDescriptor.nodeType); + } + + String next() { + return tokens[current++]; + } + + String peek(String name) { + if (current >= tokens.length) { + if (name == null) { + throw new RuleParseError("Out of tokens"); + } + throw new RuleParseError("Out of tokens looking for %s", name); + } + return tokens[current]; + } + + boolean done() { + return current == tokens.length; + } + + private MatchDescriptor parseExpression() { + if (peek("(").equals("(")) { + next(); + MatchDescriptor descriptor = parseType(true); + for (int n = 0; n < descriptor.nodeType.inputs.length; n++) { + if (peek("(").equals("(")) { + descriptor.inputs[n] = parseExpression(); + } else { + descriptor.inputs[n] = parseType(false); + } + } + for (int n = 0; n < descriptor.nodeType.inputs.length; n++) { + if (descriptor.inputs[n] == null) { + throw new RuleParseError("not enough inputs for " + descriptor.name); + } + } + if (peek(")").equals(")")) { + next(); + return descriptor; + } + throw new RuleParseError("Too many arguments to " + descriptor.nodeType.nodeClass); + } + throw new RuleParseError("Extra tokens following match pattern: " + peek(null)); + } + + private MatchDescriptor parseType(boolean forExpression) { + TypeDescriptor type = null; + String name = null; + if (Character.isUpperCase(peek("node type or name").charAt(0))) { + String token = next(); + type = knownTypes.get(token); + if (type == null) { + throw new RuleParseError("Unknown node type: " + token); + } + if (peek("=").equals("=")) { + next(); + name = next(); + } + originatingElements.addAll(type.originatingElements); + requiredPackages.add(type.nodePackage); + } else if (Character.isLowerCase(peek("name").charAt(0))) { + name = next(); + type = valueType; + } else { + throw new RuleParseError("Unexpected token \"%s\" when looking for name or node type", peek(null)); + } + if (name != null) { + if (!capturedNames.contains(name)) { + capturedNames.add(name); + capturedTypes.add(type); + } else { + int index = capturedNames.indexOf(name); + if (capturedTypes.get(index) != type) { + throw new RuleParseError("Captured node \"%s\" has differing types", name); + } + } + } + return new MatchDescriptor(type, name, forExpression); + } + + List generateVariants() { + return matchDescriptor.generateVariants(); + } + + /** + * Recursively accumulate any required Position declarations. + */ + void generatePositionDeclarations(Set declarations) { + matchDescriptor.generatePositionDeclarations(declarations); + } + + /** + * + * @return the list of node types which are captured by name + */ + public ArrayList capturedTypes() { + return capturedTypes; + } + + public ArrayList capturedNames() { + return capturedNames; + } + } + + /** + * Set to true to enable logging to a local file during annotation processing. There's no normal + * channel for any debug messages and debugging annotation processors requires some special + * setup. + */ + private static final boolean DEBUG = false; + + private PrintWriter log; + + /** + * Logging facility for debugging the annotation processor. + */ + + private PrintWriter getLog() { + if (log == null) { + try { + // Create the log file within the generated source directory so it's easy to find. + // /tmp isn't platform independent and java.io.tmpdir can map anywhere, particularly + // on the mac. + FileObject file = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", getClass().getSimpleName() + "log"); + log = new PrintWriter(new FileWriter(file.toUri().getPath(), true)); + } catch (IOException e) { + // Do nothing + } + } + return log; + } + + private void logMessage(String format, Object... args) { + if (!DEBUG) { + return; + } + PrintWriter bw = getLog(); + if (bw != null) { + bw.printf(format, args); + bw.flush(); + } + } + + private void logException(Throwable t) { + if (!DEBUG) { + return; + } + PrintWriter bw = getLog(); + if (bw != null) { + t.printStackTrace(bw); + bw.flush(); + } + } + + /** + * Bugs in an annotation processor can cause silent failure so try to report any exception + * throws as errors. + */ + private void reportExceptionThrow(Element element, Throwable t) { + if (element != null) { + logMessage("throw for %s:\n", element); + } + logException(t); + errorMessage(element, "Exception throw during processing: %s %s", t, Arrays.toString(Arrays.copyOf(t.getStackTrace(), 4))); + } + + static class TypeDescriptor { + final TypeMirror mirror; + + /** + * The name uses in match expressions to refer to this type. + */ + final String shortName; + + /** + * The simple name of the {@link ValueNode} class represented by this type. + */ + final String nodeClass; + + /** + * The package of {@link ValueNode} class represented by this type. + */ + final String nodePackage; + + /** + * The matchable inputs of the node. + */ + final String[] inputs; + + /** + * Should swapped variants of this match be generated. The user of the match is expected to + * compensate for any ordering differences in compare which are commutative but require + * reinterpreting the condition in that case. + */ + final boolean commutative; + + /** + * Can multiple users of this node subsume it. Constants can be swallowed into a match even + * if there are multiple users. + */ + final boolean shareable; + + final Set originatingElements = new HashSet<>(); + + TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable) { + this.mirror = mirror; + this.shortName = shortName; + this.nodeClass = nodeClass; + this.nodePackage = nodePackage; + this.inputs = inputs; + this.commutative = commutative; + this.shareable = shareable; + assert !commutative || inputs.length == 2; + } + } + + /** + * The types which are know for purpose of parsing MatchRule expressions. + */ + Map knownTypes = new HashMap<>(); + + private TypeDescriptor valueType; + + private TypeMirror matchRulesTypeMirror; + + private TypeMirror matchRuleTypeMirror; + + private TypeMirror matchableNodeTypeMirror; + + private TypeMirror matchableNodesTypeMirror; + + private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable, Element element) { + TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable); + descriptor.originatingElements.add(element); + knownTypes.put(shortName, descriptor); + } + + private String findPackage(Element type) { + PackageElement p = processingEnv.getElementUtils().getPackageOf(type); + if (p != null) { + return p.getQualifiedName().toString(); + } + throw new GraalError("can't find package for %s", type); + } + + class MatchDescriptor { + TypeDescriptor nodeType; + String name; + MatchDescriptor[] inputs; + + MatchDescriptor(TypeDescriptor nodeType, String name, boolean forExpression) { + this.nodeType = nodeType; + this.name = name; + if (forExpression) { + this.inputs = new MatchDescriptor[nodeType.inputs.length]; + } else { + this.inputs = new MatchDescriptor[0]; + } + } + + public void generatePositionDeclarations(Set declarations) { + if (inputs.length == 0) { + return; + } + declarations.add(generatePositionDeclaration()); + for (MatchDescriptor desc : inputs) { + desc.generatePositionDeclarations(declarations); + } + } + + List recurseVariants(int index) { + if (inputs.length == 0) { + return new ArrayList<>(); + } + List currentVariants = inputs[index].generateVariants(); + if (index == inputs.length - 1) { + return currentVariants; + } + List subVariants = recurseVariants(index + 1); + List result = new ArrayList<>(); + for (String current : currentVariants) { + for (String sub : subVariants) { + result.add(current + ", " + sub); + if (nodeType.commutative) { + result.add(sub + ", " + current); + } + } + } + return result; + } + + /** + * Recursively generate all the variants of this rule pattern. Currently that just means to + * swap the inputs for commutative rules, producing all possible permutations. + * + * @return a list of Strings which will construct pattern matchers for this rule. + */ + List generateVariants() { + String prefix = formatPrefix(); + String suffix = formatSuffix(); + ArrayList variants = new ArrayList<>(); + if (inputs.length > 0) { + for (String var : recurseVariants(0)) { + variants.add(prefix + ", " + var + suffix); + } + } else { + assert inputs.length == 0; + variants.add(prefix + suffix); + } + + return variants; + } + + private String formatPrefix() { + if (nodeType == valueType) { + return String.format("new MatchPattern(%s, false", name != null ? ("\"" + name + "\"") : "null"); + } else { + return String.format("new MatchPattern(%s.class, %s", nodeType.nodeClass, name != null ? ("\"" + name + "\"") : "null"); + } + } + + private String formatSuffix() { + if (nodeType != null) { + if (inputs.length != nodeType.inputs.length) { + return ", true)"; + } else { + if (nodeType.inputs.length > 0) { + return ", " + nodeType.nodeClass + "_positions, " + !nodeType.shareable + ")"; + } + if (nodeType.shareable) { + return ", false)"; + } + } + } + return ")"; + } + + String generatePositionDeclaration() { + return String.format("Position[] %s_positions = MatchRuleRegistry.findPositions(%s.TYPE, new String[]{\"%s\"});", nodeType.nodeClass, nodeType.nodeClass, + String.join("\", \"", nodeType.inputs)); + } + } + + /** + * Strip the package off a class name leaving the full class name including any outer classes. + */ + private String fullClassName(Element element) { + assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE : element; + String pkg = findPackage(element); + return ((TypeElement) element).getQualifiedName().toString().substring(pkg.length() + 1); + } + + private void createFiles(MatchRuleDescriptor info) { + String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString(); + Name topDeclaringClass = info.topDeclaringType.getSimpleName(); + + String matchStatementClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName(); + Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]); + + Types typeUtils = typeUtils(); + Filer filer = processingEnv.getFiler(); + try (PrintWriter out = createSourceFile(pkg, matchStatementClassName, filer, originatingElements)) { + + out.println("// CheckStyle: stop header check"); + out.println("// CheckStyle: stop line length check"); + out.println("// GENERATED CONTENT - DO NOT EDIT"); + out.println("// Source: " + topDeclaringClass + ".java"); + out.println("package " + pkg + ";"); + out.println(""); + out.println("import java.util.*;"); + out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;"); + out.println("import " + NodeMatchRules.class.getName() + ";"); + out.println("import " + Position.class.getName() + ";"); + out.println("import " + ServiceProvider.class.getName() + ";"); + for (String p : info.requiredPackages) { + out.println("import " + p + ".*;"); + } + out.println(""); + + out.println("@" + ServiceProvider.class.getSimpleName() + "(" + MatchStatementSet.class.getSimpleName() + ".class)"); + out.println("public class " + matchStatementClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {"); + + out.println(); + + // Generate declarations for the wrapper class to invoke the code generation methods. + for (MethodInvokerItem invoker : info.invokers.values()) { + StringBuilder args = new StringBuilder(); + StringBuilder types = new StringBuilder(); + int count = invoker.fields.size(); + int index = 0; + for (VariableElement arg : invoker.fields) { + args.append('"'); + args.append(arg.getSimpleName()); + args.append('"'); + types.append(String.format("(%s) args[%s]", fullClassName(typeUtils.asElement(arg.asType())), index++)); + if (count-- > 1) { + args.append(", "); + types.append(", "); + } + } + out.printf(" private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args); + out.printf(" private static final class %s implements MatchGenerator {\n", invoker.wrapperClass()); + out.printf(" static MatchGenerator instance = new %s();\n", invoker.wrapperClass()); + out.printf(" @Override\n"); + out.printf(" public ComplexMatchResult match(NodeMatchRules nodeMatchRules, Object...args) {\n"); + out.printf(" return ((%s) nodeMatchRules).%s(%s);\n", invoker.nodeLIRBuilderClass, invoker.methodName, types); + out.printf(" }\n"); + out.printf(" @Override\n"); + out.printf(" public String getName() {\n"); + out.printf(" return \"%s\";\n", invoker.methodName); + out.printf(" }\n"); + out.printf(" }\n"); + out.println(); + + } + + String desc = MatchStatement.class.getSimpleName(); + + out.println(" @Override"); + out.println(" public Class forClass() {"); + out.println(" return " + topDeclaringClass + ".class;"); + out.println(" }"); + out.println(); + out.println(" @Override"); + out.println(" public List<" + desc + "> statements() {"); + out.println(" // Checkstyle: stop "); + + for (String positionDeclaration : info.positionDeclarations) { + out.println(" " + positionDeclaration); + } + out.println(); + + out.println(" List<" + desc + "> statements = Collections.unmodifiableList(Arrays.asList("); + + int i = 0; + for (MatchRuleItem matchRule : info.matchRules) { + String comma = i == info.matchRules.size() - 1 ? "" : ","; + out.printf(" %s%s\n", matchRule.ruleBuilder(), comma); + i++; + } + out.println(" ));"); + out.println(" // Checkstyle: resume"); + out.println(" return statements;"); + out.println(" }"); + + out.println(); + + out.println("}"); + } + } + + protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) { + try { + // Ensure Unix line endings to comply with Graal code style guide checked by Checkstyle + JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements); + return new PrintWriter(sourceFile.openWriter()) { + + @Override + public void println() { + print("\n"); + } + }; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Used to generate the MatchStatement constructor invocation. + */ + static class MatchRuleItem { + private final String matchPattern; + private final MethodInvokerItem invoker; + + MatchRuleItem(String matchPattern, MethodInvokerItem invoker) { + this.matchPattern = matchPattern; + this.invoker = invoker; + } + + /** + * @return a string which will construct the MatchStatement instance to match this pattern. + */ + public String ruleBuilder() { + return String.format("new MatchStatement(\"%s\", %s, %s.instance, %s)", invoker.methodName, matchPattern, invoker.wrapperClass(), invoker.argumentsListName()); + } + } + + /** + * Used to generate the wrapper class to invoke the code generation method. + */ + static class MethodInvokerItem { + final String methodName; + final String nodeLIRBuilderClass; + final ExecutableElement method; + final List fields; + + MethodInvokerItem(String methodName, String nodeLIRBuilderClass, ExecutableElement method, List fields) { + this.methodName = methodName; + this.nodeLIRBuilderClass = nodeLIRBuilderClass; + this.method = method; + this.fields = fields; + } + + String wrapperClass() { + return "MatchGenerator_" + methodName; + } + + String argumentsListName() { + return methodName + "_arguments"; + } + } + + static class MatchRuleDescriptor { + + final TypeElement topDeclaringType; + final List matchRules = new ArrayList<>(); + private final Set originatingElements = new HashSet<>(); + public Set positionDeclarations = new LinkedHashSet<>(); + + /** + * The mapping between elements with MatchRules and the wrapper class used invoke the code + * generation after the match. + */ + Map invokers = new LinkedHashMap<>(); + + /** + * The set of packages which must be imported to refer the classes mention in matchRules. + */ + Set requiredPackages = new HashSet<>(); + + MatchRuleDescriptor(TypeElement topDeclaringType) { + this.topDeclaringType = topDeclaringType; + } + } + + private static TypeElement topDeclaringType(Element element) { + Element enclosing = element.getEnclosingElement(); + if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) { + assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE; + return (TypeElement) element; + } + return topDeclaringType(enclosing); + } + + private AnnotationMirror findAnnotationMirror(Element element, TypeMirror typeMirror) { + for (AnnotationMirror mirror : element.getAnnotationMirrors()) { + if (typeUtils().isSameType(mirror.getAnnotationType(), typeMirror)) { + return mirror; + } + } + return null; + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + return true; + } + + logMessage("Starting round %s\n", roundEnv); + matchRulesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRules.class.getCanonicalName()).asType(); + matchRuleTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRule.class.getCanonicalName()).asType(); + + matchableNodeTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNode.class.getCanonicalName()).asType(); + matchableNodesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNodes.class.getCanonicalName()).asType(); + + Element currentElement = null; + try { + for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNode.class)) { + logMessage("%s\n", element); + processMatchableNode(element); + } + for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodes.class)) { + logMessage("%s\n", element); + processMatchableNode(element); + } + // Define a TypeDescriptor for the generic node but don't enter it into the nodeTypes + // table since it shouldn't be mentioned in match rules. + TypeMirror valueTypeMirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType(); + valueType = new TypeDescriptor(valueTypeMirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), new String[0], false, false); + + Map map = new LinkedHashMap<>(); + + for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) { + currentElement = element; + processMatchRule(map, element, findAnnotationMirror(element, matchRuleTypeMirror)); + } + for (Element element : roundEnv.getElementsAnnotatedWith(MatchRules.class)) { + currentElement = element; + processMatchRule(map, element, findAnnotationMirror(element, matchRulesTypeMirror)); + } + + currentElement = null; + for (MatchRuleDescriptor info : map.values()) { + createFiles(info); + } + + } catch (Throwable t) { + reportExceptionThrow(currentElement, t); + } + + return true; + } + + /** + * Build up the type table to be used during parsing of the MatchRule. + */ + private void processMatchableNode(Element element) { + if (!processedMatchableNode.contains(element)) { + try { + processedMatchableNode.add(element); + + AnnotationMirror mirror = findAnnotationMirror(element, matchableNodesTypeMirror); + if (mirror == null) { + mirror = findAnnotationMirror(element, matchableNodeTypeMirror); + } + if (mirror == null) { + return; + } + TypeElement topDeclaringType = topDeclaringType(element); + List mirrors = null; + if (typeUtils().isSameType(mirror.getAnnotationType(), matchableNodesTypeMirror)) { + // Unpack the mirrors for a repeatable annotation + mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value"); + } + int i = 0; + for (MatchableNode matchableNode : element.getAnnotationsByType(MatchableNode.class)) { + processMatchableNode(element, topDeclaringType, matchableNode, mirrors != null ? mirrors.get(i++) : mirror); + } + } catch (Throwable t) { + reportExceptionThrow(element, t); + } + } + } + + private void processMatchableNode(Element element, TypeElement topDeclaringType, MatchableNode matchable, AnnotationMirror mirror) throws GraalError { + logMessage("processMatchableNode %s %s %s\n", topDeclaringType, element, matchable); + String nodeClass; + String nodePackage; + TypeMirror nodeClassMirror = null; + try { + matchable.nodeClass(); + } catch (MirroredTypeException e) { + nodeClassMirror = e.getTypeMirror(); + } + if (nodeClassMirror == null) { + throw new GraalError("Can't get mirror for node class %s", element); + } + if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) { + nodeClass = topDeclaringType.getQualifiedName().toString(); + } else { + nodeClass = nodeClassMirror.toString(); + } + TypeElement typeElement = processingEnv.getElementUtils().getTypeElement(nodeClass); + if (typeElement == null) { + errorMessage(element, mirror, "Class \"%s\" cannot be resolved to a type", nodeClass); + return; + } + nodePackage = findPackage(typeElement); + assert nodeClass.startsWith(nodePackage); + nodeClass = nodeClass.substring(nodePackage.length() + 1); + assert nodeClass.endsWith("Node"); + String shortName = nodeClass.substring(0, nodeClass.length() - 4); + + Types typeUtils = processingEnv.getTypeUtils(); + TypeElement nodeClassElement = (TypeElement) typeUtils.asElement(nodeClassMirror); + for (String input : matchable.inputs()) { + boolean ok = false; + TypeElement current = nodeClassElement; + while (!ok && current != null) { + for (Element fieldElement : ElementFilter.fieldsIn(current.getEnclosedElements())) { + if (fieldElement.getSimpleName().toString().equals(input)) { + ok = true; + break; + } + } + TypeMirror theSuper = current.getSuperclass(); + current = (TypeElement) typeUtils.asElement(theSuper); + } + if (!ok) { + errorMessage(element, mirror, "Input named \"%s\" doesn't exist in %s", input, nodeClassElement.getSimpleName()); + } + } + + declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), matchable.commutative(), matchable.shareable(), element); + } + + private void processMatchRule(Map map, Element element, AnnotationMirror mirror) { + if (!processedMatchRule.contains(element)) { + try { + processedMatchRule.add(element); + + // The annotation element type should ensure this is true. + assert element instanceof ExecutableElement; + + findMatchableNodes(element); + + TypeElement topDeclaringType = topDeclaringType(element); + MatchRuleDescriptor info = map.get(topDeclaringType); + if (info == null) { + info = new MatchRuleDescriptor(topDeclaringType); + map.put(topDeclaringType, info); + } + List mirrors = null; + if (typeUtils().isSameType(mirror.getAnnotationType(), matchRulesTypeMirror)) { + // Unpack the mirrors for a repeatable annotation + mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value"); + } + int i = 0; + for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) { + processMethodMatchRule((ExecutableElement) element, info, matchRule, mirrors != null ? mirrors.get(i++) : mirror); + } + } catch (Throwable t) { + reportExceptionThrow(element, t); + } + } + } + + /** + * Search the super types of element for MatchableNode definitions. Any superclass or super + * interface can contain definitions of matchable nodes. + * + * @param element + */ + private void findMatchableNodes(Element element) { + processMatchableNode(element); + Element enclosing = element.getEnclosingElement(); + while (enclosing != null) { + if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { + TypeElement current = (TypeElement) enclosing; + while (current != null) { + processMatchableNode(current); + for (TypeMirror intf : current.getInterfaces()) { + Element interfaceElement = typeUtils().asElement(intf); + processMatchableNode(interfaceElement); + // Recurse + findMatchableNodes(interfaceElement); + } + TypeMirror theSuper = current.getSuperclass(); + current = (TypeElement) typeUtils().asElement(theSuper); + } + } + enclosing = enclosing.getEnclosingElement(); + } + } + + private Types typeUtils() { + return processingEnv.getTypeUtils(); + } + + private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule, AnnotationMirror mirror) { + logMessage("processMethodMatchRule %s %s\n", method, mirror); + + Types typeUtils = typeUtils(); + + if (!method.getModifiers().contains(Modifier.PUBLIC)) { + errorMessage(method, "MatchRule method %s must be public", method.getSimpleName()); + return; + } + if (method.getModifiers().contains(Modifier.STATIC)) { + errorMessage(method, "MatchRule method %s must be non-static", method.getSimpleName()); + return; + } + + try { + TypeMirror returnType = method.getReturnType(); + if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(ComplexMatchResult.class.getName()).asType())) { + errorMessage(method, "MatchRule method return type must be %s", ComplexMatchResult.class.getName()); + return; + } + + String rule = matchRule.value(); + RuleParser parser = new RuleParser(rule); + ArrayList expectedTypes = parser.capturedTypes(); + ArrayList expectedNames = parser.capturedNames(); + List actualParameters = method.getParameters(); + if (expectedTypes.size() + 1 < actualParameters.size()) { + errorMessage(method, "Too many arguments for match method %s != %s", expectedTypes.size() + 1, actualParameters.size()); + return; + } + + // Walk through the parameters to the method and see if they exist in the match rule. + // The order doesn't matter but only names mentioned in the rule can be used and they + // must be assignment compatible. + for (VariableElement parameter : actualParameters) { + String name = parameter.getSimpleName().toString(); + int nameIndex = expectedNames.indexOf(name); + if (nameIndex == -1) { + errorMessage(method, "Argument \"%s\" isn't captured in the match rule", name); + return; + } + TypeMirror type = parameter.asType(); + if (!typeUtils.isAssignable(expectedTypes.get(nameIndex).mirror, type)) { + errorMessage(method, "Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type); + return; + } + } + + String methodName = method.getSimpleName().toString(); + MethodInvokerItem invoker = info.invokers.get(methodName); + if (invoker == null) { + invoker = new MethodInvokerItem(methodName, topDeclaringType(method).getSimpleName().toString(), method, actualParameters); + info.invokers.put(methodName, invoker); + } else if (invoker.method != method) { + // This could be supported but it's easier if they are unique since the names + // are used in log output and snippet counters. + errorMessage(method, "Use unique method names for match methods: %s.%s != %s.%s", method.getReceiverType(), method.getSimpleName(), invoker.method.getReceiverType(), + invoker.method.getSimpleName()); + return; + } + + Element enclosing = method.getEnclosingElement(); + String declaringClass = ""; + String separator = ""; + Set originatingElementsList = info.originatingElements; + originatingElementsList.add(method); + while (enclosing != null) { + if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { + if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { + errorMessage(method, "MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); + return; + } + originatingElementsList.add(enclosing); + declaringClass = enclosing.getSimpleName() + separator + declaringClass; + separator = "."; + } else { + assert enclosing.getKind() == ElementKind.PACKAGE; + } + enclosing = enclosing.getEnclosingElement(); + } + + originatingElementsList.addAll(parser.originatingElements); + info.requiredPackages.addAll(parser.requiredPackages); + + // Accumulate any position declarations. + parser.generatePositionDeclarations(info.positionDeclarations); + + List matches = parser.generateVariants(); + for (String match : matches) { + info.matchRules.add(new MatchRuleItem(match, invoker)); + } + } catch (RuleParseError e) { + errorMessage(method, mirror, e.getMessage()); + } + } + + private void errorMessage(Element element, String format, Object... args) { + processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element); + } + + private void errorMessage(Element element, AnnotationMirror mirror, String format, Object... args) { + processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element, mirror); + } + + // TODO borrowed from com.oracle.truffle.dsl.processor.Utils + @SuppressWarnings("unchecked") + private static List getAnnotationValueList(Class expectedListType, AnnotationMirror mirror, String name) { + List values = getAnnotationValue(List.class, mirror, name); + List result = new ArrayList<>(); + + if (values != null) { + for (AnnotationValue value : values) { + T annotationValue = resolveAnnotationValue(expectedListType, value); + if (annotationValue != null) { + result.add(annotationValue); + } + } + } + return result; + } + + private static T getAnnotationValue(Class expectedType, AnnotationMirror mirror, String name) { + return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name)); + } + + @SuppressWarnings({"unchecked"}) + private static T resolveAnnotationValue(Class expectedType, AnnotationValue value) { + if (value == null) { + return null; + } + + Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null); + if (unboxedValue != null) { + if (expectedType == TypeMirror.class && unboxedValue instanceof String) { + return null; + } + if (!expectedType.isAssignableFrom(unboxedValue.getClass())) { + throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName()); + } + } + return (T) unboxedValue; + } + + private static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) { + ExecutableElement valueMethod = null; + for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) { + if (method.getSimpleName().toString().equals(name)) { + valueMethod = method; + break; + } + } + + if (valueMethod == null) { + return null; + } + + AnnotationValue value = mirror.getElementValues().get(valueMethod); + if (value == null) { + value = valueMethod.getDefaultValue(); + } + + return value; + } + + private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7 { + + @Override + public Object visitBoolean(boolean b, Void p) { + return Boolean.valueOf(b); + } + + @Override + public Object visitByte(byte b, Void p) { + return Byte.valueOf(b); + } + + @Override + public Object visitChar(char c, Void p) { + return c; + } + + @Override + public Object visitDouble(double d, Void p) { + return d; + } + + @Override + public Object visitFloat(float f, Void p) { + return f; + } + + @Override + public Object visitInt(int i, Void p) { + return i; + } + + @Override + public Object visitLong(long i, Void p) { + return i; + } + + @Override + public Object visitShort(short s, Void p) { + return s; + } + + @Override + public Object visitString(String s, Void p) { + return s; + } + + @Override + public Object visitType(TypeMirror t, Void p) { + return t; + } + + @Override + public Object visitEnumConstant(VariableElement c, Void p) { + return c; + } + + @Override + public Object visitAnnotation(AnnotationMirror a, Void p) { + return a; + } + + @Override + public Object visitArray(List vals, Void p) { + return vals; + } + + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java 2016-12-07 13:48:09.546932371 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.sparc.test; + +import static org.graalvm.compiler.core.common.GraalOptions.TraceRA; +import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure; +import static org.junit.Assume.assumeTrue; +import jdk.vm.ci.sparc.SPARC; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.core.test.backend.AllocatorTest; + +public class SPARCAllocatorTest extends AllocatorTest { + + @Before + public void checkSPARC() { + assumeTrue("skipping SPARC specific test", getTarget().arch instanceof SPARC); + assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue() == null); + assumeTrue("TraceRA is set -> skip", !TraceRA.getValue()); + } + + @Test + public void test1() { + testAllocation("test1snippet", 2, 0, 0); + } + + public static long test1snippet(long x) { + return x + 5; + } + + @Test + public void test2() { + testAllocation("test2snippet", 2, 0, 0); + } + + public static long test2snippet(long x) { + return x * 5; + } + + @Test + public void test3() { + testAllocation("test3snippet", 4, 0, 0); + } + + public static long test3snippet(long x) { + return x / 3 + x % 3; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCAddressLowering.java 2016-12-07 13:48:09.812944059 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, 2016, 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.core.sparc; + +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering; + +import jdk.vm.ci.meta.JavaConstant; + +public class SPARCAddressLowering extends AddressLowering { + + @Override + public AddressNode lower(ValueNode address) { + return lower(address, 0); + } + + @Override + public AddressNode lower(ValueNode base, ValueNode offset) { + JavaConstant immBase = asImmediate(base); + if (immBase != null && SPARCAssembler.isSimm13(immBase)) { + return lower(offset, immBase.asLong()); + } + + JavaConstant immOffset = asImmediate(offset); + if (immOffset != null && SPARCAssembler.isSimm13(immOffset)) { + return lower(base, immOffset.asLong()); + } + return base.graph().unique(new SPARCIndexedAddressNode(base, offset)); + } + + private AddressNode lower(ValueNode base, long displacement) { + if (base instanceof AddNode) { + AddNode add = (AddNode) base; + + JavaConstant immX = asImmediate(add.getX()); + if (immX != null && SPARCAssembler.isSimm13(displacement + immX.asLong())) { + return lower(add.getY(), displacement + immX.asLong()); + } + + JavaConstant immY = asImmediate(add.getY()); + if (immY != null && SPARCAssembler.isSimm13(displacement + immY.asLong())) { + return lower(add.getX(), displacement + immY.asLong()); + } + + if (displacement == 0) { + return lower(add.getX(), add.getY()); + } + } + + assert SPARCAssembler.isSimm13(displacement); + return base.graph().unique(new SPARCImmediateAddressNode(base, (int) displacement)); + } + + private static JavaConstant asImmediate(ValueNode value) { + JavaConstant c = value.asJavaConstant(); + if (c != null && c.getJavaKind().isNumericInteger()) { + return c; + } else { + return null; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java 2016-12-07 13:48:10.075955616 -0800 @@ -0,0 +1,693 @@ +/* + * Copyright (c) 2009, 2016, 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.core.sparc; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Add; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Addcc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.And; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Mulx; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sdivx; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sllx; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sra; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srax; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srl; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sub; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Udivx; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xnor; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Faddd; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fadds; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtos; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitod; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitos; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuld; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuls; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegd; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegs; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstod; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fxtod; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.UMulxhi; +import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_DREM; +import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_FREM; +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.BSF; +import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.IBSR; +import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.LBSR; +import static jdk.vm.ci.code.CodeUtil.mask; +import static jdk.vm.ci.meta.JavaConstant.forLong; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARCKind.DOUBLE; +import static jdk.vm.ci.sparc.SPARCKind.SINGLE; +import static jdk.vm.ci.sparc.SPARCKind.WORD; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; + +import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.FloatConvert; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.ConstantValue; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator; +import org.graalvm.compiler.lir.sparc.SPARCAddressValue; +import org.graalvm.compiler.lir.sparc.SPARCArithmetic; +import org.graalvm.compiler.lir.sparc.SPARCArithmetic.FloatConvertOp; +import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp; +import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp.MulHigh; +import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp; +import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp.Rem; +import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCIMulccOp; +import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCLMulccOp; +import org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp; +import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp; +import org.graalvm.compiler.lir.sparc.SPARCMove.MoveFpGp; +import org.graalvm.compiler.lir.sparc.SPARCMove.StoreConstantOp; +import org.graalvm.compiler.lir.sparc.SPARCMove.StoreOp; +import org.graalvm.compiler.lir.sparc.SPARCOP3Op; +import org.graalvm.compiler.lir.sparc.SPARCOPFOp; + +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; +import jdk.vm.ci.sparc.SPARC; +import jdk.vm.ci.sparc.SPARC.CPUFeature; +import jdk.vm.ci.sparc.SPARCKind; + +/** + * This class implements the SPARC specific portion of the LIR generator. + */ +public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator { + + @Override + public SPARCLIRGenerator getLIRGen() { + return (SPARCLIRGenerator) super.getLIRGen(); + } + + @Override + public Variable emitBitCount(Value operand) { + Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD)); + Value usedOperand = operand; + if (operand.getPlatformKind() == SPARCKind.WORD) { // Zero extend + usedOperand = getLIRGen().newVariable(operand.getValueKind()); + getLIRGen().append(new SPARCOP3Op(Op3s.Srl, operand, SPARC.g0.asValue(), usedOperand)); + } + getLIRGen().append(new SPARCOP3Op(Op3s.Popc, SPARC.g0.asValue(), usedOperand, result)); + return result; + } + + @Override + public Variable emitBitScanForward(Value operand) { + Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD)); + getLIRGen().append(new SPARCBitManipulationOp(BSF, result, getLIRGen().asAllocatable(operand), getLIRGen())); + return result; + } + + @Override + public Variable emitBitScanReverse(Value operand) { + Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD)); + if (operand.getPlatformKind() == SPARCKind.XWORD) { + getLIRGen().append(new SPARCBitManipulationOp(LBSR, result, getLIRGen().asAllocatable(operand), getLIRGen())); + } else { + getLIRGen().append(new SPARCBitManipulationOp(IBSR, result, getLIRGen().asAllocatable(operand), getLIRGen())); + } + return result; + } + + @Override + public Value emitMathAbs(Value input) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + SPARCKind kind = (SPARCKind) input.getPlatformKind(); + Opfs opf; + switch (kind) { + case SINGLE: + opf = Opfs.Fabss; + break; + case DOUBLE: + opf = Opfs.Fabsd; + break; + default: + throw GraalError.shouldNotReachHere("Input kind: " + kind); + } + getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result)); + return result; + } + + @Override + public Value emitMathSqrt(Value input) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + SPARCKind kind = (SPARCKind) input.getPlatformKind(); + Opfs opf; + switch (kind) { + case SINGLE: + opf = Opfs.Fsqrts; + break; + case DOUBLE: + opf = Opfs.Fsqrtd; + break; + default: + throw GraalError.shouldNotReachHere("Input kind: " + kind); + } + getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result)); + return result; + } + + @Override + public Value emitNegate(Value input) { + PlatformKind inputKind = input.getPlatformKind(); + if (isNumericInteger(inputKind)) { + return emitUnary(Sub, input); + } else { + return emitUnary(inputKind.equals(DOUBLE) ? Fnegd : Fnegs, input); + } + } + + @Override + public Value emitNot(Value input) { + return emitUnary(Xnor, input); + } + + private Variable emitUnary(Opfs opf, Value input) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result)); + return result; + } + + private Variable emitUnary(Op3s op3, Value input) { + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + getLIRGen().append(SPARCOP3Op.newUnary(op3, input, result)); + return result; + } + + private Variable emitBinary(ValueKind resultKind, Opfs opf, Value a, Value b) { + return emitBinary(resultKind, opf, a, b, null); + } + + private Variable emitBinary(ValueKind resultKind, Opfs opf, Value a, Value b, LIRFrameState state) { + Variable result = getLIRGen().newVariable(resultKind); + if (opf.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) { + getLIRGen().append(new SPARCOPFOp(opf, b, a, result, state)); + } else { + getLIRGen().append(new SPARCOPFOp(opf, a, b, result, state)); + } + return result; + } + + private Variable emitBinary(ValueKind resultKind, Op3s op3, Value a, int b) { + return emitBinary(resultKind, op3, a, new ConstantValue(LIRKind.value(WORD), JavaConstant.forInt(b))); + } + + private Variable emitBinary(ValueKind resultKind, Op3s op3, Value a, Value b) { + return emitBinary(resultKind, op3, a, b, null); + } + + private Variable emitBinary(ValueKind resultKind, Op3s op3, Value a, Value b, LIRFrameState state) { + Variable result = getLIRGen().newVariable(resultKind); + if (op3.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) { + getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(b), a, result, state)); + } else { + getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(a), b, result, state)); + } + return result; + } + + @Override + protected boolean isNumericInteger(PlatformKind kind) { + return ((SPARCKind) kind).isInteger(); + } + + @Override + public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) { + if (isNumericInteger(a.getPlatformKind())) { + return emitBinary(resultKind, setFlags ? Addcc : Add, a, b); + } else { + boolean isDouble = a.getPlatformKind().equals(DOUBLE); + return emitBinary(resultKind, isDouble ? Faddd : Fadds, a, b); + } + } + + @Override + public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) { + if (isNumericInteger(a.getPlatformKind())) { + return emitBinary(resultKind, setFlags ? Subcc : Sub, a, b); + } else { + boolean isDouble = a.getPlatformKind().equals(DOUBLE); + return emitBinary(resultKind, isDouble ? Opfs.Fsubd : Opfs.Fsubs, a, b); + } + } + + @Override + public Variable emitMul(Value a, Value b, boolean setFlags) { + LIRKind resultKind = LIRKind.combine(a, b); + PlatformKind aKind = a.getPlatformKind(); + if (isNumericInteger(aKind)) { + if (setFlags) { + Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); + if (aKind == XWORD) { + getLIRGen().append(new SPARCLMulccOp(result, getLIRGen().load(a), getLIRGen().load(b), getLIRGen())); + } else if (aKind == WORD) { + getLIRGen().append(new SPARCIMulccOp(result, getLIRGen().load(a), getLIRGen().load(b))); + } else { + throw GraalError.shouldNotReachHere(); + } + return result; + } else { + return emitBinary(resultKind, setFlags ? Op3s.Mulscc : Op3s.Mulx, a, b); + } + } else { + boolean isDouble = a.getPlatformKind().equals(DOUBLE); + return emitBinary(resultKind, isDouble ? Fmuld : Fmuls, a, b); + } + } + + @Override + public Value emitMulHigh(Value a, Value b) { + MulHigh opcode; + switch (((SPARCKind) a.getPlatformKind())) { + case WORD: + opcode = MulHigh.IMUL; + break; + case XWORD: + opcode = MulHigh.LMUL; + break; + default: + throw GraalError.shouldNotReachHere(); + } + return emitMulHigh(opcode, a, b); + } + + @Override + public Value emitUMulHigh(Value a, Value b) { + switch (((SPARCKind) a.getPlatformKind())) { + case WORD: + Value aExtended = emitBinary(LIRKind.combine(a), Srl, a, 0); + Value bExtended = emitBinary(LIRKind.combine(b), Srl, b, 0); + Value result = emitBinary(LIRKind.combine(a, b), Mulx, aExtended, bExtended); + return emitBinary(LIRKind.combine(a, b), Srax, result, WORD.getSizeInBits()); + case XWORD: + return emitBinary(LIRKind.combine(a, b), UMulxhi, a, b); + default: + throw GraalError.shouldNotReachHere(); + } + } + + private Value emitMulHigh(MulHigh opcode, Value a, Value b) { + Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); + MulHighOp mulHigh = new MulHighOp(opcode, getLIRGen().load(a), getLIRGen().load(b), result, getLIRGen().newVariable(LIRKind.combine(a, b))); + getLIRGen().append(mulHigh); + return result; + } + + @Override + public Value emitDiv(Value a, Value b, LIRFrameState state) { + LIRKind resultKind = LIRKind.combine(a, b); + PlatformKind aKind = a.getPlatformKind(); + PlatformKind bKind = b.getPlatformKind(); + if (isJavaConstant(b) && asJavaConstant(b).isDefaultForKind()) { // Div by zero + Value zero = SPARC.g0.asValue(LIRKind.value(SPARCKind.WORD)); + return emitBinary(resultKind, Op3s.Sdivx, zero, zero, state); + } else if (isNumericInteger(aKind)) { + Value fixedA = emitSignExtend(a, aKind.getSizeInBytes() * 8, 64); + Value fixedB = emitSignExtend(b, bKind.getSizeInBytes() * 8, 64); + return emitBinary(resultKind, Op3s.Sdivx, fixedA, fixedB, state); + } else { + boolean isDouble = a.getPlatformKind().equals(DOUBLE); + return emitBinary(resultKind, isDouble ? Opfs.Fdivd : Opfs.Fdivs, a, b, state); + } + } + + @Override + public Value emitRem(Value a, Value b, LIRFrameState state) { + Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); + Value aLoaded; + Variable q1; // Intermediate values + Variable q2; + SPARCKind aKind = (SPARCKind) a.getPlatformKind(); + switch (aKind) { + case WORD: + // Sign extend a and b + Variable as = emitBinary(result.getValueKind(), Sra, a, g0.asValue(LIRKind.value(WORD))); + Variable bs = emitBinary(result.getValueKind(), Sra, b, g0.asValue(LIRKind.value(WORD))); + q1 = emitBinary(as.getValueKind(), Sdivx, as, bs, state); + q2 = emitBinary(q1.getValueKind(), Mulx, q1, bs); + result = emitSub(as, q2, false); + break; + case XWORD: + aLoaded = getLIRGen().load(a); // Reuse the loaded value + q1 = emitBinary(result.getValueKind(), Sdivx, aLoaded, b, state); + q2 = emitBinary(result.getValueKind(), Mulx, q1, b); + result = emitSub(aLoaded, q2, false); + break; + case SINGLE: + ForeignCallLinkage fremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_FREM); + result = getLIRGen().emitForeignCall(fremCall, state, a, b); + break; + case DOUBLE: + ForeignCallLinkage dremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_DREM); + result = getLIRGen().emitForeignCall(dremCall, state, a, b); + break; + default: + throw GraalError.shouldNotReachHere("missing: " + a.getPlatformKind()); + } + return result; + } + + @Override + public Value emitURem(Value a, Value b, LIRFrameState state) { + Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); + Variable scratch1 = getLIRGen().newVariable(LIRKind.combine(a, b)); + Variable scratch2 = getLIRGen().newVariable(LIRKind.combine(a, b)); + Rem opcode; + switch (((SPARCKind) a.getPlatformKind())) { + case WORD: + opcode = Rem.IUREM; + break; + case XWORD: + opcode = Rem.LUREM; + break; + default: + throw GraalError.shouldNotReachHere(); + } + getLIRGen().append(new RemOp(opcode, result, getLIRGen().load(a), getLIRGen().load(b), scratch1, scratch2, state)); + return result; + + } + + @Override + public Value emitUDiv(Value a, Value b, LIRFrameState state) { + Value actualA = a; + Value actualB = b; + switch (((SPARCKind) a.getPlatformKind())) { + case WORD: + actualA = emitZeroExtend(actualA, 32, 64); + actualB = emitZeroExtend(actualB, 32, 64); + break; + case XWORD: + break; + default: + throw GraalError.shouldNotReachHere(); + } + return emitBinary(LIRKind.combine(actualA, actualB), Udivx, actualA, actualB, state); + } + + @Override + public Variable emitAnd(Value a, Value b) { + LIRKind resultKind = LIRKind.combine(a, b); + return emitBinary(resultKind, Op3s.And, a, b); + } + + @Override + public Variable emitOr(Value a, Value b) { + LIRKind resultKind = LIRKind.combine(a, b); + return emitBinary(resultKind, Op3s.Or, a, b); + } + + @Override + public Variable emitXor(Value a, Value b) { + LIRKind resultKind = LIRKind.combine(a, b); + return emitBinary(resultKind, Op3s.Xor, a, b); + } + + @Override + public Variable emitShl(Value a, Value b) { + SPARCKind aKind = (SPARCKind) a.getPlatformKind(); + LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind); + Op3s op; + switch (aKind) { + case WORD: + op = Op3s.Sll; + break; + case XWORD: + op = Op3s.Sllx; + break; + default: + throw GraalError.shouldNotReachHere(String.format("Unsupported kind %s", aKind)); + } + return emitBinary(resultKind, op, a, b); + } + + @Override + public Variable emitShr(Value a, Value b) { + SPARCKind aKind = (SPARCKind) a.getPlatformKind(); + LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind); + Op3s op; + switch (aKind) { + case WORD: + op = Op3s.Sra; + break; + case XWORD: + op = Op3s.Srax; + break; + default: + throw GraalError.shouldNotReachHere(); + } + return emitBinary(resultKind, op, a, b); + } + + @Override + public Variable emitUShr(Value a, Value b) { + SPARCKind aKind = (SPARCKind) a.getPlatformKind(); + LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind); + Op3s op; + switch (aKind) { + case WORD: + op = Op3s.Srl; + break; + case XWORD: + op = Op3s.Srlx; + break; + default: + throw GraalError.shouldNotReachHere(); + } + return emitBinary(resultKind, op, a, b); + } + + private AllocatableValue emitConvertMove(LIRKind kind, AllocatableValue input) { + Variable result = getLIRGen().newVariable(kind); + getLIRGen().emitMove(result, input); + return result; + } + + @Override + public Value emitFloatConvert(FloatConvert op, Value inputVal) { + AllocatableValue input = getLIRGen().asAllocatable(inputVal); + Value result; + switch (op) { + case D2F: + result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(SINGLE)); + getLIRGen().append(new SPARCOPFOp(Fdtos, inputVal, result)); + break; + case F2D: + result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(DOUBLE)); + getLIRGen().append(new SPARCOPFOp(Fstod, inputVal, result)); + break; + case I2F: { + AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE)); + result = getLIRGen().newVariable(intEncodedFloatReg.getValueKind()); + moveBetweenFpGp(intEncodedFloatReg, input); + getLIRGen().append(new SPARCOPFOp(Fitos, intEncodedFloatReg, result)); + break; + } + case I2D: { + // Unfortunately we must do int -> float -> double because fitod has float + // and double encoding in one instruction + AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE)); + result = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE)); + moveBetweenFpGp(convertedFloatReg, input); + getLIRGen().append(new SPARCOPFOp(Fitod, convertedFloatReg, result)); + break; + } + case L2D: { + AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE)); + moveBetweenFpGp(longEncodedDoubleReg, input); + AllocatableValue convertedDoubleReg = getLIRGen().newVariable(longEncodedDoubleReg.getValueKind()); + getLIRGen().append(new SPARCOPFOp(Fxtod, longEncodedDoubleReg, convertedDoubleReg)); + result = convertedDoubleReg; + break; + } + case D2I: { + AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE)); + getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, input, convertedFloatReg)); + AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD)); + moveBetweenFpGp(convertedIntReg, convertedFloatReg); + result = convertedIntReg; + break; + } + case F2L: { + AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE)); + getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, input, convertedDoubleReg)); + AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD)); + moveBetweenFpGp(convertedLongReg, convertedDoubleReg); + result = convertedLongReg; + break; + } + case F2I: { + AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE)); + getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, input, convertedFloatReg)); + AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD)); + moveBetweenFpGp(convertedIntReg, convertedFloatReg); + result = convertedIntReg; + break; + } + case D2L: { + AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE)); + getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, input, convertedDoubleReg)); + AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD)); + moveBetweenFpGp(convertedLongReg, convertedDoubleReg); + result = convertedLongReg; + break; + } + case L2F: { + AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE)); + result = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE)); + moveBetweenFpGp(convertedDoubleReg, input); + getLIRGen().append(new SPARCOPFOp(Opfs.Fxtos, convertedDoubleReg, result)); + break; + } + default: + throw GraalError.shouldNotReachHere(); + } + return result; + } + + protected VirtualStackSlot getTempSlot(LIRKind kind) { + return getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(kind); + } + + private void moveBetweenFpGp(AllocatableValue dst, AllocatableValue src) { + AllocatableValue tempSlot; + PlatformKind dstKind = dst.getPlatformKind(); + PlatformKind srcKind = src.getPlatformKind(); + if (getLIRGen().getArchitecture().getFeatures().contains(CPUFeature.VIS3) && !(srcKind == WORD && dstKind == SINGLE) && !(srcKind == SINGLE && dstKind == WORD)) { + tempSlot = AllocatableValue.ILLEGAL; + } else { + tempSlot = getTempSlot(LIRKind.value(XWORD)); + } + getLIRGen().append(new MoveFpGp(dst, src, tempSlot)); + } + + @Override + public Value emitNarrow(Value inputVal, int bits) { + if (inputVal.getPlatformKind() == XWORD && bits <= 32) { + LIRKind resultKind = LIRKind.combine(inputVal).changeType(WORD); + Variable result = getLIRGen().newVariable(resultKind); + getLIRGen().emitMove(result, inputVal); + return result; + } else { + return inputVal; + } + } + + @Override + public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= XWORD.getSizeInBits(); + LIRKind shiftKind = LIRKind.value(WORD); + LIRKind resultKind = LIRKind.combine(inputVal).changeType(toBits > 32 ? XWORD : WORD); + Value result; + int shiftCount = XWORD.getSizeInBits() - fromBits; + if (fromBits == toBits) { + result = inputVal; + } else if (isJavaConstant(inputVal)) { + JavaConstant javaConstant = asJavaConstant(inputVal); + long constant; + if (javaConstant.isNull()) { + constant = 0; + } else { + constant = javaConstant.asLong(); + } + return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount)); + } else if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) { + result = getLIRGen().newVariable(resultKind); + getLIRGen().append(new SPARCOP3Op(Sra, inputVal, SPARC.g0.asValue(LIRKind.value(WORD)), result)); + } else { + Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD)); + result = getLIRGen().newVariable(resultKind); + getLIRGen().append(new SPARCOP3Op(Sllx, inputVal, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), tmp)); + getLIRGen().append(new SPARCOP3Op(Srax, tmp, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), result)); + } + return result; + } + + @Override + public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + if (fromBits == toBits) { + return inputVal; + } + Variable result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD)); + if (fromBits == 32) { + getLIRGen().append(new SPARCOP3Op(Srl, inputVal, g0.asValue(), result)); + } else { + Value mask = getLIRGen().emitConstant(LIRKind.value(XWORD), forLong(mask(fromBits))); + getLIRGen().append(new SPARCOP3Op(And, inputVal, mask, result)); + } + return result; + } + + @Override + public AllocatableValue emitReinterpret(LIRKind to, Value inputVal) { + SPARCKind fromKind = (SPARCKind) inputVal.getPlatformKind(); + SPARCKind toKind = (SPARCKind) to.getPlatformKind(); + AllocatableValue input = getLIRGen().asAllocatable(inputVal); + Variable result = getLIRGen().newVariable(to); + // These cases require a move between CPU and FPU registers: + if (fromKind.isFloat() != toKind.isFloat()) { + moveBetweenFpGp(result, input); + return result; + } else { + // Otherwise, just emit an ordinary move instruction. + // Instructions that move or generate 32-bit register values also set the upper 32 + // bits of the register to zero. + // Consequently, there is no need for a special zero-extension move. + return emitConvertMove(to, input); + } + } + + @Override + public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { + SPARCAddressValue loadAddress = getLIRGen().asAddressValue(address); + Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind)); + getLIRGen().append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state)); + return result; + } + + @Override + public void emitStore(ValueKind kind, Value address, Value inputVal, LIRFrameState state) { + SPARCAddressValue storeAddress = getLIRGen().asAddressValue(address); + if (isJavaConstant(inputVal)) { + JavaConstant c = asJavaConstant(inputVal); + if (c.isDefaultForKind()) { + getLIRGen().append(new StoreConstantOp(kind.getPlatformKind(), storeAddress, c, state)); + return; + } + } + Variable input = getLIRGen().load(inputVal); + getLIRGen().append(new StoreOp(kind.getPlatformKind(), storeAddress, input, state)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCImmediateAddressNode.java 2016-12-07 13:48:10.341967305 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, 2015, 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.core.sparc; + +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Represents an address of the form [base + simm13]. + */ +@NodeInfo +public class SPARCImmediateAddressNode extends AddressNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(SPARCImmediateAddressNode.class); + + @Input private ValueNode base; + private int displacement; + + public SPARCImmediateAddressNode(ValueNode base, int displacement) { + super(TYPE); + assert SPARCAssembler.isSimm13(displacement); + this.base = base; + this.displacement = displacement; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + SPARCLIRGenerator tool = (SPARCLIRGenerator) gen.getLIRGeneratorTool(); + + AllocatableValue baseValue = tool.asAllocatable(gen.operand(base)); + + LIRKind kind = tool.getLIRKind(stamp()); + AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue); + if (baseReference != null) { + kind = kind.makeDerivedReference(baseReference); + } + + gen.setResult(this, new SPARCImmediateAddressValue(kind, baseValue, displacement)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIndexedAddressNode.java 2016-12-07 13:48:10.606978948 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, 2015, 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.core.sparc; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.lir.sparc.SPARCIndexedAddressValue; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Represents an address of the form [base + index]. + */ +@NodeInfo +public class SPARCIndexedAddressNode extends AddressNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(SPARCIndexedAddressNode.class); + + @Input private ValueNode base; + @Input private ValueNode index; + + public SPARCIndexedAddressNode(ValueNode base, ValueNode index) { + super(TYPE); + this.base = base; + this.index = index; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + SPARCLIRGenerator tool = (SPARCLIRGenerator) gen.getLIRGeneratorTool(); + + AllocatableValue baseValue = tool.asAllocatable(gen.operand(base)); + AllocatableValue indexValue = tool.asAllocatable(gen.operand(index)); + + AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue); + AllocatableValue indexReference = LIRKind.derivedBaseFromValue(indexValue); + + LIRKind kind = LIRKind.combineDerived(tool.getLIRKind(stamp()), baseReference, indexReference); + gen.setResult(this, new SPARCIndexedAddressValue(kind, baseValue, indexValue)); + } + + public ValueNode getBase() { + return base; + } + + public void setBase(ValueNode base) { + updateUsages(this.base, base); + this.base = base; + } + + public ValueNode getIndex() { + return index; + } + + public void setIndex(ValueNode index) { + updateUsages(this.index, index); + this.index = index; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIntegerCompareCanonicalizationPhase.java 2016-12-07 13:48:10.870990549 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, 2016, 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.core.sparc; + +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.CompareNode; +import org.graalvm.compiler.nodes.calc.SignExtendNode; +import org.graalvm.compiler.phases.Phase; + +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.meta.JavaConstant; + +/** + * SPARC only supports 32 and 64 bit integer compare. + * + * This phase turns {@link CompareNode}s which have {@link IntegerStamp} as input and its bit-width + * is not 32 or 64 bit into either a 32 or 64 bit compare by sign extending the input values. + * + * Why we do this in the HIR instead in the LIR? This enables the pattern matcher + * {@link SPARCNodeMatchRules#signExtend(SignExtendNode, org.graalvm.compiler.nodes.memory.Access)} + * to do it's job and replace loads with sign extending ones. + */ +public class SPARCIntegerCompareCanonicalizationPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + for (Node n : graph.getNodes()) { + if (n instanceof CompareNode) { + CompareNode enode = (CompareNode) n; + min32(enode, enode.getX()); + min32(enode, enode.getY()); + } + } + } + + private static void min32(CompareNode enode, ValueNode v) { + Stamp s = v.stamp(); + if (s instanceof IntegerStamp) { + int bits = ((IntegerStamp) s).getBits(); + if (bits != 32 && bits != 64) { + if (bits <= 32) { + bits = 32; + } else { + bits = 64; + } + ValueNode replacement; + if (v instanceof ConstantNode) { + JavaConstant newConst; + if (bits == 32) { + newConst = JavaConstant.forInt(v.asJavaConstant().asInt()); + } else if (bits == 64) { + newConst = JavaConstant.forLong(v.asJavaConstant().asLong()); + } else { + throw GraalError.shouldNotReachHere(); + } + long mask = CodeUtil.mask(bits); + replacement = v.graph().addOrUnique(new ConstantNode(newConst, IntegerStamp.stampForMask(bits, newConst.asLong() & mask, newConst.asLong() & mask))); + } else { + replacement = v.graph().addOrUnique(new SignExtendNode(v, bits)); + } + v.replaceAtUsages(replacement, x -> x == enode); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java 2016-12-07 13:48:11.137002238 -0800 @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2009, 2016, 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.core.sparc; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FMOVDCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FMOVSCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.MOVicc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps; +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static jdk.vm.ci.sparc.SPARCKind.SINGLE; +import static jdk.vm.ci.sparc.SPARCKind.WORD; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; + +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.CMOV; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRValueUtil; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.StandardOp.NoOp; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.gen.LIRGenerator; +import org.graalvm.compiler.lir.sparc.SPARCAddressValue; +import org.graalvm.compiler.lir.sparc.SPARCArrayEqualsOp; +import org.graalvm.compiler.lir.sparc.SPARCByteSwapOp; +import org.graalvm.compiler.lir.sparc.SPARCCall; +import org.graalvm.compiler.lir.sparc.SPARCControlFlow; +import org.graalvm.compiler.lir.sparc.SPARCControlFlow.BranchOp; +import org.graalvm.compiler.lir.sparc.SPARCControlFlow.CondMoveOp; +import org.graalvm.compiler.lir.sparc.SPARCControlFlow.ReturnOp; +import org.graalvm.compiler.lir.sparc.SPARCControlFlow.StrategySwitchOp; +import org.graalvm.compiler.lir.sparc.SPARCControlFlow.TableSwitchOp; +import org.graalvm.compiler.lir.sparc.SPARCFloatCompareOp; +import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue; +import org.graalvm.compiler.lir.sparc.SPARCJumpOp; +import org.graalvm.compiler.lir.sparc.SPARCLoadConstantTableBaseOp; +import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp; +import org.graalvm.compiler.lir.sparc.SPARCMove.MembarOp; +import org.graalvm.compiler.lir.sparc.SPARCMove.NullCheckOp; +import org.graalvm.compiler.lir.sparc.SPARCMove.StackLoadAddressOp; +import org.graalvm.compiler.lir.sparc.SPARCOP3Op; +import org.graalvm.compiler.lir.sparc.SPARCPauseOp; +import org.graalvm.compiler.phases.util.Providers; + +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; +import jdk.vm.ci.sparc.SPARC; +import jdk.vm.ci.sparc.SPARCKind; + +/** + * This class implements the SPARC specific portion of the LIR generator. + */ +public abstract class SPARCLIRGenerator extends LIRGenerator { + + private SPARCLoadConstantTableBaseOp loadConstantTableBaseOp; + private final ConstantTableBaseProvider constantTableBaseProvider; + + public static final class ConstantTableBaseProvider { + private Variable constantTableBase; + private boolean useConstantTableBase = false; + + public Variable getConstantTableBase() { + useConstantTableBase = true; + return constantTableBase; + } + } + + public SPARCLIRGenerator(LIRKindTool lirKindTool, SPARCArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes, + ConstantTableBaseProvider constantTableBaseProvider) { + super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes); + this.constantTableBaseProvider = constantTableBaseProvider; + } + + @Override + protected JavaConstant zapValueForKind(PlatformKind kind) { + long dead = 0xDEADDEADDEADDEADL; + switch ((SPARCKind) kind) { + case BYTE: + return JavaConstant.forByte((byte) dead); + case HWORD: + return JavaConstant.forShort((short) dead); + case WORD: + return JavaConstant.forInt((int) dead); + case XWORD: + return JavaConstant.forLong(dead); + case SINGLE: + case V32_BYTE: + case V32_HWORD: + return JavaConstant.forFloat(Float.intBitsToFloat((int) dead)); + case DOUBLE: + case V64_BYTE: + case V64_HWORD: + case V64_WORD: + return JavaConstant.forDouble(Double.longBitsToDouble(dead)); + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * The SPARC backend only uses WORD and DWORD values in registers because except to the ld/st + * instructions no instruction deals either with 32 or 64 bits. This function converts small + * integer kinds to WORD. + */ + @Override + public > K toRegisterKind(K kind) { + switch ((SPARCKind) kind.getPlatformKind()) { + case BYTE: + case HWORD: + return kind.changeType(SPARCKind.WORD); + default: + return kind; + } + } + + public SPARCAddressValue asAddressValue(Value address) { + if (address instanceof SPARCAddressValue) { + return (SPARCAddressValue) address; + } else { + ValueKind kind = address.getValueKind(); + if (address instanceof JavaConstant) { + long displacement = ((JavaConstant) address).asLong(); + if (SPARCAssembler.isSimm13(displacement)) { + return new SPARCImmediateAddressValue(kind, SPARC.g0.asValue(kind), (int) displacement); + } + } + return new SPARCImmediateAddressValue(kind, asAllocatable(address), 0); + } + } + + @Override + public Variable emitAddress(AllocatableValue stackslot) { + Variable result = newVariable(LIRKind.value(target().arch.getWordKind())); + append(new StackLoadAddressOp(result, stackslot)); + return result; + } + + @Override + public void emitReturn(JavaKind javaKind, Value input) { + AllocatableValue operand = Value.ILLEGAL; + if (input != null) { + operand = resultOperandFor(javaKind, input.getValueKind()); + emitMove(operand, input); + } + append(new ReturnOp(operand)); + } + + @Override + public void emitJump(LabelRef label) { + append(new SPARCJumpOp(label)); + } + + @Override + public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, + double trueDestinationProbability) { + Value left; + Value right; + Condition actualCondition; + if (isJavaConstant(x)) { + left = load(y); + right = loadNonConst(x); + actualCondition = cond.mirror(); + } else { + left = load(x); + right = loadNonConst(y); + actualCondition = cond; + } + SPARCKind actualCmpKind = (SPARCKind) cmpKind; + if (actualCmpKind.isInteger()) { + assert actualCmpKind.equals(XWORD) || actualCmpKind.equals(WORD) : "SPARC does not support compare of: " + actualCmpKind; + append(new SPARCControlFlow.CompareBranchOp(left, right, actualCondition, trueDestination, falseDestination, actualCmpKind, unorderedIsTrue, trueDestinationProbability)); + } else if (actualCmpKind.isFloat()) { + emitFloatCompare(actualCmpKind, x, y, Fcc0); + ConditionFlag cf = SPARCControlFlow.fromCondition(false, cond, unorderedIsTrue); + append(new SPARCControlFlow.BranchOp(cf, trueDestination, falseDestination, actualCmpKind, trueDestinationProbability)); + } else { + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability) { + SPARCKind cmpKind = (SPARCKind) cmpLIRKind.getPlatformKind(); + append(new BranchOp(ConditionFlag.OverflowSet, overflow, noOverflow, cmpKind, overflowProbability)); + } + + @Override + public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { + emitIntegerTest(left, right); + append(new BranchOp(ConditionFlag.Equal, trueDestination, falseDestination, (SPARCKind) left.getPlatformKind(), trueDestinationProbability)); + } + + private void emitIntegerTest(Value a, Value b) { + assert ((SPARCKind) a.getPlatformKind()).isInteger(); + if (LIRValueUtil.isVariable(b)) { + append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(b), loadNonConst(a))); + } else { + append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(a), loadNonConst(b))); + } + } + + private Value loadSimm11(Value value) { + if (isJavaConstant(value)) { + JavaConstant c = asJavaConstant(value); + if (c.isNull() || SPARCAssembler.isSimm11(c)) { + return value; + } + } + return load(value); + } + + @Override + public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { + // Emit compare + SPARCKind cmpSPARCKind = (SPARCKind) cmpKind; + boolean mirrored = emitCompare(cmpSPARCKind, left, right); + + // Emit move + Value actualTrueValue = trueValue; + Value actualFalseValue = falseValue; + SPARCKind valueKind = (SPARCKind) trueValue.getPlatformKind(); + CMOV cmove; + if (valueKind.isFloat()) { + actualTrueValue = load(trueValue); // Floats cannot be immediate at all + actualFalseValue = load(falseValue); + cmove = valueKind.equals(SINGLE) ? FMOVSCC : FMOVDCC; + } else if (valueKind.isInteger()) { + actualTrueValue = loadSimm11(trueValue); + actualFalseValue = loadSimm11(falseValue); + cmove = MOVicc; + } else { + throw GraalError.shouldNotReachHere(); + } + Variable result = newVariable(trueValue.getValueKind()); + ConditionFlag finalCondition = SPARCControlFlow.fromCondition(cmpSPARCKind.isInteger(), mirrored ? cond.mirror() : cond, unorderedIsTrue); + CC cc = CC.forKind(cmpSPARCKind); + append(new CondMoveOp(cmove, cc, finalCondition, actualTrueValue, actualFalseValue, result)); + return result; + } + + /** + * This method emits the compare instruction, and may reorder the operands. It returns true if + * it did so. + * + * @param cmpKind Kind how a and b have to be compared + * @param a the left operand of the comparison + * @param b the right operand of the comparison + * @return true if the left and right operands were switched, false otherwise + */ + protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) { + boolean mirrored; + if (cmpKind.isInteger()) { // Integer case + mirrored = emitIntegerCompare(cmpKind, a, b); + } else if (cmpKind.isFloat()) { // Float case + mirrored = false; // No mirroring done on floats + emitFloatCompare(cmpKind, a, b, Fcc0); + } else { + throw GraalError.shouldNotReachHere(); + } + return mirrored; + } + + private boolean emitIntegerCompare(SPARCKind cmpKind, Value a, Value b) { + boolean mirrored; + assert cmpKind.isInteger(); + Value left; + Value right; + if (LIRValueUtil.isVariable(b)) { + left = load(b); + right = loadNonConst(a); + mirrored = true; + } else { + left = load(a); + right = loadNonConst(b); + mirrored = false; + } + int compareBytes = cmpKind.getSizeInBytes(); + // SPARC compares 32 or 64 bits + if (compareBytes < left.getPlatformKind().getSizeInBytes()) { + left = arithmeticLIRGen.emitSignExtend(left, compareBytes * 8, XWORD.getSizeInBytes() * 8); + } + if (compareBytes < right.getPlatformKind().getSizeInBytes()) { + right = arithmeticLIRGen.emitSignExtend(right, compareBytes * 8, XWORD.getSizeInBytes() * 8); + } + append(SPARCOP3Op.newBinaryVoid(Subcc, left, right)); + return mirrored; + } + + private void emitFloatCompare(SPARCKind cmpJavaKind, Value a, Value b, CC cc) { + Opfs floatCompareOpcode; + assert cmpJavaKind.isFloat(); + switch (cmpJavaKind) { + case DOUBLE: + floatCompareOpcode = Fcmpd; + break; + case SINGLE: + floatCompareOpcode = Fcmps; + break; + default: + throw GraalError.shouldNotReachHere(); + } + append(new SPARCFloatCompareOp(floatCompareOpcode, cc, load(a), load(b))); + } + + @Override + public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) { + emitIntegerTest(left, right); + Variable result = newVariable(trueValue.getValueKind()); + ConditionFlag flag = SPARCControlFlow.fromCondition(true, Condition.EQ, false); + CC cc = CC.forKind(left.getPlatformKind()); + append(new CondMoveOp(MOVicc, cc, flag, loadSimm11(trueValue), loadSimm11(falseValue), result)); + return result; + } + + @Override + protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + long maxOffset = linkage.getMaxCallTargetOffset(); + if (SPARCAssembler.isWordDisp30(maxOffset)) { + append(new SPARCCall.DirectNearForeignCallOp(linkage, result, arguments, temps, info)); + } else { + append(new SPARCCall.DirectFarForeignCallOp(linkage, result, arguments, temps, info)); + } + } + + @Override + public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { + AllocatableValue scratchValue = newVariable(key.getValueKind()); + AllocatableValue base = AllocatableValue.ILLEGAL; + for (Constant c : strategy.getKeyConstants()) { + if (!(c instanceof JavaConstant) || !getMoveFactory().canInlineConstant((JavaConstant) c)) { + base = constantTableBaseProvider.getConstantTableBase(); + break; + } + } + append(createStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue)); + } + + protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue) { + return new StrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue); + } + + @Override + protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) { + // Making a copy of the switch value is necessary because jump table destroys the input + // value + Variable tmp = newVariable(key.getValueKind()); + emitMove(tmp, key); + append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(LIRKind.value(target().arch.getWordKind())))); + } + + protected SPARC getArchitecture() { + return (SPARC) target().arch; + } + + @Override + public Variable emitByteSwap(Value input) { + Variable result = newVariable(LIRKind.combine(input)); + append(new SPARCByteSwapOp(this, result, input)); + return result; + } + + @Override + public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) { + Variable result = newVariable(LIRKind.value(SPARCKind.WORD)); + append(new SPARCArrayEqualsOp(this, kind, result, load(array1), load(array2), asAllocatable(length))); + return result; + } + + @Override + public void emitMembar(int barriers) { + int necessaryBarriers = target().arch.requiredBarriers(barriers); + if (target().isMP && necessaryBarriers != 0) { + append(new MembarOp(necessaryBarriers)); + } + } + + @Override + public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) { + append(new ReturnOp(Value.ILLEGAL)); + } + + public Value emitSignExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) { + SPARCAddressValue loadAddress = asAddressValue(address); + Variable result = newVariable(resultKind); + append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state, true)); + return result; + } + + public Value emitZeroExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) { + SPARCAddressValue loadAddress = asAddressValue(address); + Variable result = newVariable(resultKind); + append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state)); + return result; + } + + @Override + public void emitNullCheck(Value address, LIRFrameState state) { + PlatformKind kind = address.getPlatformKind(); + assert kind == XWORD : address + " - " + kind + " not an object!"; + append(new NullCheckOp(asAddressValue(address), state)); + } + + public void emitLoadConstantTableBase() { + constantTableBaseProvider.constantTableBase = newVariable(LIRKind.value(XWORD)); + int nextPosition = getResult().getLIR().getLIRforBlock(getCurrentBlock()).size(); + NoOp placeHolder = append(new NoOp(getCurrentBlock(), nextPosition)); + loadConstantTableBaseOp = new SPARCLoadConstantTableBaseOp(constantTableBaseProvider.constantTableBase, placeHolder); + } + + @Override + public void beforeRegisterAllocation() { + LIR lir = getResult().getLIR(); + loadConstantTableBaseOp.setAlive(lir, constantTableBaseProvider.useConstantTableBase); + } + + @Override + public void emitPause() { + append(new SPARCPauseOp()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRKindTool.java 2016-12-07 13:48:11.403013926 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 2015, 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.core.sparc; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.sparc.SPARCKind; + +public class SPARCLIRKindTool implements LIRKindTool { + + @Override + public LIRKind getIntegerKind(int bits) { + if (bits <= 8) { + return LIRKind.value(SPARCKind.BYTE); + } else if (bits <= 16) { + return LIRKind.value(SPARCKind.HWORD); + } else if (bits <= 32) { + return LIRKind.value(SPARCKind.WORD); + } else { + assert bits <= 64; + return LIRKind.value(SPARCKind.XWORD); + } + } + + @Override + public LIRKind getFloatingKind(int bits) { + switch (bits) { + case 32: + return LIRKind.value(SPARCKind.SINGLE); + case 64: + return LIRKind.value(SPARCKind.DOUBLE); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public LIRKind getObjectKind() { + return LIRKind.reference(SPARCKind.XWORD); + } + + @Override + public LIRKind getWordKind() { + return LIRKind.value(SPARCKind.XWORD); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCMoveFactory.java 2016-12-07 13:48:11.669025614 -0800 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015, 2016, 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.core.sparc; + +import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; +import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; + +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.core.common.type.DataPointerConstant; +import org.graalvm.compiler.core.sparc.SPARCLIRGenerator.ConstantTableBaseProvider; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; +import org.graalvm.compiler.lir.sparc.SPARCAddressValue; +import org.graalvm.compiler.lir.sparc.SPARCMove; +import org.graalvm.compiler.lir.sparc.SPARCMove.LoadAddressOp; +import org.graalvm.compiler.lir.sparc.SPARCMove.Move; + +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.Value; + +public class SPARCMoveFactory implements MoveFactory { + + protected final ConstantTableBaseProvider constantTableBaseProvider; + + public SPARCMoveFactory(ConstantTableBaseProvider constantTableBaseProvider) { + this.constantTableBaseProvider = constantTableBaseProvider; + } + + @Override + public LIRInstruction createMove(AllocatableValue dst, Value src) { + boolean srcIsSlot = isStackSlotValue(src); + boolean dstIsSlot = isStackSlotValue(dst); + if (isConstantValue(src)) { + return createLoad(dst, asConstant(src)); + } else if (src instanceof SPARCAddressValue) { + return new LoadAddressOp(dst, (SPARCAddressValue) src); + } else { + assert src instanceof AllocatableValue; + if (srcIsSlot && dstIsSlot) { + throw GraalError.shouldNotReachHere(src.getClass() + " " + dst.getClass()); + } else { + return new Move(dst, (AllocatableValue) src); + } + } + } + + @Override + public LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) { + return new SPARCMove.Move(result, input); + } + + @Override + public LIRInstruction createLoad(AllocatableValue dst, Constant src) { + if (src instanceof JavaConstant) { + JavaConstant javaConstant = (JavaConstant) src; + if (canInlineConstant(javaConstant)) { + return new SPARCMove.LoadInlineConstant(javaConstant, dst); + } else { + return new SPARCMove.LoadConstantFromTable(javaConstant, constantTableBaseProvider.getConstantTableBase(), dst); + } + } else if (src instanceof DataPointerConstant) { + return new SPARCMove.LoadDataAddressOp(dst, (DataPointerConstant) src); + } else { + throw GraalError.shouldNotReachHere(src.getClass().toString()); + } + } + + @Override + public boolean canInlineConstant(JavaConstant c) { + switch (c.getJavaKind()) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + return SPARCAssembler.isSimm13(c.asInt()); + case Long: + return SPARCAssembler.isSimm13(c.asLong()); + case Object: + return c.isNull(); + default: + return false; + } + } + + @Override + public boolean allowConstantToStackMove(Constant value) { + return false; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeLIRBuilder.java 2016-12-07 13:48:11.934037259 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2009, 2015, 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.core.sparc; + +import org.graalvm.compiler.core.gen.NodeLIRBuilder; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.StandardOp.JumpOp; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.sparc.SPARCJumpOp; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; + +/** + * This class implements the SPARC specific portion of the LIR generator. + */ +public abstract class SPARCNodeLIRBuilder extends NodeLIRBuilder { + + public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, SPARCNodeMatchRules nodeMatchRules) { + super(graph, lirGen, nodeMatchRules); + } + + @Override + protected boolean peephole(ValueNode valueNode) { + // No peephole optimizations for now + return false; + } + + @Override + protected JumpOp newJumpOp(LabelRef ref) { + return new SPARCJumpOp(ref); + } + + @Override + public SPARCLIRGenerator getLIRGeneratorTool() { + return (SPARCLIRGenerator) super.getLIRGeneratorTool(); + } + + @Override + protected void emitPrologue(StructuredGraph graph) { + getLIRGeneratorTool().emitLoadConstantTableBase(); + super.emitPrologue(graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java 2016-12-07 13:48:12.199048904 -0800 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2009, 2015, 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.core.sparc; + +import static jdk.vm.ci.sparc.SPARCKind.BYTE; +import static jdk.vm.ci.sparc.SPARCKind.HWORD; +import static jdk.vm.ci.sparc.SPARCKind.WORD; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.gen.NodeMatchRules; +import org.graalvm.compiler.core.match.ComplexMatchResult; +import org.graalvm.compiler.core.match.MatchRule; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.DeoptimizingNode; +import org.graalvm.compiler.nodes.calc.SignExtendNode; +import org.graalvm.compiler.nodes.calc.ZeroExtendNode; +import org.graalvm.compiler.nodes.memory.Access; + +import jdk.vm.ci.sparc.SPARCKind; + +/** + * This class implements the SPARC specific portion of the LIR generator. + */ +public class SPARCNodeMatchRules extends NodeMatchRules { + + public SPARCNodeMatchRules(LIRGeneratorTool gen) { + super(gen); + } + + protected LIRFrameState getState(Access access) { + if (access instanceof DeoptimizingNode) { + return state((DeoptimizingNode) access); + } + return null; + } + + private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + SPARCKind toKind = null; + SPARCKind fromKind = null; + if (fromBits == toBits) { + return null; + } + toKind = toBits > 32 ? XWORD : WORD; + switch (fromBits) { + case 8: + fromKind = BYTE; + break; + case 16: + fromKind = HWORD; + break; + case 32: + fromKind = WORD; + break; + default: + throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + SPARCKind localFromKind = fromKind; + SPARCKind localToKind = toKind; + return builder -> { + return getLIRGeneratorTool().emitSignExtendLoad(LIRKind.value(localFromKind), LIRKind.value(localToKind), operand(access.getAddress()), getState(access)); + }; + } + + private ComplexMatchResult emitZeroExtendMemory(Access access, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + SPARCKind toKind = null; + SPARCKind fromKind = null; + if (fromBits == toBits) { + return null; + } + toKind = toBits > 32 ? XWORD : WORD; + switch (fromBits) { + case 8: + fromKind = BYTE; + break; + case 16: + fromKind = HWORD; + break; + case 32: + fromKind = WORD; + break; + default: + throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + SPARCKind localFromKind = fromKind; + SPARCKind localToKind = toKind; + return builder -> { + // Loads are always zero extending load + return getLIRGeneratorTool().emitZeroExtendLoad(LIRKind.value(localFromKind), LIRKind.value(localToKind), operand(access.getAddress()), getState(access)); + }; + } + + @MatchRule("(SignExtend Read=access)") + @MatchRule("(SignExtend FloatingRead=access)") + public ComplexMatchResult signExtend(SignExtendNode root, Access access) { + return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits()); + } + + @MatchRule("(ZeroExtend Read=access)") + @MatchRule("(ZeroExtend FloatingRead=access)") + public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) { + return emitZeroExtendMemory(access, root.getInputBits(), root.getResultBits()); + } + + @Override + public SPARCLIRGenerator getLIRGeneratorTool() { + return (SPARCLIRGenerator) super.getLIRGeneratorTool(); + } + + protected SPARCArithmeticLIRGenerator getArithmeticLIRGenerator() { + return (SPARCArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCSuitesProvider.java 2016-12-07 13:48:12.464060548 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, 2016, 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.core.sparc; + +import java.util.ListIterator; + +import org.graalvm.compiler.java.DefaultSuitesProvider; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.ExpandLogicPhase; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.phases.tiers.LowTierContext; +import org.graalvm.compiler.phases.tiers.Suites; + +public class SPARCSuitesProvider extends DefaultSuitesProvider { + public SPARCSuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) { + super(compilerConfiguration, plugins); + } + + @Override + public Suites createSuites() { + Suites s = super.createSuites(); + ListIterator> l = s.getLowTier().findPhase(ExpandLogicPhase.class); + while (PhaseSuite.findNextPhase(l, ExpandLogicPhase.class)) { + // Search for last occurrence of ExpandLogicPhase + } + l.previous(); + l.add(new SPARCIntegerCompareCanonicalizationPhase()); + return s; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/overview.html 2016-12-07 13:48:12.728072148 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.tests project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/AllocSpy.java 2016-12-07 13:48:12.992083749 -0800 @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2011, 2014, 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.core.test; + +import static java.lang.Boolean.parseBoolean; +import static java.lang.Integer.getInteger; +import static java.lang.System.getProperty; + +import java.io.PrintStream; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.monitoring.runtime.instrumentation.AllocationRecorder; +import com.google.monitoring.runtime.instrumentation.Sampler; + +/** + * Tool for analyzing allocations within a scope using the + * Java Allocation + * Instrumenter. Allocation records are aggregated per stack trace at an allocation site. The + * size of the stack trace is governed by the value of the "AllocSpy.ContextSize" system property + * (default is 5). + *

+ * Using this facility requires using -javaagent on the command line. For example: + * + *

+ * mx --vm server unittest -javaagent:lib/java-allocation-instrumenter.jar -dsa -DAllocSpy.ContextSize=6 BC_iadd2
+ * 
+ * + * @see #SampleBytes + * @see #SampleInstances + * @see #HistogramLimit + * @see #NameSize + * @see #BarSize + * @see #NumberSize + */ +public final class AllocSpy implements AutoCloseable { + + static ThreadLocal current = new ThreadLocal<>(); + + private static final boolean ENABLED; + + static { + boolean enabled = false; + try { + Field field = AllocationRecorder.class.getDeclaredField("instrumentation"); + field.setAccessible(true); + enabled = field.get(null) != null; + } catch (Exception e) { + } + ENABLED = enabled; + if (ENABLED) { + AllocationRecorder.addSampler(new GraalContextSampler()); + } + } + + public static boolean isEnabled() { + return ENABLED; + } + + static String prop(String sfx) { + return AllocSpy.class.getSimpleName() + "." + sfx; + } + + /** + * Determines if bytes per allocation site are recorded. + */ + private static final boolean SampleBytes = parseBoolean(getProperty(prop("SampleBytes"), "true")); + + /** + * Determines if allocations per allocation site are recorded. + */ + private static final boolean SampleInstances = parseBoolean(getProperty(prop("SampleInstances"), "true")); + + /** + * The size of context to record for each allocation site in terms of Graal frames. + */ + private static final int ContextSize = getInteger(prop("ContextSize"), 5); + + /** + * Only the {@code HistogramLimit} most frequent values are printed. + */ + private static final int HistogramLimit = getInteger(prop("HistogramLimit"), 40); + + /** + * The width of the allocation context column. + */ + private static final int NameSize = getInteger(prop("NameSize"), 50); + + /** + * The width of the histogram bar column. + */ + private static final int BarSize = getInteger(prop("BarSize"), 100); + + /** + * The width of the frequency column. + */ + private static final int NumberSize = getInteger(prop("NumberSize"), 10); + + final Object name; + final AllocSpy parent; + final Map bytesPerGraalContext = new HashMap<>(); + final Map instancesPerGraalContext = new HashMap<>(); + + public static AllocSpy open(Object name) { + if (ENABLED) { + return new AllocSpy(name); + } + return null; + } + + private AllocSpy(Object name) { + this.name = name; + parent = current.get(); + current.set(this); + } + + @Override + public void close() { + current.set(parent); + PrintStream ps = System.out; + ps.println("\n\nAllocation histograms for " + name); + if (SampleBytes) { + print(ps, bytesPerGraalContext, "BytesPerGraalContext", HistogramLimit, NameSize + 60, BarSize); + } + if (SampleInstances) { + print(ps, instancesPerGraalContext, "InstancesPerGraalContext", HistogramLimit, NameSize + 60, BarSize); + } + } + + private static void printLine(PrintStream printStream, char c, int lineSize) { + char[] charArr = new char[lineSize]; + Arrays.fill(charArr, c); + printStream.printf("%s%n", new String(charArr)); + } + + private static void print(PrintStream ps, Map map, String name, int limit, int nameSize, int barSize) { + if (map.isEmpty()) { + return; + } + + List list = new ArrayList<>(map.values()); + Collections.sort(list); + + // Sum up the total number of elements. + int total = 0; + for (CountedValue cv : list) { + total += cv.getCount(); + } + + // Print header. + ps.printf("%s has %d unique elements and %d total elements:%n", name, list.size(), total); + + int max = list.get(0).getCount(); + final int lineSize = nameSize + NumberSize + barSize + 10; + printLine(ps, '-', lineSize); + String formatString = "| %-" + nameSize + "s | %-" + NumberSize + "d | %-" + barSize + "s |\n"; + for (int i = 0; i < list.size() && i < limit; ++i) { + CountedValue cv = list.get(i); + int value = cv.getCount(); + char[] bar = new char[(int) (((double) value / (double) max) * barSize)]; + Arrays.fill(bar, '='); + String[] lines = String.valueOf(cv.getValue()).split("\\n"); + + String objectString = lines[0]; + if (objectString.length() > nameSize) { + objectString = objectString.substring(0, nameSize - 3) + "..."; + } + ps.printf(formatString, objectString, value, new String(bar)); + for (int j = 1; j < lines.length; j++) { + String line = lines[j]; + if (line.length() > nameSize) { + line = line.substring(0, nameSize - 3) + "..."; + } + ps.printf("| %-" + (nameSize - 2) + "s | %-" + NumberSize + "s | %-" + barSize + "s |%n", line, " ", " "); + + } + } + printLine(ps, '-', lineSize); + } + + CountedValue bytesPerGraalContext(String context) { + return getCounter(context, bytesPerGraalContext); + } + + CountedValue instancesPerGraalContext(String context) { + return getCounter(context, instancesPerGraalContext); + } + + protected static CountedValue getCounter(String desc, Map map) { + CountedValue count = map.get(desc); + if (count == null) { + count = new CountedValue(0, desc); + map.put(desc, count); + } + return count; + } + + private static final String[] Excluded = {AllocSpy.class.getName(), AllocationRecorder.class.getName()}; + + private static boolean excludeFrame(String className) { + for (String e : Excluded) { + if (className.startsWith(e)) { + return true; + } + } + return false; + } + + static class GraalContextSampler implements Sampler { + + @Override + public void sampleAllocation(int count, String desc, Object newObj, long size) { + AllocSpy scope = current.get(); + if (scope != null) { + StringBuilder sb = new StringBuilder(200); + Throwable t = new Throwable(); + int remainingGraalFrames = ContextSize; + for (StackTraceElement e : t.getStackTrace()) { + if (remainingGraalFrames < 0) { + break; + } + String className = e.getClassName(); + boolean isGraalFrame = className.contains(".graal."); + if (sb.length() != 0) { + append(sb.append('\n'), e); + } else { + if (!excludeFrame(className)) { + sb.append("type=").append(desc); + if (count != -1) { + sb.append('[').append(count).append(']'); + } + append(sb.append('\n'), e); + } + } + if (isGraalFrame) { + remainingGraalFrames--; + } + } + String context = sb.toString(); + if (SampleBytes) { + scope.bytesPerGraalContext(context).add((int) size); + } + if (SampleInstances) { + scope.instancesPerGraalContext(context).inc(); + } + } + } + + protected StringBuilder append(StringBuilder sb, StackTraceElement e) { + String className = e.getClassName(); + int period = className.lastIndexOf('.'); + if (period != -1) { + sb.append(className, period + 1, className.length()); + } else { + sb.append(className); + } + sb.append('.').append(e.getMethodName()); + if (e.isNativeMethod()) { + sb.append("(Native Method)"); + } else if (e.getFileName() != null && e.getLineNumber() >= 0) { + sb.append('(').append(e.getFileName()).append(':').append(e.getLineNumber()).append(")"); + } else { + sb.append("(Unknown Source)"); + } + return sb; + } + } + + /** + * A value and a frequency. The ordering imposed by {@link #compareTo(CountedValue)} places + * values with higher frequencies first. + */ + static class CountedValue implements Comparable { + + private int count; + private final Object value; + + CountedValue(int count, Object value) { + this.count = count; + this.value = value; + } + + @Override + public int compareTo(CountedValue o) { + if (count < o.count) { + return 1; + } else if (count > o.count) { + return -1; + } + return 0; + } + + @Override + public String toString() { + return count + " -> " + value; + } + + public void inc() { + count++; + } + + public void add(int n) { + count += n; + } + + public int getCount() { + return count; + } + + public Object getValue() { + return value; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java 2016-12-07 13:48:13.258095437 -0800 @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2011, 2014, 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.core.test; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.loop.DefaultLoopPolicies; +import org.graalvm.compiler.loop.phases.LoopPeelingPhase; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; + +/** + * In the following tests, the usages of local variable "a" are replaced with the integer constant + * 0. Then boxing elimination is applied and it is verified that the resulting graph is equal to the + * graph of the method that just has a "return 1" statement in it. + */ +public class BoxingEliminationTest extends GraalCompilerTest { + + private static final Short s = 2; + + @SuppressWarnings("all") + public static short referenceSnippet1() { + return 1; + } + + @SuppressWarnings("all") + public static short referenceSnippet2() { + return 2; + } + + public static Short boxedShort() { + return 1; + } + + public static Object boxedObjectShort() { + return (short) 1; + } + + public static Object boxedObjectInteger() { + return 1; + } + + public static Integer boxedInteger() { + return 2; + } + + public static Short constantBoxedShort() { + return s; + } + + @Test + public void test1() { + compareGraphs("test1Snippet", "referenceSnippet1"); + } + + @SuppressWarnings("all") + public static short test1Snippet() { + return boxedShort(); + } + + @Test + public void test2() { + compareGraphs("test2Snippet", "referenceSnippet1"); + } + + @SuppressWarnings("all") + public static short test2Snippet() { + return (Short) boxedObjectShort(); + } + + @Test + public void test3() { + compareGraphs("test3Snippet", "referenceSnippet1"); + } + + @SuppressWarnings("all") + public static short test3Snippet() { + short b = boxedShort(); + if (b < 0) { + b = boxedShort(); + } + return b; + } + + @Test + public void test4() { + compareGraphs("test4Snippet", "referenceSnippet2"); + } + + @SuppressWarnings("all") + public static short test4Snippet() { + return constantBoxedShort(); + } + + @Ignore + @Test + public void testLoop() { + compareGraphs("testLoopSnippet", "referenceLoopSnippet", false, true); + } + + public static int testLoopSnippet(int n, int a) { + Integer sum = a; + for (Integer i = 0; i < n; i++) { + sum += i; + } + return sum; + } + + public static int referenceLoopSnippet(int n, int a) { + int sum = a; + for (int i = 0; i < n; i++) { + sum += i; + } + return sum; + } + + @Test + public void testLoop2() { + compareGraphs("testLoop2Snippet", "referenceLoop2Snippet", true, true); + } + + public static int testLoop2Snippet(int n, Integer a) { + Integer sum = a; + for (Integer i = 0; i < n; i++) { + sum += i; + } + return sum; + } + + public static int referenceLoop2Snippet(int n, Integer a) { + Integer sum0; + if (n <= 0) { + sum0 = a; + } else { + int sum = a; + for (int i = 0; i < n; i++) { + sum += i; + } + sum0 = sum; + } + return sum0; + } + + public static int referenceIfSnippet(int a) { + int result; + if (a < 0) { + result = 2; + } else { + result = 1; + } + return result; + } + + @Test + public void testIf() { + compareGraphs("testIfSnippet", "referenceIfSnippet"); + } + + public static int testIfSnippet(int a) { + Integer result; + if (a < 0) { + result = boxedInteger(); + } else { + result = (Integer) boxedObjectInteger(); + } + return result; + } + + @Test + public void testComparison() { + compareGraphs("testComparison1Snippet", "referenceComparisonSnippet"); + compareGraphs("testComparison2Snippet", "referenceComparisonSnippet"); + } + + @SuppressWarnings("cast") + public static boolean testComparison1Snippet(int a, int b) { + return ((Integer) a) == b; + } + + public static boolean testComparison2Snippet(int a, int b) { + Integer x = a; + Integer y = b; + return x == y; + } + + public static boolean referenceComparisonSnippet(int a, int b) { + return a == b; + } + + @Test + public void testLateCanonicalization() { + compareGraphs("testLateCanonicalizationSnippet", "referenceLateCanonicalizationSnippet"); + } + + public static boolean testLateCanonicalizationSnippet(int a) { + Integer x = a; + Integer y = 1000; + return x == y; + } + + public static boolean referenceLateCanonicalizationSnippet(int a) { + return a == 1000; + } + + private StructuredGraph graph; + + public static Integer materializeReferenceSnippet(int a) { + return Integer.valueOf(a); + } + + public static Integer materializeTest1Snippet(int a) { + Integer v = a; + + if (v == a) { + return v; + } else { + return null; + } + } + + @Test + public void materializeTest1() { + test("materializeTest1Snippet", 1); + } + + public static int intTest1Snippet() { + return Integer.valueOf(1); + } + + @Test + public void intTest1() { + ValueNode result = getResult("intTest1Snippet"); + Assert.assertTrue(result.isConstant()); + Assert.assertEquals(1, result.asJavaConstant().asInt()); + } + + public static int mergeTest1Snippet(boolean d, int a, int b) { + Integer v; + if (d) { + v = a; + } else { + v = b; + } + return v; + } + + @Test + public void mergeTest1() { + processMethod("mergeTest1Snippet"); + } + + public static boolean equalsTest1Snippet(int x, int y) { + Integer a = x; + Integer b = y; + return a == b; + } + + @Test + public void equalsTest1() { + processMethod("equalsTest1Snippet"); + } + + public static int loopTest1Snippet(int n, int v) { + Integer sum = 0; + for (int i = 0; i < n; i++) { + sum += v; + } + return sum; + } + + @Test + public void loopTest1() { + processMethod("loopTest1Snippet"); + + } + + final ValueNode getResult(String snippet) { + processMethod(snippet); + assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count()); + return graph.getNodes(ReturnNode.TYPE).first().result(); + } + + private void processMethod(final String snippet) { + graph = parseEager(snippet, AllowAssumptions.NO); + HighTierContext context = getDefaultHighTierContext(); + new InliningPhase(new CanonicalizerPhase()).apply(graph, context); + new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context); + } + + private void compareGraphs(final String snippet, final String referenceSnippet) { + compareGraphs(snippet, referenceSnippet, false, false); + } + + private void compareGraphs(final String snippet, final String referenceSnippet, final boolean loopPeeling, final boolean excludeVirtual) { + graph = parseEager(snippet, AllowAssumptions.NO); + HighTierContext context = getDefaultHighTierContext(); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + canonicalizer.apply(graph, context); + new InliningPhase(new CanonicalizerPhase()).apply(graph, context); + if (loopPeeling) { + new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph, context); + } + new DeadCodeEliminationPhase().apply(graph); + canonicalizer.apply(graph, context); + new PartialEscapePhase(false, canonicalizer).apply(graph, context); + + new DeadCodeEliminationPhase().apply(graph); + canonicalizer.apply(graph, context); + + StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.YES); + new InliningPhase(new CanonicalizerPhase()).apply(referenceGraph, context); + new DeadCodeEliminationPhase().apply(referenceGraph); + new CanonicalizerPhase().apply(referenceGraph, context); + + assertEquals(referenceGraph, graph, excludeVirtual, true); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingTest.java 2016-12-07 13:48:13.524107126 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Test; + +public class BoxingTest extends GraalCompilerTest { + + public static Object boxSnippet(int arg) { + return arg; + } + + @Test + public void test0() { + test("boxSnippet", 0); + } + + @Test + public void test5() { + test("boxSnippet", 5); + } + + @Test + public void testMinus5() { + test("boxSnippet", -5); + } + + @Test + public void test300() { + test("boxSnippet", 300); + } + + @Test + public void testMinus300() { + test("boxSnippet", -300); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java 2016-12-07 13:48:13.789118770 -0800 @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2014, 2016, 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.core.test; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; +import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.INTERCEPT; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.bytecode.BridgeMethodUtils; +import org.graalvm.compiler.core.CompilerThreadFactory; +import org.graalvm.compiler.core.CompilerThreadFactory.DebugConfigAccess; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugConfigScope; +import org.graalvm.compiler.debug.DebugEnvironment; +import org.graalvm.compiler.debug.DelegatingDebugConfig; +import org.graalvm.compiler.debug.GraalDebugConfig; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.VerifyPhase; +import org.graalvm.compiler.phases.VerifyPhase.VerificationError; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.phases.verify.VerifyBailoutUsage; +import org.graalvm.compiler.phases.verify.VerifyCallerSensitiveMethods; +import org.graalvm.compiler.phases.verify.VerifyDebugUsage; +import org.graalvm.compiler.phases.verify.VerifyUpdateUsages; +import org.graalvm.compiler.phases.verify.VerifyUsageWithEquals; +import org.graalvm.compiler.phases.verify.VerifyVirtualizableUsage; +import org.graalvm.compiler.runtime.RuntimeProvider; +import org.graalvm.compiler.test.GraalTest; + +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.Register.RegisterCategory; +import jdk.vm.ci.meta.JavaField; +import jdk.vm.ci.meta.JavaMethod; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Value; + +/** + * Checks that all classes in *graal*.jar and *jvmci*.jar entries on the boot class path comply with + * global invariants such as using {@link Object#equals(Object)} to compare certain types instead of + * identity comparisons. + */ +public class CheckGraalInvariants extends GraalTest { + + private static boolean shouldVerifyEquals(ResolvedJavaMethod m) { + if (m.getName().equals("identityEquals")) { + ResolvedJavaType c = m.getDeclaringClass(); + if (c.getName().equals("Ljdk/vm/ci/meta/AbstractValue;") || c.getName().equals("jdk/vm/ci/meta/Value")) { + return false; + } + } + + return true; + } + + private static boolean shouldProcess(String classpathEntry) { + if (classpathEntry.endsWith(".jar")) { + String name = new File(classpathEntry).getName(); + return name.contains("jvmci") || name.contains("graal"); + } + return false; + } + + @Test + @SuppressWarnings("try") + public void test() { + RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class); + Providers providers = rt.getHostBackend().getProviders(); + MetaAccessProvider metaAccess = providers.getMetaAccess(); + + PhaseSuite graphBuilderSuite = new PhaseSuite<>(); + Plugins plugins = new Plugins(new InvocationPlugins(metaAccess)); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); + + Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus()); + + String propertyName = Java8OrEarlier ? "sun.boot.class.path" : "jdk.module.path"; + String bootclasspath = System.getProperty(propertyName); + Assert.assertNotNull("Cannot find value of " + propertyName, bootclasspath); + + final List classNames = new ArrayList<>(); + for (String path : bootclasspath.split(File.pathSeparator)) { + if (shouldProcess(path)) { + try { + final ZipFile zipFile = new ZipFile(new File(path)); + for (final Enumeration entry = zipFile.entries(); entry.hasMoreElements();) { + final ZipEntry zipEntry = entry.nextElement(); + String name = zipEntry.getName(); + if (name.endsWith(".class")) { + String className = name.substring(0, name.length() - ".class".length()).replace('/', '.'); + classNames.add(className); + } + } + } catch (IOException ex) { + Assert.fail(ex.toString()); + } + } + } + Assert.assertFalse("Could not find graal jars on boot class path: " + bootclasspath, classNames.isEmpty()); + + // Allows a subset of methods to be checked through use of a system property + String property = System.getProperty(CheckGraalInvariants.class.getName() + ".filters"); + String[] filters = property == null ? null : property.split(","); + + CompilerThreadFactory factory = new CompilerThreadFactory("CheckInvariantsThread", new DebugConfigAccess() { + @Override + public GraalDebugConfig getDebugConfig() { + return DebugEnvironment.initialize(System.out); + } + }); + int availableProcessors = Runtime.getRuntime().availableProcessors(); + ThreadPoolExecutor executor = new ThreadPoolExecutor(availableProcessors, availableProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), factory); + + List errors = Collections.synchronizedList(new ArrayList<>()); + // Order outer classes before the inner classes + classNames.sort((String a, String b) -> a.compareTo(b)); + // Initialize classes in single thread to avoid deadlocking issues during initialization + List> classes = initializeClasses(classNames); + for (Class c : classes) { + String className = c.getName(); + executor.execute(() -> { + try { + checkClass(c, metaAccess); + } catch (Throwable e) { + errors.add(String.format("Error while checking %s:%n%s", className, printStackTraceToString(e))); + } + }); + + for (Method m : c.getDeclaredMethods()) { + if (Modifier.isNative(m.getModifiers()) || Modifier.isAbstract(m.getModifiers())) { + // ignore + } else { + String methodName = className + "." + m.getName(); + if (matches(filters, methodName)) { + executor.execute(() -> { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID); + try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("CheckingGraph", graph, method)) { + graphBuilderSuite.apply(graph, context); + // update phi stamps + graph.getNodes().filter(PhiNode.class).forEach(PhiNode::inferStamp); + checkGraph(context, graph); + } catch (VerificationError e) { + errors.add(e.getMessage()); + } catch (LinkageError e) { + // suppress linkages errors resulting from eager resolution + } catch (BailoutException e) { + // Graal bail outs on certain patterns in Java bytecode (e.g., + // unbalanced monitors introduced by jacoco). + } catch (Throwable e) { + errors.add(String.format("Error while checking %s:%n%s", methodName, printStackTraceToString(e))); + } + }); + } + } + } + } + executor.shutdown(); + try { + executor.awaitTermination(1, TimeUnit.HOURS); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + + if (!errors.isEmpty()) { + StringBuilder msg = new StringBuilder(); + String nl = String.format("%n"); + for (String e : errors) { + if (msg.length() != 0) { + msg.append(nl); + } + msg.append(e); + } + Assert.fail(msg.toString()); + } + } + + private static List> initializeClasses(List classNames) { + List> classes = new ArrayList<>(classNames.size()); + for (String className : classNames) { + if (className.equals("module-info")) { + continue; + } + try { + Class c = Class.forName(className, true, CheckGraalInvariants.class.getClassLoader()); + classes.add(c); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + return classes; + } + + /** + * @param metaAccess + */ + private static void checkClass(Class c, MetaAccessProvider metaAccess) { + if (Node.class.isAssignableFrom(c)) { + if (c.getAnnotation(NodeInfo.class) == null) { + throw new AssertionError(String.format("Node subclass %s requires %s annotation", c.getName(), NodeClass.class.getSimpleName())); + } + } + } + + /** + * Checks the invariants for a single graph. + */ + private static void checkGraph(HighTierContext context, StructuredGraph graph) { + if (shouldVerifyEquals(graph.method())) { + new VerifyUsageWithEquals(Value.class).apply(graph, context); + new VerifyUsageWithEquals(Register.class).apply(graph, context); + new VerifyUsageWithEquals(RegisterCategory.class).apply(graph, context); + new VerifyUsageWithEquals(JavaType.class).apply(graph, context); + new VerifyUsageWithEquals(JavaMethod.class).apply(graph, context); + new VerifyUsageWithEquals(JavaField.class).apply(graph, context); + new VerifyUsageWithEquals(LocationIdentity.class).apply(graph, context); + new VerifyUsageWithEquals(LIRKind.class).apply(graph, context); + new VerifyUsageWithEquals(ArithmeticOpTable.class).apply(graph, context); + new VerifyUsageWithEquals(ArithmeticOpTable.Op.class).apply(graph, context); + } + new VerifyDebugUsage().apply(graph, context); + new VerifyCallerSensitiveMethods().apply(graph, context); + new VerifyVirtualizableUsage().apply(graph, context); + new VerifyUpdateUsages().apply(graph, context); + new VerifyBailoutUsage().apply(graph, context); + if (graph.method().isBridge()) { + BridgeMethodUtils.getBridgedMethod(graph.method()); + } + } + + private static boolean matches(String[] filters, String s) { + if (filters == null || filters.length == 0) { + return true; + } + for (String filter : filters) { + if (s.contains(filter)) { + return true; + } + } + return false; + } + + private static String printStackTraceToString(Throwable t) { + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + return sw.toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CommonedConstantsTest.java 2016-12-07 13:48:14.054130414 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2012, 2012, 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.core.test; + +import java.lang.reflect.Array; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Test; + +import org.graalvm.compiler.phases.common.AbstractInliningPhase; + +/** + * Tests any optimization that commons loads of non-inlineable constants. + */ +public class CommonedConstantsTest extends GraalCompilerTest { + + public static final String[] array = {"1", "2", null}; + + // A method where a constant is used on the normal and exception edge of a non-inlined call. + // The dominating block of both usages is the block containing the call. + public static Object test0Snippet(String[] arr, int i) { + Object result = null; + try { + result = Array.get(arr, i); + } catch (ArrayIndexOutOfBoundsException e) { + result = array[0]; + } + if (result == null) { + result = array[2]; + } + return result; + } + + @Test + public void test0() { + // Ensure the exception path is profiled + ResolvedJavaMethod javaMethod = getResolvedJavaMethod("test0Snippet"); + javaMethod.reprofile(); + test0Snippet(array, array.length); + + test("test0Snippet", array, 0); + test("test0Snippet", array, 2); + test("test0Snippet", array, 3); + test("test0Snippet", array, 1); + } + + public static final char[] alphabet = "abcdefghijklmnopqrstuvwxyz".toCharArray(); + + static int noninlineLength(char[] s) { + return s.length; + } + + /** + * A constant with usages before and after a non-inlined call. + */ + public static int test1Snippet(String s) { + if (s == null) { + return noninlineLength(alphabet) + 1; + } + char[] sChars = s.toCharArray(); + int count = 0; + for (int i = 0; i < alphabet.length && i < sChars.length; i++) { + if (alphabet[i] == sChars[i]) { + count++; + } + } + return count; + } + + @Test + public void test1() { + getSuites().getHighTier().findPhase(AbstractInliningPhase.class).remove(); + test1Snippet(new String(alphabet)); + + test("test1Snippet", (Object) null); + test("test1Snippet", "test1Snippet"); + test("test1Snippet", ""); + } + + /** + * A constant with only usage in a loop. + */ + public static int test2Snippet(String s) { + char[] sChars = s.toCharArray(); + int count = 0; + for (int i = 0; i < alphabet.length && i < sChars.length; i++) { + if (alphabet[i] == sChars[i]) { + count++; + } + } + return count; + } + + @Test + public void test2() { + assert getSuites().getHighTier().findPhase(AbstractInliningPhase.class).hasNext(); + test2Snippet(new String(alphabet)); + + test("test2Snippet", (Object) null); + test("test2Snippet", "test1Snippet"); + test("test2Snippet", ""); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest.java 2016-12-07 13:48:14.320142103 -0800 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2012, 2014, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.ConditionalNode; +import org.graalvm.compiler.nodes.calc.IntegerTestNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class CompareCanonicalizerTest extends GraalCompilerTest { + + private StructuredGraph getCanonicalizedGraph(String name) { + StructuredGraph graph = parseEager(name, AllowAssumptions.YES); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + return graph; + } + + private static ValueNode getResult(StructuredGraph graph) { + assertTrue(graph.start().next() instanceof ReturnNode); + ReturnNode ret = (ReturnNode) graph.start().next(); + return ret.result(); + } + + @Test + public void testCanonicalComparison() { + StructuredGraph referenceGraph = parseEager("referenceCanonicalComparison", AllowAssumptions.NO); + for (int i = 1; i < 4; i++) { + StructuredGraph graph = parseEager("canonicalCompare" + i, AllowAssumptions.NO); + assertEquals(referenceGraph, graph); + } + new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders())); + for (int i = 1; i < 4; i++) { + StructuredGraph graph = getCanonicalizedGraph("canonicalCompare" + i); + assertEquals(referenceGraph, graph); + } + } + + public static int referenceCanonicalComparison(int a, int b) { + if (a < b) { + return 1; + } else { + return 2; + } + } + + public static int canonicalCompare1(int a, int b) { + if (a >= b) { + return 2; + } else { + return 1; + } + } + + public static int canonicalCompare2(int a, int b) { + if (b > a) { + return 1; + } else { + return 2; + } + } + + public static int canonicalCompare3(int a, int b) { + if (b <= a) { + return 2; + } else { + return 1; + } + } + + @Test + public void testIntegerTest() { + for (int i = 1; i <= 4; i++) { + StructuredGraph graph = getCanonicalizedGraph("integerTest" + i); + + ReturnNode returnNode = (ReturnNode) graph.start().next(); + ConditionalNode conditional = (ConditionalNode) returnNode.result(); + IntegerTestNode test = (IntegerTestNode) conditional.condition(); + ParameterNode param0 = graph.getParameter(0); + ParameterNode param1 = graph.getParameter(1); + assertTrue((test.getX() == param0 && test.getY() == param1) || (test.getX() == param1 && test.getY() == param0)); + } + } + + public static boolean integerTest1(int x, int y) { + return (x & y) == 0; + } + + public static boolean integerTest2(long x, long y) { + return 0 == (x & y); + } + + public static boolean integerTest3(long x, long y) { + int c = 5; + return (c - 5) == (x & y); + } + + public static boolean integerTest4(int x, int y) { + int c = 10; + return (x & y) == (10 - c); + } + + @Test + public void testIntegerTestCanonicalization() { + ValueNode result = getResult(getCanonicalizedGraph("integerTestCanonicalization1")); + assertTrue(result.isConstant() && result.asJavaConstant().asLong() == 1); + result = getResult(getCanonicalizedGraph("integerTestCanonicalization2")); + assertTrue(result.isConstant() && result.asJavaConstant().asLong() == 1); + StructuredGraph graph = getCanonicalizedGraph("integerTestCanonicalization3"); + assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count()); + assertTrue(graph.getNodes(ReturnNode.TYPE).first().result() instanceof ConditionalNode); + } + + public static int integerTestCanonicalization1(boolean b) { + int x = b ? 128 : 256; + if ((x & 8) == 0) { + return 1; + } else { + return 2; + } + } + + public static int integerTestCanonicalization2(boolean b) { + int x = b ? 128 : 256; + int y = b ? 32 : 64; + if ((x & y) == 0) { + return 1; + } else { + return 2; + } + } + + public static int integerTestCanonicalization3(boolean b) { + int x = b ? 128 : 64; + int y = b ? 32 : 64; + if ((x & y) == 0) { + return 1; + } else { + return 2; + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConcreteSubtypeTest.java 2016-12-07 13:48:14.585153747 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, 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.core.test; + +import jdk.vm.ci.meta.Assumptions.Assumption; +import jdk.vm.ci.meta.Assumptions.ConcreteSubtype; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.StructuredGraph; + +/** + * Ensure that abstract classes with a single implementor are properly optimized and that loading a + * subclass below the leaf type triggers invalidation. + */ +public class ConcreteSubtypeTest extends GraalCompilerAssumptionsTest { + abstract static class AbstractBase { + abstract void check(); + } + + static class Subclass extends AbstractBase { + @Override + public void check() { + throw new InternalError(); + } + } + + static class SubSubclass extends Subclass { + @Override + public void check() { + } + } + + public void callAbstractType(AbstractBase object) { + object.check(); + } + + @Override + protected void checkGraph(Assumption expectedAssumption, StructuredGraph graph) { + super.checkGraph(expectedAssumption, graph); + assertTrue(graph.isTrivial()); + } + + /** + * Test that {@link #callAbstractType} gets compiled into an empty method with a + * {@link ConcreteSubtype} assumption on {@link AbstractBase} and {@link Subclass}. Then ensures + * that loading and initialization of {@link SubSubclass} causes the compiled method to be + * invalidated. + */ + @Test + public void testLeafAbstractType() { + testAssumptionInvalidate("callAbstractType", new ConcreteSubtype(resolveAndInitialize(AbstractBase.class), resolveAndInitialize(Subclass.class)), "SubSubclass"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionTest.java 2016-12-07 13:48:14.849165348 -0800 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2012, 2014, 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.core.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Random; + +import jdk.vm.ci.meta.JavaConstant; + +import org.junit.Test; + +import org.graalvm.compiler.core.common.calc.Condition; + +public class ConditionTest { + + @Test + public void testImplies() { + Random rand = new Random(13); + for (Condition c1 : Condition.values()) { + for (Condition c2 : Condition.values()) { + boolean implies = c1.implies(c2); + if (implies) { + for (int i = 0; i < 1000; i++) { + JavaConstant a = JavaConstant.forInt(rand.nextInt()); + JavaConstant b = JavaConstant.forInt(i < 100 ? a.asInt() : rand.nextInt()); + boolean result1 = c1.foldCondition(a, b, null, false); + boolean result2 = c2.foldCondition(a, b, null, false); + if (result1) { + assertTrue(result2); + } + } + } + } + } + } + + @Test + public void testJoin() { + Random rand = new Random(13); + for (Condition c1 : Condition.values()) { + for (Condition c2 : Condition.values()) { + Condition join = c1.join(c2); + assertEquals(join, c2.join(c1)); + if (join != null) { + for (int i = 0; i < 1000; i++) { + JavaConstant a = JavaConstant.forInt(rand.nextInt()); + JavaConstant b = JavaConstant.forInt(i < 100 ? a.asInt() : rand.nextInt()); + boolean result1 = c1.foldCondition(a, b, null, false); + boolean result2 = c2.foldCondition(a, b, null, false); + boolean resultJoin = join.foldCondition(a, b, null, false); + if (result1 && result2) { + assertTrue(resultJoin); + } else { + assertFalse(resultJoin); + } + } + } + } + } + } + + @Test + public void testMeet() { + Random rand = new Random(13); + for (Condition c1 : Condition.values()) { + for (Condition c2 : Condition.values()) { + Condition meet = c1.meet(c2); + assertEquals(meet, c2.meet(c1)); + if (meet != null) { + for (int i = 0; i < 1000; i++) { + JavaConstant a = JavaConstant.forInt(rand.nextInt()); + JavaConstant b = JavaConstant.forInt(i < 100 ? a.asInt() : rand.nextInt()); + boolean result1 = c1.foldCondition(a, b, null, false); + boolean result2 = c2.foldCondition(a, b, null, false); + boolean resultMeet = meet.foldCondition(a, b, null, false); + if (result1 || result2) { + assertTrue(resultMeet); + } else { + assertFalse(resultMeet); + } + } + } + } + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationLoadFieldConstantFoldTest.java 2016-12-07 13:48:15.114176992 -0800 @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import java.lang.reflect.Field; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase; +import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase; + +import sun.misc.Unsafe; + +public class ConditionalEliminationLoadFieldConstantFoldTest extends GraalCompilerTest { + public static int intSideEffect; + + public static final B FinalField = new B(10); + + private abstract static class A { + + } + + private static class B extends A { + final int a; + + B(int a) { + this.a = a; + } + } + + private static class C extends A { + final B b; + + C(B b) { + this.b = b; + } + } + + private static class D extends A { + final C c; + + D(C c) { + this.c = c; + } + } + + private static class E extends D { + final Object o; + + E(C c, Object o) { + super(c); + this.o = o; + } + } + + public static final B CONST_B = new B(10); + public static final C CONST_C = new C(CONST_B); + public static final D CONST_D = new D(CONST_C); + + public int testReadConstInBranch(B b) { + if (b == CONST_B) { + if (b.a == 5) { + intSideEffect = b.a; + } else { + intSideEffect = 10; + } + } + return 0; + } + + public int testMultipleReadsConstInBranch(D d) { + if (d == CONST_D) { + C c = d.c; + B b = c.b; + int res = b.a + 12; + if (res == 125) { + intSideEffect = 12; + } + } + return 0; + } + + public int testLoadFinalInstanceOf(E e) { + Object o = e.o; + if (o == CONST_C) { + if (o instanceof A) { + // eliminate, implied by a.x == Const(Subclass) + intSideEffect = 1; + } else { + intSideEffect = 10; + } + } + return 0; + } + + public int testLoadFinalTwiceInstanceOf(E e) { + if (e.o == CONST_C) { + if (e.o instanceof A) { + intSideEffect = 1; + } else { + intSideEffect = 10; + } + } + return 0; + } + + static class C1 { + final int a; + + C1(int a) { + this.a = a; + } + } + + static class C2 { + final C1 c1; + + C2(C1 c1) { + this.c1 = c1; + } + } + + public static int foldThatIsNotAllowed(C2 c2) { + // read before, this will be used to load through when folding + C1 c1Unknown = c2.c1; + + // be naughty (will be a store field after canonicalization as it has a constant offset, so + // we would be able to eliminate the inner if after an early read elimination but we would + // fold before and ce the inner if already) + // + // note: if the offset would not be constant but a parameter we would not even be able to + // remove in inner most if as we cannot rewrite the unsafe store to a store field node as + // the store might kill ANY_LOCATION + UNSAFE.putObject(c2, C2_C1_OFFSET, C1_AFTER_READ_CONST); + + if (c2 == C2_CONST) { + if (c1Unknown == C1_CONST) { + /* + * This if can be eliminated (as we rewrite the unsafe store with a constant offset + * to a store field node) but the remaining branch must be the false branch. If we + * do not fold through both field loads we will canonicalize the unsafe store to a + * store field, see the new value and can thus eliminate the true branch + * + * if we fold through the load fields we would load from the object read before the + * store so we miss the unsafe update + */ + if (c2.c1.a == 10) { + intSideEffect = 1; + return 1; + } else { + intSideEffect = 2; + return 2; + } + } else { + intSideEffect = -2; + return -2; + } + } else { + intSideEffect = -1; + return -1; + } + } + + public int testLoadFinalTwiceNoReadEliminationInstanceOf(E e) { + if (e.o == CONST_C) { + /* + * we cannot eliminate the second read of e.o although it is a final field. the call to + * System.gc (or any other memory checkpoint killing ANY_LOCATION) will prohibit the + * elimination of the second load, thus we have two different load nodes, we know that + * that first load field is a constant but we do not know for the second one, assuming + * e.o is final, as it might have been written in between + * + * this prohibits us to remove the if (fold through all loads to final fields) and the + * instance of e.o + */ + System.gc(); + C c = (C) e.o; + if (c.b.a == 10) { + intSideEffect = 1; + } else { + intSideEffect = 10; + } + } + return 0; + + } + + private static final C1 C1_CONST = new C1(0); + private static final C2 C2_CONST = new C2(C1_CONST); + private static final C1 C1_AFTER_READ_CONST = new C1(10); + + private static Unsafe getUnsafe() { + try { + return Unsafe.getUnsafe(); + } catch (SecurityException e) { + } + try { + Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeInstance.setAccessible(true); + return (Unsafe) theUnsafeInstance.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); + } + } + + private static final sun.misc.Unsafe UNSAFE = getUnsafe(); + private static final long C2_C1_OFFSET; + + static { + try { + Field f = C2.class.getDeclaredField("c1"); + C2_C1_OFFSET = UNSAFE.objectFieldOffset(f); + } catch (NoSuchFieldException | SecurityException e) { + throw new RuntimeException(e); + } + } + + @Test + public void test01() { + checkGraph("testReadConstInBranch", 1); + test("testReadConstInBranch", new B(1)); + } + + @Test + public void test02() { + checkGraph("testMultipleReadsConstInBranch", 1); + } + + @Test + public void test03() { + checkGraph("testLoadFinalInstanceOf", 1); + } + + @Test + public void test04() { + checkGraph("testLoadFinalTwiceInstanceOf", 1); + } + + @Test + public void test05() { + checkGraph("testLoadFinalTwiceNoReadEliminationInstanceOf", 2); + } + + @Test(expected = AssertionError.class) + @SuppressWarnings("try") + public void test06() { + Result actual = executeActual(getResolvedJavaMethod("foldThatIsNotAllowed"), null, C2_CONST); + UNSAFE.putObject(C2_CONST, C2_C1_OFFSET, C1_CONST); + Result expected = executeExpected(getResolvedJavaMethod("foldThatIsNotAllowed"), null, C2_CONST); + Assert.assertEquals(expected.returnValue, actual.returnValue); + } + + @SuppressWarnings("try") + private StructuredGraph checkGraph(String name, int nrOfIfsAfter) { + StructuredGraph g = parseForCompile(getResolvedJavaMethod(name)); + CanonicalizerPhase c = new CanonicalizerPhase(); + c.apply(g, getDefaultHighTierContext()); + new EarlyReadEliminationPhase(c).apply(g, getDefaultHighTierContext()); + new IterativeConditionalEliminationPhase(c, false).apply(g, getDefaultHighTierContext()); + Assert.assertEquals("Nr of Ifs left does not match", nrOfIfsAfter, g.getNodes().filter(IfNode.class).count()); + c.apply(g, getDefaultHighTierContext()); + return g; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java 2016-12-07 13:48:15.379188637 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +public class ConditionalEliminationMulTest extends GraalCompilerTest { + + public static void snippet01(int a) { + if (a == 2) { + if (a * 3 != 6) { + shouldBeOptimizedAway(); + } + } + } + + public static void snippet02(int a) { + if (a == 0) { + if (a * 3 != 0) { + shouldBeOptimizedAway(); + } + } + } + + public static void snippet03(int a) { + if (a * 0 == 6) { + shouldBeOptimizedAway(); + } + } + + @Test + public void testConditionalEliminated01() { + assertOptimized("snippet01"); + } + + @Test + public void testConditionalEliminated02() { + assertOptimized("snippet02"); + } + + @Test + public void testConditionalEliminated03() { + assertOptimized("snippet03"); + } + + private void assertOptimized(String snippet) { + assertOptimizedAway(prepareGraph(snippet)); + } + + private StructuredGraph prepareGraph(String snippet) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + HighTierContext context = getDefaultHighTierContext(); + CanonicalizerPhase c = new CanonicalizerPhase(); + c.apply(graph, context); + new DominatorConditionalEliminationPhase(false).apply(graph, context); + c.apply(graph, context); + return graph; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java 2016-12-07 13:48:15.645200325 -0800 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; + +/** + * Collection of tests for + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those + * that triggered bugs in this phase. + */ +public class ConditionalEliminationTest1 extends ConditionalEliminationTestBase { + + private static final String REFERENCE_SNIPPET = "referenceSnippet"; + + @SuppressWarnings("all") + public static int referenceSnippet(int a) { + if (a == 0) { + return 1; + } + return 0; + } + + @Test + public void test1() { + testConditionalElimination("test1Snippet", REFERENCE_SNIPPET); + } + + @SuppressWarnings("all") + public static int test1Snippet(int a) { + if (a == 0) { + if (a == 5) { + return 100; + } + if (a > 100) { + if (a == 0) { + return 200; + } + } + if (a != 2) { + return 1; + } + } + return 0; + } + + @Test + public void test2() { + testConditionalElimination("test2Snippet", REFERENCE_SNIPPET); + } + + @SuppressWarnings("all") + public static int test2Snippet(int a) { + if (a == 0) { + if (a > 100) { + if (a == 0) { + return 200; + } + } + if (a != 2) { + return 1; + } + } + return 0; + } + + @Test + public void test3() { + testConditionalElimination("test3Snippet", REFERENCE_SNIPPET); + } + + @SuppressWarnings("all") + public static int test3Snippet(int a) { + if (a == 0) { + if (a < 1) { + if (a < 2) { + if (a < 3) { + if (a > -1) { + if (a > -2) { + if (a > -3) { + if (a == 1) { + return 42; + } else { + return 1; + } + } + } + } + } + } + } + } + return 0; + } + + @SuppressWarnings("all") + public static int test4Snippet(int a, int b) { + if (b < 1) { + GraalDirectives.controlFlowAnchor(); + if (b < 0) { + return 1; + } + } + return 0; + } + + @Test + public void test4() { + testConditionalElimination("test4Snippet", "test4Snippet"); + } + + @SuppressWarnings("all") + public static int test5Snippet(int a, int b) { + if ((b & 3) == 0) { + GraalDirectives.controlFlowAnchor(); + if ((b & 7) == 0) { + GraalDirectives.controlFlowAnchor(); + return 1; + } + } else { + GraalDirectives.controlFlowAnchor(); + if ((b & 1) == 0) { + GraalDirectives.controlFlowAnchor(); + return 2; + } + } + return 0; + } + + @Test + public void test5() { + testConditionalElimination("test5Snippet", "test5Snippet"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java 2016-12-07 13:48:15.908211882 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.nodes.GuardNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/** + * This test checks the combined action of + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} and + * {@link org.graalvm.compiler.phases.common.LoweringPhase}. The lowering phase needs to introduce + * the null checks at the correct places for the dominator conditional elimination phase to pick + * them up. + */ +public class ConditionalEliminationTest10 extends ConditionalEliminationTestBase { + + private static class TestClass { + int x; + } + + @SuppressWarnings("all") + public static int testSnippet(int a, TestClass t) { + int result = 0; + if (a == 0) { + GraalDirectives.controlFlowAnchor(); + result = t.x; + } + GraalDirectives.controlFlowAnchor(); + return result + t.x; + } + + @Test + public void test1() { + StructuredGraph graph = parseEager("testSnippet", AllowAssumptions.YES); + PhaseContext context = new PhaseContext(getProviders()); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + Assert.assertEquals(2, graph.getNodes().filter(GuardNode.class).count()); + new DominatorConditionalEliminationPhase(true).apply(graph, context); + Assert.assertEquals(1, graph.getNodes().filter(GuardNode.class).count()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java 2016-12-07 13:48:16.172223482 -0800 @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2015, 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.core.test; + +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; + +/** + * Collection of tests for + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those + * that triggered bugs in this phase. + */ +public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase { + public ConditionalEliminationTest11() { + // Don't disable simplification + super(false); + } + + @SuppressWarnings("all") + public static int referenceSnippet(int a) { + if ((a & 15) != 15) { + GraalDirectives.deoptimize(); + } + return 0; + } + + @Test + public void test1() { + testConditionalElimination("test1Snippet", "referenceSnippet"); + } + + @SuppressWarnings("all") + public static int test1Snippet(int a) { + if ((a & 8) != 8) { + GraalDirectives.deoptimize(); + } + if ((a & 15) != 15) { + GraalDirectives.deoptimize(); + } + return 0; + } + + @SuppressWarnings("all") + public static int test2Snippet(int a) { + if ((a & 8) == 0) { + GraalDirectives.deoptimize(); + } + if ((a & 15) != 15) { + GraalDirectives.deoptimize(); + } + return 0; + } + + @Test + public void test2() { + testConditionalElimination("test2Snippet", "referenceSnippet"); + } + + @SuppressWarnings("all") + public static int test3Snippet(int a) { + if ((a & 15) != 15) { + GraalDirectives.deoptimize(); + } + if ((a & 8) != 8) { + GraalDirectives.deoptimize(); + } + return 0; + } + + @Test + public void test3() { + // Test forward elimination of bitwise tests + testConditionalElimination("test3Snippet", "referenceSnippet"); + } + + @SuppressWarnings("all") + public static int test4Snippet(int a) { + if ((a & 15) != 15) { + GraalDirectives.deoptimize(); + } + if ((a & 8) == 0) { + GraalDirectives.deoptimize(); + } + return 0; + } + + @Test + public void test4() { + // Test forward elimination of bitwise tests + testConditionalElimination("test4Snippet", "referenceSnippet"); + } + + public static int test5Snippet(int a) { + if ((a & 5) == 5) { + GraalDirectives.deoptimize(); + } + if ((a & 7) != 0) { + return 0; + } + return 1; + } + + @Test + public void test5() { + // Shouldn't be possible to optimize this + testConditionalElimination("test5Snippet", "test5Snippet"); + } + + public static int test6Snippet(int a) { + if ((a & 8) != 0) { + GraalDirectives.deoptimize(); + } + if ((a & 15) != 15) { + GraalDirectives.deoptimize(); + } + return 0; + } + + public static int reference6Snippet(int a) { + if ((a & 8) != 0) { + GraalDirectives.deoptimize(); + } + GraalDirectives.deoptimize(); + return 0; + } + + @Test + public void test6() { + testConditionalElimination("test6Snippet", "reference6Snippet"); + } + + public static int test7Snippet(int a) { + if ((a & 15) == 15) { + GraalDirectives.deoptimize(); + } + if ((a & 8) == 8) { + GraalDirectives.deoptimize(); + } + return a; + } + + public static int reference7Snippet(int a) { + if ((a & 8) == 8) { + GraalDirectives.deoptimize(); + } + return a; + } + + @Test + public void test7() { + testConditionalElimination("test7Snippet", "reference7Snippet"); + } + + public static int test8Snippet(int a) { + if ((a & 16) == 16) { + GraalDirectives.deoptimize(); + } + if ((a & 8) != 8) { + GraalDirectives.deoptimize(); + } + if ((a & 44) != 44) { + GraalDirectives.deoptimize(); + } + return a; + } + + public static int reference8Snippet(int a) { + if ((a & 60) != 44) { + GraalDirectives.deoptimize(); + } + return a; + } + + @Ignore("requires merging of bit tests") + @Test + public void test8() { + testConditionalElimination("test8Snippet", "reference8Snippet"); + } + + public static int test9Snippet(int a) { + if ((a & 16) == 16) { + GraalDirectives.deoptimize(); + } + if ((a & 8) != 8) { + GraalDirectives.deoptimize(); + } + if ((a & 44) != 44) { + GraalDirectives.deoptimize(); + } + if (a != 44) { + GraalDirectives.deoptimize(); + } + return a; + } + + public static int reference9Snippet(int a) { + if (a != 44) { + GraalDirectives.deoptimize(); + } + return a; + } + + @Test + public void test9() { + testConditionalElimination("test9Snippet", "reference9Snippet"); + } + + static class ByteHolder { + public byte b; + + byte byteValue() { + return b; + } + } + + public static int test10Snippet(ByteHolder b) { + int v = b.byteValue(); + long a = v & 0xffffffff; + if (v != 44) { + GraalDirectives.deoptimize(); + } + if ((a & 16) == 16) { + GraalDirectives.deoptimize(); + } + if ((a & 8) != 8) { + GraalDirectives.deoptimize(); + } + if ((a & 44) != 44) { + GraalDirectives.deoptimize(); + } + + return v; + } + + public static int reference10Snippet(ByteHolder b) { + byte v = b.byteValue(); + if (v != 44) { + GraalDirectives.deoptimize(); + } + return v; + } + + @Test + public void test10() { + testConditionalElimination("test10Snippet", "reference10Snippet"); + } + + public static int test11Snippet(ByteHolder b) { + int v = b.byteValue(); + long a = v & 0xffffffff; + + if ((a & 16) == 16) { + GraalDirectives.deoptimize(); + } + if ((a & 8) != 8) { + GraalDirectives.deoptimize(); + } + if ((a & 44) != 44) { + GraalDirectives.deoptimize(); + } + if (v != 44) { + GraalDirectives.deoptimize(); + } + return v; + } + + public static int reference11Snippet(ByteHolder b) { + byte v = b.byteValue(); + if (v != 44) { + GraalDirectives.deoptimize(); + } + return v; + } + + @Test + public void test11() { + testConditionalElimination("test11Snippet", "reference11Snippet"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java 2016-12-07 13:48:16.436235083 -0800 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.GuardNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/** + * Collection of tests for + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those + * that triggered bugs in this phase. + */ +public class ConditionalEliminationTest2 extends ConditionalEliminationTestBase { + + public static Object field; + + static class Entry { + + final String name; + + Entry(String name) { + this.name = name; + } + } + + static class EntryWithNext extends Entry { + + EntryWithNext(String name, Entry next) { + super(name); + this.next = next; + } + + final Entry next; + } + + public static Entry search(Entry start, String name, Entry alternative) { + Entry current = start; + do { + while (current instanceof EntryWithNext) { + if (name != null && current.name == name) { + current = null; + } else { + Entry next = ((EntryWithNext) current).next; + current = next; + } + } + + if (current != null) { + if (current.name.equals(name)) { + return current; + } + } + if (current == alternative) { + return null; + } + current = alternative; + + } while (true); + } + + public static int testRedundantComparesSnippet(int[] array) { + if (array == null) { + return 0; + } + return array[0] + array[1] + array[2] + array[3]; + } + + @Test + public void testRedundantCompares() { + StructuredGraph graph = parseEager("testRedundantComparesSnippet", AllowAssumptions.YES); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + PhaseContext context = new PhaseContext(getProviders()); + + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + canonicalizer.apply(graph, context); + new FloatingReadPhase().apply(graph); + new DominatorConditionalEliminationPhase(true).apply(graph, context); + canonicalizer.apply(graph, context); + + assertDeepEquals(1, graph.getNodes().filter(GuardNode.class).count()); + } + + public static String testInstanceOfCheckCastSnippet(Object e) { + if (e instanceof Entry) { + return ((Entry) e).name; + } + return null; + } + + @Test + public void testInstanceOfCheckCastLowered() { + StructuredGraph graph = parseEager("testInstanceOfCheckCastSnippet", AllowAssumptions.YES); + + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + PhaseContext context = new PhaseContext(getProviders()); + + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + canonicalizer.apply(graph, context); + new DominatorConditionalEliminationPhase(true).apply(graph, context); + canonicalizer.apply(graph, context); + + assertDeepEquals(0, graph.getNodes().filter(GuardNode.class).count()); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest3.java 2016-12-07 13:48:16.703246815 -0800 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Test; + +/** + * Collection of tests for + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those + * that triggered bugs in this phase. + */ +public class ConditionalEliminationTest3 extends ConditionalEliminationTestBase { + + private static final String REFERENCE_SNIPPET = "referenceSnippet"; + + @SuppressWarnings("all") + public static int referenceSnippet(int a, int b) { + int sum = 0; + outer: for (int i = 0;; ++i) { + if (b > 100) { + inner: for (int j = 0;; ++j) { + ++sum; + if (sum == 100) { + break inner; + } + if (sum == 1000 && b < 1000) { + break outer; + } + } + } + } + return sum; + } + + @Test + public void test1() { + testConditionalElimination("test1Snippet", REFERENCE_SNIPPET); + } + + @SuppressWarnings("all") + public static int test1Snippet(int a, int b) { + int sum = 0; + outer: for (int i = 0;; ++i) { + if (b > 100) { + inner: for (int j = 0;; ++j) { + ++sum; + if (sum == 100) { + break inner; + } + if (sum == 1000 && b < 1000) { + break outer; + } + } + } + } + if (b >= 1000) { + return 5; + } + return sum; + } + + @Test + public void test2() { + testConditionalElimination("test2Snippet", REFERENCE_SNIPPET); + } + + @SuppressWarnings("all") + public static int test2Snippet(int a, int b) { + int sum = 0; + outer: for (int i = 0;; ++i) { + if (b > 100) { + inner: for (int j = 0;; ++j) { + ++sum; + if (sum == 100) { + break inner; + } + if (sum == 1000 && b < 1000) { + break outer; + } + } + if (sum != 100) { + return 42; + } + } + } + return sum; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest4.java 2016-12-07 13:48:16.968258459 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Test; + +/** + * Collection of tests for + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those + * that triggered bugs in this phase. + */ +public class ConditionalEliminationTest4 extends ConditionalEliminationTestBase { + + @SuppressWarnings("all") + public static int reference1Snippet(int a, int b) { + if (a > b) { + return 1; + } + return 2; + } + + @SuppressWarnings("all") + public static int test1Snippet(int a, int b) { + if (a > b) { + if (a > b) { + return 1; + } + } + return 2; + } + + @Test + public void test1() { + testConditionalElimination("test1Snippet", "reference1Snippet"); + } + + @SuppressWarnings("all") + public static int reference2Snippet(int a, int b) { + if (a < b) { + return 1; + } + return 2; + } + + @SuppressWarnings("all") + public static int test2Snippet(int a, int b) { + if (a < b) { + if (a < b) { + return 1; + } + } + return 2; + } + + @Test + public void test2() { + testConditionalElimination("test2Snippet", "reference2Snippet"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java 2016-12-07 13:48:17.233270104 -0800 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; + +/** + * Collection of tests for + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those + * that triggered bugs in this phase. + */ +public class ConditionalEliminationTest5 extends ConditionalEliminationTestBase { + + interface A { + } + + interface B extends A { + } + + static final class DistinctA { + } + + static final class DistinctB { + } + + public static int reference1Snippet(Object a) { + if (a instanceof B) { + return 1; + } + return 2; + } + + public static int test1Snippet(Object a) { + if (a instanceof B) { + if (a instanceof A) { + return 1; + } + } + return 2; + } + + @Test + public void test1() { + testConditionalElimination("test1Snippet", "reference1Snippet"); + } + + public static int reference2Snippet(A a) { + if (a instanceof B) { + return 1; + } + return 2; + } + + public static int test2Snippet(A a) { + if (a instanceof B) { + B newVal = (B) a; + if (newVal != null) { + return 1; + } + } + return 2; + } + + @Test + public void test2() { + testConditionalElimination("test2Snippet", "reference2Snippet"); + } + + @SuppressWarnings("unused") + public static int reference3Snippet(Object a, Object b) { + if (a instanceof DistinctA) { + DistinctA proxyA = (DistinctA) a; + if (b instanceof DistinctB) { + return 1; + } + } + return 2; + } + + @SuppressWarnings("all") + public static int test3Snippet(Object a, Object b) { + if (a instanceof DistinctA) { + DistinctA proxyA = (DistinctA) a; + if (b instanceof DistinctB) { + if (proxyA == b) { + return 42; + } + return 1; + } + } + return 2; + } + + @Test + public void test3() { + testConditionalElimination("test3Snippet", "reference3Snippet", true); + } + + public static int reference4Snippet(Object a) { + if (!(a instanceof B)) { + GraalDirectives.deoptimize(); + } + return 1; + } + + public static int test4Snippet1(Object a) { + if (!(a instanceof B)) { + GraalDirectives.deoptimize(); + } + if (!(a instanceof A)) { + GraalDirectives.deoptimize(); + } + return 1; + } + + public static int test4Snippet2(Object a) { + if (!(a instanceof A)) { + GraalDirectives.deoptimize(); + } + if (!(a instanceof B)) { + GraalDirectives.deoptimize(); + } + return 1; + } + + @Test + public void test4() { + testConditionalElimination("test4Snippet1", "reference4Snippet"); + testConditionalElimination("test4Snippet2", "reference4Snippet"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest6.java 2016-12-07 13:48:17.499281792 -0800 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Test; + +/** + * Collection of tests for + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those + * that triggered bugs in this phase. + */ +public class ConditionalEliminationTest6 extends ConditionalEliminationTestBase { + + public static final A constA = new A(); + public static final B constB = new B(); + + static class A { + } + + static class B { + } + + @SuppressWarnings("all") + public static B reference1Snippet(Object a, B b) { + if (a == constA) { + return b; + } + return null; + } + + @SuppressWarnings("all") + public static B test1Snippet(Object a, B b) { + if (a == constA) { + if (a == null) { + return null; + } else { + return b; + } + } + return null; + } + + @Test + public void test1() { + testConditionalElimination("test1Snippet", "reference1Snippet"); + } + + @SuppressWarnings("all") + public static B test2Snippet(Object a, B b) { + if (a == constA) { + if (a == constB) { + return null; + } else { + return b; + } + } + return null; + } + + @Test + public void test2() { + testConditionalElimination("test2Snippet", "reference1Snippet"); + } + + @SuppressWarnings("all") + public static B test3Snippet(Object a, B b) { + if (a == constA) { + if (a == b) { + return null; + } else { + return b; + } + } + return null; + } + + @Test + public void test3() { + testConditionalElimination("test3Snippet", "reference1Snippet"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest7.java 2016-12-07 13:48:17.762293349 -0800 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Test; + +/** + * Collection of tests for + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those + * that triggered bugs in this phase. + */ +public class ConditionalEliminationTest7 extends ConditionalEliminationTestBase { + + @SuppressWarnings("all") + public static int test1Snippet(int a, Object b) { + int sum = 0; + for (int j = 0;; ++j) { + ++sum; + if (b instanceof String) { + if (sum == 100) { + break; + } + } + } + String s = (String) b; + return s.length() + sum; + } + + @Test + public void test1() { + // One loop exit is skipped. + testProxies("test1Snippet", 1); + } + + @SuppressWarnings("all") + public static int test2Snippet(int a, Object b) { + int sum = 0; + for (int j = 0;; ++j) { + ++sum; + if (b instanceof String) { + break; + } + } + String s = (String) b; + return s.length() + sum; + } + + @Test + public void test2() { + // The loop exit is the anchor => no proxy necessary. + testProxies("test2Snippet", 0); + } + + @SuppressWarnings("all") + public static int test3Snippet(int a, Object b) { + int sum = a; + outer: while (true) { + sum++; + while (sum++ != 20) { + while (sum++ != 30) { + while (sum++ != 40) { + while (sum++ != 50) { + if (b instanceof String) { + break outer; + } + } + } + } + } + } + String s = (String) b; + return s.length() + sum; + } + + @Test + public void test3() { + // The break skips over 4 other loops. + testProxies("test3Snippet", 4); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest8.java 2016-12-07 13:48:18.028305037 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Test; + +/** + * Collection of tests for + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those + * that triggered bugs in this phase. + */ +public class ConditionalEliminationTest8 extends ConditionalEliminationTestBase { + + private static double value; + + @SuppressWarnings("all") + public static int test1Snippet(int a, Object b) { + double sum = 0; + if (!(b instanceof String)) { + return 42; + } + for (int j = 0; j < a; ++j) { + sum += value; + } + return ((String) b).length(); + } + + @Test + public void test1() { + // One loop exit is skipped, because the condition dominates also the loop begin. + testProxies("test1Snippet", 0); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest9.java 2016-12-07 13:48:18.292316638 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; + +/** + * Collection of tests for + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those + * that triggered bugs in this phase. + */ +public class ConditionalEliminationTest9 extends ConditionalEliminationTestBase { + + private static final String REFERENCE_SNIPPET = "referenceSnippet"; + + @SuppressWarnings("all") + public static int referenceSnippet(int a) { + if (a == 0) { + GraalDirectives.deoptimize(); + } + return 0; + } + + @Test + public void test1() { + testConditionalElimination("test1Snippet", REFERENCE_SNIPPET); + } + + @SuppressWarnings("all") + public static int test1Snippet(int a) { + if (a == 0) { + if (a == 0) { + GraalDirectives.deoptimize(); + } + if (a == 0) { + GraalDirectives.deoptimize(); + } + } + return 0; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java 2016-12-07 13:48:18.556328238 -0800 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Assert; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.nodes.ProxyNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase; +import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase; +import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/** + * Collection of tests for + * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those + * that triggered bugs in this phase. + */ +public class ConditionalEliminationTestBase extends GraalCompilerTest { + + private final boolean disableSimplification; + + protected ConditionalEliminationTestBase() { + disableSimplification = true; + } + + protected ConditionalEliminationTestBase(boolean disableSimplification) { + this.disableSimplification = disableSimplification; + } + + protected void testConditionalElimination(String snippet, String referenceSnippet) { + testConditionalElimination(snippet, referenceSnippet, false); + } + + @SuppressWarnings("try") + protected void testConditionalElimination(String snippet, String referenceSnippet, boolean applyConditionalEliminationOnReference) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + PhaseContext context = new PhaseContext(getProviders()); + CanonicalizerPhase canonicalizer1 = new CanonicalizerPhase(); + if (disableSimplification) { + /** + * Some tests break if simplification is done so only do it when needed. + */ + canonicalizer1.disableSimplification(); + } + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest", graph)) { + canonicalizer1.apply(graph, context); + new ConvertDeoptimizeToGuardPhase().apply(graph, context); + // new DominatorConditionalEliminationPhase(true).apply(graph, context); + new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context); + canonicalizer.apply(graph, context); + canonicalizer.apply(graph, context); + new ConvertDeoptimizeToGuardPhase().apply(graph, context); + } catch (Throwable t) { + Debug.handle(t); + } + StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.YES); + try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest.ReferenceGraph", referenceGraph)) { + + new ConvertDeoptimizeToGuardPhase().apply(referenceGraph, context); + if (applyConditionalEliminationOnReference) { + new DominatorConditionalEliminationPhase(true).apply(referenceGraph, context); + canonicalizer.apply(referenceGraph, context); + canonicalizer.apply(referenceGraph, context); + } else { + canonicalizer.apply(referenceGraph, context); + } + } catch (Throwable t) { + Debug.handle(t); + } + assertEquals(referenceGraph, graph); + } + + public void testProxies(String snippet, int expectedProxiesCreated) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + PhaseContext context = new PhaseContext(getProviders()); + CanonicalizerPhase canonicalizer1 = new CanonicalizerPhase(); + canonicalizer1.disableSimplification(); + canonicalizer1.apply(graph, context); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + canonicalizer.apply(graph, context); + + int baseProxyCount = graph.getNodes().filter(ProxyNode.class).count(); + new DominatorConditionalEliminationPhase(true).apply(graph, context); + canonicalizer.apply(graph, context); + new SchedulePhase().apply(graph, context); + int actualProxiesCreated = graph.getNodes().filter(ProxyNode.class).count() - baseProxyCount; + Assert.assertEquals(expectedProxiesCreated, actualProxiesCreated); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConstantArrayReadFoldingTest.java 2016-12-07 13:48:18.822339927 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, 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.core.test; + +import org.junit.Test; + +public class ConstantArrayReadFoldingTest extends GraalCompilerTest { + + enum E { + A(0.001), + B(0.01), + C(0.5), + D(2.0), + E(3.0), + F(4.0), + G(5.0); + + public final double ceiling; + public double weight; + + E(double ceiling) { + this.ceiling = ceiling; + } + } + + public Object test1Snippet(double value) { + for (E kind : E.values()) { + if (value <= kind.ceiling) { + return kind; + } + } + throw new IllegalArgumentException(); + } + + @Test + public void test1() { + test("test1Snippet", 1.0); + test("test1Snippet", 2.0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CooperativePhaseTest.java 2016-12-07 13:48:19.086351529 -0800 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.common.RetryableBailoutException; +import org.graalvm.compiler.core.common.util.CompilationAlarm; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.phases.Phase; + +public class CooperativePhaseTest extends GraalCompilerTest { + + public static void snippet() { + // dummy snippet + } + + private static class CooperativePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + while (true) { + sleep(200); + if (CompilationAlarm.hasExpired()) { + return; + } + } + } + + } + + private static class UnCooperativePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + while (true) { + sleep(200); + if (CompilationAlarm.hasExpired()) { + throw new RetryableBailoutException("Expiring..."); + } + } + } + + } + + private static class ParlyCooperativePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + for (int i = 0; i < 10; i++) { + sleep(200); + if (CompilationAlarm.hasExpired()) { + throw new RuntimeException("Phase must not exit in the timeout path"); + } + } + } + } + + private static class CooperativePhaseWithoutAlarm extends Phase { + + @Override + protected void run(StructuredGraph graph) { + if (CompilationAlarm.hasExpired()) { + throw new RuntimeException("Phase must not exit in the timeout path"); + } + } + } + + private static void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + GraalError.shouldNotReachHere(e.getCause()); + } + } + + @Test(timeout = 60_000) + @SuppressWarnings("try") + public void test01() { + StructuredGraph g = parseEager("snippet", AllowAssumptions.NO); + try (OverrideScope o = OptionValue.override(CompilationAlarm.Options.CompilationExpirationPeriod, 1/* sec */); + CompilationAlarm c1 = CompilationAlarm.trackCompilationPeriod()) { + new CooperativePhase().apply(g); + } + } + + @Test(expected = RetryableBailoutException.class, timeout = 60_000) + @SuppressWarnings("try") + public void test02() { + StructuredGraph g = parseEager("snippet", AllowAssumptions.NO); + try (OverrideScope o = OptionValue.override(CompilationAlarm.Options.CompilationExpirationPeriod, 1/* sec */); + CompilationAlarm c1 = CompilationAlarm.trackCompilationPeriod()) { + new UnCooperativePhase().apply(g); + } + } + + @Test(timeout = 60_000) + @SuppressWarnings("try") + public void test03() { + StructuredGraph g = parseEager("snippet", AllowAssumptions.NO); + // 0 disables alarm utility + try (OverrideScope o = OptionValue.override(CompilationAlarm.Options.CompilationExpirationPeriod, 0); + CompilationAlarm c1 = CompilationAlarm.trackCompilationPeriod()) { + new ParlyCooperativePhase().apply(g); + } + } + + @Test(timeout = 60_000) + @SuppressWarnings("try") + public void test04() { + StructuredGraph g = parseEager("snippet", AllowAssumptions.NO); + new CooperativePhaseWithoutAlarm().apply(g); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CopyOfVirtualizationTest.java 2016-12-07 13:48:19.351363179 -0800 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2015, 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.core.test; + +import java.util.Arrays; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.java.NewArrayNode; + +public class CopyOfVirtualizationTest extends GraalCompilerTest { + + @Override + protected boolean checkMidTierGraph(StructuredGraph graph) { + assertTrue(graph.getNodes().filter(node -> node instanceof NewArrayNode).count() == 0, "shouldn't require allocation in %s", graph); + return super.checkMidTierGraph(graph); + } + + public byte byteCopyOfVirtualization(int index) { + byte[] array = new byte[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public short shortCopyOfVirtualization(int index) { + short[] array = new short[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public char charCopyOfVirtualization(int index) { + char[] array = new char[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public int intCopyOfVirtualization(int index) { + int[] array = new int[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public long longCopyOfVirtualization(int index) { + long[] array = new long[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public float floatCopyOfVirtualization(int index) { + float[] array = new float[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public double doubleCopyOfVirtualization(int index) { + double[] array = new double[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public Object objectCopyOfVirtualization(int index) { + Object[] array = new Object[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + // @Test + public void testCopyOfVirtualization() { + test("byteCopyOfVirtualization", 3); + test("shortCopyOfVirtualization", 3); + test("charCopyOfVirtualization", 3); + test("intCopyOfVirtualization", 3); + test("longCopyOfVirtualization", 3); + test("floatCopyOfVirtualization", 3); + test("doubleCopyOfVirtualization", 3); + test("objectCopyOfVirtualization", 3); + } + + static final byte[] byteArray = new byte[]{1, 2, 3, 4}; + + public byte byteCopyOfVirtualizableAllocation() { + return Arrays.copyOf(byteArray, byteArray.length)[3]; + } + + static final short[] shortArray = new short[]{1, 2, 3, 4}; + + public short shortCopyOfVirtualizableAllocation() { + return Arrays.copyOf(shortArray, shortArray.length)[3]; + } + + static final char[] charArray = new char[]{1, 2, 3, 4}; + + public char charCopyOfVirtualizableAllocation() { + return Arrays.copyOf(charArray, charArray.length)[3]; + } + + static final int[] intArray = new int[]{1, 2, 3, 4}; + + public int intCopyOfVirtualizableAllocation() { + return Arrays.copyOf(intArray, intArray.length)[3]; + } + + static final long[] longArray = new long[]{1, 2, 3, 4}; + + public long longCopyOfVirtualizableAllocation() { + return Arrays.copyOf(longArray, longArray.length)[3]; + } + + static final float[] floatArray = new float[]{1, 2, 3, 4}; + + public float floatCopyOfVirtualizableAllocation() { + return Arrays.copyOf(floatArray, floatArray.length)[3]; + } + + static final double[] doubleArray = new double[]{1, 2, 3, 4}; + + public double doubleCopyOfVirtualizableAllocation() { + return Arrays.copyOf(doubleArray, doubleArray.length)[3]; + } + + static final Object[] objectArray = new Object[]{1, 2, 3, 4}; + + public Object objectCopyOfVirtualizableAllocation() { + return Arrays.copyOf(objectArray, objectArray.length)[3]; + } + + @Test + public void testCopyOfVirtualizableAllocation() { + test("byteCopyOfVirtualizableAllocation"); + test("shortCopyOfVirtualizableAllocation"); + test("charCopyOfVirtualizableAllocation"); + test("intCopyOfVirtualizableAllocation"); + test("longCopyOfVirtualizableAllocation"); + test("floatCopyOfVirtualizableAllocation"); + test("doubleCopyOfVirtualizableAllocation"); + test("objectCopyOfVirtualizableAllocation"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java 2016-12-07 13:48:19.615374784 -0800 @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2015, 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.core.test; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.loop.InductionVariable; +import org.graalvm.compiler.loop.LoopsData; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class CountedLoopTest extends GraalCompilerTest { + + @FunctionalInterface + private interface IVProperty { + ValueNode get(InductionVariable iv); + } + + /** + * Get a property of an induction variable. + * + * @param property + */ + private static int get(IVProperty property, int iv) { + return iv; + } + + private static class Result { + public int extremum; + public int exitValue; + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + exitValue; + result = prime * result + extremum; + return result; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Result)) { + return false; + } + Result other = (Result) obj; + return extremum == other.extremum && exitValue == other.exitValue; + } + + @Override + public String toString() { + return String.format("extremum = %d, exitValue = %d", extremum, exitValue); + } + } + + public static Result incrementSnippet(int start, int limit, int step) { + int i; + int inc = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive + Result ret = new Result(); + for (i = start; i < limit; i += inc) { + GraalDirectives.controlFlowAnchor(); + ret.extremum = get(InductionVariable::extremumNode, i); + } + ret.exitValue = get(InductionVariable::exitValueNode, i); + return ret; + } + + @Test + public void increment1() { + test("incrementSnippet", 0, 256, 1); + } + + @Test + public void increment2() { + test("incrementSnippet", 0, 256, 2); + } + + @Test + public void increment3() { + test("incrementSnippet", 0, 256, 3); + } + + public static Result incrementEqSnippet(int start, int limit, int step) { + int i; + int inc = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive + Result ret = new Result(); + for (i = start; i <= limit; i += inc) { + GraalDirectives.controlFlowAnchor(); + ret.extremum = get(InductionVariable::extremumNode, i); + } + ret.exitValue = get(InductionVariable::exitValueNode, i); + return ret; + } + + @Test + public void incrementEq1() { + test("incrementEqSnippet", 0, 256, 1); + } + + @Test + public void incrementEq2() { + test("incrementEqSnippet", 0, 256, 2); + } + + @Test + public void incrementEq3() { + test("incrementEqSnippet", 0, 256, 3); + } + + public static Result decrementSnippet(int start, int limit, int step) { + int i; + int dec = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive + Result ret = new Result(); + for (i = start; i > limit; i -= dec) { + GraalDirectives.controlFlowAnchor(); + ret.extremum = get(InductionVariable::extremumNode, i); + } + ret.exitValue = get(InductionVariable::exitValueNode, i); + return ret; + } + + @Test + public void decrement1() { + test("decrementSnippet", 256, 0, 1); + } + + @Test + public void decrement2() { + test("decrementSnippet", 256, 0, 2); + } + + @Test + public void decrement3() { + test("decrementSnippet", 256, 0, 3); + } + + public static Result decrementEqSnippet(int start, int limit, int step) { + int i; + int dec = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive + Result ret = new Result(); + for (i = start; i >= limit; i -= dec) { + GraalDirectives.controlFlowAnchor(); + ret.extremum = get(InductionVariable::extremumNode, i); + } + ret.exitValue = get(InductionVariable::exitValueNode, i); + return ret; + } + + @Test + public void decrementEq1() { + test("decrementEqSnippet", 256, 0, 1); + } + + @Test + public void decrementEq2() { + test("decrementEqSnippet", 256, 0, 2); + } + + @Test + public void decrementEq3() { + test("decrementEqSnippet", 256, 0, 3); + } + + public static Result twoVariablesSnippet() { + Result ret = new Result(); + int j = 0; + for (int i = 0; i < 1024; i++) { + j += 5; + GraalDirectives.controlFlowAnchor(); + ret.extremum = get(InductionVariable::extremumNode, j); + } + ret.exitValue = get(InductionVariable::exitValueNode, j); + return ret; + } + + @Test + public void testTwoVariables() { + test("twoVariablesSnippet"); + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + private static class IVPropertyNode extends FloatingNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(IVPropertyNode.class); + + private final IVProperty property; + @Input private ValueNode iv; + + protected IVPropertyNode(IVProperty property, ValueNode iv) { + super(TYPE, iv.stamp().unrestricted()); + this.property = property; + this.iv = iv; + } + + public void rewrite(LoopsData loops) { + InductionVariable inductionVariable = loops.getInductionVariable(iv); + assert inductionVariable != null; + ValueNode node = property.get(inductionVariable); + replaceAtUsagesAndDelete(node); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + gen.setResult(this, gen.operand(iv)); + } + } + + @Override + protected Plugins getDefaultGraphBuilderPlugins() { + Plugins plugins = super.getDefaultGraphBuilderPlugins(); + Registration r = new Registration(plugins.getInvocationPlugins(), CountedLoopTest.class); + + r.register2("get", IVProperty.class, int.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) { + IVProperty property = null; + if (arg1.isConstant()) { + property = getSnippetReflection().asObject(IVProperty.class, arg1.asJavaConstant()); + } + if (property != null) { + b.addPush(JavaKind.Int, new IVPropertyNode(property, arg2)); + return true; + } else { + return false; + } + } + }); + + return plugins; + } + + @Override + protected boolean checkMidTierGraph(StructuredGraph graph) { + LoopsData loops = new LoopsData(graph); + loops.detectedCountedLoops(); + for (IVPropertyNode node : graph.getNodes().filter(IVPropertyNode.class)) { + node.rewrite(loops); + } + assert graph.getNodes().filter(IVPropertyNode.class).isEmpty(); + return true; + } + + public static Result incrementNeqSnippet(int limit) { + int i; + int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive + Result ret = new Result(); + for (i = 0; i != posLimit; i++) { + GraalDirectives.controlFlowAnchor(); + ret.extremum = get(InductionVariable::extremumNode, i); + } + ret.exitValue = get(InductionVariable::exitValueNode, i); + return ret; + } + + @Test + public void decrementNeq() { + test("decrementNeqSnippet", 256); + } + + public static Result decrementNeqSnippet(int limit) { + int i; + int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive + Result ret = new Result(); + for (i = posLimit; i != 0; i--) { + GraalDirectives.controlFlowAnchor(); + ret.extremum = get(InductionVariable::extremumNode, i); + } + ret.exitValue = get(InductionVariable::exitValueNode, i); + return ret; + } + + @Test + public void incrementNeq() { + test("incrementNeqSnippet", 256); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java 2016-12-07 13:48:19.881386477 -0800 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +/** + * In the following tests, the usages of local variable "a" are replaced with the integer constant + * 0. Then canonicalization is applied and it is verified that the resulting graph is equal to the + * graph of the method that just has a "return 1" statement in it. + */ +public class DegeneratedLoopsTest extends GraalCompilerTest { + + private static final String REFERENCE_SNIPPET = "referenceSnippet"; + + @SuppressWarnings("all") + public static int referenceSnippet(int a) { + return a; + } + + @Test + public void test1() { + test("test1Snippet"); + } + + private static class UnresolvedException extends RuntimeException { + + private static final long serialVersionUID = 5215434338750728440L; + + static { + if (true) { + throw new UnsupportedOperationException("this class may never be initialized"); + } + } + } + + @SuppressWarnings("all") + public static int test1Snippet(int a) { + for (;;) { + try { + test(); + break; + } catch (UnresolvedException e) { + } + } + return a; + } + + private static void test() { + + } + + @SuppressWarnings("try") + private void test(final String snippet) { + try (Scope s = Debug.scope("DegeneratedLoopsTest", new DebugDumpScope(snippet))) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + HighTierContext context = getDefaultHighTierContext(); + new InliningPhase(new CanonicalizerPhase()).apply(graph, context); + new CanonicalizerPhase().apply(graph, context); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES); + Debug.dump(Debug.BASIC_LOG_LEVEL, referenceGraph, "ReferenceGraph"); + assertEquals(referenceGraph, graph); + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DontReuseArgumentSpaceTest.java 2016-12-07 13:48:20.146398126 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.phases.HighTier; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.phases.tiers.Suites; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public final class DontReuseArgumentSpaceTest extends GraalCompilerTest { + + @Override + @SuppressWarnings("try") + protected Suites createSuites() { + try (OverrideScope scope = OptionValue.override(HighTier.Options.Inline, false)) { + return super.createSuites(); + } + } + + @BytecodeParserNeverInline + public static int killArguments(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { + return a + b + c + d + e + f + g + h + i + j; + } + + @BytecodeParserNeverInline + public static int callTwice(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { + /* + * Call the same method twice so the arguments are in the same place each time and might + * appear to be redundant moves. + */ + killArguments(a, b, c, d, e, f, g, h, i, j); + return killArguments(a, b, c, d, e, f, g, h, i, j); + } + + @Test + public void run0() throws Throwable { + /* + * Exercise the methods once so everything is resolved + */ + callTwice(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + + /* + * Create a standalone compile of killArguments. This test assumes that zapping of argument + * space is being performed by the backend. + */ + ResolvedJavaMethod javaMethod = getResolvedJavaMethod("killArguments"); + StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.YES); + CompilationResult compilationResult = compile(javaMethod, graph); + getBackend().createDefaultInstalledCode(javaMethod, compilationResult); + + test("callTwice", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/EnumSwitchTest.java 2016-12-07 13:48:20.411409775 -0800 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2016, 2016, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; +import org.graalvm.compiler.nodes.java.LoadIndexedNode; +import org.graalvm.compiler.phases.Phase; +import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; +import org.graalvm.compiler.phases.tiers.Suites; + +public class EnumSwitchTest extends GraalCompilerTest { + + enum E { + E0, + E1, + E2, + E3, + E4, + E5, + E6, + E7, + E8, + E9, + E10, + E11, + E12, + E13, + E14, + E15, + E16, + E17, + E18, + E19, + E20 + } + + public int test1Snippet(E e) { + switch (e) { + case E0: + return 0; + case E1: + return 1; + case E2: + return 2; + case E3: + return 3; + case E4: + return 4; + case E5: + return 5; + case E6: + return 6; + case E7: + return 7; + case E8: + return 8; + case E9: + return 9; + case E10: + return 10; + case E11: + return 11; + case E12: + return 12; + case E13: + return 13; + case E14: + return 14; + case E15: + return 15; + case E16: + return 16; + case E17: + return 17; + case E18: + return 18; + case E19: + return 19; + case E20: + return 20; + default: + return -1; + } + } + + @Test + public void test1() { + for (E e : E.values()) { + test("test1Snippet", e); + } + test("test1Snippet", new Object[]{null}); + } + + public int test2Snippet(E e) { + switch (e) { + case E5: + case E19: + case E20: + return 1; + case E8: + case E9: + case E10: + return 2; + } + return -1; + } + + @Test + public void test2() { + for (E e : E.values()) { + test("test2Snippet", e); + } + test("test2Snippet", new Object[]{null}); + } + + @Override + protected Suites createSuites() { + Suites ret = super.createSuites(); + ret.getHighTier().prependPhase(new Phase() { + @Override + protected void run(StructuredGraph graph) { + /* Array load from the enum switch map. */ + assertTrue(graph.getNodes().filter(LoadIndexedNode.class).count() == 1); + /* The actual switch. */ + assertTrue(graph.getNodes().filter(IntegerSwitchNode.class).count() == 1); + } + + @Override + protected CharSequence getName() { + return "CheckGraphPhase"; + } + }); + ret.getHighTier().findPhase(RemoveValueProxyPhase.class).add(new Phase() { + @Override + protected void run(StructuredGraph graph) { + /* Re-writing of the switch cases eliminates the array load. */ + assertTrue(graph.getNodes().filter(LoadIndexedNode.class).count() == 0); + /* The switch is still there. */ + assertTrue(graph.getNodes().filter(IntegerSwitchNode.class).count() == 1); + } + + @Override + protected CharSequence getName() { + return "CheckGraphPhase"; + } + }); + return ret; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FinalizableSubclassTest.java 2016-12-07 13:48:20.677421469 -0800 @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2013, 2016, 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.core.test; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; +import static org.graalvm.compiler.nodes.StructuredGraph.NO_PROFILING_INFO; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.util.HashMap; + +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.Assumptions.Assumption; +import jdk.vm.ci.meta.Assumptions.LeafType; +import jdk.vm.ci.meta.Assumptions.NoFinalizableSubclass; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.java.RegisterFinalizerNode; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +public class FinalizableSubclassTest extends GraalCompilerTest { + + /** + * used as template to generate class files at runtime. + */ + public static class NoFinalizerEverAAAA { + } + + public static class NoFinalizerYetAAAA { + } + + public static final class WithFinalizerAAAA extends NoFinalizerYetAAAA { + + @Override + protected void finalize() throws Throwable { + super.finalize(); + } + } + + private StructuredGraph parseAndProcess(Class cl, AllowAssumptions allowAssumptions) { + Constructor[] constructors = cl.getConstructors(); + Assert.assertTrue(constructors.length == 1); + final ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(constructors[0]); + StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions, NO_PROFILING_INFO, INVALID_COMPILATION_ID); + + GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins()); + new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), getProviders().getConstantFieldProvider(), conf, + OptimisticOptimizations.ALL, null).apply(graph); + HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); + new InliningPhase(new CanonicalizerPhase()).apply(graph, context); + new CanonicalizerPhase().apply(graph, context); + return graph; + } + + private void checkForRegisterFinalizeNode(Class cl, boolean shouldContainFinalizer, AllowAssumptions allowAssumptions) { + StructuredGraph graph = parseAndProcess(cl, allowAssumptions); + Assert.assertTrue(graph.getNodes().filter(RegisterFinalizerNode.class).count() == (shouldContainFinalizer ? 1 : 0)); + int noFinalizerAssumption = 0; + Assumptions assumptions = graph.getAssumptions(); + if (assumptions != null) { + for (Assumption a : assumptions) { + if (a instanceof NoFinalizableSubclass) { + noFinalizerAssumption++; + } else if (a instanceof LeafType) { + // Need to also allow leaf type assumption instead of no finalizable subclass + // assumption. + noFinalizerAssumption++; + } + } + } + Assert.assertTrue(noFinalizerAssumption == (shouldContainFinalizer ? 0 : 1)); + } + + /** + * Use a custom class loader to generate classes, to make sure the given classes are loaded in + * correct order. + */ + @Test + public void test1() throws ClassNotFoundException { + for (int i = 0; i < 2; i++) { + ClassTemplateLoader loader = new ClassTemplateLoader(); + checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), true, AllowAssumptions.NO); + checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), false, AllowAssumptions.YES); + + checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), false, AllowAssumptions.YES); + + checkForRegisterFinalizeNode(loader.findClass("WithFinalizerAAAA"), true, AllowAssumptions.YES); + checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), true, AllowAssumptions.YES); + } + } + + private static class ClassTemplateLoader extends ClassLoader { + + private static int loaderInstance = 0; + + private final String replaceTo; + private HashMap> cache = new HashMap<>(); + + ClassTemplateLoader() { + loaderInstance++; + replaceTo = String.format("%04d", loaderInstance); + } + + @Override + protected Class findClass(final String name) throws ClassNotFoundException { + String nameReplaced = name.replaceAll("AAAA", replaceTo); + if (cache.containsKey(nameReplaced)) { + return cache.get(nameReplaced); + } + + // copy classfile to byte array + byte[] classData = null; + try { + InputStream is = FinalizableSubclassTest.class.getResourceAsStream("FinalizableSubclassTest$" + name + ".class"); + assert is != null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + byte[] buf = new byte[1024]; + int size; + while ((size = is.read(buf, 0, buf.length)) != -1) { + baos.write(buf, 0, size); + } + baos.flush(); + classData = baos.toByteArray(); + } catch (IOException e) { + Assert.fail("can't access class: " + name); + } + dumpStringsInByteArray(classData); + + // replace all occurrences of "AAAA" in classfile + int index = -1; + while ((index = indexOfAAAA(classData, index + 1)) != -1) { + replaceAAAA(classData, index, replaceTo); + } + dumpStringsInByteArray(classData); + + Class c = defineClass(null, classData, 0, classData.length); + cache.put(nameReplaced, c); + return c; + } + + private static int indexOfAAAA(byte[] b, int index) { + for (int i = index; i < b.length; i++) { + boolean match = true; + for (int j = i; j < i + 4; j++) { + if (b[j] != (byte) 'A') { + match = false; + break; + } + } + if (match) { + return i; + } + } + return -1; + } + + private static void replaceAAAA(byte[] b, int index, String replacer) { + assert replacer.length() == 4; + for (int i = index; i < index + 4; i++) { + b[i] = (byte) replacer.charAt(i - index); + } + } + + private static void dumpStringsInByteArray(byte[] b) { + boolean wasChar = true; + StringBuilder sb = new StringBuilder(); + for (Byte x : b) { + // check for [a-zA-Z0-9] + if ((x >= 0x41 && x <= 0x7a) || (x >= 0x30 && x <= 0x39)) { + if (!wasChar) { + Debug.log(sb + ""); + sb.setLength(0); + } + sb.append(String.format("%c", x)); + wasChar = true; + } else { + wasChar = false; + } + } + Debug.log(sb + ""); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueConcreteMethodBugTest.java 2016-12-07 13:48:20.941433074 -0800 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2014, 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.core.test; + +import jdk.vm.ci.meta.Assumptions.AssumptionResult; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +public class FindUniqueConcreteMethodBugTest extends GraalCompilerTest { + + // To cause a C1 or C2 crash: -DFindUniqueConcreteMethodBugTest.ITERATIONS=10000 + private static final int ITERATIONS = Integer.getInteger("FindUniqueConcreteMethodBugTest.ITERATIONS", 100); + + /** + * Executing {@link ResolvedJavaType#findUniqueConcreteMethod(ResolvedJavaMethod)} for the + * method {@link Person#getName()} on the type {@link AbstractPerson} should return null as both + * {@link PersonImpl} and {@link TenantImpl} provide implementations (namely + * {@link PersonImpl#getName()} and {@link Tenant#getName()}). + */ + @Test + @Ignore("fix HotSpotResolvedObjectTypeImpl.findUniqueConcreteMethod") + public void test() throws NoSuchMethodException { + ResolvedJavaMethod ifaceMethod = getMetaAccess().lookupJavaMethod(Person.class.getDeclaredMethod("getName")); + + PersonImpl person = new PersonImpl("maya"); + TenantImpl tenant = new TenantImpl(0xdeadbeef); + + // Ensure the relevant methods are linked + person.getName(); + tenant.getName(); + + for (int i = 0; i < ITERATIONS; i++) { + getLabelLength(person); + getLabelLength(tenant); + } + + // Until HotSpotResolvedObjectTypeImpl.findUniqueConcreteMethod is fixed, + // this causes a VM crash as getLabelLength() directly invokes PersonImpl.getName(). + test("getLabelLength", tenant); + + ResolvedJavaMethod expected = null; + AssumptionResult actual = getMetaAccess().lookupJavaType(AbstractPerson.class).findUniqueConcreteMethod(ifaceMethod); + Assert.assertEquals(expected, actual.getResult()); + + } + + public int getLabelLength(AbstractPerson person) { + return person.getName().length(); + } + + interface Person { + String getName(); + + default int getId() { + return -1; + } + } + + interface Tenant extends Person { + @Override + default String getName() { + return getAddress(); + } + + String getAddress(); + } + + abstract static class AbstractPerson implements Person { + } + + static class PersonImpl extends AbstractPerson { + public String name; + + PersonImpl(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + } + + static class TenantImpl extends AbstractPerson implements Tenant { + public int id; + + TenantImpl(int id) { + this.id = id; + } + + @Override + public String getAddress() { + return String.valueOf(id); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueDefaultMethodTest.java 2016-12-07 13:48:21.205444679 -0800 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2014, 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.core.test; + +import jdk.vm.ci.meta.Assumptions.AssumptionResult; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +/** + * This test illustrates problems and limitations with class hierarchy analysis when default methods + * are involved. + */ +public class FindUniqueDefaultMethodTest extends GraalCompilerTest { + + interface Interface1 { + default int v1() { + return 1; + } + } + + static class Implementor1 implements Interface1 { + int callV1() { + return v1(); + } + } + + static class Subclass1 extends Implementor1 { + + } + + /** + * HotSpot has an internal mismatch with CHA and default methods. The initial query says that + * it's a unique method but the verification code that ensures that a dependence of this kind + * would pass will fail an assert in debug mode. + */ + @Test + public void testFindUnique() { + ResolvedJavaType cType = getMetaAccess().lookupJavaType(Implementor1.class); + cType.initialize(); + ResolvedJavaMethod v1Method = getMetaAccess().lookupJavaMethod(this.getMethod(Interface1.class, "v1")); + AssumptionResult method = cType.findUniqueConcreteMethod(v1Method); + assertDeepEquals(null, method); + } + + interface Interface2 { + default int v1() { + return 1; + } + } + + static class Base2 { + public int v2() { + return 1; + } + } + + static class Implementor2 extends Base2 implements Interface2 { + int callV1() { + return v1(); + } + + int callV2() { + return v2(); + } + } + + static class Subclass2 extends Implementor2 { + + } + + /** + * This test illustrates a common pattern where a method at the root of a hierarchy is the only + * implementation and can be statically inlined. + */ + @SuppressWarnings("unused") + @Test + public void testInherited() { + Subclass2 s = new Subclass2(); + testConstantReturn("runInherited", 1); + } + + /** + * Test same pattern as above but using default methods instead. HotSpot doesn't allow this + * version to be optimized. + */ + @SuppressWarnings("unused") + @Test + @Ignore("HotSpot CHA doesn't treat default methods like regular methods") + public void testDefault() { + Subclass2 s = new Subclass2(); + testConstantReturn("runDefault", 1); + } + + public int runDefault(Implementor2 i) { + return i.callV1(); + } + + public int runInherited(Implementor2 i) { + return i.callV2(); + } + + private void testConstantReturn(String name, Object value) { + StructuredGraph result = buildGraph(name); + ReturnNode ret = result.getNodes(ReturnNode.TYPE).first(); + assertDeepEquals(1, result.getNodes(ReturnNode.TYPE).count()); + + assertDeepEquals(true, ret.result().isConstant()); + assertDeepEquals(value, ret.result().asJavaConstant().asBoxedPrimitive()); + } + + @SuppressWarnings("try") + protected StructuredGraph buildGraph(final String snippet) { + try (Scope s = Debug.scope("InstanceOfTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + compile(graph.method(), graph); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet); + return graph; + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatOptimizationTest.java 2016-12-07 13:48:21.470456329 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014, 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.core.test; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Check for incorrect elimination of 0.0 and -0.0 from computations. They can affect the sign of + * the result of an add or substract. + */ +public class FloatOptimizationTest extends GraalCompilerTest { + + @Test + public void test1() { + test("test1Snippet", -0.0); + } + + @SuppressWarnings("all") + public static double test1Snippet(double x) { + return x + 0.0; + } + + @Test + public void test2() { + test("test2Snippet", -0.0f); + } + + @SuppressWarnings("all") + public static double test2Snippet(float x) { + return x + 0.0f; + } + + @Test + public void test3() { + test("test3Snippet", -0.0); + } + + @SuppressWarnings("all") + public static double test3Snippet(double x) { + return x - -0.0; + } + + @Test + public void test4() { + test("test4Snippet", -0.0f); + } + + @SuppressWarnings("all") + public static double test4Snippet(float x) { + return x - -0.0f; + } + + @Override + protected void assertDeepEquals(String message, Object expected, Object actual, double delta) { + if (expected instanceof Double && actual instanceof Double) { + double e = (double) expected; + double a = (double) actual; + if (Double.doubleToRawLongBits(a) != Double.doubleToRawLongBits(e)) { + Assert.fail((message == null ? "" : message) + "raw double bits not equal " + Double.doubleToRawLongBits(a) + " != " + Double.doubleToRawLongBits(e)); + } + } else { + super.assertDeepEquals(message, expected, actual, delta); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java 2016-12-07 13:48:21.738468110 -0800 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011, 2015, 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.core.test; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.extended.MonitorExit; +import org.graalvm.compiler.nodes.memory.FloatingReadNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class FloatingReadTest extends GraphScheduleTest { + + public static class Container { + + public int a; + } + + public static void changeField(Container c) { + c.a = 0xcafebabe; + } + + public static synchronized int test1Snippet() { + Container c = new Container(); + return c.a; + } + + @Test + public void test1() { + test("test1Snippet"); + } + + @SuppressWarnings("try") + private void test(final String snippet) { + try (Scope s = Debug.scope("FloatingReadTest", new DebugDumpScope(snippet))) { + + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + PhaseContext context = new PhaseContext(getProviders()); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + new FloatingReadPhase().apply(graph); + + ReturnNode returnNode = null; + MonitorExit monitorexit = null; + + for (Node n : graph.getNodes()) { + if (n instanceof ReturnNode) { + assert returnNode == null; + returnNode = (ReturnNode) n; + } else if (n instanceof MonitorExit) { + monitorexit = (MonitorExit) n; + } + } + + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After lowering"); + + Assert.assertNotNull(returnNode); + Assert.assertNotNull(monitorexit); + Assert.assertTrue(returnNode.result() instanceof FloatingReadNode); + + FloatingReadNode read = (FloatingReadNode) returnNode.result(); + + assertOrderedAfterSchedule(graph, read, (Node) monitorexit); + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerAssumptionsTest.java 2016-12-07 13:48:22.002479715 -0800 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.Assumptions.Assumption; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +public abstract class GraalCompilerAssumptionsTest extends GraalCompilerTest { + + public GraalCompilerAssumptionsTest() { + super(); + } + + public GraalCompilerAssumptionsTest(Class arch) { + super(arch); + } + + protected void testAssumptionInvalidate(String methodName, Assumption expected, String classToLoad) { + testAssumption(methodName, expected, classToLoad, true); + } + + /** + * Checks the behavior of class loading on {@link Assumption invalidation}. {@code methodName} + * is compiled and the resulting graph is checked for {@code expectedAssumption}. The code is + * installed and optionally {@code classToLoad} is loaded. The class is assumed to be an inner + * class of the test class and the name of the class to load is constructed relative to that. + * + * @param methodName the method to compile + * @param expectedAssumption expected {@link Assumption} instance to find in graph + * @param classToLoad an optional class to load to trigger an invalidation check + * @param willInvalidate true if loading {@code classToLoad} should invalidate the method + */ + protected void testAssumption(String methodName, Assumption expectedAssumption, String classToLoad, boolean willInvalidate) { + ResolvedJavaMethod javaMethod = getResolvedJavaMethod(methodName); + + StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.YES); + assertTrue(!graph.getAssumptions().isEmpty()); + checkGraph(expectedAssumption, graph); + + CompilationResult compilationResult = compile(javaMethod, graph); + final InstalledCode installedCode = getBackend().createDefaultInstalledCode(javaMethod, compilationResult); + assertTrue(installedCode.isValid()); + if (classToLoad != null) { + String fullName = getClass().getName() + "$" + classToLoad; + try { + Class.forName(fullName); + } catch (ClassNotFoundException e) { + fail("Can't find class %s", fullName); + } + assertTrue(!willInvalidate == installedCode.isValid(), "method should be %s", willInvalidate ? "invalid" : "valid"); + } + } + + protected void checkGraph(Assumption expectedAssumption, StructuredGraph graph) { + boolean found = false; + for (Assumption a : graph.getAssumptions()) { + if (expectedAssumption.equals(a)) { + found = true; + } + } + assertTrue(found, "Can't find assumption %s", expectedAssumption); + } + + /** + * Converts a {@link Class} to an initialized {@link ResolvedJavaType}. + */ + protected ResolvedJavaType resolveAndInitialize(Class clazz) { + ResolvedJavaType type = getMetaAccess().lookupJavaType(clazz); + type.initialize(); + return type; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java 2016-12-07 13:48:22.266491320 -0800 @@ -0,0 +1,1189 @@ +/* + * Copyright (c) 2011, 2016, 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.core.test; + +import static org.graalvm.compiler.core.GraalCompilerOptions.PrintCompilation; +import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; +import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION; +import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.internal.AssumptionViolatedException; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.GraalCompiler; +import org.graalvm.compiler.core.GraalCompiler.Request; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.target.Backend; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeMap; +import org.graalvm.compiler.java.BytecodeParser; +import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodeinfo.NodeSize; +import org.graalvm.compiler.nodeinfo.Verbosity; +import org.graalvm.compiler.nodes.BreakpointNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.FullInfopointNode; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.InvokeWithExceptionNode; +import org.graalvm.compiler.nodes.ProxyNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.spi.LoweringProvider; +import org.graalvm.compiler.nodes.spi.Replacements; +import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; +import org.graalvm.compiler.options.DerivedOptionValue; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.Phase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.Suites; +import org.graalvm.compiler.phases.tiers.TargetProvider; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.runtime.RuntimeProvider; +import org.graalvm.compiler.test.GraalTest; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ProfilingInfo; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.SpeculationLog; + +/** + * Base class for Graal compiler unit tests. + *

+ * White box tests for Graal compiler transformations use this pattern: + *

    + *
  1. Create a graph by {@linkplain #parseEager(String, AllowAssumptions) parsing} a method.
  2. + *
  3. Manually modify the graph (e.g. replace a parameter node with a constant).
  4. + *
  5. Apply a transformation to the graph.
  6. + *
  7. Assert that the transformed graph is equal to an expected graph.
  8. + *
+ *

+ * See {@link InvokeHintsTest} as an example of a white box test. + *

+ * Black box tests use the {@link #test(String, Object...)} or + * {@link #testN(int, String, Object...)} to execute some method in the interpreter and compare its + * result against that produced by a Graal compiled version of the method. + *

+ * These tests will be run by the {@code mx unittest} command. + */ +public abstract class GraalCompilerTest extends GraalTest { + + private final Providers providers; + private final Backend backend; + private final DerivedOptionValue suites; + private final DerivedOptionValue lirSuites; + + /** + * Denotes a test method that must be inlined by the {@link BytecodeParser}. + */ + @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) + @Retention(RetentionPolicy.RUNTIME) + public @interface BytecodeParserForceInline { + } + + /** + * Denotes a test method that must never be inlined by the {@link BytecodeParser}. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) + public @interface BytecodeParserNeverInline { + /** + * Specifies if the call should be implemented with {@link InvokeWithExceptionNode} instead + * of {@link InvokeNode}. + */ + boolean invokeWithException() default false; + } + + /** + * Can be overridden by unit tests to verify properties of the graph. + * + * @param graph the graph at the end of HighTier + */ + protected boolean checkHighTierGraph(StructuredGraph graph) { + return true; + } + + /** + * Can be overridden by unit tests to verify properties of the graph. + * + * @param graph the graph at the end of MidTier + */ + protected boolean checkMidTierGraph(StructuredGraph graph) { + return true; + } + + /** + * Can be overridden by unit tests to verify properties of the graph. + * + * @param graph the graph at the end of LowTier + */ + protected boolean checkLowTierGraph(StructuredGraph graph) { + return true; + } + + protected static void breakpoint() { + } + + @SuppressWarnings("unused") + protected static void breakpoint(int arg0) { + } + + protected static void shouldBeOptimizedAway() { + } + + protected Suites createSuites() { + Suites ret = backend.getSuites().getDefaultSuites().copy(); + ListIterator> iter = ret.getHighTier().findPhase(ConvertDeoptimizeToGuardPhase.class, true); + if (iter == null) { + /* + * in the economy configuration, we don't have the ConvertDeoptimizeToGuard phase, so we + * just select the first CanonicalizerPhase in HighTier + */ + iter = ret.getHighTier().findPhase(CanonicalizerPhase.class); + } + iter.add(new Phase() { + + @Override + protected void run(StructuredGraph graph) { + ComputeLoopFrequenciesClosure.compute(graph); + } + + @Override + public float codeSizeIncrease() { + return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR; + } + + @Override + protected CharSequence getName() { + return "ComputeLoopFrequenciesPhase"; + } + }); + ret.getHighTier().appendPhase(new Phase() { + + @Override + protected void run(StructuredGraph graph) { + assert checkHighTierGraph(graph) : "failed HighTier graph check"; + } + + @Override + public float codeSizeIncrease() { + return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR; + } + + @Override + protected CharSequence getName() { + return "CheckGraphPhase"; + } + }); + ret.getMidTier().appendPhase(new Phase() { + + @Override + protected void run(StructuredGraph graph) { + assert checkMidTierGraph(graph) : "failed MidTier graph check"; + } + + @Override + public float codeSizeIncrease() { + return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR; + } + + @Override + protected CharSequence getName() { + return "CheckGraphPhase"; + } + }); + ret.getLowTier().appendPhase(new Phase() { + + @Override + protected void run(StructuredGraph graph) { + assert checkLowTierGraph(graph) : "failed LowTier graph check"; + } + + @Override + public float codeSizeIncrease() { + return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR; + } + + @Override + protected CharSequence getName() { + return "CheckGraphPhase"; + } + }); + return ret; + } + + protected LIRSuites createLIRSuites() { + LIRSuites ret = backend.getSuites().getDefaultLIRSuites().copy(); + return ret; + } + + public GraalCompilerTest() { + this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend(); + this.providers = getBackend().getProviders(); + this.suites = new DerivedOptionValue<>(this::createSuites); + this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites); + } + + /** + * Set up a test for a non-default backend. The test should check (via {@link #getBackend()} ) + * whether the desired backend is available. + * + * @param arch the name of the desired backend architecture + */ + public GraalCompilerTest(Class arch) { + RuntimeProvider runtime = Graal.getRequiredCapability(RuntimeProvider.class); + Backend b = runtime.getBackend(arch); + if (b != null) { + this.backend = b; + } else { + // Fall back to the default/host backend + this.backend = runtime.getHostBackend(); + } + this.providers = backend.getProviders(); + this.suites = new DerivedOptionValue<>(this::createSuites); + this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites); + } + + /** + * Set up a test for a non-default backend. + * + * @param backend the desired backend + */ + public GraalCompilerTest(Backend backend) { + this.backend = backend; + this.providers = backend.getProviders(); + this.suites = new DerivedOptionValue<>(this::createSuites); + this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites); + } + + private Scope debugScope; + + @Before + public void beforeTest() { + assert debugScope == null; + debugScope = Debug.scope(getClass()); + } + + @After + public void afterTest() { + if (debugScope != null) { + debugScope.close(); + } + debugScope = null; + } + + protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { + assertEquals(expected, graph, false, true); + } + + protected int countUnusedConstants(StructuredGraph graph) { + int total = 0; + for (ConstantNode node : getConstantNodes(graph)) { + if (node.hasNoUsages()) { + total++; + } + } + return total; + } + + protected int getNodeCountExcludingUnusedConstants(StructuredGraph graph) { + return graph.getNodeCount() - countUnusedConstants(graph); + } + + protected void assertEquals(StructuredGraph expected, StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) { + String expectedString = getCanonicalGraphString(expected, excludeVirtual, checkConstants); + String actualString = getCanonicalGraphString(graph, excludeVirtual, checkConstants); + String mismatchString = compareGraphStrings(expected, expectedString, graph, actualString); + + if (!excludeVirtual && getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(graph)) { + Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "Node count not matching - expected"); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Node count not matching - actual"); + Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount() + "\n" + mismatchString); + } + if (!expectedString.equals(actualString)) { + Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "mismatching graphs - expected"); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "mismatching graphs - actual"); + Assert.fail(mismatchString); + } + } + + private static String compareGraphStrings(StructuredGraph expectedGraph, String expectedString, StructuredGraph actualGraph, String actualString) { + if (!expectedString.equals(actualString)) { + String[] expectedLines = expectedString.split("\n"); + String[] actualLines = actualString.split("\n"); + int diffIndex = -1; + int limit = Math.min(actualLines.length, expectedLines.length); + String marker = " <<<"; + for (int i = 0; i < limit; i++) { + if (!expectedLines[i].equals(actualLines[i])) { + diffIndex = i; + break; + } + } + if (diffIndex == -1) { + // Prefix is the same so add some space after the prefix + diffIndex = limit; + if (actualLines.length == limit) { + actualLines = Arrays.copyOf(actualLines, limit + 1); + actualLines[diffIndex] = ""; + } else { + assert expectedLines.length == limit; + expectedLines = Arrays.copyOf(expectedLines, limit + 1); + expectedLines[diffIndex] = ""; + } + } + // Place a marker next to the first line that differs + expectedLines[diffIndex] = expectedLines[diffIndex] + marker; + actualLines[diffIndex] = actualLines[diffIndex] + marker; + String ediff = String.join("\n", expectedLines); + String adiff = String.join("\n", actualLines); + return "mismatch in graphs:\n========= expected (" + expectedGraph + ") =========\n" + ediff + "\n\n========= actual (" + actualGraph + ") =========\n" + adiff; + } else { + return "mismatch in graphs"; + } + } + + protected void assertOptimizedAway(StructuredGraph g) { + Assert.assertEquals(0, g.getNodes().filter(NotOptimizedNode.class).count()); + } + + protected void assertConstantReturn(StructuredGraph graph, int value) { + String graphString = getCanonicalGraphString(graph, false, true); + Assert.assertEquals("unexpected number of ReturnNodes: " + graphString, graph.getNodes(ReturnNode.TYPE).count(), 1); + ValueNode result = graph.getNodes(ReturnNode.TYPE).first().result(); + Assert.assertTrue("unexpected ReturnNode result node: " + graphString, result.isConstant()); + Assert.assertEquals("unexpected ReturnNode result kind: " + graphString, result.asJavaConstant().getJavaKind(), JavaKind.Int); + Assert.assertEquals("unexpected ReturnNode result: " + graphString, result.asJavaConstant().asInt(), value); + } + + protected static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) { + SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST); + schedule.apply(graph); + ScheduleResult scheduleResult = graph.getLastSchedule(); + + NodeMap canonicalId = graph.createNodeMap(); + int nextId = 0; + + List constantsLines = new ArrayList<>(); + + StringBuilder result = new StringBuilder(); + for (Block block : scheduleResult.getCFG().getBlocks()) { + result.append("Block " + block + " "); + if (block == scheduleResult.getCFG().getStartBlock()) { + result.append("* "); + } + result.append("-> "); + for (Block succ : block.getSuccessors()) { + result.append(succ + " "); + } + result.append("\n"); + for (Node node : scheduleResult.getBlockToNodesMap().get(block)) { + if (node instanceof ValueNode && node.isAlive()) { + if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof FullInfopointNode)) { + if (node instanceof ConstantNode) { + String name = checkConstants ? node.toString(Verbosity.Name) : node.getClass().getSimpleName(); + String str = name + (excludeVirtual ? "\n" : " (" + filteredUsageCount(node) + ")\n"); + constantsLines.add(str); + } else { + int id; + if (canonicalId.get(node) != null) { + id = canonicalId.get(node); + } else { + id = nextId++; + canonicalId.set(node, id); + } + String name = node.getClass().getSimpleName(); + String str = " " + id + "|" + name + (excludeVirtual ? "\n" : " (" + filteredUsageCount(node) + ")\n"); + result.append(str); + } + } + } + } + } + + StringBuilder constantsLinesResult = new StringBuilder(); + constantsLinesResult.append(constantsLines.size() + " constants:\n"); + Collections.sort(constantsLines); + for (String s : constantsLines) { + constantsLinesResult.append(s); + constantsLinesResult.append("\n"); + } + + return constantsLines.toString() + result.toString(); + } + + /** + * @return usage count excluding {@link FrameState} usages + */ + private static int filteredUsageCount(Node node) { + return node.usages().filter(n -> !(n instanceof FrameState)).count(); + } + + /** + * @param graph + * @return a scheduled textual dump of {@code graph} . + */ + protected static String getScheduledGraphString(StructuredGraph graph) { + SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST); + schedule.apply(graph); + ScheduleResult scheduleResult = graph.getLastSchedule(); + + StringBuilder result = new StringBuilder(); + Block[] blocks = scheduleResult.getCFG().getBlocks(); + for (Block block : blocks) { + result.append("Block " + block + " "); + if (block == scheduleResult.getCFG().getStartBlock()) { + result.append("* "); + } + result.append("-> "); + for (Block succ : block.getSuccessors()) { + result.append(succ + " "); + } + result.append("\n"); + for (Node node : scheduleResult.getBlockToNodesMap().get(block)) { + result.append(String.format("%1S\n", node)); + } + } + return result.toString(); + } + + protected Backend getBackend() { + return backend; + } + + protected Suites getSuites() { + return suites.getValue(); + } + + protected LIRSuites getLIRSuites() { + return lirSuites.getValue(); + } + + protected final Providers getProviders() { + return providers; + } + + protected HighTierContext getDefaultHighTierContext() { + return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); + } + + protected SnippetReflectionProvider getSnippetReflection() { + return Graal.getRequiredCapability(SnippetReflectionProvider.class); + } + + protected TargetDescription getTarget() { + return getTargetProvider().getTarget(); + } + + protected TargetProvider getTargetProvider() { + return getBackend(); + } + + protected CodeCacheProvider getCodeCache() { + return getProviders().getCodeCache(); + } + + protected ConstantReflectionProvider getConstantReflection() { + return getProviders().getConstantReflection(); + } + + protected MetaAccessProvider getMetaAccess() { + return getProviders().getMetaAccess(); + } + + protected LoweringProvider getLowerer() { + return getProviders().getLowerer(); + } + + protected CompilationIdentifier getCompilationId(ResolvedJavaMethod method) { + return getBackend().getCompilationIdentifier(method); + } + + protected CompilationIdentifier getOrCreateCompilationId(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) { + if (graph != null) { + return graph.compilationId(); + } + return getCompilationId(installedCodeOwner); + } + + protected void testN(int n, final String name, final Object... args) { + final List errors = new ArrayList<>(n); + Thread[] threads = new Thread[n]; + for (int i = 0; i < n; i++) { + Thread t = new Thread(i + ":" + name) { + + @Override + public void run() { + try { + test(name, args); + } catch (Throwable e) { + errors.add(e); + } + } + }; + threads[i] = t; + t.start(); + } + for (int i = 0; i < n; i++) { + try { + threads[i].join(); + } catch (InterruptedException e) { + errors.add(e); + } + } + if (!errors.isEmpty()) { + throw new MultiCauseAssertionError(errors.size() + " failures", errors.toArray(new Throwable[errors.size()])); + } + } + + protected Object referenceInvoke(ResolvedJavaMethod method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + return invoke(method, receiver, args); + } + + protected static class Result { + + public final Object returnValue; + public final Throwable exception; + + public Result(Object returnValue, Throwable exception) { + this.returnValue = returnValue; + this.exception = exception; + } + + @Override + public String toString() { + return exception == null ? returnValue == null ? "null" : returnValue.toString() : "!" + exception; + } + } + + /** + * Called before a test is executed. + */ + protected void before(@SuppressWarnings("unused") ResolvedJavaMethod method) { + } + + /** + * Called after a test is executed. + */ + protected void after() { + } + + protected Result executeExpected(ResolvedJavaMethod method, Object receiver, Object... args) { + before(method); + try { + // This gives us both the expected return value as well as ensuring that the method to + // be compiled is fully resolved + return new Result(referenceInvoke(method, receiver, args), null); + } catch (InvocationTargetException e) { + return new Result(null, e.getTargetException()); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + after(); + } + } + + protected Result executeActual(ResolvedJavaMethod method, Object receiver, Object... args) { + before(method); + Object[] executeArgs = argsWithReceiver(receiver, args); + + checkArgs(method, executeArgs); + + InstalledCode compiledMethod = getCode(method); + try { + return new Result(compiledMethod.executeVarargs(executeArgs), null); + } catch (Throwable e) { + return new Result(null, e); + } finally { + after(); + } + } + + protected void checkArgs(ResolvedJavaMethod method, Object[] args) { + JavaType[] sig = method.toParameterTypes(); + Assert.assertEquals(sig.length, args.length); + for (int i = 0; i < args.length; i++) { + JavaType javaType = sig[i]; + JavaKind kind = javaType.getJavaKind(); + Object arg = args[i]; + if (kind == JavaKind.Object) { + if (arg != null && javaType instanceof ResolvedJavaType) { + ResolvedJavaType resolvedJavaType = (ResolvedJavaType) javaType; + Assert.assertTrue(resolvedJavaType + " from " + getMetaAccess().lookupJavaType(arg.getClass()), resolvedJavaType.isAssignableFrom(getMetaAccess().lookupJavaType(arg.getClass()))); + } + } else { + Assert.assertNotNull(arg); + Assert.assertEquals(kind.toBoxedJavaClass(), arg.getClass()); + } + } + } + + /** + * Prepends a non-null receiver argument to a given list or args. + * + * @param receiver the receiver argument to prepend if it is non-null + */ + protected Object[] argsWithReceiver(Object receiver, Object... args) { + Object[] executeArgs; + if (receiver == null) { + executeArgs = args; + } else { + executeArgs = new Object[args.length + 1]; + executeArgs[0] = receiver; + for (int i = 0; i < args.length; i++) { + executeArgs[i + 1] = args[i]; + } + } + return applyArgSuppliers(executeArgs); + } + + protected void test(String name, Object... args) { + try { + ResolvedJavaMethod method = getResolvedJavaMethod(name); + Object receiver = method.isStatic() ? null : this; + test(method, receiver, args); + } catch (AssumptionViolatedException e) { + // Suppress so that subsequent calls to this method within the + // same Junit @Test annotated method can proceed. + } + } + + /** + * Type denoting a lambda that supplies a fresh value each time it is called. This is useful + * when supplying an argument to {@link GraalCompilerTest#test(String, Object...)} where the + * test modifies the state of the argument (e.g., updates a field). + */ + @FunctionalInterface + public interface ArgSupplier extends Supplier { + } + + /** + * Convenience method for using an {@link ArgSupplier} lambda in a varargs list. + */ + public static Object supply(ArgSupplier supplier) { + return supplier; + } + + protected void test(ResolvedJavaMethod method, Object receiver, Object... args) { + Result expect = executeExpected(method, receiver, args); + if (getCodeCache() == null) { + return; + } + testAgainstExpected(method, expect, receiver, args); + } + + /** + * Process a given set of arguments, converting any {@link ArgSupplier} argument to the argument + * it supplies. + */ + protected Object[] applyArgSuppliers(Object... args) { + Object[] res = args; + for (int i = 0; i < args.length; i++) { + if (args[i] instanceof ArgSupplier) { + if (res == args) { + res = args.clone(); + } + res[i] = ((ArgSupplier) args[i]).get(); + } + } + return res; + } + + protected void testAgainstExpected(ResolvedJavaMethod method, Result expect, Object receiver, Object... args) { + testAgainstExpected(method, expect, Collections. emptySet(), receiver, args); + } + + protected Result executeActualCheckDeopt(ResolvedJavaMethod method, Set shouldNotDeopt, Object receiver, Object... args) { + Map deoptCounts = new EnumMap<>(DeoptimizationReason.class); + ProfilingInfo profile = method.getProfilingInfo(); + for (DeoptimizationReason reason : shouldNotDeopt) { + deoptCounts.put(reason, profile.getDeoptimizationCount(reason)); + } + Result actual = executeActual(method, receiver, args); + profile = method.getProfilingInfo(); // profile can change after execution + for (DeoptimizationReason reason : shouldNotDeopt) { + Assert.assertEquals((int) deoptCounts.get(reason), profile.getDeoptimizationCount(reason)); + } + return actual; + } + + protected void assertEquals(Result expect, Result actual) { + if (expect.exception != null) { + Assert.assertTrue("expected " + expect.exception, actual.exception != null); + Assert.assertEquals("Exception class", expect.exception.getClass(), actual.exception.getClass()); + Assert.assertEquals("Exception message", expect.exception.getMessage(), actual.exception.getMessage()); + } else { + if (actual.exception != null) { + throw new AssertionError("expected " + expect.returnValue + " but got an exception", actual.exception); + } + assertDeepEquals(expect.returnValue, actual.returnValue); + } + } + + protected void testAgainstExpected(ResolvedJavaMethod method, Result expect, Set shouldNotDeopt, Object receiver, Object... args) { + Result actual = executeActualCheckDeopt(method, shouldNotDeopt, receiver, args); + assertEquals(expect, actual); + } + + private Map cache = new HashMap<>(); + + /** + * Gets installed code for a given method, compiling it first if necessary. The graph is parsed + * {@link #parseEager(ResolvedJavaMethod, AllowAssumptions) eagerly}. + */ + protected InstalledCode getCode(ResolvedJavaMethod method) { + return getCode(method, null); + } + + /** + * Gets installed code for a given method, compiling it first if necessary. + * + * @param installedCodeOwner the method the compiled code will be associated with when installed + * @param graph the graph to be compiled. If null, a graph will be obtained from + * {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}. + */ + protected InstalledCode getCode(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) { + return getCode(installedCodeOwner, graph, false); + } + + protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph0, boolean forceCompile) { + return getCode(installedCodeOwner, graph0, forceCompile, false); + } + + /** + * Gets installed code for a given method and graph, compiling it first if necessary. + * + * @param installedCodeOwner the method the compiled code will be associated with when installed + * @param graph the graph to be compiled. If null, a graph will be obtained from + * {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}. + * @param forceCompile specifies whether to ignore any previous code cached for the (method, + * key) pair + * @param installDefault specifies whether to install as the default implementation + */ + @SuppressWarnings("try") + protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installDefault) { + if (!forceCompile) { + InstalledCode cached = cache.get(installedCodeOwner); + if (cached != null) { + if (cached.isValid()) { + return cached; + } + } + } + + final CompilationIdentifier id = getOrCreateCompilationId(installedCodeOwner, graph); + + InstalledCode installedCode = null; + try (AllocSpy spy = AllocSpy.open(installedCodeOwner); Scope ds = Debug.scope("Compiling", new DebugDumpScope(id.toString(CompilationIdentifier.Verbosity.ID), true))) { + final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed(); + if (printCompilation) { + TTY.println(String.format("@%-6s Graal %-70s %-45s %-50s ...", id, installedCodeOwner.getDeclaringClass().getName(), installedCodeOwner.getName(), installedCodeOwner.getSignature())); + } + long start = System.currentTimeMillis(); + CompilationResult compResult = compile(installedCodeOwner, graph, id); + if (printCompilation) { + TTY.println(String.format("@%-6s Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize())); + } + + try (Scope s = Debug.scope("CodeInstall", getCodeCache(), installedCodeOwner, compResult)) { + if (installDefault) { + installedCode = addDefaultMethod(installedCodeOwner, compResult); + } else { + installedCode = addMethod(installedCodeOwner, compResult); + } + if (installedCode == null) { + throw new GraalError("Could not install code for " + installedCodeOwner.format("%H.%n(%p)")); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + + if (!forceCompile) { + cache.put(installedCodeOwner, installedCode); + } + return installedCode; + } + + /** + * Used to produce a graph for a method about to be compiled by + * {@link #compile(ResolvedJavaMethod, StructuredGraph)} if the second parameter to that method + * is null. + * + * The default implementation in {@link GraalCompilerTest} is to call + * {@link #parseEager(ResolvedJavaMethod, AllowAssumptions)}. + */ + protected final StructuredGraph parseForCompile(ResolvedJavaMethod method) { + return parseEager(method, AllowAssumptions.YES); + } + + protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId) { + return parseEager(method, AllowAssumptions.YES, compilationId); + } + + /** + * Compiles a given method. + * + * @param installedCodeOwner the method the compiled code will be associated with when installed + * @param graph the graph to be compiled for {@code installedCodeOwner}. If null, a graph will + * be obtained from {@code installedCodeOwner} via + * {@link #parseForCompile(ResolvedJavaMethod)}. + */ + protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) { + return compile(installedCodeOwner, graph, getOrCreateCompilationId(installedCodeOwner, graph)); + } + + protected CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationIdentifier compilationId) { + return compile(installedCodeOwner, graph, new CompilationResult(), compilationId); + } + + /** + * Compiles a given method. + * + * @param installedCodeOwner the method the compiled code will be associated with when installed + * @param graph the graph to be compiled for {@code installedCodeOwner}. If null, a graph will + * be obtained from {@code installedCodeOwner} via + * {@link #parseForCompile(ResolvedJavaMethod)}. + * @param compilationResult + * @param compilationId + */ + @SuppressWarnings("try") + protected CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationResult compilationResult, CompilationIdentifier compilationId) { + StructuredGraph graphToCompile = graph == null ? parseForCompile(installedCodeOwner, compilationId) : graph; + lastCompiledGraph = graphToCompile; + try (Scope s = Debug.scope("Compile", graphToCompile)) { + Request request = new Request<>(graphToCompile, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, + graphToCompile.getProfilingInfo(), getSuites(), getLIRSuites(), compilationResult, CompilationResultBuilderFactory.Default); + return GraalCompiler.compile(request); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + protected StructuredGraph lastCompiledGraph; + + protected SpeculationLog getSpeculationLog() { + return null; + } + + protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult compilationResult) { + return backend.addInstalledCode(method, null, compilationResult); + } + + protected InstalledCode addDefaultMethod(final ResolvedJavaMethod method, final CompilationResult compilationResult) { + return backend.createDefaultInstalledCode(method, compilationResult); + } + + private final Map methodMap = new HashMap<>(); + + /** + * Converts a reflection {@link Method} to a {@link ResolvedJavaMethod}. + */ + protected ResolvedJavaMethod asResolvedJavaMethod(Method method) { + ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method); + methodMap.put(javaMethod, method); + return javaMethod; + } + + protected ResolvedJavaMethod getResolvedJavaMethod(String methodName) { + return asResolvedJavaMethod(getMethod(methodName)); + } + + protected ResolvedJavaMethod getResolvedJavaMethod(Class clazz, String methodName) { + return asResolvedJavaMethod(getMethod(clazz, methodName)); + } + + protected ResolvedJavaMethod getResolvedJavaMethod(Class clazz, String methodName, Class... parameterTypes) { + return asResolvedJavaMethod(getMethod(clazz, methodName, parameterTypes)); + } + + /** + * Gets the reflection {@link Method} from which a given {@link ResolvedJavaMethod} was created + * or null if {@code javaMethod} does not correspond to a reflection method. + */ + protected Method lookupMethod(ResolvedJavaMethod javaMethod) { + return methodMap.get(javaMethod); + } + + protected Object invoke(ResolvedJavaMethod javaMethod, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Method method = lookupMethod(javaMethod); + Assert.assertTrue(method != null); + if (!method.isAccessible()) { + method.setAccessible(true); + } + return method.invoke(receiver, applyArgSuppliers(args)); + } + + /** + * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault default} mode to + * produce a graph. + * + * @param methodName the name of the method in {@code this.getClass()} to be parsed + */ + protected StructuredGraph parseProfiled(String methodName, AllowAssumptions allowAssumptions) { + return parseProfiled(getResolvedJavaMethod(methodName), allowAssumptions); + } + + /** + * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault default} mode to + * produce a graph. + */ + protected final StructuredGraph parseProfiled(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { + return parseProfiled(m, allowAssumptions, getCompilationId(m)); + } + + protected StructuredGraph parseProfiled(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) { + return parse1(m, getDefaultGraphBuilderSuite(), allowAssumptions, compilationId); + } + + /** + * Parses a Java method with {@linkplain GraphBuilderConfiguration#withEagerResolving(boolean)} + * set to true to produce a graph. + * + * @param methodName the name of the method in {@code this.getClass()} to be parsed + */ + protected final StructuredGraph parseEager(String methodName, AllowAssumptions allowAssumptions) { + return parseEager(getResolvedJavaMethod(methodName), allowAssumptions); + } + + /** + * Parses a Java method with {@linkplain GraphBuilderConfiguration#withEagerResolving(boolean)} + * set to true to produce a graph. + */ + protected final StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { + return parseEager(m, allowAssumptions, getCompilationId(m)); + } + + protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) { + return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true)), allowAssumptions, compilationId); + } + + /** + * Parses a Java method using {@linkplain GraphBuilderConfiguration#withFullInfopoints(boolean) + * full debug} set to true to produce a graph. + */ + protected final StructuredGraph parseDebug(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { + return parseDebug(m, allowAssumptions, getCompilationId(m)); + } + + protected StructuredGraph parseDebug(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) { + return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true)), allowAssumptions, compilationId); + } + + @SuppressWarnings("try") + private StructuredGraph parse1(ResolvedJavaMethod javaMethod, PhaseSuite graphBuilderSuite, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) { + assert javaMethod.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + javaMethod; + StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions, getSpeculationLog(), compilationId); + try (Scope ds = Debug.scope("Parsing", javaMethod, graph)) { + graphBuilderSuite.apply(graph, getDefaultHighTierContext()); + return graph; + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + protected Plugins getDefaultGraphBuilderPlugins() { + PhaseSuite suite = backend.getSuites().getDefaultGraphBuilderSuite(); + Plugins defaultPlugins = ((GraphBuilderPhase) suite.findPhase(GraphBuilderPhase.class).previous()).getGraphBuilderConfig().getPlugins(); + // defensive copying + return new Plugins(defaultPlugins); + } + + protected PhaseSuite getDefaultGraphBuilderSuite() { + // defensive copying + return backend.getSuites().getDefaultGraphBuilderSuite().copy(); + } + + protected PhaseSuite getCustomGraphBuilderSuite(GraphBuilderConfiguration gbConf) { + PhaseSuite suite = getDefaultGraphBuilderSuite(); + ListIterator> iterator = suite.findPhase(GraphBuilderPhase.class); + GraphBuilderConfiguration gbConfCopy = editGraphBuilderConfiguration(gbConf.copy()); + iterator.remove(); + iterator.add(new GraphBuilderPhase(gbConfCopy)); + return suite; + } + + protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) { + InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins(); + invocationPlugins.register(new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + b.add(new BreakpointNode()); + return true; + } + }, GraalCompilerTest.class, "breakpoint"); + invocationPlugins.register(new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg0) { + b.add(new BreakpointNode(arg0)); + return true; + } + }, GraalCompilerTest.class, "breakpoint", int.class); + invocationPlugins.register(new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + b.add(new NotOptimizedNode()); + return true; + } + }, GraalCompilerTest.class, "shouldBeOptimizedAway"); + + conf.getPlugins().prependInlineInvokePlugin(new InlineInvokePlugin() { + + @Override + public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + BytecodeParserNeverInline neverInline = method.getAnnotation(BytecodeParserNeverInline.class); + if (neverInline != null) { + return neverInline.invokeWithException() ? DO_NOT_INLINE_WITH_EXCEPTION : DO_NOT_INLINE_NO_EXCEPTION; + } + if (method.getAnnotation(BytecodeParserForceInline.class) != null) { + return InlineInfo.createStandardInlineInfo(method); + } + return bytecodeParserShouldInlineInvoke(b, method, args); + } + }); + return conf; + } + + /** + * Supplements {@link BytecodeParserForceInline} and {@link BytecodeParserNeverInline} in terms + * of allowing a test to influence the inlining decision made during bytecode parsing. + * + * @see InlineInvokePlugin#shouldInlineInvoke(GraphBuilderContext, ResolvedJavaMethod, + * ValueNode[]) + */ + @SuppressWarnings("unused") + protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + return null; + } + + @NodeInfo + public static class NotOptimizedNode extends FixedWithNextNode { + private static final NodeClass TYPE = NodeClass.create(NotOptimizedNode.class); + + protected NotOptimizedNode() { + super(TYPE, StampFactory.forVoid()); + } + + } + + protected Replacements getReplacements() { + return getProviders().getReplacements(); + } + + /** + * Inject a probability for a branch condition into the profiling information of this test case. + * + * @param p the probability that cond is true + * @param cond the condition of the branch + * @return cond + */ + protected static boolean branchProbability(double p, boolean cond) { + return GraalDirectives.injectBranchProbability(p, cond); + } + + /** + * Inject an iteration count for a loop condition into the profiling information of this test + * case. + * + * @param i the iteration count of the loop + * @param cond the condition of the loop + * @return cond + */ + protected static boolean iterationCount(double i, boolean cond) { + return GraalDirectives.injectIterationCount(i, cond); + } + + /** + * Test if the current test runs on the given platform. The name must match the name given in + * the {@link Architecture#getName()}. + * + * @param name The name to test + * @return true if we run on the architecture given by name + */ + protected boolean isArchitecture(String name) { + return name.equals(backend.getTarget().arch.getName()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java 2016-12-07 13:48:22.533503057 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.EncodedGraph; +import org.graalvm.compiler.nodes.GraphEncoder; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class GraphEncoderTest extends GraalCompilerTest { + + @Test + public void test01() { + testStringMethods(false); + } + + @Test + public void test02() { + testStringMethods(true); + } + + public void testStringMethods(boolean canonicalize) { + /* Encode and decode all methods of java.lang.String. */ + List originalGraphs = new ArrayList<>(); + for (Method method : String.class.getDeclaredMethods()) { + ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method); + if (javaMethod.hasBytecodes()) { + StructuredGraph originalGraph = parseEager(javaMethod, AllowAssumptions.YES); + if (canonicalize) { + PhaseContext context = new PhaseContext(getProviders()); + new CanonicalizerPhase().apply(originalGraph, context); + } + originalGraphs.add(originalGraph); + } + } + + GraphEncoder encoder = new GraphEncoder(getTarget().arch); + for (StructuredGraph originalGraph : originalGraphs) { + encoder.prepare(originalGraph); + } + encoder.finishPrepare(); + Map startOffsets = new HashMap<>(); + for (StructuredGraph originalGraph : originalGraphs) { + startOffsets.put(originalGraph, encoder.encode(originalGraph)); + } + + for (StructuredGraph originalGraph : originalGraphs) { + EncodedGraph encodedGraph = new EncodedGraph(encoder.getEncoding(), startOffsets.get(originalGraph), encoder.getObjects(), encoder.getNodeClasses(), originalGraph.getAssumptions(), + originalGraph.getMethods()); + GraphEncoder.verifyEncoding(originalGraph, encodedGraph, getTarget().arch); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java 2016-12-07 13:48:22.799514750 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import java.util.List; + +import org.junit.Assert; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeMap; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.phases.schedule.SchedulePhase; + +public class GraphScheduleTest extends GraalCompilerTest { + + protected void assertOrderedAfterSchedule(StructuredGraph graph, Node a, Node b) { + SchedulePhase ibp = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST); + ibp.apply(graph); + assertOrderedAfterSchedule(graph.getLastSchedule(), a, b); + } + + protected void assertOrderedAfterSchedule(ScheduleResult ibp, Node a, Node b) { + NodeMap nodeToBlock = ibp.getCFG().getNodeToBlock(); + Block bBlock = nodeToBlock.get(b); + Block aBlock = nodeToBlock.get(a); + + if (bBlock == aBlock) { + List instructions = ibp.nodesFor(bBlock); + Assert.assertTrue(instructions.indexOf(b) > instructions.indexOf(a)); + } else { + Block block = bBlock; + while (block != null) { + if (block == aBlock) { + return; + } + block = block.getDominator(); + } + Assert.fail("block of A doesn't dominate the block of B"); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardEliminationCornerCasesTest.java 2016-12-07 13:48:23.063526356 -0800 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.BeginNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.GuardNode; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.java.InstanceOfNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.spi.ValueProxy; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase; +import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +public class GuardEliminationCornerCasesTest extends GraalCompilerTest { + + static class A { + + } + + static class B extends A { + + } + + static class C extends B { + + } + + static class D extends C { + + } + + @SuppressWarnings({"static-method", "unused"}) + private int testMethod(Object a) { + if (a instanceof A) { + if (a instanceof C) { + if (a instanceof B) { + B b = (B) a; + if (b instanceof C) { + return 1; + } else { + GraalDirectives.deoptimizeAndInvalidate(); + } + } + } else { + GraalDirectives.deoptimizeAndInvalidate(); + } + } + return 0; + } + + @Test + public void testFloatingGuards() { + HighTierContext context = getDefaultHighTierContext(); + StructuredGraph graph = parseEager("testMethod", AllowAssumptions.YES); + new ConvertDeoptimizeToGuardPhase().apply(graph, context); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after parsing"); + + GuardNode myGuardNode = null; + for (Node n : graph.getNodes()) { + if (n instanceof GuardNode) { + GuardNode guardNode = (GuardNode) n; + LogicNode condition = guardNode.getCondition(); + if (condition instanceof InstanceOfNode) { + InstanceOfNode instanceOfNode = (InstanceOfNode) condition; + if (instanceOfNode.getValue() instanceof ValueProxy) { + myGuardNode = guardNode; + break; + } + } + } + } + + AbstractBeginNode myBegin = (AbstractBeginNode) myGuardNode.getAnchor(); + AbstractBeginNode prevBegin = BeginNode.prevBegin((FixedNode) myBegin.predecessor()); + myGuardNode.setAnchor(prevBegin); + + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after manual modification"); + graph.reverseUsageOrder(); + new DominatorConditionalEliminationPhase(true).apply(graph, context); + new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST).apply(graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java 2016-12-07 13:48:23.329538049 -0800 @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import java.util.List; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.debug.OpaqueNode; +import org.graalvm.compiler.nodes.extended.LoadHubNode; +import org.graalvm.compiler.nodes.extended.LoadMethodNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Tests use of an intrinsic for virtual methods where the call site is indirect. A prime example is + * an intrinsic for {@link Object#hashCode()}. The intrinsic can only be used if the call site would + * actually dispatch to {@link Object#hashCode()} and not a method that overrides it. + */ +public class GuardedIntrinsicTest extends GraalCompilerTest { + + static class Super { + int getAge() { + return 11; + } + } + + public static class Person extends Super { + int age; + + public Person(int age) { + this.age = age; + } + + @Override + public int getAge() { + return age; + } + } + + @BytecodeParserForceInline + public static final Super createSuper() { + return new Super(); + } + + @BytecodeParserNeverInline + public static final Super createPerson() { + return new Person(42); + } + + public static int getSuperAge(Super s) { + return s.getAge(); + } + + public static int getPersonAge(Person p) { + return p.getAge(); + } + + public static int makeSuperAge() { + return createSuper().getAge(); + } + + public static int makePersonAge() { + return createPerson().getAge(); + } + + @BeforeClass + public static void init() { + // Ensure classes are initialized + new Person(0).toString(); + } + + private StructuredGraph graph; + private StructuredGraph parsedForCompile; + + @Override + protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId) { + graph = super.parseForCompile(method, compilationId); + parsedForCompile = (StructuredGraph) graph.copy(); + return graph; + } + + @Override + protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) { + InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins(); + Registration r = new Registration(invocationPlugins, Super.class); + + r.register1("getAge", Receiver.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + ConstantNode res = b.add(ConstantNode.forInt(new Super().getAge())); + b.add(new OpaqueNode(res)); + b.push(JavaKind.Int, res); + return true; + } + }); + return super.editGraphBuilderConfiguration(conf); + } + + public static int referenceMakeSuperAge() { + return 11; + } + + public static int referenceMakePersonAge() { + return 42; + } + + @Test + public void test01() { + Super inheritsHC = new Super(); + Person overridesHC = new Person(0); + test("getSuperAge", inheritsHC); + test("getSuperAge", overridesHC); + + // Check that the virtual dispatch test exists after bytecode parsing + Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadMethodNode.class).count()); + Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadHubNode.class).count()); + + // Check for the marker node indicating the intrinsic was applied + Assert.assertEquals(1, parsedForCompile.getNodes().filter(OpaqueNode.class).count()); + + // Final graph should have a single invoke + List invokes = graph.getNodes().filter(n -> n instanceof Invoke).snapshot(); + Assert.assertEquals(invokes.toString(), 1, invokes.size()); + } + + @Test + public void test02() { + test("getPersonAge", new Person(0)); + + // Check that the virtual dispatch test does not exist after bytecode parsing + Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadMethodNode.class).count()); + Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadHubNode.class).count()); + + Assert.assertEquals(0, parsedForCompile.getNodes().filter(InvokeNode.class).count()); + } + + @Test + public void test03() { + test("makeSuperAge"); + + // Check that the virtual dispatch test does not exist after bytecode parsing + Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadMethodNode.class).count()); + Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadHubNode.class).count()); + + StructuredGraph referenceGraph = parseEager("referenceMakeSuperAge", AllowAssumptions.NO); + assertEquals(referenceGraph, graph, true, true); + } + + @Test + public void test04() { + test("makePersonAge"); + + // Check that the virtual dispatch test exists after bytecode parsing + Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadMethodNode.class).count()); + Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadHubNode.class).count()); + + StructuredGraph referenceGraph = parseEager("referenceMakePersonAge", AllowAssumptions.NO); + assertEquals(referenceGraph, graph, true, true); + } + + static final class ReadCacheEntry { + + public final Object identity; + public final ValueNode object; + + ReadCacheEntry(Object identity, ValueNode object) { + this.identity = identity; + this.object = object; + } + + @Override + public int hashCode() { + int result = ((identity == null) ? 0 : identity.hashCode()); + return result + object.hashCode(); + } + } + + public static int getHashCode(ReadCacheEntry obj) { + return obj.hashCode(); + } + + @Test + public void test05() { + ReadCacheEntry val1 = new ReadCacheEntry("identity", ConstantNode.forBoolean(false)); + ReadCacheEntry val2 = new ReadCacheEntry(Integer.valueOf(34), ConstantNode.forInt(42)); + for (int i = 0; i < 10000; i++) { + getHashCode(val2); + } + test("getHashCode", val1); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashCodeTest.java 2016-12-07 13:48:23.600549962 -0800 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.core.phases.HighTier; +import org.graalvm.compiler.core.phases.MidTier; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.LoadHubNode; +import org.graalvm.compiler.nodes.extended.LoadMethodNode; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.tiers.MidTierContext; + +public class HashCodeTest extends GraalCompilerTest { + + static class OverrideHashCode { + @Override + public int hashCode() { + return 42; + } + } + + static final class DontOverrideHashCode { + } + + public static final Object NonOverridingConstant = new Object(); + public static final Object OverridingConstant = new OverrideHashCode(); + + private static void initialize(Class c) { + try { + Class.forName(c.getName(), true, c.getClassLoader()); + } catch (ClassNotFoundException e) { + throw new AssertionError(e); + } + } + + public static final int hashCodeSnippet01(Object o) { + return o.hashCode(); + } + + public static final int systemIdentityHashCodeSnippet01(Object o) { + return System.identityHashCode(o); + } + + public static final int hashCodeFoldSnippet01() { + return NonOverridingConstant.hashCode(); + } + + public static final int identityHashCodeFoldSnippet01() { + return System.identityHashCode(NonOverridingConstant); + } + + public static final int hashCodeNoFoldOverridingSnippet01(Object o) { + return o.hashCode(); + } + + public static final int identityHashCodeFoldOverridingSnippet01() { + return System.identityHashCode(OverridingConstant); + } + + public static final int dontOverrideHashCodeFinalClass(DontOverrideHashCode o) { + return o.hashCode(); + } + + @Test + public void test01() { + test("hashCodeSnippet01", new Object()); + } + + @Test + public void test02() { + test("systemIdentityHashCodeSnippet01", new Object()); + } + + @Test + public void test03() { + StructuredGraph g = buildGraphAfterMidTier("hashCodeFoldSnippet01"); + Assert.assertEquals(0, g.getNodes().filter(InvokeNode.class).count()); + } + + @Test + public void test04() { + StructuredGraph g = buildGraphAfterMidTier("identityHashCodeFoldSnippet01"); + Assert.assertEquals(0, g.getNodes().filter(InvokeNode.class).count()); + } + + @Test + public void test05() { + checkForGuardedIntrinsicPattern("hashCodeNoFoldOverridingSnippet01"); + + Object nullObject = null; + test("hashCodeNoFoldOverridingSnippet01", nullObject); + test("hashCodeNoFoldOverridingSnippet01", new Object()); + test("hashCodeNoFoldOverridingSnippet01", new DontOverrideHashCode()); + } + + @Test + public void test06() { + StructuredGraph g = buildGraphAfterMidTier("identityHashCodeFoldOverridingSnippet01"); + Assert.assertEquals(0, g.getNodes().filter(InvokeNode.class).count()); + } + + @Test + public void test07() { + initialize(DontOverrideHashCode.class); + StructuredGraph g = buildGraphAfterMidTier("dontOverrideHashCodeFinalClass"); + Assert.assertEquals(0, g.getNodes().filter(InvokeNode.class).count()); + } + + public static final int hashCodeInterface(Appendable o) { + return o.hashCode(); + } + + @Test + public void test08() { + initialize(Appendable.class); + checkForGuardedIntrinsicPattern("hashCodeInterface"); + checkForGuardedIntrinsicPattern("hashCodeSnippet01"); + } + + private void checkForGuardedIntrinsicPattern(String name) { + StructuredGraph g = parseForCompile(getResolvedJavaMethod(name)); + Assert.assertEquals(1, g.getNodes().filter(InvokeNode.class).count()); + Assert.assertEquals(1, g.getNodes().filter(LoadHubNode.class).count()); + Assert.assertEquals(1, g.getNodes().filter(LoadMethodNode.class).count()); + } + + @SuppressWarnings("try") + private StructuredGraph buildGraphAfterMidTier(String name) { + StructuredGraph g = parseForCompile(getResolvedJavaMethod(name)); + new HighTier().apply(g, getDefaultHighTierContext()); + new MidTier().apply(g, new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, g.getProfilingInfo())); + return g; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java 2016-12-07 13:48:23.864561567 -0800 @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2011, 2015, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase; +import org.graalvm.compiler.phases.common.GuardLoweringPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.ValueAnchorCleanupPhase; +import org.graalvm.compiler.phases.tiers.MidTierContext; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/** + * In the following tests, the usages of local variable "a" are replaced with the integer constant + * 0. Then canonicalization is applied and it is verified that the resulting graph is equal to the + * graph of the method that just has a "return 1" statement in it. + */ +public class IfCanonicalizerTest extends GraalCompilerTest { + + private static final String REFERENCE_SNIPPET = "referenceSnippet"; + + @SuppressWarnings("all") + public static int referenceSnippet(int a) { + return 1; + } + + @Test + public void test1() { + test("test1Snippet"); + } + + @SuppressWarnings("all") + public static int test1Snippet(int a) { + if (a == 0) { + return 1; + } else { + return 2; + } + } + + @Test + public void test2() { + test("test2Snippet"); + } + + @SuppressWarnings("all") + public static int test2Snippet(int a) { + if (a == 0) { + if (a == 0) { + if (a == 0) { + return 1; + } + } + } else { + return 2; + } + return 3; + } + + @Test + public void test3() { + test("test3Snippet"); + } + + @SuppressWarnings("all") + public static int test3Snippet(int a) { + if (a == 0) { + if (a != 1) { + if (a == 1) { + return 3; + } else { + if (a >= 0) { + if (a <= 0) { + if (a > -1) { + if (a < 1) { + return 1; + } + } + } + } + } + } + } else { + return 2; + } + return 3; + } + + @Test + public void test4() { + test("test4Snippet"); + } + + public static int test4Snippet(int a) { + if (a == 0) { + return 1; + } + return 1; + } + + @Test + public void test5() { + test("test5Snippet"); + } + + public static int test5Snippet(int a) { + int val = 2; + if (a == 0) { + val = 1; + } + if (a * (3 + val) == 0) { + return 1; + } + return 1; + } + + @Test + public void test6() { + testCombinedIf("test6Snippet", 3); + test("test6Snippet", new int[]{0}); + } + + public static int test6Snippet(int[] a) { + int i = a[0]; + if (i >= 0 && i < a.length) { + return a[i]; + } + return 1; + } + + @Test + public void test7() { + testCombinedIf("test7Snippet", 1); + test("test7Snippet", -1); + } + + public static int test7Snippet(int v) { + if (v >= 0 && v < 1024) { + return v + 1; + } + return v - 1; + } + + @Test + public void test8() { + testCombinedIf("test8Snippet", 1); + test("test8Snippet", -1); + } + + public static int test8Snippet(int v) { + if (v >= 0 && v <= 1024) { + return v + 1; + } + return v - 1; + } + + @Test + public void test9() { + testCombinedIf("test9Snippet", 2); + test("test9Snippet", -1); + test("test9Snippet", 1025); + } + + public static int test9Snippet(int n) { + return (n < 0) ? 1 : (n >= 1024) ? 1024 : n + 1; + } + + private void testCombinedIf(String snippet, int count) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + PhaseContext context = new PhaseContext(getProviders()); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + new FloatingReadPhase().apply(graph); + MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); + new GuardLoweringPhase().apply(graph, midContext); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext); + new ValueAnchorCleanupPhase().apply(graph); + new CanonicalizerPhase().apply(graph, context); + assertDeepEquals(count, graph.getNodes().filter(IfNode.class).count()); + } + + private void test(String snippet) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + ParameterNode param = graph.getNodes(ParameterNode.TYPE).iterator().next(); + ConstantNode constant = ConstantNode.forInt(0, graph); + for (Node n : param.usages().snapshot()) { + if (!(n instanceof FrameState)) { + n.replaceFirstInput(param, constant); + } + } + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + for (FrameState fs : param.usages().filter(FrameState.class).snapshot()) { + fs.replaceFirstInput(param, null); + param.safeDelete(); + } + StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES); + assertEquals(referenceGraph, graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfReorderTest.java 2016-12-07 13:48:24.128573172 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +public class IfReorderTest extends GraalCompilerTest { + + private static Object fieldA = Integer.class; + private static Object fieldB = Double.class; + + @Test + public void test1() { + test("test1Snippet", new ArrayList<>()); + } + + public static Object test1Snippet(Object o) { + /* + * Serializable and List are not mutually exclusive, so these two IFs should never be + * reordered. + */ + if (branchProbability(0.1, o instanceof Serializable)) { + return fieldA; + } + if (branchProbability(0.9, o instanceof List)) { + return fieldB; + } + return null; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ImplicitNullCheckTest.java 2016-12-07 13:48:24.393584822 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011, 2015, 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.core.test; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase; +import org.graalvm.compiler.phases.common.GuardLoweringPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.tiers.MidTierContext; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/** + * Tests that the hub access and the null check are folded. + */ +public class ImplicitNullCheckTest extends GraphScheduleTest { + + public static final class Receiver { + + public int a; + } + + public static int test1Snippet(Object o) { + if (GraalDirectives.guardingNonNull(o) instanceof Receiver) { + return 42; + } + return 0; + } + + @Ignore("temporarily disable until LoadHub lowering is clarified") + @Test + public void test1() { + test("test1Snippet"); + } + + @SuppressWarnings("try") + private void test(final String snippet) { + try (Scope s = Debug.scope("FloatingReadTest", new DebugDumpScope(snippet))) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + PhaseContext context = new PhaseContext(getProviders()); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + new FloatingReadPhase().apply(graph); + MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); + new GuardLoweringPhase().apply(graph, midTierContext); + + Assert.assertEquals(0, graph.getNodes(DeoptimizeNode.TYPE).count()); + Assert.assertTrue(graph.getNodes().filter(ReadNode.class).first().canNullCheck()); + + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java 2016-12-07 13:48:24.658596471 -0800 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2013, 2016, 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.core.test; + +import static org.graalvm.compiler.core.GraalCompiler.compileGraph; +import static org.graalvm.compiler.core.common.GraalOptions.OptAssumptions; +import static org.junit.Assert.assertNotNull; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.code.site.InfopointReason; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Test; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.nodes.FullInfopointNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +/** + * Test that infopoints in {@link CompilationResult}s have correctly assigned reasons. + */ +public class InfopointReasonTest extends GraalCompilerTest { + + public static final String[] STRINGS = new String[]{"world", "everyone", "you"}; + + public String testMethod() { + StringBuilder sb = new StringBuilder("Hello "); + for (String s : STRINGS) { + sb.append(s).append(", "); + } + sb.replace(sb.length() - 2, sb.length(), "!"); + return sb.toString(); + } + + @Test + public void callInfopoints() { + final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod"); + final StructuredGraph graph = parseEager(method, AllowAssumptions.YES); + final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(), + getSuites(), getLIRSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default); + for (Infopoint sp : cr.getInfopoints()) { + assertNotNull(sp.reason); + if (sp instanceof Call) { + assertDeepEquals(InfopointReason.CALL, sp.reason); + } + } + } + + @Test + public void lineInfopoints() { + final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod"); + final StructuredGraph graph = parseDebug(method, AllowAssumptions.from(OptAssumptions.getValue())); + int graphLineSPs = 0; + for (FullInfopointNode ipn : graph.getNodes().filter(FullInfopointNode.class)) { + if (ipn.getReason() == InfopointReason.BYTECODE_POSITION) { + ++graphLineSPs; + } + } + assertTrue(graphLineSPs > 0); + PhaseSuite graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true)); + final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), graphBuilderSuite, OptimisticOptimizations.ALL, graph.getProfilingInfo(), getSuites(), + getLIRSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default); + int lineSPs = 0; + for (Infopoint sp : cr.getInfopoints()) { + assertNotNull(sp.reason); + if (sp.reason == InfopointReason.BYTECODE_POSITION) { + ++lineSPs; + } + } + assertTrue(lineSPs > 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InstalledCodeInvalidationTest.java 2016-12-07 13:48:24.923608120 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, 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.core.test; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; + +public class InstalledCodeInvalidationTest extends GraalCompilerTest { + + public void recurse(InstalledCode code, int depth) throws InvalidInstalledCodeException { + if (depth > 1) { + /* + * Recurse a few times to ensure there are multiple activations. + */ + code.executeVarargs(this, code, depth - 1); + } else { + /* + * Deoptimize this activation and make the compiled code no longer usable. + */ + + GraalDirectives.deoptimizeAndInvalidate(); + assert code.isAlive() && !code.isValid(); + code.invalidate(); + assert !code.isAlive(); + } + if (GraalDirectives.inCompiledCode()) { + /* + * If this still in compiled code then the deoptimizeAndInvalidate call above didn't + * remove all existing activations. + */ + throw new InternalError(); + } + } + + /** + * Test that after uncommon trapping in an installed code it's still possible to invalidate all + * existing activations of that installed code. + * + * @throws InvalidInstalledCodeException + */ + @Test + public void testInstalledCodeInvalidation() throws InvalidInstalledCodeException { + InstalledCode code = getCode(getMetaAccess().lookupJavaMethod(getMethod("recurse"))); + code.executeVarargs(this, code, 3); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerEqualsCanonicalizerTest.java 2016-12-07 13:48:25.188619769 -0800 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2011, 2015, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class IntegerEqualsCanonicalizerTest extends GraalCompilerTest { + + @Test + public void testSubtractEqualsZero() { + test("testSubtractEqualsZeroSnippet", "testSubtractEqualsZeroReference"); + } + + public static int testSubtractEqualsZeroReference(int a, int b) { + if (a == b) { + return 1; + } + return 0; + } + + public static int testSubtractEqualsZeroSnippet(int a, int b) { + if (a - b == 0) { + return 1; + } + return 0; + } + + @Test + public void testSubtractEqualsZeroLong() { + test("testSubtractEqualsZeroLongSnippet", "testSubtractEqualsZeroLongReference"); + } + + public static int testSubtractEqualsZeroLongReference(long a, long b) { + if (a == b) { + return 1; + } + return 0; + } + + public static int testSubtractEqualsZeroLongSnippet(long a, long b) { + if (a - b == 0) { + return 1; + } + return 0; + } + + /** + * Tests the canonicalization of (x >>> const) == 0 to x |test| (-1 << const). + */ + @Test + public void testShiftEquals() { + test("testShiftEqualsSnippet", "testShiftEqualsReference"); + } + + @SuppressWarnings("unused") private static int field; + + public static void testShiftEqualsSnippet(int x, int[] array, int y) { + // optimize + field = (x >>> 10) == 0 ? 1 : 0; + field = (array.length >> 10) == 0 ? 1 : 0; + field = (x << 10) == 0 ? 1 : 0; + // don't optimize + field = (x >> 10) == 0 ? 1 : 0; + field = (x >>> y) == 0 ? 1 : 0; + field = (x >> y) == 0 ? 1 : 0; + field = (x << y) == 0 ? 1 : 0; + field = (x >>> y) == 1 ? 1 : 0; + field = (x >> y) == 1 ? 1 : 0; + field = (x << y) == 1 ? 1 : 0; + } + + public static void testShiftEqualsReference(int x, int[] array, int y) { + field = (x & 0xfffffc00) == 0 ? 1 : 0; + field = (array.length & 0xfffffc00) == 0 ? 1 : 0; + field = (x & 0x3fffff) == 0 ? 1 : 0; + // don't optimize signed right shifts + field = (x >> 10) == 0 ? 1 : 0; + // don't optimize no-constant shift amounts + field = (x >>> y) == 0 ? 1 : 0; + field = (x >> y) == 0 ? 1 : 0; + field = (x << y) == 0 ? 1 : 0; + // don't optimize non-zero comparisons + field = (x >>> y) == 1 ? 1 : 0; + field = (x >> y) == 1 ? 1 : 0; + field = (x << y) == 1 ? 1 : 0; + } + + @Test + public void testCompare() { + test("testCompareSnippet", "testCompareReference"); + } + + public static void testCompareSnippet(int x, int y, int[] array1, int[] array2) { + int tempX = x; + int array1Length = array1.length; + int array2Length = array2.length; + // optimize + field = x == tempX ? 1 : 0; + field = x != tempX ? 1 : 0; + field = array1Length != (-1 - array2Length) ? 1 : 0; + field = array1Length == (-1 - array2Length) ? 1 : 0; + // don't optimize + field = x == y ? 1 : 0; + field = array1Length == array2Length ? 1 : 0; + field = array1Length == (-array2Length) ? 1 : 0; + } + + public static void testCompareReference(int x, int y, int[] array1, int[] array2) { + int array1Length = array1.length; + int array2Length = array2.length; + // optimize + field = 1; + field = 0; + field = 1; + field = 0; + // don't optimize (overlapping value ranges) + field = x == y ? 1 : 0; + field = array1Length == array2Length ? 1 : 0; + field = array1Length == (-array2Length) ? 1 : 0; + } + + public static boolean testNormalIntegerTest(int a) { + return (a & 8) != 0; + } + + public static boolean testAlternateIntegerTest(int a) { + return (a & 8) == 8; + } + + @Test + public void testIntegerTest() { + test("testNormalIntegerTest", "testAlternateIntegerTest"); + } + + private void test(String snippet, String referenceSnippet) { + StructuredGraph graph = getCanonicalizedGraph(snippet); + StructuredGraph referenceGraph = getCanonicalizedGraph(referenceSnippet); + assertEquals(referenceGraph, graph); + } + + private StructuredGraph getCanonicalizedGraph(String snippet) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + for (FrameState state : graph.getNodes(FrameState.TYPE).snapshot()) { + state.replaceAtUsages(null); + state.safeDelete(); + } + return graph; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerStampMulFoldTest.java 2016-12-07 13:48:25.453631418 -0800 @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import java.util.ArrayList; +import java.util.Collection; + +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; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.StampFactory; + +@RunWith(Suite.class) +@SuiteClasses({IntegerStampMulFoldTest.OverflowTest.class, IntegerStampMulFoldTest.FoldTest.class}) +public class IntegerStampMulFoldTest extends GraalCompilerTest { + + public static class OverflowTest { + @Test + public void testOverflowCheck() { + // a.u * b.u overflows + long a = Integer.MIN_VALUE; + long b = -1; + Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 32)); + } + + @Test + public void testOverflowCheck01() { + // a.u * b.u overflows + long a = Integer.MAX_VALUE; + long b = Integer.MAX_VALUE; + Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 32)); + } + + @Test + public void testOverflowCheck02() { + // a.u * b.u overflows + long a = Integer.MIN_VALUE; + long b = Integer.MIN_VALUE; + Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 32)); + } + + @Test + public void testOverflowCheck03() { + // a.u * b.u overflows + long a = Integer.MIN_VALUE; + long b = 1; + Assert.assertFalse(IntegerStamp.multiplicationOverflows(a, b, 32)); + } + + @Test + public void testOverflowCheck04() { + // a.u * b.u overflows + long a = Integer.MAX_VALUE; + long b = 1; + Assert.assertFalse(IntegerStamp.multiplicationOverflows(a, b, 32)); + } + + @Test + public void testOverflowCheck05() { + // a.u * b.u overflows + long a = Integer.MAX_VALUE; + long b = Integer.MIN_VALUE; + Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 32)); + } + + @Test + public void testOverflowCheck06() { + // 31bits*31bits = 62bits + 1 carry is max 63 bits, we can never need 64 bits + long a = Integer.MAX_VALUE; + long b = Integer.MAX_VALUE; + Assert.assertTrue("31bit*31bit overflows 62", IntegerStamp.multiplicationOverflows(a, b, 62)); + Assert.assertFalse("31bit*31bit does not overflow 63", IntegerStamp.multiplicationOverflows(a, b, 63)); + Assert.assertFalse("31bit*31bit does not overflow 64", IntegerStamp.multiplicationOverflows(a, b, 64)); + } + + @Test + public void testOverflowCheck07() { + long a = Long.MAX_VALUE; + long b = 2; + Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 64)); + } + + @Test + public void testOverflowCheck08() { + long a = Long.MAX_VALUE; + long b = Long.MAX_VALUE; + Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 64)); + } + + @Test + public void testOverflowCheck09() { + long a = -Long.MAX_VALUE; + long b = Long.MAX_VALUE; + Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 64)); + } + + @Test + public void testOverflowCheck10() { + long a = -Long.MAX_VALUE; + long b = -Long.MAX_VALUE; + Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 64)); + } + + @Test + public void testOverflowCheck11() { + long a = Long.MAX_VALUE; + long b = -Long.MAX_VALUE; + Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 64)); + } + } + + @RunWith(Parameterized.class) + public static class FoldTest { + @Parameter(0) public long lowerBound1; + @Parameter(1) public long upperBound1; + @Parameter(2) public long lowerBound2; + @Parameter(3) public long upperBound2; + @Parameter(4) public int bits; + + @Test + public void computeStamp() { + IntegerStamp a = StampFactory.forInteger(bits, lowerBound1, upperBound1); + IntegerStamp b = StampFactory.forInteger(bits, lowerBound2, upperBound2); + IntegerStamp result = foldMul(a, b); + for (long l1 = lowerBound1; l1 <= upperBound1; l1++) { + for (long l2 = lowerBound2; l2 <= upperBound2; l2++) { + long res = 0; + if (bits == 8) { + res = (byte) (l1 * l2); + } else if (bits == 16) { + res = (short) (l1 * l2); + } else if (bits == 32) { + res = (int) (l1 * l2); + } else if (bits == 64) { + res = l1 * l2; + } + Assert.assertTrue(result.contains(res)); + if (l2 == Long.MAX_VALUE) { + // do not want to overflow the check loop + break; + } + } + if (l1 == Long.MAX_VALUE) { + // do not want to overflow the check loop + break; + } + } + } + + @Parameters(name = "a[{0} - {1}] b[{2} - {3}] bits=32") + public static Collection data() { + ArrayList tests = new ArrayList<>(); + + // zero related + addTest(tests, -2, 2, 3, 3, 8); + addTest(tests, 0, 0, 1, 1, 8); + addTest(tests, 1, 1, 0, 0, 8); + addTest(tests, -1, 1, 0, 1, 8); + addTest(tests, -1, 1, 1, 1, 8); + addTest(tests, -1, 1, -1, 1, 8); + + addTest(tests, -2, 2, 3, 3, 16); + addTest(tests, 0, 0, 1, 1, 16); + addTest(tests, 1, 1, 0, 0, 16); + addTest(tests, -1, 1, 0, 1, 16); + addTest(tests, -1, 1, 1, 1, 16); + addTest(tests, -1, 1, -1, 1, 16); + + addTest(tests, -2, 2, 3, 3, 32); + addTest(tests, 0, 0, 1, 1, 32); + addTest(tests, 1, 1, 0, 0, 32); + addTest(tests, -1, 1, 0, 1, 32); + addTest(tests, -1, 1, 1, 1, 32); + addTest(tests, -1, 1, -1, 1, 32); + + addTest(tests, 0, 0, 1, 1, 64); + addTest(tests, 1, 1, 0, 0, 64); + addTest(tests, -1, 1, 0, 1, 64); + addTest(tests, -1, 1, 1, 1, 64); + addTest(tests, -1, 1, -1, 1, 64); + + // bounds + addTest(tests, Byte.MIN_VALUE, Byte.MIN_VALUE + 1, Byte.MAX_VALUE - 1, Byte.MAX_VALUE, 8); + addTest(tests, Byte.MIN_VALUE, Byte.MIN_VALUE + 1, -1, -1, 8); + addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFF, Integer.MAX_VALUE - 0xFF, + Integer.MAX_VALUE, 32); + addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFFF, -1, -1, 32); + addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFF, Integer.MAX_VALUE - 0xFF, + Integer.MAX_VALUE, 64); + addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFFF, -1, -1, 64); + addTest(tests, Long.MIN_VALUE, Long.MIN_VALUE + 0xFFF, -1, -1, 64); + + // constants + addTest(tests, 2, 2, 2, 2, 32); + addTest(tests, 1, 1, 2, 2, 32); + addTest(tests, 2, 2, 4, 4, 32); + addTest(tests, 3, 3, 3, 3, 32); + addTest(tests, -4, -4, 3, 3, 32); + addTest(tests, -4, -4, -3, -3, 32); + addTest(tests, 4, 4, -3, -3, 32); + + addTest(tests, 2, 2, 2, 2, 64); + addTest(tests, 1, 1, 2, 2, 64); + addTest(tests, 3, 3, 3, 3, 64); + + addTest(tests, Long.MAX_VALUE, Long.MAX_VALUE, 1, 1, 64); + addTest(tests, Long.MAX_VALUE, Long.MAX_VALUE, -1, -1, 64); + addTest(tests, Long.MIN_VALUE, Long.MIN_VALUE, -1, -1, 64); + addTest(tests, Long.MIN_VALUE, Long.MIN_VALUE, 1, 1, 64); + + return tests; + } + + private static void addTest(ArrayList tests, long lowerBound1, long upperBound1, long lowerBound2, long upperBound2, int bits) { + tests.add(new Object[]{lowerBound1, upperBound1, lowerBound2, upperBound2, bits}); + } + + } + + private static IntegerStamp foldMul(IntegerStamp a, IntegerStamp b) { + return (IntegerStamp) IntegerStamp.OPS.getMul().foldStamp(a, b); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InterfaceMethodHandleTest.java 2016-12-07 13:48:25.721643199 -0800 @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import org.junit.Test; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.test.ExportingClassLoader; + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public final class InterfaceMethodHandleTest extends GraalCompilerTest implements Opcodes { + private static final MethodHandle INTERFACE_HANDLE_M; + private static final MethodHandle INTERFACE_HANDLE_M2; + + public interface I { + int m(); + + int m2(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); + } + + static class A implements I { + @Override + public int m() { + return 0; + } + + @Override + public int m2(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { + return 1; + } + + } + + static class M2Thrower implements I { + @Override + public int m() { + return 0; + } + + @Override + public int m2(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { + throw new InternalError(); + } + + } + + static { + try { + MethodType type = MethodType.fromMethodDescriptorString("()I", I.class.getClassLoader()); + INTERFACE_HANDLE_M = MethodHandles.lookup().findVirtual(I.class, "m", type); + MethodType type2 = MethodType.fromMethodDescriptorString("(IIIIIIIIII)I", I.class.getClassLoader()); + INTERFACE_HANDLE_M2 = MethodHandles.lookup().findVirtual(I.class, "m2", type2); + } catch (IllegalAccessException | NoSuchMethodException e) { + throw new RuntimeException("unable to initialize method handle", e); + } + } + + public static Object invokeInterfaceHandle(I o) throws Throwable { + return (int) INTERFACE_HANDLE_M.invokeExact(o); + } + + @Test + public void testInvokeInterface01() { + test("invokeInterfaceHandle", new A()); + + } + + @Test + public void testInvokeInterface02() throws InstantiationException, IllegalAccessException, ClassNotFoundException { + test("invokeInterfaceHandle", loader.findClass(NAME).newInstance()); + } + + public static Object invokeInterfaceHandle2(I o, int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) throws Throwable { + return (int) INTERFACE_HANDLE_M2.invokeExact(o, a, b, c, d, e, f, g, h, i, j); + } + + @Override + protected InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) { + if (method.getDeclaringClass().equals(getMetaAccess().lookupJavaType(M2Thrower.class))) { + // Make sure M2Thrower.m2 is invoked from normal code + return getBackend().createDefaultInstalledCode(method, compResult); + } + return super.addMethod(method, compResult); + } + + /** + * Try to exercise a mixed calling sequence with regular JIT code calling a method handle that + * can't be inlined with an implementation compiled by Graal that throws an exception. + */ + @Test + public void testInvokeInterface03() throws Throwable { + A goodInstance = new A(); + I badInstance = new M2Thrower(); + getCode(getMetaAccess().lookupJavaMethod(getMethod(M2Thrower.class, "m2"))); + for (int x = 0; x < 1000; x++) { + final int limit = 20000; + for (int i = 0; i <= limit; i++) { + try { + invokeInterfaceHandle2(i < limit - 1 ? goodInstance : badInstance, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } catch (InternalError e) { + + } + } + } + } + + private static final String BASENAME = InterfaceMethodHandleTest.class.getName(); + private static final String NAME = BASENAME + "_B"; + private AsmLoader loader = new AsmLoader(UnbalancedMonitorsTest.class.getClassLoader()); + + /** + * Construct a type which claims to implement {@link I} but with incorrect access on {@link I#m} + * so that an exception must be thrown. + */ + public static byte[] bytesForB() { + + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + String jvmName = NAME.replace('.', '/'); + cw.visit(52, ACC_SUPER | ACC_PUBLIC, jvmName, null, "java/lang/Object", new String[]{BASENAME.replace('.', '/') + "$I"}); + + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitMaxs(1, 1); + mv.visitEnd(); + + mv = cw.visitMethod(ACC_PRIVATE, "m", "()I", null, null); + mv.visitCode(); + l0 = new Label(); + mv.visitLabel(l0); + mv.visitInsn(ICONST_0); + mv.visitInsn(IRETURN); + l1 = new Label(); + mv.visitLabel(l1); + mv.visitMaxs(1, 1); + mv.visitEnd(); + + cw.visitEnd(); + + mv = cw.visitMethod(ACC_PRIVATE, "m2", "(IIIIIIIIII)I", null, null); + mv.visitCode(); + l0 = new Label(); + mv.visitLabel(l0); + mv.visitInsn(ICONST_0); + mv.visitInsn(IRETURN); + l1 = new Label(); + mv.visitLabel(l1); + mv.visitMaxs(1, 11); + mv.visitEnd(); + + cw.visitEnd(); + + return cw.toByteArray(); + } + + public static class AsmLoader extends ExportingClassLoader { + Class loaded; + + public AsmLoader(ClassLoader parent) { + super(parent); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals(NAME)) { + if (loaded != null) { + return loaded; + } + byte[] bytes = bytesForB(); + return (loaded = defineClass(name, bytes, 0, bytes.length)); + } else { + return super.findClass(name); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeExceptionTest.java 2016-12-07 13:48:25.985654805 -0800 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +public class InvokeExceptionTest extends GraalCompilerTest { + + public static synchronized void throwException(int i) { + if (i == 1) { + throw new RuntimeException(); + } + } + + @Test + public void test1() { + // fill the profiling data... + for (int i = 0; i < 10000; i++) { + try { + throwException(i & 1); + test1Snippet(0); + } catch (Throwable t) { + // nothing to do... + } + } + test("test1Snippet"); + } + + @SuppressWarnings("all") + public static void test1Snippet(int a) { + throwException(a); + } + + private void test(String snippet) { + StructuredGraph graph = parseProfiled(snippet, AllowAssumptions.NO); + Map hints = new HashMap<>(); + for (Invoke invoke : graph.getInvokes()) { + hints.put(invoke, 1000d); + } + HighTierContext context = getDefaultHighTierContext(); + new InliningPhase(hints, new CanonicalizerPhase()).apply(graph, context); + new CanonicalizerPhase().apply(graph, context); + new DeadCodeEliminationPhase().apply(graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeHintsTest.java 2016-12-07 13:48:26.250666454 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +public class InvokeHintsTest extends GraalCompilerTest { + + private static final String REFERENCE_SNIPPET = "referenceSnippet"; + + public static int const1() { + return 1; + } + + public static int const7() { + return 7; + } + + @SuppressWarnings("all") + public static int referenceSnippet() { + return 7; + } + + @Test + public void test1() { + test("test1Snippet"); + } + + @SuppressWarnings("all") + public static int test1Snippet() { + return const7(); + } + + @Test + public void test2() { + test("test2Snippet"); + } + + @SuppressWarnings("all") + public static int test2Snippet() { + return const1() + const1() + const1() + const1() + const1() + const1() + const1(); + } + + private void test(String snippet) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + Map hints = new HashMap<>(); + for (Invoke invoke : graph.getInvokes()) { + hints.put(invoke, 1000d); + } + + HighTierContext context = getDefaultHighTierContext(); + new InliningPhase(hints, new CanonicalizerPhase()).apply(graph, context); + new CanonicalizerPhase().apply(graph, context); + new DeadCodeEliminationPhase().apply(graph); + StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.NO); + assertEquals(referenceGraph, graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java 2016-12-07 13:48:26.517678191 -0800 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.java.MonitorExitNode; +import org.graalvm.compiler.nodes.java.RawMonitorEnterNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.LockEliminationPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.ValueAnchorCleanupPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class LockEliminationTest extends GraalCompilerTest { + + static class A { + + int value; + + public synchronized int getValue() { + return value; + } + } + + static int field1; + static int field2; + + public static void testSynchronizedSnippet(A x, A y) { + synchronized (x) { + field1 = x.value; + } + synchronized (x) { + field2 = y.value; + } + } + + @Test + public void testLock() { + test("testSynchronizedSnippet", new A(), new A()); + + StructuredGraph graph = getGraph("testSynchronizedSnippet"); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + new LockEliminationPhase().apply(graph); + assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count()); + assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count()); + } + + public static void testSynchronizedMethodSnippet(A x) { + int value1 = x.getValue(); + int value2 = x.getValue(); + field1 = value1; + field2 = value2; + } + + @Test + public void testSynchronizedMethod() { + test("testSynchronizedMethodSnippet", new A()); + + StructuredGraph graph = getGraph("testSynchronizedMethodSnippet"); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + new LockEliminationPhase().apply(graph); + assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count()); + assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count()); + } + + private StructuredGraph getGraph(String snippet) { + ResolvedJavaMethod method = getResolvedJavaMethod(snippet); + StructuredGraph graph = parseEager(method, AllowAssumptions.YES); + HighTierContext context = getDefaultHighTierContext(); + new CanonicalizerPhase().apply(graph, context); + new InliningPhase(new CanonicalizerPhase()).apply(graph, context); + new CanonicalizerPhase().apply(graph, context); + new DeadCodeEliminationPhase().apply(graph); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + new ValueAnchorCleanupPhase().apply(graph); + new LockEliminationPhase().apply(graph); + return graph; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java 2016-12-07 13:48:26.782689840 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, 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.core.test; + +import jdk.vm.ci.meta.JavaConstant; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.debug.OpaqueNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +public class LongNodeChainTest extends GraalCompilerTest { + + public static final int N = 10000; + + private static final SchedulingStrategy[] Strategies = new SchedulingStrategy[]{SchedulingStrategy.EARLIEST}; + + @Test + public void testLongAddChain() { + longAddChain(true); + longAddChain(false); + } + + private void longAddChain(boolean reverse) { + HighTierContext context = getDefaultHighTierContext(); + StructuredGraph graph = new StructuredGraph(AllowAssumptions.NO, INVALID_COMPILATION_ID); + ValueNode constant = graph.unique(ConstantNode.forPrimitive(JavaConstant.INT_1)); + ValueNode value = null; + if (reverse) { + // Make sure the constant's stamp is not used to infer the add node's stamp. + OpaqueNode opaque = graph.unique(new OpaqueNode(constant)); + constant = opaque; + AddNode addNode = graph.unique(new AddNode(constant, constant)); + value = addNode; + for (int i = 1; i < N; ++i) { + AddNode newAddNode = graph.addWithoutUnique(new AddNode(constant, constant)); + addNode.setY(newAddNode); + addNode = newAddNode; + } + opaque.replaceAndDelete(opaque.getValue()); + } else { + value = constant; + for (int i = 0; i < N; ++i) { + value = graph.unique(new AddNode(constant, value)); + } + } + ReturnNode returnNode = graph.add(new ReturnNode(value)); + graph.start().setNext(returnNode); + + for (SchedulingStrategy s : Strategies) { + new SchedulePhase(s).apply(graph); + } + + new CanonicalizerPhase().apply(graph, context); + JavaConstant asConstant = (JavaConstant) returnNode.result().asConstant(); + Assert.assertEquals(N + 1, asConstant.asInt()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopUnswitchTest.java 2016-12-07 13:48:27.046701445 -0800 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.loop.DefaultLoopPolicies; +import org.graalvm.compiler.loop.phases.LoopUnswitchingPhase; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class LoopUnswitchTest extends GraalCompilerTest { + + public static int referenceSnippet1(int a) { + int sum = 0; + if (a > 2) { + for (int i = 0; i < 1000; i++) { + sum += 2; + } + } else { + for (int i = 0; i < 1000; i++) { + sum += a; + } + } + return sum; + } + + public static int test1Snippet(int a) { + int sum = 0; + for (int i = 0; i < 1000; i++) { + if (a > 2) { + sum += 2; + } else { + sum += a; + } + } + return sum; + } + + public static int referenceSnippet2(int a) { + int sum = 0; + switch (a) { + case 0: + for (int i = 0; i < 1000; i++) { + sum += System.currentTimeMillis(); + } + break; + case 1: + for (int i = 0; i < 1000; i++) { + sum += 1; + sum += 5; + } + break; + case 55: + for (int i = 0; i < 1000; i++) { + sum += 5; + } + break; + default: + for (int i = 0; i < 1000; i++) { + // nothing + } + break; + } + return sum; + } + + @SuppressWarnings("fallthrough") + public static int test2Snippet(int a) { + int sum = 0; + for (int i = 0; i < 1000; i++) { + switch (a) { + case 0: + sum += System.currentTimeMillis(); + break; + case 1: + sum += 1; + // fall through + case 55: + sum += 5; + break; + default: + // nothing + break; + } + } + return sum; + } + + @Test + public void test1() { + test("test1Snippet", "referenceSnippet1"); + } + + @Test + public void test2() { + test("test2Snippet", "referenceSnippet2"); + } + + @SuppressWarnings("try") + private void test(String snippet, String referenceSnippet) { + final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + final StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO); + + new LoopUnswitchingPhase(new DefaultLoopPolicies()).apply(graph); + + // Framestates create comparison problems + graph.clearAllStateAfter(); + referenceGraph.clearAllStateAfter(); + + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders())); + try (Scope s = Debug.scope("Test", new DebugDumpScope("Test:" + snippet))) { + assertEquals(referenceGraph, graph); + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java 2016-12-07 13:48:27.311713095 -0800 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import static java.nio.file.StandardOpenOption.READ; +import static java.nio.file.StandardOpenOption.WRITE; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.Files; +import java.nio.file.Path; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +import sun.misc.Unsafe; + +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +public class MarkUnsafeAccessTest extends GraalCompilerTest { + + public static Unsafe unsafe; + + public void getRaw() { + unsafe.getInt(0L); + } + + public void get() { + unsafe.getInt(null, 0L); + } + + public void putRaw() { + unsafe.putInt(0L, 0); + } + + public void put() { + unsafe.putInt(null, 0L, 0); + } + + public void cas() { + unsafe.compareAndSwapInt(null, 0, 0, 0); + } + + public void noAccess() { + unsafe.addressSize(); + unsafe.pageSize(); + } + + private void assertHasUnsafe(String name, boolean hasUnsafe) { + Assert.assertEquals(hasUnsafe, compile(getResolvedJavaMethod(name), null).hasUnsafeAccess()); + } + + @Test + public void testGet() { + assertHasUnsafe("get", true); + assertHasUnsafe("getRaw", true); + } + + @Test + public void testPut() { + assertHasUnsafe("put", true); + assertHasUnsafe("putRaw", true); + } + + @Test + public void testCas() { + assertHasUnsafe("cas", true); + } + + @Test + public void testNoAcces() { + assertHasUnsafe("noAccess", false); + } + + @FunctionalInterface + private interface MappedByteBufferGetter { + byte get(MappedByteBuffer mbb); + } + + @Test + public void testStandard() throws IOException { + testMappedByteBuffer(MappedByteBuffer::get); + } + + @Test + public void testCompiled() throws IOException { + ResolvedJavaMethod getMethod = asResolvedJavaMethod(getMethod(ByteBuffer.class, "get", new Class[]{})); + ResolvedJavaType mbbClass = getMetaAccess().lookupJavaType(MappedByteBuffer.class); + ResolvedJavaMethod getMethodImpl = mbbClass.findUniqueConcreteMethod(getMethod).getResult(); + Assert.assertNotNull(getMethodImpl); + StructuredGraph graph = parseForCompile(getMethodImpl); + HighTierContext highContext = getDefaultHighTierContext(); + new CanonicalizerPhase().apply(graph, highContext); + new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase()).apply(graph, highContext); + InstalledCode compiledCode = getCode(getMethodImpl, graph); + testMappedByteBuffer(mbb -> { + try { + return (byte) compiledCode.executeVarargs(mbb); + } catch (InvalidInstalledCodeException e) { + Assert.fail(); + return 0; + } + }); + } + + private static final int BLOCK_SIZE = 512; + private static final int BLOCK_COUNT = 16; + + public void testMappedByteBuffer(MappedByteBufferGetter getter) throws IOException { + Path tmp = Files.createTempFile(null, null); + tmp.toFile().deleteOnExit(); + FileChannel tmpFileChannel = FileChannel.open(tmp, READ, WRITE); + ByteBuffer bb = ByteBuffer.allocate(BLOCK_SIZE); + while (bb.remaining() >= 4) { + bb.putInt(0xA8A8A8A8); + } + for (int i = 0; i < BLOCK_COUNT; ++i) { + bb.flip(); + while (bb.hasRemaining()) { + tmpFileChannel.write(bb); + } + } + tmpFileChannel.force(true); + MappedByteBuffer mbb = tmpFileChannel.map(MapMode.READ_WRITE, 0, BLOCK_SIZE * BLOCK_COUNT); + Assert.assertEquals((byte) 0xA8, mbb.get()); + mbb.position(mbb.position() + BLOCK_SIZE); + Assert.assertEquals((byte) 0xA8, mbb.get()); + boolean truncated = false; + try { + tmpFileChannel.truncate(0); + tmpFileChannel.force(true); + truncated = true; + } catch (IOException e) { + // not all platforms support truncating memory-mapped files + } + Assume.assumeTrue(truncated); + try { + mbb.position(BLOCK_SIZE); + getter.get(mbb); + System.currentTimeMillis(); // materialize async exception + } catch (InternalError e) { + return; + } + Assert.fail("Expected exception"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryArithmeticTest.java 2016-12-07 13:48:27.577724788 -0800 @@ -0,0 +1,4337 @@ +/* + * Copyright (c) 2014, 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.core.test; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.StructuredGraph; + +public class MemoryArithmeticTest extends GraalCompilerTest { + + @Override + protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) { + return getCode(method, graph, true); + } + + /** + * Called before a test is executed. + */ + @Override + protected void before(ResolvedJavaMethod method) { + // don't let any null exception tracking change the generated code. + method.reprofile(); + } + + /** + * A dummy field used by some tests to create side effects. + */ + protected static int count; + + static class FieldObject { + boolean booleanValue; + byte byteValue; + short shortValue; + char charValue; + int intValue; + float floatValue; + long longValue; + double doubleValue; + Object objectValue; + } + + static FieldObject maxObject = new FieldObject(); + static FieldObject minObject; + + static final boolean booleanTestValue1 = false; + static final byte byteTestValue1 = 0; + static final short shortTestValue1 = 0; + static final char charTestValue1 = 0; + static final int intTestValue1 = 0; + static final float floatTestValue1 = 0; + static final long longTestValue1 = 0; + static final double doubleTestValue1 = 0; + static final Object objectTestValue1 = null; + + static final boolean booleanTestValue2 = true; + static final byte byteTestValue2 = Byte.MAX_VALUE; + static final short shortTestValue2 = Short.MAX_VALUE; + static final char charTestValue2 = Character.MAX_VALUE; + static final int intTestValue2 = Integer.MAX_VALUE; + static final float floatTestValue2 = Float.MAX_VALUE; + static final long longTestValue2 = Long.MAX_VALUE; + static final double doubleTestValue2 = Double.MAX_VALUE; + static final Object objectTestValue2 = "String"; + + static { + maxObject.booleanValue = true; + maxObject.byteValue = Byte.MAX_VALUE; + maxObject.shortValue = Short.MAX_VALUE; + maxObject.charValue = Character.MAX_VALUE; + maxObject.intValue = Integer.MAX_VALUE; + maxObject.floatValue = Float.MAX_VALUE; + maxObject.longValue = Long.MAX_VALUE; + maxObject.doubleValue = Double.MAX_VALUE; + maxObject.objectValue = "String"; + } + + public static Object testBooleanCompare(FieldObject f, boolean booleanValue) { + if (f.booleanValue == booleanValue) { + return f; + } + return null; + } + + public static Object testBooleanCompareConstant1(FieldObject f) { + if (f.booleanValue == booleanTestValue1) { + return f; + } + return null; + } + + public static Object testBooleanCompareConstant2(FieldObject f) { + if (f.booleanValue == booleanTestValue2) { + return f; + } + return null; + } + + @Test + public void testBooleanCompares() { + FieldObject f = new FieldObject(); + test("testBooleanCompare", f, booleanTestValue1); + test("testBooleanCompareConstant1", f); + test("testBooleanCompareConstant2", f); + } + + @Test + public void testBooleanNullCompares() { + test("testBooleanCompare", null, booleanTestValue1); + } + + @Test + public void testBooleanNullCompares1() { + test("testBooleanCompareConstant1", (Object) null); + } + + @Test + public void testBooleanNullCompares2() { + test("testBooleanCompareConstant2", (Object) null); + } + + public static Object testByteCompare(FieldObject f, byte byteValue) { + if (f.byteValue == byteValue) { + return f; + } + return null; + } + + public static Object testByteCompareConstant1(FieldObject f) { + if (f.byteValue == byteTestValue1) { + return f; + } + return null; + } + + public static Object testByteCompareConstant2(FieldObject f) { + if (f.byteValue == byteTestValue2) { + return f; + } + return null; + } + + @Test + public void testByteCompares() { + FieldObject f = new FieldObject(); + test("testByteCompare", f, byteTestValue1); + test("testByteCompareConstant1", f); + test("testByteCompareConstant2", f); + } + + @Test + public void testByteNullCompares() { + test("testByteCompare", null, byteTestValue1); + } + + @Test + public void testByteNullCompares1() { + test("testByteCompareConstant1", (Object) null); + } + + @Test + public void testByteNullCompares2() { + test("testByteCompareConstant2", (Object) null); + } + + public static Object testByteCompareLess(FieldObject f, byte byteValue) { + if (f.byteValue < byteValue) { + return f; + } + return null; + } + + public static Object testByteCompareLessConstant1(FieldObject f) { + if (f.byteValue < byteTestValue1) { + return f; + } + return null; + } + + public static Object testByteCompareLessConstant2(FieldObject f) { + if (f.byteValue < byteTestValue2) { + return f; + } + return null; + } + + @Test + public void testByteComparesLess() { + FieldObject f = new FieldObject(); + test("testByteCompareLess", f, byteTestValue1); + test("testByteCompareLessConstant1", f); + test("testByteCompareLessConstant2", f); + } + + @Test + public void testByteNullComparesLess() { + test("testByteCompareLess", null, byteTestValue1); + } + + @Test + public void testByteNullComparesLess1() { + test("testByteCompareLessConstant1", (Object) null); + } + + @Test + public void testByteNullComparesLess2() { + test("testByteCompareLessConstant2", (Object) null); + } + + public static Object testByteSwappedCompareLess(FieldObject f, byte byteValue) { + if (byteValue < f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareLessConstant1(FieldObject f) { + if (byteTestValue1 < f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareLessConstant2(FieldObject f) { + if (byteTestValue2 < f.byteValue) { + return f; + } + return null; + } + + @Test + public void testByteSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testByteSwappedCompareLess", f, byteTestValue1); + test("testByteSwappedCompareLessConstant1", f); + test("testByteSwappedCompareLessConstant2", f); + } + + @Test + public void testByteNullSwappedComparesLess() { + test("testByteSwappedCompareLess", null, byteTestValue1); + } + + @Test + public void testByteNullSwappedComparesLess1() { + test("testByteSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testByteNullSwappedComparesLess2() { + test("testByteSwappedCompareLessConstant2", (Object) null); + } + + public static Object testByteCompareLessEqual(FieldObject f, byte byteValue) { + if (f.byteValue <= byteValue) { + return f; + } + return null; + } + + public static Object testByteCompareLessEqualConstant1(FieldObject f) { + if (f.byteValue <= byteTestValue1) { + return f; + } + return null; + } + + public static Object testByteCompareLessEqualConstant2(FieldObject f) { + if (f.byteValue <= byteTestValue2) { + return f; + } + return null; + } + + @Test + public void testByteComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testByteCompareLessEqual", f, byteTestValue1); + test("testByteCompareLessEqualConstant1", f); + test("testByteCompareLessEqualConstant2", f); + } + + @Test + public void testByteNullComparesLessEqual() { + test("testByteCompareLessEqual", null, byteTestValue1); + } + + @Test + public void testByteNullComparesLessEqual1() { + test("testByteCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testByteNullComparesLessEqual2() { + test("testByteCompareLessEqualConstant2", (Object) null); + } + + public static Object testByteSwappedCompareLessEqual(FieldObject f, byte byteValue) { + if (byteValue <= f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareLessEqualConstant1(FieldObject f) { + if (byteTestValue1 <= f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareLessEqualConstant2(FieldObject f) { + if (byteTestValue2 <= f.byteValue) { + return f; + } + return null; + } + + @Test + public void testByteSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testByteSwappedCompareLessEqual", f, byteTestValue1); + test("testByteSwappedCompareLessEqualConstant1", f); + test("testByteSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testByteNullSwappedComparesLessEqual() { + test("testByteSwappedCompareLessEqual", null, byteTestValue1); + } + + @Test + public void testByteNullSwappedComparesLessEqual1() { + test("testByteSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testByteNullSwappedComparesLessEqual2() { + test("testByteSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testByteCompareGreater(FieldObject f, byte byteValue) { + if (f.byteValue > byteValue) { + return f; + } + return null; + } + + public static Object testByteCompareGreaterConstant1(FieldObject f) { + if (f.byteValue > byteTestValue1) { + return f; + } + return null; + } + + public static Object testByteCompareGreaterConstant2(FieldObject f) { + if (f.byteValue > byteTestValue2) { + return f; + } + return null; + } + + @Test + public void testByteComparesGreater() { + FieldObject f = new FieldObject(); + test("testByteCompareGreater", f, byteTestValue1); + test("testByteCompareGreaterConstant1", f); + test("testByteCompareGreaterConstant2", f); + } + + @Test + public void testByteNullComparesGreater() { + test("testByteCompareGreater", null, byteTestValue1); + } + + @Test + public void testByteNullComparesGreater1() { + test("testByteCompareGreaterConstant1", (Object) null); + } + + @Test + public void testByteNullComparesGreater2() { + test("testByteCompareGreaterConstant2", (Object) null); + } + + public static Object testByteSwappedCompareGreater(FieldObject f, byte byteValue) { + if (byteValue > f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareGreaterConstant1(FieldObject f) { + if (byteTestValue1 > f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareGreaterConstant2(FieldObject f) { + if (byteTestValue2 > f.byteValue) { + return f; + } + return null; + } + + @Test + public void testByteSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testByteSwappedCompareGreater", f, byteTestValue1); + test("testByteSwappedCompareGreaterConstant1", f); + test("testByteSwappedCompareGreaterConstant2", f); + } + + @Test + public void testByteNullSwappedComparesGreater() { + test("testByteSwappedCompareGreater", null, byteTestValue1); + } + + @Test + public void testByteNullSwappedComparesGreater1() { + test("testByteSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testByteNullSwappedComparesGreater2() { + test("testByteSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testByteCompareGreaterEqual(FieldObject f, byte byteValue) { + if (f.byteValue >= byteValue) { + return f; + } + return null; + } + + public static Object testByteCompareGreaterEqualConstant1(FieldObject f) { + if (f.byteValue >= byteTestValue1) { + return f; + } + return null; + } + + public static Object testByteCompareGreaterEqualConstant2(FieldObject f) { + if (f.byteValue >= byteTestValue2) { + return f; + } + return null; + } + + @Test + public void testByteComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testByteCompareGreaterEqual", f, byteTestValue1); + test("testByteCompareGreaterEqualConstant1", f); + test("testByteCompareGreaterEqualConstant2", f); + } + + @Test + public void testByteNullComparesGreaterEqual() { + test("testByteCompareGreaterEqual", null, byteTestValue1); + } + + @Test + public void testByteNullComparesGreaterEqual1() { + test("testByteCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testByteNullComparesGreaterEqual2() { + test("testByteCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testByteSwappedCompareGreaterEqual(FieldObject f, byte byteValue) { + if (byteValue >= f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (byteTestValue1 >= f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (byteTestValue2 >= f.byteValue) { + return f; + } + return null; + } + + @Test + public void testByteSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testByteSwappedCompareGreaterEqual", f, byteTestValue1); + test("testByteSwappedCompareGreaterEqualConstant1", f); + test("testByteSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testByteNullSwappedComparesGreaterEqual() { + test("testByteSwappedCompareGreaterEqual", null, byteTestValue1); + } + + @Test + public void testByteNullSwappedComparesGreaterEqual1() { + test("testByteSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testByteNullSwappedComparesGreaterEqual2() { + test("testByteSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testShortCompare(FieldObject f, short shortValue) { + if (f.shortValue == shortValue) { + return f; + } + return null; + } + + public static Object testShortCompareConstant1(FieldObject f) { + if (f.shortValue == shortTestValue1) { + return f; + } + return null; + } + + public static Object testShortCompareConstant2(FieldObject f) { + if (f.shortValue == shortTestValue2) { + return f; + } + return null; + } + + @Test + public void testShortCompares() { + FieldObject f = new FieldObject(); + test("testShortCompare", f, shortTestValue1); + test("testShortCompareConstant1", f); + test("testShortCompareConstant2", f); + } + + @Test + public void testShortNullCompares() { + test("testShortCompare", null, shortTestValue1); + } + + @Test + public void testShortNullCompares1() { + test("testShortCompareConstant1", (Object) null); + } + + @Test + public void testShortNullCompares2() { + test("testShortCompareConstant2", (Object) null); + } + + public static Object testShortCompareLess(FieldObject f, short shortValue) { + if (f.shortValue < shortValue) { + return f; + } + return null; + } + + public static Object testShortCompareLessConstant1(FieldObject f) { + if (f.shortValue < shortTestValue1) { + return f; + } + return null; + } + + public static Object testShortCompareLessConstant2(FieldObject f) { + if (f.shortValue < shortTestValue2) { + return f; + } + return null; + } + + @Test + public void testShortComparesLess() { + FieldObject f = new FieldObject(); + test("testShortCompareLess", f, shortTestValue1); + test("testShortCompareLessConstant1", f); + test("testShortCompareLessConstant2", f); + } + + @Test + public void testShortNullComparesLess() { + test("testShortCompareLess", null, shortTestValue1); + } + + @Test + public void testShortNullComparesLess1() { + test("testShortCompareLessConstant1", (Object) null); + } + + @Test + public void testShortNullComparesLess2() { + test("testShortCompareLessConstant2", (Object) null); + } + + public static Object testShortSwappedCompareLess(FieldObject f, short shortValue) { + if (shortValue < f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareLessConstant1(FieldObject f) { + if (shortTestValue1 < f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareLessConstant2(FieldObject f) { + if (shortTestValue2 < f.shortValue) { + return f; + } + return null; + } + + @Test + public void testShortSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testShortSwappedCompareLess", f, shortTestValue1); + test("testShortSwappedCompareLessConstant1", f); + test("testShortSwappedCompareLessConstant2", f); + } + + @Test + public void testShortNullSwappedComparesLess() { + test("testShortSwappedCompareLess", null, shortTestValue1); + } + + @Test + public void testShortNullSwappedComparesLess1() { + test("testShortSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testShortNullSwappedComparesLess2() { + test("testShortSwappedCompareLessConstant2", (Object) null); + } + + public static Object testShortCompareLessEqual(FieldObject f, short shortValue) { + if (f.shortValue <= shortValue) { + return f; + } + return null; + } + + public static Object testShortCompareLessEqualConstant1(FieldObject f) { + if (f.shortValue <= shortTestValue1) { + return f; + } + return null; + } + + public static Object testShortCompareLessEqualConstant2(FieldObject f) { + if (f.shortValue <= shortTestValue2) { + return f; + } + return null; + } + + @Test + public void testShortComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testShortCompareLessEqual", f, shortTestValue1); + test("testShortCompareLessEqualConstant1", f); + test("testShortCompareLessEqualConstant2", f); + } + + @Test + public void testShortNullComparesLessEqual() { + test("testShortCompareLessEqual", null, shortTestValue1); + } + + @Test + public void testShortNullComparesLessEqual1() { + test("testShortCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testShortNullComparesLessEqual2() { + test("testShortCompareLessEqualConstant2", (Object) null); + } + + public static Object testShortSwappedCompareLessEqual(FieldObject f, short shortValue) { + if (shortValue <= f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareLessEqualConstant1(FieldObject f) { + if (shortTestValue1 <= f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareLessEqualConstant2(FieldObject f) { + if (shortTestValue2 <= f.shortValue) { + return f; + } + return null; + } + + @Test + public void testShortSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testShortSwappedCompareLessEqual", f, shortTestValue1); + test("testShortSwappedCompareLessEqualConstant1", f); + test("testShortSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testShortNullSwappedComparesLessEqual() { + test("testShortSwappedCompareLessEqual", null, shortTestValue1); + } + + @Test + public void testShortNullSwappedComparesLessEqual1() { + test("testShortSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testShortNullSwappedComparesLessEqual2() { + test("testShortSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testShortCompareGreater(FieldObject f, short shortValue) { + if (f.shortValue > shortValue) { + return f; + } + return null; + } + + public static Object testShortCompareGreaterConstant1(FieldObject f) { + if (f.shortValue > shortTestValue1) { + return f; + } + return null; + } + + public static Object testShortCompareGreaterConstant2(FieldObject f) { + if (f.shortValue > shortTestValue2) { + return f; + } + return null; + } + + @Test + public void testShortComparesGreater() { + FieldObject f = new FieldObject(); + test("testShortCompareGreater", f, shortTestValue1); + test("testShortCompareGreaterConstant1", f); + test("testShortCompareGreaterConstant2", f); + } + + @Test + public void testShortNullComparesGreater() { + test("testShortCompareGreater", null, shortTestValue1); + } + + @Test + public void testShortNullComparesGreater1() { + test("testShortCompareGreaterConstant1", (Object) null); + } + + @Test + public void testShortNullComparesGreater2() { + test("testShortCompareGreaterConstant2", (Object) null); + } + + public static Object testShortSwappedCompareGreater(FieldObject f, short shortValue) { + if (shortValue > f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareGreaterConstant1(FieldObject f) { + if (shortTestValue1 > f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareGreaterConstant2(FieldObject f) { + if (shortTestValue2 > f.shortValue) { + return f; + } + return null; + } + + @Test + public void testShortSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testShortSwappedCompareGreater", f, shortTestValue1); + test("testShortSwappedCompareGreaterConstant1", f); + test("testShortSwappedCompareGreaterConstant2", f); + } + + @Test + public void testShortNullSwappedComparesGreater() { + test("testShortSwappedCompareGreater", null, shortTestValue1); + } + + @Test + public void testShortNullSwappedComparesGreater1() { + test("testShortSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testShortNullSwappedComparesGreater2() { + test("testShortSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testShortCompareGreaterEqual(FieldObject f, short shortValue) { + if (f.shortValue >= shortValue) { + return f; + } + return null; + } + + public static Object testShortCompareGreaterEqualConstant1(FieldObject f) { + if (f.shortValue >= shortTestValue1) { + return f; + } + return null; + } + + public static Object testShortCompareGreaterEqualConstant2(FieldObject f) { + if (f.shortValue >= shortTestValue2) { + return f; + } + return null; + } + + @Test + public void testShortComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testShortCompareGreaterEqual", f, shortTestValue1); + test("testShortCompareGreaterEqualConstant1", f); + test("testShortCompareGreaterEqualConstant2", f); + } + + @Test + public void testShortNullComparesGreaterEqual() { + test("testShortCompareGreaterEqual", null, shortTestValue1); + } + + @Test + public void testShortNullComparesGreaterEqual1() { + test("testShortCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testShortNullComparesGreaterEqual2() { + test("testShortCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testShortSwappedCompareGreaterEqual(FieldObject f, short shortValue) { + if (shortValue >= f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (shortTestValue1 >= f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (shortTestValue2 >= f.shortValue) { + return f; + } + return null; + } + + @Test + public void testShortSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testShortSwappedCompareGreaterEqual", f, shortTestValue1); + test("testShortSwappedCompareGreaterEqualConstant1", f); + test("testShortSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testShortNullSwappedComparesGreaterEqual() { + test("testShortSwappedCompareGreaterEqual", null, shortTestValue1); + } + + @Test + public void testShortNullSwappedComparesGreaterEqual1() { + test("testShortSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testShortNullSwappedComparesGreaterEqual2() { + test("testShortSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testCharCompare(FieldObject f, char charValue) { + if (f.charValue == charValue) { + return f; + } + return null; + } + + public static Object testCharCompareConstant1(FieldObject f) { + if (f.charValue == charTestValue1) { + return f; + } + return null; + } + + public static Object testCharCompareConstant2(FieldObject f) { + if (f.charValue == charTestValue2) { + return f; + } + return null; + } + + @Test + public void testCharCompares() { + FieldObject f = new FieldObject(); + test("testCharCompare", f, charTestValue1); + test("testCharCompareConstant1", f); + test("testCharCompareConstant2", f); + } + + @Test + public void testCharNullCompares() { + test("testCharCompare", null, charTestValue1); + } + + @Test + public void testCharNullCompares1() { + test("testCharCompareConstant1", (Object) null); + } + + @Test + public void testCharNullCompares2() { + test("testCharCompareConstant2", (Object) null); + } + + public static Object testCharCompareLess(FieldObject f, char charValue) { + if (f.charValue < charValue) { + return f; + } + return null; + } + + public static Object testCharCompareLessConstant1(FieldObject f) { + if (f.charValue < charTestValue1) { + return f; + } + return null; + } + + public static Object testCharCompareLessConstant2(FieldObject f) { + if (f.charValue < charTestValue2) { + return f; + } + return null; + } + + @Test + public void testCharComparesLess() { + FieldObject f = new FieldObject(); + test("testCharCompareLess", f, charTestValue1); + test("testCharCompareLessConstant1", f); + test("testCharCompareLessConstant2", f); + } + + @Test + public void testCharNullComparesLess() { + test("testCharCompareLess", null, charTestValue1); + } + + @Test + public void testCharNullComparesLess1() { + test("testCharCompareLessConstant1", (Object) null); + } + + @Test + public void testCharNullComparesLess2() { + test("testCharCompareLessConstant2", (Object) null); + } + + public static Object testCharSwappedCompareLess(FieldObject f, char charValue) { + if (charValue < f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareLessConstant1(FieldObject f) { + if (charTestValue1 < f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareLessConstant2(FieldObject f) { + if (charTestValue2 < f.charValue) { + return f; + } + return null; + } + + @Test + public void testCharSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testCharSwappedCompareLess", f, charTestValue1); + test("testCharSwappedCompareLessConstant1", f); + test("testCharSwappedCompareLessConstant2", f); + } + + @Test + public void testCharNullSwappedComparesLess() { + test("testCharSwappedCompareLess", null, charTestValue1); + } + + @Test + public void testCharNullSwappedComparesLess1() { + test("testCharSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testCharNullSwappedComparesLess2() { + test("testCharSwappedCompareLessConstant2", (Object) null); + } + + public static Object testCharCompareLessEqual(FieldObject f, char charValue) { + if (f.charValue <= charValue) { + return f; + } + return null; + } + + public static Object testCharCompareLessEqualConstant1(FieldObject f) { + if (f.charValue <= charTestValue1) { + return f; + } + return null; + } + + public static Object testCharCompareLessEqualConstant2(FieldObject f) { + if (f.charValue <= charTestValue2) { + return f; + } + return null; + } + + @Test + public void testCharComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testCharCompareLessEqual", f, charTestValue1); + test("testCharCompareLessEqualConstant1", f); + test("testCharCompareLessEqualConstant2", f); + } + + @Test + public void testCharNullComparesLessEqual() { + test("testCharCompareLessEqual", null, charTestValue1); + } + + @Test + public void testCharNullComparesLessEqual1() { + test("testCharCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testCharNullComparesLessEqual2() { + test("testCharCompareLessEqualConstant2", (Object) null); + } + + public static Object testCharSwappedCompareLessEqual(FieldObject f, char charValue) { + if (charValue <= f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareLessEqualConstant1(FieldObject f) { + if (charTestValue1 <= f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareLessEqualConstant2(FieldObject f) { + if (charTestValue2 <= f.charValue) { + return f; + } + return null; + } + + @Test + public void testCharSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testCharSwappedCompareLessEqual", f, charTestValue1); + test("testCharSwappedCompareLessEqualConstant1", f); + test("testCharSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testCharNullSwappedComparesLessEqual() { + test("testCharSwappedCompareLessEqual", null, charTestValue1); + } + + @Test + public void testCharNullSwappedComparesLessEqual1() { + test("testCharSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testCharNullSwappedComparesLessEqual2() { + test("testCharSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testCharCompareGreater(FieldObject f, char charValue) { + if (f.charValue > charValue) { + return f; + } + return null; + } + + public static Object testCharCompareGreaterConstant1(FieldObject f) { + if (f.charValue > charTestValue1) { + return f; + } + return null; + } + + public static Object testCharCompareGreaterConstant2(FieldObject f) { + if (f.charValue > charTestValue2) { + return f; + } + return null; + } + + @Test + public void testCharComparesGreater() { + FieldObject f = new FieldObject(); + test("testCharCompareGreater", f, charTestValue1); + test("testCharCompareGreaterConstant1", f); + test("testCharCompareGreaterConstant2", f); + } + + @Test + public void testCharNullComparesGreater() { + test("testCharCompareGreater", null, charTestValue1); + } + + @Test + public void testCharNullComparesGreater1() { + test("testCharCompareGreaterConstant1", (Object) null); + } + + @Test + public void testCharNullComparesGreater2() { + test("testCharCompareGreaterConstant2", (Object) null); + } + + public static Object testCharSwappedCompareGreater(FieldObject f, char charValue) { + if (charValue > f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareGreaterConstant1(FieldObject f) { + if (charTestValue1 > f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareGreaterConstant2(FieldObject f) { + if (charTestValue2 > f.charValue) { + return f; + } + return null; + } + + @Test + public void testCharSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testCharSwappedCompareGreater", f, charTestValue1); + test("testCharSwappedCompareGreaterConstant1", f); + test("testCharSwappedCompareGreaterConstant2", f); + } + + @Test + public void testCharNullSwappedComparesGreater() { + test("testCharSwappedCompareGreater", null, charTestValue1); + } + + @Test + public void testCharNullSwappedComparesGreater1() { + test("testCharSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testCharNullSwappedComparesGreater2() { + test("testCharSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testCharCompareGreaterEqual(FieldObject f, char charValue) { + if (f.charValue >= charValue) { + return f; + } + return null; + } + + public static Object testCharCompareGreaterEqualConstant1(FieldObject f) { + if (f.charValue >= charTestValue1) { + return f; + } + return null; + } + + public static Object testCharCompareGreaterEqualConstant2(FieldObject f) { + if (f.charValue >= charTestValue2) { + return f; + } + return null; + } + + @Test + public void testCharComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testCharCompareGreaterEqual", f, charTestValue1); + test("testCharCompareGreaterEqualConstant1", f); + test("testCharCompareGreaterEqualConstant2", f); + } + + @Test + public void testCharNullComparesGreaterEqual() { + test("testCharCompareGreaterEqual", null, charTestValue1); + } + + @Test + public void testCharNullComparesGreaterEqual1() { + test("testCharCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testCharNullComparesGreaterEqual2() { + test("testCharCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testCharSwappedCompareGreaterEqual(FieldObject f, char charValue) { + if (charValue >= f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (charTestValue1 >= f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (charTestValue2 >= f.charValue) { + return f; + } + return null; + } + + @Test + public void testCharSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testCharSwappedCompareGreaterEqual", f, charTestValue1); + test("testCharSwappedCompareGreaterEqualConstant1", f); + test("testCharSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testCharNullSwappedComparesGreaterEqual() { + test("testCharSwappedCompareGreaterEqual", null, charTestValue1); + } + + @Test + public void testCharNullSwappedComparesGreaterEqual1() { + test("testCharSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testCharNullSwappedComparesGreaterEqual2() { + test("testCharSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testIntCompare(FieldObject f, int intValue) { + if (f.intValue == intValue) { + return f; + } + return null; + } + + public static Object testIntCompareConstant1(FieldObject f) { + if (f.intValue == intTestValue1) { + return f; + } + return null; + } + + public static Object testIntCompareConstant2(FieldObject f) { + if (f.intValue == intTestValue2) { + return f; + } + return null; + } + + @Test + public void testIntCompares() { + FieldObject f = new FieldObject(); + test("testIntCompare", f, intTestValue1); + test("testIntCompareConstant1", f); + test("testIntCompareConstant2", f); + } + + @Test + public void testIntNullCompares() { + test("testIntCompare", null, intTestValue1); + } + + @Test + public void testIntNullCompares1() { + test("testIntCompareConstant1", (Object) null); + } + + @Test + public void testIntNullCompares2() { + test("testIntCompareConstant2", (Object) null); + } + + public static Object testIntCompareLess(FieldObject f, int intValue) { + if (f.intValue < intValue) { + return f; + } + return null; + } + + public static Object testIntCompareLessConstant1(FieldObject f) { + if (f.intValue < intTestValue1) { + return f; + } + return null; + } + + public static Object testIntCompareLessConstant2(FieldObject f) { + if (f.intValue < intTestValue2) { + return f; + } + return null; + } + + @Test + public void testIntComparesLess() { + FieldObject f = new FieldObject(); + test("testIntCompareLess", f, intTestValue1); + test("testIntCompareLessConstant1", f); + test("testIntCompareLessConstant2", f); + } + + @Test + public void testIntNullComparesLess() { + test("testIntCompareLess", null, intTestValue1); + } + + @Test + public void testIntNullComparesLess1() { + test("testIntCompareLessConstant1", (Object) null); + } + + @Test + public void testIntNullComparesLess2() { + test("testIntCompareLessConstant2", (Object) null); + } + + public static Object testIntSwappedCompareLess(FieldObject f, int intValue) { + if (intValue < f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareLessConstant1(FieldObject f) { + if (intTestValue1 < f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareLessConstant2(FieldObject f) { + if (intTestValue2 < f.intValue) { + return f; + } + return null; + } + + @Test + public void testIntSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testIntSwappedCompareLess", f, intTestValue1); + test("testIntSwappedCompareLessConstant1", f); + test("testIntSwappedCompareLessConstant2", f); + } + + @Test + public void testIntNullSwappedComparesLess() { + test("testIntSwappedCompareLess", null, intTestValue1); + } + + @Test + public void testIntNullSwappedComparesLess1() { + test("testIntSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testIntNullSwappedComparesLess2() { + test("testIntSwappedCompareLessConstant2", (Object) null); + } + + public static Object testIntCompareLessEqual(FieldObject f, int intValue) { + if (f.intValue <= intValue) { + return f; + } + return null; + } + + public static Object testIntCompareLessEqualConstant1(FieldObject f) { + if (f.intValue <= intTestValue1) { + return f; + } + return null; + } + + public static Object testIntCompareLessEqualConstant2(FieldObject f) { + if (f.intValue <= intTestValue2) { + return f; + } + return null; + } + + @Test + public void testIntComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testIntCompareLessEqual", f, intTestValue1); + test("testIntCompareLessEqualConstant1", f); + test("testIntCompareLessEqualConstant2", f); + } + + @Test + public void testIntNullComparesLessEqual() { + test("testIntCompareLessEqual", null, intTestValue1); + } + + @Test + public void testIntNullComparesLessEqual1() { + test("testIntCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testIntNullComparesLessEqual2() { + test("testIntCompareLessEqualConstant2", (Object) null); + } + + public static Object testIntSwappedCompareLessEqual(FieldObject f, int intValue) { + if (intValue <= f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareLessEqualConstant1(FieldObject f) { + if (intTestValue1 <= f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareLessEqualConstant2(FieldObject f) { + if (intTestValue2 <= f.intValue) { + return f; + } + return null; + } + + @Test + public void testIntSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testIntSwappedCompareLessEqual", f, intTestValue1); + test("testIntSwappedCompareLessEqualConstant1", f); + test("testIntSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testIntNullSwappedComparesLessEqual() { + test("testIntSwappedCompareLessEqual", null, intTestValue1); + } + + @Test + public void testIntNullSwappedComparesLessEqual1() { + test("testIntSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testIntNullSwappedComparesLessEqual2() { + test("testIntSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testIntCompareGreater(FieldObject f, int intValue) { + if (f.intValue > intValue) { + return f; + } + return null; + } + + public static Object testIntCompareGreaterConstant1(FieldObject f) { + if (f.intValue > intTestValue1) { + return f; + } + return null; + } + + public static Object testIntCompareGreaterConstant2(FieldObject f) { + if (f.intValue > intTestValue2) { + return f; + } + return null; + } + + @Test + public void testIntComparesGreater() { + FieldObject f = new FieldObject(); + test("testIntCompareGreater", f, intTestValue1); + test("testIntCompareGreaterConstant1", f); + test("testIntCompareGreaterConstant2", f); + } + + @Test + public void testIntNullComparesGreater() { + test("testIntCompareGreater", null, intTestValue1); + } + + @Test + public void testIntNullComparesGreater1() { + test("testIntCompareGreaterConstant1", (Object) null); + } + + @Test + public void testIntNullComparesGreater2() { + test("testIntCompareGreaterConstant2", (Object) null); + } + + public static Object testIntSwappedCompareGreater(FieldObject f, int intValue) { + if (intValue > f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareGreaterConstant1(FieldObject f) { + if (intTestValue1 > f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareGreaterConstant2(FieldObject f) { + if (intTestValue2 > f.intValue) { + return f; + } + return null; + } + + @Test + public void testIntSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testIntSwappedCompareGreater", f, intTestValue1); + test("testIntSwappedCompareGreaterConstant1", f); + test("testIntSwappedCompareGreaterConstant2", f); + } + + @Test + public void testIntNullSwappedComparesGreater() { + test("testIntSwappedCompareGreater", null, intTestValue1); + } + + @Test + public void testIntNullSwappedComparesGreater1() { + test("testIntSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testIntNullSwappedComparesGreater2() { + test("testIntSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testIntCompareGreaterEqual(FieldObject f, int intValue) { + if (f.intValue >= intValue) { + return f; + } + return null; + } + + public static Object testIntCompareGreaterEqualConstant1(FieldObject f) { + if (f.intValue >= intTestValue1) { + return f; + } + return null; + } + + public static Object testIntCompareGreaterEqualConstant2(FieldObject f) { + if (f.intValue >= intTestValue2) { + return f; + } + return null; + } + + @Test + public void testIntComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testIntCompareGreaterEqual", f, intTestValue1); + test("testIntCompareGreaterEqualConstant1", f); + test("testIntCompareGreaterEqualConstant2", f); + } + + @Test + public void testIntNullComparesGreaterEqual() { + test("testIntCompareGreaterEqual", null, intTestValue1); + } + + @Test + public void testIntNullComparesGreaterEqual1() { + test("testIntCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testIntNullComparesGreaterEqual2() { + test("testIntCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testIntSwappedCompareGreaterEqual(FieldObject f, int intValue) { + if (intValue >= f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (intTestValue1 >= f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (intTestValue2 >= f.intValue) { + return f; + } + return null; + } + + @Test + public void testIntSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testIntSwappedCompareGreaterEqual", f, intTestValue1); + test("testIntSwappedCompareGreaterEqualConstant1", f); + test("testIntSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testIntNullSwappedComparesGreaterEqual() { + test("testIntSwappedCompareGreaterEqual", null, intTestValue1); + } + + @Test + public void testIntNullSwappedComparesGreaterEqual1() { + test("testIntSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testIntNullSwappedComparesGreaterEqual2() { + test("testIntSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testFloatCompare(FieldObject f, float floatValue) { + if (f.floatValue == floatValue) { + return f; + } + return null; + } + + public static Object testFloatCompareConstant1(FieldObject f) { + if (f.floatValue == floatTestValue1) { + return f; + } + return null; + } + + public static Object testFloatCompareConstant2(FieldObject f) { + if (f.floatValue == floatTestValue2) { + return f; + } + return null; + } + + @Test + public void testFloatCompares() { + FieldObject f = new FieldObject(); + test("testFloatCompare", f, floatTestValue1); + test("testFloatCompareConstant1", f); + test("testFloatCompareConstant2", f); + } + + @Test + public void testFloatNullCompares() { + test("testFloatCompare", null, floatTestValue1); + } + + @Test + public void testFloatNullCompares1() { + test("testFloatCompareConstant1", (Object) null); + } + + @Test + public void testFloatNullCompares2() { + test("testFloatCompareConstant2", (Object) null); + } + + public static Object testFloatCompareLess(FieldObject f, float floatValue) { + if (f.floatValue < floatValue) { + return f; + } + return null; + } + + public static Object testFloatCompareLessConstant1(FieldObject f) { + if (f.floatValue < floatTestValue1) { + return f; + } + return null; + } + + public static Object testFloatCompareLessConstant2(FieldObject f) { + if (f.floatValue < floatTestValue2) { + return f; + } + return null; + } + + @Test + public void testFloatComparesLess() { + FieldObject f = new FieldObject(); + test("testFloatCompareLess", f, floatTestValue1); + test("testFloatCompareLessConstant1", f); + test("testFloatCompareLessConstant2", f); + } + + @Test + public void testFloatNullComparesLess() { + test("testFloatCompareLess", null, floatTestValue1); + } + + @Test + public void testFloatNullComparesLess1() { + test("testFloatCompareLessConstant1", (Object) null); + } + + @Test + public void testFloatNullComparesLess2() { + test("testFloatCompareLessConstant2", (Object) null); + } + + public static Object testFloatSwappedCompareLess(FieldObject f, float floatValue) { + if (floatValue < f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareLessConstant1(FieldObject f) { + if (floatTestValue1 < f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareLessConstant2(FieldObject f) { + if (floatTestValue2 < f.floatValue) { + return f; + } + return null; + } + + @Test + public void testFloatSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testFloatSwappedCompareLess", f, floatTestValue1); + test("testFloatSwappedCompareLessConstant1", f); + test("testFloatSwappedCompareLessConstant2", f); + } + + @Test + public void testFloatNullSwappedComparesLess() { + test("testFloatSwappedCompareLess", null, floatTestValue1); + } + + @Test + public void testFloatNullSwappedComparesLess1() { + test("testFloatSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testFloatNullSwappedComparesLess2() { + test("testFloatSwappedCompareLessConstant2", (Object) null); + } + + public static Object testFloatCompareLessEqual(FieldObject f, float floatValue) { + if (f.floatValue <= floatValue) { + return f; + } + return null; + } + + public static Object testFloatCompareLessEqualConstant1(FieldObject f) { + if (f.floatValue <= floatTestValue1) { + return f; + } + return null; + } + + public static Object testFloatCompareLessEqualConstant2(FieldObject f) { + if (f.floatValue <= floatTestValue2) { + return f; + } + return null; + } + + @Test + public void testFloatComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testFloatCompareLessEqual", f, floatTestValue1); + test("testFloatCompareLessEqualConstant1", f); + test("testFloatCompareLessEqualConstant2", f); + } + + @Test + public void testFloatNullComparesLessEqual() { + test("testFloatCompareLessEqual", null, floatTestValue1); + } + + @Test + public void testFloatNullComparesLessEqual1() { + test("testFloatCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testFloatNullComparesLessEqual2() { + test("testFloatCompareLessEqualConstant2", (Object) null); + } + + public static Object testFloatSwappedCompareLessEqual(FieldObject f, float floatValue) { + if (floatValue <= f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareLessEqualConstant1(FieldObject f) { + if (floatTestValue1 <= f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareLessEqualConstant2(FieldObject f) { + if (floatTestValue2 <= f.floatValue) { + return f; + } + return null; + } + + @Test + public void testFloatSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testFloatSwappedCompareLessEqual", f, floatTestValue1); + test("testFloatSwappedCompareLessEqualConstant1", f); + test("testFloatSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testFloatNullSwappedComparesLessEqual() { + test("testFloatSwappedCompareLessEqual", null, floatTestValue1); + } + + @Test + public void testFloatNullSwappedComparesLessEqual1() { + test("testFloatSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testFloatNullSwappedComparesLessEqual2() { + test("testFloatSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testFloatCompareGreater(FieldObject f, float floatValue) { + if (f.floatValue > floatValue) { + return f; + } + return null; + } + + public static Object testFloatCompareGreaterConstant1(FieldObject f) { + if (f.floatValue > floatTestValue1) { + return f; + } + return null; + } + + public static Object testFloatCompareGreaterConstant2(FieldObject f) { + if (f.floatValue > floatTestValue2) { + return f; + } + return null; + } + + @Test + public void testFloatComparesGreater() { + FieldObject f = new FieldObject(); + test("testFloatCompareGreater", f, floatTestValue1); + test("testFloatCompareGreaterConstant1", f); + test("testFloatCompareGreaterConstant2", f); + } + + @Test + public void testFloatNullComparesGreater() { + test("testFloatCompareGreater", null, floatTestValue1); + } + + @Test + public void testFloatNullComparesGreater1() { + test("testFloatCompareGreaterConstant1", (Object) null); + } + + @Test + public void testFloatNullComparesGreater2() { + test("testFloatCompareGreaterConstant2", (Object) null); + } + + public static Object testFloatSwappedCompareGreater(FieldObject f, float floatValue) { + if (floatValue > f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareGreaterConstant1(FieldObject f) { + if (floatTestValue1 > f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareGreaterConstant2(FieldObject f) { + if (floatTestValue2 > f.floatValue) { + return f; + } + return null; + } + + @Test + public void testFloatSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testFloatSwappedCompareGreater", f, floatTestValue1); + test("testFloatSwappedCompareGreaterConstant1", f); + test("testFloatSwappedCompareGreaterConstant2", f); + } + + @Test + public void testFloatNullSwappedComparesGreater() { + test("testFloatSwappedCompareGreater", null, floatTestValue1); + } + + @Test + public void testFloatNullSwappedComparesGreater1() { + test("testFloatSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testFloatNullSwappedComparesGreater2() { + test("testFloatSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testFloatCompareGreaterEqual(FieldObject f, float floatValue) { + if (f.floatValue >= floatValue) { + return f; + } + return null; + } + + public static Object testFloatCompareGreaterEqualConstant1(FieldObject f) { + if (f.floatValue >= floatTestValue1) { + return f; + } + return null; + } + + public static Object testFloatCompareGreaterEqualConstant2(FieldObject f) { + if (f.floatValue >= floatTestValue2) { + return f; + } + return null; + } + + @Test + public void testFloatComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testFloatCompareGreaterEqual", f, floatTestValue1); + test("testFloatCompareGreaterEqualConstant1", f); + test("testFloatCompareGreaterEqualConstant2", f); + } + + @Test + public void testFloatNullComparesGreaterEqual() { + test("testFloatCompareGreaterEqual", null, floatTestValue1); + } + + @Test + public void testFloatNullComparesGreaterEqual1() { + test("testFloatCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testFloatNullComparesGreaterEqual2() { + test("testFloatCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testFloatSwappedCompareGreaterEqual(FieldObject f, float floatValue) { + if (floatValue >= f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (floatTestValue1 >= f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (floatTestValue2 >= f.floatValue) { + return f; + } + return null; + } + + @Test + public void testFloatSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testFloatSwappedCompareGreaterEqual", f, floatTestValue1); + test("testFloatSwappedCompareGreaterEqualConstant1", f); + test("testFloatSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testFloatNullSwappedComparesGreaterEqual() { + test("testFloatSwappedCompareGreaterEqual", null, floatTestValue1); + } + + @Test + public void testFloatNullSwappedComparesGreaterEqual1() { + test("testFloatSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testFloatNullSwappedComparesGreaterEqual2() { + test("testFloatSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testLongCompare(FieldObject f, long longValue) { + if (f.longValue == longValue) { + return f; + } + return null; + } + + public static Object testLongCompareConstant1(FieldObject f) { + if (f.longValue == longTestValue1) { + return f; + } + return null; + } + + public static Object testLongCompareConstant2(FieldObject f) { + if (f.longValue == longTestValue2) { + return f; + } + return null; + } + + @Test + public void testLongCompares() { + FieldObject f = new FieldObject(); + test("testLongCompare", f, longTestValue1); + test("testLongCompareConstant1", f); + test("testLongCompareConstant2", f); + } + + @Test + public void testLongNullCompares() { + test("testLongCompare", null, longTestValue1); + } + + @Test + public void testLongNullCompares1() { + test("testLongCompareConstant1", (Object) null); + } + + @Test + public void testLongNullCompares2() { + test("testLongCompareConstant2", (Object) null); + } + + public static Object testLongCompareLess(FieldObject f, long longValue) { + if (f.longValue < longValue) { + return f; + } + return null; + } + + public static Object testLongCompareLessConstant1(FieldObject f) { + if (f.longValue < longTestValue1) { + return f; + } + return null; + } + + public static Object testLongCompareLessConstant2(FieldObject f) { + if (f.longValue < longTestValue2) { + return f; + } + return null; + } + + @Test + public void testLongComparesLess() { + FieldObject f = new FieldObject(); + test("testLongCompareLess", f, longTestValue1); + test("testLongCompareLessConstant1", f); + test("testLongCompareLessConstant2", f); + } + + @Test + public void testLongNullComparesLess() { + test("testLongCompareLess", null, longTestValue1); + } + + @Test + public void testLongNullComparesLess1() { + test("testLongCompareLessConstant1", (Object) null); + } + + @Test + public void testLongNullComparesLess2() { + test("testLongCompareLessConstant2", (Object) null); + } + + public static Object testLongSwappedCompareLess(FieldObject f, long longValue) { + if (longValue < f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareLessConstant1(FieldObject f) { + if (longTestValue1 < f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareLessConstant2(FieldObject f) { + if (longTestValue2 < f.longValue) { + return f; + } + return null; + } + + @Test + public void testLongSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testLongSwappedCompareLess", f, longTestValue1); + test("testLongSwappedCompareLessConstant1", f); + test("testLongSwappedCompareLessConstant2", f); + } + + @Test + public void testLongNullSwappedComparesLess() { + test("testLongSwappedCompareLess", null, longTestValue1); + } + + @Test + public void testLongNullSwappedComparesLess1() { + test("testLongSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testLongNullSwappedComparesLess2() { + test("testLongSwappedCompareLessConstant2", (Object) null); + } + + public static Object testLongCompareLessEqual(FieldObject f, long longValue) { + if (f.longValue <= longValue) { + return f; + } + return null; + } + + public static Object testLongCompareLessEqualConstant1(FieldObject f) { + if (f.longValue <= longTestValue1) { + return f; + } + return null; + } + + public static Object testLongCompareLessEqualConstant2(FieldObject f) { + if (f.longValue <= longTestValue2) { + return f; + } + return null; + } + + @Test + public void testLongComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testLongCompareLessEqual", f, longTestValue1); + test("testLongCompareLessEqualConstant1", f); + test("testLongCompareLessEqualConstant2", f); + } + + @Test + public void testLongNullComparesLessEqual() { + test("testLongCompareLessEqual", null, longTestValue1); + } + + @Test + public void testLongNullComparesLessEqual1() { + test("testLongCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testLongNullComparesLessEqual2() { + test("testLongCompareLessEqualConstant2", (Object) null); + } + + public static Object testLongSwappedCompareLessEqual(FieldObject f, long longValue) { + if (longValue <= f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareLessEqualConstant1(FieldObject f) { + if (longTestValue1 <= f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareLessEqualConstant2(FieldObject f) { + if (longTestValue2 <= f.longValue) { + return f; + } + return null; + } + + @Test + public void testLongSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testLongSwappedCompareLessEqual", f, longTestValue1); + test("testLongSwappedCompareLessEqualConstant1", f); + test("testLongSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testLongNullSwappedComparesLessEqual() { + test("testLongSwappedCompareLessEqual", null, longTestValue1); + } + + @Test + public void testLongNullSwappedComparesLessEqual1() { + test("testLongSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testLongNullSwappedComparesLessEqual2() { + test("testLongSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testLongCompareGreater(FieldObject f, long longValue) { + if (f.longValue > longValue) { + return f; + } + return null; + } + + public static Object testLongCompareGreaterConstant1(FieldObject f) { + if (f.longValue > longTestValue1) { + return f; + } + return null; + } + + public static Object testLongCompareGreaterConstant2(FieldObject f) { + if (f.longValue > longTestValue2) { + return f; + } + return null; + } + + @Test + public void testLongComparesGreater() { + FieldObject f = new FieldObject(); + test("testLongCompareGreater", f, longTestValue1); + test("testLongCompareGreaterConstant1", f); + test("testLongCompareGreaterConstant2", f); + } + + @Test + public void testLongNullComparesGreater() { + test("testLongCompareGreater", null, longTestValue1); + } + + @Test + public void testLongNullComparesGreater1() { + test("testLongCompareGreaterConstant1", (Object) null); + } + + @Test + public void testLongNullComparesGreater2() { + test("testLongCompareGreaterConstant2", (Object) null); + } + + public static Object testLongSwappedCompareGreater(FieldObject f, long longValue) { + if (longValue > f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareGreaterConstant1(FieldObject f) { + if (longTestValue1 > f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareGreaterConstant2(FieldObject f) { + if (longTestValue2 > f.longValue) { + return f; + } + return null; + } + + @Test + public void testLongSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testLongSwappedCompareGreater", f, longTestValue1); + test("testLongSwappedCompareGreaterConstant1", f); + test("testLongSwappedCompareGreaterConstant2", f); + } + + @Test + public void testLongNullSwappedComparesGreater() { + test("testLongSwappedCompareGreater", null, longTestValue1); + } + + @Test + public void testLongNullSwappedComparesGreater1() { + test("testLongSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testLongNullSwappedComparesGreater2() { + test("testLongSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testLongCompareGreaterEqual(FieldObject f, long longValue) { + if (f.longValue >= longValue) { + return f; + } + return null; + } + + public static Object testLongCompareGreaterEqualConstant1(FieldObject f) { + if (f.longValue >= longTestValue1) { + return f; + } + return null; + } + + public static Object testLongCompareGreaterEqualConstant2(FieldObject f) { + if (f.longValue >= longTestValue2) { + return f; + } + return null; + } + + @Test + public void testLongComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testLongCompareGreaterEqual", f, longTestValue1); + test("testLongCompareGreaterEqualConstant1", f); + test("testLongCompareGreaterEqualConstant2", f); + } + + @Test + public void testLongNullComparesGreaterEqual() { + test("testLongCompareGreaterEqual", null, longTestValue1); + } + + @Test + public void testLongNullComparesGreaterEqual1() { + test("testLongCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testLongNullComparesGreaterEqual2() { + test("testLongCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testLongSwappedCompareGreaterEqual(FieldObject f, long longValue) { + if (longValue >= f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (longTestValue1 >= f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (longTestValue2 >= f.longValue) { + return f; + } + return null; + } + + @Test + public void testLongSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testLongSwappedCompareGreaterEqual", f, longTestValue1); + test("testLongSwappedCompareGreaterEqualConstant1", f); + test("testLongSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testLongNullSwappedComparesGreaterEqual() { + test("testLongSwappedCompareGreaterEqual", null, longTestValue1); + } + + @Test + public void testLongNullSwappedComparesGreaterEqual1() { + test("testLongSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testLongNullSwappedComparesGreaterEqual2() { + test("testLongSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testDoubleCompare(FieldObject f, double doubleValue) { + if (f.doubleValue == doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleCompareConstant1(FieldObject f) { + if (f.doubleValue == doubleTestValue1) { + return f; + } + return null; + } + + public static Object testDoubleCompareConstant2(FieldObject f) { + if (f.doubleValue == doubleTestValue2) { + return f; + } + return null; + } + + @Test + public void testDoubleCompares() { + FieldObject f = new FieldObject(); + test("testDoubleCompare", f, doubleTestValue1); + test("testDoubleCompareConstant1", f); + test("testDoubleCompareConstant2", f); + } + + @Test + public void testDoubleNullCompares() { + test("testDoubleCompare", null, doubleTestValue1); + } + + @Test + public void testDoubleNullCompares1() { + test("testDoubleCompareConstant1", (Object) null); + } + + @Test + public void testDoubleNullCompares2() { + test("testDoubleCompareConstant2", (Object) null); + } + + public static Object testDoubleCompareLess(FieldObject f, double doubleValue) { + if (f.doubleValue < doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleCompareLessConstant1(FieldObject f) { + if (f.doubleValue < doubleTestValue1) { + return f; + } + return null; + } + + public static Object testDoubleCompareLessConstant2(FieldObject f) { + if (f.doubleValue < doubleTestValue2) { + return f; + } + return null; + } + + @Test + public void testDoubleComparesLess() { + FieldObject f = new FieldObject(); + test("testDoubleCompareLess", f, doubleTestValue1); + test("testDoubleCompareLessConstant1", f); + test("testDoubleCompareLessConstant2", f); + } + + @Test + public void testDoubleNullComparesLess() { + test("testDoubleCompareLess", null, doubleTestValue1); + } + + @Test + public void testDoubleNullComparesLess1() { + test("testDoubleCompareLessConstant1", (Object) null); + } + + @Test + public void testDoubleNullComparesLess2() { + test("testDoubleCompareLessConstant2", (Object) null); + } + + public static Object testDoubleSwappedCompareLess(FieldObject f, double doubleValue) { + if (doubleValue < f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareLessConstant1(FieldObject f) { + if (doubleTestValue1 < f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareLessConstant2(FieldObject f) { + if (doubleTestValue2 < f.doubleValue) { + return f; + } + return null; + } + + @Test + public void testDoubleSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testDoubleSwappedCompareLess", f, doubleTestValue1); + test("testDoubleSwappedCompareLessConstant1", f); + test("testDoubleSwappedCompareLessConstant2", f); + } + + @Test + public void testDoubleNullSwappedComparesLess() { + test("testDoubleSwappedCompareLess", null, doubleTestValue1); + } + + @Test + public void testDoubleNullSwappedComparesLess1() { + test("testDoubleSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testDoubleNullSwappedComparesLess2() { + test("testDoubleSwappedCompareLessConstant2", (Object) null); + } + + public static Object testDoubleCompareLessEqual(FieldObject f, double doubleValue) { + if (f.doubleValue <= doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleCompareLessEqualConstant1(FieldObject f) { + if (f.doubleValue <= doubleTestValue1) { + return f; + } + return null; + } + + public static Object testDoubleCompareLessEqualConstant2(FieldObject f) { + if (f.doubleValue <= doubleTestValue2) { + return f; + } + return null; + } + + @Test + public void testDoubleComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testDoubleCompareLessEqual", f, doubleTestValue1); + test("testDoubleCompareLessEqualConstant1", f); + test("testDoubleCompareLessEqualConstant2", f); + } + + @Test + public void testDoubleNullComparesLessEqual() { + test("testDoubleCompareLessEqual", null, doubleTestValue1); + } + + @Test + public void testDoubleNullComparesLessEqual1() { + test("testDoubleCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testDoubleNullComparesLessEqual2() { + test("testDoubleCompareLessEqualConstant2", (Object) null); + } + + public static Object testDoubleSwappedCompareLessEqual(FieldObject f, double doubleValue) { + if (doubleValue <= f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareLessEqualConstant1(FieldObject f) { + if (doubleTestValue1 <= f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareLessEqualConstant2(FieldObject f) { + if (doubleTestValue2 <= f.doubleValue) { + return f; + } + return null; + } + + @Test + public void testDoubleSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testDoubleSwappedCompareLessEqual", f, doubleTestValue1); + test("testDoubleSwappedCompareLessEqualConstant1", f); + test("testDoubleSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testDoubleNullSwappedComparesLessEqual() { + test("testDoubleSwappedCompareLessEqual", null, doubleTestValue1); + } + + @Test + public void testDoubleNullSwappedComparesLessEqual1() { + test("testDoubleSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testDoubleNullSwappedComparesLessEqual2() { + test("testDoubleSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testDoubleCompareGreater(FieldObject f, double doubleValue) { + if (f.doubleValue > doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleCompareGreaterConstant1(FieldObject f) { + if (f.doubleValue > doubleTestValue1) { + return f; + } + return null; + } + + public static Object testDoubleCompareGreaterConstant2(FieldObject f) { + if (f.doubleValue > doubleTestValue2) { + return f; + } + return null; + } + + @Test + public void testDoubleComparesGreater() { + FieldObject f = new FieldObject(); + test("testDoubleCompareGreater", f, doubleTestValue1); + test("testDoubleCompareGreaterConstant1", f); + test("testDoubleCompareGreaterConstant2", f); + } + + @Test + public void testDoubleNullComparesGreater() { + test("testDoubleCompareGreater", null, doubleTestValue1); + } + + @Test + public void testDoubleNullComparesGreater1() { + test("testDoubleCompareGreaterConstant1", (Object) null); + } + + @Test + public void testDoubleNullComparesGreater2() { + test("testDoubleCompareGreaterConstant2", (Object) null); + } + + public static Object testDoubleSwappedCompareGreater(FieldObject f, double doubleValue) { + if (doubleValue > f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareGreaterConstant1(FieldObject f) { + if (doubleTestValue1 > f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareGreaterConstant2(FieldObject f) { + if (doubleTestValue2 > f.doubleValue) { + return f; + } + return null; + } + + @Test + public void testDoubleSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testDoubleSwappedCompareGreater", f, doubleTestValue1); + test("testDoubleSwappedCompareGreaterConstant1", f); + test("testDoubleSwappedCompareGreaterConstant2", f); + } + + @Test + public void testDoubleNullSwappedComparesGreater() { + test("testDoubleSwappedCompareGreater", null, doubleTestValue1); + } + + @Test + public void testDoubleNullSwappedComparesGreater1() { + test("testDoubleSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testDoubleNullSwappedComparesGreater2() { + test("testDoubleSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testDoubleCompareGreaterEqual(FieldObject f, double doubleValue) { + if (f.doubleValue >= doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleCompareGreaterEqualConstant1(FieldObject f) { + if (f.doubleValue >= doubleTestValue1) { + return f; + } + return null; + } + + public static Object testDoubleCompareGreaterEqualConstant2(FieldObject f) { + if (f.doubleValue >= doubleTestValue2) { + return f; + } + return null; + } + + @Test + public void testDoubleComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testDoubleCompareGreaterEqual", f, doubleTestValue1); + test("testDoubleCompareGreaterEqualConstant1", f); + test("testDoubleCompareGreaterEqualConstant2", f); + } + + @Test + public void testDoubleNullComparesGreaterEqual() { + test("testDoubleCompareGreaterEqual", null, doubleTestValue1); + } + + @Test + public void testDoubleNullComparesGreaterEqual1() { + test("testDoubleCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testDoubleNullComparesGreaterEqual2() { + test("testDoubleCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testDoubleSwappedCompareGreaterEqual(FieldObject f, double doubleValue) { + if (doubleValue >= f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (doubleTestValue1 >= f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (doubleTestValue2 >= f.doubleValue) { + return f; + } + return null; + } + + @Test + public void testDoubleSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testDoubleSwappedCompareGreaterEqual", f, doubleTestValue1); + test("testDoubleSwappedCompareGreaterEqualConstant1", f); + test("testDoubleSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testDoubleNullSwappedComparesGreaterEqual() { + test("testDoubleSwappedCompareGreaterEqual", null, doubleTestValue1); + } + + @Test + public void testDoubleNullSwappedComparesGreaterEqual1() { + test("testDoubleSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testDoubleNullSwappedComparesGreaterEqual2() { + test("testDoubleSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testObjectCompare(FieldObject f, Object objectValue) { + if (f.objectValue == objectValue) { + return f; + } + return null; + } + + public static Object testObjectCompareConstant1(FieldObject f) { + if (f.objectValue == objectTestValue1) { + return f; + } + return null; + } + + public static Object testObjectCompareConstant2(FieldObject f) { + if (f.objectValue == objectTestValue2) { + return f; + } + return null; + } + + @Test + public void testObjectCompares() { + FieldObject f = new FieldObject(); + test("testObjectCompare", f, objectTestValue1); + test("testObjectCompareConstant1", f); + test("testObjectCompareConstant2", f); + } + + @Test + public void testObjectNullCompares() { + test("testObjectCompare", null, objectTestValue1); + } + + @Test + public void testObjectNullCompares1() { + test("testObjectCompareConstant1", (Object) null); + } + + @Test + public void testObjectNullCompares2() { + test("testObjectCompareConstant2", (Object) null); + } + + public static int testByteAdd(FieldObject f, byte byteValue) { + return f.byteValue + byteValue; + } + + public static int testByteAddConstant1(FieldObject f) { + return f.byteValue + byteTestValue1; + } + + public static int testByteAddConstant2(FieldObject f) { + return f.byteValue + byteTestValue2; + } + + @Test + public void testByteAdds() { + FieldObject f = new FieldObject(); + test("testByteAdd", f, byteTestValue1); + test("testByteAddConstant1", f); + test("testByteAddConstant2", f); + } + + @Test + public void testByteNullAdd() { + test("testByteAdd", null, byteTestValue1); + } + + public static int testShortAdd(FieldObject f, short shortValue) { + return f.shortValue + shortValue; + } + + public static int testShortAddConstant1(FieldObject f) { + return f.shortValue + shortTestValue1; + } + + public static int testShortAddConstant2(FieldObject f) { + return f.shortValue + shortTestValue2; + } + + @Test + public void testShortAdds() { + FieldObject f = new FieldObject(); + test("testShortAdd", f, shortTestValue1); + test("testShortAddConstant1", f); + test("testShortAddConstant2", f); + } + + @Test + public void testShortNullAdd() { + test("testShortAdd", null, shortTestValue1); + } + + public static int testCharAdd(FieldObject f, char charValue) { + return f.charValue + charValue; + } + + public static int testCharAddConstant1(FieldObject f) { + return f.charValue + charTestValue1; + } + + public static int testCharAddConstant2(FieldObject f) { + return f.charValue + charTestValue2; + } + + @Test + public void testCharAdds() { + FieldObject f = new FieldObject(); + test("testCharAdd", f, charTestValue1); + test("testCharAddConstant1", f); + test("testCharAddConstant2", f); + } + + @Test + public void testCharNullAdd() { + test("testCharAdd", null, charTestValue1); + } + + public static int testIntAdd(FieldObject f, int intValue) { + return f.intValue + intValue; + } + + public static int testIntAddConstant1(FieldObject f) { + return f.intValue + intTestValue1; + } + + public static int testIntAddConstant2(FieldObject f) { + return f.intValue + intTestValue2; + } + + @Test + public void testIntAdds() { + FieldObject f = new FieldObject(); + test("testIntAdd", f, intTestValue1); + test("testIntAddConstant1", f); + test("testIntAddConstant2", f); + } + + @Test + public void testIntNullAdd() { + test("testIntAdd", null, intTestValue1); + } + + public static long testLongAdd(FieldObject f, long longValue) { + return f.longValue + longValue; + } + + public static long testLongAddConstant1(FieldObject f) { + return f.longValue + longTestValue1; + } + + public static long testLongAddConstant2(FieldObject f) { + return f.longValue + longTestValue2; + } + + @Test + public void testLongAdds() { + FieldObject f = new FieldObject(); + test("testLongAdd", f, longTestValue1); + test("testLongAddConstant1", f); + test("testLongAddConstant2", f); + } + + @Test + public void testLongNullAdd() { + test("testLongAdd", null, longTestValue1); + } + + public static float testFloatAdd(FieldObject f, float floatValue) { + return f.floatValue + floatValue; + } + + public static float testFloatAddConstant1(FieldObject f) { + return f.floatValue + floatTestValue1; + } + + public static float testFloatAddConstant2(FieldObject f) { + return f.floatValue + floatTestValue2; + } + + @Test + public void testFloatAdds() { + FieldObject f = new FieldObject(); + test("testFloatAdd", f, floatTestValue1); + test("testFloatAddConstant1", f); + test("testFloatAddConstant2", f); + } + + @Test + public void testFloatNullAdd() { + test("testFloatAdd", null, floatTestValue1); + } + + public static double testDoubleAdd(FieldObject f, double doubleValue) { + return f.doubleValue + doubleValue; + } + + public static double testDoubleAddConstant1(FieldObject f) { + return f.doubleValue + doubleTestValue1; + } + + public static double testDoubleAddConstant2(FieldObject f) { + return f.doubleValue + doubleTestValue2; + } + + @Test + public void testDoubleAdds() { + FieldObject f = new FieldObject(); + test("testDoubleAdd", f, doubleTestValue1); + test("testDoubleAddConstant1", f); + test("testDoubleAddConstant2", f); + } + + @Test + public void testDoubleNullAdd() { + test("testDoubleAdd", null, doubleTestValue1); + } + + public static int testByteSub(FieldObject f, byte byteValue) { + return f.byteValue - byteValue; + } + + public static int testByteSubConstant1(FieldObject f) { + return f.byteValue - byteTestValue1; + } + + public static int testByteSubConstant2(FieldObject f) { + return f.byteValue - byteTestValue2; + } + + @Test + public void testByteSubs() { + FieldObject f = new FieldObject(); + test("testByteSub", f, byteTestValue1); + test("testByteSubConstant1", f); + test("testByteSubConstant2", f); + } + + @Test + public void testByteNullSub() { + test("testByteSub", null, byteTestValue1); + } + + public static int testShortSub(FieldObject f, short shortValue) { + return f.shortValue - shortValue; + } + + public static int testShortSubConstant1(FieldObject f) { + return f.shortValue - shortTestValue1; + } + + public static int testShortSubConstant2(FieldObject f) { + return f.shortValue - shortTestValue2; + } + + @Test + public void testShortSubs() { + FieldObject f = new FieldObject(); + test("testShortSub", f, shortTestValue1); + test("testShortSubConstant1", f); + test("testShortSubConstant2", f); + } + + @Test + public void testShortNullSub() { + test("testShortSub", null, shortTestValue1); + } + + public static int testCharSub(FieldObject f, char charValue) { + return f.charValue - charValue; + } + + public static int testCharSubConstant1(FieldObject f) { + return f.charValue - charTestValue1; + } + + public static int testCharSubConstant2(FieldObject f) { + return f.charValue - charTestValue2; + } + + @Test + public void testCharSubs() { + FieldObject f = new FieldObject(); + test("testCharSub", f, charTestValue1); + test("testCharSubConstant1", f); + test("testCharSubConstant2", f); + } + + @Test + public void testCharNullSub() { + test("testCharSub", null, charTestValue1); + } + + public static int testIntSub(FieldObject f, int intValue) { + return f.intValue - intValue; + } + + public static int testIntSubConstant1(FieldObject f) { + return f.intValue - intTestValue1; + } + + public static int testIntSubConstant2(FieldObject f) { + return f.intValue - intTestValue2; + } + + @Test + public void testIntSubs() { + FieldObject f = new FieldObject(); + test("testIntSub", f, intTestValue1); + test("testIntSubConstant1", f); + test("testIntSubConstant2", f); + } + + @Test + public void testIntNullSub() { + test("testIntSub", null, intTestValue1); + } + + public static long testLongSub(FieldObject f, long longValue) { + return f.longValue - longValue; + } + + public static long testLongSubConstant1(FieldObject f) { + return f.longValue - longTestValue1; + } + + public static long testLongSubConstant2(FieldObject f) { + return f.longValue - longTestValue2; + } + + @Test + public void testLongSubs() { + FieldObject f = new FieldObject(); + test("testLongSub", f, longTestValue1); + test("testLongSubConstant1", f); + test("testLongSubConstant2", f); + } + + @Test + public void testLongNullSub() { + test("testLongSub", null, longTestValue1); + } + + public static float testFloatSub(FieldObject f, float floatValue) { + return f.floatValue - floatValue; + } + + public static float testFloatSubConstant1(FieldObject f) { + return f.floatValue - floatTestValue1; + } + + public static float testFloatSubConstant2(FieldObject f) { + return f.floatValue - floatTestValue2; + } + + @Test + public void testFloatSubs() { + FieldObject f = new FieldObject(); + test("testFloatSub", f, floatTestValue1); + test("testFloatSubConstant1", f); + test("testFloatSubConstant2", f); + } + + @Test + public void testFloatNullSub() { + test("testFloatSub", null, floatTestValue1); + } + + public static double testDoubleSub(FieldObject f, double doubleValue) { + return f.doubleValue - doubleValue; + } + + public static double testDoubleSubConstant1(FieldObject f) { + return f.doubleValue - doubleTestValue1; + } + + public static double testDoubleSubConstant2(FieldObject f) { + return f.doubleValue - doubleTestValue2; + } + + @Test + public void testDoubleSubs() { + FieldObject f = new FieldObject(); + test("testDoubleSub", f, doubleTestValue1); + test("testDoubleSubConstant1", f); + test("testDoubleSubConstant2", f); + } + + @Test + public void testDoubleNullSub() { + test("testDoubleSub", null, doubleTestValue1); + } + + public static int testByteMul(FieldObject f, byte byteValue) { + return f.byteValue * byteValue; + } + + public static int testByteMulConstant1(FieldObject f) { + return f.byteValue * byteTestValue1; + } + + public static int testByteMulConstant2(FieldObject f) { + return f.byteValue * byteTestValue2; + } + + @Test + public void testByteMuls() { + FieldObject f = new FieldObject(); + test("testByteMul", f, byteTestValue1); + test("testByteMulConstant1", f); + test("testByteMulConstant2", f); + } + + @Test + public void testByteNullMul() { + test("testByteMul", null, byteTestValue1); + } + + public static int testShortMul(FieldObject f, short shortValue) { + return f.shortValue * shortValue; + } + + public static int testShortMulConstant1(FieldObject f) { + return f.shortValue * shortTestValue1; + } + + public static int testShortMulConstant2(FieldObject f) { + return f.shortValue * shortTestValue2; + } + + @Test + public void testShortMuls() { + FieldObject f = new FieldObject(); + test("testShortMul", f, shortTestValue1); + test("testShortMulConstant1", f); + test("testShortMulConstant2", f); + } + + @Test + public void testShortNullMul() { + test("testShortMul", null, shortTestValue1); + } + + public static int testCharMul(FieldObject f, char charValue) { + return f.charValue * charValue; + } + + public static int testCharMulConstant1(FieldObject f) { + return f.charValue * charTestValue1; + } + + public static int testCharMulConstant2(FieldObject f) { + return f.charValue * charTestValue2; + } + + @Test + public void testCharMuls() { + FieldObject f = new FieldObject(); + test("testCharMul", f, charTestValue1); + test("testCharMulConstant1", f); + test("testCharMulConstant2", f); + } + + @Test + public void testCharNullMul() { + test("testCharMul", null, charTestValue1); + } + + public static int testIntMul(FieldObject f, int intValue) { + return f.intValue * intValue; + } + + public static int testIntMulConstant1(FieldObject f) { + return f.intValue * intTestValue1; + } + + public static int testIntMulConstant2(FieldObject f) { + return f.intValue * intTestValue2; + } + + @Test + public void testIntMuls() { + FieldObject f = new FieldObject(); + test("testIntMul", f, intTestValue1); + test("testIntMulConstant1", f); + test("testIntMulConstant2", f); + } + + @Test + public void testIntNullMul() { + test("testIntMul", null, intTestValue1); + } + + public static long testLongMul(FieldObject f, long longValue) { + return f.longValue * longValue; + } + + public static long testLongMulConstant1(FieldObject f) { + return f.longValue * longTestValue1; + } + + public static long testLongMulConstant2(FieldObject f) { + return f.longValue * longTestValue2; + } + + @Test + public void testLongMuls() { + FieldObject f = new FieldObject(); + test("testLongMul", f, longTestValue1); + test("testLongMulConstant1", f); + test("testLongMulConstant2", f); + } + + @Test + public void testLongNullMul() { + test("testLongMul", null, longTestValue1); + } + + public static float testFloatMul(FieldObject f, float floatValue) { + return f.floatValue * floatValue; + } + + public static float testFloatMulConstant1(FieldObject f) { + return f.floatValue * floatTestValue1; + } + + public static float testFloatMulConstant2(FieldObject f) { + return f.floatValue * floatTestValue2; + } + + @Test + public void testFloatMuls() { + FieldObject f = new FieldObject(); + test("testFloatMul", f, floatTestValue1); + test("testFloatMulConstant1", f); + test("testFloatMulConstant2", f); + } + + @Test + public void testFloatNullMul() { + test("testFloatMul", null, floatTestValue1); + } + + public static double testDoubleMul(FieldObject f, double doubleValue) { + return f.doubleValue * doubleValue; + } + + public static double testDoubleMulConstant1(FieldObject f) { + return f.doubleValue * doubleTestValue1; + } + + public static double testDoubleMulConstant2(FieldObject f) { + return f.doubleValue * doubleTestValue2; + } + + @Test + public void testDoubleMuls() { + FieldObject f = new FieldObject(); + test("testDoubleMul", f, doubleTestValue1); + test("testDoubleMulConstant1", f); + test("testDoubleMulConstant2", f); + } + + @Test + public void testDoubleNullMul() { + test("testDoubleMul", null, doubleTestValue1); + } + + public static int testByteDiv(FieldObject f, byte byteValue) { + return f.byteValue / byteValue; + } + + @SuppressWarnings("divzero") + public static int testByteDivConstant1(FieldObject f) { + return f.byteValue / byteTestValue1; + } + + public static int testByteDivConstant2(FieldObject f) { + return f.byteValue / byteTestValue2; + } + + @Test + public void testByteDivs() { + FieldObject f = new FieldObject(); + test("testByteDiv", f, byteTestValue1); + test("testByteDivConstant1", f); + test("testByteDivConstant2", f); + } + + @Test + public void testByteNullDiv() { + test("testByteDiv", null, byteTestValue1); + } + + public static int testShortDiv(FieldObject f, short shortValue) { + return f.shortValue / shortValue; + } + + @SuppressWarnings("divzero") + public static int testShortDivConstant1(FieldObject f) { + return f.shortValue / shortTestValue1; + } + + public static int testShortDivConstant2(FieldObject f) { + return f.shortValue / shortTestValue2; + } + + @Test + public void testShortDivs() { + FieldObject f = new FieldObject(); + test("testShortDiv", f, shortTestValue1); + test("testShortDivConstant1", f); + test("testShortDivConstant2", f); + } + + @Test + public void testShortNullDiv() { + test("testShortDiv", null, shortTestValue1); + } + + public static int testCharDiv(FieldObject f, char charValue) { + return f.charValue / charValue; + } + + @SuppressWarnings("divzero") + public static int testCharDivConstant1(FieldObject f) { + return f.charValue / charTestValue1; + } + + public static int testCharDivConstant2(FieldObject f) { + return f.charValue / charTestValue2; + } + + @Test + public void testCharDivs() { + FieldObject f = new FieldObject(); + test("testCharDiv", f, charTestValue1); + test("testCharDivConstant1", f); + test("testCharDivConstant2", f); + } + + @Test + public void testCharNullDiv() { + test("testCharDiv", null, charTestValue1); + } + + public static int testIntDiv(FieldObject f, int intValue) { + return f.intValue / intValue; + } + + @SuppressWarnings("divzero") + public static int testIntDivConstant1(FieldObject f) { + return f.intValue / intTestValue1; + } + + public static int testIntDivConstant2(FieldObject f) { + return f.intValue / intTestValue2; + } + + @Test + public void testIntDivs() { + FieldObject f = new FieldObject(); + test("testIntDiv", f, intTestValue1); + test("testIntDivConstant1", f); + test("testIntDivConstant2", f); + } + + @Test + public void testIntNullDiv() { + test("testIntDiv", null, intTestValue1); + } + + public static long testLongDiv(FieldObject f, long longValue) { + return f.longValue / longValue; + } + + @SuppressWarnings("divzero") + public static long testLongDivConstant1(FieldObject f) { + return f.longValue / longTestValue1; + } + + public static long testLongDivConstant2(FieldObject f) { + return f.longValue / longTestValue2; + } + + @Test + public void testLongDivs() { + FieldObject f = new FieldObject(); + test("testLongDiv", f, longTestValue1); + test("testLongDivConstant1", f); + test("testLongDivConstant2", f); + } + + @Test + public void testLongNullDiv() { + test("testLongDiv", null, longTestValue1); + } + + public static float testFloatDiv(FieldObject f, float floatValue) { + return f.floatValue / floatValue; + } + + public static float testFloatDivConstant1(FieldObject f) { + return f.floatValue / floatTestValue1; + } + + public static float testFloatDivConstant2(FieldObject f) { + return f.floatValue / floatTestValue2; + } + + @Test + public void testFloatDivs() { + FieldObject f = new FieldObject(); + test("testFloatDiv", f, floatTestValue1); + test("testFloatDivConstant1", f); + test("testFloatDivConstant2", f); + } + + @Test + public void testFloatNullDiv() { + test("testFloatDiv", null, floatTestValue1); + } + + public static double testDoubleDiv(FieldObject f, double doubleValue) { + return f.doubleValue / doubleValue; + } + + public static double testDoubleDivConstant1(FieldObject f) { + return f.doubleValue / doubleTestValue1; + } + + public static double testDoubleDivConstant2(FieldObject f) { + return f.doubleValue / doubleTestValue2; + } + + @Test + public void testDoubleDivs() { + FieldObject f = new FieldObject(); + test("testDoubleDiv", f, doubleTestValue1); + test("testDoubleDivConstant1", f); + test("testDoubleDivConstant2", f); + } + + @Test + public void testDoubleNullDiv() { + test("testDoubleDiv", null, doubleTestValue1); + } + + public static int testByteOr(FieldObject f, byte byteValue) { + return f.byteValue | byteValue; + } + + public static int testByteOrConstant1(FieldObject f) { + return f.byteValue | byteTestValue1; + } + + public static int testByteOrConstant2(FieldObject f) { + return f.byteValue | byteTestValue2; + } + + @Test + public void testByteOrs() { + FieldObject f = new FieldObject(); + test("testByteOr", f, byteTestValue1); + test("testByteOrConstant1", f); + test("testByteOrConstant2", f); + } + + @Test + public void testByteNullOr() { + test("testByteOr", null, byteTestValue1); + } + + public static int testShortOr(FieldObject f, short shortValue) { + return f.shortValue | shortValue; + } + + public static int testShortOrConstant1(FieldObject f) { + return f.shortValue | shortTestValue1; + } + + public static int testShortOrConstant2(FieldObject f) { + return f.shortValue | shortTestValue2; + } + + @Test + public void testShortOrs() { + FieldObject f = new FieldObject(); + test("testShortOr", f, shortTestValue1); + test("testShortOrConstant1", f); + test("testShortOrConstant2", f); + } + + @Test + public void testShortNullOr() { + test("testShortOr", null, shortTestValue1); + } + + public static int testCharOr(FieldObject f, char charValue) { + return f.charValue | charValue; + } + + public static int testCharOrConstant1(FieldObject f) { + return f.charValue | charTestValue1; + } + + public static int testCharOrConstant2(FieldObject f) { + return f.charValue | charTestValue2; + } + + @Test + public void testCharOrs() { + FieldObject f = new FieldObject(); + test("testCharOr", f, charTestValue1); + test("testCharOrConstant1", f); + test("testCharOrConstant2", f); + } + + @Test + public void testCharNullOr() { + test("testCharOr", null, charTestValue1); + } + + public static int testIntOr(FieldObject f, int intValue) { + return f.intValue | intValue; + } + + public static int testIntOrConstant1(FieldObject f) { + return f.intValue | intTestValue1; + } + + public static int testIntOrConstant2(FieldObject f) { + return f.intValue | intTestValue2; + } + + @Test + public void testIntOrs() { + FieldObject f = new FieldObject(); + test("testIntOr", f, intTestValue1); + test("testIntOrConstant1", f); + test("testIntOrConstant2", f); + } + + @Test + public void testIntNullOr() { + test("testIntOr", null, intTestValue1); + } + + public static long testLongOr(FieldObject f, long longValue) { + return f.longValue | longValue; + } + + public static long testLongOrConstant1(FieldObject f) { + return f.longValue | longTestValue1; + } + + public static long testLongOrConstant2(FieldObject f) { + return f.longValue | longTestValue2; + } + + @Test + public void testLongOrs() { + FieldObject f = new FieldObject(); + test("testLongOr", f, longTestValue1); + test("testLongOrConstant1", f); + test("testLongOrConstant2", f); + } + + @Test + public void testLongNullOr() { + test("testLongOr", null, longTestValue1); + } + + public static int testByteXor(FieldObject f, byte byteValue) { + return f.byteValue ^ byteValue; + } + + public static int testByteXorConstant1(FieldObject f) { + return f.byteValue ^ byteTestValue1; + } + + public static int testByteXorConstant2(FieldObject f) { + return f.byteValue ^ byteTestValue2; + } + + @Test + public void testByteXors() { + FieldObject f = new FieldObject(); + test("testByteXor", f, byteTestValue1); + test("testByteXorConstant1", f); + test("testByteXorConstant2", f); + } + + @Test + public void testByteNullXor() { + test("testByteXor", null, byteTestValue1); + } + + public static int testShortXor(FieldObject f, short shortValue) { + return f.shortValue ^ shortValue; + } + + public static int testShortXorConstant1(FieldObject f) { + return f.shortValue ^ shortTestValue1; + } + + public static int testShortXorConstant2(FieldObject f) { + return f.shortValue ^ shortTestValue2; + } + + @Test + public void testShortXors() { + FieldObject f = new FieldObject(); + test("testShortXor", f, shortTestValue1); + test("testShortXorConstant1", f); + test("testShortXorConstant2", f); + } + + @Test + public void testShortNullXor() { + test("testShortXor", null, shortTestValue1); + } + + public static int testCharXor(FieldObject f, char charValue) { + return f.charValue ^ charValue; + } + + public static int testCharXorConstant1(FieldObject f) { + return f.charValue ^ charTestValue1; + } + + public static int testCharXorConstant2(FieldObject f) { + return f.charValue ^ charTestValue2; + } + + @Test + public void testCharXors() { + FieldObject f = new FieldObject(); + test("testCharXor", f, charTestValue1); + test("testCharXorConstant1", f); + test("testCharXorConstant2", f); + } + + @Test + public void testCharNullXor() { + test("testCharXor", null, charTestValue1); + } + + public static int testIntXor(FieldObject f, int intValue) { + return f.intValue ^ intValue; + } + + public static int testIntXorConstant1(FieldObject f) { + return f.intValue ^ intTestValue1; + } + + public static int testIntXorConstant2(FieldObject f) { + return f.intValue ^ intTestValue2; + } + + @Test + public void testIntXors() { + FieldObject f = new FieldObject(); + test("testIntXor", f, intTestValue1); + test("testIntXorConstant1", f); + test("testIntXorConstant2", f); + } + + @Test + public void testIntNullXor() { + test("testIntXor", null, intTestValue1); + } + + public static long testLongXor(FieldObject f, long longValue) { + return f.longValue ^ longValue; + } + + public static long testLongXorConstant1(FieldObject f) { + return f.longValue ^ longTestValue1; + } + + public static long testLongXorConstant2(FieldObject f) { + return f.longValue ^ longTestValue2; + } + + @Test + public void testLongXors() { + FieldObject f = new FieldObject(); + test("testLongXor", f, longTestValue1); + test("testLongXorConstant1", f); + test("testLongXorConstant2", f); + } + + @Test + public void testLongNullXor() { + test("testLongXor", null, longTestValue1); + } + + public static int testByteAnd(FieldObject f, byte byteValue) { + return f.byteValue & byteValue; + } + + public static int testByteAndConstant1(FieldObject f) { + return f.byteValue & byteTestValue1; + } + + public static int testByteAndConstant2(FieldObject f) { + return f.byteValue & byteTestValue2; + } + + @Test + public void testByteAnds() { + FieldObject f = new FieldObject(); + test("testByteAnd", f, byteTestValue1); + test("testByteAndConstant1", f); + test("testByteAndConstant2", f); + } + + @Test + public void testByteNullAnd() { + test("testByteAnd", null, byteTestValue1); + } + + public static int testShortAnd(FieldObject f, short shortValue) { + return f.shortValue & shortValue; + } + + public static int testShortAndConstant1(FieldObject f) { + return f.shortValue & shortTestValue1; + } + + public static int testShortAndConstant2(FieldObject f) { + return f.shortValue & shortTestValue2; + } + + @Test + public void testShortAnds() { + FieldObject f = new FieldObject(); + test("testShortAnd", f, shortTestValue1); + test("testShortAndConstant1", f); + test("testShortAndConstant2", f); + } + + @Test + public void testShortNullAnd() { + test("testShortAnd", null, shortTestValue1); + } + + public static int testCharAnd(FieldObject f, char charValue) { + return f.charValue & charValue; + } + + public static int testCharAndConstant1(FieldObject f) { + return f.charValue & charTestValue1; + } + + public static int testCharAndConstant2(FieldObject f) { + return f.charValue & charTestValue2; + } + + @Test + public void testCharAnds() { + FieldObject f = new FieldObject(); + test("testCharAnd", f, charTestValue1); + test("testCharAndConstant1", f); + test("testCharAndConstant2", f); + } + + @Test + public void testCharNullAnd() { + test("testCharAnd", null, charTestValue1); + } + + public static int testIntAnd(FieldObject f, int intValue) { + return f.intValue & intValue; + } + + public static int testIntAndConstant1(FieldObject f) { + return f.intValue & intTestValue1; + } + + public static int testIntAndConstant2(FieldObject f) { + return f.intValue & intTestValue2; + } + + @Test + public void testIntAnds() { + FieldObject f = new FieldObject(); + test("testIntAnd", f, intTestValue1); + test("testIntAndConstant1", f); + test("testIntAndConstant2", f); + } + + @Test + public void testIntNullAnd() { + test("testIntAnd", null, intTestValue1); + } + + public static long testLongAnd(FieldObject f, long longValue) { + return f.longValue & longValue; + } + + public static long testLongAndConstant1(FieldObject f) { + return f.longValue & longTestValue1; + } + + public static long testLongAndConstant2(FieldObject f) { + return f.longValue & longTestValue2; + } + + @Test + public void testLongAnds() { + FieldObject f = new FieldObject(); + test("testLongAnd", f, longTestValue1); + test("testLongAndConstant1", f); + test("testLongAndConstant2", f); + } + + @Test + public void testLongNullAnd() { + test("testLongAnd", null, longTestValue1); + } + + public static boolean testIntMask(FieldObject f, int intValue) { + if ((f.intValue & intValue) != 0) { + count++; + return false; + } + return true; + } + + public static boolean testIntMaskConstant1(FieldObject f) { + return (f.intValue & intTestValue1) != 0; + } + + public static boolean testIntMaskConstant2(FieldObject f) { + return (f.intValue & intTestValue2) != 0; + } + + @Test + public void testIntMasks() { + FieldObject f = new FieldObject(); + test("testIntMask", f, intTestValue1); + test("testIntMaskConstant1", f); + test("testIntMaskConstant2", f); + } + + @Test + public void testIntNullMask() { + test("testIntMask", null, intTestValue1); + } + + public static boolean testLongMask(FieldObject f, long longValue) { + if ((f.longValue & longValue) != 0) { + count++; + return false; + } + return true; + } + + public static boolean testLongMaskConstant1(FieldObject f) { + return (f.longValue & longTestValue1) != 0; + } + + public static boolean testLongMaskConstant2(FieldObject f) { + return (f.longValue & longTestValue2) != 0; + } + + @Test + public void testLongMasks() { + FieldObject f = new FieldObject(); + test("testLongMask", f, longTestValue1); + test("testLongMaskConstant1", f); + test("testLongMaskConstant2", f); + } + + @Test + public void testLongNullMask() { + test("testLongMask", null, longTestValue1); + } + + public static int doConvertByteInt(FieldObject f) { + return f.byteValue; + } + + @Test + public void testConvertByteInt() { + test("doConvertByteInt", maxObject); + test("doConvertByteInt", (FieldObject) null); + } + + public static int doConvertShortInt(FieldObject f) { + return f.shortValue; + } + + @Test + public void testConvertShortInt() { + test("doConvertShortInt", maxObject); + test("doConvertShortInt", (FieldObject) null); + } + + public static int doConvertCharInt(FieldObject f) { + return f.charValue; + } + + @Test + public void testConvertCharInt() { + test("doConvertCharInt", maxObject); + test("doConvertCharInt", (FieldObject) null); + } + + public static int doConvertLongInt(FieldObject f) { + return (int) f.longValue; + } + + @Test + public void testConvertLongInt() { + test("doConvertLongInt", maxObject); + test("doConvertLongInt", (FieldObject) null); + } + + public static int doConvertFloatInt(FieldObject f) { + return (int) f.floatValue; + } + + @Test + public void testConvertFloatInt() { + test("doConvertFloatInt", maxObject); + test("doConvertFloatInt", (FieldObject) null); + } + + public static int doConvertDoubleInt(FieldObject f) { + return (int) f.doubleValue; + } + + @Test + public void testConvertDoubleInt() { + test("doConvertDoubleInt", maxObject); + test("doConvertDoubleInt", (FieldObject) null); + } + + public static long doConvertByteLong(FieldObject f) { + return f.byteValue; + } + + @Test + public void testConvertByteLong() { + test("doConvertByteLong", maxObject); + test("doConvertByteLong", (FieldObject) null); + } + + public static long doConvertShortLong(FieldObject f) { + return f.shortValue; + } + + @Test + public void testConvertShortLong() { + test("doConvertShortLong", maxObject); + test("doConvertShortLong", (FieldObject) null); + } + + public static long doConvertCharLong(FieldObject f) { + return f.charValue; + } + + @Test + public void testConvertCharLong() { + test("doConvertCharLong", maxObject); + test("doConvertCharLong", (FieldObject) null); + } + + public static long doConvertIntLong(FieldObject f) { + return f.intValue; + } + + @Test + public void testConvertIntLong() { + test("doConvertIntLong", maxObject); + test("doConvertIntLong", (FieldObject) null); + } + + public static long doConvertFloatLong(FieldObject f) { + return (long) f.floatValue; + } + + @Test + public void testConvertFloatLong() { + test("doConvertFloatLong", maxObject); + test("doConvertFloatLong", (FieldObject) null); + } + + public static long doConvertDoubleLong(FieldObject f) { + return (long) f.doubleValue; + } + + @Test + public void testConvertDoubleLong() { + test("doConvertDoubleLong", maxObject); + test("doConvertDoubleLong", (FieldObject) null); + } + + public static float doConvertByteFloat(FieldObject f) { + return f.byteValue; + } + + @Test + public void testConvertByteFloat() { + test("doConvertByteFloat", maxObject); + test("doConvertByteFloat", (FieldObject) null); + } + + public static float doConvertShortFloat(FieldObject f) { + return f.shortValue; + } + + @Test + public void testConvertShortFloat() { + test("doConvertShortFloat", maxObject); + test("doConvertShortFloat", (FieldObject) null); + } + + public static float doConvertCharFloat(FieldObject f) { + return f.charValue; + } + + @Test + public void testConvertCharFloat() { + test("doConvertCharFloat", maxObject); + test("doConvertCharFloat", (FieldObject) null); + } + + public static float doConvertIntFloat(FieldObject f) { + return f.intValue; + } + + @Test + public void testConvertIntFloat() { + test("doConvertIntFloat", maxObject); + test("doConvertIntFloat", (FieldObject) null); + } + + public static float doConvertLongFloat(FieldObject f) { + return f.longValue; + } + + @Test + public void testConvertLongFloat() { + test("doConvertLongFloat", maxObject); + test("doConvertLongFloat", (FieldObject) null); + } + + public static float doConvertDoubleFloat(FieldObject f) { + return (float) f.doubleValue; + } + + @Test + public void testConvertDoubleFloat() { + test("doConvertDoubleFloat", maxObject); + test("doConvertDoubleFloat", (FieldObject) null); + } + + public static double doConvertByteDouble(FieldObject f) { + return f.byteValue; + } + + @Test + public void testConvertByteDouble() { + test("doConvertByteDouble", maxObject); + test("doConvertByteDouble", (FieldObject) null); + } + + public static double doConvertShortDouble(FieldObject f) { + return f.shortValue; + } + + @Test + public void testConvertShortDouble() { + test("doConvertShortDouble", maxObject); + test("doConvertShortDouble", (FieldObject) null); + } + + public static double doConvertCharDouble(FieldObject f) { + return f.charValue; + } + + @Test + public void testConvertCharDouble() { + test("doConvertCharDouble", maxObject); + test("doConvertCharDouble", (FieldObject) null); + } + + public static double doConvertIntDouble(FieldObject f) { + return f.intValue; + } + + @Test + public void testConvertIntDouble() { + test("doConvertIntDouble", maxObject); + test("doConvertIntDouble", (FieldObject) null); + } + + public static double doConvertLongDouble(FieldObject f) { + return f.longValue; + } + + @Test + public void testConvertLongDouble() { + test("doConvertLongDouble", maxObject); + test("doConvertLongDouble", (FieldObject) null); + } + + public static double doConvertFloatDouble(FieldObject f) { + return f.floatValue; + } + + @Test + public void testConvertFloatDouble() { + test("doConvertFloatDouble", maxObject); + test("doConvertFloatDouble", (FieldObject) null); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java 2016-12-07 13:48:27.847736657 -0800 @@ -0,0 +1,758 @@ +/* + * Copyright (c) 2011, 2015, 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.core.test; + +import static org.graalvm.compiler.core.common.GraalOptions.OptImplicitNullChecks; +import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops; +import static org.graalvm.compiler.graph.test.matchers.NodeIterableCount.hasCount; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StartNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.memory.FloatingReadNode; +import org.graalvm.compiler.nodes.memory.WriteNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase; +import org.graalvm.compiler.phases.common.GuardLoweringPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.MidTierContext; + +/** + * In these test the FrameStates are explicitly cleared out, so that the scheduling of + * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the + * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the + * right thing. + * + * The scheduling shouldn't depend on FrameStates, which is tested by this class. + */ +public class MemoryScheduleTest extends GraphScheduleTest { + + private enum TestMode { + WITH_FRAMESTATES, + WITHOUT_FRAMESTATES, + INLINED_WITHOUT_FRAMESTATES + } + + public static class Container { + + public int a; + public int b; + public int c; + + public Object obj; + } + + private static final Container container = new Container(); + private static final List containerList = new ArrayList<>(); + + /** + * In this test the read should be scheduled before the write. + */ + public static int testSimpleSnippet() { + try { + return container.a; + } finally { + container.a = 15; + } + } + + @Test + public void testSimple() { + for (TestMode mode : TestMode.values()) { + ScheduleResult schedule = getFinalSchedule("testSimpleSnippet", mode); + StructuredGraph graph = schedule.getCFG().graph; + assertReadAndWriteInSameBlock(schedule, true); + assertOrderedAfterSchedule(schedule, graph.getNodes().filter(FloatingReadNode.class).first(), graph.getNodes().filter(WriteNode.class).first()); + } + } + + /** + * In this case the read should be scheduled in the first block. + */ + public static int testSplit1Snippet(int a) { + try { + return container.a; + } finally { + if (a < 0) { + container.a = 15; + } else { + container.b = 15; + } + } + } + + @Test + public void testSplit1() { + for (TestMode mode : TestMode.values()) { + ScheduleResult schedule = getFinalSchedule("testSplit1Snippet", mode); + assertReadWithinStartBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, false); + } + } + + /** + * Here the read should float to the end. + */ + public static int testSplit2Snippet(int a) { + try { + return container.a; + } finally { + if (a < 0) { + container.c = 15; + } else { + container.b = 15; + } + container.obj = null; + } + } + + @Test + public void testSplit2() { + ScheduleResult schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, true); + } + + /** + * Here the read should not float to the end. + */ + public static int testLoop1Snippet(int a, int b) { + try { + return container.a; + } finally { + for (int i = 0; i < a; i++) { + if (b < 0) { + container.b = 10; + } else { + container.a = 15; + } + } + } + } + + @Test + public void testLoop1() { + ScheduleResult schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(6, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, false); + } + + /** + * Here the read should float to the end. + */ + public static int testLoop2Snippet(int a, int b) { + try { + return container.a; + } finally { + for (int i = 0; i < a; i++) { + if (b < 0) { + container.b = 10; + } else { + container.c = 15; + } + } + } + } + + @Test + public void testLoop2() { + ScheduleResult schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(6, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, true); + } + + /** + * Here the read should float out of the loop. + */ + public static int testLoop3Snippet(int a) { + int j = 0; + for (int i = 0; i < a; i++) { + if (i - container.a == 0) { + break; + } + j++; + } + return j; + } + + @Test + public void testLoop3() { + ScheduleResult schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(6, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, false); + } + + public String testStringReplaceSnippet(String input) { + return input.replace('a', 'b'); + } + + @Test + public void testStringReplace() { + getFinalSchedule("testStringReplaceSnippet", TestMode.INLINED_WITHOUT_FRAMESTATES); + test("testStringReplaceSnippet", "acbaaa"); + } + + /** + * Here the read should float out of the loop. + */ + public static int testLoop5Snippet(int a, int b, MemoryScheduleTest obj) { + int ret = 0; + int bb = b; + for (int i = 0; i < a; i++) { + ret = obj.hash; + if (a > 10) { + bb++; + } else { + bb--; + } + ret = ret / 10; + } + return ret + bb; + } + + @Test + public void testLoop5() { + ScheduleResult schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(10, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); + } + + /** + * Here the read should not float out of the loop. + */ + public static int testLoop6Snippet(int a, int b, MemoryScheduleTest obj) { + int ret = 0; + int bb = b; + for (int i = 0; i < a; i++) { + ret = obj.hash; + if (a > 10) { + bb++; + } else { + bb--; + for (int j = 0; j < b; ++j) { + obj.hash = 3; + } + } + ret = ret / 10; + } + return ret + bb; + } + + @Test + public void testLoop6() { + ScheduleResult schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(13, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); + } + + /** + * Here the read should not float out of the loop. + */ + public static int testLoop7Snippet(int a, int b, MemoryScheduleTest obj) { + int ret = 0; + int bb = b; + for (int i = 0; i < a; i++) { + ret = obj.hash; + if (a > 10) { + bb++; + } else { + bb--; + for (int k = 0; k < a; ++k) { + if (k % 2 == 1) { + for (int j = 0; j < b; ++j) { + obj.hash = 3; + } + } + } + } + ret = ret / 10; + } + return ret + bb; + } + + @Test + public void testLoop7() { + ScheduleResult schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(18, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); + } + + /** + * Here the read should not float to the end. + */ + public static int testLoop8Snippet(int a, int b) { + int result = container.a; + for (int i = 0; i < a; i++) { + if (b < 0) { + container.b = 10; + break; + } else { + for (int j = 0; j < b; j++) { + container.a = 0; + } + } + } + GraalDirectives.controlFlowAnchor(); + return result; + } + + @Test + public void testLoop8() { + ScheduleResult schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(10, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, false); + } + + /** + * Here the read should float after the loop. + */ + public static int testLoop9Snippet(int a, int b) { + container.a = b; + for (int i = 0; i < a; i++) { + container.a = i; + } + GraalDirectives.controlFlowAnchor(); + return container.a; + } + + @Test + public void testLoop9() { + ScheduleResult schedule = getFinalSchedule("testLoop9Snippet", TestMode.WITHOUT_FRAMESTATES); + StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph(); + assertThat(graph.getNodes(ReturnNode.TYPE), hasCount(1)); + ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first(); + assertThat(ret.result(), instanceOf(FloatingReadNode.class)); + Block readBlock = schedule.getNodeToBlockMap().get(ret.result()); + Assert.assertEquals(0, readBlock.getLoopDepth()); + } + + /** + * Here the read should float to the end (into the same block as the return). + */ + public static int testArrayCopySnippet(Integer intValue, char[] a, char[] b, int len) { + System.arraycopy(a, 0, b, 0, len); + return intValue.intValue(); + } + + @Test + public void testArrayCopy() { + ScheduleResult schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES); + StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph(); + assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count()); + ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first(); + assertTrue(ret.result() + " should be a FloatingReadNode", ret.result() instanceof FloatingReadNode); + assertDeepEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result())); + assertReadWithinAllReturnBlocks(schedule, true); + } + + /** + * Here the read should not float to the end. + */ + public static int testIfRead1Snippet(int a) { + int res = container.a; + if (a < 0) { + container.a = 10; + } + return res; + } + + @Test + public void testIfRead1() { + ScheduleResult schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(3, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, true); + assertReadAndWriteInSameBlock(schedule, false); + } + + /** + * Here the read should float in the else block. + */ + public static int testIfRead2Snippet(int a) { + int res = 0; + if (a < 0) { + container.a = 10; + } else { + res = container.a; + } + return res; + } + + @Test + public void testIfRead2() { + ScheduleResult schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(3, schedule.getCFG().getBlocks().length); + assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count()); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); + assertReadAndWriteInSameBlock(schedule, false); + } + + /** + * Here the read should float to the end, right before the write. + */ + public static int testIfRead3Snippet(int a) { + if (a < 0) { + container.a = 10; + } + int res = container.a; + container.a = 20; + return res; + } + + @Test + public void testIfRead3() { + ScheduleResult schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(4, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, true); + } + + /** + * Here the read should be just in the if branch (with the write). + */ + public static int testIfRead4Snippet(int a) { + if (a > 0) { + int res = container.a; + container.a = 0x20; + return res; + } else { + return 0x10; + } + } + + @Test + public void testIfRead4() { + ScheduleResult schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(3, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); + assertReadAndWriteInSameBlock(schedule, true); + } + + /** + * Here the read should float to the end. + */ + public static int testIfRead5Snippet(int a) { + if (a < 0) { + container.a = 10; + } + return container.a; + } + + @Test + public void testIfRead5() { + ScheduleResult schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(4, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, true); + assertReadAndWriteInSameBlock(schedule, false); + } + + public static int testAntiDependencySnippet(int a) { + /* + * This read must not be scheduled after the following write. + */ + int res = container.a; + container.a = 10; + + /* + * Add some more basic blocks. + */ + if (a < 0) { + container.b = 20; + } + container.c = 30; + return res; + } + + @Test + public void testAntiDependency() { + ScheduleResult schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(4, schedule.getCFG().getBlocks().length); + assertReadBeforeAllWritesInStartBlock(schedule); + } + + /** + * testing scheduling within a block. + */ + public static int testBlockScheduleSnippet() { + int res = 0; + container.a = 0x00; + container.a = 0x10; + container.a = 0x20; + container.a = 0x30; + container.a = 0x40; + res = container.a; + container.a = 0x50; + container.a = 0x60; + container.a = 0x70; + return res; + } + + @Test + public void testBlockSchedule() { + ScheduleResult schedule = getFinalSchedule("testBlockScheduleSnippet", TestMode.WITHOUT_FRAMESTATES); + StructuredGraph graph = schedule.getCFG().graph; + NodeIterable writeNodes = graph.getNodes().filter(WriteNode.class); + + assertDeepEquals(1, schedule.getCFG().getBlocks().length); + assertDeepEquals(8, writeNodes.count()); + assertDeepEquals(1, graph.getNodes().filter(FloatingReadNode.class).count()); + + FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first(); + + WriteNode[] writes = new WriteNode[8]; + int i = 0; + for (WriteNode n : writeNodes) { + writes[i] = n; + i++; + } + assertOrderedAfterSchedule(schedule, writes[4], read); + assertOrderedAfterSchedule(schedule, read, writes[5]); + for (int j = 0; j < 7; j++) { + assertOrderedAfterSchedule(schedule, writes[j], writes[j + 1]); + } + } + + /** + * read should move inside the loop (out of loop is disabled). + */ + public static int testBlockSchedule2Snippet(int value) { + int res = 0; + + container.a = value; + for (int i = 0; i < 100; i++) { + if (i == 10) { + return container.a; + } + res += i; + } + return res; + } + + @Test + public void testBlockSchedule2() { + ScheduleResult schedule = getFinalSchedule("testBlockSchedule2Snippet", TestMode.WITHOUT_FRAMESTATES, SchedulingStrategy.LATEST); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); + assertReadAndWriteInSameBlock(schedule, false); + } + + public static void testProxySnippet() { + while (container.a < container.b) { + List list = new ArrayList<>(containerList); + while (container.c < list.size()) { + if (container.obj != null) { + return; + } + container.c++; + } + container.a = 0; + container.b--; + } + container.b++; + } + + @Test + public void testProxy() { + ScheduleResult schedule = getFinalSchedule("testProxySnippet", TestMode.WITHOUT_FRAMESTATES); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); + } + + private int hash = 0; + private final char[] value = new char[3]; + + public int testStringHashCodeSnippet() { + int h = hash; + if (h == 0 && value.length > 0) { + char[] val = value; + + for (int i = 0; i < value.length; i++) { + h = 31 * h + val[i]; + } + hash = h; + } + return h; + } + + @Test + public void testStringHashCode() { + ScheduleResult schedule = getFinalSchedule("testStringHashCodeSnippet", TestMode.WITHOUT_FRAMESTATES); + assertReadWithinStartBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, false); + + hash = 0x1337; + value[0] = 'a'; + value[1] = 'b'; + value[2] = 'c'; + test("testStringHashCodeSnippet"); + } + + public static int testLoop4Snippet(int count) { + int[] a = new int[count]; + + for (int i = 0; i < a.length; i++) { + a[i] = i; + } + + int i = 0; + int iwrap = count - 1; + int sum = 0; + + while (i < count) { + sum += (a[i] + a[iwrap]) / 2; + iwrap = i; + i++; + } + return sum; + } + + @Test + public void testLoop4() { + ScheduleResult schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); + } + + private void assertReadWithinAllReturnBlocks(ScheduleResult schedule, boolean withinReturnBlock) { + StructuredGraph graph = schedule.getCFG().graph; + assertTrue(graph.getNodes(ReturnNode.TYPE).isNotEmpty()); + + int withRead = 0; + int returnBlocks = 0; + for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) { + Block block = schedule.getCFG().getNodeToBlock().get(returnNode); + for (Node node : schedule.getBlockToNodesMap().get(block)) { + if (node instanceof FloatingReadNode) { + withRead++; + break; + } + } + returnBlocks++; + } + assertDeepEquals(withRead == returnBlocks, withinReturnBlock); + } + + private void assertReadWithinStartBlock(ScheduleResult schedule, boolean withinStartBlock) { + boolean readEncountered = false; + for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) { + if (node instanceof FloatingReadNode) { + readEncountered = true; + } + } + assertDeepEquals(withinStartBlock, readEncountered); + } + + private static void assertReadAndWriteInSameBlock(ScheduleResult schedule, boolean inSame) { + StructuredGraph graph = schedule.getCFG().graph; + FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first(); + WriteNode write = graph.getNodes().filter(WriteNode.class).first(); + assertTrue(!(inSame ^ schedule.getCFG().blockFor(read) == schedule.getCFG().blockFor(write))); + } + + private static void assertReadBeforeAllWritesInStartBlock(ScheduleResult schedule) { + boolean writeNodeFound = false; + boolean readNodeFound = false; + for (Node node : schedule.nodesFor(schedule.getCFG().getStartBlock())) { + if (node instanceof FloatingReadNode) { + assertTrue(!writeNodeFound); + readNodeFound = true; + } else if (node instanceof WriteNode) { + writeNodeFound = true; + } + } + assertTrue(readNodeFound); + } + + private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode) { + return getFinalSchedule(snippet, mode, SchedulingStrategy.LATEST_OUT_OF_LOOPS); + } + + @SuppressWarnings("try") + private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) { + final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + try (Scope d = Debug.scope("FloatingReadTest", graph)) { + try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) { + HighTierContext context = getDefaultHighTierContext(); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + canonicalizer.apply(graph, context); + if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { + new InliningPhase(canonicalizer).apply(graph, context); + } + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { + graph.clearAllStateAfter(); + } + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after removal of framestates"); + + new FloatingReadPhase().apply(graph); + new RemoveValueProxyPhase().apply(graph); + + MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); + new GuardLoweringPhase().apply(graph, midContext); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, midContext); + + SchedulePhase schedule = new SchedulePhase(schedulingStrategy); + schedule.apply(graph); + assertDeepEquals(1, graph.getNodes().filter(StartNode.class).count()); + return graph.getLastSchedule(); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java 2016-12-07 13:48:28.113748350 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class MergeCanonicalizerTest extends GraalCompilerTest { + + public static int staticField; + + private int field; + + @Test + public void testSplitReturn() { + test("testSplitReturnSnippet", 2); + testReturnCount("testSplitReturnSnippet", 2); + } + + public int testSplitReturnSnippet(int b) { + int v; + if (b < 0) { + staticField = 1; + v = 10; + } else { + staticField = 2; + v = 20; + } + int i = field; + i = field + i; + return v; + } + + private void testReturnCount(String snippet, int returnCount) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + assertDeepEquals(returnCount, graph.getNodes(ReturnNode.TYPE).count()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MethodHandleEagerResolution.java 2016-12-07 13:48:28.377759955 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011, 2014, 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.core.test; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +public final class MethodHandleEagerResolution extends GraalCompilerTest { + private static final MethodHandle FIELD_HANDLE; + + static { + Field field; + try { + field = String.class.getDeclaredField("value"); + } catch (NoSuchFieldException ex) { + throw new RuntimeException(ex.getMessage(), ex); + } + field.setAccessible(true); + + try { + FIELD_HANDLE = MethodHandles.lookup().unreflectGetter(field); + } catch (IllegalAccessException e) { + throw new RuntimeException("unable to initialize field handle", e); + } + } + + public static char[] getBackingCharArray(String str) { + try { + return (char[]) FIELD_HANDLE.invokeExact(str); + } catch (Throwable e) { + throw new IllegalStateException(); + } + } + + @Test + public void testFieldInvokeExact() { + StructuredGraph graph = parseEager("getBackingCharArray", AllowAssumptions.NO); + assertTrue(graph.getNodes().filter(DeoptimizeNode.class).isEmpty()); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MonitorGraphTest.java 2016-12-07 13:48:28.642771604 -0800 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.java.MonitorExitNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +/** + * In the following tests, the usages of local variable "a" are replaced with the integer constant + * 0. Then canonicalization is applied and it is verified that the resulting graph is equal to the + * graph of the method that just has a "return 1" statement in it. + */ +public class MonitorGraphTest extends GraalCompilerTest { + + private static final String REFERENCE_SNIPPET = "referenceSnippet"; + + @SuppressWarnings("all") + public static synchronized int referenceSnippet(int a) { + return 1; + } + + public static int const1() { + return 1; + } + + @Test + public void test1() { + test("test1Snippet"); + } + + @SuppressWarnings("all") + public static synchronized int test1Snippet(int a) { + return const1(); + } + + @Test + public void test2() { + StructuredGraph graph = parseAndProcess("test2Snippet"); + NodeIterable monitors = graph.getNodes(MonitorExitNode.TYPE); + Assert.assertEquals(1, monitors.count()); + Assert.assertEquals(monitors.first().stateAfter().bci, 3); + } + + @SuppressWarnings("all") + public static int test2Snippet(int a) { + return const2(); + } + + public static synchronized int const2() { + return 1; + } + + private StructuredGraph parseAndProcess(String snippet) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + ParameterNode param = graph.getNodes(ParameterNode.TYPE).first(); + if (param != null) { + ConstantNode constant = ConstantNode.forInt(0, graph); + for (Node n : param.usages().snapshot()) { + if (!(n instanceof FrameState)) { + n.replaceFirstInput(param, constant); + } + } + } + Map hints = new HashMap<>(); + for (Invoke invoke : graph.getInvokes()) { + hints.put(invoke, 1000d); + } + HighTierContext context = getDefaultHighTierContext(); + new InliningPhase(hints, new CanonicalizerPhase()).apply(graph, context); + new CanonicalizerPhase().apply(graph, context); + new DeadCodeEliminationPhase().apply(graph); + return graph; + } + + private void test(String snippet) { + StructuredGraph graph = parseAndProcess(snippet); + StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.NO); + assertEquals(referenceGraph, graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NestedLoopTest.java 2016-12-07 13:48:28.907783253 -0800 @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.core.common.cfg.Loop; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.nodes.java.MethodCallTargetNode; + +public class NestedLoopTest extends GraalCompilerTest { + + @Test + public void test1() { + test("test1Snippet", 1, 2, 2); + } + + @Test + public void test2() { + test("test2Snippet", 1, 2, 2); + } + + @Test + public void test3() { + test("test3Snippet", 1, 2, 2); + } + + @Test + public void test4() { + test("test4Snippet", 1, 3, 2); + } + + @SuppressWarnings("all") + public static void test1Snippet(int a) { + while (a()) { // a() exits root, while() exits root + m1: while (b()) { // b() exits nested & root, while() exits nested + while (c()) { // c() exits innermost & nested & root, while() exits innermost + if (d()) { // d() exits innermost & nested & root + break m1; // break exits innermost & nested + } + } + } + } + }// total : root = 5 exits, nested = 5, innermost = 4 + + @SuppressWarnings("all") + public static void test2Snippet(int a) { + while (a()) { // a() exits root, while() exits root + try { + m1: while (b()) { // b() exits nested, while() exits nested + while (c()) { // c() exits innermost & nested, while() exits innermost + if (d()) { // d() exits innermost & nested + break m1; // break exits innermost & nested + } + } + } + } catch (Throwable t) { + } + } + }// total : root = 2 exits, nested = 5, innermost = 4 + + @SuppressWarnings("all") + public static void test3Snippet(int a) { + while (a == 0) { // while() exits root + try { + m1: while (b()) { // b() exits nested, while() exits nested + while (c()) { // c() exits innermost & nested, while() exits innermost + if (d()) { // d() exits innermost & nested + a(); // a() exits nothing (already outside innermost & nested) + break m1; // break exits innermost & nested + } + } + } + } catch (Throwable t) { + } + } + }// total : root = 1 exit, nested = 5, innermost = 4 + + public static void test4Snippet(int a) { + while (a != 0) { // while() exits root + try { + m1: while (a != 0) { // while() exits nested + b(); // b() exits nested + while (c()) { // c() exits innermost & nested, while() exits innermost + if (d()) { // d() exits innermost & nested + break m1; // break exits innermost & nested + } + } + if (a != 2) { + a(); // a() exits nothing (already outside innermost & nested) + throw new Exception(); // throw exits nested + } + } + } catch (Throwable t) { + } + } + } // total : root = 1 exit, nested = 6, innermost = 4 + + private static native boolean a(); + + private static native boolean b(); + + private static native boolean c(); + + private static native boolean d(); + + private static Invoke getInvoke(String name, StructuredGraph graph) { + for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) { + if (callTarget.targetMethod().getName().equals(name)) { + return callTarget.invoke(); + } + } + return null; + } + + private void test(String snippet, int rootExits, int nestedExits, int innerExits) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); + + Assert.assertEquals(3, cfg.getLoops().size()); + Loop rootLoop = cfg.getLoops().get(0); + Loop nestedLoop = cfg.getLoops().get(1); + Loop innerMostLoop = cfg.getLoops().get(2); + Invoke a = getInvoke("a", graph); + Invoke b = getInvoke("b", graph); + Invoke c = getInvoke("c", graph); + Invoke d = getInvoke("d", graph); + Assert.assertTrue(containsDirect(rootLoop, a, cfg)); + Assert.assertTrue(containsDirect(nestedLoop, b, cfg)); + Assert.assertTrue(containsDirect(innerMostLoop, c, cfg)); + Assert.assertTrue(containsDirect(innerMostLoop, d, cfg)); + Assert.assertTrue(contains(rootLoop, d, cfg)); + Assert.assertTrue(contains(nestedLoop, d, cfg)); + Assert.assertEquals(rootExits, rootLoop.getExits().size()); + Assert.assertEquals(nestedExits, nestedLoop.getExits().size()); + Assert.assertEquals(innerExits, innerMostLoop.getExits().size()); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + } + + private static boolean contains(Loop loop, Invoke node, ControlFlowGraph cfg) { + Block block = cfg.blockFor((Node) node); + Assert.assertNotNull(block); + return loop.getBlocks().contains(block); + } + + private static boolean containsDirect(Loop loop, Invoke node, ControlFlowGraph cfg) { + for (Loop child : loop.getChildren()) { + if (contains(child, node, cfg)) { + return false; + } + } + return contains(loop, node, cfg); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePosIteratorTest.java 2016-12-07 13:48:29.171794859 -0800 @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2012, 2012, 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.core.test; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; + +import java.util.Iterator; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.graph.NodeSuccessorList; +import org.graalvm.compiler.graph.Position; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.EndNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; + +public class NodePosIteratorTest extends GraalCompilerTest { + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static final class TestNode extends Node { + public static final NodeClass TYPE = NodeClass.create(TestNode.class); + @Successor Node s1; + @Successor Node s2; + @Successor NodeSuccessorList stail; + + @Input NodeInputList itail; + @Input ConstantNode i1; + @Input FloatingNode i2; + + protected TestNode() { + super(TYPE); + } + + } + + @Test + public void testInputs() { + TestNode n = new TestNode(); + + ConstantNode i1 = ConstantNode.forInt(1); + ConstantNode i2 = ConstantNode.forDouble(1.0d); + ConstantNode i3 = ConstantNode.forInt(4); + ConstantNode i4 = ConstantNode.forInt(14); + n.itail = new NodeInputList<>(n, new ValueNode[]{i3, i4}); + n.i1 = i1; + n.i2 = i2; + + NodeIterable inputs = n.inputs(); + + Iterator iterator = inputs.iterator(); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i1); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i2); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i3); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i4); + Assert.assertFalse(iterator.hasNext()); + Assert.assertFalse(iterator.hasNext()); + + Iterator positionIterator = n.inputPositions().iterator(); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertEquals("ConstantNode:i1", positionIterator.next().toString()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertEquals("FloatingNode:i2", positionIterator.next().toString()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertEquals("NodeInputList:itail[0]", positionIterator.next().toString()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertEquals("NodeInputList:itail[1]", positionIterator.next().toString()); + Assert.assertFalse(positionIterator.hasNext()); + Assert.assertFalse(positionIterator.hasNext()); + + iterator = inputs.iterator(); + n.i1 = i4; + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i4); + n.i2 = i1; + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i1); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i3); + n.itail.initialize(1, i4); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i4); + Assert.assertFalse(iterator.hasNext()); + + iterator = inputs.iterator(); + n.i1 = null; + n.i2 = i2; + n.itail.initialize(0, null); + n.itail.initialize(1, i4); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i2); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i4); + Assert.assertFalse(iterator.hasNext()); + } + + @Test + public void testSuccessors() { + TestNode n = new TestNode(); + EndNode s1 = new EndNode(); + EndNode s2 = new EndNode(); + EndNode s3 = new EndNode(); + EndNode s4 = new EndNode(); + n.s1 = s1; + n.s2 = s2; + n.stail = new NodeSuccessorList<>(n, new Node[]{s3, s4}); + + NodeIterable successors = n.successors(); + Iterator iterator = successors.iterator(); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s1); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s2); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s3); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s4); + Assert.assertFalse(iterator.hasNext()); + Assert.assertFalse(iterator.hasNext()); + + Iterator positionIterator = n.successorPositions().iterator(); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertEquals(Node.class.getSimpleName() + ":s1", positionIterator.next().toString()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertEquals(Node.class.getSimpleName() + ":s2", positionIterator.next().toString()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertEquals(NodeSuccessorList.class.getSimpleName() + ":stail[0]", positionIterator.next().toString()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertTrue(positionIterator.hasNext()); + Assert.assertEquals(NodeSuccessorList.class.getSimpleName() + ":stail[1]", positionIterator.next().toString()); + Assert.assertFalse(positionIterator.hasNext()); + Assert.assertFalse(positionIterator.hasNext()); + + iterator = successors.iterator(); + n.s1 = s4; + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s4); + n.s2 = s1; + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s1); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s3); + n.stail.initialize(1, s4); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s4); + Assert.assertFalse(iterator.hasNext()); + + iterator = successors.iterator(); + n.s1 = null; + n.s2 = s2; + n.stail.initialize(0, null); + n.stail.initialize(1, s4); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s2); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s4); + Assert.assertFalse(iterator.hasNext()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java 2016-12-07 13:48:29.436806508 -0800 @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.SimplifierTool; +import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.NodeCostProvider; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.CanonicalizerPhase.CustomCanonicalizer; +import org.graalvm.compiler.phases.contract.NodeCostUtil; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class NodePropertiesTest extends GraalCompilerTest { + + public static Object sideEffect; + + public static Object[] array = new Object[]{new Object(), new Object(), new Object()}; + + public static int test1Snippet(int a) { + int x = 0; + if (a > 0) { + x = 1; + sideEffect = null; + } else { + x = 2; + sideEffect = null; + } + sideEffect = null; + // can shift + return a * x * 4; + } + + public static int test2Snippet(int a) { + int x = 0; + if (a > 0) { + x = 1; + sideEffect = null; + } else { + x = 2; + sideEffect = null; + } + sideEffect = null; + // cannot shift + return a * x * 3; + } + + public static final int ITERATIONS_LOOP_1 = 128; + public static final int ITERATIONS_LOOP_2 = 256; + + public static int testLoop01(int a) { + int res = 0; + for (int i = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_1, i < a); i++) { + res += i; + } + return res; + } + + public static int testLoop02(int a) { + int res = 0; + for (int i = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_2, i < a); i++) { + res += i; + } + return res; + } + + public static int testLoop03(int a) { + int res = 0; + for (int i = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_1, i < a); i++) { + res *= i; + } + return res; + } + + public static int testLoop04(int a) { + int res = 0; + for (int i = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_1 * ITERATIONS_LOOP_2, i < a); i++) { + res += i; + } + return res; + } + + public static int testLoop05(int a) { + int res = 0; + for (int i = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_1, i < a); i++) { + res += i; + for (int j = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_2, j < ITERATIONS_LOOP_2); j++) { + res += i; + } + } + return res; + } + + public static int dontInline(int a) { + int res = 1; + for (int i = 0; i < a; i++) { + for (int j = 0; j < i; j++) { + for (int k = 0; k < j; k++) { + res += i + j + k; + } + } + } + sideEffect = res; + return (Integer) sideEffect; + } + + public static int untrused01(int a) { + return dontInline(a); + } + + public static int arrayLoadTest(int a) { + return array[a].hashCode(); + } + + public static int arrayStoreTest(int a) { + String s = String.valueOf(a); + array[2] = s; + return s.length(); + } + + public static int fieldLoad(int a) { + return sideEffect.hashCode() * a; + } + + public static int fieldStore(int a) { + sideEffect = a; + return a; + } + + @Test + public void testCanonicalizationExample() { + HighTierContext htc = getDefaultHighTierContext(); + ImprovementSavingCanonicalizer c1 = new ImprovementSavingCanonicalizer(htc.getNodeCostProvider()); + StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("test1Snippet")); + new CanonicalizerPhase(c1).apply(g1, htc); + ImprovementSavingCanonicalizer c2 = new ImprovementSavingCanonicalizer(htc.getNodeCostProvider()); + StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("test2Snippet")); + new CanonicalizerPhase(c2).apply(g2, htc); + Assert.assertTrue(c1.savedCycles > c2.savedCycles); + } + + private static void prepareGraphForLoopFrequencies(StructuredGraph g, HighTierContext htc) { + // let canonicalizer work away branch probability nodes + new CanonicalizerPhase().apply(g, htc); + // recompute the loop frequencies + ComputeLoopFrequenciesClosure.compute(g); + } + + private static void assertFrequency(StructuredGraph g, int iterations) { + NodeIterable loopBeginNodes = g.getNodes(LoopBeginNode.TYPE); + LoopBeginNode loopBeginNode = loopBeginNodes.first(); + Assert.assertEquals("loop frequency of " + loopBeginNode, iterations, loopBeginNode.loopFrequency(), 0); + } + + @Test + public void testDifferentLoopFaster() { + HighTierContext htc = getDefaultHighTierContext(); + StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("testLoop01")); + StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("testLoop03")); + prepareGraphForLoopFrequencies(g1, htc); + prepareGraphForLoopFrequencies(g2, htc); + assertFrequency(g1, ITERATIONS_LOOP_1); + assertFrequency(g2, ITERATIONS_LOOP_1); + GraphCostPhase gc1 = new GraphCostPhase(); + GraphCostPhase gc2 = new GraphCostPhase(); + gc1.apply(g1, htc); + gc2.apply(g2, htc); + Debug.log("Test testDifferentLoopFaster --> 1.Graph cycles:%f size:%f vs. 2.Graph cycles:%f size:%f\n", gc1.finalCycles, gc1.finalSize, gc2.finalCycles, gc2.finalSize); + Assert.assertTrue(gc2.finalCycles > gc1.finalCycles); + Assert.assertTrue(gc2.finalSize == gc1.finalSize); + } + + @Test + public void testSameLoopMoreIterationsCostlier() { + HighTierContext htc = getDefaultHighTierContext(); + StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("testLoop01")); + StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("testLoop02")); + prepareGraphForLoopFrequencies(g1, htc); + prepareGraphForLoopFrequencies(g2, htc); + assertFrequency(g1, ITERATIONS_LOOP_1); + assertFrequency(g2, ITERATIONS_LOOP_2); + GraphCostPhase gc1 = new GraphCostPhase(); + GraphCostPhase gc2 = new GraphCostPhase(); + gc1.apply(g1, htc); + gc2.apply(g2, htc); + Debug.log("Test testSameLoopMoreIterationsCostlier --> 1.Graph cycles:%f size:%f vs. 2.Graph cycles:%f size:%f\n", gc1.finalCycles, gc1.finalSize, gc2.finalCycles, gc2.finalSize); + Assert.assertTrue(gc2.finalCycles > gc1.finalCycles); + Assert.assertTrue(gc2.finalSize == gc1.finalSize); + } + + @Test + public void testDifferentLoopsInnerOuter() { + HighTierContext htc = getDefaultHighTierContext(); + StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("testLoop04")); + StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("testLoop05")); + prepareGraphForLoopFrequencies(g1, htc); + prepareGraphForLoopFrequencies(g2, htc); + assertFrequency(g1, ITERATIONS_LOOP_1 * ITERATIONS_LOOP_2); + GraphCostPhase gc1 = new GraphCostPhase(); + GraphCostPhase gc2 = new GraphCostPhase(); + gc1.apply(g1, htc); + gc2.apply(g2, htc); + Debug.log("Test testDifferentLoopsInnerOuter --> 1.Graph cycles:%f size:%f vs. 2.Graph cycles:%f size:%f\n", gc1.finalCycles, gc1.finalSize, gc2.finalCycles, gc2.finalSize); + Assert.assertTrue(gc2.finalSize > gc1.finalSize); + } + + @Test + public void testGraphCost() { + StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("test1Snippet")); + StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("test2Snippet")); + HighTierContext htc = getDefaultHighTierContext(); + new CanonicalizerPhase().apply(g1, htc); + new CanonicalizerPhase().apply(g2, htc); + GraphCostPhase gc1 = new GraphCostPhase(); + GraphCostPhase gc2 = new GraphCostPhase(); + gc1.apply(g1, htc); + gc2.apply(g2, htc); + Debug.log("Test Graph Cost --> 1.Graph cost:%f vs. 2.Graph cost:%f\n", gc1.finalCycles, gc2.finalCycles); + Assert.assertTrue(gc2.finalCycles > gc1.finalCycles); + Assert.assertTrue(gc2.finalSize == gc1.finalSize + 1/* mul has 3 const input */); + } + + @Test + public void testExpectUntrusted() { + StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("untrused01")); + HighTierContext htc = getDefaultHighTierContext(); + new CanonicalizerPhase().apply(g1, htc); + GraphCostPhase gc1 = new GraphCostPhase(); + gc1.apply(g1, htc); + } + + @Test + public void testArrayLoad() { + StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("arrayLoadTest")); + HighTierContext htc = getDefaultHighTierContext(); + new CanonicalizerPhase().apply(g1, htc); + GraphCostPhase gc1 = new GraphCostPhase(); + gc1.apply(g1, htc); + Assert.assertEquals(35, gc1.finalCycles, 25); + } + + @Test + public void testArrayStore() { + StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("arrayStoreTest")); + HighTierContext htc = getDefaultHighTierContext(); + new CanonicalizerPhase().apply(g1, htc); + GraphCostPhase gc1 = new GraphCostPhase(); + gc1.apply(g1, htc); + Assert.assertEquals(50, gc1.finalCycles, 25); + } + + @Test + public void testFieldLoad() { + StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("fieldLoad")); + HighTierContext htc = getDefaultHighTierContext(); + new CanonicalizerPhase().apply(g1, htc); + GraphCostPhase gc1 = new GraphCostPhase(); + gc1.apply(g1, htc); + Assert.assertEquals(30, gc1.finalCycles, 25); + } + + @Test + public void testFieldStore() { + StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("fieldStore")); + HighTierContext htc = getDefaultHighTierContext(); + new CanonicalizerPhase().apply(g1, htc); + GraphCostPhase gc1 = new GraphCostPhase(); + gc1.apply(g1, htc); + Assert.assertEquals(120, gc1.finalCycles, 25); + } + + static class ImprovementSavingCanonicalizer extends CustomCanonicalizer { + private int savedCycles; + private final NodeCostProvider nodeCostProvider; + + ImprovementSavingCanonicalizer(NodeCostProvider nodeCostProvider) { + this.nodeCostProvider = nodeCostProvider; + } + + @Override + public void simplify(Node node, SimplifierTool tool) { + if (node instanceof Canonicalizable.Binary) { + @SuppressWarnings("unchecked") + Canonicalizable.Binary bc = (Canonicalizable.Binary) node; + Node canonicalized = bc.canonical(tool, bc.getX(), bc.getY()); + if (canonicalized != node) { + savedCycles += nodeCostProvider.getEstimatedCPUCycles(node) - nodeCostProvider.getEstimatedCPUCycles(canonicalized); + } + } + } + } + + private static class GraphCostPhase extends BasePhase { + private double finalCycles; + private double finalSize; + + @Override + protected void run(StructuredGraph graph, PhaseContext context) { + finalCycles = NodeCostUtil.computeGraphCycles(graph, context.getNodeCostProvider(), true); + finalSize = NodeCostUtil.computeGraphSize(graph, context.getNodeCostProvider()); + } + + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OnStackReplacementTest.java 2016-12-07 13:48:29.702818201 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, 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.core.test; + +import org.junit.Test; + +public class OnStackReplacementTest extends GraalCompilerTest { + + @Test + public void test1() { + test("test1Snippet"); + } + + static int limit = 10000; + + public static void test1Snippet() { + for (int i = 0; !Thread.currentThread().isInterrupted() && i < limit; i++) { + for (int j = 0; !Thread.currentThread().isInterrupted() && j < limit; j++) { + } + } + + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OptionsVerifierTest.java 2016-12-07 13:48:29.966829806 -0800 @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2014, 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.core.test; + +import static java.lang.String.format; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.ServiceLoader; +import java.util.Set; + +import org.junit.Test; + +import org.graalvm.compiler.options.OptionDescriptor; +import org.graalvm.compiler.options.OptionDescriptors; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.test.GraalTest; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; + +/** + * Verifies a class declaring one or more {@linkplain OptionValue options} has a class initializer + * that only initializes the option(s). This sanity check mitigates the possibility of an option + * value being used before being set. + */ +public class OptionsVerifierTest { + + @Test + public void verifyOptions() throws IOException { + try (Classpath cp = new Classpath()) { + HashSet> checked = new HashSet<>(); + for (OptionDescriptors opts : ServiceLoader.load(OptionDescriptors.class, getClass().getClassLoader())) { + for (OptionDescriptor desc : opts) { + OptionsVerifier.checkClass(desc.getDeclaringClass(), desc, checked, cp); + } + } + } + } + + static class Classpath implements AutoCloseable { + private final Map entries = new LinkedHashMap<>(); + + Classpath() throws IOException { + List names = new ArrayList<>(Arrays.asList(System.getProperty("java.class.path").split(File.pathSeparator))); + if (GraalTest.Java8OrEarlier) { + names.addAll(Arrays.asList(System.getProperty("sun.boot.class.path").split(File.pathSeparator))); + } else { + names.addAll(Arrays.asList(System.getProperty("jdk.module.path").split(File.pathSeparator))); + } + for (String n : names) { + File path = new File(n); + if (path.exists()) { + if (path.isDirectory()) { + entries.put(n, path); + } else if (n.endsWith(".jar") || n.endsWith(".zip")) { + URL url = new URL("jar", "", "file:" + n + "!/"); + entries.put(n, new URLClassLoader(new URL[]{url})); + } + } + } + } + + @Override + public void close() throws IOException { + for (Object e : entries.values()) { + if (e instanceof URLClassLoader) { + ((URLClassLoader) e).close(); + } + } + } + + public byte[] getInputStream(String classFilePath) throws IOException { + for (Object e : entries.values()) { + if (e instanceof File) { + File path = new File((File) e, classFilePath.replace('/', File.separatorChar)); + if (path.exists()) { + return Files.readAllBytes(path.toPath()); + } + } else { + assert e instanceof URLClassLoader; + URLClassLoader ucl = (URLClassLoader) e; + try (InputStream in = ucl.getResourceAsStream(classFilePath)) { + if (in != null) { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[1024]; + while ((nRead = in.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + return buffer.toByteArray(); + } + } + } + } + return null; + } + } + + static final class OptionsVerifier extends ClassVisitor { + + public static void checkClass(Class cls, OptionDescriptor option, Set> checked, Classpath cp) throws IOException { + if (!checked.contains(cls)) { + checked.add(cls); + Class superclass = cls.getSuperclass(); + if (superclass != null && !superclass.equals(Object.class)) { + checkClass(superclass, option, checked, cp); + } + + String classFilePath = cls.getName().replace('.', '/') + ".class"; + ClassReader cr = new ClassReader(Objects.requireNonNull(cp.getInputStream(classFilePath), "Could not find class file for " + cls.getName())); + + ClassVisitor cv = new OptionsVerifier(cls, option); + cr.accept(cv, 0); + } + } + + /** + * The option field context of the verification. + */ + private final OptionDescriptor option; + + /** + * The class in which {@link #option} is declared or a super-class of that class. This is + * the class whose {@code } method is being verified. + */ + private final Class cls; + + /** + * Source file context for error reporting. + */ + String sourceFile = null; + + /** + * Line number for error reporting. + */ + int lineNo = -1; + + final Class[] boxingTypes = {Boolean.class, Byte.class, Short.class, Character.class, Integer.class, Float.class, Long.class, Double.class}; + + private static Class resolve(String name) { + try { + return Class.forName(name.replace('/', '.')); + } catch (ClassNotFoundException e) { + throw new InternalError(e); + } + } + + OptionsVerifier(Class cls, OptionDescriptor desc) { + super(Opcodes.ASM5); + this.cls = cls; + this.option = desc; + } + + @Override + public void visitSource(String source, String debug) { + this.sourceFile = source; + } + + void verify(boolean condition, String message) { + if (!condition) { + error(message); + } + } + + void error(String message) { + String errorMessage = format( + "%s:%d: Illegal code in %s. which may be executed when %s.%s is initialized:%n%n %s%n%n" + "The recommended solution is to move " + option.getName() + + " into a separate class (e.g., %s.Options).%n", + sourceFile, lineNo, cls.getSimpleName(), option.getDeclaringClass().getSimpleName(), option.getName(), + message, option.getDeclaringClass().getSimpleName()); + throw new InternalError(errorMessage); + + } + + @Override + public MethodVisitor visitMethod(int access, String name, String d, String signature, String[] exceptions) { + if (name.equals("")) { + return new MethodVisitor(Opcodes.ASM5) { + + @Override + public void visitLineNumber(int line, Label start) { + lineNo = line; + } + + @Override + public void visitFieldInsn(int opcode, String owner, String fieldName, String fieldDesc) { + if (opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC) { + verify(resolve(owner).equals(option.getDeclaringClass()), format("store to field %s.%s", resolve(owner).getSimpleName(), fieldName)); + verify(opcode != Opcodes.PUTFIELD, format("store to non-static field %s.%s", resolve(owner).getSimpleName(), fieldName)); + } + } + + private Executable resolveMethod(String owner, String methodName, String methodDesc) { + Class declaringClass = resolve(owner); + if (methodName.equals("")) { + for (Constructor c : declaringClass.getDeclaredConstructors()) { + if (methodDesc.equals(Type.getConstructorDescriptor(c))) { + return c; + } + } + } else { + Type[] argumentTypes = Type.getArgumentTypes(methodDesc); + for (Method m : declaringClass.getDeclaredMethods()) { + if (m.getName().equals(methodName)) { + if (Arrays.equals(argumentTypes, Type.getArgumentTypes(m))) { + if (Type.getReturnType(methodDesc).equals(Type.getReturnType(m))) { + return m; + } + } + } + } + } + throw new NoSuchMethodError(declaringClass + "." + methodName + methodDesc); + } + + /** + * Checks whether a given method is allowed to be called. + */ + private boolean checkInvokeTarget(Executable method) { + Class holder = method.getDeclaringClass(); + if (method instanceof Constructor) { + if (OptionValue.class.isAssignableFrom(holder)) { + return true; + } + } else if (Arrays.asList(boxingTypes).contains(holder)) { + return method.getName().equals("valueOf"); + } else if (method.getDeclaringClass().equals(Class.class)) { + return method.getName().equals("desiredAssertionStatus"); + } + return false; + } + + @Override + public void visitMethodInsn(int opcode, String owner, String methodName, String methodDesc, boolean itf) { + Executable callee = resolveMethod(owner, methodName, methodDesc); + verify(checkInvokeTarget(callee), "invocation of " + callee); + } + }; + } else { + return null; + } + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PhiCreationTests.java 2016-12-07 13:48:30.230841411 -0800 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValuePhiNode; + +/** + * In the following tests, the correct removal of redundant phis during graph building is tested. + */ +public class PhiCreationTests extends GraalCompilerTest { + + /** + * Dummy method to avoid javac dead code elimination. + */ + private static void test() { + } + + @Test + public void test1() { + StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.YES); + Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext()); + } + + public static int test1Snippet(int a) { + if (a > 1) { + test(); + } + return a; + } + + @Test + public void test2() { + StructuredGraph graph = parseEager("test2Snippet", AllowAssumptions.YES); + Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext()); + } + + public static int test2Snippet(int a) { + while (a > 1) { + test(); + } + return a; + } + + @Test + public void test3() { + StructuredGraph graph = parseEager("test3Snippet", AllowAssumptions.YES); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext()); + } + + public static int test3Snippet(int a) { + while (a > 1) { + while (a > 1) { + test(); + } + } + return a; + } + + @Test + public void test4() { + StructuredGraph graph = parseEager("test4Snippet", AllowAssumptions.YES); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext()); + } + + public static int test4Snippet(int a) { + int b = 5; + while (a > 1) { + while (a > 1) { + while (a > 1) { + try { + test(); + } catch (Throwable t) { + + } + } + } + while (a > 1) { + while (a > 1) { + try { + test(); + } catch (Throwable t) { + + } + } + } + } + return a + b; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ProfilingInfoTest.java 2016-12-07 13:48:30.496853104 -0800 @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.test; + +import java.io.Serializable; + +import jdk.vm.ci.meta.JavaTypeProfile; +import jdk.vm.ci.meta.ProfilingInfo; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.TriState; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests profiling information provided by the runtime. + *

+ * NOTE: These tests are actually not very robust. The problem is that only partial profiling + * information may be gathered for any given method. For example, HotSpot's advanced compilation + * policy can decide to only gather partial profiles in a first level compilation (see + * AdvancedThresholdPolicy::common(...) in advancedThresholdPolicy.cpp). Because of this, + * occasionally tests for {@link ProfilingInfo#getNullSeen(int)} can fail since HotSpot only set's + * the null_seen bit when doing full profiling. + */ +public class ProfilingInfoTest extends GraalCompilerTest { + + private static final int N = 10; + private static final double DELTA = 1d / Integer.MAX_VALUE; + + @Test + public void testBranchTakenProbability() { + ProfilingInfo info = profile("branchProbabilitySnippet", 0); + Assert.assertEquals(0.0, info.getBranchTakenProbability(1), DELTA); + Assert.assertEquals(N, info.getExecutionCount(1)); + Assert.assertEquals(-1.0, info.getBranchTakenProbability(8), DELTA); + Assert.assertEquals(0, info.getExecutionCount(8)); + + info = profile("branchProbabilitySnippet", 1); + Assert.assertEquals(1.0, info.getBranchTakenProbability(1), DELTA); + Assert.assertEquals(N, info.getExecutionCount(1)); + Assert.assertEquals(0.0, info.getBranchTakenProbability(8), DELTA); + Assert.assertEquals(N, info.getExecutionCount(8)); + + info = profile("branchProbabilitySnippet", 2); + Assert.assertEquals(1.0, info.getBranchTakenProbability(1), DELTA); + Assert.assertEquals(N, info.getExecutionCount(1)); + Assert.assertEquals(1.0, info.getBranchTakenProbability(8), DELTA); + Assert.assertEquals(N, info.getExecutionCount(8)); + + continueProfiling(3 * N, "branchProbabilitySnippet", 0); + Assert.assertEquals(0.25, info.getBranchTakenProbability(1), DELTA); + Assert.assertEquals(4 * N, info.getExecutionCount(1)); + Assert.assertEquals(1.0, info.getBranchTakenProbability(8), DELTA); + Assert.assertEquals(N, info.getExecutionCount(8)); + + resetProfile("branchProbabilitySnippet"); + Assert.assertEquals(-1.0, info.getBranchTakenProbability(1), DELTA); + Assert.assertEquals(0, info.getExecutionCount(1)); + Assert.assertEquals(-1.0, info.getBranchTakenProbability(8), DELTA); + Assert.assertEquals(0, info.getExecutionCount(8)); + } + + public static int branchProbabilitySnippet(int value) { + if (value == 0) { + return -1; + } else if (value == 1) { + return -2; + } else { + return -3; + } + } + + @Test + public void testSwitchProbabilities() { + ProfilingInfo info = profile("switchProbabilitySnippet", 0); + Assert.assertArrayEquals(new double[]{1.0, 0.0, 0.0}, info.getSwitchProbabilities(1), DELTA); + + info = profile("switchProbabilitySnippet", 1); + Assert.assertArrayEquals(new double[]{0.0, 1.0, 0.0}, info.getSwitchProbabilities(1), DELTA); + + info = profile("switchProbabilitySnippet", 2); + Assert.assertArrayEquals(new double[]{0.0, 0.0, 1.0}, info.getSwitchProbabilities(1), DELTA); + + resetProfile("switchProbabilitySnippet"); + Assert.assertNull(info.getSwitchProbabilities(1)); + } + + public static int switchProbabilitySnippet(int value) { + switch (value) { + case 0: + return -1; + case 1: + return -2; + default: + return -3; + } + } + + @Test + public void testProfileInvokeVirtual() { + testTypeProfile("invokeVirtualSnippet", 1); + } + + public static int invokeVirtualSnippet(Object obj) { + return obj.hashCode(); + } + + @Test + public void testTypeProfileInvokeInterface() { + testTypeProfile("invokeInterfaceSnippet", 1); + } + + public static int invokeInterfaceSnippet(CharSequence a) { + return a.length(); + } + + @Test + public void testTypeProfileCheckCast() { + testTypeProfile("checkCastSnippet", 1); + } + + public static Serializable checkCastSnippet(Object obj) { + try { + return (Serializable) obj; + } catch (ClassCastException e) { + return null; + } + } + + @Test + public void testTypeProfileInstanceOf() { + testTypeProfile("instanceOfSnippet", 1); + } + + public static boolean instanceOfSnippet(Object obj) { + return obj instanceof Serializable; + } + + private void testTypeProfile(String testSnippet, int bci) { + ResolvedJavaType stringType = getMetaAccess().lookupJavaType(String.class); + ResolvedJavaType stringBuilderType = getMetaAccess().lookupJavaType(StringBuilder.class); + + ProfilingInfo info = profile(testSnippet, "ABC"); + JavaTypeProfile typeProfile = info.getTypeProfile(bci); + Assert.assertEquals(0.0, typeProfile.getNotRecordedProbability(), DELTA); + Assert.assertEquals(1, typeProfile.getTypes().length); + Assert.assertEquals(stringType, typeProfile.getTypes()[0].getType()); + Assert.assertEquals(1.0, typeProfile.getTypes()[0].getProbability(), DELTA); + + continueProfiling(testSnippet, new StringBuilder()); + typeProfile = info.getTypeProfile(bci); + Assert.assertEquals(0.0, typeProfile.getNotRecordedProbability(), DELTA); + Assert.assertEquals(2, typeProfile.getTypes().length); + Assert.assertEquals(stringType, typeProfile.getTypes()[0].getType()); + Assert.assertEquals(stringBuilderType, typeProfile.getTypes()[1].getType()); + Assert.assertEquals(0.5, typeProfile.getTypes()[0].getProbability(), DELTA); + Assert.assertEquals(0.5, typeProfile.getTypes()[1].getProbability(), DELTA); + + resetProfile(testSnippet); + typeProfile = info.getTypeProfile(bci); + Assert.assertNull(typeProfile); + } + + @Test + public void testExceptionSeen() { + // NullPointerException + ProfilingInfo info = profile("nullPointerExceptionSnippet", 5); + Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); + + info = profile("nullPointerExceptionSnippet", (Object) null); + Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1)); + + resetProfile("nullPointerExceptionSnippet"); + Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); + + // ArrayOutOfBoundsException + info = profile("arrayIndexOutOfBoundsExceptionSnippet", new int[1]); + Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(2)); + + info = profile("arrayIndexOutOfBoundsExceptionSnippet", new int[0]); + Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(2)); + + resetProfile("arrayIndexOutOfBoundsExceptionSnippet"); + Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(2)); + + // CheckCastException + info = profile("checkCastExceptionSnippet", "ABC"); + Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); + + info = profile("checkCastExceptionSnippet", 5); + Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1)); + + resetProfile("checkCastExceptionSnippet"); + Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); + + // Invoke with exception + info = profile("invokeWithExceptionSnippet", false); + Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); + + info = profile("invokeWithExceptionSnippet", true); + Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1)); + + resetProfile("invokeWithExceptionSnippet"); + Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); + } + + public static int nullPointerExceptionSnippet(Object obj) { + try { + return obj.hashCode(); + } catch (NullPointerException e) { + return 1; + } + } + + public static int arrayIndexOutOfBoundsExceptionSnippet(int[] array) { + try { + return array[0]; + } catch (ArrayIndexOutOfBoundsException e) { + return 1; + } + } + + public static int checkCastExceptionSnippet(Object obj) { + try { + return ((String) obj).length(); + } catch (ClassCastException e) { + return 1; + } + } + + public static int invokeWithExceptionSnippet(boolean doThrow) { + try { + return throwException(doThrow); + } catch (IllegalArgumentException e) { + return 1; + } + } + + private static int throwException(boolean doThrow) { + if (doThrow) { + throw new IllegalArgumentException(); + } else { + return 1; + } + } + + @Test + public void testNullSeen() { + testNullSeen("instanceOfSnippet"); + testNullSeen("checkCastSnippet"); + } + + private void testNullSeen(String snippet) { + ProfilingInfo info = profile(snippet, 1); + Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); + + continueProfiling(snippet, "ABC"); + Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); + + continueProfiling(snippet, new Object()); + Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); + + if (TriState.TRUE == info.getNullSeen(1)) { + // See the javadoc comment for ProfilingInfoTest. + continueProfiling(snippet, (Object) null); + Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); + + continueProfiling(snippet, 0.0); + Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); + + continueProfiling(snippet, new Object()); + Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); + } + + resetProfile(snippet); + Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); + } + + private ProfilingInfo profile(String methodName, Object... args) { + return profile(true, N, methodName, args); + } + + private void continueProfiling(String methodName, Object... args) { + profile(false, N, methodName, args); + } + + private void continueProfiling(int executions, String methodName, Object... args) { + profile(false, executions, methodName, args); + } + + private ProfilingInfo profile(boolean resetProfile, int executions, String methodName, Object... args) { + ResolvedJavaMethod javaMethod = getResolvedJavaMethod(methodName); + Assert.assertTrue(javaMethod.isStatic()); + if (resetProfile) { + javaMethod.reprofile(); + } + + for (int i = 0; i < executions; ++i) { + try { + invoke(javaMethod, null, args); + } catch (Throwable e) { + Assert.fail("method should not throw an exception: " + e.toString()); + } + } + + ProfilingInfo info = javaMethod.getProfilingInfo(); + // The execution counts are low so force maturity + info.setMature(); + return info; + } + + private void resetProfile(String methodName) { + ResolvedJavaMethod javaMethod = getResolvedJavaMethod(methodName); + javaMethod.reprofile(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushNodesThroughPiTest.java 2016-12-07 13:48:30.761864754 -0800 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2013, 2015, 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.core.test; + +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaType; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.calc.IsNullNode; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.PushThroughPiPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class PushNodesThroughPiTest extends GraalCompilerTest { + + public static class A { + + public long x = 20; + } + + public static class B extends A { + + public long y = 10; + } + + public static class C extends B { + + public long z = 5; + } + + public static long test1Snippet(A a) { + C c = (C) a; + long ret = c.x; // this can be pushed before the checkcast + ret += c.y; // not allowed to push + ret += c.z; // not allowed to push + // the null-check should be canonicalized with the null-check of the checkcast + ret += c != null ? 100 : 200; + return ret; + } + + @Test + @SuppressWarnings("try") + public void test1() { + final String snippet = "test1Snippet"; + try (Scope s = Debug.scope("PushThroughPi", new DebugDumpScope(snippet))) { + StructuredGraph graph = compileTestSnippet(snippet); + for (ReadNode rn : graph.getNodes().filter(ReadNode.class)) { + OffsetAddressNode address = (OffsetAddressNode) rn.getAddress(); + long disp = address.getOffset().asJavaConstant().asLong(); + + ResolvedJavaType receiverType = StampTool.typeOrNull(address.getBase()); + ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(disp, rn.getStackKind()); + + assert field != null : "Node " + rn + " tries to access a field which doesn't exists for this type"; + if (field.getName().equals("x")) { + Assert.assertTrue(address.getBase() instanceof ParameterNode); + } else { + Assert.assertTrue(address.getBase().toString(), address.getBase() instanceof PiNode); + } + } + + Assert.assertTrue(graph.getNodes().filter(IsNullNode.class).count() == 1); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + private StructuredGraph compileTestSnippet(final String snippet) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + PhaseContext context = new PhaseContext(getProviders()); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + canonicalizer.apply(graph, context); + new PushThroughPiPhase().apply(graph); + canonicalizer.apply(graph, context); + + return graph; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java 2016-12-07 13:48:31.027876447 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class PushThroughIfTest extends GraalCompilerTest { + + public int field1; + public int field2; + + public int testSnippet(boolean b) { + int i; + if (b) { + i = field1; + } else { + i = field1; + } + return i + field2; + } + + @SuppressWarnings("unused") + public int referenceSnippet(boolean b) { + return field1 + field2; + } + + @Test + public void test1() { + test("testSnippet", "referenceSnippet"); + } + + private void test(String snippet, String reference) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + for (FrameState fs : graph.getNodes(FrameState.TYPE).snapshot()) { + fs.replaceAtUsages(null); + GraphUtil.killWithUnusedFloatingInputs(fs); + } + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + + StructuredGraph referenceGraph = parseEager(reference, AllowAssumptions.YES); + for (FrameState fs : referenceGraph.getNodes(FrameState.TYPE).snapshot()) { + fs.replaceAtUsages(null); + GraphUtil.killWithUnusedFloatingInputs(fs); + } + new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders())); + assertEquals(referenceGraph, graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java 2016-12-07 13:48:31.291888052 -0800 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2013, 2015, 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.core.test; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.memory.FloatingReadNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.OptimizeGuardAnchorsPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/* consider + * B b = (B) a; + * return b.x10; + * + * With snippets a typecheck is performed and if it was successful, a PiNode is created. + * For the read node, however, there is only a dependency to the PiNode, but not to the + * typecheck itself. With special crafting, it's possible to get the scheduler moving the + * FloatingReadNode before the typecheck. Assuming the object is of the wrong type (here for + * example A), an invalid field read is done. + * + * In order to avoid this situation, an anchor node is introduced in CheckCastSnippts. + */ + +public class ReadAfterCheckCastTest extends GraphScheduleTest { + + public static long foo = 0; + + public static class A { + + public long x1; + } + + public static class B extends A { + + public long x10; + } + + public static long test1Snippet(A a) { + if (foo > 4) { + B b = (B) a; + b.x10 += 1; + return b.x10; + } else { + B b = (B) a; + b.x10 += 1; + return b.x10; + } + } + + @Test + public void test1() { + test("test1Snippet"); + } + + @SuppressWarnings("try") + private void test(final String snippet) { + try (Scope s = Debug.scope("ReadAfterCheckCastTest", new DebugDumpScope(snippet))) { + // check shape of graph, with lots of assumptions. will probably fail if graph + // structure changes significantly + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + PhaseContext context = new PhaseContext(getProviders()); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + new FloatingReadPhase().apply(graph); + new OptimizeGuardAnchorsPhase().apply(graph); + canonicalizer.apply(graph, context); + + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After lowering"); + + for (FloatingReadNode node : graph.getNodes(ParameterNode.TYPE).first().usages().filter(FloatingReadNode.class)) { + // Checking that the parameter a is not directly used for the access to field + // x10 (because x10 must be guarded by the checkcast). + Assert.assertTrue(node.getLocationIdentity().isImmutable()); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReassociateAndCanonicalTest.java 2016-12-07 13:48:31.558899789 -0800 @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.graph.IterableNodeType; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class ReassociateAndCanonicalTest extends GraalCompilerTest { + + public static int rnd = (int) (Math.random() * 100); + + @Test + public void test1() { + test("test1Snippet", "ref1Snippet"); + } + + public static int test1Snippet() { + return 1 + (rnd + 2); + } + + public static int ref1Snippet() { + return rnd + 3; + } + + @Test + public void test2() { + test("test2Snippet", "ref2Snippet"); + } + + public static int test2Snippet() { + return rnd + 3; + } + + public static int ref2Snippet() { + return (rnd + 2) + 1; + } + + @Test + public void test3() { + test("test3Snippet", "ref3Snippet"); + } + + public static int test3Snippet() { + return rnd + 3; + } + + public static int ref3Snippet() { + return 1 + (2 + rnd); + } + + @Test + public void test4() { + test("test4Snippet", "ref4Snippet"); + } + + public static int test4Snippet() { + return rnd + 3; + } + + public static int ref4Snippet() { + return (2 + rnd) + 1; + } + + @Test + public void test5() { + test("test5Snippet", "ref5Snippet"); + } + + public static int test5Snippet() { + return -1 - rnd; + } + + public static int ref5Snippet() { + return 1 - (rnd + 2); + } + + @Test + public void test6() { + test("test6Snippet", "ref6Snippet"); + } + + public static int test6Snippet() { + return rnd + 1; + } + + public static int ref6Snippet() { + return (rnd + 2) - 1; + } + + @Test + public void test7() { + test("test7Snippet", "ref7Snippet"); + } + + public static int test7Snippet() { + return -1 - rnd; + } + + public static int ref7Snippet() { + return 1 - (2 + rnd); + } + + @Test + public void test8() { + test("test8Snippet", "ref8Snippet"); + } + + public static int test8Snippet() { + return rnd + 1; + } + + public static int ref8Snippet() { + return (2 + rnd) - 1; + } + + @Test + public void test9() { + test("test9Snippet", "ref9Snippet"); + } + + public static int test9Snippet() { + return rnd - 1; + } + + public static int ref9Snippet() { + return 1 + (rnd - 2); + } + + @Test + public void test10() { + test("test10Snippet", "ref10Snippet"); + } + + public static int test10Snippet() { + return rnd - 1; + } + + public static int ref10Snippet() { + return (rnd - 2) + 1; + } + + @Test + public void test11() { + test("test11Snippet", "ref11Snippet"); + } + + public static int test11Snippet() { + return -rnd + 3; + } + + public static int ref11Snippet() { + return 1 + (2 - rnd); + } + + @Test + public void test12() { + test("test12Snippet", "ref12Snippet"); + } + + public static int test12Snippet() { + return -rnd + 3; + } + + public static int ref12Snippet() { + return (2 - rnd) + 1; + } + + @Test + public void test13() { + test("test13Snippet", "ref13Snippet"); + } + + public static int test13Snippet() { + return -rnd + 3; + } + + public static int ref13Snippet() { + return 1 - (rnd - 2); + } + + @Test + public void test14() { + test("test14Snippet", "ref14Snippet"); + } + + public static int test14Snippet() { + return rnd - 3; + } + + public static int ref14Snippet() { + return (rnd - 2) - 1; + } + + @Test + public void test15() { + test("test15Snippet", "ref15Snippet"); + } + + public static int test15Snippet() { + return rnd + -1; + } + + public static int ref15Snippet() { + return 1 - (2 - rnd); + } + + @Test + public void test16() { + test("test16Snippet", "ref16Snippet"); + } + + public static int test16Snippet() { + return -rnd + 1; + } + + public static int ref16Snippet() { + return (2 - rnd) - 1; + } + + private void test(String test, String ref) { + StructuredGraph testGraph = parseEager(test, AllowAssumptions.NO); + new CanonicalizerPhase().apply(testGraph, new PhaseContext(getProviders())); + StructuredGraph refGraph = parseEager(ref, AllowAssumptions.NO); + new CanonicalizerPhase().apply(refGraph, new PhaseContext(getProviders())); + assertEquals(testGraph, refGraph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReentrantBlockIteratorTest.java 2016-12-07 13:48:31.823911438 -0800 @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.cfg.Loop; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.phases.graph.ReentrantBlockIterator; +import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; +import org.graalvm.compiler.phases.schedule.SchedulePhase; + +public class ReentrantBlockIteratorTest extends GraalCompilerTest { + + public static int IntSideEffect; + + public static int oneBlock() { + return 0; + } + + public static int fourBlock(int a) { + if (a > 0) { + IntSideEffect = a; + } else { + IntSideEffect = 0; + } + GraalDirectives.controlFlowAnchor(); + return 0; + } + + public static int loopBlocks(int a) { + int phi = 0; + for (int i = 0; i < a; i++) { + phi += i; + } + return phi; + } + + public static int loopBlocks2(int a) { + int phi = 0; + for (int i = 0; i < a; i++) { + phi += i; + } + // first loop exit, second loop will not be visited at all AFTER_FSA + for (int i = 0; i < a; i++) { + phi += i; + } + return phi; + } + + // from String.indexof + @SuppressWarnings("all") + public static int loopBlocks3(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, + int fromIndex) { + + // Checkstyle: stop + if (fromIndex >= sourceCount) { + return (targetCount == 0 ? sourceCount : -1); + } + if (fromIndex < 0) { + fromIndex = 0; + } + if (targetCount == 0) { + return fromIndex; + } + + char first = target[targetOffset]; + int max = sourceOffset + (sourceCount - targetCount); + + for (int i = sourceOffset + fromIndex; i <= max; i++) { + /* Look for first character. */ + if (source[i] != first) { + while (++i <= max && source[i] != first) { + + } + } + + /* Found first character, now look at the rest of v2 */ + if (i <= max) { + int j = i + 1; + int end = j + targetCount - 1; + for (int k = targetOffset + 1; j < end && source[j] == target[k]; j++, k++) { + + } + + if (j == end) { + /* Found whole string. */ + return i - sourceOffset; + } + } + } + return -1; + // Checkstyle: resume + } + + public static int loopBlocks4(int a, int c, int d) { + int phi = 0; + l1: for (int i = 0; i < a; i++) { + l3: for (int k = 0; k < c; k++) { + for (int l = 0; l < d; l++) { + phi += i * k * l; + if (phi == 5) { + break l3; + } + } + } + if (phi > 100) { + break l1; + } + } + return phi; + } + + @Test + + public void test01() { + List blocks = getVisitedBlocksInOrder("oneBlock"); + assertOrder(blocks, 0); + } + + @Test + public void test02() { + List blocks = getVisitedBlocksInOrder("fourBlock"); + assertOrder(blocks, 0, 1, 2, 3); + } + + @Test + public void test03() { + List blocks = getVisitedBlocksInOrder("loopBlocks"); + assertOrder(blocks, 0, 1, 2, 3); + } + + @Test + public void test04() { + List blocks = getVisitedBlocksInOrder("loopBlocks2"); + assertOrder(blocks, 0, 1, 2, 3, 4, 5, 6); + } + + @Test + public void test05() { + List blocks = getVisitedBlocksInOrder("loopBlocks3"); + assertVisited(blocks, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + } + + @Test + public void test06() { + getVisitedBlocksInOrder("loopBlocks4"); + } + + private static void assertOrder(List blocks, int... ids) { + if (blocks.size() != ids.length) { + Assert.fail("Different length of blocks " + Arrays.toString(blocks.toArray()) + " ids:" + Arrays.toString(ids)); + } + for (int i = 0; i < blocks.size(); i++) { + if (blocks.get(i).getId() != ids[i]) { + Assert.fail("Different id for block " + blocks.get(i) + " and associated id " + ids[i]); + } + } + } + + private static void assertVisited(List blocks, int... ids) { + if (blocks.size() != ids.length) { + Assert.fail("Different length of blocks " + Arrays.toString(blocks.toArray()) + " ids:" + Arrays.toString(ids)); + } + outer: for (int i = 0; i < blocks.size(); i++) { + for (int j = 0; j < blocks.size(); j++) { + if (blocks.get(i).getId() == ids[j]) { + continue outer; + } + } + Assert.fail("Id for block " + blocks.get(i) + " not found"); + } + } + + private List getVisitedBlocksInOrder(String snippet) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + // after FSA to ensure HIR loop data structure does not contain loop exits + graph.setGuardsStage(GuardsStage.AFTER_FSA); + ArrayList blocks = new ArrayList<>(); + class VoidState { + } + final VoidState voidState = new VoidState(); + BlockIteratorClosure closure = new BlockIteratorClosure() { + + @Override + protected VoidState getInitialState() { + return voidState; + } + + @Override + protected VoidState processBlock(Block block, VoidState currentState) { + // remember the visit order + blocks.add(block); + return currentState; + } + + @Override + protected VoidState merge(Block merge, List states) { + return voidState; + } + + @Override + protected VoidState cloneState(VoidState oldState) { + return voidState; + } + + @Override + protected List processLoop(Loop loop, VoidState initialState) { + return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates; + } + }; + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, false); + ReentrantBlockIterator.apply(closure, cfg.getStartBlock()); + // schedule for IGV + new SchedulePhase().apply(graph); + return blocks; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java 2016-12-07 13:48:32.088923087 -0800 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; + +import org.junit.Test; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.loop.LoopEx; +import org.graalvm.compiler.loop.LoopsData; +import org.graalvm.compiler.nodes.FieldLocationIdentity; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.memory.Access; + +import jdk.vm.ci.meta.ResolvedJavaField; + +public class ReferenceGetLoopTest extends GraalCompilerTest { + + @Override + protected boolean checkMidTierGraph(StructuredGraph graph) { + final LoopsData loops = new LoopsData(graph); + boolean found = false; + for (LoopEx loop : loops.loops()) { + for (Node node : loop.inside().nodes()) { + if (node instanceof Access) { + Access access = (Access) node; + LocationIdentity location = access.getLocationIdentity(); + if (location instanceof FieldLocationIdentity) { + ResolvedJavaField field = ((FieldLocationIdentity) location).getField(); + if (field.getName().equals("referent") && field.getDeclaringClass().equals(getMetaAccess().lookupJavaType(Reference.class))) { + found = true; + } + } + } + } + } + if (!found) { + assertTrue(false, "Reference.referent not found in loop: " + getCanonicalGraphString(graph, true, false)); + } + return true; + } + + public volatile Object referent; + public final FinalWeakReference ref; + public final ReferenceQueue refQueue; + + /* + * Ensure that the Reference.get invoke is statically bindable. + */ + public static final class FinalWeakReference extends WeakReference { + public FinalWeakReference(T referent, ReferenceQueue q) { + super(referent, q); + } + } + + public ReferenceGetLoopTest() { + referent = new Object(); + refQueue = new ReferenceQueue<>(); + ref = new FinalWeakReference<>(referent, refQueue); + } + + @Test + public void test() { + getCode(getMetaAccess().lookupJavaMethod(getMethod("testSnippet"))); + } + + public void testSnippet() { + while (ref.get() != null) { + // burn! + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java 2016-12-07 13:48:32.353934736 -0800 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/** + * In the following tests, the scalar type system of the compiler should be complete enough to see + * the relation between the different conditions. + */ +public class ScalarTypeSystemTest extends GraalCompilerTest { + + public static int referenceSnippet1(int a) { + if (a > 0) { + return 1; + } else { + return 2; + } + } + + @Test(expected = AssertionError.class) + public void test1() { + test("test1Snippet", "referenceSnippet1"); + } + + public static int test1Snippet(int a) { + if (a > 0) { + if (a > -1) { + return 1; + } else { + return 3; + } + } else { + return 2; + } + } + + @Test(expected = AssertionError.class) + public void test2() { + test("test2Snippet", "referenceSnippet1"); + } + + public static int test2Snippet(int a) { + if (a > 0) { + if (a == -15) { + return 3; + } else { + return 1; + } + } else { + return 2; + } + } + + @Test(expected = AssertionError.class) + public void test3() { + test("test3Snippet", "referenceSnippet2"); + } + + public static int referenceSnippet2(int a, int b) { + if (a > b) { + return 1; + } else { + return 2; + } + } + + public static int test3Snippet(int a, int b) { + if (a > b) { + if (a == b) { + return 3; + } else { + return 1; + } + } else { + return 2; + } + } + + public static int referenceSnippet3(int a, int b) { + if (a == b) { + return 1; + } else { + return 2; + } + } + + @Test(expected = AssertionError.class) + public void test6() { + test("test6Snippet", "referenceSnippet3"); + } + + public static int test6Snippet(int a, int b) { + if (a == b) { + if (a == b + 1) { + return 3; + } else { + return 1; + } + } else { + return 2; + } + } + + private void test(final String snippet, final String referenceSnippet) { + // No debug scope to reduce console noise for @Test(expected = ...) tests + StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + PhaseContext context = new PhaseContext(getProviders()); + new CanonicalizerPhase().apply(graph, context); + StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO); + assertEquals(referenceGraph, graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest.java 2016-12-07 13:48:32.618946385 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, 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.core.test; + +import java.util.List; + +import org.junit.Test; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeMap; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.LoopExitNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; + +public class SchedulingTest extends GraphScheduleTest { + + public static int testValueProxyInputsSnippet(int s) { + int i = 0; + while (true) { + i++; + int v = i - s * 2; + if (i == s) { + return v; + } + } + } + + @Test + public void testValueProxyInputs() { + StructuredGraph graph = parseEager("testValueProxyInputsSnippet", AllowAssumptions.YES); + for (FrameState fs : graph.getNodes().filter(FrameState.class).snapshot()) { + fs.replaceAtUsages(null); + GraphUtil.killWithUnusedFloatingInputs(fs); + } + SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST); + schedulePhase.apply(graph); + ScheduleResult schedule = graph.getLastSchedule(); + NodeMap nodeToBlock = schedule.getCFG().getNodeToBlock(); + assertTrue(graph.getNodes().filter(LoopExitNode.class).count() == 1); + LoopExitNode loopExit = graph.getNodes().filter(LoopExitNode.class).first(); + List list = schedule.nodesFor(nodeToBlock.get(loopExit)); + for (BinaryArithmeticNode node : graph.getNodes().filter(BinaryArithmeticNode.class)) { + if (!(node instanceof AddNode)) { + assertTrue(node.toString(), nodeToBlock.get(node) == nodeToBlock.get(loopExit)); + assertTrue(list.indexOf(node) + " < " + list.indexOf(loopExit) + ", " + node + ", " + loopExit, list.indexOf(node) < list.indexOf(loopExit)); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java 2016-12-07 13:48:32.882957991 -0800 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import java.util.List; + +import org.junit.Test; + +import org.graalvm.compiler.core.common.cfg.BlockMap; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeMap; +import org.graalvm.compiler.nodes.BeginNode; +import org.graalvm.compiler.nodes.DeoptimizingNode.DeoptDuring; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StateSplit; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase; +import org.graalvm.compiler.phases.common.GuardLoweringPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; +import org.graalvm.compiler.phases.tiers.MidTierContext; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class SchedulingTest2 extends GraphScheduleTest { + + public static int testSnippet() { + return test() + 2; + } + + public static int test() { + return 40; + } + + @Test + public void testValueProxyInputs() { + StructuredGraph graph = parseEager("testSnippet", AllowAssumptions.YES); + ReturnNode returnNode = graph.getNodes(ReturnNode.TYPE).first(); + BeginNode beginNode = graph.add(new BeginNode()); + returnNode.replaceAtPredecessor(beginNode); + beginNode.setNext(returnNode); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST); + schedulePhase.apply(graph); + ScheduleResult schedule = graph.getLastSchedule(); + BlockMap> blockToNodesMap = schedule.getBlockToNodesMap(); + NodeMap nodeToBlock = schedule.getNodeToBlockMap(); + assertDeepEquals(2, schedule.getCFG().getBlocks().length); + for (BinaryArithmeticNode node : graph.getNodes().filter(BinaryArithmeticNode.class)) { + if (node instanceof AddNode) { + assertTrue(node.toString() + " expected: " + nodeToBlock.get(beginNode) + " but was: " + nodeToBlock.get(node), nodeToBlock.get(node) != nodeToBlock.get(beginNode)); + } + } + + for (FrameState fs : graph.getNodes(FrameState.TYPE)) { + Block block = nodeToBlock.get(fs); + assertTrue(fs.toString(), block == schedule.getCFG().getStartBlock()); + for (Node usage : fs.usages()) { + if (usage instanceof StateSplit && ((StateSplit) usage).stateAfter() == fs) { + assertTrue(usage.toString(), nodeToBlock.get(usage) == block); + if (usage != block.getBeginNode()) { + List map = blockToNodesMap.get(block); + assertTrue(map.indexOf(fs) + " < " + map.indexOf(usage), map.indexOf(fs) < map.indexOf(usage)); + } + } + } + } + + PhaseContext context = new PhaseContext(getProviders()); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context); + MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); + + new GuardLoweringPhase().apply(graph, midContext); + FrameStateAssignmentPhase phase = new FrameStateAssignmentPhase(); + phase.apply(graph); + + schedulePhase.apply(graph); + schedule = graph.getLastSchedule(); + blockToNodesMap = schedule.getBlockToNodesMap(); + nodeToBlock = schedule.getNodeToBlockMap(); + for (FrameState fs : graph.getNodes(FrameState.TYPE)) { + Block block = nodeToBlock.get(fs); + assertTrue(fs.toString(), block == schedule.getCFG().getStartBlock()); + for (Node usage : fs.usages()) { + if ((usage instanceof StateSplit && ((StateSplit) usage).stateAfter() == fs) || (usage instanceof DeoptDuring && ((DeoptDuring) usage).stateDuring() == fs)) { + assertTrue(usage.toString(), nodeToBlock.get(usage) == block); + if (usage != block.getBeginNode()) { + List map = blockToNodesMap.get(block); + assertTrue(map.indexOf(fs) + " < " + map.indexOf(usage), map.indexOf(fs) < map.indexOf(usage)); + } + } + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ShortCircuitNodeTest.java 2016-12-07 13:48:33.146969596 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.core.test.ea.EATestBase.TestClassInt; + +public class ShortCircuitNodeTest extends GraalCompilerTest { + + @Test + public void test1() { + // only executeActual, to avoid creating profiling information + executeActual(getResolvedJavaMethod("test1Snippet"), 1, 2); + } + + public static final TestClassInt field = null; + public static TestClassInt field2 = null; + + @SuppressWarnings("unused") + public static void test1Snippet(int a, int b) { + /* + * if a ShortCircuitOrNode is created for the check inside test2, then faulty handling of + * guards can create a cycle in the graph. + */ + int v; + if (a == 1) { + if (b != 1) { + int i = field.x; + } + field2 = null; + v = 0; + } else { + v = 1; + } + + if (test2(v, b)) { + int i = field.x; + } + } + + public static boolean test2(int a, int b) { + return a != 0 || b != 1; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java 2016-12-07 13:48:33.411981245 -0800 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2012, 2012, 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.core.test; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.BeginNode; +import org.graalvm.compiler.nodes.EndNode; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.MergeNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; + +public class SimpleCFGTest extends GraalCompilerTest { + + private static void dumpGraph(final StructuredGraph graph) { + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + } + + @Test + public void testImplies() { + StructuredGraph graph = new StructuredGraph(AllowAssumptions.YES, INVALID_COMPILATION_ID); + + EndNode trueEnd = graph.add(new EndNode()); + EndNode falseEnd = graph.add(new EndNode()); + + AbstractBeginNode trueBegin = graph.add(new BeginNode()); + trueBegin.setNext(trueEnd); + AbstractBeginNode falseBegin = graph.add(new BeginNode()); + falseBegin.setNext(falseEnd); + + IfNode ifNode = graph.add(new IfNode(null, trueBegin, falseBegin, 0.5)); + graph.start().setNext(ifNode); + + AbstractMergeNode merge = graph.add(new MergeNode()); + merge.addForwardEnd(trueEnd); + merge.addForwardEnd(falseEnd); + ReturnNode returnNode = graph.add(new ReturnNode(null)); + merge.setNext(returnNode); + + dumpGraph(graph); + + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); + + Block[] blocks = cfg.getBlocks(); + // check number of blocks + assertDeepEquals(4, blocks.length); + + // check block - node assignment + assertDeepEquals(blocks[0], cfg.blockFor(graph.start())); + assertDeepEquals(blocks[0], cfg.blockFor(ifNode)); + assertDeepEquals(blocks[1], cfg.blockFor(trueBegin)); + assertDeepEquals(blocks[1], cfg.blockFor(trueEnd)); + assertDeepEquals(blocks[2], cfg.blockFor(falseBegin)); + assertDeepEquals(blocks[2], cfg.blockFor(falseEnd)); + assertDeepEquals(blocks[3], cfg.blockFor(merge)); + assertDeepEquals(blocks[3], cfg.blockFor(returnNode)); + + // check dominators + assertDominator(blocks[0], null); + assertDominator(blocks[1], blocks[0]); + assertDominator(blocks[2], blocks[0]); + assertDominator(blocks[3], blocks[0]); + + // check dominated + assertDominatedSize(blocks[0], 3); + assertDominatedSize(blocks[1], 0); + assertDominatedSize(blocks[2], 0); + assertDominatedSize(blocks[3], 0); + + // check postdominators + assertPostdominator(blocks[0], blocks[3]); + assertPostdominator(blocks[1], blocks[3]); + assertPostdominator(blocks[2], blocks[3]); + assertPostdominator(blocks[3], null); + } + + public static void assertDominator(Block block, Block expectedDominator) { + Assert.assertEquals("dominator of " + block, expectedDominator, block.getDominator()); + } + + public static void assertDominatedSize(Block block, int size) { + Assert.assertEquals("number of dominated blocks of " + block, size, block.getDominated().size()); + } + + public static void assertPostdominator(Block block, Block expectedPostdominator) { + Assert.assertEquals("postdominator of " + block, expectedPostdominator, block.getPostdominator()); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampCanonicalizerTest.java 2016-12-07 13:48:33.676992894 -0800 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2012, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/** + * This class tests some specific patterns the stamp system should be able to canonicalize away + * using {@link IntegerStamp#upMask()}. + */ +public class StampCanonicalizerTest extends GraalCompilerTest { + + public static int andStamp(int a, int b) { + int v = (a & 0xffff00) & (b & 0xff0000f); + return v & 1; + } + + @Test + public void testAnd() { + testZeroReturn("andStamp"); + } + + public static int shiftLeftStamp1(int a) { + int v = a << 1; + return v & 1; + } + + public static int shiftLeftStamp2(int a) { + int v = a << 1; + if (a == 17) { + v = a * 4; + } + return v & 1; + } + + @Test + public void testShift() { + testZeroReturn("shiftLeftStamp1"); + testZeroReturn("shiftLeftStamp2"); + } + + public static int upperBoundShiftStamp1(int a) { + int v = a & 0xffff; + return (v << 4) & 0xff00000; + } + + public static int upperBoundShiftStamp2(int a) { + int v = a & 0xffff; + return (v >> 4) & 0xf000; + } + + @Test + public void testUpperBoundShift() { + testZeroReturn("upperBoundShiftStamp1"); + testZeroReturn("upperBoundShiftStamp2"); + } + + public static int divStamp1(int[] a) { + int v = a.length / 4; + return v & 0x80000000; + } + + public static int divStamp2(int[] a) { + int v = a.length / 5; + return v & 0x80000000; + } + + @Test + public void testDiv() { + testZeroReturn("divStamp1"); + testZeroReturn("divStamp2"); + } + + public static int distinctMask(int a, int b) { + int x = a & 0xaaaa; + int y = (b & 0x5555) | 0x1; + return x == y ? 1 : 0; + } + + @Test + public void testDistinctMask() { + testZeroReturn("distinctMask"); + } + + private void testZeroReturn(String methodName) { + StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + new DeadCodeEliminationPhase().apply(graph); + assertConstantReturn(graph, 0); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java 2016-12-07 13:48:33.942004543 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015, 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.core.test; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; +import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.INTERCEPT; + +import java.lang.reflect.Method; + +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Assume; +import org.junit.Test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugConfigScope; +import org.graalvm.compiler.debug.DelegatingDebugConfig; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.VerifyPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.runtime.RuntimeProvider; +import org.graalvm.compiler.test.GraalTest; + +/** + * Test that interfaces are correctly initialized by a static field resolution during eager graph + * building. + */ +public class StaticInterfaceFieldTest extends GraalTest { + + private interface I { + Object CONST = new Object() { + }; + + } + + private static final class C implements I { + @SuppressWarnings({"static-method", "unused"}) + public Object test() { + return CONST; + } + } + + @Test + public void test() { + eagerlyParseMethod(C.class, "test"); + + } + + @SuppressWarnings("try") + private void eagerlyParseMethod(Class clazz, String methodName) { + RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class); + Providers providers = rt.getHostBackend().getProviders(); + MetaAccessProvider metaAccess = providers.getMetaAccess(); + + PhaseSuite graphBuilderSuite = new PhaseSuite<>(); + Plugins plugins = new Plugins(new InvocationPlugins(metaAccess)); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); + + Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus()); + + final Method m = getMethod(clazz, methodName); + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID); + try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("GraphBuilding", graph, method)) { + graphBuilderSuite.apply(graph, context); + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java 2016-12-07 13:48:34.205016104 -0800 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class StraighteningTest extends GraalCompilerTest { + + private static final String REFERENCE_SNIPPET = "ref"; + + public static boolean ref(int a, int b) { + return a == b; + } + + public static boolean test1Snippet(int a, int b) { + int c = a; + if (c == b) { + c = 0x55; + } + if (c != 0x55) { + return false; + } + return true; + } + + public static boolean test3Snippet(int a, int b) { + int val = (int) System.currentTimeMillis(); + int c = val + 1; + if (a == b) { + c = val; + } + if (c != val) { + return false; + } + return true; + } + + public static boolean test2Snippet(int a, int b) { + int c; + if (a == b) { + c = 1; + } else { + c = 0; + } + return c == 1; + } + + @Test(expected = AssertionError.class) + public void test1() { + test("test1Snippet"); + } + + public void test2() { + test("test2Snippet"); + } + + @Test(expected = AssertionError.class) + public void test3() { + test("test3Snippet"); + } + + private void test(final String snippet) { + // No debug scope to reduce console noise for @Test(expected = ...) tests + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES); + assertEquals(referenceGraph, graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java 2016-12-07 13:48:34.471027797 -0800 @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2011, 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.core.test; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodeinfo.Verbosity; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.java.InstanceOfNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/** + * In the following tests, the scalar type system of the compiler should be complete enough to see + * the relation between the different conditions. + */ +public class TypeSystemTest extends GraalCompilerTest { + + @Test + public void test3() { + test("test3Snippet", "referenceSnippet3"); + } + + public static int referenceSnippet3(Object o) { + if (o == null) { + return 1; + } else { + return 2; + } + } + + @SuppressWarnings("unused") + public static int test3Snippet(Object o) { + if (o == null) { + if (o != null) { + return 3; + } else { + return 1; + } + } else { + return 2; + } + } + + @Test + public void test4() { + test("test4Snippet", "referenceSnippet3"); + } + + @SuppressWarnings("unused") + public static int test4Snippet(Object o) { + if (o == null) { + Object o2 = Integer.class; + if (o == o2) { + return 3; + } else { + return 1; + } + } else { + return 2; + } + } + + @Test + @Ignore + public void test5() { + test("test5Snippet", "referenceSnippet5"); + } + + public static int referenceSnippet5(Object o, Object a) { + if (o == null) { + if (a == Integer.class) { + return 1; + } + } else { + if (a == Double.class) { + return 11; + } + } + if (a == Integer.class) { + return 3; + } + return 5; + } + + @SuppressWarnings("unused") + public static int test5Snippet(Object o, Object a) { + if (o == null) { + if (a == Integer.class) { + if (a == null) { + return 10; + } + return 1; + } + } else { + if (a == Double.class) { + if (a != null) { + return 11; + } + return 2; + } + } + if (a == Integer.class) { + return 3; + } + return 5; + } + + @Test + public void test6() { + testHelper("test6Snippet", InstanceOfNode.class); + } + + public static int test6Snippet(int i) throws IOException { + Object o = null; + + if (i == 5) { + o = new FileInputStream("asdf"); + } + if (i < 10) { + o = new ByteArrayInputStream(new byte[]{1, 2, 3}); + } + if (i > 0) { + o = new BufferedInputStream(null); + } + + return ((InputStream) o).available(); + } + + @Test + public void test7() { + test("test7Snippet", "referenceSnippet7"); + } + + public static int test7Snippet(int x) { + return ((x & 0xff) << 10) == ((x & 0x1f) + 1) ? 0 : x; + } + + public static int referenceSnippet7(int x) { + return x; + } + + private void test(String snippet, String referenceSnippet) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + /* + * When using FlowSensitiveReductionPhase instead of ConditionalEliminationPhase, + * tail-duplication gets activated thus resulting in a graph with more nodes than the + * reference graph. + */ + new DominatorConditionalEliminationPhase(false).apply(graph, new PhaseContext(getProviders())); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + // a second canonicalizer is needed to process nested MaterializeNodes + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO); + new DominatorConditionalEliminationPhase(false).apply(referenceGraph, new PhaseContext(getProviders())); + new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders())); + new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders())); + assertEquals(referenceGraph, graph); + } + + @Override + protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { + if (getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(graph)) { + Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "expected (node count)"); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "graph (node count)"); + Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount()); + } + } + + public static void outputGraph(StructuredGraph graph, String message) { + TTY.println("========================= " + message); + SchedulePhase schedulePhase = new SchedulePhase(); + schedulePhase.apply(graph); + ScheduleResult schedule = graph.getLastSchedule(); + for (Block block : schedule.getCFG().getBlocks()) { + TTY.print("Block " + block + " "); + if (block == schedule.getCFG().getStartBlock()) { + TTY.print("* "); + } + TTY.print("-> "); + for (Block succ : block.getSuccessors()) { + TTY.print(succ + " "); + } + TTY.println(); + for (Node node : schedule.getBlockToNodesMap().get(block)) { + outputNode(node); + } + } + } + + private static void outputNode(Node node) { + TTY.print(" " + node + " (usage count: " + node.getUsageCount() + ") (inputs:"); + for (Node input : node.inputs()) { + TTY.print(" " + input.toString(Verbosity.Id)); + } + TTY.println(")"); + if (node instanceof AbstractMergeNode) { + for (PhiNode phi : ((AbstractMergeNode) node).phis()) { + outputNode(phi); + } + } + } + + private void testHelper(String snippet, Class clazz) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph " + snippet); + Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes().filter(clazz).iterator().hasNext()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeWriterTest.java 2016-12-07 13:48:34.736039446 -0800 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.core.common.util.TypeConversion; +import org.graalvm.compiler.core.common.util.TypeReader; +import org.graalvm.compiler.core.common.util.TypeWriter; +import org.graalvm.compiler.core.common.util.UnsafeArrayTypeReader; +import org.graalvm.compiler.core.common.util.UnsafeArrayTypeWriter; + +public class TypeWriterTest extends GraalCompilerTest { + + private static void putValue(TypeWriter writer, long value) { + if (TypeConversion.isS1(value)) { + writer.putS1(value); + } + if (TypeConversion.isU1(value)) { + writer.putU1(value); + } + if (TypeConversion.isS2(value)) { + writer.putS2(value); + } + if (TypeConversion.isU2(value)) { + writer.putU2(value); + } + if (TypeConversion.isS4(value)) { + writer.putS4(value); + } + if (TypeConversion.isU4(value)) { + writer.putU4(value); + } + writer.putS8(value); + writer.putSV(value); + if (value >= 0) { + writer.putUV(value); + } + } + + private static void checkValue(TypeReader reader, long value) { + if (TypeConversion.isS1(value)) { + Assert.assertEquals(value, reader.getS1()); + } + if (TypeConversion.isU1(value)) { + Assert.assertEquals(value, reader.getU1()); + } + if (TypeConversion.isS2(value)) { + Assert.assertEquals(value, reader.getS2()); + } + if (TypeConversion.isU2(value)) { + Assert.assertEquals(value, reader.getU2()); + } + if (TypeConversion.isS4(value)) { + Assert.assertEquals(value, reader.getS4()); + } + if (TypeConversion.isU4(value)) { + Assert.assertEquals(value, reader.getU4()); + } + Assert.assertEquals(value, reader.getS8()); + Assert.assertEquals(value, reader.getSV()); + if (value >= 0) { + Assert.assertEquals(value, reader.getUV()); + } + } + + private static void putValues(TypeWriter writer) { + for (int i = 0; i < 64; i++) { + long value = 1L << i; + putValue(writer, value - 2); + putValue(writer, value - 1); + putValue(writer, value); + putValue(writer, value + 1); + putValue(writer, value + 2); + + putValue(writer, -value - 2); + putValue(writer, -value - 1); + putValue(writer, -value); + putValue(writer, -value + 1); + putValue(writer, -value + 2); + } + } + + private static void checkValues(TypeReader reader) { + for (int i = 0; i < 64; i++) { + long value = 1L << i; + checkValue(reader, value - 2); + checkValue(reader, value - 1); + checkValue(reader, value); + checkValue(reader, value + 1); + checkValue(reader, value + 2); + + checkValue(reader, -value - 2); + checkValue(reader, -value - 1); + checkValue(reader, -value); + checkValue(reader, -value + 1); + checkValue(reader, -value + 2); + } + } + + private static void test01(boolean supportsUnalignedMemoryAccess) { + UnsafeArrayTypeWriter writer = UnsafeArrayTypeWriter.create(supportsUnalignedMemoryAccess); + putValues(writer); + + byte[] array = new byte[(int) writer.getBytesWritten()]; + writer.toArray(array); + UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(array, 0, supportsUnalignedMemoryAccess); + checkValues(reader); + } + + @Test + public void test01a() { + test01(getTarget().arch.supportsUnalignedMemoryAccess()); + } + + @Test + public void test01b() { + test01(false); + } + + private static void checkSignedSize(TypeWriter writer, long value, int expectedSize) { + long sizeBefore = writer.getBytesWritten(); + writer.putSV(value); + Assert.assertEquals(expectedSize, writer.getBytesWritten() - sizeBefore); + } + + private static void checkUnsignedSize(TypeWriter writer, long value, int expectedSize) { + long sizeBefore = writer.getBytesWritten(); + writer.putUV(value); + Assert.assertEquals(expectedSize, writer.getBytesWritten() - sizeBefore); + } + + private static void checkSizes(TypeWriter writer) { + checkSignedSize(writer, 0, 1); + checkSignedSize(writer, 63, 1); + checkSignedSize(writer, -64, 1); + checkSignedSize(writer, 64, 2); + checkSignedSize(writer, -65, 2); + checkSignedSize(writer, 8191, 2); + checkSignedSize(writer, -8192, 2); + checkSignedSize(writer, 8192, 3); + checkSignedSize(writer, -8193, 3); + checkSignedSize(writer, Long.MAX_VALUE, 10); + checkSignedSize(writer, Long.MIN_VALUE, 10); + + checkUnsignedSize(writer, 0, 1); + checkUnsignedSize(writer, 127, 1); + checkUnsignedSize(writer, 128, 2); + checkUnsignedSize(writer, 16383, 2); + checkUnsignedSize(writer, 16384, 3); + checkUnsignedSize(writer, Long.MAX_VALUE, 9); + } + + @Test + public void test02a() { + checkSizes(UnsafeArrayTypeWriter.create(getTarget().arch.supportsUnalignedMemoryAccess())); + } + + @Test + public void test02b() { + checkSizes(UnsafeArrayTypeWriter.create(false)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java 2016-12-07 13:48:35.002051140 -0800 @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test; + +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; + +import org.junit.Test; + +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.phases.OptimisticOptimizations; + +/** + * Exercise handling of unbalanced monitor operations by the parser. Algorithmically Graal assumes + * that locks are statically block structured but that isn't something enforced by the bytecodes. In + * HotSpot a dataflow is performed to ensure they are properly structured and methods with + * unstructured locking aren't compiled and fall back to the interpreter. Having the Graal parser + * handle this directly is simplifying for targets of Graal since they don't have to provide a data + * flow that checks this property. + */ +public class UnbalancedMonitorsTest extends GraalCompilerTest implements Opcodes { + private static final String CLASS_NAME = UnbalancedMonitorsTest.class.getName(); + private static final String INNER_CLASS_NAME = CLASS_NAME + "$UnbalancedMonitors"; + private static final String CLASS_NAME_INTERNAL = CLASS_NAME.replace('.', '/'); + private static final String INNER_CLASS_NAME_INTERNAL = INNER_CLASS_NAME.replace('.', '/'); + + private static AsmLoader LOADER = new AsmLoader(UnbalancedMonitorsTest.class.getClassLoader()); + + @Test + public void runWrongOrder() throws Exception { + checkForBailout("wrongOrder"); + } + + @Test + public void runTooFewExits() throws Exception { + checkForBailout("tooFewExits"); + } + + @Test + public void runTooManyExits() throws Exception { + checkForBailout("tooManyExits"); + } + + @Test + public void runTooFewExitsExceptional() throws Exception { + checkForBailout("tooFewExitsExceptional"); + } + + @Test + public void runTooManyExitsExceptional() throws Exception { + checkForBailout("tooManyExitsExceptional"); + } + + private void checkForBailout(String name) throws ClassNotFoundException { + ResolvedJavaMethod method = getResolvedJavaMethod(LOADER.findClass(INNER_CLASS_NAME), name); + try { + StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID); + Plugins plugins = new Plugins(new InvocationPlugins(getMetaAccess())); + GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE; + + GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), null, null, graphBuilderConfig, optimisticOpts, null); + graphBuilder.apply(graph); + } catch (BailoutException e) { + if (e.getMessage().contains("unbalanced monitors")) { + return; + } + throw e; + } + assertTrue("should have bailed out", false); + } + + // @formatter:off + // Template class used with Bytecode Outline to generate ASM code + // public static class UnbalancedMonitors { + // + // public UnbalancedMonitors() { + // } + // + // public Object wrongOrder(Object a, Object b) { + // synchronized (a) { + // synchronized (b) { + // return b; + // } + // } + // } + // + // public Object tooFewExits(Object a, Object b) { + // synchronized (a) { + // synchronized (b) { + // return b; + // } + // } + // } + // + // public boolean tooFewExitsExceptional(Object a, Object b) { + // synchronized (a) { + // synchronized (b) { + // return b.equals(a); + // } + // } + // } + // } + // @formatter:on + + public static byte[] generateClass() { + + ClassWriter cw = new ClassWriter(0); + + cw.visit(52, ACC_SUPER | ACC_PUBLIC, INNER_CLASS_NAME_INTERNAL, null, "java/lang/Object", null); + + cw.visitSource("UnbalancedMonitorsTest.java", null); + + cw.visitInnerClass(INNER_CLASS_NAME_INTERNAL, CLASS_NAME_INTERNAL, "UnbalancedMonitors", ACC_STATIC); + + visitConstructor(cw); + visitWrongOrder(cw); + visitBlockStructured(cw, true, false); + visitBlockStructured(cw, true, true); + visitBlockStructured(cw, false, false); + visitBlockStructured(cw, false, true); + cw.visitEnd(); + + return cw.toByteArray(); + } + + private static void visitBlockStructured(ClassWriter cw, boolean normalReturnError, boolean tooMany) { + String name = (tooMany ? "tooMany" : "tooFew") + "Exits" + (normalReturnError ? "" : "Exceptional"); + // Generate too many or too few exits down the either the normal or exceptional return paths + int exceptionalExitCount = normalReturnError ? 1 : (tooMany ? 2 : 0); + int normalExitCount = normalReturnError ? (tooMany ? 2 : 0) : 1; + MethodVisitor mv; + mv = cw.visitMethod(ACC_PUBLIC, name, "(Ljava/lang/Object;Ljava/lang/Object;)Z", null, null); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, null); + Label l3 = new Label(); + mv.visitTryCatchBlock(l2, l3, l2, null); + Label l4 = new Label(); + Label l5 = new Label(); + Label l6 = new Label(); + mv.visitTryCatchBlock(l4, l5, l6, null); + Label l7 = new Label(); + mv.visitTryCatchBlock(l2, l7, l6, null); + Label l8 = new Label(); + mv.visitLabel(l8); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, 3); + mv.visitInsn(MONITORENTER); + mv.visitLabel(l4); + mv.visitVarInsn(ALOAD, 2); + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, 4); + mv.visitInsn(MONITORENTER); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false); + mv.visitVarInsn(ALOAD, 4); + mv.visitInsn(MONITOREXIT); + mv.visitLabel(l1); + for (int i = 0; i < normalExitCount; i++) { + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(MONITOREXIT); + } + mv.visitLabel(l5); + mv.visitInsn(IRETURN); + mv.visitLabel(l2); + mv.visitFrame(Opcodes.F_FULL, 5, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object", + "java/lang/Object"}, 1, new Object[]{"java/lang/Throwable"}); + mv.visitVarInsn(ALOAD, 4); + mv.visitInsn(MONITOREXIT); + mv.visitLabel(l3); + mv.visitInsn(ATHROW); + mv.visitLabel(l6); + mv.visitFrame(Opcodes.F_FULL, 4, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object"}, 1, + new Object[]{"java/lang/Throwable"}); + for (int i = 0; i < exceptionalExitCount; i++) { + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(MONITOREXIT); + } + mv.visitLabel(l7); + mv.visitInsn(ATHROW); + Label l9 = new Label(); + mv.visitLabel(l9); + mv.visitMaxs(2, 5); + mv.visitEnd(); + } + + private static void visitWrongOrder(ClassWriter cw) { + MethodVisitor mv; + mv = cw.visitMethod(ACC_PUBLIC, "wrongOrder", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, null); + Label l3 = new Label(); + mv.visitTryCatchBlock(l2, l3, l2, null); + Label l4 = new Label(); + Label l5 = new Label(); + Label l6 = new Label(); + mv.visitTryCatchBlock(l4, l5, l6, null); + Label l7 = new Label(); + mv.visitTryCatchBlock(l2, l7, l6, null); + Label l8 = new Label(); + mv.visitLabel(l8); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, 3); + mv.visitInsn(MONITORENTER); + mv.visitLabel(l4); + mv.visitVarInsn(ALOAD, 2); + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, 4); + mv.visitInsn(MONITORENTER); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(MONITOREXIT); + mv.visitLabel(l1); + // Swapped exit order with exit above + mv.visitVarInsn(ALOAD, 4); + mv.visitInsn(MONITOREXIT); + mv.visitLabel(l5); + mv.visitInsn(ARETURN); + mv.visitLabel(l2); + mv.visitFrame(Opcodes.F_FULL, 5, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object", + "java/lang/Object"}, 1, new Object[]{"java/lang/Throwable"}); + mv.visitVarInsn(ALOAD, 4); + mv.visitInsn(MONITOREXIT); + mv.visitLabel(l3); + mv.visitInsn(ATHROW); + mv.visitLabel(l6); + mv.visitFrame(Opcodes.F_FULL, 4, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object"}, 1, + new Object[]{"java/lang/Throwable"}); + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(MONITOREXIT); + mv.visitLabel(l7); + mv.visitInsn(ATHROW); + Label l9 = new Label(); + mv.visitLabel(l9); + mv.visitMaxs(2, 5); + mv.visitEnd(); + } + + private static void visitConstructor(ClassWriter cw) { + MethodVisitor mv; + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitInsn(RETURN); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + public static class AsmLoader extends ClassLoader { + Class loaded; + + public AsmLoader(ClassLoader parent) { + super(parent); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals(INNER_CLASS_NAME)) { + if (loaded != null) { + return loaded; + } + byte[] bytes = generateClass(); + return (loaded = defineClass(name, bytes, 0, bytes.length)); + } else { + return super.findClass(name); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java 2016-12-07 13:48:35.267062789 -0800 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import java.lang.reflect.Field; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.extended.UnsafeAccessNode; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.WriteNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; +import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase; +import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; + +import sun.misc.Unsafe; + +public class UnsafeReadEliminationTest extends GraalCompilerTest { + + public static final Unsafe UNSAFE; + static { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + UNSAFE = (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("Exception while trying to get Unsafe", e); + } + } + + public static long[] Memory = new long[]{1, 2}; + public static double SideEffectD; + public static double SideEffectL; + + public static long test1Snippet(double a) { + final Object m = Memory; + if (a > 0) { + UNSAFE.putDouble(m, (long) Unsafe.ARRAY_LONG_BASE_OFFSET, a); + } else { + SideEffectL = UNSAFE.getLong(m, (long) Unsafe.ARRAY_LONG_BASE_OFFSET); + } + return UNSAFE.getLong(m, (long) Unsafe.ARRAY_LONG_BASE_OFFSET); + } + + public static class A { + long[][] o; + long[][] p; + } + + public static Object test2Snippet(A a, int c) { + Object phi = null; + if (c != 0) { + long[][] r = a.o; + phi = r; + UNSAFE.putDouble(r, (long) Unsafe.ARRAY_LONG_BASE_OFFSET, 12d); + } else { + long[][] r = a.p; + phi = r; + UNSAFE.putLong(r, (long) Unsafe.ARRAY_LONG_BASE_OFFSET, 123); + } + GraalDirectives.controlFlowAnchor(); + SideEffectD = UNSAFE.getDouble(phi, (long) Unsafe.ARRAY_LONG_BASE_OFFSET); + return phi; + } + + @Test + public void test01() { + StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.NO); + testEarlyReadElimination(graph, 3, 2); + } + + @Test + public void test02() { + StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.NO); + testPartialEscapeReadElimination(graph, 3, 2); + } + + @Test + public void test03() { + StructuredGraph graph = parseEager("test2Snippet", AllowAssumptions.NO); + testEarlyReadElimination(graph, 3, 3); + } + + @Test + public void test04() { + StructuredGraph graph = parseEager("test2Snippet", AllowAssumptions.NO); + testEarlyReadElimination(graph, 3, 3); + } + + public void testEarlyReadElimination(StructuredGraph graph, int reads, int writes) { + PhaseContext context = getDefaultHighTierContext(); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + canonicalizer.apply(graph, context); + new EarlyReadEliminationPhase(canonicalizer).apply(graph, context); + Assert.assertEquals(3, graph.getNodes().filter(UnsafeAccessNode.class).count()); + // after lowering the same applies for reads and writes + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + canonicalizer.apply(graph, context); + new EarlyReadEliminationPhase(canonicalizer).apply(graph, context); + Assert.assertEquals(reads, graph.getNodes().filter(ReadNode.class).count()); + Assert.assertEquals(writes, graph.getNodes().filter(WriteNode.class).count()); + } + + public void testPartialEscapeReadElimination(StructuredGraph graph, int reads, int writes) { + PhaseContext context = getDefaultHighTierContext(); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + canonicalizer.apply(graph, context); + new PartialEscapePhase(true, true, canonicalizer, null).apply(graph, context); + Assert.assertEquals(3, graph.getNodes().filter(UnsafeAccessNode.class).count()); + // after lowering the same applies for reads and writes + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + canonicalizer.apply(graph, context); + new PartialEscapePhase(true, true, canonicalizer, null).apply(graph, context); + Assert.assertEquals(reads, graph.getNodes().filter(ReadNode.class).count()); + Assert.assertEquals(writes, graph.getNodes().filter(WriteNode.class).count()); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java 2016-12-07 13:48:35.532074438 -0800 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2016, 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.core.test; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.junit.Test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.common.RetryableBailoutException; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugConfigScope; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.Phase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.VerifyPhase.VerificationError; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.phases.verify.VerifyBailoutUsage; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class VerifyBailoutUsageTest { + + private static class InvalidBailoutUsagePhase1 extends Phase { + @Override + protected void run(StructuredGraph graph) { + throw new BailoutException("Bailout in graph %s", graph); + } + } + + private static class InvalidBailoutUsagePhase2 extends Phase { + @Override + protected void run(StructuredGraph graph) { + throw new BailoutException(new GraalError("other cause"), "Bailout in graph %s", graph); + } + } + + private static class InvalidBailoutUsagePhase3 extends Phase { + @Override + protected void run(StructuredGraph graph) { + throw new BailoutException(true/* permanent */, "Bailout in graph %s", graph); + } + } + + private static class ValidPermanentBailoutUsage extends Phase { + @Override + protected void run(StructuredGraph graph) { + throw new PermanentBailoutException("Valid permanent bailout %s", graph); + } + } + + private static class ValidRetryableBailoutUsage extends Phase { + @Override + protected void run(StructuredGraph graph) { + throw new RetryableBailoutException("Valid retryable bailout %s", graph); + } + } + + @Test(expected = VerificationError.class) + public void testInvalidBailout01() { + testBailoutUsage(InvalidBailoutUsagePhase1.class); + } + + @Test(expected = VerificationError.class) + public void testInvalidBailout02() { + testBailoutUsage(InvalidBailoutUsagePhase2.class); + } + + @Test(expected = VerificationError.class) + public void testInvalidBailout03() { + testBailoutUsage(InvalidBailoutUsagePhase3.class); + } + + @Test + public void testValidPermanentBailout() { + testBailoutUsage(ValidPermanentBailoutUsage.class); + } + + @Test + public void testValidRetryableBailout() { + testBailoutUsage(ValidRetryableBailoutUsage.class); + } + + @SuppressWarnings("try") + private static void testBailoutUsage(Class c) { + RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class); + Providers providers = rt.getHostBackend().getProviders(); + MetaAccessProvider metaAccess = providers.getMetaAccess(); + PhaseSuite graphBuilderSuite = new PhaseSuite<>(); + Plugins plugins = new Plugins(new InvocationPlugins(metaAccess)); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); + for (Method m : c.getDeclaredMethods()) { + if (!Modifier.isNative(m.getModifiers()) && !Modifier.isAbstract(m.getModifiers())) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID); + graphBuilderSuite.apply(graph, context); + try (DebugConfigScope s = Debug.disableIntercept()) { + new VerifyBailoutUsage().apply(graph, context); + } + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java 2016-12-07 13:48:35.796086043 -0800 @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.junit.Test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugConfigScope; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.Indent; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.Phase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.VerifyPhase.VerificationError; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.phases.verify.VerifyDebugUsage; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class VerifyDebugUsageTest { + + private static class InvalidLogUsagePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + for (Node n : graph.getNodes()) { + Debug.log("%s", n.toString()); + } + } + + } + + private static class InvalidLogAndIndentUsagePhase extends Phase { + + @Override + @SuppressWarnings("try") + protected void run(StructuredGraph graph) { + try (Indent i = Debug.logAndIndent("%s", graph.toString())) { + for (Node n : graph.getNodes()) { + Debug.log("%s", n); + } + } + } + + } + + private static class InvalidDumpUsagePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", graph.toString()); + } + + } + + private static class InvalidVerifyUsagePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + Debug.verify(graph, "%s", graph.toString()); + } + + } + + private static class InvalidConcatLogUsagePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + for (Node n : graph.getNodes()) { + Debug.log("error " + n); + } + } + + } + + private static class InvalidConcatLogAndIndentUsagePhase extends Phase { + + @Override + @SuppressWarnings("try") + protected void run(StructuredGraph graph) { + try (Indent i = Debug.logAndIndent("error " + graph)) { + for (Node n : graph.getNodes()) { + Debug.log("%s", n); + } + } + } + + } + + private static class InvalidConcatDumpUsagePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "error " + graph); + } + + } + + private static class InvalidConcatVerifyUsagePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + Debug.verify(graph, "error " + graph); + } + + } + + private static class ValidLogUsagePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + for (Node n : graph.getNodes()) { + Debug.log("%s", n); + } + } + + } + + private static class ValidLogAndIndentUsagePhase extends Phase { + + @Override + @SuppressWarnings("try") + protected void run(StructuredGraph graph) { + try (Indent i = Debug.logAndIndent("%s", graph)) { + for (Node n : graph.getNodes()) { + Debug.log("%s", n); + } + } + } + + } + + private static class ValidDumpUsagePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", graph); + } + + } + + private static class ValidVerifyUsagePhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + Debug.verify(graph, "%s", graph); + } + + } + + private static class InvalidGraalErrorGuaranteePhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + GraalError.guarantee(graph.getNodes().count() > 0, "Graph must contain nodes %s %s %s", graph, graph, graph, graph.toString()); + } + } + + private static class ValidGraalErrorGuaranteePhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + GraalError.guarantee(graph.getNodes().count() > 0, "Graph must contain nodes %s", graph); + } + } + + public static Object sideEffect; + + private static class InvalidGraalErrorCtorPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + sideEffect = new GraalError("No Error %s", graph.toString()); + } + } + + private static class ValidGraalErrorCtorPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + sideEffect = new GraalError("Error %s", graph); + } + } + + @Test(expected = VerificationError.class) + public void testLogInvalid() { + testDebugUsageClass(InvalidLogUsagePhase.class); + } + + @Test(expected = VerificationError.class) + public void testLogAndIndentInvalid() { + testDebugUsageClass(InvalidLogAndIndentUsagePhase.class); + } + + @Test(expected = VerificationError.class) + public void testVerifyInvalid() { + testDebugUsageClass(InvalidVerifyUsagePhase.class); + } + + @Test(expected = VerificationError.class) + public void testDumpInvalid() { + testDebugUsageClass(InvalidDumpUsagePhase.class); + } + + @Test(expected = VerificationError.class) + public void testLogInvalidConcat() { + testDebugUsageClass(InvalidConcatLogUsagePhase.class); + } + + @Test(expected = VerificationError.class) + public void testLogAndIndentInvalidConcat() { + testDebugUsageClass(InvalidConcatLogAndIndentUsagePhase.class); + } + + @Test(expected = VerificationError.class) + public void testVerifyInvalidConcat() { + testDebugUsageClass(InvalidConcatVerifyUsagePhase.class); + } + + @Test(expected = VerificationError.class) + public void testDumpInvalidConcat() { + testDebugUsageClass(InvalidConcatDumpUsagePhase.class); + } + + @Test + public void testLogValid() { + testDebugUsageClass(ValidLogUsagePhase.class); + } + + @Test() + public void testLogAndIndentValid() { + testDebugUsageClass(ValidLogAndIndentUsagePhase.class); + } + + @Test + public void testVerifyValid() { + testDebugUsageClass(ValidVerifyUsagePhase.class); + } + + @Test + public void testDumpValid() { + testDebugUsageClass(ValidDumpUsagePhase.class); + } + + @Test(expected = VerificationError.class) + public void testGraalGuaranteeInvalid() { + testDebugUsageClass(InvalidGraalErrorGuaranteePhase.class); + } + + @Test + public void testGraalGuaranteeValid() { + testDebugUsageClass(ValidGraalErrorGuaranteePhase.class); + } + + @Test(expected = VerificationError.class) + public void testGraalCtorInvalid() { + testDebugUsageClass(InvalidGraalErrorCtorPhase.class); + } + + @Test + public void testGraalCtorValid() { + testDebugUsageClass(ValidGraalErrorCtorPhase.class); + } + + @SuppressWarnings("try") + private static void testDebugUsageClass(Class c) { + RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class); + Providers providers = rt.getHostBackend().getProviders(); + MetaAccessProvider metaAccess = providers.getMetaAccess(); + PhaseSuite graphBuilderSuite = new PhaseSuite<>(); + Plugins plugins = new Plugins(new InvocationPlugins(metaAccess)); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); + for (Method m : c.getDeclaredMethods()) { + if (!Modifier.isNative(m.getModifiers()) && !Modifier.isAbstract(m.getModifiers())) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID); + graphBuilderSuite.apply(graph, context); + try (DebugConfigScope s = Debug.disableIntercept()) { + new VerifyDebugUsage().apply(graph, context); + } + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java 2016-12-07 13:48:36.061097692 -0800 @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.junit.Test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugConfigScope; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.java.ArrayLengthNode; +import org.graalvm.compiler.nodes.spi.Virtualizable; +import org.graalvm.compiler.nodes.spi.VirtualizerTool; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.VerifyPhase.VerificationError; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.phases.verify.VerifyVirtualizableUsage; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class VerifyVirtualizableTest { + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class InvalidEffectNodeAdd extends ValueNode implements Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(InvalidEffectNodeAdd.class); + + protected InvalidEffectNodeAdd() { + super(TYPE, StampFactory.forVoid()); + } + + @Override + public void virtualize(VirtualizerTool tool) { + graph().add(new ArrayLengthNode(null)); + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class InvalidEffectNodeAddWithoutUnique extends ValueNode implements Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(InvalidEffectNodeAddWithoutUnique.class); + + protected InvalidEffectNodeAddWithoutUnique() { + super(TYPE, StampFactory.forVoid()); + } + + @Override + public void virtualize(VirtualizerTool tool) { + graph().addWithoutUnique(new ArrayLengthNode(null)); + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class InvalidEffectNodeAddOrUnique extends ValueNode implements Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(InvalidEffectNodeAddOrUnique.class); + + protected InvalidEffectNodeAddOrUnique() { + super(TYPE, StampFactory.forVoid()); + } + + @Override + public void virtualize(VirtualizerTool tool) { + graph().addOrUnique(new ArrayLengthNode(null)); + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class InvalidEffectNodeAddWithoutUniqueWithInputs extends ValueNode implements Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(InvalidEffectNodeAddWithoutUniqueWithInputs.class); + + protected InvalidEffectNodeAddWithoutUniqueWithInputs() { + super(TYPE, StampFactory.forVoid()); + } + + @Override + public void virtualize(VirtualizerTool tool) { + graph().addOrUnique(new ArrayLengthNode(null)); + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class InvalidEffectNodeAddOrUniqueWithInputs extends ValueNode implements Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(InvalidEffectNodeAddOrUniqueWithInputs.class); + + protected InvalidEffectNodeAddOrUniqueWithInputs() { + super(TYPE, StampFactory.forVoid()); + } + + @Override + public void virtualize(VirtualizerTool tool) { + graph().addOrUnique(new ArrayLengthNode(null)); + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class ValidEffectNodeAdd extends ValueNode implements Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(ValidEffectNodeAdd.class); + + protected ValidEffectNodeAdd() { + super(TYPE, StampFactory.forVoid()); + } + + @Override + public void virtualize(VirtualizerTool tool) { + graph().add(ConstantNode.forBoolean(false)); + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class ValidEffectNodeAddWithoutUnique extends ValueNode implements Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(ValidEffectNodeAddWithoutUnique.class); + + protected ValidEffectNodeAddWithoutUnique() { + super(TYPE, StampFactory.forVoid()); + } + + @Override + public void virtualize(VirtualizerTool tool) { + graph().addWithoutUnique(ConstantNode.forBoolean(false)); + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class ValidEffectNodeAddOrUnique extends ValueNode implements Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(ValidEffectNodeAddOrUnique.class); + + protected ValidEffectNodeAddOrUnique() { + super(TYPE, StampFactory.forVoid()); + } + + @Override + public void virtualize(VirtualizerTool tool) { + graph().addOrUnique(ConstantNode.forBoolean(false)); + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class ValidEffectNodeAddWithoutUniqueWithInputs extends ValueNode implements Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(ValidEffectNodeAddWithoutUniqueWithInputs.class); + + protected ValidEffectNodeAddWithoutUniqueWithInputs() { + super(TYPE, StampFactory.forVoid()); + } + + @Override + public void virtualize(VirtualizerTool tool) { + graph().addOrUnique(ConstantNode.forBoolean(false)); + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class ValidEffectNodeAddOrUniqueWithInputs extends ValueNode implements Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(ValidEffectNodeAddOrUniqueWithInputs.class); + + protected ValidEffectNodeAddOrUniqueWithInputs() { + super(TYPE, StampFactory.forVoid()); + } + + @Override + public void virtualize(VirtualizerTool tool) { + graph().addOrUnique(ConstantNode.forBoolean(false)); + } + } + + @Test(expected = VerificationError.class) + public void testInvalidAdd() { + testVirtualizableEffects(InvalidEffectNodeAdd.class); + } + + @Test(expected = VerificationError.class) + public void testInvalidAddWithoutUnique() { + testVirtualizableEffects(InvalidEffectNodeAddWithoutUnique.class); + } + + @Test(expected = VerificationError.class) + public void testInvalidAddOrUnique() { + testVirtualizableEffects(InvalidEffectNodeAddOrUnique.class); + } + + @Test(expected = VerificationError.class) + public void testInvalidAddWithoutUniqueWithInputs() { + testVirtualizableEffects(InvalidEffectNodeAddWithoutUniqueWithInputs.class); + } + + @Test(expected = VerificationError.class) + public void testInvalidAddOrUniqueWithInputs() { + testVirtualizableEffects(InvalidEffectNodeAddOrUniqueWithInputs.class); + } + + @Test + public void testValidAdd() { + testVirtualizableEffects(ValidEffectNodeAdd.class); + } + + @Test + public void testValidAddWithoutUnique() { + testVirtualizableEffects(ValidEffectNodeAddWithoutUnique.class); + } + + @Test + public void testValidAddOrUnique() { + testVirtualizableEffects(ValidEffectNodeAddOrUnique.class); + } + + @Test + public void testValidAddWithoutUniqueWithInputs() { + testVirtualizableEffects(ValidEffectNodeAddWithoutUniqueWithInputs.class); + } + + @Test + public void testValidAddOrUniqueWithInputs() { + testVirtualizableEffects(ValidEffectNodeAddOrUniqueWithInputs.class); + } + + @SuppressWarnings("try") + private static void testVirtualizableEffects(Class c) { + RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class); + Providers providers = rt.getHostBackend().getProviders(); + MetaAccessProvider metaAccess = providers.getMetaAccess(); + PhaseSuite graphBuilderSuite = new PhaseSuite<>(); + Plugins plugins = new Plugins(new InvocationPlugins(metaAccess)); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); + for (Method m : c.getDeclaredMethods()) { + if (!Modifier.isNative(m.getModifiers()) && !Modifier.isAbstract(m.getModifiers())) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID); + graphBuilderSuite.apply(graph, context); + try (DebugConfigScope s = Debug.disableIntercept()) { + new VerifyVirtualizableUsage().apply(graph, context); + } + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/backend/AllocatorTest.java 2016-12-07 13:48:36.325109297 -0800 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013, 2015, 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.core.test.backend; + +import java.util.HashSet; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.meta.Value; + +import org.junit.Assert; + +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRValueUtil; +import org.graalvm.compiler.lir.StandardOp.ValueMoveOp; +import org.graalvm.compiler.lir.ValueProcedure; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +public class AllocatorTest extends BackendTest { + + @SuppressWarnings("try") + protected void testAllocation(String snippet, final int expectedRegisters, final int expectedRegRegMoves, final int expectedSpillMoves) { + final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + try (Scope s = Debug.scope("AllocatorTest", graph, graph.method(), getCodeCache())) { + final RegisterStats stats = new RegisterStats(getLIRGenerationResult(graph).getLIR()); + try (Scope s2 = Debug.scope("Assertions", stats.lir)) { + Assert.assertEquals("register count", expectedRegisters, stats.registers.size()); + Assert.assertEquals("reg-reg moves", expectedRegRegMoves, stats.regRegMoves); + Assert.assertEquals("spill moves", expectedSpillMoves, stats.spillMoves); + } catch (Throwable e) { + throw Debug.handle(e); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + private class RegisterStats { + + public final LIR lir; + public HashSet registers = new HashSet<>(); + public int regRegMoves; + public int spillMoves; + + RegisterStats(LIR lir) { + this.lir = lir; + + for (AbstractBlockBase block : lir.codeEmittingOrder()) { + if (block == null) { + continue; + } + for (LIRInstruction instr : lir.getLIRforBlock(block)) { + collectStats(instr); + } + } + } + + private ValueProcedure collectStatsProc = (value, mode, flags) -> { + if (ValueUtil.isRegister(value)) { + final Register reg = ValueUtil.asRegister(value); + registers.add(reg); + } + return value; + }; + + private void collectStats(final LIRInstruction instr) { + instr.forEachOutput(collectStatsProc); + + if (instr instanceof ValueMoveOp) { + ValueMoveOp move = (ValueMoveOp) instr; + Value def = move.getResult(); + Value use = move.getInput(); + if (ValueUtil.isRegister(def)) { + if (ValueUtil.isRegister(use)) { + regRegMoves++; + } + } else if (LIRValueUtil.isStackSlotValue(def)) { + spillMoves++; + } + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/backend/BackendTest.java 2016-12-07 13:48:36.594121122 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, 2015, 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.core.test.backend; + +import jdk.vm.ci.code.Architecture; + +import org.graalvm.compiler.core.GraalCompiler; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.phases.OptimisticOptimizations; + +public abstract class BackendTest extends GraalCompilerTest { + + public BackendTest() { + super(); + } + + public BackendTest(Class arch) { + super(arch); + } + + @SuppressWarnings("try") + protected LIRGenerationResult getLIRGenerationResult(final StructuredGraph graph) { + try (Scope s = Debug.scope("FrontEnd")) { + GraalCompiler.emitFrontEnd(getProviders(), getBackend(), graph, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE, graph.getProfilingInfo(), getSuites()); + } catch (Throwable e) { + throw Debug.handle(e); + } + + LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), graph, null, null, getLIRSuites()); + return lirGen; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest.java 2016-12-07 13:48:36.859132771 -0800 @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.debug; + +import java.io.PrintStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.stream.Collectors; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.debug.DebugConfigScope; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.DebugDumpHandler; +import org.graalvm.compiler.debug.DebugMethodMetrics; +import org.graalvm.compiler.debug.DebugTimer; +import org.graalvm.compiler.debug.DebugVerifyHandler; +import org.graalvm.compiler.debug.DelegatingDebugConfig; +import org.graalvm.compiler.debug.DelegatingDebugConfig.Feature; +import org.graalvm.compiler.debug.GraalDebugConfig; +import org.graalvm.compiler.debug.internal.DebugScope; +import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl; +import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl.CompilationData; +import org.graalvm.compiler.debug.internal.method.MethodMetricsInlineeScopeInfo; +import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.calc.BinaryNode; +import org.graalvm.compiler.nodes.calc.FixedBinaryNode; +import org.graalvm.compiler.nodes.calc.MulNode; +import org.graalvm.compiler.nodes.calc.ShiftNode; +import org.graalvm.compiler.nodes.calc.SignedDivNode; +import org.graalvm.compiler.nodes.calc.SubNode; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.Phase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.Suites; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public abstract class MethodMetricsTest extends GraalCompilerTest { + static class TestApplication { + public static int m01(int x, int y) { + return x + y; + } + + public static int m02(int x, int y) { + return x * y; + } + + public static int m03(int x, int y) { + return x ^ y; + } + + public static int m04(int x, int y) { + return x >> y; + } + + public static int m05(int x, int y) { + return x >>> y; + } + + public static int m06(int x, int y) { + return x << y; + } + + public static int m07(int x, int y) { + return x > y ? 0 : 1; + } + + public static int m08(int x, int y) { + return x % y; + } + + public static int m09(int x, int y) { + return x / y; + } + + public static int m10(int x, int y) { + return x - y; + } + + } + + public static final Class[] testSignature = new Class[]{int.class, int.class}; + public static final Object[] testArgs = new Object[]{10, 10}; + + static class MethodMetricPhases { + static class CountingAddPhase extends Phase { + + // typically those global metrics would be static final, but we need new timers every + // invocation if we override the debugvaluefactory + private final DebugCounter globalCounter = Debug.counter("GlobalMetric"); + private final DebugTimer globalTimer = Debug.timer("GlobalTimer"); + + @Override + @SuppressWarnings("try") + protected void run(StructuredGraph graph) { + try (DebugCloseable d = globalTimer.start()) { + ResolvedJavaMethod method = graph.method(); + DebugMethodMetrics mm = Debug.methodMetrics(method); + mm.addToMetric(graph.getNodes().filter(InvokeNode.class).count(), "Invokes"); + mm.incrementMetric("PhaseRunsOnMethod"); + globalCounter.increment(); + } + } + } + + static class CountingShiftPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + Debug.methodMetrics(graph.method()).addToMetric(graph.getNodes().filter(ShiftNode.class).count(), "Shifts"); + } + } + + static class CountingMulPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + Debug.methodMetrics(graph.method()).addToMetric(graph.getNodes().filter(MulNode.class).count(), "Muls"); + } + } + + static class CountingSubPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + Debug.methodMetrics(graph.method()).addToMetric(graph.getNodes().filter(SubNode.class).count(), "Subs"); + } + } + + static class CountingDivPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + Debug.methodMetrics(graph.method()).addToMetric(graph.getNodes().filter(SignedDivNode.class).count(), "Divs"); + } + } + + static class CountingBinOpPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + Debug.methodMetrics(graph.method()).addToMetric(graph.getNodes().filter(x -> x instanceof BinaryNode || x instanceof FixedBinaryNode).count(), "BinOps"); + } + } + + static class ScopeTestPhase extends Phase { + // typically those global metrics would be static final, but we need new timers every + // invocation if we override the debugvaluefactory + private final DebugTimer timer = Debug.timer("GlobalTimer1"); + private final DebugTimer scopedTimer = Debug.timer("GlobalTimer2"); + private final DebugTimer scopedScopedTimer = Debug.timer("GlobalTimer3"); + private final DebugTimer scopedScopedScopeTimer = Debug.timer("GlobalTimer4"); + + private final DebugTimer timer1 = Debug.timer("GlobalTimer1_WithoutInlineEnhancement"); + private final DebugTimer scopedTimer1 = Debug.timer("GlobalTimer2_WithoutInlineEnhancement"); + private final DebugTimer scopedScopedTimer1 = Debug.timer("GlobalTimer3_WithoutInlineEnhancement"); + private final DebugTimer scopedScopedScopeTimer1 = Debug.timer("GlobalTimer4_WithoutInlineEnhancement"); + + @Override + @SuppressWarnings("try") + protected void run(StructuredGraph graph) { + // we are in an enhanced debug scope from graal compiler + // now we open multiple inlining scopes, record their time + try (DebugCloseable c1 = timer.start()) { + try (DebugCloseable c2 = scopedTimer.start()) { + try (DebugCloseable c3 = scopedScopedTimer.start()) { + // do sth unnecessary long allocating many inlinee scopes + for (int i = 0; i < 50; i++) { + try (Debug.Scope s1 = Debug.methodMetricsScope("InlineEnhancement1", MethodMetricsInlineeScopeInfo.create(graph.method()), false)) { + try (DebugCloseable c4 = scopedScopedScopeTimer.start()) { + new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS).apply(graph); + // double scoped inlinee scopes should not make problems + // with the data + try (Debug.Scope s2 = Debug.methodMetricsScope("InlineEnhancement2", MethodMetricsInlineeScopeInfo.create(graph.method()), + false)) { + new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS).apply(graph); + } + } + } + } + } + } + } + + // now lets try different counters without the inline enhancement + try (DebugCloseable c1 = timer1.start()) { + try (DebugCloseable c2 = scopedTimer1.start()) { + try (DebugCloseable c3 = scopedScopedTimer1.start()) { + // do sth unnecessary long allocating many inlinee scopes + for (int i = 0; i < 50; i++) { + try (DebugCloseable c4 = scopedScopedScopeTimer1.start()) { + new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS).apply(graph); + new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS).apply(graph); + } + } + } + } + } + } + + } + } + + static DebugConfig overrideGraalDebugConfig(PrintStream log, String methodFilter, String methodMeter) { + List dumpHandlers = new ArrayList<>(); + List verifyHandlers = new ArrayList<>(); + GraalDebugConfig debugConfig = new GraalDebugConfig( + GraalDebugConfig.Options.Log.getValue(), + GraalDebugConfig.Options.Count.getValue(), + GraalDebugConfig.Options.TrackMemUse.getValue(), + GraalDebugConfig.Options.Time.getValue(), + GraalDebugConfig.Options.Dump.getValue(), + GraalDebugConfig.Options.Verify.getValue(), + methodFilter, + methodMeter, + log, dumpHandlers, verifyHandlers); + return debugConfig; + } + + private static OverrideScope overrideMetricPrinterConfig() { + Map, Object> mapping = new HashMap<>(); + mapping.put(MethodMetricsPrinter.Options.MethodMeterPrintAscii, true); + return OptionValue.override(mapping); + } + + abstract Phase additionalPhase(); + + @Override + protected Suites createSuites() { + Suites ret = super.createSuites(); + ListIterator> iter = ret.getHighTier().findPhase(ConvertDeoptimizeToGuardPhase.class, true); + PhaseSuite.findNextPhase(iter, CanonicalizerPhase.class); + iter.add(additionalPhase()); + return ret; + } + + @Test + @SuppressWarnings("try") + public void test() throws Throwable { + try (DebugConfigScope s = Debug.setConfig(getConfig()); OverrideScope o = getOScope();) { + executeMethod(TestApplication.class.getMethod("m01", testSignature), null, testArgs); + executeMethod(TestApplication.class.getMethod("m02", testSignature), null, testArgs); + executeMethod(TestApplication.class.getMethod("m03", testSignature), null, testArgs); + executeMethod(TestApplication.class.getMethod("m04", testSignature), null, testArgs); + executeMethod(TestApplication.class.getMethod("m05", testSignature), null, testArgs); + executeMethod(TestApplication.class.getMethod("m06", testSignature), null, testArgs); + executeMethod(TestApplication.class.getMethod("m07", testSignature), null, testArgs); + executeMethod(TestApplication.class.getMethod("m08", testSignature), null, testArgs); + executeMethod(TestApplication.class.getMethod("m09", testSignature), null, testArgs); + executeMethod(TestApplication.class.getMethod("m10", testSignature), null, testArgs); + assertValues(); + } + } + + @Before + public void rememberScopeId() { + scopeIdBeforeAccess = DebugScope.getCurrentGlobalScopeId(); + } + + @After + public void clearMMCache() { + MethodMetricsImpl.clearMM(); + } + + abstract DebugConfig getConfig(); + + OverrideScope getOScope() { + return overrideMetricPrinterConfig(); + } + + abstract void assertValues() throws Throwable; + + @SuppressWarnings("unchecked") + private static Map readMethodMetricsImplData() { + Map threadLocalMap = null; + for (Field f : MethodMetricsImpl.class.getDeclaredFields()) { + if (f.getName().equals("threadEntries")) { + f.setAccessible(true); + Object map; + try { + map = ((ThreadLocal) f.get(null)).get(); + } catch (Throwable t) { + throw new RuntimeException(t); + } + threadLocalMap = (Map) map; + break; + } + } + return threadLocalMap; + } + + private long scopeIdBeforeAccess; + private long scopeIdAfterAccess; + + protected long readValFromCurrThread(ResolvedJavaMethod method, String metricName) { + + Map threadLocalMap = readMethodMetricsImplData(); + assert threadLocalMap != null; + CompilationData compilationData = threadLocalMap.get(method); + assert compilationData != null; + Map> compilations = compilationData.getCompilations(); + List> compilationEntries = new ArrayList<>(); + compilations.forEach((x, y) -> { + if (x >= scopeIdBeforeAccess && x <= scopeIdAfterAccess) { + compilationEntries.add(y); + } + }); + List> listView = compilationEntries.stream().filter(x -> x.size() > 0).collect(Collectors.toList()); + assert listView.size() <= 1 : "There must be at most one none empty compilation data point present:" + listView.size(); + /* + * NOTE: Using the pre-generation of compilation entries for a method has the disadvantage + * that during testing we have different points in time when we request the metric. First, + * properly, when we use it and then when we want to know the result, but when we check the + * result the debug context no longer holds a correct scope with the unique id, so we return + * the first compilation entry that is not empty. + */ + Map entries = listView.size() > 0 ? listView.get(0) : null; + Long res = entries != null ? entries.get(metricName) : null; + return res != null ? res : 0; + } + + @SuppressWarnings("try") + void assertValues(String metricName, long[] vals) { + scopeIdAfterAccess = DebugScope.getCurrentGlobalScopeId(); + try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().enable(Feature.METHOD_METRICS))) { + Assert.assertEquals(vals[0], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m01", testSignature)), metricName)); + Assert.assertEquals(vals[1], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m02", testSignature)), metricName)); + Assert.assertEquals(vals[2], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m03", testSignature)), metricName)); + Assert.assertEquals(vals[3], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m04", testSignature)), metricName)); + Assert.assertEquals(vals[4], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m05", testSignature)), metricName)); + Assert.assertEquals(vals[5], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m06", testSignature)), metricName)); + Assert.assertEquals(vals[6], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m07", testSignature)), metricName)); + Assert.assertEquals(vals[7], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m08", testSignature)), metricName)); + Assert.assertEquals(vals[8], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m09", testSignature)), metricName)); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + void executeMethod(Method m, Object receiver, Object... args) { + test(asResolvedJavaMethod(m), receiver, args); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest1.java 2016-12-07 13:48:37.123144376 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.debug; + +import org.junit.Test; + +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.phases.Phase; + +public class MethodMetricsTest1 extends MethodMetricsTest { + @Override + protected Phase additionalPhase() { + return new MethodMetricPhases.CountingAddPhase(); + } + + @Override + DebugConfig getConfig() { + return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingAddPhase"); + } + + @Override + void assertValues() throws Throwable { + assertValues("PhaseRunsOnMethod", new long[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}); + } + + @Override + @Test + public void test() throws Throwable { + super.test(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest2.java 2016-12-07 13:48:37.388156025 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.debug; + +import org.junit.Test; + +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.phases.Phase; + +public class MethodMetricsTest2 extends MethodMetricsTest { + + @Override + protected Phase additionalPhase() { + return new MethodMetricPhases.CountingShiftPhase(); + } + + @Override + DebugConfig getConfig() { + return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingShiftPhase"); + } + + @Override + void assertValues() throws Throwable { + assertValues("Shifts", new long[]{0, 0, 0, 1, 1, 1, 0, 0, 0, 0}); + } + + @Test + @Override + public void test() throws Throwable { + super.test(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest3.java 2016-12-07 13:48:37.654167718 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.debug; + +import org.junit.Test; + +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.phases.Phase; + +public class MethodMetricsTest3 extends MethodMetricsTest { + + @Override + protected Phase additionalPhase() { + return new MethodMetricPhases.CountingMulPhase(); + } + + @Override + DebugConfig getConfig() { + return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingMulPhase"); + } + + @Override + void assertValues() throws Throwable { + assertValues("Muls", new long[]{0, 1, 0, 0, 0, 0, 0, 0, 0, 0}); + } + + @Override + @Test + public void test() throws Throwable { + super.test(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest4.java 2016-12-07 13:48:37.917179280 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.debug; + +import org.junit.Test; + +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.phases.Phase; + +public class MethodMetricsTest4 extends MethodMetricsTest { + + @Override + protected Phase additionalPhase() { + return new MethodMetricPhases.CountingSubPhase(); + } + + @Override + DebugConfig getConfig() { + return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingSubPhase"); + } + + @Override + void assertValues() throws Throwable { + assertValues("Subs", new long[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 1}); + } + + @Override + @Test + public void test() throws Throwable { + super.test(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest5.java 2016-12-07 13:48:38.182190929 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.debug; + +import org.junit.Test; + +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.phases.Phase; + +public class MethodMetricsTest5 extends MethodMetricsTest { + + @Override + protected Phase additionalPhase() { + return new MethodMetricPhases.CountingDivPhase(); + } + + @Override + DebugConfig getConfig() { + return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingDivPhase"); + } + + @Override + void assertValues() throws Throwable { + assertValues("Divs", new long[]{0, 0, 0, 0, 0, 0, 0, 0, 1, 0}); + } + + @Override + @Test + public void test() throws Throwable { + super.test(); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest6.java 2016-12-07 13:48:38.447202578 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.debug; + +import org.junit.Test; + +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.phases.Phase; + +public class MethodMetricsTest6 extends MethodMetricsTest { + + @Override + protected Phase additionalPhase() { + return new MethodMetricPhases.CountingBinOpPhase(); + } + + @Override + DebugConfig getConfig() { + return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingBinOpPhase"); + } + + @Override + void assertValues() throws Throwable { + assertValues("BinOps", new long[]{1, 1, 1, 1, 1, 1, 0, 1, 1, 1}); + } + + @Override + @Test + public void test() throws Throwable { + super.test(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTestInterception01.java 2016-12-07 13:48:38.711214183 -0800 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.debug; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.DebugDumpHandler; +import org.graalvm.compiler.debug.DebugMemUseTracker; +import org.graalvm.compiler.debug.DebugMethodMetrics; +import org.graalvm.compiler.debug.DebugTimer; +import org.graalvm.compiler.debug.DebugValueFactory; +import org.graalvm.compiler.debug.DebugVerifyHandler; +import org.graalvm.compiler.debug.GraalDebugConfig; +import org.graalvm.compiler.debug.internal.CounterImpl; +import org.graalvm.compiler.debug.internal.MemUseTrackerImpl; +import org.graalvm.compiler.debug.internal.TimerImpl; +import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl; +import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.phases.Phase; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +// intercepting metrics +public class MethodMetricsTestInterception01 extends MethodMetricsTest { + + @Override + protected Phase additionalPhase() { + return new MethodMetricPhases.CountingAddPhase(); + } + + @Override + DebugConfig getConfig() { + List dumpHandlers = new ArrayList<>(); + List verifyHandlers = new ArrayList<>(); + GraalDebugConfig debugConfig = new GraalDebugConfig( + GraalDebugConfig.Options.Log.getValue(), + "CountingAddPhase", + GraalDebugConfig.Options.TrackMemUse.getValue(), + "CountingAddPhase", + GraalDebugConfig.Options.Dump.getValue(), + GraalDebugConfig.Options.Verify.getValue(), + "MethodMetricsTest$TestApplication.*", + "CountingAddPhase", + System.out, dumpHandlers, verifyHandlers); + return debugConfig; + } + + @Override + protected OverrideScope getOScope() { + Map, Object> mapping = new HashMap<>(); + mapping.put(MethodMetricsPrinter.Options.MethodMeterPrintAscii, true); + return OptionValue.override(mapping); + } + + private DebugValueFactory factory; + + @Test + @Override + @SuppressWarnings("try") + public void test() throws Throwable { + factory = Debug.getDebugValueFactory(); + Debug.setDebugValueFactory(new DebugValueFactory() { + @Override + public DebugTimer createTimer(String name, boolean conditional) { + return new TimerImpl(name, conditional, true); + } + + @Override + public DebugCounter createCounter(String name, boolean conditional) { + return CounterImpl.create(name, conditional, true); + } + + @Override + public DebugMethodMetrics createMethodMetrics(ResolvedJavaMethod method) { + return MethodMetricsImpl.getMethodMetrics(method); + } + + @Override + public DebugMemUseTracker createMemUseTracker(String name, boolean conditional) { + return new MemUseTrackerImpl(name, conditional, true); + } + }); + super.test(); + + } + + @Override + public void afterTest() { + super.afterTest(); + Debug.setDebugValueFactory(factory); + } + + @Override + @SuppressWarnings("try") + void assertValues() throws Throwable { + assertValues("GlobalMetric", new long[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTestInterception02.java 2016-12-07 13:48:38.977225876 -0800 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.debug; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.DebugDumpHandler; +import org.graalvm.compiler.debug.DebugMemUseTracker; +import org.graalvm.compiler.debug.DebugMethodMetrics; +import org.graalvm.compiler.debug.DebugTimer; +import org.graalvm.compiler.debug.DebugValueFactory; +import org.graalvm.compiler.debug.DebugVerifyHandler; +import org.graalvm.compiler.debug.GraalDebugConfig; +import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl; +import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.phases.Phase; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +// intercepting metrics +public class MethodMetricsTestInterception02 extends MethodMetricsTest { + + @Override + protected Phase additionalPhase() { + return new MethodMetricPhases.ScopeTestPhase(); + } + + private DebugValueFactory factory; + + public void setFactory() { + /* + * setting a custom debug value factory creating a constant timer for checking scope + * creation and inlining scopes with metric intercepting works + */ + factory = Debug.getDebugValueFactory(); + Debug.setDebugValueFactory(new DebugValueFactory() { + @Override + public DebugTimer createTimer(String name, boolean conditional) { + // can still use together with real timer + // TimerImpl realTimer = new TimerImpl(name, conditional, true); + return new DebugTimer() { + int runs = 0; + + // private DebugCloseable t; + + @Override + public DebugCloseable start() { + // t = realTimer.start(); + return new DebugCloseable() { + @Override + public void close() { + // t.close(); + runs++; + MethodMetricsImpl.addToCurrentScopeMethodMetrics(name, 1); + } + }; + } + + @Override + public void setConditional(boolean flag) { + + } + + @Override + public boolean isConditional() { + return false; + } + + @Override + public TimeUnit getTimeUnit() { + return TimeUnit.MILLISECONDS; + } + + @Override + public long getCurrentValue() { + return runs; + } + }; + } + + @Override + public DebugCounter createCounter(String name, boolean conditional) { + return factory.createCounter(name, conditional); + } + + @Override + public DebugMethodMetrics createMethodMetrics(ResolvedJavaMethod method) { + return factory.createMethodMetrics(method); + } + + @Override + public DebugMemUseTracker createMemUseTracker(String name, boolean conditional) { + return factory.createMemUseTracker(name, conditional); + } + }); + } + + @Override + protected OverrideScope getOScope() { + Map, Object> mapping = new HashMap<>(); + mapping.put(MethodMetricsPrinter.Options.MethodMeterPrintAscii, true); + return OptionValue.override(mapping); + } + + @Test + @Override + public void test() throws Throwable { + setFactory(); + super.test(); + } + + @Override + public void afterTest() { + super.afterTest(); + Debug.setDebugValueFactory(factory); + } + + @Override + DebugConfig getConfig() { + List dumpHandlers = new ArrayList<>(); + List verifyHandlers = new ArrayList<>(); + GraalDebugConfig debugConfig = new GraalDebugConfig( + GraalDebugConfig.Options.Log.getValue(), + ""/* unscoped meter */, + GraalDebugConfig.Options.TrackMemUse.getValue(), + ""/* unscoped time */, + GraalDebugConfig.Options.Dump.getValue(), + GraalDebugConfig.Options.Verify.getValue(), + null /* no method filter */, + "" /* unscoped method metering */, + System.out, dumpHandlers, verifyHandlers); + return debugConfig; + } + + @Override + @SuppressWarnings("try") + void assertValues() throws Throwable { + assertValues("GlobalTimer4_WithoutInlineEnhancement", new long[]{50, 50, 50, 50, 50, 50, 50, 50, 50, 50}); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/VerifyMethodMetricsTest.java 2016-12-07 13:48:39.241237481 -0800 @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.debug; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.junit.Test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugConfigScope; +import org.graalvm.compiler.debug.DebugMethodMetrics; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.Phase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.VerifyPhase.VerificationError; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.phases.verify.VerifyDebugUsage; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * + * Tests to verify that the usage of method metrics does not generate compile time overhead through + * eager evaluation of arguments. + */ +public class VerifyMethodMetricsTest { + + private static class InvalidCCP_ToString01Inc extends Phase { + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.incrementMetric(n.toString()); + } + } + } + + private static class InvalidCCP_Concat01Inc extends Phase { + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.incrementMetric("a" + n.toString()); + } + } + } + + private static class InvalidCCP_ToString02Inc extends Phase { + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.incrementMetric("%s", n.toString()); + } + } + } + + private static class InvalidCCP_Concat02Inc extends Phase { + private final String s = this.getClass().toGenericString(); + + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.incrementMetric("%s%s", "a" + s, n); + } + } + } + + private static class ValidCCP_ToStringInc extends Phase { + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.addToMetric(1, "%s", n); + } + } + } + + private static class ValidCCP_ConcatInc extends Phase { + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.incrementMetric("%s%s", "a", n); + } + } + } + + private static class InvalidCCP_ToString01Add extends Phase { + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.addToMetric(1, n.toString()); + } + } + } + + private static class InvalidCCP_Concat01Add extends Phase { + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.addToMetric(1, "a" + n.toString()); + } + } + } + + private static class InvalidCCP_ToString02Add extends Phase { + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.addToMetric(1, "%s", n.toString()); + } + } + } + + private static class InvalidCCP_Concat02Add extends Phase { + private final String s = this.getClass().toGenericString(); + + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.addToMetric(1, "%s%s", "a" + s, n); + } + } + } + + private static class ValidCCP_ToStringAdd extends Phase { + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.addToMetric(1, "%s", n); + } + } + } + + private static class ValidCCP_ConcatAdd extends Phase { + @Override + protected void run(StructuredGraph graph) { + DebugMethodMetrics m = Debug.methodMetrics(graph.method()); + for (Node n : graph.getNodes()) { + m.addToMetric(1, "%s%s", "a", n); + } + } + } + + @Test(expected = VerificationError.class) + public void testLogInvalidToString01Add() { + testDebugUsageClass(InvalidCCP_ToString01Add.class); + } + + @Test(expected = VerificationError.class) + public void testLogInvalidConcat01Add() { + testDebugUsageClass(InvalidCCP_Concat01Add.class); + } + + @Test(expected = VerificationError.class) + public void testLogInvalidToString02Add() { + testDebugUsageClass(InvalidCCP_ToString02Add.class); + } + + @Test(expected = VerificationError.class) + public void testLogInvalidConcat02Add() { + testDebugUsageClass(InvalidCCP_Concat02Add.class); + } + + @Test + public void testLogValidToStringAdd() { + testDebugUsageClass(ValidCCP_ToStringAdd.class); + } + + @Test + public void testLogValidConcatAdd() { + testDebugUsageClass(ValidCCP_ConcatAdd.class); + } + + @Test(expected = VerificationError.class) + public void testLogInvalidToString01Inc() { + testDebugUsageClass(InvalidCCP_ToString01Inc.class); + } + + @Test(expected = VerificationError.class) + public void testLogInvalidConcat01Inc() { + testDebugUsageClass(InvalidCCP_Concat01Inc.class); + } + + @Test(expected = VerificationError.class) + public void testLogInvalidToString02Inc() { + testDebugUsageClass(InvalidCCP_ToString02Inc.class); + } + + @Test(expected = VerificationError.class) + public void testLogInvalidConcat02Inc() { + testDebugUsageClass(InvalidCCP_Concat02Inc.class); + } + + @Test + public void testLogValidToStringInc() { + testDebugUsageClass(ValidCCP_ToStringInc.class); + } + + @Test + public void testLogValidConcatInc() { + testDebugUsageClass(ValidCCP_ConcatInc.class); + } + + @SuppressWarnings("try") + private static void testDebugUsageClass(Class c) { + RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class); + Providers providers = rt.getHostBackend().getProviders(); + MetaAccessProvider metaAccess = providers.getMetaAccess(); + PhaseSuite graphBuilderSuite = new PhaseSuite<>(); + Plugins plugins = new Plugins(new InvocationPlugins(metaAccess)); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); + for (Method m : c.getDeclaredMethods()) { + if (!Modifier.isNative(m.getModifiers()) && !Modifier.isAbstract(m.getModifiers())) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID); + graphBuilderSuite.apply(graph, context); + try (DebugConfigScope s = Debug.disableIntercept()) { + new VerifyDebugUsage().apply(graph, context); + } + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/CompiledMethodTest.java 2016-12-07 13:48:39.507249174 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011, 2015, 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.core.test.deopt; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/** + * In the following tests, the usages of local variable "a" are replaced with the integer constant + * 0. Then canonicalization is applied and it is verified that the resulting graph is equal to the + * graph of the method that just has a "return 1" statement in it. + */ +public class CompiledMethodTest extends GraalCompilerTest { + + public static Object testMethod(Object arg1, Object arg2, Object arg3) { + return arg1 + " " + arg2 + " " + arg3; + } + + Object f1; + + public Object testMethodVirtual(Object arg1, Object arg2, Object arg3) { + return f1 + " " + arg1 + " " + arg2 + " " + arg3; + } + + @Test + public void test1() { + final ResolvedJavaMethod javaMethod = getResolvedJavaMethod("testMethod"); + final StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.NO); + new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); + new DeadCodeEliminationPhase().apply(graph); + + for (ConstantNode node : ConstantNode.getConstantNodes(graph)) { + if (node.getStackKind() == JavaKind.Object && " ".equals(getSnippetReflection().asObject(String.class, node.asJavaConstant()))) { + node.replace(graph, ConstantNode.forConstant(getSnippetReflection().forObject("-"), getMetaAccess(), graph)); + } + } + + InstalledCode compiledMethod = getCode(javaMethod, graph); + try { + Object result = compiledMethod.executeVarargs("1", "2", "3"); + Assert.assertEquals("1-2-3", result); + } catch (InvalidInstalledCodeException t) { + Assert.fail("method invalidated"); + } + } + + @Test + public void test3() { + final ResolvedJavaMethod javaMethod = getResolvedJavaMethod("testMethod"); + InstalledCode compiledMethod = getCode(javaMethod); + try { + Object result = compiledMethod.executeVarargs("1", "2", "3"); + Assert.assertEquals("1 2 3", result); + } catch (InvalidInstalledCodeException t) { + Assert.fail("method invalidated"); + } + } + + @Test + public void test4() { + final ResolvedJavaMethod javaMethod = getResolvedJavaMethod("testMethodVirtual"); + InstalledCode compiledMethod = getCode(javaMethod); + try { + f1 = "0"; + Object result = compiledMethod.executeVarargs(this, "1", "2", "3"); + Assert.assertEquals("0 1 2 3", result); + } catch (InvalidInstalledCodeException t) { + Assert.fail("method invalidated"); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/MonitorDeoptTest.java 2016-12-07 13:48:39.775260955 -0800 @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2007, 2016, 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.core.test.deopt; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.AbstractEndNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +public final class MonitorDeoptTest extends GraalCompilerTest { + + private enum State { + INITIAL, + ALLOWING_SAFEPOINT, + RUNNING_GRAAL, + INVALIDATED, + RUNNING_INTERPRETER, + TERMINATED + } + + static final long TIMEOUT = 5000; + + private static class Monitor { + private volatile State state = State.INITIAL; + + public synchronized void setState(State newState) { + state = newState; + notifyAll(); + } + + public synchronized boolean tryUpdateState(State oldState, State newState) { + if (state == oldState) { + state = newState; + notifyAll(); + return true; + } else { + return false; + } + } + + public synchronized void waitState(State targetState) throws InterruptedException { + long startTime = System.currentTimeMillis(); + while (state != targetState && System.currentTimeMillis() - startTime < TIMEOUT) { + wait(100); + } + if (state != targetState) { + throw new IllegalStateException("Timed out waiting for " + targetState); + } + } + + /** + * Change the current state to {@link State#ALLOWING_SAFEPOINT} and do a short wait to allow + * a safepoint to happen. Then restore the state to the original value. + * + * @param expectedState + * @throws InterruptedException + */ + public synchronized void safepoint(State expectedState) throws InterruptedException { + if (state == expectedState) { + state = State.ALLOWING_SAFEPOINT; + wait(1); + if (state != State.ALLOWING_SAFEPOINT) { + throw new InternalError("Other threads can not update the state from ALLOWING_SAFEPOINT: " + state); + } + state = expectedState; + notifyAll(); + } + } + + public synchronized State getState() { + return state; + } + + public synchronized void invalidate(InstalledCode code) throws InterruptedException { + // wait for the main thread to start + waitState(State.RUNNING_GRAAL); + + state = State.INVALIDATED; + code.invalidate(); + } + } + + public static boolean test(Monitor monitor) throws InterruptedException { + // initially, we're running as Graal compiled code + monitor.setState(State.RUNNING_GRAAL); + + boolean timedOut = true; + long startTime = System.currentTimeMillis(); + long safepointCheckTime = startTime; + while (System.currentTimeMillis() - startTime < TIMEOUT) { + // wait for the compiled code to be invalidated + if (monitor.tryUpdateState(State.INVALIDATED, State.RUNNING_INTERPRETER)) { + timedOut = false; + break; + } + if (System.currentTimeMillis() - safepointCheckTime > 200) { + /* + * It's possible for a safepoint to be triggered by external code before + * invalidation is ready. Allow a safepoint to occur if required but don't allow + * invalidation to proceed. + */ + monitor.safepoint(State.RUNNING_GRAAL); + safepointCheckTime = System.currentTimeMillis(); + } + } + if (timedOut) { + throw new InternalError("Timed out while waiting for code to be invalidated: " + monitor.getState()); + } + + for (int i = 0; i < 500; i++) { + // wait for the control thread to send the TERMINATED signal + if (monitor.getState() == State.TERMINATED) { + return true; + } + + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + } + + // we're running for more than 5 s in the interpreter + // probably the control thread is deadlocked + return false; + } + + private static LoopBeginNode findFirstLoop(StructuredGraph graph) { + FixedNode node = graph.start(); + for (;;) { + if (node instanceof LoopBeginNode) { + return (LoopBeginNode) node; + } else if (node instanceof FixedWithNextNode) { + node = ((FixedWithNextNode) node).next(); + } else if (node instanceof AbstractEndNode) { + node = ((AbstractEndNode) node).merge(); + } else { + Assert.fail(String.format("unexpected node %s in graph of test method", node)); + } + } + } + + /** + * Remove the safepoint from the first loop in the test method, so only the safepoints on + * MonitorEnter and MonitorExit remain in the loop. That way, we can make sure it deopts inside + * the MonitorEnter by invalidating the code while holding the lock. + */ + private static void removeLoopSafepoint(StructuredGraph graph) { + LoopBeginNode loopBegin = findFirstLoop(graph); + loopBegin.disableSafepoint(); + } + + @Test + public void run0() throws Throwable { + ResolvedJavaMethod javaMethod = getResolvedJavaMethod("test"); + + StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.YES); + removeLoopSafepoint(graph); + + CompilationResult compilationResult = compile(javaMethod, graph); + final InstalledCode installedCode = getBackend().createDefaultInstalledCode(javaMethod, compilationResult); + + final Monitor monitor = new Monitor(); + + Thread controlThread = new Thread(new Runnable() { + + @Override + public void run() { + try { + // Wait for thread to reach RUNNING_GRAAL and then invalidate the code + monitor.invalidate(installedCode); + + // wait for the main thread to continue running in the interpreter + monitor.waitState(State.RUNNING_INTERPRETER); + + // terminate the main thread + monitor.setState(State.TERMINATED); + } catch (InterruptedException e) { + } + } + }); + + controlThread.start(); + + boolean result = test(monitor); + Assert.assertTrue(result); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/SafepointRethrowDeoptTest.java 2016-12-07 13:48:40.042272692 -0800 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test.deopt; + +import java.util.concurrent.CountDownLatch; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.test.GraalCompilerTest; + +import jdk.vm.ci.code.InstalledCode; + +public final class SafepointRethrowDeoptTest extends GraalCompilerTest { + + private static final Object RETURN_VALUE = "1 2 3"; + private static final RuntimeException BREAK_EX = new RuntimeException(); + private static final RuntimeException CONTINUE_EX = new RuntimeException(); + private static volatile int terminate; + private static volatile int entered; + + public static Object execute() { + entered = 1; + for (;;) { + try { + if (terminate != 0) { + throw BREAK_EX; + } else { + throw CONTINUE_EX; + } + } catch (RuntimeException e) { + if (e == BREAK_EX) { + break; + } else if (e == CONTINUE_EX) { + continue; + } + throw e; + } + } + return RETURN_VALUE; + } + + @Test + public void test() { + Assume.assumeTrue(GraalOptions.GenLoopSafepoints.getValue()); + synchronized (SafepointRethrowDeoptTest.class) { + // needs static fields + terminate = 1; + + InstalledCode installed = getCode(getResolvedJavaMethod("execute")); + + terminate = 0; + entered = 0; + CountDownLatch cdl = new CountDownLatch(1); + Thread t1 = new Thread(() -> { + try { + cdl.await(); + while (entered == 0) { + /* spin */ + } + installed.invalidate(); + } catch (InterruptedException e) { + Assert.fail("interrupted"); + } finally { + terminate = 1; + } + }); + Thread t2 = new Thread(() -> { + cdl.countDown(); + Object result; + try { + result = installed.executeVarargs(); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail("exception"); + return; + } + Assert.assertEquals(RETURN_VALUE, result); + }); + + t1.start(); + t2.start(); + try { + t1.join(); + t2.join(); + } catch (InterruptedException e) { + Assert.fail("interrupted"); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/SynchronizedMethodDeoptimizationTest.java 2016-12-07 13:48:40.308284385 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011, 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.core.test.deopt; + +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.core.test.ea.EATestBase.TestClassObject; + +/** + * In the following tests, we try to deoptimize out of synchronized methods. + */ +public class SynchronizedMethodDeoptimizationTest extends GraalCompilerTest { + + public static final TestClassObject testObject = null; + + public static synchronized Object testMethodSynchronized(Object o) { + if (o == null) { + // this branch will always deoptimize + return testObject.x; + } + return o; + } + + @Test + public void test1() { + test("testMethodSynchronized", "test"); + test("testMethodSynchronized", (Object) null); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EAMergingTest.java 2016-12-07 13:48:40.573296034 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, 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.core.test.ea; + +import org.junit.Test; + +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.ValuePhiNode; + +public class EAMergingTest extends EATestBase { + + @Test + public void testSimpleMerge() { + testEscapeAnalysis("simpleMergeSnippet", null, false); + assertDeepEquals(1, returnNodes.size()); + assertTrue(returnNodes.get(0).result() instanceof ValuePhiNode); + PhiNode phi = (PhiNode) returnNodes.get(0).result(); + assertTrue(phi.valueAt(0) instanceof ParameterNode); + assertTrue(phi.valueAt(1) instanceof ParameterNode); + } + + public static int simpleMergeSnippet(boolean b, int u, int v) { + TestClassInt obj; + if (b) { + obj = new TestClassInt(u, 0); + notInlineable(); + } else { + obj = new TestClassInt(v, 0); + notInlineable(); + } + return obj.x; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java 2016-12-07 13:48:40.838307683 -0800 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2011, 2014, 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.core.test.ea; + +import java.util.List; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Assert; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.java.NewArrayNode; +import org.graalvm.compiler.nodes.java.NewInstanceNode; +import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; + +//JaCoCo Exclude + +/** + * This base class for all Escape Analysis tests does not contain tests itself, therefore it is not + * automatically excluded from JaCoCo. Since it includes code that is used in the test snippets, it + * needs to be excluded manually. + */ +public class EATestBase extends GraalCompilerTest { + + public static class TestClassInt { + public int x; + public int y; + public int z; + + public TestClassInt() { + this(0, 0); + } + + public TestClassInt(int x) { + this(x, 0); + } + + public TestClassInt(int x, int y) { + this.x = x; + this.y = y; + } + + @Override + public boolean equals(Object obj) { + TestClassInt other = (TestClassInt) obj; + return x == other.x && y == other.y && z == other.z; + } + + @Override + public String toString() { + return "{" + x + "," + y + "}"; + } + + @Override + public int hashCode() { + return x + 13 * y; + } + } + + public static class TestClassObject { + public Object x; + public Object y; + + public TestClassObject() { + this(null, null); + } + + public TestClassObject(Object x) { + this(x, null); + } + + public TestClassObject(Object x, Object y) { + this.x = x; + this.y = y; + } + + @Override + public boolean equals(Object obj) { + TestClassObject other = (TestClassObject) obj; + return x == other.x && y == other.y; + } + + @Override + public String toString() { + return "{" + x + "," + y + "}"; + } + + @Override + public int hashCode() { + return (x == null ? 0 : x.hashCode()) + 13 * (y == null ? 0 : y.hashCode()); + } + } + + protected static native void notInlineable(); + + protected StructuredGraph graph; + protected HighTierContext context; + protected List returnNodes; + + /** + * Runs Escape Analysis on the given snippet and makes sure that no allocations remain in the + * graph. + * + * @param snippet the name of the method whose graph should be processed + * @param expectedConstantResult if this is non-null, the resulting graph needs to have the + * given constant return value + * @param iterativeEscapeAnalysis true if escape analysis should be run for more than one + * iteration + */ + protected void testEscapeAnalysis(String snippet, JavaConstant expectedConstantResult, boolean iterativeEscapeAnalysis) { + prepareGraph(snippet, iterativeEscapeAnalysis); + if (expectedConstantResult != null) { + for (ReturnNode returnNode : returnNodes) { + Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant()); + Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant()); + } + } + int newInstanceCount = graph.getNodes().filter(NewInstanceNode.class).count() + graph.getNodes().filter(NewArrayNode.class).count() + + graph.getNodes().filter(CommitAllocationNode.class).count(); + Assert.assertEquals(0, newInstanceCount); + } + + @SuppressWarnings("try") + protected void prepareGraph(String snippet, boolean iterativeEscapeAnalysis) { + ResolvedJavaMethod method = getResolvedJavaMethod(snippet); + try (Scope s = Debug.scope(getClass(), method, getCodeCache())) { + graph = parseEager(method, AllowAssumptions.YES); + context = getDefaultHighTierContext(); + new InliningPhase(new CanonicalizerPhase()).apply(graph, context); + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase().apply(graph, context); + new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(), null).apply(graph, context); + returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot(); + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EarlyReadEliminationTest.java 2016-12-07 13:48:41.102319288 -0800 @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2011, 2015, 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.core.test.ea; + +import java.util.List; + +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.ProxyNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.ValuePhiNode; +import org.graalvm.compiler.nodes.java.LoadFieldNode; +import org.graalvm.compiler.nodes.java.StoreFieldNode; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase; + +public class EarlyReadEliminationTest extends GraalCompilerTest { + + public static Object staticField; + + public static class TestObject { + + public int x; + public int y; + + public TestObject(int x, int y) { + this.x = x; + this.y = y; + } + } + + public static class TestObject2 { + + public Object x; + public Object y; + + public TestObject2(Object x, Object y) { + this.x = x; + this.y = y; + } + } + + public static class TestObject3 extends TestObject { + + public int z; + + public TestObject3(int x, int y, int z) { + super(x, y); + this.z = z; + } + } + + @SuppressWarnings("all") + public static int testSimpleSnippet(TestObject a) { + a.x = 2; + staticField = a; + return a.x; + } + + @Test + public void testSimple() { + // Test without lowering. + ValueNode result = getReturn("testSimpleSnippet", false).result(); + assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty()); + assertTrue(result.isConstant()); + assertDeepEquals(2, result.asJavaConstant().asInt()); + + // Test with lowering. + result = getReturn("testSimpleSnippet", true).result(); + assertTrue(result.graph().getNodes().filter(ReadNode.class).isEmpty()); + assertTrue(result.isConstant()); + assertDeepEquals(2, result.asJavaConstant().asInt()); + } + + @SuppressWarnings("all") + public static int testSimpleConflictSnippet(TestObject a, TestObject b) { + a.x = 2; + b.x = 3; + staticField = a; + return a.x; + } + + @Test + public void testSimpleConflict() { + ValueNode result = getReturn("testSimpleConflictSnippet", false).result(); + assertFalse(result.isConstant()); + assertTrue(result instanceof LoadFieldNode); + } + + @SuppressWarnings("all") + public static int testParamSnippet(TestObject a, int b) { + a.x = b; + return a.x; + } + + @Test + public void testParam() { + ValueNode result = getReturn("testParamSnippet", false).result(); + assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty()); + assertDeepEquals(result.graph().getParameter(1), result); + } + + @SuppressWarnings("all") + public static int testMaterializedSnippet(int a) { + TestObject obj = new TestObject(a, 0); + staticField = obj; + return obj.x; + } + + @Test + public void testMaterialized() { + ValueNode result = getReturn("testMaterializedSnippet", false).result(); + assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty()); + assertDeepEquals(result.graph().getParameter(0), result); + } + + @SuppressWarnings("all") + public static int testSimpleLoopSnippet(TestObject obj, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + staticField = obj; + } + return obj.x; + } + + @Test + public void testSimpleLoop() { + // Test without lowering. + ValueNode result = getReturn("testSimpleLoopSnippet", false).result(); + assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty()); + assertDeepEquals(result.graph().getParameter(1), result); + + // Now test with lowering. + result = getReturn("testSimpleLoopSnippet", true).result(); + assertTrue(result.graph().getNodes().filter(ReadNode.class).isEmpty()); + assertDeepEquals(result.graph().getParameter(1), result); + } + + @SuppressWarnings("all") + public static int testBadLoopSnippet(TestObject obj, TestObject obj2, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + staticField = obj; + obj2.x = 10; + obj.x = 0; + } + return obj.x; + } + + @Test + public void testBadLoop() { + ValueNode result = getReturn("testBadLoopSnippet", false).result(); + assertDeepEquals(0, result.graph().getNodes().filter(LoadFieldNode.class).count()); + assertTrue(result instanceof ProxyNode); + assertTrue(((ProxyNode) result).value() instanceof ValuePhiNode); + } + + @SuppressWarnings("all") + public static int testBadLoop2Snippet(TestObject obj, TestObject obj2, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + obj.x = 0; + obj2.x = 10; + } + return obj.x; + } + + @Test + public void testBadLoop2() { + ValueNode result = getReturn("testBadLoop2Snippet", false).result(); + assertDeepEquals(1, result.graph().getNodes().filter(LoadFieldNode.class).count()); + assertTrue(result instanceof LoadFieldNode); + } + + @SuppressWarnings("all") + public static int testPhiSnippet(TestObject a, int b) { + if (b < 0) { + a.x = 1; + } else { + a.x = 2; + } + return a.x; + } + + @Test + public void testPhi() { + StructuredGraph graph = processMethod("testPhiSnippet", false); + assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty()); + List returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot(); + assertDeepEquals(2, returnNodes.size()); + assertTrue(returnNodes.get(0).predecessor() instanceof StoreFieldNode); + assertTrue(returnNodes.get(1).predecessor() instanceof StoreFieldNode); + assertTrue(returnNodes.get(0).result().isConstant()); + assertTrue(returnNodes.get(1).result().isConstant()); + } + + @SuppressWarnings("all") + public static void testSimpleStoreSnippet(TestObject a, int b) { + a.x = b; + a.x = b; + } + + @Test + public void testSimpleStore() { + StructuredGraph graph = processMethod("testSimpleStoreSnippet", false); + assertDeepEquals(1, graph.getNodes().filter(StoreFieldNode.class).count()); + } + + public static int testValueProxySnippet(boolean b, TestObject o) { + int sum = 0; + if (b) { + sum += o.x; + } else { + TestObject3 p = (TestObject3) o; + sum += p.x; + } + sum += o.x; + return sum; + } + + @Test + public void testValueProxy() { + StructuredGraph graph = processMethod("testValueProxySnippet", false); + assertDeepEquals(2, graph.getNodes().filter(LoadFieldNode.class).count()); + } + + ReturnNode getReturn(String snippet, boolean doLowering) { + StructuredGraph graph = processMethod(snippet, doLowering); + assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count()); + return graph.getNodes(ReturnNode.TYPE).first(); + } + + protected StructuredGraph processMethod(String snippet, boolean doLowering) { + StructuredGraph graph = parseEager(getResolvedJavaMethod(snippet), AllowAssumptions.NO); + HighTierContext context = getDefaultHighTierContext(); + new InliningPhase(new CanonicalizerPhase()).apply(graph, context); + if (doLowering) { + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + } + new EarlyReadEliminationPhase(new CanonicalizerPhase()).apply(graph, context); + return graph; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java 2016-12-07 13:48:41.367330937 -0800 @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2011, 2014, 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.core.test.ea; + +import jdk.vm.ci.meta.JavaConstant; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.loop.DefaultLoopPolicies; +import org.graalvm.compiler.loop.phases.LoopFullUnrollPhase; +import org.graalvm.compiler.loop.phases.LoopPeelingPhase; +import org.graalvm.compiler.nodes.extended.ValueAnchorNode; +import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode; +import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; + +/** + * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct + * values. + */ +public class EscapeAnalysisTest extends EATestBase { + + @Test + public void test1() { + testEscapeAnalysis("test1Snippet", JavaConstant.forInt(101), false); + } + + public static int test1Snippet() { + Integer x = new Integer(101); + return x.intValue(); + } + + @Test + public void test2() { + testEscapeAnalysis("test2Snippet", JavaConstant.forInt(0), false); + } + + public static int test2Snippet() { + Integer[] x = new Integer[0]; + return x.length; + } + + @Test + public void test3() { + testEscapeAnalysis("test3Snippet", JavaConstant.NULL_POINTER, false); + } + + public static Object test3Snippet() { + Integer[] x = new Integer[1]; + return x[0]; + } + + @Test + public void testMonitor() { + testEscapeAnalysis("testMonitorSnippet", JavaConstant.forInt(0), false); + } + + public static int testMonitorSnippet() { + Integer x = new Integer(0); + Double y = new Double(0); + Object z = new Object(); + synchronized (x) { + synchronized (y) { + synchronized (z) { + notInlineable(); + } + } + } + return x.intValue(); + } + + @Test + public void testMonitor2() { + testEscapeAnalysis("testMonitor2Snippet", JavaConstant.forInt(0), false); + } + + /** + * This test case differs from the last one in that it requires inlining within a synchronized + * region. + */ + public static int testMonitor2Snippet() { + Integer x = new Integer(0); + Double y = new Double(0); + Object z = new Object(); + synchronized (x) { + synchronized (y) { + synchronized (z) { + notInlineable(); + return x.intValue(); + } + } + } + } + + @Test + public void testMerge() { + testEscapeAnalysis("testMerge1Snippet", JavaConstant.forInt(0), true); + } + + public static int testMerge1Snippet(int a) { + TestClassInt obj = new TestClassInt(1, 0); + if (a < 0) { + obj.x = obj.x + 1; + } else { + obj.x = obj.x + 2; + obj.y = 0; + } + if (obj.x > 1000) { + return 1; + } + return obj.y; + } + + @Test + public void testSimpleLoop() { + testEscapeAnalysis("testSimpleLoopSnippet", JavaConstant.forInt(1), false); + } + + public int testSimpleLoopSnippet(int a) { + TestClassInt obj = new TestClassInt(1, 2); + for (int i = 0; i < a; i++) { + notInlineable(); + } + return obj.x; + } + + @Test + public void testModifyingLoop() { + testEscapeAnalysis("testModifyingLoopSnippet", JavaConstant.forInt(1), false); + } + + public int testModifyingLoopSnippet(int a) { + TestClassInt obj = new TestClassInt(1, 2); + for (int i = 0; i < a; i++) { + obj.x = 3; + notInlineable(); + } + return obj.x <= 3 ? 1 : 0; + } + + @Test + public void testMergeAllocationsInt() { + testEscapeAnalysis("testMergeAllocationsIntSnippet", JavaConstant.forInt(1), false); + } + + public int testMergeAllocationsIntSnippet(int a) { + TestClassInt obj; + if (a < 0) { + obj = new TestClassInt(1, 2); + notInlineable(); + } else { + obj = new TestClassInt(1, 2); + notInlineable(); + } + return obj.x <= 3 ? 1 : 0; + } + + @Test + public void testMergeAllocationsObj() { + testEscapeAnalysis("testMergeAllocationsObjSnippet", JavaConstant.forInt(1), false); + } + + public int testMergeAllocationsObjSnippet(int a) { + TestClassObject obj; + Integer one = 1; + Integer two = 2; + Integer three = 3; + if (a < 0) { + obj = new TestClassObject(one, two); + notInlineable(); + } else { + obj = new TestClassObject(one, three); + notInlineable(); + } + return ((Integer) obj.x).intValue() <= 3 ? 1 : 0; + } + + @Test + public void testMergeAllocationsObjCirc() { + testEscapeAnalysis("testMergeAllocationsObjCircSnippet", JavaConstant.forInt(1), false); + } + + public int testMergeAllocationsObjCircSnippet(int a) { + TestClassObject obj; + Integer one = 1; + Integer two = 2; + Integer three = 3; + if (a < 0) { + obj = new TestClassObject(one); + obj.y = obj; + obj.y = two; + notInlineable(); + } else { + obj = new TestClassObject(one); + obj.y = obj; + obj.y = three; + notInlineable(); + } + return ((Integer) obj.x).intValue() <= 3 ? 1 : 0; + } + + static class MyException extends RuntimeException { + + private static final long serialVersionUID = 0L; + + protected Integer value; + + MyException(Integer value) { + super((Throwable) null); + this.value = value; + } + + @SuppressWarnings("sync-override") + @Override + public final Throwable fillInStackTrace() { + return null; + } + } + + @Test + public void testMergeAllocationsException() { + testEscapeAnalysis("testMergeAllocationsExceptionSnippet", JavaConstant.forInt(1), false); + } + + public int testMergeAllocationsExceptionSnippet(int a) { + MyException obj; + Integer one = 1; + if (a < 0) { + obj = new MyException(one); + notInlineable(); + } else { + obj = new MyException(one); + notInlineable(); + } + return obj.value <= 3 ? 1 : 0; + } + + @Test + public void testCheckCast() { + testEscapeAnalysis("testCheckCastSnippet", getSnippetReflection().forObject(TestClassObject.class), false); + } + + public Object testCheckCastSnippet() { + TestClassObject obj = new TestClassObject(TestClassObject.class); + TestClassObject obj2 = new TestClassObject(obj); + return ((TestClassObject) obj2.x).x; + } + + @Test + public void testInstanceOf() { + testEscapeAnalysis("testInstanceOfSnippet", JavaConstant.forInt(1), false); + } + + public boolean testInstanceOfSnippet() { + TestClassObject obj = new TestClassObject(TestClassObject.class); + TestClassObject obj2 = new TestClassObject(obj); + return obj2.x instanceof TestClassObject; + } + + @SuppressWarnings("unused") + public static void testNewNodeSnippet() { + new ValueAnchorNode(null); + } + + /** + * This test makes sure that the allocation of a {@link Node} can be removed. It therefore also + * tests the intrinsification of {@link Object#getClass()}. + */ + @Test + public void testNewNode() { + testEscapeAnalysis("testNewNodeSnippet", null, false); + } + + private static final TestClassObject staticObj = new TestClassObject(); + + public static Object testFullyUnrolledLoopSnippet() { + /* + * This tests a case that can appear if PEA is performed both before and after loop + * unrolling/peeling: If the VirtualInstanceNode is not duplicated correctly with the loop, + * the resulting object will reference itself, and not a second (different) object. + */ + TestClassObject obj = staticObj; + for (int i = 0; i < 2; i++) { + obj = new TestClassObject(obj); + } + return obj.x; + } + + @Test + public void testFullyUnrolledLoop() { + prepareGraph("testFullyUnrolledLoopSnippet", false); + new LoopFullUnrollPhase(new CanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context); + new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context); + Assert.assertEquals(1, returnNodes.size()); + Assert.assertTrue(returnNodes.get(0).result() instanceof AllocatedObjectNode); + CommitAllocationNode commit = ((AllocatedObjectNode) returnNodes.get(0).result()).getCommit(); + Assert.assertEquals(2, commit.getValues().size()); + Assert.assertEquals(1, commit.getVirtualObjects().size()); + Assert.assertTrue("non-cyclic data structure expected", commit.getVirtualObjects().get(0) != commit.getValues().get(0)); + } + + @SuppressWarnings("unused") private static Object staticField; + + private static TestClassObject inlinedPart(TestClassObject obj) { + TestClassObject ret = new TestClassObject(obj); + staticField = null; + return ret; + } + + public static Object testPeeledLoopSnippet() { + TestClassObject obj = staticObj; + int i = 0; + do { + obj = inlinedPart(obj); + } while (i++ < 10); + staticField = obj; + return obj.x; + } + + @Test + public void testPeeledLoop() { + prepareGraph("testPeeledLoopSnippet", false); + new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph, getDefaultHighTierContext()); + new SchedulePhase().apply(graph); + } + + public static void testDeoptMonitorSnippetInner(Object o2, Object t, int i) { + staticField = null; + if (i == 0) { + staticField = o2; + Number n = (Number) t; + n.toString(); + } + } + + public static void testDeoptMonitorSnippet(Object t, int i) { + TestClassObject o = new TestClassObject(); + TestClassObject o2 = new TestClassObject(o); + + synchronized (o) { + testDeoptMonitorSnippetInner(o2, t, i); + } + } + + @Test + public void testDeoptMonitor() { + test("testDeoptMonitorSnippet", new Object(), 0); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/NestedBoxingTest.java 2016-12-07 13:48:41.635342718 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test.ea; + +import org.junit.Test; + +public class NestedBoxingTest extends EATestBase { + + @Test + public void testSimpleMerge() { + testEscapeAnalysis("testSnippet", null, false); + } + + public static int testSnippet(int n) { + Integer cur = 1; + Integer prev = 1; + + for (int i = 0; i < n; i++) { + Integer next = prev + cur; + prev = cur; + cur = next; + } + return cur; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java 2016-12-07 13:48:41.899354323 -0800 @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2015, 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.core.test.ea; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.code.SourceStackTraceBailoutException; +import org.graalvm.compiler.core.test.GraalCompilerTest; + +public class PEAAssertionsTest extends GraalCompilerTest { + + public static Object field; + + public static void snippet1(int i) { + Integer object = new Integer(i); + GraalDirectives.ensureVirtualized(object); + } + + @Test + public void test1() { + test("snippet1", 1); + } + + public static void snippet2(int i) { + Integer object = new Integer(i); + GraalDirectives.ensureVirtualized(object); + field = object; // assert here + } + + @Test(expected = SourceStackTraceBailoutException.class) + public void test2() { + test("snippet2", 1); + } + + public static void snippet3(int i) { + Integer object = new Integer(i); + field = object; + GraalDirectives.ensureVirtualized(object); // assert here + } + + @Test(expected = SourceStackTraceBailoutException.class) + public void test3() { + test("snippet3", 1); + } + + public static void snippetHere1(int i) { + Integer object = new Integer(i); + GraalDirectives.ensureVirtualizedHere(object); + } + + @Test + public void testHere1() { + test("snippetHere1", 1); + } + + public static void snippetHere2(int i) { + Integer object = new Integer(i); + GraalDirectives.ensureVirtualizedHere(object); + field = object; + } + + @Test + public void testHere2() { + test("snippetHere2", 1); + } + + public static void snippetHere3(int i) { + Integer object = new Integer(i); + field = object; + GraalDirectives.ensureVirtualizedHere(object); // assert here + } + + @Test(expected = SourceStackTraceBailoutException.class) + public void testHere3() { + test("snippetHere3", 1); + } + + public static void snippetBoxing1(int i) { + Integer object = i; + GraalDirectives.ensureVirtualizedHere(object); // assert here + } + + @Test(expected = SourceStackTraceBailoutException.class) + public void testBoxing1() { + test("snippetBoxing1", 1); + } + + public static void snippetBoxing2(int i) { + Integer object = i; + GraalDirectives.ensureVirtualized(object); // assert here + field = object; + } + + @Test(expected = SourceStackTraceBailoutException.class) + public void testBoxing2() { + test("snippetBoxing2", 1); + } + + public static void snippetControlFlow1(boolean b, int i) { + Integer object = new Integer(i); + if (b) { + GraalDirectives.ensureVirtualized(object); + } + GraalDirectives.controlFlowAnchor(); + field = object; + } + + @Test + public void testControlFlow1() { + test("snippetControlFlow1", true, 1); + } + + public static void snippetControlFlow2(boolean b, int i) { + Integer object = new Integer(i); + if (b) { + GraalDirectives.ensureVirtualized(object); + } else { + GraalDirectives.ensureVirtualized(object); + } + GraalDirectives.controlFlowAnchor(); + field = object; // assert here + } + + @Test(expected = SourceStackTraceBailoutException.class) + public void testControlFlow2() { + test("snippetControlFlow2", true, 1); + } + + public static void snippetControlFlow3(boolean b, int i) { + Integer object = new Integer(i); + GraalDirectives.ensureVirtualized(object); + if (b) { + field = 1; + } else { + field = 2; + } + GraalDirectives.controlFlowAnchor(); + field = object; // assert here + } + + @Test(expected = SourceStackTraceBailoutException.class) + public void testControlFlow3() { + test("snippetControlFlow3", true, 1); + } + + public static void snippetControlFlow4(boolean b, int i) { + Integer object = new Integer(i); + if (b) { + field = object; + } else { + field = 2; + } + GraalDirectives.ensureVirtualized(object); // assert here + } + + @Test(expected = SourceStackTraceBailoutException.class) + public void testControlFlow4() { + test("snippetControlFlow4", true, 1); + } + + public static void snippetControlFlow5(boolean b, int i) { + Integer object = new Integer(i); + if (b) { + field = object; + } else { + field = 2; + } + GraalDirectives.ensureVirtualizedHere(object); // assert here + } + + @Test(expected = SourceStackTraceBailoutException.class) + public void testControlFlow5() { + test("snippetControlFlow5", true, 1); + } + + public static final class TestClass { + Object a; + Object b; + } + + public static void snippetIndirect1(boolean b, int i) { + Integer object = new Integer(i); + TestClass t = new TestClass(); + t.a = object; + GraalDirectives.ensureVirtualized(object); + + if (b) { + field = t; // assert here + } else { + field = 2; + } + } + + @Test(expected = SourceStackTraceBailoutException.class) + public void testIndirect1() { + test("snippetIndirect1", true, 1); + } + + public static void snippetIndirect2(boolean b, int i) { + Integer object = new Integer(i); + TestClass t = new TestClass(); + t.a = object; + GraalDirectives.ensureVirtualized(t); + + if (b) { + field = object; + } else { + field = 2; + } + } + + @Test + public void testIndirect2() { + test("snippetIndirect2", true, 1); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java 2016-12-07 13:48:42.165366016 -0800 @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2011, 2015, 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.core.test.ea; + +import org.junit.Test; + +import sun.misc.Unsafe; + +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.extended.UnsafeLoadNode; +import org.graalvm.compiler.nodes.java.LoadIndexedNode; +import org.graalvm.compiler.nodes.java.StoreIndexedNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; + +public class PEAReadEliminationTest extends EarlyReadEliminationTest { + + public static int testIndexed1Snippet(int[] array) { + array[1] = 1; + array[2] = 2; + array[3] = 3; + array[4] = 4; + array[5] = 5; + array[6] = 6; + return array[1] + array[2] + array[3] + array[4] + array[5] + array[6]; + } + + @Test + public void testIndexed1() { + StructuredGraph graph = processMethod("testIndexed1Snippet", false); + assertDeepEquals(0, graph.getNodes().filter(LoadIndexedNode.class).count()); + } + + public static int testIndexed2Snippet(int v, int[] array) { + array[1] = 1; + array[2] = 2; + array[3] = 3; + array[v] = 0; + array[4] = 4; + array[5] = 5; + array[6] = 6; + array[4] = 4; + array[5] = 5; + array[6] = 6; + return array[1] + array[2] + array[3] + array[4] + array[5] + array[6]; + } + + @Test + public void testIndexed2() { + StructuredGraph graph = processMethod("testIndexed2Snippet", false); + assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); + assertDeepEquals(7, graph.getNodes().filter(StoreIndexedNode.class).count()); + } + + public static int testIndexed3Snippet(int v, int[] array, short[] array2) { + array[1] = 1; + array2[1] = 1; + array[2] = 2; + array2[2] = 2; + array[3] = 3; + array2[3] = 3; + array[v] = 0; + array[4] = 4; + array2[4] = 4; + array[5] = 5; + array2[5] = 5; + array[6] = 6; + array2[6] = 6; + return array[1] + array[2] + array[3] + array[4] + array[5] + array[6] + array2[1] + array2[2] + array2[3] + array2[4] + array2[5] + array2[6]; + } + + @Test + public void testIndexed3() { + StructuredGraph graph = processMethod("testIndexed3Snippet", false); + assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); + } + + private static native void nonInlineable(); + + public static int testIndexed4Snippet(int[] array) { + array[1] = 1; + array[2] = 2; + array[3] = 3; + nonInlineable(); + array[4] = 4; + array[5] = 5; + array[6] = 6; + return array[1] + array[2] + array[3] + array[4] + array[5] + array[6]; + } + + @Test + public void testIndexed4() { + StructuredGraph graph = processMethod("testIndexed4Snippet", false); + assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); + } + + private static final long offsetInt1 = Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * 1; + private static final long offsetInt2 = Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * 2; + + public static int testUnsafe1Snippet(int v, int[] array) { + int s = UNSAFE.getInt(array, offsetInt1); + UNSAFE.putInt(array, offsetInt1, v); + UNSAFE.putInt(array, offsetInt2, v); + return s + UNSAFE.getInt(array, offsetInt1) + UNSAFE.getInt(array, offsetInt2); + } + + @Test + public void testUnsafe1() { + StructuredGraph graph = processMethod("testUnsafe1Snippet", false); + assertDeepEquals(1, graph.getNodes().filter(UnsafeLoadNode.class).count()); + } + + public static int testUnsafe2Snippet(int v, Object array) { + int s = UNSAFE.getInt(array, offsetInt1); + UNSAFE.putInt(array, offsetInt1, v); + UNSAFE.putInt(array, offsetInt2, v); + return s + UNSAFE.getInt(array, offsetInt1) + UNSAFE.getInt(array, offsetInt2); + } + + @Test + public void testUnsafe2() { + StructuredGraph graph = processMethod("testUnsafe2Snippet", false); + assertDeepEquals(3, graph.getNodes().filter(UnsafeLoadNode.class).count()); + } + + private static final long offsetObject1 = Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * 1; + private static final long offsetObject2 = Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * 2; + + public static int testUnsafe3Snippet(int v, Object[] array) { + int s = (Integer) UNSAFE.getObject(array, offsetObject1); + UNSAFE.putObject(array, offsetObject1, v); + UNSAFE.putObject(array, offsetObject2, v); + return s + (Integer) UNSAFE.getObject(array, offsetObject1) + (Integer) UNSAFE.getObject(array, offsetObject2); + } + + @Test + public void testUnsafe3() { + StructuredGraph graph = processMethod("testUnsafe3Snippet", false); + assertDeepEquals(1, graph.getNodes().filter(UnsafeLoadNode.class).count()); + } + + public static int testUnsafe4Snippet(int v, Object[] array) { + int s = (Integer) UNSAFE.getObject(array, offsetObject1); + UNSAFE.putObject(array, offsetObject1, v); + UNSAFE.putObject(array, offsetObject2, v); + array[v] = null; + return s + (Integer) UNSAFE.getObject(array, offsetObject1) + (Integer) UNSAFE.getObject(array, offsetObject2); + } + + @Test + public void testUnsafe4() { + StructuredGraph graph = processMethod("testUnsafe4Snippet", false); + assertDeepEquals(3, graph.getNodes().filter(UnsafeLoadNode.class).count()); + } + + private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1; + private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2; + + public static int testUnsafe5Snippet(int v, long[] array) { + int s = UNSAFE.getInt(array, offsetLong1); + UNSAFE.putInt(array, offsetLong1, v); + UNSAFE.putInt(array, offsetLong2, v); + return s + UNSAFE.getInt(array, offsetLong1) + UNSAFE.getInt(array, offsetLong2); + } + + @Test + public void testUnsafe5() { + StructuredGraph graph = processMethod("testUnsafe5Snippet", false); + assertDeepEquals(1, graph.getNodes().filter(UnsafeLoadNode.class).count()); + } + + @Override + protected StructuredGraph processMethod(final String snippet, boolean doLowering) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + HighTierContext context = getDefaultHighTierContext(); + new InliningPhase(new CanonicalizerPhase()).apply(graph, context); + new PartialEscapePhase(false, true, new CanonicalizerPhase(), null).apply(graph, context); + return graph; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java 2016-12-07 13:48:42.430377665 -0800 @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2011, 2012, 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.core.test.ea; + +import java.lang.ref.SoftReference; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.test.TypeSystemTest; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.nodes.extended.BoxNode; +import org.graalvm.compiler.nodes.extended.UnboxNode; +import org.graalvm.compiler.nodes.java.LoadFieldNode; +import org.graalvm.compiler.nodes.java.LoadIndexedNode; +import org.graalvm.compiler.nodes.java.NewArrayNode; +import org.graalvm.compiler.nodes.java.NewInstanceNode; +import org.graalvm.compiler.nodes.java.StoreFieldNode; +import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; + +/** + * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct + * values. + */ +public class PartialEscapeAnalysisTest extends EATestBase { + + public static class TestObject { + + public int x; + public int y; + + public TestObject(int x, int y) { + this.x = x; + this.y = y; + } + } + + public static class TestObject2 { + + public Object x; + public Object y; + + public TestObject2(Object x, Object y) { + this.x = x; + this.y = y; + } + } + + @Test + public void test1() { + testPartialEscapeAnalysis("test1Snippet", 0.25, 1); + } + + @SuppressWarnings("all") + public static Object test1Snippet(int a, int b, Object x, Object y) { + TestObject2 obj = new TestObject2(x, y); + if (a < 0) { + if (b < 0) { + return obj; + } else { + return obj.y; + } + } else { + return obj.x; + } + } + + @Test + public void test2() { + testPartialEscapeAnalysis("test2Snippet", 1.5, 3, LoadIndexedNode.class); + } + + public static Object test2Snippet(int a, Object x, Object y, Object z) { + TestObject2 obj = new TestObject2(x, y); + obj.x = new TestObject2(obj, z); + if (a < 0) { + ((TestObject2) obj.x).y = null; + obj.y = null; + return obj; + } else { + ((TestObject2) obj.x).y = Integer.class; + ((TestObject2) obj.x).x = null; + return obj.x; + } + } + + @Test + public void test3() { + testPartialEscapeAnalysis("test3Snippet", 0.5, 1, StoreFieldNode.class, LoadFieldNode.class); + } + + public static Object test3Snippet(int a) { + if (a < 0) { + TestObject obj = new TestObject(1, 2); + obj.x = 123; + obj.y = 234; + obj.x = 123111; + obj.y = new Integer(123).intValue(); + return obj; + } else { + return null; + } + } + + @Test + public void testArrayCopy() { + testPartialEscapeAnalysis("testArrayCopySnippet", 0, 0); + } + + public static Object[] array = new Object[]{1, 2, 3, 4, 5, "asdf", "asdf"}; + + public static Object testArrayCopySnippet(int a) { + Object[] tmp = new Object[]{a != 1 ? array[a] : null}; + Object[] tmp2 = new Object[5]; + System.arraycopy(tmp, 0, tmp2, 4, 1); + return tmp2[4]; + } + + @Test + @Ignore + public void testCache() { + testPartialEscapeAnalysis("testCacheSnippet", 0.75, 1); + } + + public static class CacheKey { + + private final int idx; + private final Object ref; + + public CacheKey(int idx, Object ref) { + this.idx = idx; + this.ref = ref; + } + + @Override + public int hashCode() { + return 31 * idx + ref.hashCode(); + } + + public synchronized boolean equals(CacheKey other) { + return idx == other.idx && ref == other.ref; + } + } + + public static CacheKey cacheKey = null; + public static Object value = null; + + private static native Object createValue(CacheKey key); + + public static Object testCacheSnippet(int idx, Object ref) { + CacheKey key = new CacheKey(idx, ref); + if (!key.equals(cacheKey)) { + cacheKey = key; + value = createValue(key); + } + return value; + } + + public static int testReference1Snippet(Object a) { + SoftReference softReference = new SoftReference<>(a); + if (softReference.get().hashCode() == 0) { + return 1; + } else { + return 2; + } + } + + @Test + public void testReference1() { + prepareGraph("testReference1Snippet", false); + assertDeepEquals(1, graph.getNodes().filter(NewInstanceNode.class).count()); + } + + public static int testCanonicalizeSnippet(int v) { + CacheKey key = new CacheKey(v, null); + + CacheKey key2; + if (key.idx == v) { + key2 = new CacheKey(v, null); + } else { + key2 = null; + } + return key2.idx; + } + + @Test + public void testCanonicalize() { + prepareGraph("testCanonicalizeSnippet", false); + assertTrue(graph.getNodes().filter(ReturnNode.class).count() == 1); + assertTrue(graph.getNodes().filter(ReturnNode.class).first().result() == graph.getParameter(0)); + } + + public static int testBoxLoopSnippet(int n) { + Integer sum = 0; + for (Integer i = 0; i < n; i++) { + if (sum == null) { + sum = null; + } else { + sum += i; + } + } + return sum; + } + + @Test + public void testBoxLoop() { + testPartialEscapeAnalysis("testBoxLoopSnippet", 0, 0, BoxNode.class, UnboxNode.class); + } + + static volatile int staticField; + static boolean executedDeoptimizeDirective; + + static class A { + String field; + } + + public static Object deoptWithVirtualObjectsSnippet() { + A a = new A(); + a.field = "field"; + + staticField = 5; + if (staticField == 5) { + GraalDirectives.deoptimize(); + executedDeoptimizeDirective = true; + } + + return a.field; + } + + /** + * Tests deoptimizing with virtual objects in debug info. + */ + @Test + public void testDeoptWithVirtualObjects() { + assertFalse(executedDeoptimizeDirective); + test("deoptWithVirtualObjectsSnippet"); + assertTrue(executedDeoptimizeDirective); + } + + @SafeVarargs + protected final void testPartialEscapeAnalysis(String snippet, double expectedProbability, int expectedCount, Class... invalidNodeClasses) { + prepareGraph(snippet, false); + for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.TYPE)) { + merge.setStateAfter(null); + } + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase().apply(graph, context); + try { + Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", graph.getNodes().filter(NewInstanceNode.class).isEmpty()); + Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", graph.getNodes().filter(NewArrayNode.class).isEmpty()); + + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); + double probabilitySum = 0; + int materializeCount = 0; + for (CommitAllocationNode materialize : graph.getNodes().filter(CommitAllocationNode.class)) { + probabilitySum += cfg.blockFor(materialize).probability() * materialize.getVirtualObjects().size(); + materializeCount += materialize.getVirtualObjects().size(); + } + Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount); + Assert.assertEquals("unexpected probability of MaterializeObjectNodes", expectedProbability, probabilitySum, 0.01); + for (Node node : graph.getNodes()) { + for (Class clazz : invalidNodeClasses) { + Assert.assertFalse("instance of invalid class: " + clazz.getSimpleName(), clazz.isInstance(node) && node.usages().isNotEmpty()); + } + } + } catch (AssertionError e) { + TypeSystemTest.outputGraph(graph, snippet + ": " + e.getMessage()); + throw e; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PoorMansEATest.java 2016-12-07 13:48:42.696389358 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2014, 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.core.test.ea; + +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.java.AbstractNewObjectNode; +import org.graalvm.compiler.nodes.java.NewInstanceNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/** + * Tests {@link AbstractNewObjectNode#simplify(org.graalvm.compiler.graph.spi.SimplifierTool)}. + * + */ +public class PoorMansEATest extends GraalCompilerTest { + public static class A { + public A obj; + } + + public static A test1Snippet() { + A a = new A(); + a.obj = a; + return null; + } + + @Test + public void test1() { + test("test1Snippet"); + } + + @SuppressWarnings("try") + private void test(final String snippet) { + try (Scope s = Debug.scope("PoorMansEATest", new DebugDumpScope(snippet))) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + HighTierContext highTierContext = getDefaultHighTierContext(); + new InliningPhase(new CanonicalizerPhase()).apply(graph, highTierContext); + PhaseContext context = new PhaseContext(getProviders()); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + + // remove framestates in order to trigger the simplification. + cleanup: for (FrameState fs : graph.getNodes(FrameState.TYPE).snapshot()) { + for (Node input : fs.inputs()) { + if (input instanceof NewInstanceNode) { + fs.replaceAtUsages(null); + fs.safeDelete(); + continue cleanup; + } + } + } + new CanonicalizerPhase().apply(graph, context); + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java 2016-12-07 13:48:42.962401051 -0800 @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2011, 2014, 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.core.test.ea; + +import jdk.vm.ci.meta.JavaConstant; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.ValuePhiNode; +import org.graalvm.compiler.nodes.java.LoadFieldNode; + +public class UnsafeEATest extends EATestBase { + + public static int zero = 0; + + private static final long fieldOffset1; + private static final long fieldOffset2; + + static { + try { + long localFieldOffset1 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("x")); + // Make the fields 8 byte aligned (Required for testing setLong on Architectures which + // does not support unaligned memory access + if (localFieldOffset1 % 8 == 0) { + fieldOffset1 = localFieldOffset1; + fieldOffset2 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("y")); + } else { + fieldOffset1 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("y")); + fieldOffset2 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("z")); + } + assert fieldOffset2 == fieldOffset1 + 4; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Test + public void testSimpleInt() { + testEscapeAnalysis("testSimpleIntSnippet", JavaConstant.forInt(101), false); + } + + public static int testSimpleIntSnippet() { + TestClassInt x = new TestClassInt(); + UNSAFE.putInt(x, fieldOffset1, 101); + return UNSAFE.getInt(x, fieldOffset1); + } + + @Test + public void testMaterializedInt() { + test("testMaterializedIntSnippet"); + } + + public static TestClassInt testMaterializedIntSnippet() { + TestClassInt x = new TestClassInt(); + UNSAFE.putInt(x, fieldOffset1, 101); + return x; + } + + @Test + public void testSimpleDouble() { + testEscapeAnalysis("testSimpleDoubleSnippet", JavaConstant.forDouble(10.1), false); + } + + public static double testSimpleDoubleSnippet() { + TestClassInt x = new TestClassInt(); + UNSAFE.putDouble(x, fieldOffset1, 10.1); + return UNSAFE.getDouble(x, fieldOffset1); + } + + @Test + public void testMergedDouble() { + testEscapeAnalysis("testMergedDoubleSnippet", null, false); + Assert.assertEquals(1, returnNodes.size()); + Assert.assertTrue(returnNodes.get(0).result() instanceof ValuePhiNode); + PhiNode phi = (PhiNode) returnNodes.get(0).result(); + Assert.assertTrue(phi.valueAt(0) instanceof LoadFieldNode); + Assert.assertTrue(phi.valueAt(1) instanceof LoadFieldNode); + } + + public static double testMergedDoubleSnippet(boolean a) { + TestClassInt x; + if (a) { + x = new TestClassInt(0, 0); + UNSAFE.putDouble(x, fieldOffset1, doubleField); + } else { + x = new TestClassInt(); + UNSAFE.putDouble(x, fieldOffset1, doubleField2); + } + return UNSAFE.getDouble(x, fieldOffset1); + } + + @Test + public void testMaterializedDouble() { + test("testMaterializedDoubleSnippet"); + } + + public static TestClassInt testMaterializedDoubleSnippet() { + TestClassInt x = new TestClassInt(); + UNSAFE.putDouble(x, fieldOffset1, 10.1); + return x; + } + + @Test + public void testDeoptDoubleVar() { + test("testDeoptDoubleVarSnippet"); + } + + public static double doubleField = 10.1e99; + public static double doubleField2; + + public static TestClassInt testDeoptDoubleVarSnippet() { + TestClassInt x = new TestClassInt(); + UNSAFE.putDouble(x, fieldOffset1, doubleField); + doubleField2 = 123; + try { + doubleField = ((int) UNSAFE.getDouble(x, fieldOffset1)) / zero; + } catch (RuntimeException e) { + return x; + } + return x; + } + + @Test + public void testDeoptDoubleConstant() { + test("testDeoptDoubleConstantSnippet"); + } + + public static TestClassInt testDeoptDoubleConstantSnippet() { + TestClassInt x = new TestClassInt(); + UNSAFE.putDouble(x, fieldOffset1, 10.123); + doubleField2 = 123; + try { + doubleField = ((int) UNSAFE.getDouble(x, fieldOffset1)) / zero; + } catch (RuntimeException e) { + return x; + } + return x; + } + + @Test + public void testDeoptLongVar() { + test("testDeoptLongVarSnippet"); + } + + public static long longField = 0x133443218aaaffffL; + public static long longField2; + + public static TestClassInt testDeoptLongVarSnippet() { + TestClassInt x = new TestClassInt(); + UNSAFE.putLong(x, fieldOffset1, longField); + longField2 = 123; + try { + longField = UNSAFE.getLong(x, fieldOffset1) / zero; + } catch (RuntimeException e) { + return x; + } + return x; + } + + @Test + public void testDeoptLongConstant() { + test("testDeoptLongConstantSnippet"); + } + + public static TestClassInt testDeoptLongConstantSnippet() { + TestClassInt x = new TestClassInt(); + UNSAFE.putLong(x, fieldOffset1, 0x2222222210123L); + longField2 = 123; + try { + longField = UNSAFE.getLong(x, fieldOffset1) / zero; + } catch (RuntimeException e) { + return x; + } + return x; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java 2016-12-07 13:48:43.229412788 -0800 @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2012, 2016, 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.core.test.inlining; + +import jdk.vm.ci.code.site.InfopointReason; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.FullInfopointNode; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +public class InliningTest extends GraalCompilerTest { + + @Test + public void testInvokeStaticInlining() { + assertInlined(getGraph("invokeStaticSnippet", false)); + assertInlined(getGraph("invokeStaticOnInstanceSnippet", false)); + } + + @SuppressWarnings("all") + public static Boolean invokeStaticSnippet(boolean value) { + return Boolean.valueOf(value); + } + + @SuppressWarnings({"all", "static"}) + public static Boolean invokeStaticOnInstanceSnippet(Boolean obj, boolean value) { + return obj.valueOf(value); + } + + @Test + public void testStaticBindableInlining() { + assertInlined(getGraph("invokeConstructorSnippet", false)); + assertInlined(getGraph("invokeFinalMethodSnippet", false)); + assertInlined(getGraph("invokeMethodOnFinalClassSnippet", false)); + assertInlined(getGraph("invokeMethodOnStaticFinalFieldSnippet", false)); + } + + @Ignore("would need read elimination/EA before inlining") + @Test + public void testDependentStaticBindableInlining() { + assertInlined(getGraph("invokeMethodOnFinalFieldSnippet", false)); + assertInlined(getGraph("invokeMethodOnFieldSnippet", false)); + } + + @Test + public void testStaticBindableInliningIP() { + assertManyMethodInfopoints(assertInlined(getGraph("invokeConstructorSnippet", true))); + assertManyMethodInfopoints(assertInlined(getGraph("invokeFinalMethodSnippet", true))); + assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFinalClassSnippet", true))); + assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnStaticFinalFieldSnippet", true))); + } + + @Ignore("would need read elimination/EA before inlining") + @Test + public void testDependentStaticBindableInliningIP() { + assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFinalFieldSnippet", true))); + assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFieldSnippet", true))); + } + + @SuppressWarnings("all") + public static Object invokeConstructorSnippet(int value) { + return new SuperClass(value); + } + + @SuppressWarnings("all") + public static int invokeFinalMethodSnippet(SuperClass superClass, SubClassA subClassA, FinalSubClass finalSubClass) { + return superClass.publicFinalMethod() + subClassA.publicFinalMethod() + finalSubClass.publicFinalMethod() + superClass.protectedFinalMethod() + subClassA.protectedFinalMethod() + + finalSubClass.protectedFinalMethod(); + } + + @SuppressWarnings("all") + public static int invokeMethodOnFinalClassSnippet(FinalSubClass finalSubClass) { + return finalSubClass.publicFinalMethod() + finalSubClass.publicNotOverriddenMethod() + finalSubClass.publicOverriddenMethod() + finalSubClass.protectedFinalMethod() + + finalSubClass.protectedNotOverriddenMethod() + finalSubClass.protectedOverriddenMethod(); + } + + @SuppressWarnings("all") + public static int invokeMethodOnStaticFinalFieldSnippet() { + return StaticFinalFields.NumberStaticFinalField.intValue() + StaticFinalFields.SuperClassStaticFinalField.publicOverriddenMethod() + + StaticFinalFields.FinalSubClassStaticFinalField.publicOverriddenMethod() + StaticFinalFields.SingleImplementorStaticFinalField.publicOverriddenMethod() + + StaticFinalFields.MultipleImplementorsStaticFinalField.publicOverriddenMethod() + StaticFinalFields.SubClassAStaticFinalField.publicOverriddenMethod() + + StaticFinalFields.SubClassBStaticFinalField.publicOverriddenMethod() + StaticFinalFields.SubClassCStaticFinalField.publicOverriddenMethod(); + } + + @SuppressWarnings("all") + public static int invokeMethodOnFinalFieldSnippet() { + FinalFields fields = new FinalFields(); + return fields.numberFinalField.intValue() + fields.superClassFinalField.publicOverriddenMethod() + fields.finalSubClassFinalField.publicOverriddenMethod() + + fields.singleImplementorFinalField.publicOverriddenMethod() + fields.multipleImplementorsFinalField.publicOverriddenMethod() + + fields.subClassAFinalField.publicOverriddenMethod() + fields.subClassBFinalField.publicOverriddenMethod() + fields.subClassCFinalField.publicOverriddenMethod(); + } + + @SuppressWarnings("all") + public static int invokeMethodOnFieldSnippet() { + Fields fields = new Fields(); + return fields.numberField.intValue() + fields.superClassField.publicOverriddenMethod() + fields.finalSubClassField.publicOverriddenMethod() + + fields.singleImplementorField.publicOverriddenMethod() + fields.multipleImplementorsField.publicOverriddenMethod() + fields.subClassAField.publicOverriddenMethod() + + fields.subClassBField.publicOverriddenMethod() + fields.subClassCField.publicOverriddenMethod(); + } + + public interface Attributes { + + int getLength(); + } + + public class NullAttributes implements Attributes { + + @Override + public int getLength() { + return 0; + } + + } + + public class TenAttributes implements Attributes { + + @Override + public int getLength() { + return 10; + } + + } + + public int getAttributesLength(Attributes a) { + return a.getLength(); + } + + @Test + public void testGuardedInline() { + NullAttributes nullAttributes = new NullAttributes(); + for (int i = 0; i < 10000; i++) { + getAttributesLength(nullAttributes); + } + getAttributesLength(new TenAttributes()); + + test("getAttributesLength", nullAttributes); + test("getAttributesLength", (Object) null); + } + + @Test + public void testClassHierarchyAnalysis() { + assertInlined(getGraph("invokeLeafClassMethodSnippet", false)); + assertInlined(getGraph("invokeConcreteMethodSnippet", false)); + assertInlined(getGraph("invokeSingleImplementorInterfaceSnippet", false)); + // assertInlined(getGraph("invokeConcreteInterfaceMethodSnippet", false)); + + assertNotInlined(getGraph("invokeOverriddenPublicMethodSnippet", false)); + assertNotInlined(getGraph("invokeOverriddenProtectedMethodSnippet", false)); + assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", false)); + } + + @Test + public void testClassHierarchyAnalysisIP() { + assertManyMethodInfopoints(assertInlined(getGraph("invokeLeafClassMethodSnippet", true))); + assertManyMethodInfopoints(assertInlined(getGraph("invokeConcreteMethodSnippet", true))); + assertManyMethodInfopoints(assertInlined(getGraph("invokeSingleImplementorInterfaceSnippet", true))); + //@formatter:off + // assertInlineInfopoints(assertInlined(getGraph("invokeConcreteInterfaceMethodSnippet", true))); + //@formatter:on + + assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenPublicMethodSnippet", true))); + assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenProtectedMethodSnippet", true))); + assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", true))); + } + + @SuppressWarnings("all") + public static int invokeLeafClassMethodSnippet(SubClassA subClassA) { + return subClassA.publicFinalMethod() + subClassA.publicNotOverriddenMethod() + subClassA.publicOverriddenMethod(); + } + + @SuppressWarnings("all") + public static int invokeConcreteMethodSnippet(SuperClass superClass) { + return superClass.publicNotOverriddenMethod() + superClass.protectedNotOverriddenMethod(); + } + + @SuppressWarnings("all") + public static int invokeSingleImplementorInterfaceSnippet(SingleImplementorInterface testInterface) { + return testInterface.publicNotOverriddenMethod() + testInterface.publicOverriddenMethod(); + } + + @SuppressWarnings("all") + public static int invokeConcreteInterfaceMethodSnippet(MultipleImplementorsInterface testInterface) { + return testInterface.publicNotOverriddenMethod(); + } + + @SuppressWarnings("all") + public static int invokeOverriddenInterfaceMethodSnippet(MultipleImplementorsInterface testInterface) { + return testInterface.publicOverriddenMethod(); + } + + @SuppressWarnings("all") + public static int invokeOverriddenPublicMethodSnippet(SuperClass superClass) { + return superClass.publicOverriddenMethod(); + } + + @SuppressWarnings("all") + public static int invokeOverriddenProtectedMethodSnippet(SuperClass superClass) { + return superClass.protectedOverriddenMethod(); + } + + @SuppressWarnings("try") + private StructuredGraph getGraph(final String snippet, final boolean eagerInfopointMode) { + try (Scope s = Debug.scope("InliningTest", new DebugDumpScope(snippet, true))) { + ResolvedJavaMethod method = getResolvedJavaMethod(snippet); + StructuredGraph graph = eagerInfopointMode ? parseDebug(method, AllowAssumptions.YES) : parseEager(method, AllowAssumptions.YES); + try (Scope s2 = Debug.scope("Inlining", graph)) { + PhaseSuite graphBuilderSuite = eagerInfopointMode + ? getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true)) + : getDefaultGraphBuilderSuite(); + HighTierContext context = new HighTierContext(getProviders(), graphBuilderSuite, OptimisticOptimizations.ALL); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + new CanonicalizerPhase().apply(graph, context); + new InliningPhase(new CanonicalizerPhase()).apply(graph, context); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + new CanonicalizerPhase().apply(graph, context); + new DeadCodeEliminationPhase().apply(graph); + return graph; + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + private static StructuredGraph assertInlined(StructuredGraph graph) { + return assertNotInGraph(graph, Invoke.class); + } + + private static StructuredGraph assertNotInlined(StructuredGraph graph) { + return assertInGraph(graph, Invoke.class); + } + + private static StructuredGraph assertNotInGraph(StructuredGraph graph, Class clazz) { + for (Node node : graph.getNodes()) { + if (clazz.isInstance(node)) { + fail(node.toString()); + } + } + return graph; + } + + private static StructuredGraph assertInGraph(StructuredGraph graph, Class clazz) { + for (Node node : graph.getNodes()) { + if (clazz.isInstance(node)) { + return graph; + } + } + fail("Graph does not contain a node of class " + clazz.getName()); + return graph; + } + + private static int[] countMethodInfopoints(StructuredGraph graph) { + int start = 0; + int end = 0; + for (FullInfopointNode ipn : graph.getNodes().filter(FullInfopointNode.class)) { + if (ipn.getReason() == InfopointReason.METHOD_START) { + ++start; + } else if (ipn.getReason() == InfopointReason.METHOD_END) { + ++end; + } + } + return new int[]{start, end}; + } + + private static StructuredGraph assertManyMethodInfopoints(StructuredGraph graph) { + int[] counts = countMethodInfopoints(graph); + if (counts[0] <= 1 || counts[1] <= 1) { + fail(String.format("Graph contains too few required method boundary infopoints: %d starts, %d ends.", counts[0], counts[1])); + } + return graph; + } + + private static StructuredGraph assertFewMethodInfopoints(StructuredGraph graph) { + int[] counts = countMethodInfopoints(graph); + if (counts[0] > 1 || counts[1] > 1) { + fail(String.format("Graph contains too many method boundary infopoints: %d starts, %d ends.", counts[0], counts[1])); + } + return graph; + } + + // some interfaces and classes for testing + private interface MultipleImplementorsInterface { + + int publicNotOverriddenMethod(); + + int publicOverriddenMethod(); + } + + private interface SingleImplementorInterface { + + int publicNotOverriddenMethod(); + + int publicOverriddenMethod(); + } + + private static class SuperClass implements MultipleImplementorsInterface { + + protected int value; + + SuperClass(int value) { + this.value = value; + } + + @Override + public int publicNotOverriddenMethod() { + return value; + } + + @Override + public int publicOverriddenMethod() { + return value; + } + + protected int protectedNotOverriddenMethod() { + return value; + } + + protected int protectedOverriddenMethod() { + return value; + } + + public final int publicFinalMethod() { + return value + 255; + } + + protected final int protectedFinalMethod() { + return value + 255; + } + } + + private static class SubClassA extends SuperClass implements SingleImplementorInterface { + + SubClassA(int value) { + super(value); + } + + @Override + public int publicOverriddenMethod() { + return value + 2; + } + + @Override + protected int protectedOverriddenMethod() { + return value * 2; + } + } + + private static class SubClassB extends SuperClass { + + SubClassB(int value) { + super(value); + } + + @Override + public int publicOverriddenMethod() { + return value + 3; + } + + @Override + protected int protectedOverriddenMethod() { + return value * 3; + } + } + + private static class SubClassC extends SuperClass { + + SubClassC(int value) { + super(value); + } + + @Override + public int publicOverriddenMethod() { + return value + 4; + } + + @Override + protected int protectedOverriddenMethod() { + return value * 4; + } + } + + private static final class FinalSubClass extends SuperClass { + + FinalSubClass(int value) { + super(value); + } + + @Override + public int publicOverriddenMethod() { + return value + 5; + } + + @Override + protected int protectedOverriddenMethod() { + return value * 5; + } + } + + private static final class StaticFinalFields { + + private static final Number NumberStaticFinalField = new Integer(1); + private static final SuperClass SuperClassStaticFinalField = new SubClassA(2); + private static final FinalSubClass FinalSubClassStaticFinalField = new FinalSubClass(3); + private static final SingleImplementorInterface SingleImplementorStaticFinalField = new SubClassA(4); + private static final MultipleImplementorsInterface MultipleImplementorsStaticFinalField = new SubClassC(5); + private static final SubClassA SubClassAStaticFinalField = new SubClassA(6); + private static final SubClassB SubClassBStaticFinalField = new SubClassB(7); + private static final SubClassC SubClassCStaticFinalField = new SubClassC(8); + } + + private static final class FinalFields { + + private final Number numberFinalField = new Integer(1); + private final SuperClass superClassFinalField = new SubClassA(2); + private final FinalSubClass finalSubClassFinalField = new FinalSubClass(3); + private final SingleImplementorInterface singleImplementorFinalField = new SubClassA(4); + private final MultipleImplementorsInterface multipleImplementorsFinalField = new SubClassC(5); + private final SubClassA subClassAFinalField = new SubClassA(6); + private final SubClassB subClassBFinalField = new SubClassB(7); + private final SubClassC subClassCFinalField = new SubClassC(8); + } + + private static final class Fields { + + private Number numberField = new Integer(1); + private SuperClass superClassField = new SubClassA(2); + private FinalSubClass finalSubClassField = new FinalSubClass(3); + private SingleImplementorInterface singleImplementorField = new SubClassA(4); + private MultipleImplementorsInterface multipleImplementorsField = new SubClassC(5); + private SubClassA subClassAField = new SubClassA(6); + private SubClassB subClassBField = new SubClassB(7); + private SubClassC subClassCField = new SubClassC(8); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/RecursiveInliningTest.java 2016-12-07 13:48:43.496424525 -0800 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2016, 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.core.test.inlining; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; +import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.inlining.InliningUtil; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase; +import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import sun.misc.Unsafe; + +public class RecursiveInliningTest extends GraalCompilerTest { + + public static int SideEffectI; + public static int[] Memory = new int[]{1, 2}; + + public static final Unsafe UNSAFE; + static { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + UNSAFE = (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("Exception while trying to get Unsafe", e); + } + } + + public static void recursiveLoopMethodUnsafeLoad(int a) { + if (UNSAFE.getInt(Memory, (long) Unsafe.ARRAY_LONG_BASE_OFFSET) == 0) { + return; + } + for (int i = 0; i < a; i++) { + recursiveLoopMethodUnsafeLoad(i); + } + } + + public static void recursiveLoopMethodFieldLoad(int a) { + if (SideEffectI == 0) { + return; + } + for (int i = 0; i < a; i++) { + recursiveLoopMethodFieldLoad(i); + } + } + + public static void recursiveLoopMethod(int a) { + if (a == 0) { + return; + } + for (int i = 0; i < a; i++) { + recursiveLoopMethod(i); + } + } + + public static final boolean LOG = false; + + public static int IterationsStart = 1; + public static int IterationsEnd = 128; + + @Test(timeout = 120_000) + public void inlineDirectRecursiveLoopCallUnsafeLoad() { + testAndTime("recursiveLoopMethodUnsafeLoad"); + } + + @Test(timeout = 120_000) + public void inlineDirectRecursiveLoopCallFieldLoad() { + testAndTime("recursiveLoopMethodFieldLoad"); + } + + @Test(timeout = 120_000) + public void inlineDirectRecursiveLoopCallNoReads() { + testAndTime("recursiveLoopMethod"); + } + + private void testAndTime(String snippet) { + for (int i = IterationsStart; i < IterationsEnd; i++) { + StructuredGraph graph = getGraph(snippet, i); + long elapsed = runAndTimeEarlyReadEliminationPhase(graph); + if (LOG) { + System.out.printf("Needed %dms to run early read elimination on a graph with %d recursive inlined calls of method %s\n", elapsed, i, graph.method()); + } + } + for (int i = IterationsStart; i < IterationsEnd; i++) { + StructuredGraph graph = getGraph(snippet, i); + long elapsed = runAndTimePartialEscapeAnalysis(graph); + if (LOG) { + System.out.printf("Needed %dms to run early partial escape analysis on a graph with %d recursive inlined calls of method %s\n", elapsed, i, graph.method()); + } + } + } + + private long runAndTimePartialEscapeAnalysis(StructuredGraph g) { + PartialEscapePhase p = new PartialEscapePhase(true, new CanonicalizerPhase()); + HighTierContext context = getDefaultHighTierContext(); + long start = System.currentTimeMillis(); + p.apply(g, context); + long end = System.currentTimeMillis(); + Debug.dump(Debug.BASIC_LOG_LEVEL, g, "After PEA"); + return end - start; + } + + private long runAndTimeEarlyReadEliminationPhase(StructuredGraph g) { + EarlyReadEliminationPhase er = new EarlyReadEliminationPhase(new CanonicalizerPhase()); + HighTierContext context = getDefaultHighTierContext(); + long start = System.currentTimeMillis(); + er.apply(g, context); + long end = System.currentTimeMillis(); + Debug.dump(Debug.BASIC_LOG_LEVEL, g, "After Early Read Elimination"); + return end - start; + } + + @SuppressWarnings("try") + private StructuredGraph getGraph(final String snippet, int nrOfInlinings) { + try (Scope s = Debug.scope("RecursiveInliningTest", new DebugDumpScope(snippet, true))) { + ResolvedJavaMethod callerMethod = getResolvedJavaMethod(snippet); + StructuredGraph callerGraph = parseEager(callerMethod, AllowAssumptions.YES); + PhaseSuite graphBuilderSuite = getDefaultGraphBuilderSuite(); + HighTierContext context = new HighTierContext(getProviders(), graphBuilderSuite, OptimisticOptimizations.ALL); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + + for (int i = 0; i < nrOfInlinings; i++) { + InvokeNode next = getNextInvoke(callerGraph); + ResolvedJavaMethod calleeMethod = next.callTarget().targetMethod(); + StructuredGraph calleeGraph = getInlineeGraph(next, callerGraph, context, canonicalizer); + List canonicalizeNodes = new ArrayList<>(); + InliningUtil.inline(next, calleeGraph, false, canonicalizeNodes, calleeMethod); + canonicalizer.applyIncremental(callerGraph, context, canonicalizeNodes); + Debug.dump(Debug.BASIC_LOG_LEVEL, callerGraph, "After inlining %s into %s iteration %d", calleeMethod, callerMethod, i); + } + new SchedulePhase().apply(callerGraph); + return callerGraph; + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + private static StructuredGraph getInlineeGraph(InvokeNode invoke, StructuredGraph caller, HighTierContext context, CanonicalizerPhase canonicalizer) { + StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), invoke.callTarget().targetMethod(), invoke.bci()); + if (result != null) { + return result; + } + return parseBytecodes(invoke.callTarget().targetMethod(), context, canonicalizer, caller); + } + + @SuppressWarnings("try") + private static StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller) { + StructuredGraph newGraph = new StructuredGraph(method, AllowAssumptions.from(caller.getAssumptions() != null), INVALID_COMPILATION_ID); + if (!caller.isUnsafeAccessTrackingEnabled()) { + newGraph.disableUnsafeAccessTracking(); + } + if (context.getGraphBuilderSuite() != null) { + context.getGraphBuilderSuite().apply(newGraph, context); + } + assert newGraph.start().next() != null : "graph needs to be populated by the GraphBuilderSuite " + method + ", " + method.canBeInlined(); + new DeadCodeEliminationPhase(Optional).apply(newGraph); + canonicalizer.apply(newGraph, context); + return newGraph; + } + + private static InvokeNode getNextInvoke(StructuredGraph graph) { + return graph.getNodes().filter(InvokeNode.class).first(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/GraalTutorial.java 2016-12-07 13:48:43.761436174 -0800 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test.tutorial; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.bytecode.Bytecode; +import org.graalvm.compiler.bytecode.BytecodeDisassembler; +import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Examples for the Graal tutorial. Run them using the unittest harness of the mx script. To look at + * the examples in IGV (the graph visualization tool), use the {@code -Dgraal.Dump} and + * {@code -Dgraal.MethodFilter} options. For example, run the first test case using + * + *
+ * mx unittest -Dgraal.Dump= -Dgraal.MethodFilter=String.hashCode GraalTutorial#testStringHashCode
+ * 
+ */ +public class GraalTutorial extends InvokeGraal { + + /* + * Example for the Graal API: access the Graal API metadata object for a method. + */ + + @Test + public void testPrintBytecodes() { + ResolvedJavaMethod method = findMethod(String.class, "hashCode"); + Bytecode bytecode = new ResolvedJavaMethodBytecode(method); + + byte[] bytecodes = bytecode.getCode(); + Assert.assertNotNull(bytecodes); + + System.out.println(new BytecodeDisassembler().disassemble(bytecode)); + } + + /* + * A simple Graal compilation example: Compile the method String.hashCode() + */ + + @Test + public void testStringHashCode() throws InvalidInstalledCodeException { + int expectedResult = "Hello World".hashCode(); + + InstalledCode installedCode = compileAndInstallMethod(findMethod(String.class, "hashCode")); + + int result = (int) installedCode.executeVarargs("Hello World"); + Assert.assertEquals(expectedResult, result); + } + + /* + * Tutorial example for speculative optimizations. + */ + + int f1; + int f2; + + public void speculativeOptimization(boolean flag) { + f1 = 41; + if (flag) { + f2 = 42; + return; + } + f2 = 43; + } + + @Test + public void testSpeculativeOptimization() throws InvalidInstalledCodeException { + /* + * Collect profiling information by running the method in the interpreter. + */ + + for (int i = 0; i < 10000; i++) { + /* Execute several times so that enough profiling information gets collected. */ + speculativeOptimization(false); + } + + /* + * Warmup to collect profiling information is done, now we compile the method. Since the + * value of "flag" was always false during the warmup, the compiled code speculates that the + * value remains false. + */ + + InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization")); + f1 = 0; + f2 = 0; + compiledMethod.executeVarargs(this, true); + Assert.assertEquals(41, f1); + Assert.assertEquals(42, f2); + + /* + * We executed the compiled method with a "flag" value that triggered deoptimization (since + * the warmup always used the different "flag" value). The interpreter updated the profiling + * information, so the second compilation does not perform the speculative optimization. + */ + + compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization")); + f1 = 0; + f2 = 0; + compiledMethod.executeVarargs(this, false); + Assert.assertEquals(41, f1); + Assert.assertEquals(43, f2); + } + + /* + * Tutorial example for snippets and lowering. + */ + + static class A { + } + + static class B extends A { + } + + public static int instanceOfUsage(Object obj) { + if (obj instanceof A) { + return 42; + } else { + return 0; + } + } + + @Test + public void testInstanceOfUsage() throws InvalidInstalledCodeException { + /* + * Collect profiling information by running the method in the interpreter. + */ + + A a = new A(); + /* Allocate an (unused) instance of B so that the class B gets loaded. */ + @SuppressWarnings("unused") + B b = new B(); + int expectedResult = instanceOfUsage(a); + for (int i = 0; i < 10000; i++) { + /* Execute several times so that enough profiling information gets collected. */ + instanceOfUsage(a); + } + + /* Warmup to collect profiling information is done, now compile the method. */ + + InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "instanceOfUsage")); + + int result = (int) compiledMethod.executeVarargs(a); + Assert.assertEquals(expectedResult, result); + } + + /* + * Tutorial example for intrinsic methods. + */ + + public static double intrinsicUsage(double val) { + return Math.sin(val); + } + + @Test + public void testIntrinsicUsage() throws InvalidInstalledCodeException { + double expectedResult = intrinsicUsage(42d); + + InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "intrinsicUsage")); + + double result = (double) compiledMethod.executeVarargs(42d); + Assert.assertEquals(expectedResult, result, 0); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java 2016-12-07 13:48:44.027447867 -0800 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.tutorial; + +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.core.GraalCompiler; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.target.Backend; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.Suites; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ProfilingInfo; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Sample code that shows how to invoke Graal from an application. + */ +public class InvokeGraal { + + protected final Backend backend; + protected final Providers providers; + protected final MetaAccessProvider metaAccess; + protected final CodeCacheProvider codeCache; + + public InvokeGraal() { + /* Ask the hosting Java VM for the entry point object to the Graal API. */ + RuntimeProvider runtimeProvider = Graal.getRequiredCapability(RuntimeProvider.class); + + /* + * The default backend (architecture, VM configuration) that the hosting VM is running on. + */ + backend = runtimeProvider.getHostBackend(); + /* Access to all of the Graal API providers, as implemented by the hosting VM. */ + providers = backend.getProviders(); + /* Some frequently used providers and configuration objects. */ + metaAccess = providers.getMetaAccess(); + codeCache = providers.getCodeCache(); + } + + /** + * The simplest way to compile a method, using the default behavior for everything. + */ + @SuppressWarnings("try") + protected InstalledCode compileAndInstallMethod(ResolvedJavaMethod method) { + /* Create a unique compilation identifier, visible in IGV. */ + CompilationIdentifier compilationId = backend.getCompilationIdentifier(method); + try (Scope s = Debug.scope("compileAndInstallMethod", new DebugDumpScope(String.valueOf(compilationId), true))) { + + /* + * The graph that is compiled. We leave it empty (no nodes added yet). This means that + * it will be filled according to the graphBuilderSuite defined below. We also specify + * that we want the compilation to make optimistic assumptions about runtime state such + * as the loaded class hierarchy. + */ + StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.YES, compilationId); + + /* + * The phases used to build the graph. Usually this is just the GraphBuilderPhase. If + * the graph already contains nodes, it is ignored. + */ + PhaseSuite graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite(); + + /* + * The optimization phases that are applied to the graph. This is the main configuration + * point for Graal. Add or remove phases to customize your compilation. + */ + Suites suites = backend.getSuites().getDefaultSuites(); + + /* + * The low-level phases that are applied to the low-level representation. + */ + LIRSuites lirSuites = backend.getSuites().getDefaultLIRSuites(); + + /* + * We want Graal to perform all speculative optimistic optimizations, using the + * profiling information that comes with the method (collected by the interpreter) for + * speculation. + */ + OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL; + ProfilingInfo profilingInfo = graph.getProfilingInfo(method); + + /* The default class and configuration for compilation results. */ + CompilationResult compilationResult = new CompilationResult(); + CompilationResultBuilderFactory factory = CompilationResultBuilderFactory.Default; + + /* Invoke the whole Graal compilation pipeline. */ + GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory); + + /* + * Install the compilation result into the VM, i.e., copy the byte[] array that contains + * the machine code into an actual executable memory location. + */ + return backend.addInstalledCode(method, asCompilationRequest(compilationId), compilationResult); + } catch (Throwable ex) { + throw Debug.handle(ex); + } + } + + /** + * Look up a method using Java reflection and convert it to the Graal API method object. + */ + protected ResolvedJavaMethod findMethod(Class declaringClass, String name) { + Method reflectionMethod = null; + for (Method m : declaringClass.getDeclaredMethods()) { + if (m.getName().equals(name)) { + assert reflectionMethod == null : "More than one method with name " + name + " in class " + declaringClass.getName(); + reflectionMethod = m; + } + } + assert reflectionMethod != null : "No method with name " + name + " in class " + declaringClass.getName(); + return metaAccess.lookupJavaMethod(reflectionMethod); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java 2016-12-07 13:48:44.293459560 -0800 @@ -0,0 +1,619 @@ +/* + * Copyright (c) 2015, 2016, 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.core.test.tutorial; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; + +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeMap; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.ValuePhiNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.java.LoadFieldNode; +import org.graalvm.compiler.nodes.java.MethodCallTargetNode; +import org.graalvm.compiler.nodes.java.NewArrayNode; +import org.graalvm.compiler.nodes.java.NewInstanceNode; +import org.graalvm.compiler.nodes.java.StoreFieldNode; +import org.graalvm.compiler.nodes.spi.StampProvider; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.graph.StatelessPostOrderNodeIterator; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * A simple context-insensitive static analysis based on the Graal API. It is intended for + * educational purposes, not for use in production. Only a limited set of Java functionality is + * supported to keep the code minimal. + *

+ * The analysis builds a directed graph of {@link TypeFlow type flows}. If a type is added to type + * flow, it is propagated to all {@link TypeFlow#uses uses} of the type flow. Types are propagated + * using a {@link #worklist} of changed type flows until a fixpoint is reached, i.e., until no more + * types need to be added to any type state. + *

+ * The type flows are constructed from a high-level Graal graph by the {@link TypeFlowBuilder}. All + * nodes that operate on {@link JavaKind#Object object} values are converted to the appropriate type + * flows. The analysis is context insensitive: every Java field has {@link Results#lookupField one + * list} of types assigned to the field; every Java method has {@link Results#lookupMethod one + * state} for each {@link MethodState#formalParameters parameter} as well as the + * {@link MethodState#formalReturn return value}. + */ +public class StaticAnalysis { + /** Access to type, method, and fields using the Graal API. */ + private final MetaAccessProvider metaAccess; + /** Access to platform dependent stamps. */ + private final StampProvider stampProvider; + /** The results of the static analysis. */ + private final Results results; + /** Worklist for fixpoint iteration. */ + private final Deque worklist; + + public StaticAnalysis(MetaAccessProvider metaAccess, StampProvider stampProvider) { + this.metaAccess = metaAccess; + this.stampProvider = stampProvider; + this.results = new Results(); + this.worklist = new ArrayDeque<>(); + } + + /** + * Adds a root method to the static analysis. The method must be static and must not have any + * parameters, because the possible types of the parameters would not be known. + */ + public void addMethod(ResolvedJavaMethod method) { + if (!method.isStatic() || method.getSignature().getParameterCount(false) > 0) { + error("Entry point method is not static or has parameters: " + method.format("%H.%n(%p)")); + } + addToWorklist(results.lookupMethod(method)); + } + + /** + * Performs the fixed-point analysis that finds all methods transitively reachable from the + * {@link #addMethod root methods}. + */ + public void finish() { + while (!worklist.isEmpty()) { + worklist.removeFirst().process(); + } + } + + /** + * Returns the static analysis results computed by {@link StaticAnalysis#finish}. + */ + public Results getResults() { + return results; + } + + protected void addToWorklist(WorklistEntry task) { + worklist.addLast(task); + } + + protected static RuntimeException error(String msg) { + throw GraalError.shouldNotReachHere(msg); + } + + /** + * Base class for all work items that can be {@link #addToWorklist added to the worklist}. + */ + abstract class WorklistEntry { + protected abstract void process(); + } + + /** + * The results computed by the static analysis. + */ + public class Results { + private final TypeFlow allInstantiatedTypes; + private final Map fields; + private final Map methods; + + protected Results() { + allInstantiatedTypes = new TypeFlow(); + fields = new HashMap<>(); + methods = new HashMap<>(); + } + + /** + * All {@link TypeFlow#getTypes() types} that are found to be instantiated, i.e., all types + * allocated by the reachable instance and array allocation bytecodes. + */ + public TypeFlow getAllInstantiatedTypes() { + return allInstantiatedTypes; + } + + /** + * All {@link TypeFlow#getTypes() types} that the given field can have, i.e., all types + * assigned by the reachable field store bytecodes. + */ + public TypeFlow lookupField(ResolvedJavaField field) { + TypeFlow result = fields.get(field); + if (result == null) { + result = new TypeFlow(); + fields.put(field, result); + } + return result; + } + + /** + * All {@link TypeFlow#getTypes() types} that {@link MethodState#formalParameters + * parameters} and {@link MethodState#formalReturn return value} of the given method can + * have. + */ + public MethodState lookupMethod(ResolvedJavaMethod method) { + MethodState result = methods.get(method); + if (result == null) { + result = new MethodState(method); + methods.put(method, result); + } + return result; + } + } + + /** + * The {@link TypeFlow#getTypes() types} of the parameters and return value of a method. Also + * serves as the worklist element to parse the bytecodes of the method. + */ + public class MethodState extends WorklistEntry { + private final ResolvedJavaMethod method; + private final TypeFlow[] formalParameters; + private final TypeFlow formalReturn; + private boolean processed; + + protected MethodState(ResolvedJavaMethod method) { + this.method = method; + + formalParameters = new TypeFlow[method.getSignature().getParameterCount(!method.isStatic())]; + for (int i = 0; i < formalParameters.length; i++) { + formalParameters[i] = new TypeFlow(); + } + formalReturn = new TypeFlow(); + } + + /** + * All {@link TypeFlow#getTypes() types} that the parameters of this method can have. + */ + public TypeFlow[] getFormalParameters() { + return formalParameters; + } + + /** + * All {@link TypeFlow#getTypes() types} that the return value of this method can have. + */ + public TypeFlow getFormalReturn() { + return formalReturn; + } + + @Override + @SuppressWarnings("try") + protected void process() { + if (!processed) { + /* We want to process a method only once. */ + processed = true; + + /* + * Build the Graal graph for the method using the bytecode parser provided by Graal. + */ + + StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID); + /* + * Support for graph dumping, IGV uses this information to show the method name of a + * graph. + */ + try (Scope scope = Debug.scope("graph building", graph)) { + /* + * We want all types to be resolved by the graph builder, i.e., we want classes + * referenced by the bytecodes to be loaded and initialized. Since we do not run + * the code before static analysis, the classes would otherwise be not loaded + * yet and the bytecode parser would only create a graph. + */ + Plugins plugins = new Plugins(new InvocationPlugins(metaAccess)); + GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + /* + * For simplicity, we ignore all exception handling during the static analysis. + * This is a constraint of this example code, a real static analysis needs to + * handle the Graal nodes for throwing and handling exceptions. + */ + graphBuilderConfig = graphBuilderConfig.withBytecodeExceptionMode(BytecodeExceptionMode.OmitAll); + /* + * We do not want Graal to perform any speculative optimistic optimizations, + * i.e., we do not want to use profiling information. Since we do not run the + * code before static analysis, the profiling information is empty and therefore + * wrong. + */ + OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE; + + GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, null, null, graphBuilderConfig, optimisticOpts, null); + graphBuilder.apply(graph); + } catch (Throwable ex) { + Debug.handle(ex); + } + + /* + * Build the type flow graph from the Graal graph, i.e., process all nodes that are + * deal with objects. + */ + + TypeFlowBuilder typeFlowBuilder = new TypeFlowBuilder(graph); + typeFlowBuilder.apply(); + } + } + } + + /** + * The active element during static analysis: types are added until a fixed point is reached. + * When a new type is added, it is propagated to all usages by putting this element on the + * {@link StaticAnalysis#addToWorklist worklist}. + */ + public class TypeFlow extends WorklistEntry { + private final Set types; + private final Set uses; + + protected TypeFlow() { + types = new HashSet<>(); + uses = new HashSet<>(); + } + + /** Returns the types of this element. */ + public Set getTypes() { + return types; + } + + /** + * Adds new types to this element. If that changes the state of this element, it is added to + * the {@link StaticAnalysis#addToWorklist worklist} in order to propagate the added types + * to all usages. + */ + protected void addTypes(Set newTypes) { + if (types.addAll(newTypes)) { + addToWorklist(this); + } + } + + /** + * Adds a new use to this element. All types of this element are propagated to the new + * usage. + */ + protected void addUse(TypeFlow use) { + if (uses.add(use)) { + use.addTypes(types); + } + } + + /** + * Processing of the worklist element: propagate the types to all usages. That in turn can + * add the usages to the worklist (if the types of the usage are changed). + */ + @Override + protected void process() { + for (TypeFlow use : uses) { + use.addTypes(types); + } + } + } + + /** + * The active element for method invocations. For {@link InvokeKind#Virtual virtual} and + * {@link InvokeKind#Interface interface} calls, the {@link TypeFlow#getTypes() types} of this + * node are the receiver types. When a new receiver type is added, a new callee might be added. + * Adding a new callee means linking the type flow of the actual parameters with the formal + * parameters of the callee, and linking the return value of the callee with the return value + * state of the invocation. + * + * Statically bindable methods calls ({@link InvokeKind#Static static} and + * {@link InvokeKind#Special special} calls) have only one callee, but use the same code for + * simplicity. + */ + class InvokeTypeFlow extends TypeFlow { + private final MethodCallTargetNode callTarget; + private final TypeFlow[] actualParameters; + private final TypeFlow actualReturn; + private final Set callees; + + protected InvokeTypeFlow(MethodCallTargetNode callTarget, TypeFlow[] actualParameterFlows, TypeFlow actualReturnFlow) { + this.callTarget = callTarget; + this.actualParameters = actualParameterFlows; + this.actualReturn = actualReturnFlow; + this.callees = new HashSet<>(); + } + + private void linkCallee(ResolvedJavaMethod callee) { + if (callees.add(callee)) { + /* We have added a new callee. */ + + /* + * Connect the actual parameters of the invocation with the formal parameters of the + * callee. + */ + MethodState calleeState = results.lookupMethod(callee); + for (int i = 0; i < actualParameters.length; i++) { + if (actualParameters[i] != null) { + actualParameters[i].addUse(calleeState.formalParameters[i]); + } + } + + /* + * Connect the formal return value of the callee with the actual return value of the + * invocation. + */ + if (actualReturn != null) { + calleeState.formalReturn.addUse(actualReturn); + } + addToWorklist(calleeState); + } + } + + @Override + protected void process() { + if (callTarget.invokeKind().isDirect()) { + /* Static and special calls: link the statically known callee method. */ + linkCallee(callTarget.targetMethod()); + } else { + /* Virtual and interface call: Iterate all receiver types. */ + for (ResolvedJavaType type : getTypes()) { + /* + * Resolve the method call for one exact receiver type. The method linking + * semantics of Java are complicated, but fortunatley we can use the linker of + * the hosting Java VM. The Graal API exposes this functionality. + */ + ResolvedJavaMethod method = type.resolveConcreteMethod(callTarget.targetMethod(), callTarget.invoke().getContextType()); + + /* + * Since the static analysis is conservative, the list of receiver types can + * contain types that actually do not provide the method to be called. Ignore + * these. + */ + if (method != null && !method.isAbstract()) { + linkCallee(method); + } + } + } + super.process(); + } + } + + /** + * Converts the Graal nodes of a method to a type flow graph. The main part of the algorithm is + * a reverse-postorder iteration of the Graal nodes, which is provided by the base class + * {@link StatelessPostOrderNodeIterator}. + */ + class TypeFlowBuilder extends StatelessPostOrderNodeIterator { + private final StructuredGraph graph; + private final MethodState methodState; + /** + * Mapping from Graal nodes to type flows. This uses an efficient Graal-provided + * {@link NodeMap collection class}. + */ + private final NodeMap typeFlows; + + protected TypeFlowBuilder(StructuredGraph graph) { + super(graph.start()); + + this.graph = graph; + this.methodState = results.lookupMethod(graph.method()); + this.typeFlows = new NodeMap<>(graph); + } + + /** + * Register the type flow node for a Graal node. + */ + private void registerFlow(ValueNode node, TypeFlow flow) { + /* + * We ignore intermediate nodes used by Graal that, e.g., add more type information or + * encapsulate values flowing out of loops. + */ + ValueNode unproxiedNode = GraphUtil.unproxify(node); + + assert typeFlows.get(unproxiedNode) == null : "overwriting existing value"; + typeFlows.set(unproxiedNode, flow); + } + + /** + * Lookup the type flow node for a Graal node. + */ + private TypeFlow lookupFlow(ValueNode node) { + ValueNode unproxiedNode = GraphUtil.unproxify(node); + TypeFlow result = typeFlows.get(unproxiedNode); + if (result == null) { + /* + * This is only the prototype of a static analysis, the handling of many Graal nodes + * (such as array accesses) is not implemented. + */ + throw error("Node is not supported yet by static analysis: " + node.getClass().getName()); + } + return result; + } + + private boolean isObject(ValueNode node) { + return node.getStackKind() == JavaKind.Object; + } + + @Override + public void apply() { + /* + * Before the reverse-postorder iteration of fixed nodes, we handle some classes of + * floating nodes. + */ + for (Node n : graph.getNodes()) { + if (n instanceof ParameterNode) { + /* + * Incoming method parameter already have a type flow created by the + * MethodState. + */ + ParameterNode node = (ParameterNode) n; + if (isObject(node)) { + registerFlow(node, methodState.formalParameters[(node.index())]); + } + } else if (n instanceof ValuePhiNode) { + /* + * Phi functions for loops are cyclic. We create the type flow here (before + * processing any loop nodes), but link the phi values only later (after + * processing of all loop nodes. + */ + ValuePhiNode node = (ValuePhiNode) n; + if (isObject(node)) { + registerFlow(node, new TypeFlow()); + } + } else if (n instanceof ConstantNode) { + /* Constants have a known type. */ + ConstantNode node = (ConstantNode) n; + JavaConstant constant = node.asJavaConstant(); + if (constant.isNull()) { + registerFlow(node, new TypeFlow()); + } + } + } + + super.apply(); + + for (Node n : graph.getNodes()) { + if (n instanceof ValuePhiNode) { + /* + * Post-processing of phi functions. Now the type flow for all input values has + * been created, so we can link the type flows together. + */ + ValuePhiNode node = (ValuePhiNode) n; + if (isObject(node)) { + TypeFlow phiFlow = lookupFlow(node); + for (ValueNode value : node.values()) { + lookupFlow(value).addUse(phiFlow); + } + } + } + } + } + + private void allocation(ValueNode node, ResolvedJavaType type) { + /* + * The type flow of allocation nodes is one exact type. This is the source of the + * fixpoint iteration, the types are propagated downwards from these sources. + */ + TypeFlow flow = new TypeFlow(); + flow.addTypes(Collections.singleton(type)); + registerFlow(node, flow); + flow.addUse(results.getAllInstantiatedTypes()); + } + + @Override + protected void node(FixedNode n) { + if (n instanceof NewInstanceNode) { + NewInstanceNode node = (NewInstanceNode) n; + allocation(node, node.instanceClass()); + } else if (n instanceof NewArrayNode) { + NewArrayNode node = (NewArrayNode) n; + allocation(node, node.elementType().getArrayClass()); + + } else if (n instanceof LoadFieldNode) { + /* + * The type flow of a field load is the type flow of the field itself. It + * accumulates all types ever stored to the field. + */ + LoadFieldNode node = (LoadFieldNode) n; + if (isObject(node)) { + registerFlow(node, results.lookupField(node.field())); + } + } else if (n instanceof StoreFieldNode) { + /* + * Connect the type flow of the stored value with the type flow of the field. + */ + StoreFieldNode node = (StoreFieldNode) n; + if (isObject(node.value())) { + TypeFlow fieldFlow = results.lookupField(node.field()); + lookupFlow(node.value()).addUse(fieldFlow); + } + + } else if (n instanceof ReturnNode) { + /* + * Connect the type flow of the returned value with the formal return type flow of + * the MethodState. + */ + ReturnNode node = (ReturnNode) n; + if (node.result() != null && isObject(node.result())) { + lookupFlow(node.result()).addUse(methodState.formalReturn); + } + + } else if (n instanceof Invoke) { + /* + * Create the InvokeTypeFlow, which performs all the linking of actual and formal + * parameter values with all identified callees. + */ + Invoke invoke = (Invoke) n; + MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + + TypeFlow[] actualParameters = new TypeFlow[callTarget.arguments().size()]; + for (int i = 0; i < actualParameters.length; i++) { + ValueNode actualParam = callTarget.arguments().get(i); + if (isObject(actualParam)) { + actualParameters[i] = lookupFlow(actualParam); + } + } + TypeFlow actualReturn = null; + if (isObject(invoke.asNode())) { + actualReturn = new TypeFlow(); + registerFlow(invoke.asNode(), actualReturn); + } + + InvokeTypeFlow invokeFlow = new InvokeTypeFlow(callTarget, actualParameters, actualReturn); + + if (callTarget.invokeKind().isIndirect()) { + /* + * For virtual and interface calls, new receiver types can lead to new callees. + * Connect the type flow of the receiver with the invocation flow. + */ + lookupFlow(callTarget.arguments().get(0)).addUse(invokeFlow); + } + /* + * Ensure the invocation is on the worklist at least once, even if it is a static + * call with not parameters that does not involve any type flows. + */ + addToWorklist(invokeFlow); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysisTests.java 2016-12-07 13:48:44.559471253 -0800 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2015, 2015, 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.core.test.tutorial; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; + +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.core.target.Backend; +import org.graalvm.compiler.core.test.tutorial.StaticAnalysis.MethodState; +import org.graalvm.compiler.core.test.tutorial.StaticAnalysis.TypeFlow; +import org.graalvm.compiler.nodes.spi.StampProvider; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.runtime.RuntimeProvider; + +public class StaticAnalysisTests { + + static class A { + Object foo(Object arg) { + return arg; + } + } + + static class B extends A { + @Override + Object foo(Object arg) { + if (arg instanceof Data) { + return ((Data) arg).f; + } else { + return super.foo(arg); + } + } + } + + static class Data { + Object f; + } + + private final MetaAccessProvider metaAccess; + private final StampProvider stampProvider; + + public StaticAnalysisTests() { + Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend(); + Providers providers = backend.getProviders(); + this.metaAccess = providers.getMetaAccess(); + this.stampProvider = providers.getStampProvider(); + } + + static void test01Entry() { + A a = new A(); + a.foo(null); + } + + @Test + public void test01() { + StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider); + sa.addMethod(findMethod(StaticAnalysisTests.class, "test01Entry")); + sa.finish(); + + assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class)); + assertEquals(f(sa, Data.class, "f")); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[1]); + assertEquals(m(sa, A.class, "foo").getFormalReturn()); + } + + static void test02Entry() { + A a = new A(); + a.foo(new Data()); + + B b = new B(); + b.foo(null); + } + + @Test + public void test02() { + StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider); + sa.addMethod(findMethod(StaticAnalysisTests.class, "test02Entry")); + sa.finish(); + + assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(B.class), t(Data.class)); + assertEquals(f(sa, Data.class, "f")); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class), t(B.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class)); + assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class)); + assertEquals(m(sa, B.class, "foo").getFormalParameters()[0], t(B.class)); + assertEquals(m(sa, B.class, "foo").getFormalParameters()[1]); + assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class)); + } + + static void test03Entry() { + Data data = new Data(); + data.f = new Integer(42); + + A a = new A(); + a.foo(new Data()); + + B b = new B(); + b.foo(null); + } + + @Test + public void test03() { + StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider); + sa.addMethod(findMethod(StaticAnalysisTests.class, "test03Entry")); + sa.finish(); + + assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(B.class), t(Data.class), t(Integer.class)); + assertEquals(f(sa, Data.class, "f"), t(Integer.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class), t(B.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class)); + assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class)); + assertEquals(m(sa, B.class, "foo").getFormalParameters()[0], t(B.class)); + assertEquals(m(sa, B.class, "foo").getFormalParameters()[1]); + assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class), t(Integer.class)); + } + + static void test04Entry() { + Data data = null; + for (int i = 0; i < 2; i++) { + if (i == 0) { + data = new Data(); + } else if (i == 1) { + data.f = new Integer(42); + } + } + + A a = new A(); + a.foo(data); + } + + @Test + public void test04() { + StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider); + sa.addMethod(findMethod(StaticAnalysisTests.class, "test04Entry")); + sa.finish(); + + assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(Data.class), t(Integer.class)); + assertEquals(f(sa, Data.class, "f"), t(Integer.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class)); + assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class)); + assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class)); + } + + private MethodState m(StaticAnalysis sa, Class declaringClass, String name) { + return sa.getResults().lookupMethod(findMethod(declaringClass, name)); + } + + private TypeFlow f(StaticAnalysis sa, Class declaringClass, String name) { + return sa.getResults().lookupField(findField(declaringClass, name)); + } + + private static void assertEquals(TypeFlow actual, Object... expected) { + Collection actualTypes = actual.getTypes(); + if (actualTypes.size() != expected.length || !actualTypes.containsAll(Arrays.asList(expected))) { + Assert.fail(actualTypes + " != " + Arrays.asList(expected)); + } + } + + private ResolvedJavaType t(Class clazz) { + return metaAccess.lookupJavaType(clazz); + } + + private ResolvedJavaMethod findMethod(Class declaringClass, String name) { + Method reflectionMethod = null; + for (Method m : declaringClass.getDeclaredMethods()) { + if (m.getName().equals(name)) { + assert reflectionMethod == null : "More than one method with name " + name + " in class " + declaringClass.getName(); + reflectionMethod = m; + } + } + assert reflectionMethod != null : "No method with name " + name + " in class " + declaringClass.getName(); + return metaAccess.lookupJavaMethod(reflectionMethod); + } + + private ResolvedJavaField findField(Class declaringClass, String name) { + Field reflectionField; + try { + reflectionField = declaringClass.getDeclaredField(name); + } catch (NoSuchFieldException | SecurityException ex) { + throw new AssertionError(ex); + } + return metaAccess.lookupJavaField(reflectionField); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/overview.html 2016-12-07 13:48:44.825482946 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.core project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilerThread.java 2016-12-07 13:48:45.091494639 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012, 2014, 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.core; + +import org.graalvm.compiler.core.CompilerThreadFactory.DebugConfigAccess; +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.debug.DebugDumpHandler; +import org.graalvm.compiler.debug.GraalDebugConfig; + +/** + * A compiler thread is a daemon thread that runs at {@link Thread#MAX_PRIORITY} and executes in the + * context of a thread-local {@linkplain GraalDebugConfig debug configuration}. + */ +public class CompilerThread extends Thread { + + private final DebugConfigAccess debugConfigAccess; + + public CompilerThread(Runnable r, String namePrefix, DebugConfigAccess debugConfigAccess) { + super(r); + this.setName(namePrefix + "-" + this.getId()); + this.setPriority(Thread.MAX_PRIORITY); + this.setDaemon(true); + this.debugConfigAccess = debugConfigAccess; + } + + @Override + public void run() { + DebugConfig debugConfig = debugConfigAccess.getDebugConfig(); + setContextClassLoader(getClass().getClassLoader()); + try { + super.run(); + } finally { + if (debugConfig != null) { + for (DebugDumpHandler dumpHandler : debugConfig.dumpHandlers()) { + try { + dumpHandler.close(); + } catch (Throwable t) { + } + } + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilerThreadFactory.java 2016-12-07 13:48:45.356506288 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, 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.core; + +import java.util.concurrent.ThreadFactory; + +import org.graalvm.compiler.debug.DebugConfig; + +/** + * Facility for creating {@linkplain CompilerThread compiler threads}. + */ +public class CompilerThreadFactory implements ThreadFactory { + + /** + * Capability to get a thread-local debug configuration for the current thread. + */ + public interface DebugConfigAccess { + /** + * Get a thread-local debug configuration for the current thread. This will be null if + * debugging is disabled. + */ + DebugConfig getDebugConfig(); + } + + protected final String threadNamePrefix; + protected final DebugConfigAccess debugConfigAccess; + + public CompilerThreadFactory(String threadNamePrefix, DebugConfigAccess debugConfigAccess) { + this.threadNamePrefix = threadNamePrefix; + this.debugConfigAccess = debugConfigAccess; + } + + @Override + public Thread newThread(Runnable r) { + return new CompilerThread(r, threadNamePrefix, debugConfigAccess); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java 2016-12-07 13:48:45.622517981 -0800 @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2009, 2016, 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.core; + +import static org.graalvm.compiler.core.GraalCompilerOptions.EmitLIRRepeatCount; +import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation; +import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional; + +import java.util.Collection; +import java.util.List; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.LIRGenerationPhase.LIRGenerationContext; +import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder; +import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.core.common.util.CompilationAlarm; +import org.graalvm.compiler.core.target.Backend; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.DebugTimer; +import org.graalvm.compiler.debug.internal.method.MethodMetricsRootScopeInfo; +import org.graalvm.compiler.lir.BailoutAndRestartBackendException; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.lir.framemap.FrameMap; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext; +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext; +import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.instrumentation.ExtractInstrumentationPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.LowTierContext; +import org.graalvm.compiler.phases.tiers.MidTierContext; +import org.graalvm.compiler.phases.tiers.Suites; +import org.graalvm.compiler.phases.tiers.TargetProvider; +import org.graalvm.compiler.phases.util.Providers; + +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.code.site.ConstantReference; +import jdk.vm.ci.code.site.DataPatch; +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ProfilingInfo; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.VMConstant; + +/** + * Static methods for orchestrating the compilation of a {@linkplain StructuredGraph graph}. + */ +public class GraalCompiler { + + private static final DebugTimer CompilerTimer = Debug.timer("GraalCompiler"); + private static final DebugTimer FrontEnd = Debug.timer("FrontEnd"); + private static final DebugTimer BackEnd = Debug.timer("BackEnd"); + private static final DebugTimer EmitLIR = Debug.timer("EmitLIR"); + private static final DebugTimer EmitCode = Debug.timer("EmitCode"); + private static final LIRGenerationPhase LIR_GENERATION_PHASE = new LIRGenerationPhase(); + + /** + * Encapsulates all the inputs to a {@linkplain GraalCompiler#compile(Request) compilation}. + */ + public static class Request { + public final StructuredGraph graph; + public final ResolvedJavaMethod installedCodeOwner; + public final Providers providers; + public final Backend backend; + public final PhaseSuite graphBuilderSuite; + public final OptimisticOptimizations optimisticOpts; + public final ProfilingInfo profilingInfo; + public final Suites suites; + public final LIRSuites lirSuites; + public final T compilationResult; + public final CompilationResultBuilderFactory factory; + + /** + * @param graph the graph to be compiled + * @param installedCodeOwner the method the compiled code will be associated with once + * installed. This argument can be null. + * @param providers + * @param backend + * @param graphBuilderSuite + * @param optimisticOpts + * @param profilingInfo + * @param suites + * @param lirSuites + * @param compilationResult + * @param factory + */ + public Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite graphBuilderSuite, + OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory) { + this.graph = graph; + this.installedCodeOwner = installedCodeOwner; + this.providers = providers; + this.backend = backend; + this.graphBuilderSuite = graphBuilderSuite; + this.optimisticOpts = optimisticOpts; + this.profilingInfo = profilingInfo; + this.suites = suites; + this.lirSuites = lirSuites; + this.compilationResult = compilationResult; + this.factory = factory; + } + + /** + * Executes this compilation request. + * + * @return the result of the compilation + */ + public T execute() { + return GraalCompiler.compile(this); + } + } + + /** + * Requests compilation of a given graph. + * + * @param graph the graph to be compiled + * @param installedCodeOwner the method the compiled code will be associated with once + * installed. This argument can be null. + * @return the result of the compilation + */ + public static T compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, + PhaseSuite graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, + CompilationResultBuilderFactory factory) { + return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory)); + } + + /** + * Services a given compilation request. + * + * @return the result of the compilation + */ + @SuppressWarnings("try") + public static T compile(Request r) { + try (Scope s = MethodMetricsRootScopeInfo.createRootScopeIfAbsent(r.installedCodeOwner); + CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod()) { + assert !r.graph.isFrozen(); + try (Scope s0 = Debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache()); DebugCloseable a = CompilerTimer.start()) { + emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites); + emitBackEnd(r.graph, null, r.installedCodeOwner, r.backend, r.compilationResult, r.factory, null, r.lirSuites); + } catch (Throwable e) { + throw Debug.handle(e); + } + return r.compilationResult; + } + } + + /** + * Builds the graph, optimizes it. + */ + @SuppressWarnings("try") + public static void emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite graphBuilderSuite, OptimisticOptimizations optimisticOpts, + ProfilingInfo profilingInfo, Suites suites) { + try (Scope s = Debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start()) { + HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts); + if (graph.start().next() == null) { + graphBuilderSuite.apply(graph, highTierContext); + new DeadCodeEliminationPhase(Optional).apply(graph); + } else { + Debug.dump(Debug.INFO_LOG_LEVEL, graph, "initial state"); + } + if (UseGraalInstrumentation.getValue()) { + new ExtractInstrumentationPhase().apply(graph, highTierContext); + } + + suites.getHighTier().apply(graph, highTierContext); + graph.maybeCompress(); + + MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo); + suites.getMidTier().apply(graph, midTierContext); + graph.maybeCompress(); + + LowTierContext lowTierContext = new LowTierContext(providers, target); + suites.getLowTier().apply(graph, lowTierContext); + + Debug.dump(Debug.BASIC_LOG_LEVEL, graph.getLastSchedule(), "Final HIR schedule"); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + @SuppressWarnings("try") + public static void emitBackEnd(StructuredGraph graph, Object stub, ResolvedJavaMethod installedCodeOwner, Backend backend, T compilationResult, + CompilationResultBuilderFactory factory, RegisterConfig registerConfig, LIRSuites lirSuites) { + try (Scope s = Debug.scope("BackEnd", graph.getLastSchedule()); DebugCloseable a = BackEnd.start()) { + // Repeatedly run the LIR code generation pass to improve statistical profiling results. + for (int i = 0; i < EmitLIRRepeatCount.getValue(); i++) { + SchedulePhase dummySchedule = new SchedulePhase(); + dummySchedule.apply(graph); + emitLIR(backend, graph, stub, registerConfig, lirSuites); + } + + LIRGenerationResult lirGen = null; + lirGen = emitLIR(backend, graph, stub, registerConfig, lirSuites); + try (Scope s2 = Debug.scope("CodeGen", lirGen, lirGen.getLIR())) { + int bytecodeSize = graph.method() == null ? 0 : graph.getBytecodeSize(); + compilationResult.setHasUnsafeAccess(graph.hasUnsafeAccess()); + emitCode(backend, graph.getAssumptions(), graph.method(), graph.getMethods(), graph.getFields(), bytecodeSize, lirGen, compilationResult, installedCodeOwner, factory); + } catch (Throwable e) { + throw Debug.handle(e); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + @SuppressWarnings("try") + public static LIRGenerationResult emitLIR(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites) { + OverrideScope overrideScope = null; + LIRSuites lirSuites0 = lirSuites; + while (true) { + try (OverrideScope scope = overrideScope) { + return emitLIR0(backend, graph, stub, registerConfig, lirSuites0); + } catch (BailoutAndRestartBackendException e) { + if (BailoutAndRestartBackendException.Options.LIRUnlockBackendRestart.getValue() && e.shouldRestart()) { + overrideScope = e.getOverrideScope(); + lirSuites0 = e.updateLIRSuites(lirSuites); + if (lirSuites0 != null) { + continue; + } + } + /* + * The BailoutAndRestartBackendException is permanent. If restart fails or is + * disabled we throw the bailout. + */ + throw e; + } + } + } + + @SuppressWarnings("try") + private static LIRGenerationResult emitLIR0(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites) { + try (Scope ds = Debug.scope("EmitLIR"); DebugCloseable a = EmitLIR.start()) { + ScheduleResult schedule = graph.getLastSchedule(); + Block[] blocks = schedule.getCFG().getBlocks(); + Block startBlock = schedule.getCFG().getStartBlock(); + assert startBlock != null; + assert startBlock.getPredecessorCount() == 0; + + LIR lir = null; + AbstractBlockBase[] codeEmittingOrder = null; + AbstractBlockBase[] linearScanOrder = null; + try (Scope s = Debug.scope("ComputeLinearScanOrder", lir)) { + codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock); + linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock); + + lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder); + Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After linear scan order"); + } catch (Throwable e) { + throw Debug.handle(e); + } + FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig); + LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(graph.compilationId(), lir, frameMapBuilder, graph, stub); + LIRGeneratorTool lirGen = backend.newLIRGenerator(lirGenRes); + NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen); + + // LIR generation + LIRGenerationContext context = new LIRGenerationContext(lirGen, nodeLirGen, graph, schedule); + LIR_GENERATION_PHASE.apply(backend.getTarget(), lirGenRes, context); + + try (Scope s = Debug.scope("LIRStages", nodeLirGen, lir)) { + Debug.dump(Debug.BASIC_LOG_LEVEL, lir, "After LIR generation"); + LIRGenerationResult result = emitLowLevel(backend.getTarget(), lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig)); + Debug.dump(Debug.BASIC_LOG_LEVEL, lir, "Before code generation"); + return result; + } catch (Throwable e) { + throw Debug.handle(e); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + protected static String getCompilationUnitName(StructuredGraph graph, T compilationResult) { + if (compilationResult != null && compilationResult.getName() != null) { + return compilationResult.getName(); + } + ResolvedJavaMethod method = graph.method(); + if (method == null) { + return ""; + } + return method.format("%H.%n(%p)"); + } + + public static LIRGenerationResult emitLowLevel(TargetDescription target, LIRGenerationResult lirGenRes, LIRGeneratorTool lirGen, LIRSuites lirSuites, + RegisterAllocationConfig registerAllocationConfig) { + PreAllocationOptimizationContext preAllocOptContext = new PreAllocationOptimizationContext(lirGen); + lirSuites.getPreAllocationOptimizationStage().apply(target, lirGenRes, preAllocOptContext); + + AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory(), registerAllocationConfig); + lirSuites.getAllocationStage().apply(target, lirGenRes, allocContext); + + PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext(lirGen); + lirSuites.getPostAllocationOptimizationStage().apply(target, lirGenRes, postAllocOptContext); + + return lirGenRes; + } + + @SuppressWarnings("try") + public static void emitCode(Backend backend, Assumptions assumptions, ResolvedJavaMethod rootMethod, Collection inlinedMethods, Collection accessedFields, + int bytecodeSize, LIRGenerationResult lirGenRes, + CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner, CompilationResultBuilderFactory factory) { + try (DebugCloseable a = EmitCode.start()) { + FrameMap frameMap = lirGenRes.getFrameMap(); + CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGenRes, frameMap, compilationResult, factory); + backend.emitCode(crb, lirGenRes.getLIR(), installedCodeOwner); + if (assumptions != null && !assumptions.isEmpty()) { + compilationResult.setAssumptions(assumptions.toArray()); + } + if (rootMethod != null) { + compilationResult.setMethods(rootMethod, inlinedMethods); + compilationResult.setFields(accessedFields); + compilationResult.setBytecodeSize(bytecodeSize); + } + crb.finish(); + if (Debug.isCountEnabled()) { + List ldp = compilationResult.getDataPatches(); + JavaKind[] kindValues = JavaKind.values(); + DebugCounter[] dms = new DebugCounter[kindValues.length]; + for (int i = 0; i < dms.length; i++) { + dms[i] = Debug.counter("DataPatches-%s", kindValues[i]); + } + + for (DataPatch dp : ldp) { + JavaKind kind = JavaKind.Illegal; + if (dp.reference instanceof ConstantReference) { + VMConstant constant = ((ConstantReference) dp.reference).getConstant(); + if (constant instanceof JavaConstant) { + kind = ((JavaConstant) constant).getJavaKind(); + } + } + dms[kind.ordinal()].add(1); + } + + Debug.counter("CompilationResults").increment(); + Debug.counter("CodeBytesEmitted").add(compilationResult.getTargetCodeSize()); + Debug.counter("InfopointsEmitted").add(compilationResult.getInfopoints().size()); + Debug.counter("DataPatches").add(ldp.size()); + Debug.counter("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size()); + } + + Debug.dump(Debug.BASIC_LOG_LEVEL, compilationResult, "After code generation"); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java 2016-12-07 13:48:45.888529674 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, 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.core; + +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +/** + * Options related to {@link GraalCompiler}. + */ +public class GraalCompilerOptions { + + // @formatter:off + @Option(help = "Repeatedly run the LIR code generation pass to improve statistical profiling results.", type = OptionType.Debug) + public static final OptionValue EmitLIRRepeatCount = new OptionValue<>(0); + @Option(help = "", type = OptionType.Debug) + public static final OptionValue PrintFilter = new OptionValue<>(null); + @Option(help = "", type = OptionType.Debug) + public static final OptionValue PrintCompilation = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) + public static final OptionValue PrintAfterCompilation = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) + public static final OptionValue PrintBailout = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) + public static final OptionValue ExitVMOnBailout = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) + public static final OptionValue ExitVMOnException = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) + public static final OptionValue PrintStackTraceOnException = new OptionValue<>(false); + // @formatter:on + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalDebugInitializationParticipant.java 2016-12-07 13:48:46.153541323 -0800 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015, 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.core; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Params; +import org.graalvm.compiler.debug.DebugInitializationParticipant; +import org.graalvm.compiler.debug.GraalDebugConfig; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter; +import org.graalvm.compiler.serviceprovider.ServiceProvider; + +/** + * A service provider that may modify the initialization of {@link Debug} based on the values + * specified for various {@link GraalDebugConfig} options. + */ +@ServiceProvider(DebugInitializationParticipant.class) +public class GraalDebugInitializationParticipant implements DebugInitializationParticipant { + + @Override + public void apply(Params params) { + if (GraalDebugConfig.areDebugScopePatternsEnabled()) { + params.enable = true; + } + if ("".equals(GraalDebugConfig.Options.Count.getValue())) { + params.enableUnscopedCounters = true; + } + if ("".equals(GraalDebugConfig.Options.MethodMeter.getValue())) { + params.enableUnscopedMethodMetrics = true; + // mm requires full debugging support + params.enable = true; + } + if ("".equals(GraalDebugConfig.Options.Time.getValue())) { + params.enableUnscopedTimers = true; + } + if ("".equals(GraalDebugConfig.Options.TrackMemUse.getValue())) { + params.enableUnscopedMemUseTrackers = true; + } + // unscoped counters/timers/mem use trackers/method metrics should respect method filter + // semantics + if (!params.enable && (params.enableUnscopedMemUseTrackers || params.enableUnscopedMethodMetrics || params.enableUnscopedCounters || params.enableUnscopedTimers) && + GraalDebugConfig.isNotEmpty(GraalDebugConfig.Options.MethodFilter)) { + params.enable = true; + params.enableMethodFilter = true; + } + + if (!params.enableUnscopedMethodMetrics && GraalDebugConfig.Options.MethodMeter.getValue() != null) { + // mm requires full debugging support + params.enable = true; + } + + if (GraalDebugConfig.isGlobalMetricsInterceptedByMethodMetricsEnabled()) { + if (!params.enable) { + TTY.println("WARNING: MethodMeter is disabled but GlobalMetricsInterceptedByMethodMetrics is enabled. Ignoring MethodMeter and GlobalMetricsInterceptedByMethodMetrics."); + } else { + parseMethodMetricsDebugValueInterception(params); + } + } + if (GraalDebugConfig.isNotEmpty(GraalDebugConfig.Options.MethodMeter) || params.enableUnscopedMethodMetrics) { + if (!MethodMetricsPrinter.methodMetricsDumpingEnabled()) { + TTY.println("WARNING: MethodMeter is enabled but MethodMeter dumping is disabled. Output will not contain MethodMetrics."); + } + } + } + + private static void parseMethodMetricsDebugValueInterception(Params params) { + String interceptionGroup = GraalDebugConfig.Options.GlobalMetricsInterceptedByMethodMetrics.getValue(); + boolean intercepted = false; + if (interceptionGroup.contains("Timers")) { + params.interceptTime = true; + intercepted = true; + } + if (interceptionGroup.contains("Counters")) { + params.interceptCount = true; + intercepted = true; + } + if (interceptionGroup.contains("MemUseTrackers")) { + params.interceptMem = true; + intercepted = true; + } + + if (!intercepted) { + TTY.println("WARNING: Ignoring GlobalMetricsInterceptedByMethodMetrics as the supplied argument does not contain Timers/Counters/MemUseTrackers."); + GraalDebugConfig.Options.GlobalMetricsInterceptedByMethodMetrics.setValue(null); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/LIRGenerationPhase.java 2016-12-07 13:48:46.418552972 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2015, 2015, 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.core; + +import java.util.List; + +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.core.common.cfg.BlockMap; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.phases.LIRPhase; +import org.graalvm.compiler.lir.ssa.SSAUtil; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.code.TargetDescription; + +public class LIRGenerationPhase extends LIRPhase { + + public static final class LIRGenerationContext { + private final NodeLIRBuilderTool nodeLirBuilder; + private final LIRGeneratorTool lirGen; + private final StructuredGraph graph; + private final ScheduleResult schedule; + + public LIRGenerationContext(LIRGeneratorTool lirGen, NodeLIRBuilderTool nodeLirBuilder, StructuredGraph graph, ScheduleResult schedule) { + this.nodeLirBuilder = nodeLirBuilder; + this.lirGen = lirGen; + this.graph = graph; + this.schedule = schedule; + } + } + + private static final DebugCounter instructionCounter = Debug.counter("GeneratedLIRInstructions"); + + @Override + protected final void run(TargetDescription target, LIRGenerationResult lirGenRes, LIRGenerationPhase.LIRGenerationContext context) { + NodeLIRBuilderTool nodeLirBuilder = context.nodeLirBuilder; + StructuredGraph graph = context.graph; + ScheduleResult schedule = context.schedule; + for (AbstractBlockBase b : lirGenRes.getLIR().getControlFlowGraph().getBlocks()) { + emitBlock(nodeLirBuilder, lirGenRes, (Block) b, graph, schedule.getBlockToNodesMap()); + } + context.lirGen.beforeRegisterAllocation(); + assert SSAUtil.verifySSAForm(lirGenRes.getLIR()); + } + + private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap> blockMap) { + assert !isProcessed(lirGenRes, b) : "Block already processed " + b; + assert verifyPredecessors(lirGenRes, b); + nodeLirGen.doBlock(b, graph, blockMap); + if (instructionCounter.isEnabled()) { + instructionCounter.add(lirGenRes.getLIR().getLIRforBlock(b).size()); + } + } + + private static boolean verifyPredecessors(LIRGenerationResult lirGenRes, Block block) { + for (Block pred : block.getPredecessors()) { + if (!block.isLoopHeader() || !pred.isLoopEnd()) { + assert isProcessed(lirGenRes, pred) : "Predecessor not yet processed " + pred; + } + } + return true; + } + + private static boolean isProcessed(LIRGenerationResult lirGenRes, Block b) { + return lirGenRes.getLIR().getLIRforBlock(b) != null; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/BytecodeParserTool.java 2016-12-07 13:48:46.687564797 -0800 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, 2014, 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.core.gen; + +import jdk.vm.ci.meta.Value; + +/** + * visible interface of bytecode parsers. + */ +public interface BytecodeParserTool { + + void storeLocal(int i, Value x); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java 2016-12-07 13:48:46.952576446 -0800 @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2011, 2015, 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.core.gen; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Map; +import java.util.Queue; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.lir.ConstantValue; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.NodeValueMap; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.nodes.virtual.EscapeObjectState; +import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; +import org.graalvm.compiler.virtual.nodes.MaterializedObjectState; +import org.graalvm.compiler.virtual.nodes.VirtualObjectState; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.VirtualObject; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.JavaValue; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Value; + +/** + * Builds {@link LIRFrameState}s from {@link FrameState}s. + */ +public class DebugInfoBuilder { + + protected final NodeValueMap nodeValueMap; + + public DebugInfoBuilder(NodeValueMap nodeValueMap) { + this.nodeValueMap = nodeValueMap; + } + + private static final JavaValue[] NO_JAVA_VALUES = {}; + private static final JavaKind[] NO_JAVA_KINDS = {}; + + protected final Map virtualObjects = Node.newMap(); + protected final Map objectStates = Node.newIdentityMap(); + + protected final Queue pendingVirtualObjects = new ArrayDeque<>(); + + public LIRFrameState build(FrameState topState, LabelRef exceptionEdge) { + assert virtualObjects.size() == 0; + assert objectStates.size() == 0; + assert pendingVirtualObjects.size() == 0; + + // collect all VirtualObjectField instances: + FrameState current = topState; + do { + if (current.virtualObjectMappingCount() > 0) { + for (EscapeObjectState state : current.virtualObjectMappings()) { + if (!objectStates.containsKey(state.object())) { + if (!(state instanceof MaterializedObjectState) || ((MaterializedObjectState) state).materializedValue() != state.object()) { + objectStates.put(state.object(), state); + } + } + } + } + current = current.outerFrameState(); + } while (current != null); + + BytecodeFrame frame = computeFrameForState(topState); + + VirtualObject[] virtualObjectsArray = null; + if (virtualObjects.size() != 0) { + // fill in the VirtualObject values + VirtualObjectNode vobjNode; + while ((vobjNode = pendingVirtualObjects.poll()) != null) { + VirtualObject vobjValue = virtualObjects.get(vobjNode); + assert vobjValue.getValues() == null; + + JavaValue[] values; + JavaKind[] slotKinds; + int entryCount = vobjNode.entryCount(); + if (entryCount == 0) { + values = NO_JAVA_VALUES; + slotKinds = NO_JAVA_KINDS; + } else { + values = new JavaValue[entryCount]; + slotKinds = new JavaKind[entryCount]; + } + if (values.length > 0) { + VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobjNode); + assert currentField != null; + int pos = 0; + for (int i = 0; i < entryCount; i++) { + if (!currentField.values().get(i).isConstant() || currentField.values().get(i).asJavaConstant().getJavaKind() != JavaKind.Illegal) { + ValueNode value = currentField.values().get(i); + values[pos] = toJavaValue(value); + slotKinds[pos] = toSlotKind(value); + pos++; + } else { + assert currentField.values().get(i - 1).getStackKind() == JavaKind.Double || currentField.values().get(i - 1).getStackKind() == JavaKind.Long : vobjNode + " " + i + " " + + currentField.values().get(i - 1); + } + } + if (pos != entryCount) { + values = Arrays.copyOf(values, pos); + slotKinds = Arrays.copyOf(slotKinds, pos); + } + } + assert checkValues(vobjValue.getType(), values, slotKinds); + vobjValue.setValues(values, slotKinds); + } + + virtualObjectsArray = virtualObjects.values().toArray(new VirtualObject[virtualObjects.size()]); + virtualObjects.clear(); + } + objectStates.clear(); + + return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray); + } + + private boolean checkValues(ResolvedJavaType type, JavaValue[] values, JavaKind[] slotKinds) { + assert (values == null) == (slotKinds == null); + if (values != null) { + assert values.length == slotKinds.length; + if (!type.isArray()) { + ResolvedJavaField[] fields = type.getInstanceFields(true); + int fieldIndex = 0; + for (int i = 0; i < values.length; i++) { + ResolvedJavaField field = fields[fieldIndex++]; + JavaKind valKind = slotKinds[i].getStackKind(); + JavaKind fieldKind = storageKind(field.getType()); + if (fieldKind == JavaKind.Object) { + assert valKind.isObject() : field + ": " + valKind + " != " + fieldKind; + } else { + if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && fieldKind == JavaKind.Int) { + assert storageKind(fields[fieldIndex].getType()) == JavaKind.Int; + fieldIndex++; + } else { + assert valKind == fieldKind.getStackKind() : field + ": " + valKind + " != " + fieldKind; + } + } + } + assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values); + } else { + JavaKind componentKind = storageKind(type.getComponentType()).getStackKind(); + if (componentKind == JavaKind.Object) { + for (int i = 0; i < values.length; i++) { + assert slotKinds[i].isObject() : slotKinds[i] + " != " + componentKind; + } + } else { + for (int i = 0; i < values.length; i++) { + assert slotKinds[i] == componentKind || componentKind.getBitCount() >= slotKinds[i].getBitCount() || + (componentKind == JavaKind.Int && slotKinds[i].getBitCount() >= JavaKind.Int.getBitCount()) : slotKinds[i] + " != " + componentKind; + } + } + } + } + return true; + } + + /* + * Customization point for subclasses. For example, Word types have a kind Object, but are + * internally stored as a primitive value. We do not know about Word types here, but subclasses + * do know. + */ + protected JavaKind storageKind(JavaType type) { + return type.getJavaKind(); + } + + protected LIRFrameState newLIRFrameState(LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) { + return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge); + } + + protected BytecodeFrame computeFrameForState(FrameState state) { + try { + assert state.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI; + assert state.bci != BytecodeFrame.UNKNOWN_BCI; + assert state.bci != BytecodeFrame.BEFORE_BCI || state.locksSize() == 0; + assert state.bci != BytecodeFrame.AFTER_BCI || state.locksSize() == 0; + assert state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI || state.locksSize() == 0; + assert !(state.getMethod().isSynchronized() && state.bci != BytecodeFrame.BEFORE_BCI && state.bci != BytecodeFrame.AFTER_BCI && state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI) || + state.locksSize() > 0; + assert state.verify(); + + int numLocals = state.localsSize(); + int numStack = state.stackSize(); + int numLocks = state.locksSize(); + + int numValues = numLocals + numStack + numLocks; + int numKinds = numLocals + numStack; + + JavaValue[] values = numValues == 0 ? NO_JAVA_VALUES : new JavaValue[numValues]; + JavaKind[] slotKinds = numKinds == 0 ? NO_JAVA_KINDS : new JavaKind[numKinds]; + computeLocals(state, numLocals, values, slotKinds); + computeStack(state, numLocals, numStack, values, slotKinds); + computeLocks(state, values); + + BytecodeFrame caller = null; + if (state.outerFrameState() != null) { + caller = computeFrameForState(state.outerFrameState()); + } + + if (!state.canProduceBytecodeFrame()) { + // This typically means a snippet or intrinsic frame state made it to the backend + StackTraceElement ste = state.getCode().asStackTraceElement(state.bci); + throw new GraalError("Frame state for %s cannot be converted to a BytecodeFrame since the frame state's code is " + + "not the same as the frame state method's code", ste); + } + + return new BytecodeFrame(caller, state.getMethod(), state.bci, state.rethrowException(), state.duringCall(), values, slotKinds, numLocals, numStack, numLocks); + } catch (GraalError e) { + throw e.addContext("FrameState: ", state); + } + } + + protected void computeLocals(FrameState state, int numLocals, JavaValue[] values, JavaKind[] slotKinds) { + for (int i = 0; i < numLocals; i++) { + ValueNode local = state.localAt(i); + values[i] = toJavaValue(local); + slotKinds[i] = toSlotKind(local); + } + } + + protected void computeStack(FrameState state, int numLocals, int numStack, JavaValue[] values, JavaKind[] slotKinds) { + for (int i = 0; i < numStack; i++) { + ValueNode stack = state.stackAt(i); + values[numLocals + i] = toJavaValue(stack); + slotKinds[numLocals + i] = toSlotKind(stack); + } + } + + protected void computeLocks(FrameState state, JavaValue[] values) { + for (int i = 0; i < state.locksSize(); i++) { + values[state.localsSize() + state.stackSize() + i] = computeLockValue(state, i); + } + } + + protected JavaValue computeLockValue(FrameState state, int i) { + return toJavaValue(state.lockAt(i)); + } + + private static final DebugCounter STATE_VIRTUAL_OBJECTS = Debug.counter("StateVirtualObjects"); + private static final DebugCounter STATE_ILLEGALS = Debug.counter("StateIllegals"); + private static final DebugCounter STATE_VARIABLES = Debug.counter("StateVariables"); + private static final DebugCounter STATE_CONSTANTS = Debug.counter("StateConstants"); + + private static JavaKind toSlotKind(ValueNode value) { + if (value == null) { + return JavaKind.Illegal; + } else { + return value.getStackKind(); + } + } + + protected JavaValue toJavaValue(ValueNode value) { + try { + if (value instanceof VirtualObjectNode) { + VirtualObjectNode obj = (VirtualObjectNode) value; + EscapeObjectState state = objectStates.get(obj); + if (state == null && obj.entryCount() > 0) { + // null states occur for objects with 0 fields + throw new GraalError("no mapping found for virtual object %s", obj); + } + if (state instanceof MaterializedObjectState) { + return toJavaValue(((MaterializedObjectState) state).materializedValue()); + } else { + assert obj.entryCount() == 0 || state instanceof VirtualObjectState; + VirtualObject vobject = virtualObjects.get(obj); + if (vobject == null) { + vobject = VirtualObject.get(obj.type(), virtualObjects.size()); + virtualObjects.put(obj, vobject); + pendingVirtualObjects.add(obj); + } + STATE_VIRTUAL_OBJECTS.increment(); + return vobject; + } + } else { + // Remove proxies from constants so the constant can be directly embedded. + ValueNode unproxied = GraphUtil.unproxify(value); + if (unproxied instanceof ConstantNode) { + STATE_CONSTANTS.increment(); + return unproxied.asJavaConstant(); + + } else if (value != null) { + STATE_VARIABLES.increment(); + Value operand = nodeValueMap.operand(value); + if (operand instanceof ConstantValue && ((ConstantValue) operand).isJavaConstant()) { + return ((ConstantValue) operand).getJavaConstant(); + } else { + assert operand instanceof Variable : operand + " for " + value; + return (JavaValue) operand; + } + + } else { + // return a dummy value because real value not needed + STATE_ILLEGALS.increment(); + return Value.ILLEGAL; + } + } + } catch (GraalError e) { + throw e.addContext("toValue: ", value); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/InstructionPrinter.java 2016-12-07 13:48:47.217588095 -0800 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2009, 2011, 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.core.gen; + +import static org.graalvm.compiler.core.gen.InstructionPrinter.InstructionLineColumn.BCI; +import static org.graalvm.compiler.core.gen.InstructionPrinter.InstructionLineColumn.END; +import static org.graalvm.compiler.core.gen.InstructionPrinter.InstructionLineColumn.INSTRUCTION; +import static org.graalvm.compiler.core.gen.InstructionPrinter.InstructionLineColumn.USE; +import static org.graalvm.compiler.core.gen.InstructionPrinter.InstructionLineColumn.VALUE; + +import org.graalvm.compiler.debug.LogStream; +import org.graalvm.compiler.nodes.StateSplit; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.ValueNodeUtil; + +/** + * A utility for {@linkplain #printInstruction(ValueNode) printing} a node as an expression or + * statement. + */ +public class InstructionPrinter { + + /** + * The columns printed in a tabulated instruction + * {@linkplain InstructionPrinter#printInstructionListing(ValueNode) listing}. + */ + public enum InstructionLineColumn { + /** + * The instruction's bytecode index. + */ + BCI(2, "bci"), + + /** + * The instruction's use count. + */ + USE(7, "use"), + + /** + * The instruction as a value. + */ + VALUE(12, "tid"), + + /** + * The instruction formatted as an expression or statement. + */ + INSTRUCTION(19, "instr"), + + END(60, ""); + + final int position; + final String label; + + InstructionLineColumn(int position, String label) { + this.position = position; + this.label = label; + } + + /** + * Prints this column's label to a given stream after padding the stream with '_' characters + * until its {@linkplain LogStream#position() position} is equal to this column's position. + * + * @param out the print stream + */ + public void printLabel(LogStream out) { + out.fillTo(position + out.indentationLevel(), '_'); + out.print(label); + } + + /** + * Prints space characters to a given stream until its {@linkplain LogStream#position() + * position} is equal to this column's position. + * + * @param out the print stream + */ + public void advance(LogStream out) { + out.fillTo(position + out.indentationLevel(), ' '); + } + } + + private final LogStream out; + + public InstructionPrinter(LogStream out) { + this.out = out; + } + + public LogStream out() { + return out; + } + + /** + * Prints a header for the tabulated data printed by {@link #printInstructionListing(ValueNode)} + * . + */ + public void printInstructionListingHeader() { + BCI.printLabel(out); + USE.printLabel(out); + VALUE.printLabel(out); + INSTRUCTION.printLabel(out); + END.printLabel(out); + out.println(); + } + + /** + * Prints an instruction listing on one line. The instruction listing is composed of the columns + * specified by {@link InstructionLineColumn}. + * + * @param instruction the instruction to print + */ + public void printInstructionListing(ValueNode instruction) { + int indentation = out.indentationLevel(); + out.fillTo(BCI.position + indentation, ' ').print(0).fillTo(USE.position + indentation, ' ').print("0").fillTo(VALUE.position + indentation, ' ').print( + ValueNodeUtil.valueString(instruction)).fillTo( + INSTRUCTION.position + indentation, ' '); + printInstruction(instruction); + if (instruction instanceof StateSplit) { + out.print(" [state: " + ((StateSplit) instruction).stateAfter() + "]"); + } + out.println(); + } + + public void printInstruction(ValueNode node) { + out.print(node.toString()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java 2016-12-07 13:48:47.482599744 -0800 @@ -0,0 +1,746 @@ +/* + * Copyright (c) 2009, 2016, 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.core.gen; + +import static org.graalvm.compiler.core.common.GraalOptions.MatchExpressions; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.LogVerbose; +import static org.graalvm.compiler.lir.LIR.verifyBlock; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isLegal; +import static jdk.vm.ci.code.ValueUtil.isRegister; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.core.common.cfg.BlockMap; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.match.ComplexMatchValue; +import org.graalvm.compiler.core.match.MatchRuleRegistry; +import org.graalvm.compiler.core.match.MatchStatement; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.graph.GraalGraphError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeMap; +import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.lir.FullInfopointOp; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.StandardOp.JumpOp; +import org.graalvm.compiler.lir.StandardOp.LabelOp; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.debug.LIRGenerationDebugContext; +import org.graalvm.compiler.lir.gen.LIRGenerator; +import org.graalvm.compiler.lir.gen.LIRGenerator.Options; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool.BlockScope; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.AbstractEndNode; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.DeoptimizingNode; +import org.graalvm.compiler.nodes.DirectCallTargetNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.FullInfopointNode; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.IndirectCallTargetNode; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.InvokeWithExceptionNode; +import org.graalvm.compiler.nodes.LogicConstantNode; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.LoopEndNode; +import org.graalvm.compiler.nodes.LoweredCallTargetNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.ValuePhiNode; +import org.graalvm.compiler.nodes.calc.CompareNode; +import org.graalvm.compiler.nodes.calc.ConditionalNode; +import org.graalvm.compiler.nodes.calc.IntegerTestNode; +import org.graalvm.compiler.nodes.calc.IsNullNode; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; +import org.graalvm.compiler.nodes.extended.SwitchNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.spi.NodeValueMap; +import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +/** + * This class traverses the HIR instructions and generates LIR instructions from them. + */ +public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGenerationDebugContext { + + private final NodeMap nodeOperands; + private final DebugInfoBuilder debugInfoBuilder; + + protected final LIRGenerator gen; + + private ValueNode currentInstruction; + private ValueNode lastInstructionPrinted; // Debugging only + + private final NodeMatchRules nodeMatchRules; + private Map, List> matchRules; + + public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, NodeMatchRules nodeMatchRules) { + this.gen = (LIRGenerator) gen; + this.nodeMatchRules = nodeMatchRules; + this.nodeOperands = graph.createNodeMap(); + this.debugInfoBuilder = createDebugInfoBuilder(graph, this); + if (MatchExpressions.getValue()) { + matchRules = MatchRuleRegistry.lookup(nodeMatchRules.getClass()); + } + + assert nodeMatchRules.lirBuilder == null; + nodeMatchRules.lirBuilder = this; + } + + public NodeMatchRules getNodeMatchRules() { + return nodeMatchRules; + } + + @SuppressWarnings({"unused"}) + protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) { + return new DebugInfoBuilder(nodeValueMap); + } + + /** + * Returns the operand that has been previously initialized by + * {@link #setResult(ValueNode, Value)} with the result of an instruction. It's a code + * generation error to ask for the operand of ValueNode that doesn't have one yet. + * + * @param node A node that produces a result value. + */ + @Override + public Value operand(Node node) { + Value operand = getOperand(node); + assert operand != null : String.format("missing operand for %1s", node); + return operand; + } + + @Override + public boolean hasOperand(Node node) { + return getOperand(node) != null; + } + + private Value getOperand(Node node) { + if (nodeOperands == null) { + return null; + } + return nodeOperands.get(node); + } + + @Override + public ValueNode valueForOperand(Value value) { + assert nodeOperands != null; + for (Entry entry : nodeOperands.entries()) { + if (entry.getValue().equals(value)) { + return (ValueNode) entry.getKey(); + } + } + return null; + } + + @Override + public Object getSourceForOperand(Value value) { + return valueForOperand(value); + } + + @Override + public Value setResult(ValueNode x, Value operand) { + assert (!isRegister(operand) || !gen.attributes(asRegister(operand)).isAllocatable()); + assert nodeOperands != null && (nodeOperands.get(x) == null || nodeOperands.get(x) instanceof ComplexMatchValue) : "operand cannot be set twice"; + assert operand != null && isLegal(operand) : "operand must be legal"; + assert !(x instanceof VirtualObjectNode); + nodeOperands.set(x, operand); + return operand; + } + + /** + * Used by the {@link MatchStatement} machinery to override the generation LIR for some + * ValueNodes. + */ + public void setMatchResult(Node x, Value operand) { + assert operand.equals(ComplexMatchValue.INTERIOR_MATCH) || operand instanceof ComplexMatchValue; + assert operand instanceof ComplexMatchValue || x.getUsageCount() == 1 : "interior matches must be single user"; + assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice"; + assert !(x instanceof VirtualObjectNode); + nodeOperands.set(x, operand); + } + + public LabelRef getLIRBlock(FixedNode b) { + assert gen.getResult().getLIR().getControlFlowGraph() instanceof ControlFlowGraph; + Block result = ((ControlFlowGraph) gen.getResult().getLIR().getControlFlowGraph()).blockFor(b); + int suxIndex = 0; + for (AbstractBlockBase succ : gen.getCurrentBlock().getSuccessors()) { + if (succ == result) { + assert gen.getCurrentBlock() instanceof Block; + return LabelRef.forSuccessor(gen.getResult().getLIR(), gen.getCurrentBlock(), suxIndex); + } + suxIndex++; + } + throw GraalError.shouldNotReachHere("Block not in successor list of current block"); + } + + public final void append(LIRInstruction op) { + if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) { + if (currentInstruction != null && lastInstructionPrinted != currentInstruction) { + lastInstructionPrinted = currentInstruction; + InstructionPrinter ip = new InstructionPrinter(TTY.out()); + ip.printInstructionListing(currentInstruction); + } + } + gen.append(op); + } + + protected LIRKind getExactPhiKind(PhiNode phi) { + // TODO (je): maybe turn this into generator-style instead of allocating an ArrayList. + ArrayList values = new ArrayList<>(phi.valueCount()); + for (int i = 0; i < phi.valueCount(); i++) { + ValueNode node = phi.valueAt(i); + Value value = getOperand(node); + if (value != null) { + values.add(value.getValueKind(LIRKind.class)); + } else { + assert isPhiInputFromBackedge(phi, i) : String.format("Input %s to phi node %s is not yet available although it is not coming from a loop back edge", node, phi); + // non-java constant -> get LIRKind from stamp. + LIRKind kind = gen.getLIRKind(node.stamp()); + values.add(gen.toRegisterKind(kind)); + } + } + LIRKind derivedKind = LIRKind.merge(values); + assert verifyPHIKind(derivedKind, gen.getLIRKind(phi.stamp())); + return derivedKind; + } + + private boolean verifyPHIKind(LIRKind derivedKind, LIRKind phiKind) { + PlatformKind derivedPlatformKind = derivedKind.getPlatformKind(); + PlatformKind phiPlatformKind = gen.toRegisterKind(phiKind).getPlatformKind(); + assert derivedPlatformKind.equals(phiPlatformKind) : "kinds don't match: " + derivedPlatformKind + " vs " + phiPlatformKind; + return true; + } + + private static boolean isPhiInputFromBackedge(PhiNode phi, int index) { + AbstractMergeNode merge = phi.merge(); + AbstractEndNode end = merge.phiPredecessorAt(index); + return end instanceof LoopEndNode && ((LoopEndNode) end).loopBegin().equals(merge); + } + + private Value[] createPhiIn(AbstractMergeNode merge) { + List values = new ArrayList<>(); + for (ValuePhiNode phi : merge.valuePhis()) { + assert getOperand(phi) == null; + Variable value = gen.newVariable(getExactPhiKind(phi)); + values.add(value); + setResult(phi, value); + } + return values.toArray(new Value[values.size()]); + } + + /** + * @return {@code true} if object constant to stack moves are supported. + */ + protected boolean allowObjectConstantToStackMove() { + return true; + } + + private Value[] createPhiOut(AbstractMergeNode merge, AbstractEndNode pred) { + List values = new ArrayList<>(); + for (PhiNode phi : merge.valuePhis()) { + ValueNode node = phi.valueAt(pred); + Value value = operand(node); + assert value != null; + if (isRegister(value)) { + /* + * Fixed register intervals are not allowed at block boundaries so we introduce a + * new Variable. + */ + value = gen.emitMove(value); + } else if (!allowObjectConstantToStackMove() && node instanceof ConstantNode && !LIRKind.isValue(value)) { + /* + * Some constants are not allowed as inputs for PHIs in certain backends. Explicitly + * create a copy of this value to force it into a register. The new variable is only + * used in the PHI. + */ + Variable result = gen.newVariable(value.getValueKind()); + gen.emitMove(result, value); + value = result; + } + values.add(value); + } + return values.toArray(new Value[values.size()]); + } + + @Override + @SuppressWarnings("try") + public void doBlock(Block block, StructuredGraph graph, BlockMap> blockMap) { + try (BlockScope blockScope = gen.getBlockScope(block)) { + setSourcePosition(null); + + if (block == gen.getResult().getLIR().getControlFlowGraph().getStartBlock()) { + assert block.getPredecessorCount() == 0; + emitPrologue(graph); + } else { + assert block.getPredecessorCount() > 0; + // create phi-in value array + AbstractBeginNode begin = block.getBeginNode(); + if (begin instanceof AbstractMergeNode) { + AbstractMergeNode merge = (AbstractMergeNode) begin; + LabelOp label = (LabelOp) gen.getResult().getLIR().getLIRforBlock(block).get(0); + label.setPhiValues(createPhiIn(merge)); + if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) { + TTY.println("Created PhiIn: " + label); + + } + } + } + + List nodes = blockMap.get(block); + + // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups + // of instructions + matchComplexExpressions(nodes); + + for (int i = 0; i < nodes.size(); i++) { + Node node = nodes.get(i); + if (node instanceof ValueNode) { + ValueNode valueNode = (ValueNode) node; + if (Options.TraceLIRGeneratorLevel.getValue() >= 3) { + TTY.println("LIRGen for " + valueNode); + } + Value operand = getOperand(valueNode); + if (operand == null) { + if (!peephole(valueNode)) { + try { + doRoot(valueNode); + } catch (GraalError e) { + throw GraalGraphError.transformAndAddContext(e, valueNode); + } catch (Throwable e) { + throw new GraalGraphError(e).addContext(valueNode); + } + } + } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) { + // Doesn't need to be evaluated + Debug.log("interior match for %s", valueNode); + } else if (operand instanceof ComplexMatchValue) { + Debug.log("complex match for %s", valueNode); + ComplexMatchValue match = (ComplexMatchValue) operand; + operand = match.evaluate(this); + if (operand != null) { + setResult(valueNode, operand); + } + } else { + // There can be cases in which the result of an instruction is already set + // before by other instructions. + } + } + } + + if (!gen.hasBlockEnd(block)) { + NodeIterable successors = block.getEndNode().successors(); + assert successors.count() == block.getSuccessorCount(); + if (block.getSuccessorCount() != 1) { + /* + * If we have more than one successor, we cannot just use the first one. Since + * successors are unordered, this would be a random choice. + */ + throw new GraalError("Block without BlockEndOp: " + block.getEndNode()); + } + gen.emitJump(getLIRBlock((FixedNode) successors.first())); + } + + assert verifyBlock(gen.getResult().getLIR(), block); + } + } + + @SuppressWarnings("try") + protected void matchComplexExpressions(List nodes) { + if (matchRules != null) { + try (Scope s = Debug.scope("MatchComplexExpressions")) { + if (LogVerbose.getValue()) { + int i = 0; + for (Node node : nodes) { + Debug.log("%d: (%s) %1S", i++, node.getUsageCount(), node); + } + } + + // Match the nodes in backwards order to encourage longer matches. + for (int index = nodes.size() - 1; index >= 0; index--) { + Node node = nodes.get(index); + if (getOperand(node) != null) { + continue; + } + // See if this node is the root of any MatchStatements + List statements = matchRules.get(node.getClass()); + if (statements != null) { + for (MatchStatement statement : statements) { + if (statement.generate(this, index, node, nodes)) { + // Found a match so skip to the next + break; + } + } + } + } + } + } + } + + protected abstract boolean peephole(ValueNode valueNode); + + private void doRoot(ValueNode instr) { + if (Options.TraceLIRGeneratorLevel.getValue() >= 2) { + TTY.println("Emitting LIR for instruction " + instr); + } + currentInstruction = instr; + + Debug.log("Visiting %s", instr); + emitNode(instr); + Debug.log("Operand for %s = %s", instr, getOperand(instr)); + } + + protected void emitNode(ValueNode node) { + if (Debug.isLogEnabled() && node.stamp().isEmpty()) { + Debug.log("This node has an empty stamp, we are emitting dead code(?): %s", node); + } + setSourcePosition(node.getNodeSourcePosition()); + if (node instanceof LIRLowerable) { + ((LIRLowerable) node).generate(this); + } else { + throw GraalError.shouldNotReachHere("node is not LIRLowerable: " + node); + } + } + + protected void emitPrologue(StructuredGraph graph) { + CallingConvention incomingArguments = gen.getResult().getCallingConvention(); + + Value[] params = new Value[incomingArguments.getArgumentCount()]; + for (int i = 0; i < params.length; i++) { + params[i] = incomingArguments.getArgument(i); + if (ValueUtil.isStackSlot(params[i])) { + StackSlot slot = ValueUtil.asStackSlot(params[i]); + if (slot.isInCallerFrame() && !gen.getResult().getLIR().hasArgInCallerFrame()) { + gen.getResult().getLIR().setHasArgInCallerFrame(); + } + } + } + + gen.emitIncomingValues(params); + + for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { + Value paramValue = params[param.index()]; + assert paramValue.getValueKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp())) : paramValue + " " + getLIRGeneratorTool().getLIRKind(param.stamp()); + setResult(param, gen.emitMove(paramValue)); + } + } + + @Override + public void visitMerge(AbstractMergeNode x) { + } + + @Override + public void visitEndNode(AbstractEndNode end) { + AbstractMergeNode merge = end.merge(); + JumpOp jump = newJumpOp(getLIRBlock(merge)); + jump.setPhiValues(createPhiOut(merge, end)); + append(jump); + } + + /** + * Runtime specific classes can override this to insert a safepoint at the end of a loop. + */ + @Override + public void visitLoopEnd(LoopEndNode x) { + } + + protected JumpOp newJumpOp(LabelRef ref) { + return new JumpOp(ref); + } + + protected LIRKind getPhiKind(PhiNode phi) { + return gen.getLIRKind(phi.stamp()); + } + + @Override + public void emitIf(IfNode x) { + emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor())); + } + + public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + if (node instanceof IsNullNode) { + emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); + } else if (node instanceof CompareNode) { + emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); + } else if (node instanceof LogicConstantNode) { + emitConstantBranch(((LogicConstantNode) node).getValue(), trueSuccessor, falseSuccessor); + } else if (node instanceof IntegerTestNode) { + emitIntegerTestBranch((IntegerTestNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); + } else { + throw GraalError.unimplemented(node.toString()); + } + } + + private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + LIRKind kind = gen.getLIRKind(node.getValue().stamp()); + Value nullValue = gen.emitConstant(kind, JavaConstant.NULL_POINTER); + gen.emitCompareBranch(kind.getPlatformKind(), operand(node.getValue()), nullValue, Condition.EQ, false, trueSuccessor, falseSuccessor, trueSuccessorProbability); + } + + public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + PlatformKind kind = gen.getLIRKind(compare.getX().stamp()).getPlatformKind(); + gen.emitCompareBranch(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability); + } + + public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + gen.emitIntegerTestBranch(operand(test.getX()), operand(test.getY()), trueSuccessor, falseSuccessor, trueSuccessorProbability); + } + + public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) { + LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock; + gen.emitJump(block); + } + + @Override + public void emitConditional(ConditionalNode conditional) { + Value tVal = operand(conditional.trueValue()); + Value fVal = operand(conditional.falseValue()); + setResult(conditional, emitConditional(conditional.condition(), tVal, fVal)); + } + + public Variable emitConditional(LogicNode node, Value trueValue, Value falseValue) { + if (node instanceof IsNullNode) { + IsNullNode isNullNode = (IsNullNode) node; + LIRKind kind = gen.getLIRKind(isNullNode.getValue().stamp()); + Value nullValue = gen.emitConstant(kind, JavaConstant.NULL_POINTER); + return gen.emitConditionalMove(kind.getPlatformKind(), operand(isNullNode.getValue()), nullValue, Condition.EQ, false, trueValue, falseValue); + } else if (node instanceof CompareNode) { + CompareNode compare = (CompareNode) node; + PlatformKind kind = gen.getLIRKind(compare.getX().stamp()).getPlatformKind(); + return gen.emitConditionalMove(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueValue, falseValue); + } else if (node instanceof LogicConstantNode) { + return gen.emitMove(((LogicConstantNode) node).getValue() ? trueValue : falseValue); + } else if (node instanceof IntegerTestNode) { + IntegerTestNode test = (IntegerTestNode) node; + return gen.emitIntegerTestMove(operand(test.getX()), operand(test.getY()), trueValue, falseValue); + } else { + throw GraalError.unimplemented(node.toString()); + } + } + + @Override + public void emitInvoke(Invoke x) { + LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget(); + CallingConvention invokeCc = gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(gen.getMetaAccess()), + callTarget.signature(), gen); + gen.getResult().getFrameMapBuilder().callsMethod(invokeCc); + + Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments()); + + LabelRef exceptionEdge = null; + if (x instanceof InvokeWithExceptionNode) { + exceptionEdge = getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()); + } + LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge); + + Value result = invokeCc.getReturn(); + if (callTarget instanceof DirectCallTargetNode) { + emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); + } else if (callTarget instanceof IndirectCallTargetNode) { + emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); + } else { + throw GraalError.shouldNotReachHere(); + } + + if (isLegal(result)) { + setResult(x.asNode(), gen.emitMove(result)); + } + + if (x instanceof InvokeWithExceptionNode) { + gen.emitJump(getLIRBlock(((InvokeWithExceptionNode) x).next())); + } + } + + protected abstract void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); + + protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); + + @Override + public Value[] visitInvokeArguments(CallingConvention invokeCc, Collection arguments) { + // for each argument, load it into the correct location + Value[] result = new Value[arguments.size()]; + int j = 0; + for (ValueNode arg : arguments) { + if (arg != null) { + AllocatableValue operand = invokeCc.getArgument(j); + gen.emitMove(operand, operand(arg)); + result[j] = operand; + j++; + } else { + throw GraalError.shouldNotReachHere("I thought we no longer have null entries for two-slot types..."); + } + } + return result; + } + + /** + * This method tries to create a switch implementation that is optimal for the given switch. It + * will either generate a sequential if/then/else cascade, a set of range tests or a table + * switch. + * + * If the given switch does not contain int keys, it will always create a sequential + * implementation. + */ + @Override + public void emitSwitch(SwitchNode x) { + assert x.defaultSuccessor() != null; + LabelRef defaultTarget = getLIRBlock(x.defaultSuccessor()); + int keyCount = x.keyCount(); + if (keyCount == 0) { + gen.emitJump(defaultTarget); + } else { + Variable value = gen.load(operand(x.value())); + if (keyCount == 1) { + assert defaultTarget != null; + double probability = x.probability(x.keySuccessor(0)); + LIRKind kind = gen.getLIRKind(x.value().stamp()); + Value key = gen.emitConstant(kind, x.keyAt(0)); + gen.emitCompareBranch(kind.getPlatformKind(), gen.load(operand(x.value())), key, Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget, probability); + } else if (x instanceof IntegerSwitchNode && x.isSorted()) { + IntegerSwitchNode intSwitch = (IntegerSwitchNode) x; + LabelRef[] keyTargets = new LabelRef[keyCount]; + JavaConstant[] keyConstants = new JavaConstant[keyCount]; + double[] keyProbabilities = new double[keyCount]; + JavaKind keyKind = intSwitch.keyAt(0).getJavaKind(); + for (int i = 0; i < keyCount; i++) { + keyTargets[i] = getLIRBlock(intSwitch.keySuccessor(i)); + keyConstants[i] = intSwitch.keyAt(i); + keyProbabilities[i] = intSwitch.keyProbability(i); + assert keyConstants[i].getJavaKind() == keyKind; + } + gen.emitStrategySwitch(keyConstants, keyProbabilities, keyTargets, defaultTarget, value); + } else { + // keyKind != JavaKind.Int || !x.isSorted() + LabelRef[] keyTargets = new LabelRef[keyCount]; + Constant[] keyConstants = new Constant[keyCount]; + double[] keyProbabilities = new double[keyCount]; + for (int i = 0; i < keyCount; i++) { + keyTargets[i] = getLIRBlock(x.keySuccessor(i)); + keyConstants[i] = x.keyAt(i); + keyProbabilities[i] = x.keyProbability(i); + } + + // hopefully only a few entries + gen.emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget); + } + } + } + + public DebugInfoBuilder getDebugInfoBuilder() { + assert debugInfoBuilder != null; + return debugInfoBuilder; + } + + private static FrameState getFrameState(DeoptimizingNode deopt) { + if (deopt instanceof DeoptimizingNode.DeoptBefore) { + assert !(deopt instanceof DeoptimizingNode.DeoptDuring || deopt instanceof DeoptimizingNode.DeoptAfter); + return ((DeoptimizingNode.DeoptBefore) deopt).stateBefore(); + } else if (deopt instanceof DeoptimizingNode.DeoptDuring) { + assert !(deopt instanceof DeoptimizingNode.DeoptAfter); + return ((DeoptimizingNode.DeoptDuring) deopt).stateDuring(); + } else { + assert deopt instanceof DeoptimizingNode.DeoptAfter; + return ((DeoptimizingNode.DeoptAfter) deopt).stateAfter(); + } + } + + @Override + public LIRFrameState state(DeoptimizingNode deopt) { + if (!deopt.canDeoptimize()) { + return null; + } + return stateFor(getFrameState(deopt)); + } + + public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) { + if (!deopt.canDeoptimize()) { + return null; + } + return stateForWithExceptionEdge(getFrameState(deopt), exceptionEdge); + } + + public LIRFrameState stateFor(FrameState state) { + return stateForWithExceptionEdge(state, null); + } + + public LIRFrameState stateForWithExceptionEdge(FrameState state, LabelRef exceptionEdge) { + if (gen.needOnlyOopMaps()) { + return new LIRFrameState(null, null, null); + } + assert state != null; + return getDebugInfoBuilder().build(state, exceptionEdge); + } + + @Override + public void emitOverflowCheckBranch(AbstractBeginNode overflowSuccessor, AbstractBeginNode next, Stamp stamp, double probability) { + LIRKind cmpKind = getLIRGeneratorTool().getLIRKind(stamp); + gen.emitOverflowCheckBranch(getLIRBlock(overflowSuccessor), getLIRBlock(next), cmpKind, probability); + } + + @Override + public void visitFullInfopointNode(FullInfopointNode i) { + append(new FullInfopointOp(stateFor(i.getState()), i.getReason())); + } + + @Override + public void setSourcePosition(NodeSourcePosition position) { + gen.setSourcePosition(position); + } + + @Override + public LIRGeneratorTool getLIRGeneratorTool() { + return gen; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java 2016-12-07 13:48:47.749611481 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2009, 2015, 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.core.gen; + +import jdk.vm.ci.meta.Value; + +import org.graalvm.compiler.core.match.MatchableNode; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.DeoptimizingNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.AndNode; +import org.graalvm.compiler.nodes.calc.FloatConvertNode; +import org.graalvm.compiler.nodes.calc.FloatEqualsNode; +import org.graalvm.compiler.nodes.calc.FloatLessThanNode; +import org.graalvm.compiler.nodes.calc.IntegerBelowNode; +import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; +import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; +import org.graalvm.compiler.nodes.calc.IntegerTestNode; +import org.graalvm.compiler.nodes.calc.LeftShiftNode; +import org.graalvm.compiler.nodes.calc.MulNode; +import org.graalvm.compiler.nodes.calc.NarrowNode; +import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; +import org.graalvm.compiler.nodes.calc.OrNode; +import org.graalvm.compiler.nodes.calc.PointerEqualsNode; +import org.graalvm.compiler.nodes.calc.ReinterpretNode; +import org.graalvm.compiler.nodes.calc.SignExtendNode; +import org.graalvm.compiler.nodes.calc.SubNode; +import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode; +import org.graalvm.compiler.nodes.calc.XorNode; +import org.graalvm.compiler.nodes.calc.ZeroExtendNode; +import org.graalvm.compiler.nodes.memory.FloatingReadNode; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.WriteNode; + +@MatchableNode(nodeClass = ConstantNode.class, shareable = true) +@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"value"}) +@MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"address"}) +@MatchableNode(nodeClass = IfNode.class, inputs = {"condition"}) +@MatchableNode(nodeClass = SubNode.class, inputs = {"x", "y"}) +@MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"}) +@MatchableNode(nodeClass = NarrowNode.class, inputs = {"value"}) +@MatchableNode(nodeClass = ReadNode.class, inputs = {"address"}) +@MatchableNode(nodeClass = ReinterpretNode.class, inputs = {"value"}) +@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"value"}) +@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = {"x", "y"}) +@MatchableNode(nodeClass = WriteNode.class, inputs = {"address", "value"}) +@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"value"}) +@MatchableNode(nodeClass = AndNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = FloatEqualsNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = FloatLessThanNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = PointerEqualsNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = AddNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = IntegerBelowNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = MulNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = IntegerTestNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = OrNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = XorNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = PiNode.class, inputs = {"object"}) +public abstract class NodeMatchRules { + + NodeLIRBuilder lirBuilder; + protected final LIRGeneratorTool gen; + + protected NodeMatchRules(LIRGeneratorTool gen) { + this.gen = gen; + } + + protected LIRGeneratorTool getLIRGeneratorTool() { + return gen; + } + + /* + * For now we do not want to expose the full lirBuilder to subclasses, so we delegate the few + * methods that are actually needed. If the list grows too long, exposing lirBuilder might be + * the better approach. + */ + + protected final Value operand(Node node) { + return lirBuilder.operand(node); + } + + protected final LIRFrameState state(DeoptimizingNode deopt) { + return lirBuilder.state(deopt); + } + + protected final LabelRef getLIRBlock(FixedNode b) { + return lirBuilder.getLIRBlock(b); + } + + protected final void append(LIRInstruction op) { + lirBuilder.append(op); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/package-info.java 2016-12-07 13:48:48.014623130 -0800 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2009, 2011, 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. + */ +/** + * This package contains the port of the LIRGenerator which translates HIR instructions to LIR + * instructions for the backend. + */ +package org.graalvm.compiler.core.gen; --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/ComplexMatchResult.java 2016-12-07 13:48:48.278634735 -0800 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, 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.core.match; + +import jdk.vm.ci.meta.Value; + +import org.graalvm.compiler.core.gen.NodeLIRBuilder; + +/** + * A closure that can be evaluated to produce the LIR for some complex match. Using a closure allows + * normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes evaluated at + * the proper time. + */ +public interface ComplexMatchResult { + Value evaluate(NodeLIRBuilder gen); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/ComplexMatchValue.java 2016-12-07 13:48:48.542646340 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014, 2015, 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.core.match; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.gen.NodeLIRBuilder; + +import jdk.vm.ci.meta.Value; + +/** + * A wrapper value for the lazy evaluation of a complex match. There's an intermediate class for the + * closure because Value is serializable which is a hassle for the little inner classes which + * usually occur here. + */ +public class ComplexMatchValue extends Value { + + /** + * This is the Value of a node which was matched as part of a complex match. The value isn't + * actually useable but this marks it as having been evaluated. + */ + public static final Value INTERIOR_MATCH = new Value(LIRKind.Illegal) { + + @Override + public String toString() { + return "INTERIOR_MATCH"; + } + + @Override + public boolean equals(Object other) { + // This class is a singleton + return other != null && getClass() == other.getClass(); + } + }; + + final ComplexMatchResult result; + + public ComplexMatchValue(ComplexMatchResult result) { + super(LIRKind.Illegal); + this.result = result; + } + + public Value evaluate(NodeLIRBuilder builder) { + return result.evaluate(builder); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java 2016-12-07 13:48:48.807657989 -0800 @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2014, 2015, 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.core.match; + +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.LogVerbose; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.graalvm.compiler.core.gen.NodeLIRBuilder; +import org.graalvm.compiler.core.match.MatchPattern.Result; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; + +/** + * Container for state captured during a match. + */ +public class MatchContext { + + private final Node root; + + private final List nodes; + + private final MatchStatement rule; + + private Map namedNodes; + + private ArrayList consumed; + + private int startIndex; + + private int endIndex; + + private final NodeLIRBuilder builder; + + private static class NamedNode { + final Class type; + final Node value; + + NamedNode(Class type, Node value) { + this.type = type; + this.value = value; + } + } + + public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, Node node, List nodes) { + this.builder = builder; + this.rule = rule; + this.root = node; + this.nodes = nodes; + assert index == nodes.indexOf(node); + // The root should be the last index since all the inputs must be scheduled before it. + startIndex = endIndex = index; + } + + public Node getRoot() { + return root; + } + + public Result captureNamedValue(String name, Class type, Node value) { + if (namedNodes == null) { + namedNodes = new HashMap<>(2); + } + NamedNode current = namedNodes.get(name); + if (current == null) { + current = new NamedNode(type, value); + namedNodes.put(name, current); + return Result.OK; + } else { + if (current.value != value || current.type != type) { + return Result.namedValueMismatch(value, rule.getPattern()); + } + return Result.OK; + } + } + + public Result validate() { + // Ensure that there's no unsafe work in between these operations. + for (int i = startIndex; i <= endIndex; i++) { + Node node = nodes.get(i); + if (node instanceof VirtualObjectNode || node instanceof FloatingNode) { + // The order of evaluation of these nodes controlled by data dependence so they + // don't interfere with this match. + continue; + } else if ((consumed == null || !consumed.contains(node)) && node != root) { + if (LogVerbose.getValue()) { + Debug.log("unexpected node %s", node); + for (int j = startIndex; j <= endIndex; j++) { + Node theNode = nodes.get(j); + Debug.log("%s(%s) %1s", (consumed != null && consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.getUsageCount(), theNode); + } + } + return Result.notSafe(node, rule.getPattern()); + } + } + return Result.OK; + } + + /** + * Mark the interior nodes with INTERIOR_MATCH and set the Value of the root to be the result. + * During final LIR generation it will be evaluated to produce the actual LIR value. + * + * @param result + */ + public void setResult(ComplexMatchResult result) { + ComplexMatchValue value = new ComplexMatchValue(result); + if (Debug.isLogEnabled()) { + Debug.log("matched %s %s", rule.getName(), rule.getPattern()); + Debug.log("with nodes %s", rule.formatMatch(root)); + } + if (consumed != null) { + for (Node node : consumed) { + // All the interior nodes should be skipped during the normal doRoot calls in + // NodeLIRBuilder so mark them as interior matches. The root of the match will get a + // closure which will be evaluated to produce the final LIR. + builder.setMatchResult(node, ComplexMatchValue.INTERIOR_MATCH); + } + } + builder.setMatchResult(root, value); + } + + /** + * Mark a node as consumed by the match. Consumed nodes will never be evaluated. + * + * @return Result.OK if the node can be safely consumed. + */ + public Result consume(Node node) { + assert node.getUsageCount() <= 1 : "should have already been checked"; + + // Check NOT_IN_BLOCK first since that usually implies ALREADY_USED + int index = nodes.indexOf(node); + if (index == -1) { + return Result.notInBlock(node, rule.getPattern()); + } + + if (builder.hasOperand(node)) { + return Result.alreadyUsed(node, rule.getPattern()); + } + + startIndex = Math.min(startIndex, index); + if (consumed == null) { + consumed = new ArrayList<>(2); + } + consumed.add(node); + return Result.OK; + } + + /** + * Return the named node. It's an error if the + * + * @param name the name of a node in the match rule + * @return the matched node + * @throws GraalError is the named node doesn't exist. + */ + public Node namedNode(String name) { + if (namedNodes != null) { + NamedNode value = namedNodes.get(name); + if (value != null) { + return value.value; + } + } + throw new GraalError("missing node %s", name); + } + + @Override + public String toString() { + return String.format("%s %s (%d, %d) consumed %s", rule, root, startIndex, endIndex, consumed != null ? Arrays.toString(consumed.toArray()) : ""); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchGenerator.java 2016-12-07 13:48:49.072669638 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, 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.core.match; + +import org.graalvm.compiler.core.gen.NodeMatchRules; + +/** + * Code generator for complex match patterns. + */ +public interface MatchGenerator { + /** + * @returns null if the match can't be generated or a {@link ComplexMatchResult} that can be + * evaluated during LIR generation to produce the final LIR value. + */ + ComplexMatchResult match(NodeMatchRules matchRules, Object... args); + + /** + * @return a descriptive name meaningful to the user. + */ + String getName(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchPattern.java 2016-12-07 13:48:49.337681287 -0800 @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2014, 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.core.match; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.Position; +import org.graalvm.compiler.nodeinfo.Verbosity; + +/** + * A simple recursive pattern matcher for a DAG of nodes. + */ + +public class MatchPattern { + + enum MatchResultCode { + OK, + WRONG_CLASS, + NAMED_VALUE_MISMATCH, + TOO_MANY_USERS, + NOT_IN_BLOCK, + NOT_SAFE, + ALREADY_USED, + } + + /** + * A descriptive result for match failures. This can be helpful for debugging why a match + * doesn't work as expected. + */ + static class Result { + final MatchResultCode code; + + final Node node; + + final MatchPattern matcher; + + Result(MatchResultCode result, Node node, MatchPattern matcher) { + this.code = result; + this.node = node; + this.matcher = matcher; + } + + private static final DebugCounter MatchResult_WRONG_CLASS = Debug.counter("MatchResult_WRONG_CLASS"); + private static final DebugCounter MatchResult_NAMED_VALUE_MISMATCH = Debug.counter("MatchResult_NAMED_VALUE_MISMATCH"); + private static final DebugCounter MatchResult_TOO_MANY_USERS = Debug.counter("MatchResult_TOO_MANY_USERS"); + private static final DebugCounter MatchResult_NOT_IN_BLOCK = Debug.counter("MatchResult_NOT_IN_BLOCK"); + private static final DebugCounter MatchResult_NOT_SAFE = Debug.counter("MatchResult_NOT_SAFE"); + private static final DebugCounter MatchResult_ALREADY_USED = Debug.counter("MatchResult_ALREADY_USED"); + + static final Result OK = new Result(MatchResultCode.OK, null, null); + private static final Result CACHED_WRONG_CLASS = new Result(MatchResultCode.WRONG_CLASS, null, null); + private static final Result CACHED_NAMED_VALUE_MISMATCH = new Result(MatchResultCode.NAMED_VALUE_MISMATCH, null, null); + private static final Result CACHED_TOO_MANY_USERS = new Result(MatchResultCode.TOO_MANY_USERS, null, null); + private static final Result CACHED_NOT_IN_BLOCK = new Result(MatchResultCode.NOT_IN_BLOCK, null, null); + private static final Result CACHED_NOT_SAFE = new Result(MatchResultCode.NOT_SAFE, null, null); + private static final Result CACHED_ALREADY_USED = new Result(MatchResultCode.ALREADY_USED, null, null); + + static Result wrongClass(Node node, MatchPattern matcher) { + MatchResult_WRONG_CLASS.increment(); + return Debug.isLogEnabled() ? new Result(MatchResultCode.WRONG_CLASS, node, matcher) : CACHED_WRONG_CLASS; + } + + static Result namedValueMismatch(Node node, MatchPattern matcher) { + MatchResult_NAMED_VALUE_MISMATCH.increment(); + return Debug.isLogEnabled() ? new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher) : CACHED_NAMED_VALUE_MISMATCH; + } + + static Result tooManyUsers(Node node, MatchPattern matcher) { + MatchResult_TOO_MANY_USERS.increment(); + return Debug.isLogEnabled() ? new Result(MatchResultCode.TOO_MANY_USERS, node, matcher) : CACHED_TOO_MANY_USERS; + } + + static Result notInBlock(Node node, MatchPattern matcher) { + MatchResult_NOT_IN_BLOCK.increment(); + return Debug.isLogEnabled() ? new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher) : CACHED_NOT_IN_BLOCK; + } + + static Result notSafe(Node node, MatchPattern matcher) { + MatchResult_NOT_SAFE.increment(); + return Debug.isLogEnabled() ? new Result(MatchResultCode.NOT_SAFE, node, matcher) : CACHED_NOT_SAFE; + } + + static Result alreadyUsed(Node node, MatchPattern matcher) { + MatchResult_ALREADY_USED.increment(); + return Debug.isLogEnabled() ? new Result(MatchResultCode.ALREADY_USED, node, matcher) : CACHED_ALREADY_USED; + } + + @Override + public String toString() { + if (code == MatchResultCode.OK) { + return "OK"; + } + if (node == null) { + return code.toString(); + } else { + return code + " " + node.toString(Verbosity.Id) + "|" + node.getClass().getSimpleName() + " " + matcher; + } + } + } + + /** + * The expected type of the node. It must match exactly. + */ + private final Class nodeClass; + + /** + * An optional name for this node. A name can occur multiple times in a match and that name must + * always refer to the same node of the match will fail. + */ + private final String name; + + /** + * Patterns to match the inputs. + */ + private final MatchPattern[] patterns; + + /** + * The inputs to match the patterns against. + */ + private final Position[] inputs; + + /** + * Can there only be one user of the node. Constant nodes can be matched even if there are other + * users. + */ + private final boolean singleUser; + + private static final MatchPattern[] EMPTY_PATTERNS = new MatchPattern[0]; + + public MatchPattern(String name, boolean singleUser) { + this(null, name, singleUser); + } + + public MatchPattern(Class nodeClass, String name, boolean singleUser) { + this.nodeClass = nodeClass; + this.name = name; + this.singleUser = singleUser; + this.patterns = EMPTY_PATTERNS; + this.inputs = null; + } + + private MatchPattern(Class nodeClass, String name, boolean singleUser, MatchPattern[] patterns, Position[] inputs) { + assert inputs == null || inputs.length == patterns.length; + this.nodeClass = nodeClass; + this.name = name; + this.singleUser = singleUser; + this.patterns = patterns; + this.inputs = inputs; + } + + public MatchPattern(Class nodeClass, String name, MatchPattern first, Position[] inputs, boolean singleUser) { + this(nodeClass, name, singleUser, new MatchPattern[]{first}, inputs); + } + + public MatchPattern(Class nodeClass, String name, MatchPattern first, MatchPattern second, Position[] inputs, boolean singleUser) { + this(nodeClass, name, singleUser, new MatchPattern[]{first, second}, inputs); + } + + public MatchPattern(Class nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, Position[] inputs, boolean singleUser) { + this(nodeClass, name, singleUser, new MatchPattern[]{first, second, third}, inputs); + } + + Class nodeClass() { + return nodeClass; + } + + private Result matchType(Node node) { + if (nodeClass != null && node.getClass() != nodeClass) { + return Result.wrongClass(node, this); + } + return Result.OK; + } + + /** + * Match any named nodes and ensure that the consumed nodes can be safely merged. + * + * @param node + * @param context + * @return Result.OK is the pattern can be safely matched. + */ + Result matchUsage(Node node, MatchContext context) { + Result result = matchUsage(node, context, true); + if (result == Result.OK) { + result = context.validate(); + } + return result; + } + + private Result matchUsage(Node node, MatchContext context, boolean atRoot) { + Result result = matchType(node); + if (result != Result.OK) { + return result; + } + if (singleUser && !atRoot) { + result = context.consume(node); + if (result != Result.OK) { + return result; + } + } + + if (name != null) { + result = context.captureNamedValue(name, nodeClass, node); + } + + for (int input = 0; input < patterns.length; input++) { + result = patterns[input].matchUsage(getInput(input, node), context, false); + if (result != Result.OK) { + return result; + } + } + + return result; + } + + /** + * Recursively match the shape of the tree without worry about named values. Most matches fail + * at this point so it's performed first. + * + * @param node + * @param statement + * @return Result.OK if the shape of the pattern matches. + */ + public Result matchShape(Node node, MatchStatement statement) { + return matchShape(node, statement, true); + } + + private Result matchShape(Node node, MatchStatement statement, boolean atRoot) { + Result result = matchType(node); + if (result != Result.OK) { + return result; + } + + if (singleUser && !atRoot) { + if (node.getUsageCount() > 1) { + return Result.tooManyUsers(node, statement.getPattern()); + } + } + + for (int input = 0; input < patterns.length; input++) { + result = patterns[input].matchShape(getInput(input, node), statement, false); + if (result != Result.OK) { + return result; + } + } + + return result; + } + + /** + * For a node starting at root, produce a String showing the inputs that matched against this + * rule. It's assumed that a match has already succeeded against this rule, otherwise the + * printing may produce exceptions. + */ + public String formatMatch(Node root) { + String result = String.format("%s", root); + if (patterns.length == 0) { + return result; + } else { + StringBuilder sb = new StringBuilder(); + sb.append("("); + sb.append(result); + for (int input = 0; input < patterns.length; input++) { + sb.append(" "); + sb.append(patterns[input].formatMatch(getInput(input, root))); + } + sb.append(")"); + return sb.toString(); + } + } + + private Node getInput(int index, Node node) { + return inputs[index].get(node); + } + + @Override + public String toString() { + if (nodeClass == null) { + return name; + } else { + String nodeName = nodeClass.getSimpleName(); + if (nodeName.endsWith("Node")) { + nodeName = nodeName.substring(0, nodeName.length() - 4); + } + if (patterns.length == 0) { + return nodeName + (name != null ? "=" + name : ""); + } else { + StringBuilder sb = new StringBuilder(); + sb.append("("); + sb.append(nodeName); + for (int index = 0; index < patterns.length; index++) { + sb.append(" "); + sb.append(patterns[index].toString()); + } + sb.append(")"); + return sb.toString(); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRule.java 2016-12-07 13:48:49.602692936 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, 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.core.match; + +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 org.graalvm.compiler.nodes.ConstantNode; + +/** + * This annotation declares a textual pattern for matching an HIR tree. The format is a LISP style + * s-expression with node types and/or names that are matched against the HIR. Node types are always + * uppercase and the names of nodes are always lowercase. Named nodes can be used to match trees + * where a node is used multiple times but only as an input to the full match. + * + *

+ *   <node-name>    := [a-z][a-zA-Z0-9]*
+ *   <node-type>    := [A-Z][a-zA-Z0-9]*
+ *   <node-spec>    := <node-type> { '=' <node-name> }
+ *   <node-or-name> := <node-spec> | <node-name>
+ *   <argument>     := <node-or-name> | <match-rule>
+ *   <match-rule>   := '(' <node-spec> <argument>+ ')'
+ * 
+ * + * All matched nodes except the root of the match and {@link ConstantNode}s must have a single user. + * All matched nodes must be in the same block. + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Repeatable(value = MatchRules.class) +public @interface MatchRule { + String value(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java 2016-12-07 13:48:49.867704585 -0800 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2014, 2015, 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.core.match; + +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.LogVerbose; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.graalvm.compiler.core.gen.NodeMatchRules; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Edges; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.Position; +import org.graalvm.compiler.serviceprovider.GraalServices; + +public class MatchRuleRegistry { + + /** + * Convert a list of field names into {@link org.graalvm.compiler.graph.Position} objects that + * can be used to read them during a match. The names should already have been confirmed to + * exist in the type. + * + * @param nodeClass + * @param names + * @return an array of Position objects corresponding to the named fields. + */ + public static Position[] findPositions(NodeClass nodeClass, String[] names) { + Position[] result = new Position[names.length]; + for (int i = 0; i < names.length; i++) { + Edges edges = nodeClass.getInputEdges(); + for (int e = 0; e < edges.getDirectCount(); e++) { + if (names[i].equals(edges.getName(e))) { + result[i] = new Position(edges, e, Node.NOT_ITERABLE); + } + } + if (result[i] == null) { + throw new GraalError("unknown field \"%s\" in class %s", names[i], nodeClass); + } + } + return result; + } + + private static final HashMap, Map, List>> registry = new HashMap<>(); + + /** + * Collect all the {@link MatchStatement}s defined by the superclass chain of theClass. + * + * @param theClass + * @return the set of {@link MatchStatement}s applicable to theClass. + */ + @SuppressWarnings("try") + public static synchronized Map, List> lookup(Class theClass) { + Map, List> result = registry.get(theClass); + + if (result == null) { + Map, List> rules = createRules(theClass); + registry.put(theClass, rules); + assert registry.get(theClass) == rules; + result = rules; + + if (LogVerbose.getValue()) { + try (Scope s = Debug.scope("MatchComplexExpressions")) { + Debug.log("Match rules for %s", theClass.getSimpleName()); + for (Entry, List> entry : result.entrySet()) { + Debug.log(" For node class: %s", entry.getKey()); + for (MatchStatement statement : entry.getValue()) { + Debug.log(" %s", statement.getPattern()); + } + } + } + } + } + + if (result.size() == 0) { + return null; + } + return result; + } + + /* + * This is a separate, public method so that external clients can create rules with a custom + * lookup and without the default caching behavior. + */ + public static Map, List> createRules(Class theClass) { + HashMap, MatchStatementSet> matchSets = new HashMap<>(); + Iterable sl = GraalServices.load(MatchStatementSet.class); + for (MatchStatementSet rules : sl) { + matchSets.put(rules.forClass(), rules); + } + + // Walk the class hierarchy collecting lists and merge them together. The subclass + // rules are first which gives them preference over earlier rules. + Map, List> rules = new HashMap<>(); + Class currentClass = theClass; + do { + MatchStatementSet matchSet = matchSets.get(currentClass); + if (matchSet != null) { + List statements = matchSet.statements(); + for (MatchStatement statement : statements) { + Class nodeClass = statement.getPattern().nodeClass(); + List current = rules.get(nodeClass); + if (current == null) { + current = new ArrayList<>(); + rules.put(nodeClass, current); + } + current.add(statement); + } + } + currentClass = currentClass.getSuperclass(); + } while (currentClass != NodeMatchRules.class); + return rules; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRules.java 2016-12-07 13:48:50.133716278 -0800 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, 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.core.match; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The repeatable representation of {@link MatchRule}. Should never be used directly. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface MatchRules { + MatchRule[] value(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchStatement.java 2016-12-07 13:48:50.399727971 -0800 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2014, 2015, 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.core.match; + +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.LogVerbose; + +import java.util.List; + +import jdk.vm.ci.meta.Value; + +import org.graalvm.compiler.core.gen.NodeLIRBuilder; +import org.graalvm.compiler.core.match.MatchPattern.MatchResultCode; +import org.graalvm.compiler.core.match.MatchPattern.Result; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.graph.GraalGraphError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodeinfo.Verbosity; + +/** + * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace + * one or more {@link Node}s with a single {@link Value}. + */ + +public class MatchStatement { + private static final DebugCounter MatchStatementSuccess = Debug.counter("MatchStatementSuccess"); + + /** + * A printable name for this statement. Usually it's just the name of the method doing the + * emission. + */ + private final String name; + + /** + * The actual match pattern. + */ + private final MatchPattern pattern; + + /** + * The method in the {@link NodeLIRBuilder} subclass that will actually do the code emission. + */ + private MatchGenerator generatorMethod; + + /** + * The name of arguments in the order they are expected to be passed to the generator method. + */ + private String[] arguments; + + public MatchStatement(String name, MatchPattern pattern, MatchGenerator generator, String[] arguments) { + this.name = name; + this.pattern = pattern; + this.generatorMethod = generator; + this.arguments = arguments; + } + + /** + * Attempt to match the current statement against a Node. + * + * @param builder the current builder instance. + * @param node the node to be matched + * @param nodes the nodes in the current block + * @return true if the statement matched something and set a {@link ComplexMatchResult} to be + * evaluated by the NodeLIRBuilder. + */ + public boolean generate(NodeLIRBuilder builder, int index, Node node, List nodes) { + assert index == nodes.indexOf(node); + // Check that the basic shape matches + Result result = pattern.matchShape(node, this); + if (result != Result.OK) { + return false; + } + // Now ensure that the other safety constraints are matched. + MatchContext context = new MatchContext(builder, this, index, node, nodes); + result = pattern.matchUsage(node, context); + if (result == Result.OK) { + // Invoke the generator method and set the result if it's non null. + ComplexMatchResult value = generatorMethod.match(builder.getNodeMatchRules(), buildArgList(context)); + if (value != null) { + context.setResult(value); + MatchStatementSuccess.increment(); + Debug.counter("MatchStatement[%s]", getName()).increment(); + return true; + } + // The pattern matched but some other code generation constraint disallowed code + // generation for the pattern. + if (LogVerbose.getValue()) { + Debug.log("while matching %s|%s %s %s returned null", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), generatorMethod.getName()); + Debug.log("with nodes %s", formatMatch(node)); + } + } else { + if (LogVerbose.getValue() && result.code != MatchResultCode.WRONG_CLASS) { + Debug.log("while matching %s|%s %s %s", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), result); + } + } + return false; + } + + /** + * @param context + * @return the Nodes captured by the match rule in the order expected by the generatorMethod + */ + private Object[] buildArgList(MatchContext context) { + Object[] result = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + if ("root".equals(arguments[i])) { + result[i] = context.getRoot(); + } else { + result[i] = context.namedNode(arguments[i]); + if (result[i] == null) { + throw new GraalGraphError("Can't find named node %s", arguments[i]); + } + } + } + return result; + } + + public String formatMatch(Node root) { + return pattern.formatMatch(root); + } + + public MatchPattern getPattern() { + return pattern; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return pattern.toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchStatementSet.java 2016-12-07 13:48:50.663739576 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, 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.core.match; + +import java.util.List; + +import org.graalvm.compiler.core.gen.NodeLIRBuilder; +import org.graalvm.compiler.core.gen.NodeMatchRules; + +public interface MatchStatementSet { + /** + * @return the {@link NodeLIRBuilder} subclass which defined this set of {@link MatchStatement} + * instances. + */ + Class forClass(); + + /** + * @return the {@link MatchStatement}s available for this {@link NodeLIRBuilder} subclass. + */ + List statements(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchableNode.java 2016-12-07 13:48:50.929751269 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014, 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.core.match; + +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 org.graalvm.compiler.nodes.ValueNode; + +/** + * Describes the properties of a node for use when building a {@link MatchPattern}. These + * declarations are required when parsing a {@link MatchRule}. They are expected to be found on a + * super type of the holder of the method declaring the {@link MatchRule}. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Repeatable(value = MatchableNodes.class) +public @interface MatchableNode { + + /** + * The {@link ValueNode} subclass this annotation describes. These annotations might work better + * if they were directly on the node being described but that may complicate the annotation + * processing. + */ + Class nodeClass(); + + /** + * The names of the inputs in the order they should appear in the match. + */ + String[] inputs() default {}; + + /** + * Can a pattern be matched with the operands swapped. This will cause swapped versions of + * patterns to be automatically generated. + */ + boolean commutative() default false; + + /** + * Can a node with multiple uses be safely matched by a rule. + */ + boolean shareable() default false; +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchableNodes.java 2016-12-07 13:48:51.195762962 -0800 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, 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.core.match; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The repeatable representation of {@link MatchableNode}. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface MatchableNodes { + MatchableNode[] value() default {}; +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/package-info.java 2016-12-07 13:48:51.459774567 -0800 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010, 2011, 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. + */ + +/** + * The top-level package in Graal containing the main compiler class + * {@link org.graalvm.compiler.core.GraalCompiler}. + */ +package org.graalvm.compiler.core; --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CoreCompilerConfiguration.java 2016-12-07 13:48:51.726786304 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013, 2015, 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.core.phases; + +import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext; +import org.graalvm.compiler.lir.phases.AllocationStage; +import org.graalvm.compiler.lir.phases.LIRPhaseSuite; +import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext; +import org.graalvm.compiler.lir.phases.PostAllocationOptimizationStage; +import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext; +import org.graalvm.compiler.lir.phases.PreAllocationOptimizationStage; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.LowTierContext; +import org.graalvm.compiler.phases.tiers.MidTierContext; + +public class CoreCompilerConfiguration implements CompilerConfiguration { + + @Override + public PhaseSuite createHighTier() { + return new HighTier(); + } + + @Override + public PhaseSuite createMidTier() { + return new MidTier(); + } + + @Override + public PhaseSuite createLowTier() { + return new LowTier(); + } + + @Override + public LIRPhaseSuite createPreAllocationOptimizationStage() { + return new PreAllocationOptimizationStage(); + } + + @Override + public LIRPhaseSuite createAllocationStage() { + return new AllocationStage(); + } + + @Override + public LIRPhaseSuite createPostAllocationOptimizationStage() { + return new PostAllocationOptimizationStage(); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java 2016-12-07 13:48:51.990797909 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, 2015, 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.core.phases; + +import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext; +import org.graalvm.compiler.lir.phases.EconomyAllocationStage; +import org.graalvm.compiler.lir.phases.EconomyPostAllocationOptimizationStage; +import org.graalvm.compiler.lir.phases.EconomyPreAllocationOptimizationStage; +import org.graalvm.compiler.lir.phases.LIRPhaseSuite; +import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext; +import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.LowTierContext; +import org.graalvm.compiler.phases.tiers.MidTierContext; + +public class EconomyCompilerConfiguration implements CompilerConfiguration { + + @Override + public PhaseSuite createHighTier() { + return new EconomyHighTier(); + } + + @Override + public PhaseSuite createMidTier() { + return new EconomyMidTier(); + } + + @Override + public PhaseSuite createLowTier() { + return new EconomyLowTier(); + } + + @Override + public LIRPhaseSuite createPreAllocationOptimizationStage() { + return new EconomyPreAllocationOptimizationStage(); + } + + @Override + public LIRPhaseSuite createAllocationStage() { + return new EconomyAllocationStage(); + } + + @Override + public LIRPhaseSuite createPostAllocationOptimizationStage() { + return new EconomyPostAllocationOptimizationStage(); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyHighTier.java 2016-12-07 13:48:52.256809602 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, 2016, 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.core.phases; + +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; + +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +public class EconomyHighTier extends PhaseSuite { + + public EconomyHighTier() { + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + if (ImmutableCode.getValue()) { + canonicalizer.disableReadCanonicalization(); + } + + appendPhase(canonicalizer); + appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java 2016-12-07 13:48:52.521821250 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, 2015, 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.core.phases; + +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; + +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.ExpandLogicPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.tiers.LowTierContext; + +public class EconomyLowTier extends PhaseSuite { + + public EconomyLowTier() { + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + if (ImmutableCode.getValue()) { + canonicalizer.disableReadCanonicalization(); + } + + appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER)); + + appendPhase(new ExpandLogicPhase()); + + appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.FINAL_SCHEDULE)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java 2016-12-07 13:48:52.786832899 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015, 2015, 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.core.phases; + +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; + +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase; +import org.graalvm.compiler.phases.common.GuardLoweringPhase; +import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; +import org.graalvm.compiler.phases.tiers.MidTierContext; + +public class EconomyMidTier extends PhaseSuite { + + public EconomyMidTier() { + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + if (ImmutableCode.getValue()) { + canonicalizer.disableReadCanonicalization(); + } + appendPhase(new RemoveValueProxyPhase()); + + appendPhase(new LoopSafepointInsertionPhase()); + + appendPhase(new GuardLoweringPhase()); + + appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER)); + + appendPhase(new FrameStateAssignmentPhase()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java 2016-12-07 13:48:53.051844548 -0800 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2015, 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.core.phases; + +import java.util.Set; +import java.util.stream.Collectors; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.graph.Graph.NodeEvent; +import org.graalvm.compiler.graph.Graph.NodeEventScope; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.LogicConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +/** + * A utility phase for detecting when a phase would change the graph and reporting extra information + * about the effects. The phase is first run on a copy of the graph and if a change in that graph is + * detected then it's rerun on the original graph inside a new debug scope under + * GraphChangeMonitoringPhase. The message argument can be used to distinguish between the same + * phase run at different points. + * + * @param + */ +public class GraphChangeMonitoringPhase extends PhaseSuite { + + private final String message; + + public GraphChangeMonitoringPhase(String message, BasePhase phase) { + super(); + this.message = message; + appendPhase(phase); + } + + public GraphChangeMonitoringPhase(String message) { + super(); + this.message = message; + } + + @Override + @SuppressWarnings("try") + protected void run(StructuredGraph graph, C context) { + /* + * Phase may add nodes but not end up using them so ignore additions. Nodes going dead and + * having their inputs change are the main interesting differences. + */ + HashSetNodeEventListener listener = new HashSetNodeEventListener().exclude(NodeEvent.NODE_ADDED); + StructuredGraph graphCopy = (StructuredGraph) graph.copy(); + try (NodeEventScope s = graphCopy.trackNodeEvents(listener)) { + try (Scope s2 = Debug.sandbox("WithoutMonitoring", null)) { + super.run(graphCopy, context); + } catch (Throwable t) { + Debug.handle(t); + } + } + /* + * Ignore LogicConstantNode since those are sometimes created and deleted as part of running + * a phase. + */ + if (listener.getNodes().stream().filter(e -> !(e instanceof LogicConstantNode)).findFirst().isPresent()) { + /* rerun it on the real graph in a new Debug scope so Dump and Log can find it. */ + listener = new HashSetNodeEventListener(); + try (NodeEventScope s = graph.trackNodeEvents(listener)) { + try (Scope s2 = Debug.scope("WithGraphChangeMonitoring")) { + if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) { + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "*** Before phase %s", getName()); + } + super.run(graph, context); + Set collect = listener.getNodes().stream().filter(e -> !e.isAlive()).filter(e -> !(e instanceof LogicConstantNode)).collect(Collectors.toSet()); + if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) { + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "*** After phase %s %s", getName(), collect); + } + Debug.log("*** %s %s %s\n", message, graph, collect); + } + } + } else { + // Go ahead and run it normally even though it should have no effect + super.run(graph, context); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java 2016-12-07 13:48:53.318856285 -0800 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2013, 2016, 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.core.phases; + +import static org.graalvm.compiler.core.common.GraalOptions.ConditionalElimination; +import static org.graalvm.compiler.core.common.GraalOptions.FullUnroll; +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; +import static org.graalvm.compiler.core.common.GraalOptions.LoopPeeling; +import static org.graalvm.compiler.core.common.GraalOptions.LoopUnswitch; +import static org.graalvm.compiler.core.common.GraalOptions.OptConvertDeoptsToGuards; +import static org.graalvm.compiler.core.common.GraalOptions.OptLoopTransform; +import static org.graalvm.compiler.core.common.GraalOptions.PartialEscapeAnalysis; +import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation; +import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional; + +import org.graalvm.compiler.loop.DefaultLoopPolicies; +import org.graalvm.compiler.loop.LoopPolicies; +import org.graalvm.compiler.loop.phases.LoopFullUnrollPhase; +import org.graalvm.compiler.loop.phases.LoopPeelingPhase; +import org.graalvm.compiler.loop.phases.LoopUnswitchingPhase; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase; +import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.common.instrumentation.HighTierReconcileInstrumentationPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; + +public class HighTier extends PhaseSuite { + + public static class Options { + + // @formatter:off + @Option(help = "Enable inlining", type = OptionType.Expert) + public static final OptionValue Inline = new OptionValue<>(true); + // @formatter:on + } + + public HighTier() { + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + if (ImmutableCode.getValue()) { + canonicalizer.disableReadCanonicalization(); + } + + appendPhase(canonicalizer); + + if (Options.Inline.getValue()) { + appendPhase(new InliningPhase(canonicalizer)); + appendPhase(new DeadCodeEliminationPhase(Optional)); + + if (ConditionalElimination.getValue()) { + appendPhase(canonicalizer); + appendPhase(new IterativeConditionalEliminationPhase(canonicalizer, false)); + } + } + + if (OptConvertDeoptsToGuards.getValue()) { + appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new ConvertDeoptimizeToGuardPhase())); + } + + LoopPolicies loopPolicies = createLoopPolicies(); + if (FullUnroll.getValue()) { + appendPhase(new LoopFullUnrollPhase(canonicalizer, loopPolicies)); + } + + if (OptLoopTransform.getValue()) { + if (LoopPeeling.getValue()) { + appendPhase(new LoopPeelingPhase(loopPolicies)); + } + if (LoopUnswitch.getValue()) { + appendPhase(new LoopUnswitchingPhase(loopPolicies)); + } + } + + appendPhase(canonicalizer); + + if (PartialEscapeAnalysis.getValue()) { + appendPhase(new PartialEscapePhase(true, canonicalizer)); + } + appendPhase(new RemoveValueProxyPhase()); + + appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER)); + if (UseGraalInstrumentation.getValue()) { + appendPhase(new HighTierReconcileInstrumentationPhase()); + } + } + + public LoopPolicies createLoopPolicies() { + return new DefaultLoopPolicies(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java 2016-12-07 13:48:53.583867934 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2013, 2016, 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.core.phases; + +import static org.graalvm.compiler.core.common.GraalOptions.ConditionalElimination; +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; +import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation; +import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required; + +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.ExpandLogicPhase; +import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.ProfileCompiledMethodsPhase; +import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; +import org.graalvm.compiler.phases.common.UseTrappingNullChecksPhase; +import org.graalvm.compiler.phases.common.instrumentation.InlineInstrumentationPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.tiers.LowTierContext; + +public class LowTier extends PhaseSuite { + + static class Options { + + // @formatter:off + @Option(help = "", type = OptionType.Debug) + public static final OptionValue ProfileCompiledMethods = new OptionValue<>(false); + // @formatter:on + + } + + public LowTier() { + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + if (ImmutableCode.getValue()) { + canonicalizer.disableReadCanonicalization(); + } + + if (Options.ProfileCompiledMethods.getValue()) { + appendPhase(new ProfileCompiledMethodsPhase()); + } + + appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER)); + if (UseGraalInstrumentation.getValue()) { + appendPhase(new InlineInstrumentationPhase()); + } + + appendPhase(new RemoveValueProxyPhase()); + + appendPhase(new ExpandLogicPhase()); + + /* Cleanup IsNull checks resulting from MID_TIER/LOW_TIER lowering and ExpandLogic phase. */ + if (ConditionalElimination.getValue()) { + appendPhase(new IterativeConditionalEliminationPhase(canonicalizer, false)); + /* Canonicalizer may create some new ShortCircuitOrNodes so clean them up. */ + appendPhase(new ExpandLogicPhase()); + } + + appendPhase(new UseTrappingNullChecksPhase()); + + appendPhase(new DeadCodeEliminationPhase(Required)); + + appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.FINAL_SCHEDULE)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java 2016-12-07 13:48:53.849879627 -0800 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2013, 2016, 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.core.phases; + +import static org.graalvm.compiler.core.common.GraalOptions.ConditionalElimination; +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; +import static org.graalvm.compiler.core.common.GraalOptions.OptDeoptimizationGrouping; +import static org.graalvm.compiler.core.common.GraalOptions.OptEliminatePartiallyRedundantGuards; +import static org.graalvm.compiler.core.common.GraalOptions.OptFloatingReads; +import static org.graalvm.compiler.core.common.GraalOptions.OptPushThroughPi; +import static org.graalvm.compiler.core.common.GraalOptions.OptReadElimination; +import static org.graalvm.compiler.core.common.GraalOptions.ReassociateInvariants; +import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation; +import static org.graalvm.compiler.core.common.GraalOptions.VerifyHeapAtReturn; + +import org.graalvm.compiler.loop.phases.LoopSafepointEliminationPhase; +import org.graalvm.compiler.loop.phases.ReassociateInvariantPhase; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.DeoptimizationGroupingPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase; +import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase; +import org.graalvm.compiler.phases.common.GuardLoweringPhase; +import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase; +import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase; +import org.graalvm.compiler.phases.common.LockEliminationPhase; +import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.OptimizeGuardAnchorsPhase; +import org.graalvm.compiler.phases.common.PushThroughPiPhase; +import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; +import org.graalvm.compiler.phases.common.ValueAnchorCleanupPhase; +import org.graalvm.compiler.phases.common.VerifyHeapAtReturnPhase; +import org.graalvm.compiler.phases.common.instrumentation.MidTierReconcileInstrumentationPhase; +import org.graalvm.compiler.phases.tiers.MidTierContext; +import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase; + +public class MidTier extends PhaseSuite { + + public MidTier() { + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + if (ImmutableCode.getValue()) { + canonicalizer.disableReadCanonicalization(); + } + + if (OptPushThroughPi.getValue()) { + appendPhase(new PushThroughPiPhase()); + } + + appendPhase(canonicalizer); + + appendPhase(new ValueAnchorCleanupPhase()); + appendPhase(new LockEliminationPhase()); + + if (OptReadElimination.getValue()) { + appendPhase(new EarlyReadEliminationPhase(canonicalizer)); + } + + if (OptFloatingReads.getValue()) { + appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new FloatingReadPhase())); + } + appendPhase(new RemoveValueProxyPhase()); + + appendPhase(canonicalizer); + + if (OptEliminatePartiallyRedundantGuards.getValue()) { + appendPhase(new OptimizeGuardAnchorsPhase()); + } + + if (ConditionalElimination.getValue()) { + appendPhase(new IterativeConditionalEliminationPhase(canonicalizer, true)); + } + + if (OptEliminatePartiallyRedundantGuards.getValue()) { + appendPhase(new OptimizeGuardAnchorsPhase()); + } + + appendPhase(canonicalizer); + + appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new LoopSafepointEliminationPhase())); + + appendPhase(new LoopSafepointInsertionPhase()); + + appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new GuardLoweringPhase())); + + if (VerifyHeapAtReturn.getValue()) { + appendPhase(new VerifyHeapAtReturnPhase()); + } + + appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER)); + if (UseGraalInstrumentation.getValue()) { + appendPhase(new MidTierReconcileInstrumentationPhase()); + } + + appendPhase(new FrameStateAssignmentPhase()); + + if (ReassociateInvariants.getValue()) { + appendPhase(new ReassociateInvariantPhase()); + } + + if (OptDeoptimizationGrouping.getValue()) { + appendPhase(new DeoptimizationGroupingPhase()); + } + + appendPhase(canonicalizer); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java 2016-12-07 13:48:54.115891320 -0800 @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2009, 2016, 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.core.target; + +import java.util.Set; + +import org.graalvm.compiler.asm.Assembler; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.lir.framemap.FrameMap; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.phases.tiers.SuitesProvider; +import org.graalvm.compiler.phases.tiers.TargetProvider; +import org.graalvm.compiler.phases.util.Providers; + +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.CompilationRequest; +import jdk.vm.ci.code.CompiledCode; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.code.ValueKindFactory; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.SpeculationLog; + +/** + * Represents a compiler backend for Graal. + */ +public abstract class Backend implements TargetProvider, ValueKindFactory { + + private final Providers providers; + + public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class); + public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class); + + protected Backend(Providers providers) { + this.providers = providers; + } + + public Providers getProviders() { + return providers; + } + + public CodeCacheProvider getCodeCache() { + return providers.getCodeCache(); + } + + public MetaAccessProvider getMetaAccess() { + return providers.getMetaAccess(); + } + + public ConstantReflectionProvider getConstantReflection() { + return providers.getConstantReflection(); + } + + public ForeignCallsProvider getForeignCalls() { + return providers.getForeignCalls(); + } + + public abstract SuitesProvider getSuites(); + + @Override + public TargetDescription getTarget() { + return providers.getCodeCache().getTarget(); + } + + @Override + public LIRKind getValueKind(JavaKind javaKind) { + return LIRKind.fromJavaKind(getTarget().arch, javaKind); + } + + /** + * The given registerConfig is optional, in case null is passed the default RegisterConfig from + * the CodeCacheProvider will be used. + */ + public abstract FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig); + + public abstract RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig); + + public abstract FrameMap newFrameMap(RegisterConfig registerConfig); + + public abstract LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes); + + public abstract LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, + Object stub); + + public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen); + + /** + * Creates the assembler used to emit the machine code. + */ + protected abstract Assembler createAssembler(FrameMap frameMap); + + /** + * Creates the object used to fill in the details of a given compilation result. + */ + public abstract CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenResult, FrameMap frameMap, CompilationResult compilationResult, + CompilationResultBuilderFactory factory); + + /** + * Turns a Graal {@link CompilationResult} into a {@link CompiledCode} object that can be passed + * to the VM for code installation. + */ + protected abstract CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult); + + /** + * @see #createInstalledCode(ResolvedJavaMethod, CompilationRequest, CompilationResult, + * SpeculationLog, InstalledCode, boolean) + */ + public InstalledCode createInstalledCode(ResolvedJavaMethod method, CompilationResult compilationResult, + SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault) { + return createInstalledCode(method, null, compilationResult, speculationLog, predefinedInstalledCode, isDefault); + } + + /** + * Installs code based on a given compilation result. + * + * @param method the method compiled to produce {@code compiledCode} or {@code null} if the + * input to {@code compResult} was not a {@link ResolvedJavaMethod} + * @param compilationRequest the compilation request or {@code null} + * @param compilationResult the code to be compiled + * @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object to use as a + * reference to the installed code. If {@code null}, a new {@link InstalledCode} + * object will be created. + * @param speculationLog the speculation log to be used + * @param isDefault specifies if the installed code should be made the default implementation of + * {@code compRequest.getMethod()}. The default implementation for a method is the + * code executed for standard calls to the method. This argument is ignored if + * {@code compRequest == null}. + * @return a reference to the compiled and ready-to-run installed code + * @throws BailoutException if the code installation failed + */ + @SuppressWarnings("try") + public InstalledCode createInstalledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult, + SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault) { + try (Scope s2 = Debug.scope("CodeInstall", getProviders().getCodeCache(), compilationResult)) { + CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult); + return getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + /** + * Installs code based on a given compilation result. + * + * @param method the method compiled to produce {@code compiledCode} or {@code null} if the + * input to {@code compResult} was not a {@link ResolvedJavaMethod} + * @param compilationRequest the request or {@code null} + * @param compilationResult the code to be compiled + * @return a reference to the compiled and ready-to-run installed code + * @throws BailoutException if the code installation failed + */ + public InstalledCode addInstalledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult) { + return createInstalledCode(method, compilationRequest, compilationResult, null, null, false); + } + + /** + * Installs code based on a given compilation result and sets it as the default code to be used + * when {@code method} is invoked. + * + * @param method the method compiled to produce {@code compiledCode} or {@code null} if the + * input to {@code compResult} was not a {@link ResolvedJavaMethod} + * @param compilationResult the code to be compiled + * @return a reference to the compiled and ready-to-run installed code + * @throws BailoutException if the code installation failed + */ + public InstalledCode createDefaultInstalledCode(ResolvedJavaMethod method, CompilationResult compilationResult) { + return createInstalledCode(method, compilationResult, null, null, true); + } + + /** + * Emits the code for a given graph. + * + * @param installedCodeOwner the method the compiled code will be associated with once + * installed. This argument can be null. + */ + public abstract void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner); + + /** + * Translates a set of registers from the callee's perspective to the caller's perspective. This + * is needed for architectures where input/output registers are renamed during a call (e.g. + * register windows on SPARC). Registers which are not visible by the caller are removed. + */ + public abstract Set translateToCallerRegisters(Set calleeRegisters); + + /** + * Gets the compilation id for a given {@link ResolvedJavaMethod}. Returns + * {@code CompilationIdentifier#INVALID_COMPILATION_ID} in case there is no such id. + * + * @param resolvedJavaMethod + */ + public CompilationIdentifier getCompilationIdentifier(ResolvedJavaMethod resolvedJavaMethod) { + return CompilationIdentifier.INVALID_COMPILATION_ID; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/CSVUtilTest.java 2016-12-07 13:48:54.382903057 -0800 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016, 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.debug.test; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; + +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import org.graalvm.compiler.debug.CSVUtil; + +@RunWith(Enclosed.class) +public class CSVUtilTest { + + @RunWith(Parameterized.class) + public static class FormatStringBuilder { + /** Some interesting values. */ + private static final Object[][] values = { + {"", ""}, + {"%s", "%s"}, + {"%s,%s", "%s;%s"}, + }; + + @Parameters(name = " [{0}] to \"{1}\" ") + public static Collection data() { + return Arrays.asList(values); + } + + @Parameter(value = 0) public String input; + @Parameter(value = 1) public String expected; + + @Test + public void testBuildFormatString() { + assertEquals(expected, CSVUtil.buildFormatString(input.split(","))); + } + } + + @RunWith(Parameterized.class) + public static class Escape { + + /** Some interesting values. */ + private static final Object[][] values = { + {"XXX\"YYY", "\"XXX\\\"YYY\""}, + {"X\\XX\"YYY", "\"X\\\\XX\\\"YYY\""}, + }; + + @Parameters(name = "''{0}'' to ''{1}''") + public static Collection data() { + return Arrays.asList(values); + } + + @Parameter(value = 0) public String input; + @Parameter(value = 1) public String expected; + + @Test + public void testEscape() { + assertEquals(expected, CSVUtil.Escape.escapeRaw(input)); + } + + } + + @RunWith(Parameterized.class) + public static class Formatter { + /** Some interesting values. */ + private static final Object[][] values = { + {"%s;%s", "XXX,YYY", "XXX;YYY"}, + {"%s;%s", "XXX,Y\"YY", "XXX;Y\"YY"}, + {"%s;%s", "XXX,Y;YY", "XXX;\"Y;YY\""}, + {"%s;%s", "XXX,Y\"Y;Y", "XXX;\"Y\\\"Y;Y\""}, + }; + + @Parameters(name = "format=''{0}'' args=''{1}'' output=''{2}''") + public static Collection data() { + return Arrays.asList(values); + } + + @Parameter(value = 0) public String format; + @Parameter(value = 1) public String args; + @Parameter(value = 2) public String expected; + + @Test + public void testFormatter() { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + // call the method under test + CSVUtil.Escape.println(new PrintStream(outputStream), format, toObjectArray(args)); + // get the actual string + String printedStream = new String(outputStream.toByteArray(), StandardCharsets.UTF_8); + // remove newline + assertEquals(expected, printedStream.substring(0, printedStream.length() - 1)); + } + + private static Object[] toObjectArray(String args) { + String[] split = args.split(","); + Object[] obj = new Object[split.length]; + for (int i = 0; i < split.length; i++) { + obj[i] = split[i]; + } + return obj; + } + + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugHistogramTest.java 2016-12-07 13:48:54.646914662 -0800 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.debug.test; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugHistogram; +import org.graalvm.compiler.debug.internal.DebugHistogramAsciiPrinter; +import org.graalvm.compiler.debug.internal.DebugHistogramRPrinter; + +public class DebugHistogramTest { + + @Test + public void testEmptyHistogram() { + DebugHistogram histogram = Debug.createHistogram("TestHistogram"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + new DebugHistogramAsciiPrinter(new PrintStream(outputStream)).print(histogram); + String line = outputStream.toString().split("\r?\n")[0]; + Assert.assertEquals("TestHistogram is empty.", line); + + outputStream.reset(); + new DebugHistogramRPrinter(new PrintStream(outputStream)).print(histogram); + Assert.assertEquals("", outputStream.toString()); + } + + @Test + public void testSingleEntryHistogram() { + DebugHistogram histogram = Debug.createHistogram("TestHistogram"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + histogram.add(new Integer(1)); + histogram.add(new Integer(1)); + new DebugHistogramAsciiPrinter(new PrintStream(outputStream)).print(histogram); + String[] lines = outputStream.toString().split("\r?\n"); + // @formatter:off + String[] expected = { + "TestHistogram has 1 unique elements and 2 total elements:", + "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------", + "| 1 | 2 | ==================================================================================================== |", + "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------" + }; + // @formatter:on + Assert.assertArrayEquals(expected, lines); + + outputStream.reset(); + new DebugHistogramRPrinter(new PrintStream(outputStream)).print(histogram); + lines = outputStream.toString().split("\r?\n"); + // @formatter:off + expected = new String[] { + "TestHistogram <- c(2);", + "names(TestHistogram) <- c(\"1\");" + }; + // @formatter:on + Assert.assertArrayEquals(expected, lines); + } + + @Test + public void testMultipleEntryHistogram() { + DebugHistogram histogram = Debug.createHistogram("TestHistogram"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + histogram.add(new Integer(1)); + histogram.add(new Integer(2)); + histogram.add(new Integer(2)); + new DebugHistogramAsciiPrinter(new PrintStream(outputStream)).print(histogram); + String[] lines = outputStream.toString().split("\r?\n"); + // @formatter:off + String[] expected = new String[] { + "TestHistogram has 2 unique elements and 3 total elements:", + "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------", + "| 2 | 2 | ==================================================================================================== |", + "| 1 | 1 | ================================================== |", + "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------" + }; + // @formatter:on + Assert.assertArrayEquals(expected, lines); + + outputStream.reset(); + new DebugHistogramRPrinter(new PrintStream(outputStream)).print(histogram); + lines = outputStream.toString().split("\r?\n"); + // @formatter:off + expected = new String[] { + "TestHistogram <- c(2, 1);", + "names(TestHistogram) <- c(\"2\", \"1\");" + }; + // @formatter:on + Assert.assertArrayEquals(expected, lines); + } + + @Test + public void testTooLongValueString() { + DebugHistogram histogram = Debug.createHistogram("TestHistogram"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + histogram.add("MyCustomValue"); + new DebugHistogramAsciiPrinter(new PrintStream(outputStream), Integer.MAX_VALUE, 10, 10, 1).print(histogram); + String[] lines = outputStream.toString().split("\r?\n"); + Assert.assertEquals(4, lines.length); + Assert.assertEquals("TestHistogram has 1 unique elements and 1 total elements:", lines[0]); + Assert.assertEquals("----------------------------------------", lines[1]); + Assert.assertEquals("| MyCusto... | 1 | ========== |", lines[2]); + Assert.assertEquals("----------------------------------------", lines[3]); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugTimerTest.java 2016-12-07 13:48:54.911926311 -0800 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2013, 2015, 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.debug.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.lang.management.ThreadMXBean; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.debug.DebugConfigScope; +import org.graalvm.compiler.debug.DebugTimer; +import org.graalvm.compiler.debug.Management; + +@SuppressWarnings("try") +public class DebugTimerTest { + + private static final ThreadMXBean threadMXBean = Management.getThreadMXBean(); + + @Before + public void checkCapabilities() { + Assume.assumeTrue("skipping management interface test", threadMXBean.isCurrentThreadCpuTimeSupported()); + } + + /** + * Actively spins the current thread for at least a given number of milliseconds in such a way + * that timers for the current thread keep ticking over. + * + * @return the number of milliseconds actually spent spinning which is guaranteed to be >= + * {@code ms} + */ + private static long spin(long ms) { + long start = threadMXBean.getCurrentThreadCpuTime(); + do { + long durationMS = (threadMXBean.getCurrentThreadCpuTime() - start) / 1000; + if (durationMS >= ms) { + return durationMS; + } + } while (true); + } + + @Test + public void test1() { + DebugConfig debugConfig = Debug.fixedConfig(0, 0, false, false, true, false, false, null, null, System.out); + try (DebugConfigScope dcs = new DebugConfigScope(debugConfig); Debug.Scope s = Debug.scope("DebugTimerTest")) { + + DebugTimer timerA = Debug.timer("TimerA"); + DebugTimer timerB = Debug.timer("TimerB"); + + long spinA; + long spinB; + + try (DebugCloseable a1 = timerA.start()) { + spinA = spin(50); + try (DebugCloseable b1 = timerB.start()) { + spinB = spin(50); + } + } + + Assert.assertTrue(timerB.getCurrentValue() < timerA.getCurrentValue()); + if (timerA.getFlat() != null && timerB.getFlat() != null) { + assertTrue(spinB >= spinA || timerB.getFlat().getCurrentValue() < timerA.getFlat().getCurrentValue()); + assertEquals(timerA.getFlat().getCurrentValue(), timerA.getCurrentValue() - timerB.getFlat().getCurrentValue(), 10D); + } + } + } + + @Test + public void test2() { + DebugConfig debugConfig = Debug.fixedConfig(0, 0, false, false, true, false, false, null, null, System.out); + try (DebugConfigScope dcs = new DebugConfigScope(debugConfig); Debug.Scope s = Debug.scope("DebugTimerTest")) { + DebugTimer timerC = Debug.timer("TimerC"); + try (DebugCloseable c1 = timerC.start()) { + spin(50); + try (DebugCloseable c2 = timerC.start()) { + spin(50); + try (DebugCloseable c3 = timerC.start()) { + spin(50); + try (DebugCloseable c4 = timerC.start()) { + spin(50); + try (DebugCloseable c5 = timerC.start()) { + spin(50); + } + } + } + } + } + if (timerC.getFlat() != null) { + assertEquals(timerC.getFlat().getCurrentValue(), timerC.getCurrentValue()); + } + } + } + + @Test + public void test3() { + DebugConfig debugConfig = Debug.fixedConfig(0, 0, false, false, true, false, false, null, null, System.out); + try (DebugConfigScope dcs = new DebugConfigScope(debugConfig); Debug.Scope s = Debug.scope("DebugTimerTest")) { + + DebugTimer timerD = Debug.timer("TimerD"); + DebugTimer timerE = Debug.timer("TimerE"); + + long spinD1; + long spinE; + + try (DebugCloseable d1 = timerD.start()) { + spinD1 = spin(50); + try (DebugCloseable e1 = timerE.start()) { + spinE = spin(50); + try (DebugCloseable d2 = timerD.start()) { + spin(50); + try (DebugCloseable d3 = timerD.start()) { + spin(50); + } + } + } + } + + Assert.assertTrue(timerE.getCurrentValue() < timerD.getCurrentValue()); + if (timerD.getFlat() != null && timerE.getFlat() != null) { + assertTrue(spinE >= spinD1 || timerE.getFlat().getCurrentValue() < timerD.getFlat().getCurrentValue()); + assertEquals(timerD.getFlat().getCurrentValue(), timerD.getCurrentValue() - timerE.getFlat().getCurrentValue(), 10D); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/overview.html 2016-12-07 13:48:55.177938004 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.debug project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CSVUtil.java 2016-12-07 13:48:55.444949741 -0800 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016, 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.debug; + +import java.io.PrintStream; + +/** + * Utilities and global definitions for creating CSV output. + */ +public final class CSVUtil { + public static final char SEPARATOR = ';'; + public static final String SEPARATOR_STR = String.valueOf(SEPARATOR); + public static final char QUOTE = '"'; + public static final String QUOTE_STR = String.valueOf(QUOTE); + public static final char ESCAPE = '\\'; + public static final String ESCAPE_STR = String.valueOf(ESCAPE); + public static final String ESCAPED_QUOTE_STR = ESCAPE_STR + QUOTE_STR; + public static final String ESCAPED_ESCAPE_STR = ESCAPE_STR + ESCAPE_STR; + + public static String buildFormatString(String format, int num) { + return buildFormatString(format, SEPARATOR, num); + } + + public static String buildFormatString(String... format) { + return String.join(SEPARATOR_STR, format); + } + + public static String buildFormatString(String format, char separator, int num) { + StringBuilder sb = new StringBuilder(num * (format.length() + 1) - 1); + sb.append(format); + for (int i = 1; i < num; i++) { + sb.append(separator).append(format); + } + return sb.toString(); + } + + public static final class Escape { + + public static PrintStream println(PrintStream out, String format, Object... args) { + return println(out, SEPARATOR, QUOTE, ESCAPE, format, args); + } + + public static LogStream println(LogStream out, String format, Object... args) { + return println(out, SEPARATOR, QUOTE, ESCAPE, format, args); + } + + public static String escape(String str) { + return escape(str, SEPARATOR, QUOTE, ESCAPE); + } + + public static String escapeRaw(String str) { + return escapeRaw(str, QUOTE, ESCAPE); + } + + public static PrintStream println(PrintStream out, char separator, char quote, char escape, String format, Object... args) { + out.printf(format, escapeArgs(separator, quote, escape, args)); + out.println(); + return out; + } + + public static LogStream println(LogStream out, char separator, char quote, char escape, String format, Object... args) { + out.printf(format, escapeArgs(separator, quote, escape, args)); + out.println(); + return out; + } + + private static Object[] escapeArgs(char separator, char quote, char escape, Object... args) { + String separatorStr = String.valueOf(separator); + for (int i = 0; i < args.length; i++) { + Object obj = args[i]; + if (obj instanceof String) { + String str = (String) obj; + if (str.contains(separatorStr)) { + args[i] = escapeRaw(str, quote, escape); + } + } + } + return args; + } + + public static String escape(String str, char separator, char quote, char escape) { + String separatorStr = String.valueOf(separator); + if (str.contains(separatorStr)) { + return escapeRaw(str, quote, escape); + } + return str; + } + + public static String escapeRaw(String str, char quote, char escape) { + String quoteStr = String.valueOf(quote); + String escapeStr = String.valueOf(escape); + String escapedEscapeStr = escapeStr + escape; + String escapedQuoteStr = escapeStr + quote; + String str1 = str.replace(escapeStr, escapedEscapeStr); + String str2 = str1.replace(quoteStr, escapedQuoteStr); + String str3 = quoteStr + str2 + quote; + return str3; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java 2016-12-07 13:48:55.708961346 -0800 @@ -0,0 +1,1713 @@ +/* + * Copyright (c) 2012, 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.debug; + +import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.INTERCEPT; +import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.LOG_METHOD; +import static java.util.FormattableFlags.LEFT_JUSTIFY; +import static java.util.FormattableFlags.UPPERCASE; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; + +import org.graalvm.compiler.debug.DelegatingDebugConfig.Level; +import org.graalvm.compiler.debug.internal.CounterImpl; +import org.graalvm.compiler.debug.internal.DebugHistogramImpl; +import org.graalvm.compiler.debug.internal.DebugScope; +import org.graalvm.compiler.debug.internal.MemUseTrackerImpl; +import org.graalvm.compiler.debug.internal.TimerImpl; +import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl; +import org.graalvm.compiler.serviceprovider.GraalServices; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Scope based debugging facility. + * + * This facility is {@linkplain #isEnabled() enabled} if any of the following hold when the + * {@link Debug} class is initialized: + *
    + *
  • assertions are enabled for the {@link Debug} class
  • + *
  • {@link Debug#params}{@code .enable} is {@code true}
  • + *
+ */ +public class Debug { + + private static final Params params = new Params(); + + static { + // Load the service providers that may want to modify any of the + // parameters encapsulated by the Initialization class below. + for (DebugInitializationParticipant p : GraalServices.load(DebugInitializationParticipant.class)) { + p.apply(params); + } + } + + /** + * The parameters for configuring the initialization of {@link Debug} class. + */ + public static class Params { + public boolean enable; + public boolean enableMethodFilter; + public boolean enableUnscopedTimers; + public boolean enableUnscopedCounters; + public boolean enableUnscopedMethodMetrics; + public boolean enableUnscopedMemUseTrackers; + public boolean interceptCount; + public boolean interceptTime; + public boolean interceptMem; + } + + @SuppressWarnings("all") + private static boolean initialize() { + boolean assertionsEnabled = false; + assert assertionsEnabled = true; + return assertionsEnabled || params.enable || GraalDebugConfig.Options.ForceDebugEnable.getValue(); + } + + private static final boolean ENABLED = initialize(); + + public static boolean isEnabled() { + return ENABLED; + } + + public static boolean isDumpEnabledForMethod() { + if (!ENABLED) { + return false; + } + DebugConfig config = DebugScope.getConfig(); + if (config == null) { + return false; + } + return config.isDumpEnabledForMethod(); + } + + public static final int BASIC_LOG_LEVEL = 1; + public static final int INFO_LOG_LEVEL = 2; + public static final int VERBOSE_LOG_LEVEL = 3; + public static final int DETAILED_LOG_LEVEL = 4; + + public static boolean isDumpEnabled(int dumpLevel) { + return ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel); + } + + /** + * Determines if verification is enabled in the current method, regardless of the + * {@linkplain Debug#currentScope() current debug scope}. + * + * @see Debug#verify(Object, String) + */ + public static boolean isVerifyEnabledForMethod() { + if (!ENABLED) { + return false; + } + DebugConfig config = DebugScope.getConfig(); + if (config == null) { + return false; + } + return config.isVerifyEnabledForMethod(); + } + + /** + * Determines if verification is enabled in the {@linkplain Debug#currentScope() current debug + * scope}. + * + * @see Debug#verify(Object, String) + */ + public static boolean isVerifyEnabled() { + return ENABLED && DebugScope.getInstance().isVerifyEnabled(); + } + + public static boolean isCountEnabled() { + return ENABLED && DebugScope.getInstance().isCountEnabled(); + } + + public static boolean isTimeEnabled() { + return ENABLED && DebugScope.getInstance().isTimeEnabled(); + } + + public static boolean isMemUseTrackingEnabled() { + return ENABLED && DebugScope.getInstance().isMemUseTrackingEnabled(); + } + + public static boolean isLogEnabledForMethod() { + if (!ENABLED) { + return false; + } + DebugConfig config = DebugScope.getConfig(); + if (config == null) { + return false; + } + return config.isLogEnabledForMethod(); + } + + public static boolean isLogEnabled() { + return isLogEnabled(BASIC_LOG_LEVEL); + } + + public static boolean isLogEnabled(int logLevel) { + return ENABLED && DebugScope.getInstance().isLogEnabled(logLevel); + } + + public static boolean isMethodMeterEnabled() { + return ENABLED && DebugScope.getInstance().isMethodMeterEnabled(); + } + + @SuppressWarnings("unused") + public static Runnable decorateDebugRoot(Runnable runnable, String name, DebugConfig config) { + return runnable; + } + + @SuppressWarnings("unused") + public static Callable decorateDebugRoot(Callable callable, String name, DebugConfig config) { + return callable; + } + + @SuppressWarnings("unused") + public static Runnable decorateScope(Runnable runnable, String name, Object... context) { + return runnable; + } + + @SuppressWarnings("unused") + public static Callable decorateScope(Callable callable, String name, Object... context) { + return callable; + } + + /** + * Gets a string composed of the names in the current nesting of debug + * {@linkplain #scope(Object) scopes} separated by {@code '.'}. + */ + public static String currentScope() { + if (ENABLED) { + return DebugScope.getInstance().getQualifiedName(); + } else { + return ""; + } + } + + /** + * Represents a debug scope entered by {@link Debug#scope(Object)} or + * {@link Debug#sandbox(CharSequence, DebugConfig, Object...)}. Leaving the scope is achieved + * via {@link #close()}. + */ + public interface Scope extends AutoCloseable { + @Override + void close(); + } + + /** + * Creates and enters a new debug scope which will be a child of the current debug scope. + *

+ * It is recommended to use the try-with-resource statement for managing entering and leaving + * debug scopes. For example: + * + *

+     * try (Scope s = Debug.scope("InliningGraph", inlineeGraph)) {
+     *     ...
+     * } catch (Throwable e) {
+     *     throw Debug.handle(e);
+     * }
+     * 
+ * + * The {@code name} argument is subject to the following type based conversion before having + * {@link Object#toString()} called on it: + * + *
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * 
+ * + * @param name the name of the new scope + * @param contextObjects an array of object to be appended to the {@linkplain #context() + * current} debug context + * @throws Throwable used to enforce a catch block. + * @return the scope entered by this method which will be exited when its {@link Scope#close()} + * method is called + */ + public static Scope scope(Object name, Object[] contextObjects) throws Throwable { + if (ENABLED) { + return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, contextObjects); + } else { + return null; + } + } + + /** + * Similar to {@link #scope(Object, Object[])} but without context objects. Therefore the catch + * block can be omitted. + * + * @see #scope(Object, Object[]) + */ + public static Scope scope(Object name) { + if (ENABLED) { + return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null); + } else { + return null; + } + } + + public static Scope methodMetricsScope(Object name, DebugScope.ExtraInfo metaInfo, boolean newId, Object... context) { + if (ENABLED) { + return DebugScope.getInstance().enhanceWithExtraInfo(convertFormatArg(name).toString(), metaInfo, newId, context); + } else { + return null; + } + } + + /** + * @see #scope(Object, Object[]) + * @param context an object to be appended to the {@linkplain #context() current} debug context + */ + public static Scope scope(Object name, Object context) throws Throwable { + if (ENABLED) { + return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context); + } else { + return null; + } + } + + /** + * @see #scope(Object, Object[]) + * @param context1 first object to be appended to the {@linkplain #context() current} debug + * context + * @param context2 second object to be appended to the {@linkplain #context() current} debug + * context + */ + public static Scope scope(Object name, Object context1, Object context2) throws Throwable { + if (ENABLED) { + return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2); + } else { + return null; + } + } + + /** + * @see #scope(Object, Object[]) + * @param context1 first object to be appended to the {@linkplain #context() current} debug + * context + * @param context2 second object to be appended to the {@linkplain #context() current} debug + * context + * @param context3 third object to be appended to the {@linkplain #context() current} debug + * context + */ + public static Scope scope(Object name, Object context1, Object context2, Object context3) throws Throwable { + if (ENABLED) { + return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2, context3); + } else { + return null; + } + } + + /** + * Creates and enters a new debug scope which will be disjoint from the current debug scope. + *

+ * It is recommended to use the try-with-resource statement for managing entering and leaving + * debug scopes. For example: + * + *

+     * try (Scope s = Debug.sandbox("CompilingStub", null, stubGraph)) {
+     *     ...
+     * } catch (Throwable e) {
+     *     throw Debug.handle(e);
+     * }
+     * 
+ * + * @param name the name of the new scope + * @param config the debug configuration to use for the new scope + * @param context objects to be appended to the {@linkplain #context() current} debug context + * @return the scope entered by this method which will be exited when its {@link Scope#close()} + * method is called + */ + public static Scope sandbox(CharSequence name, DebugConfig config, Object... context) throws Throwable { + if (ENABLED) { + DebugConfig sandboxConfig = config == null ? silentConfig() : config; + return DebugScope.getInstance().scope(name, sandboxConfig, context); + } else { + return null; + } + } + + public static Scope forceLog() throws Throwable { + ArrayList context = new ArrayList<>(); + for (Object obj : context()) { + context.add(obj); + } + return Debug.sandbox("forceLog", new DelegatingDebugConfig().override(Level.LOG, Integer.MAX_VALUE).enable(LOG_METHOD), context.toArray()); + } + + /** + * Opens a scope in which exception {@linkplain DebugConfig#interceptException(Throwable) + * interception} is disabled. It is recommended to use the try-with-resource statement for + * managing entering and leaving such scopes: + * + *
+     * try (DebugConfigScope s = Debug.disableIntercept()) {
+     *     ...
+     * }
+     * 
+ * + * This is particularly useful to suppress extraneous output in JUnit tests that are expected to + * throw an exception. + */ + public static DebugConfigScope disableIntercept() { + return Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); + } + + /** + * Handles an exception in the context of the debug scope just exited. The just exited scope + * must have the current scope as its parent which will be the case if the try-with-resource + * pattern recommended by {@link #scope(Object)} and + * {@link #sandbox(CharSequence, DebugConfig, Object...)} is used + * + * @see #scope(Object, Object[]) + * @see #sandbox(CharSequence, DebugConfig, Object...) + */ + public static RuntimeException handle(Throwable exception) { + if (ENABLED) { + return DebugScope.getInstance().handle(exception); + } else { + if (exception instanceof Error) { + throw (Error) exception; + } + if (exception instanceof RuntimeException) { + throw (RuntimeException) exception; + } + throw new RuntimeException(exception); + } + } + + public static void log(String msg) { + log(BASIC_LOG_LEVEL, msg); + } + + /** + * Prints a message to the current debug scope's logging stream if logging is enabled. + * + * @param msg the message to log + */ + public static void log(int logLevel, String msg) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, msg); + } + } + + public static void log(String format, Object arg) { + log(BASIC_LOG_LEVEL, format, arg); + } + + /** + * Prints a message to the current debug scope's logging stream if logging is enabled. + * + * @param format a format string + * @param arg the argument referenced by the format specifiers in {@code format} + */ + public static void log(int logLevel, String format, Object arg) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg); + } + } + + public static void log(String format, int arg) { + log(BASIC_LOG_LEVEL, format, arg); + } + + /** + * Prints a message to the current debug scope's logging stream if logging is enabled. + * + * @param format a format string + * @param arg the argument referenced by the format specifiers in {@code format} + */ + public static void log(int logLevel, String format, int arg) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg); + } + } + + public static void log(String format, Object arg1, Object arg2) { + log(BASIC_LOG_LEVEL, format, arg1, arg2); + } + + /** + * @see #log(int, String, Object) + */ + public static void log(int logLevel, String format, Object arg1, Object arg2) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2); + } + } + + public static void log(String format, int arg1, Object arg2) { + log(BASIC_LOG_LEVEL, format, arg1, arg2); + } + + /** + * @see #log(int, String, Object) + */ + public static void log(int logLevel, String format, int arg1, Object arg2) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2); + } + } + + public static void log(String format, Object arg1, int arg2) { + log(BASIC_LOG_LEVEL, format, arg1, arg2); + } + + /** + * @see #log(int, String, Object) + */ + public static void log(int logLevel, String format, Object arg1, int arg2) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2); + } + } + + public static void log(String format, int arg1, int arg2) { + log(BASIC_LOG_LEVEL, format, arg1, arg2); + } + + /** + * @see #log(int, String, Object) + */ + public static void log(int logLevel, String format, int arg1, int arg2) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2); + } + } + + public static void log(String format, Object arg1, Object arg2, Object arg3) { + log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3); + } + + /** + * @see #log(int, String, Object) + */ + public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3); + } + } + + public static void log(String format, int arg1, int arg2, int arg3) { + log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3); + } + + /** + * @see #log(int, String, Object) + */ + public static void log(int logLevel, String format, int arg1, int arg2, int arg3) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3); + } + } + + public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4) { + log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4); + } + + /** + * @see #log(int, String, Object) + */ + public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4); + } + } + + public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { + log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5); + } + + /** + * @see #log(int, String, Object) + */ + public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5); + } + } + + public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { + log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6); + } + + /** + * @see #log(int, String, Object) + */ + public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6); + } + } + + public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) { + log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + + public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) { + log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + + /** + * @see #log(int, String, Object) + */ + public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + } + + public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + } + + public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) { + log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + } + + public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + } + } + + public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) { + log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } + + public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) { + if (ENABLED) { + DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } + } + + public static void logv(String format, Object... args) { + logv(BASIC_LOG_LEVEL, format, args); + } + + /** + * Prints a message to the current debug scope's logging stream. This method must only be called + * if debugging is {@linkplain Debug#isEnabled() enabled} as it incurs allocation at the call + * site. If possible, call one of the other {@code log()} methods in this class that take a + * fixed number of parameters. + * + * @param format a format string + * @param args the arguments referenced by the format specifiers in {@code format} + */ + public static void logv(int logLevel, String format, Object... args) { + if (!ENABLED) { + throw new InternalError("Use of Debug.logv() must be guarded by a test of Debug.isEnabled()"); + } + DebugScope.getInstance().log(logLevel, format, args); + } + + /** + * This override exists to catch cases when {@link #log(String, Object)} is called with one + * argument bound to a varargs method parameter. It will bind to this method instead of the + * single arg variant and produce a deprecation warning instead of silently wrapping the + * Object[] inside of another Object[]. + */ + @Deprecated + public static void log(String format, Object[] args) { + assert false : "shouldn't use this"; + log(BASIC_LOG_LEVEL, format, args); + } + + /** + * This override exists to catch cases when {@link #log(int, String, Object)} is called with one + * argument bound to a varargs method parameter. It will bind to this method instead of the + * single arg variant and produce a deprecation warning instead of silently wrapping the + * Object[] inside of another Object[]. + */ + @Deprecated + public static void log(int logLevel, String format, Object[] args) { + assert false : "shouldn't use this"; + logv(logLevel, format, args); + } + + public static void dump(int dumpLevel, Object object, String msg) { + if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) { + DebugScope.getInstance().dump(dumpLevel, object, msg); + } + } + + public static void dump(int dumpLevel, Object object, String format, Object arg) { + if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) { + DebugScope.getInstance().dump(dumpLevel, object, format, arg); + } + } + + public static void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2) { + if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) { + DebugScope.getInstance().dump(dumpLevel, object, format, arg1, arg2); + } + } + + public static void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2, Object arg3) { + if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) { + DebugScope.getInstance().dump(dumpLevel, object, format, arg1, arg2, arg3); + } + } + + /** + * This override exists to catch cases when {@link #dump(int, Object, String, Object)} is called + * with one argument bound to a varargs method parameter. It will bind to this method instead of + * the single arg variant and produce a deprecation warning instead of silently wrapping the + * Object[] inside of another Object[]. + */ + @Deprecated + public static void dump(int dumpLevel, Object object, String format, Object[] args) { + assert false : "shouldn't use this"; + if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) { + DebugScope.getInstance().dump(dumpLevel, object, format, args); + } + } + + /** + * Calls all {@link DebugVerifyHandler}s in the current {@linkplain DebugScope#getConfig() + * config} to perform verification on a given object. + * + * @param object object to verify + * @param message description of verification context + * + * @see DebugVerifyHandler#verify(Object, String) + */ + public static void verify(Object object, String message) { + if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) { + DebugScope.getInstance().verify(object, message); + } + } + + /** + * Calls all {@link DebugVerifyHandler}s in the current {@linkplain DebugScope#getConfig() + * config} to perform verification on a given object. + * + * @param object object to verify + * @param format a format string for the description of the verification context + * @param arg the argument referenced by the format specifiers in {@code format} + * + * @see DebugVerifyHandler#verify(Object, String) + */ + public static void verify(Object object, String format, Object arg) { + if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) { + DebugScope.getInstance().verify(object, format, arg); + } + } + + /** + * This override exists to catch cases when {@link #verify(Object, String, Object)} is called + * with one argument bound to a varargs method parameter. It will bind to this method instead of + * the single arg variant and produce a deprecation warning instead of silently wrapping the + * Object[] inside of another Object[]. + */ + @Deprecated + public static void verify(Object object, String format, Object[] args) { + assert false : "shouldn't use this"; + if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) { + DebugScope.getInstance().verify(object, format, args); + } + } + + /** + * Opens a new indentation level (by adding some spaces) based on the current indentation level. + * This should be used in a {@linkplain Indent try-with-resources} pattern. + * + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + * @see #logAndIndent(int, String) + * @see #logAndIndent(int, String, Object) + */ + public static Indent indent() { + if (ENABLED) { + DebugScope scope = DebugScope.getInstance(); + return scope.pushIndentLogger(); + } + return null; + } + + public static Indent logAndIndent(String msg) { + return logAndIndent(BASIC_LOG_LEVEL, msg); + } + + /** + * A convenience function which combines {@link #log(String)} and {@link #indent()}. + * + * @param msg the message to log + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + */ + public static Indent logAndIndent(int logLevel, String msg) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, msg); + } + return null; + } + + public static Indent logAndIndent(String format, Object arg) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg); + } + + /** + * A convenience function which combines {@link #log(String, Object)} and {@link #indent()}. + * + * @param format a format string + * @param arg the argument referenced by the format specifiers in {@code format} + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + */ + public static Indent logAndIndent(int logLevel, String format, Object arg) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg); + } + return null; + } + + public static Indent logAndIndent(String format, int arg) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg); + } + + /** + * A convenience function which combines {@link #log(String, Object)} and {@link #indent()}. + * + * @param format a format string + * @param arg the argument referenced by the format specifiers in {@code format} + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + */ + public static Indent logAndIndent(int logLevel, String format, int arg) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg); + } + return null; + } + + public static Indent logAndIndent(String format, int arg1, Object arg2) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2); + } + + /** + * @see #logAndIndent(int, String, Object) + */ + public static Indent logAndIndent(int logLevel, String format, int arg1, Object arg2) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg1, arg2); + } + return null; + } + + public static Indent logAndIndent(String format, Object arg1, int arg2) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2); + } + + /** + * @see #logAndIndent(int, String, Object) + */ + public static Indent logAndIndent(int logLevel, String format, Object arg1, int arg2) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg1, arg2); + } + return null; + } + + public static Indent logAndIndent(String format, int arg1, int arg2) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2); + } + + /** + * @see #logAndIndent(int, String, Object) + */ + public static Indent logAndIndent(int logLevel, String format, int arg1, int arg2) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg1, arg2); + } + return null; + } + + public static Indent logAndIndent(String format, Object arg1, Object arg2) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2); + } + + /** + * @see #logAndIndent(int, String, Object) + */ + public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg1, arg2); + } + return null; + } + + public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3); + } + + /** + * @see #logAndIndent(int, String, Object) + */ + public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3); + } + return null; + } + + public static Indent logAndIndent(String format, int arg1, int arg2, int arg3) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3); + } + + /** + * @see #logAndIndent(int, String, Object) + */ + public static Indent logAndIndent(int logLevel, String format, int arg1, int arg2, int arg3) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3); + } + return null; + } + + public static Indent logAndIndent(String format, Object arg1, int arg2, int arg3) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3); + } + + /** + * @see #logAndIndent(int, String, Object) + */ + public static Indent logAndIndent(int logLevel, String format, Object arg1, int arg2, int arg3) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3); + } + return null; + } + + public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4); + } + + /** + * @see #logAndIndent(int, String, Object) + */ + public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3, arg4); + } + return null; + } + + public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5); + } + + /** + * @see #logAndIndent(int, String, Object) + */ + public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3, arg4, arg5); + } + return null; + } + + public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { + return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6); + } + + /** + * @see #logAndIndent(int, String, Object) + */ + public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { + if (ENABLED && Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6); + } + return null; + } + + /** + * A convenience function which combines {@link #logv(int, String, Object...)} and + * {@link #indent()}. + * + * @param format a format string + * @param args the arguments referenced by the format specifiers in {@code format} + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + */ + public static Indent logvAndIndent(int logLevel, String format, Object... args) { + if (ENABLED) { + if (Debug.isLogEnabled(logLevel)) { + return logvAndIndentInternal(logLevel, format, args); + } + return null; + } + throw new InternalError("Use of Debug.logvAndIndent() must be guarded by a test of Debug.isEnabled()"); + } + + private static Indent logvAndIndentInternal(int logLevel, String format, Object... args) { + assert ENABLED && Debug.isLogEnabled(logLevel) : "must have checked Debug.isLogEnabled()"; + DebugScope scope = DebugScope.getInstance(); + scope.log(logLevel, format, args); + return scope.pushIndentLogger(); + } + + /** + * This override exists to catch cases when {@link #logAndIndent(String, Object)} is called with + * one argument bound to a varargs method parameter. It will bind to this method instead of the + * single arg variant and produce a deprecation warning instead of silently wrapping the + * Object[] inside of another Object[]. + */ + @Deprecated + public static void logAndIndent(String format, Object[] args) { + assert false : "shouldn't use this"; + logAndIndent(BASIC_LOG_LEVEL, format, args); + } + + /** + * This override exists to catch cases when {@link #logAndIndent(int, String, Object)} is called + * with one argument bound to a varargs method parameter. It will bind to this method instead of + * the single arg variant and produce a deprecation warning instead of silently wrapping the + * Object[] inside of another Object[]. + */ + @Deprecated + public static void logAndIndent(int logLevel, String format, Object[] args) { + assert false : "shouldn't use this"; + logvAndIndent(logLevel, format, args); + } + + public static Iterable context() { + if (ENABLED) { + return DebugScope.getInstance().getCurrentContext(); + } else { + return Collections.emptyList(); + } + } + + @SuppressWarnings("unchecked") + public static List contextSnapshot(Class clazz) { + if (ENABLED) { + List result = new ArrayList<>(); + for (Object o : context()) { + if (clazz.isInstance(o)) { + result.add((T) o); + } + } + return result; + } else { + return Collections.emptyList(); + } + } + + /** + * Searches the current debug scope, bottom up, for a context object that is an instance of a + * given type. The first such object found is returned. + */ + @SuppressWarnings("unchecked") + public static T contextLookup(Class clazz) { + if (ENABLED) { + for (Object o : context()) { + if (clazz.isInstance(o)) { + return ((T) o); + } + } + } + return null; + } + + /** + * Creates a {@linkplain DebugMemUseTracker memory use tracker} that is enabled iff debugging is + * {@linkplain #isEnabled() enabled}. + *

+ * A disabled tracker has virtually no overhead. + */ + public static DebugMemUseTracker memUseTracker(CharSequence name) { + if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) { + return VOID_MEM_USE_TRACKER; + } + return createMemUseTracker("%s", name, null); + } + + /** + * Creates a debug memory use tracker. Invoking this method is equivalent to: + * + *

+     * Debug.memUseTracker(format, arg, null)
+     * 
+ * + * except that the string formatting only happens if mem tracking is enabled. + * + * @see #counter(String, Object, Object) + */ + public static DebugMemUseTracker memUseTracker(String format, Object arg) { + if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) { + return VOID_MEM_USE_TRACKER; + } + return createMemUseTracker(format, arg, null); + } + + /** + * Creates a debug memory use tracker. Invoking this method is equivalent to: + * + *
+     * Debug.memUseTracker(String.format(format, arg1, arg2))
+     * 
+ * + * except that the string formatting only happens if memory use tracking is enabled. In + * addition, each argument is subject to the following type based conversion before being passed + * as an argument to {@link String#format(String, Object...)}: + * + *
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * 
+ * + * @see #memUseTracker(CharSequence) + */ + public static DebugMemUseTracker memUseTracker(String format, Object arg1, Object arg2) { + if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) { + return VOID_MEM_USE_TRACKER; + } + return createMemUseTracker(format, arg1, arg2); + } + + private static DebugMemUseTracker createMemUseTracker(String format, Object arg1, Object arg2) { + String name = formatDebugName(format, arg1, arg2); + return DebugValueFactory.createMemUseTracker(name, !isUnconditionalMemUseTrackingEnabled); + } + + /** + * Creates a {@linkplain DebugCounter counter} that is enabled iff debugging is + * {@linkplain #isEnabled() enabled} or the system property whose name is formed by adding + * {@value #ENABLE_COUNTER_PROPERTY_NAME_PREFIX} to {@code name} is + * {@linkplain Boolean#getBoolean(String) true}. If the latter condition is true, then the + * returned counter is {@linkplain DebugCounter#isConditional() unconditional} otherwise it is + * conditional. + *

+ * A disabled counter has virtually no overhead. + */ + public static DebugCounter counter(CharSequence name) { + if (!areUnconditionalCountersEnabled() && !ENABLED) { + return VOID_COUNTER; + } + return createCounter("%s", name, null); + } + + /** + * Creates a {@link DebugMethodMetrics metric} that is enabled iff debugging is + * {@link #isEnabled() enabled}. + */ + public static DebugMethodMetrics methodMetrics(ResolvedJavaMethod method) { + if (isMethodMeterEnabled() && method != null) { + return MethodMetricsImpl.getMethodMetrics(method); + } + return VOID_MM; + } + + public static String applyFormattingFlagsAndWidth(String s, int flags, int width) { + if (flags == 0 && width < 0) { + return s; + } + StringBuilder sb = new StringBuilder(s); + + // apply width and justification + int len = sb.length(); + if (len < width) { + for (int i = 0; i < width - len; i++) { + if ((flags & LEFT_JUSTIFY) == LEFT_JUSTIFY) { + sb.append(' '); + } else { + sb.insert(0, ' '); + } + } + } + + String res = sb.toString(); + if ((flags & UPPERCASE) == UPPERCASE) { + res = res.toUpperCase(); + } + return res; + } + + /** + * Creates a debug counter. Invoking this method is equivalent to: + * + *

+     * Debug.counter(format, arg, null)
+     * 
+ * + * except that the string formatting only happens if count is enabled. + * + * @see #counter(String, Object, Object) + */ + public static DebugCounter counter(String format, Object arg) { + if (!areUnconditionalCountersEnabled() && !ENABLED) { + return VOID_COUNTER; + } + return createCounter(format, arg, null); + } + + /** + * Creates a debug counter. Invoking this method is equivalent to: + * + *
+     * Debug.counter(String.format(format, arg1, arg2))
+     * 
+ * + * except that the string formatting only happens if count is enabled. In addition, each + * argument is subject to the following type based conversion before being passed as an argument + * to {@link String#format(String, Object...)}: + * + *
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * 
+ * + * @see #counter(CharSequence) + */ + public static DebugCounter counter(String format, Object arg1, Object arg2) { + if (!areUnconditionalCountersEnabled() && !ENABLED) { + return VOID_COUNTER; + } + return createCounter(format, arg1, arg2); + } + + private static DebugCounter createCounter(String format, Object arg1, Object arg2) { + String name = formatDebugName(format, arg1, arg2); + boolean conditional = enabledCounters == null || !findMatch(enabledCounters, enabledCountersSubstrings, name); + if (!ENABLED && conditional) { + return VOID_COUNTER; + } + return DebugValueFactory.createCounter(name, conditional); + } + + /** + * Changes the debug configuration for the current thread. + * + * @param config new configuration to use for the current thread + * @return an object that when {@linkplain DebugConfigScope#close() closed} will restore the + * debug configuration for the current thread to what it was before this method was + * called + */ + public static DebugConfigScope setConfig(DebugConfig config) { + if (ENABLED) { + return new DebugConfigScope(config); + } else { + return null; + } + } + + /** + * Creates an object for counting value frequencies. + */ + public static DebugHistogram createHistogram(String name) { + return new DebugHistogramImpl(name); + } + + public static DebugConfig silentConfig() { + return fixedConfig(0, 0, false, false, false, false, false, Collections. emptyList(), Collections. emptyList(), null); + } + + public static DebugConfig fixedConfig(final int logLevel, final int dumpLevel, final boolean isCountEnabled, final boolean isMemUseTrackingEnabled, final boolean isTimerEnabled, + final boolean isVerifyEnabled, final boolean isMMEnabled, final Collection dumpHandlers, final Collection verifyHandlers, + final PrintStream output) { + return new DebugConfig() { + + @Override + public int getLogLevel() { + return logLevel; + } + + @Override + public boolean isLogEnabledForMethod() { + return logLevel > 0; + } + + @Override + public boolean isCountEnabled() { + return isCountEnabled; + } + + @Override + public boolean isMemUseTrackingEnabled() { + return isMemUseTrackingEnabled; + } + + @Override + public int getDumpLevel() { + return dumpLevel; + } + + @Override + public boolean isDumpEnabledForMethod() { + return dumpLevel > 0; + } + + @Override + public boolean isVerifyEnabled() { + return isVerifyEnabled; + } + + @Override + public boolean isVerifyEnabledForMethod() { + return isVerifyEnabled; + } + + @Override + public boolean isMethodMeterEnabled() { + return isMMEnabled; + } + + @Override + public boolean isTimeEnabled() { + return isTimerEnabled; + } + + @Override + public RuntimeException interceptException(Throwable e) { + return null; + } + + @Override + public Collection dumpHandlers() { + return dumpHandlers; + } + + @Override + public Collection verifyHandlers() { + return verifyHandlers; + } + + @Override + public PrintStream output() { + return output; + } + + @Override + public void addToContext(Object o) { + } + + @Override + public void removeFromContext(Object o) { + } + }; + } + + private static final DebugCounter VOID_COUNTER = new DebugCounter() { + + @Override + public void increment() { + } + + @Override + public void add(long value) { + } + + @Override + public void setConditional(boolean flag) { + throw new InternalError("Cannot make void counter conditional"); + } + + @Override + public boolean isConditional() { + return false; + } + + @Override + public long getCurrentValue() { + return 0L; + } + }; + + private static final DebugMethodMetrics VOID_MM = new DebugMethodMetrics() { + + @Override + public void addToMetric(long value, String metricName) { + } + + @Override + public void addToMetric(long value, String format, Object arg1) { + } + + @Override + public void addToMetric(long value, String format, Object arg1, Object arg2) { + } + + @Override + public void addToMetric(long value, String format, Object arg1, Object arg2, Object arg3) { + } + + @Override + public void incrementMetric(String metricName) { + } + + @Override + public void incrementMetric(String format, Object arg1) { + } + + @Override + public void incrementMetric(String format, Object arg1, Object arg2) { + } + + @Override + public void incrementMetric(String format, Object arg1, Object arg2, Object arg3) { + } + + @Override + public long getCurrentMetricValue(String metricName) { + return 0; + } + + @Override + public long getCurrentMetricValue(String format, Object arg1) { + return 0; + } + + @Override + public long getCurrentMetricValue(String format, Object arg1, Object arg2) { + return 0; + } + + @Override + public long getCurrentMetricValue(String format, Object arg1, Object arg2, Object arg3) { + return 0; + } + + @Override + public ResolvedJavaMethod getMethod() { + return null; + } + + }; + + private static final DebugMemUseTracker VOID_MEM_USE_TRACKER = new DebugMemUseTracker() { + + @Override + public DebugCloseable start() { + return DebugCloseable.VOID_CLOSEABLE; + } + + @Override + public long getCurrentValue() { + return 0; + } + }; + + /** + * @see #timer(CharSequence) + */ + public static final String ENABLE_TIMER_PROPERTY_NAME_PREFIX = "graaldebug.timer."; + + /** + * @see #counter(CharSequence) + */ + public static final String ENABLE_COUNTER_PROPERTY_NAME_PREFIX = "graaldebug.counter."; + + /** + * Set of unconditionally enabled counters. Possible values and their meanings: + *
    + *
  • {@code null}: no unconditionally enabled counters
  • + *
  • {@code isEmpty()}: all counters are unconditionally enabled
  • + *
  • {@code !isEmpty()}: use {@link #findMatch(Set, Set, String)} on this set and + * {@link #enabledCountersSubstrings} to determine which counters are unconditionally enabled + *
  • + *
+ */ + private static final Set enabledCounters; + + /** + * Set of unconditionally enabled timers. Same interpretation of values as for + * {@link #enabledCounters}. + */ + private static final Set enabledTimers; + + private static final Set enabledCountersSubstrings = new HashSet<>(); + private static final Set enabledTimersSubstrings = new HashSet<>(); + + /** + * Specifies if all mem use trackers are unconditionally enabled. + */ + private static final boolean isUnconditionalMemUseTrackingEnabled; + + static { + Set counters = new HashSet<>(); + Set timers = new HashSet<>(); + parseCounterAndTimerSystemProperties(counters, timers, enabledCountersSubstrings, enabledTimersSubstrings); + counters = counters.isEmpty() && enabledCountersSubstrings.isEmpty() ? null : counters; + timers = timers.isEmpty() && enabledTimersSubstrings.isEmpty() ? null : timers; + if (counters == null && params.enableUnscopedCounters && !params.enableMethodFilter) { + counters = Collections.emptySet(); + } + if (timers == null && params.enableUnscopedTimers && !params.enableMethodFilter) { + timers = Collections.emptySet(); + } + enabledCounters = counters; + enabledTimers = timers; + isUnconditionalMemUseTrackingEnabled = params.enableUnscopedMemUseTrackers; + DebugValueFactory = initDebugValueFactory(); + } + + private static DebugValueFactory initDebugValueFactory() { + return new DebugValueFactory() { + + @Override + public DebugTimer createTimer(String name, boolean conditional) { + return new TimerImpl(name, conditional, params.interceptTime); + } + + @Override + public DebugCounter createCounter(String name, boolean conditional) { + return CounterImpl.create(name, conditional, params.interceptCount); + } + + @Override + public DebugMethodMetrics createMethodMetrics(ResolvedJavaMethod method) { + return MethodMetricsImpl.getMethodMetrics(method); + } + + @Override + public DebugMemUseTracker createMemUseTracker(String name, boolean conditional) { + return new MemUseTrackerImpl(name, conditional, params.interceptMem); + } + }; + } + + private static DebugValueFactory DebugValueFactory; + + public static void setDebugValueFactory(DebugValueFactory factory) { + Objects.requireNonNull(factory); + DebugValueFactory = factory; + } + + public static DebugValueFactory getDebugValueFactory() { + return DebugValueFactory; + } + + private static boolean findMatch(Set haystack, Set haystackSubstrings, String needle) { + if (haystack.isEmpty() && haystackSubstrings.isEmpty()) { + // Empty haystack means match all + return true; + } + if (haystack.contains(needle)) { + return true; + } + if (!haystackSubstrings.isEmpty()) { + for (String h : haystackSubstrings) { + if (needle.startsWith(h)) { + return true; + } + } + } + return false; + } + + public static boolean areUnconditionalTimersEnabled() { + return enabledTimers != null; + } + + public static boolean areUnconditionalCountersEnabled() { + return enabledCounters != null; + } + + public static boolean isMethodFilteringEnabled() { + return params.enableMethodFilter; + } + + public static boolean areUnconditionalMethodMetricsEnabled() { + // we do not collect mm substrings + return params.enableUnscopedMethodMetrics; + } + + protected static void parseCounterAndTimerSystemProperties(Set counters, Set timers, Set countersSubstrings, Set timersSubstrings) { + do { + try { + for (Map.Entry e : System.getProperties().entrySet()) { + String name = e.getKey().toString(); + if (name.startsWith(ENABLE_COUNTER_PROPERTY_NAME_PREFIX) && Boolean.parseBoolean(e.getValue().toString())) { + if (name.endsWith("*")) { + countersSubstrings.add(name.substring(ENABLE_COUNTER_PROPERTY_NAME_PREFIX.length(), name.length() - 1)); + } else { + counters.add(name.substring(ENABLE_COUNTER_PROPERTY_NAME_PREFIX.length())); + } + } + if (name.startsWith(ENABLE_TIMER_PROPERTY_NAME_PREFIX) && Boolean.parseBoolean(e.getValue().toString())) { + if (name.endsWith("*")) { + timersSubstrings.add(name.substring(ENABLE_TIMER_PROPERTY_NAME_PREFIX.length(), name.length() - 1)); + } else { + timers.add(name.substring(ENABLE_TIMER_PROPERTY_NAME_PREFIX.length())); + } + } + } + return; + } catch (ConcurrentModificationException e) { + // Iterating over the system properties may race with another thread that is + // updating the system properties. Simply try again in this case. + } + } while (true); + } + + /** + * Creates a {@linkplain DebugTimer timer} that is enabled iff debugging is + * {@linkplain #isEnabled() enabled} or the system property whose name is formed by adding + * {@value #ENABLE_TIMER_PROPERTY_NAME_PREFIX} to {@code name} is + * {@linkplain Boolean#getBoolean(String) true}. If the latter condition is true, then the + * returned timer is {@linkplain DebugCounter#isConditional() unconditional} otherwise it is + * conditional. + *

+ * A disabled timer has virtually no overhead. + */ + public static DebugTimer timer(CharSequence name) { + if (!areUnconditionalTimersEnabled() && !ENABLED) { + return VOID_TIMER; + } + return createTimer("%s", name, null); + } + + /** + * Creates a debug timer. Invoking this method is equivalent to: + * + *

+     * Debug.timer(format, arg, null)
+     * 
+ * + * except that the string formatting only happens if timing is enabled. + * + * @see #timer(String, Object, Object) + */ + public static DebugTimer timer(String format, Object arg) { + if (!areUnconditionalTimersEnabled() && !ENABLED) { + return VOID_TIMER; + } + return createTimer(format, arg, null); + } + + /** + * Creates a debug timer. Invoking this method is equivalent to: + * + *
+     * Debug.timer(String.format(format, arg1, arg2))
+     * 
+ * + * except that the string formatting only happens if timing is enabled. In addition, each + * argument is subject to the following type based conversion before being passed as an argument + * to {@link String#format(String, Object...)}: + * + *
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * 
+ * + * @see #timer(CharSequence) + */ + public static DebugTimer timer(String format, Object arg1, Object arg2) { + if (!areUnconditionalTimersEnabled() && !ENABLED) { + return VOID_TIMER; + } + return createTimer(format, arg1, arg2); + } + + /** + * There are paths where construction of formatted class names are common and the code below is + * surprisingly expensive, so compute it once and cache it. + */ + private static final ClassValue formattedClassName = new ClassValue() { + @Override + protected String computeValue(Class c) { + final String simpleName = c.getSimpleName(); + Class enclosingClass = c.getEnclosingClass(); + if (enclosingClass != null) { + String prefix = ""; + while (enclosingClass != null) { + prefix = enclosingClass.getSimpleName() + "_" + prefix; + enclosingClass = enclosingClass.getEnclosingClass(); + } + return prefix + simpleName; + } else { + return simpleName; + } + } + }; + + public static Object convertFormatArg(Object arg) { + if (arg instanceof Class) { + return formattedClassName.get((Class) arg); + } + return arg; + } + + private static String formatDebugName(String format, Object arg1, Object arg2) { + return String.format(format, convertFormatArg(arg1), convertFormatArg(arg2)); + } + + private static DebugTimer createTimer(String format, Object arg1, Object arg2) { + String name = formatDebugName(format, arg1, arg2); + boolean conditional = enabledTimers == null || !findMatch(enabledTimers, enabledTimersSubstrings, name); + if (!ENABLED && conditional) { + return VOID_TIMER; + } + return DebugValueFactory.createTimer(name, conditional); + } + + private static final DebugTimer VOID_TIMER = new DebugTimer() { + + @Override + public DebugCloseable start() { + return DebugCloseable.VOID_CLOSEABLE; + } + + @Override + public void setConditional(boolean flag) { + throw new InternalError("Cannot make void timer conditional"); + } + + @Override + public boolean isConditional() { + return false; + } + + @Override + public long getCurrentValue() { + return 0L; + } + + @Override + public TimeUnit getTimeUnit() { + return null; + } + }; +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugCloseable.java 2016-12-07 13:48:55.975973082 -0800 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, 2015, 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.debug; + +/** + * An {@link AutoCloseable} whose {@link #close()} does not throw a checked exception. + */ +public interface DebugCloseable extends AutoCloseable { + + DebugCloseable VOID_CLOSEABLE = new DebugCloseable() { + + @Override + public void close() { + } + }; + + @Override + void close(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfig.java 2016-12-07 13:48:56.238984643 -0800 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2012, 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.debug; + +import java.io.PrintStream; +import java.util.Collection; + +public interface DebugConfig { + + /** + * Determines the current log level in the {@linkplain Debug#currentScope() current debug scope} + * . + */ + int getLogLevel(); + + /** + * Determines the current dump level in the {@linkplain Debug#currentScope() current debug + * scope}. + */ + int getDumpLevel(); + + /** + * Determines if logging can be enabled in the current method, regardless of the + * {@linkplain Debug#currentScope() current debug scope}. + */ + boolean isLogEnabledForMethod(); + + /** + * Determines if counting is enabled in the {@linkplain Debug#currentScope() current debug + * scope}. + * + * @see Debug#counter(CharSequence) + */ + boolean isCountEnabled(); + + /** + * Determines if memory use tracking is enabled in the {@linkplain Debug#currentScope() current + * debug scope}. + * + * @see Debug#memUseTracker(CharSequence) + */ + boolean isMemUseTrackingEnabled(); + + /** + * Determines if dumping can be enabled in the current method, regardless of the + * {@linkplain Debug#currentScope() current debug scope}. + */ + boolean isDumpEnabledForMethod(); + + /** + * @see Debug#isVerifyEnabled() + */ + boolean isVerifyEnabled(); + + /** + * @see Debug#isVerifyEnabledForMethod() + */ + boolean isVerifyEnabledForMethod(); + + /** + * @see Debug#isMethodMeterEnabled() + */ + boolean isMethodMeterEnabled(); + + /** + * Adds an object the context used by this configuration to do filtering. + */ + void addToContext(Object o); + + /** + * Removes an object the context used by this configuration to do filtering. + * + * This should only removes extra context added by {@link #addToContext(Object)}. + */ + void removeFromContext(Object o); + + /** + * @see Debug#timer(CharSequence) + */ + boolean isTimeEnabled(); + + /** + * Handles notification of an exception occurring within a debug scope. + * + * @return the exception object that is to be propagated to parent scope. A value of + * {@code null} indicates that {@code e} is to be propagated. + */ + RuntimeException interceptException(Throwable e); + + /** + * Gets the modifiable collection of dump handlers registered with this configuration. + */ + Collection dumpHandlers(); + + PrintStream output(); + + /** + * Gets the modifiable collection of verify handlers registered with this configuration. + */ + Collection verifyHandlers(); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigCustomizer.java 2016-12-07 13:48:56.504996336 -0800 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.debug; + +public interface DebugConfigCustomizer { + void customize(DebugConfig config, Object... extraArgs); + + static T lookupArg(Class c, Object... extraArgs) { + for (Object arg : extraArgs) { + if (c.isInstance(arg)) { + return c.cast(arg); + } + } + return null; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigScope.java 2016-12-07 13:48:56.771008029 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, 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.debug; + +import org.graalvm.compiler.debug.internal.DebugScope; + +/** + * A utility for scoping a change to the current debug {@linkplain DebugScope#setConfig(DebugConfig) + * configuration}. For example: + * + *
+ *     DebugConfig config = ...;
+ *     try (DebugConfigScope s = new DebugConfigScope(config)) {
+ *         // ...
+ *     }
+ * 
+ */ +public class DebugConfigScope implements AutoCloseable { + + private final DebugConfig current; + + /** + * Sets the current debug {@linkplain DebugScope#setConfig(DebugConfig) configuration} to a + * given value and creates an object that when {@linkplain #close() closed} resets the + * configuration to the {@linkplain DebugScope#getConfig() current} configuration. + */ + public DebugConfigScope(DebugConfig config) { + this.current = DebugScope.getConfig(); + DebugScope.getInstance().setConfig(config); + } + + @Override + public void close() { + DebugScope.getInstance().setConfig(current); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugCounter.java 2016-12-07 13:48:57.035019634 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 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.debug; + +/** + * A counter for some value of interest. + */ +public interface DebugCounter { + + /** + * Adds 1 to this counter if counting is {@link Debug#isCountEnabled() enabled} or this is an + * {@linkplain #isConditional() unconditional} counter. + */ + void increment(); + + /** + * Adds {@code value} to this counter if counting is {@link Debug#isCountEnabled() enabled} or + * this is an {@linkplain #isConditional() unconditional} counter. + */ + void add(long value); + + /** + * Sets a flag determining if this counter is only enabled if counting is + * {@link Debug#isCountEnabled() enabled}. + */ + void setConditional(boolean flag); + + /** + * Determines if this counter is only enabled if counting is {@link Debug#isCountEnabled() + * enabled}. + */ + boolean isConditional(); + + /** + * Gets the current value of this counter. + */ + long getCurrentValue(); + + /** + * Determines if this counter is enabled (either conditionally or unconditionally). + */ + default boolean isEnabled() { + return !isConditional() || Debug.isCountEnabled(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugDumpHandler.java 2016-12-07 13:48:57.300031283 -0800 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012, 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.debug; + +import java.io.Closeable; + +public interface DebugDumpHandler extends Closeable { + + void dump(Object object, String message); + + /** + * Flushes and releases resources managed by this dump handler. A subsequent call to + * {@link #dump(Object, String)} will create and open new resources. That is, this method can be + * used to reset the handler. + */ + @Override + void close(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugDumpScope.java 2016-12-07 13:48:57.565042932 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.debug; + +public class DebugDumpScope { + + public final String name; + + /** + * Specifies if this scope decorates an inner scope. A hierarchical or tree representation of + * nested scopes may choose to represent a decorator scope at the same level as the scope it + * decorates. + */ + public final boolean decorator; + + public DebugDumpScope(String name) { + this(name, false); + } + + public DebugDumpScope(String name, boolean decorator) { + this.name = name; + this.decorator = decorator; + } + + @Override + public String toString() { + return "DebugDumpScope[" + name + "]"; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugEnvironment.java 2016-12-07 13:48:57.830054581 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2013, 2015, 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.debug; + +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Log; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Count; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.MethodFilter; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Time; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.TrackMemUse; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Verify; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.MethodMeter; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import org.graalvm.compiler.serviceprovider.GraalServices; + +import jdk.vm.ci.runtime.JVMCI; + +public class DebugEnvironment { + + public static GraalDebugConfig initialize(PrintStream log, Object... extraArgs) { + // Initialize JVMCI before loading class Debug + JVMCI.initialize(); + if (!Debug.isEnabled()) { + log.println("WARNING: Scope debugging needs to be enabled with -esa"); + return null; + } + List dumpHandlers = new ArrayList<>(); + List verifyHandlers = new ArrayList<>(); + GraalDebugConfig debugConfig = new GraalDebugConfig(Log.getValue(), Count.getValue(), TrackMemUse.getValue(), Time.getValue(), Dump.getValue(), Verify.getValue(), MethodFilter.getValue(), + MethodMeter.getValue(), + log, dumpHandlers, verifyHandlers); + + for (DebugConfigCustomizer customizer : GraalServices.load(DebugConfigCustomizer.class)) { + customizer.customize(debugConfig, extraArgs); + } + + Debug.setConfig(debugConfig); + return debugConfig; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java 2016-12-07 13:48:58.093066142 -0800 @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2012, 2015, 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.debug; + +import java.util.Arrays; +import java.util.regex.Pattern; + +import org.graalvm.compiler.debug.GraalDebugConfig.Options; +import org.graalvm.compiler.debug.internal.DebugScope; + +/** + * Implements the filter specified by the {@link Options#Dump}, {@link Options#Log}, + * {@link Options#Count},{@link Options#MethodMeter} and {@link Options#Time} options. + *

+ * These options enable the associated debug facility if their filter matches the + * {@linkplain DebugScope#getQualifiedName() name} of the {@linkplain Debug#currentScope() current + * scope}. For the {@link Options#Dump} and {@link Options#Log} options, the log or dump level is + * set. The {@link Options#Count},{@link Options#MethodMeter} and {@link Options#Time} options don't + * have a level, for them {@code level = 0} means disabled and a {@code level > 0} means enabled. + *

+ * A filter is a list of comma-separated terms of the form {@code [:]}. {@code + * } is interpreted as a glob pattern if it contains a "*" or "?" character. Otherwise, it + * is interpreted as a substring. If {@code } is empty, it matches every scope. If {@code : + * } is omitted, it defaults to {@link Debug#BASIC_LOG_LEVEL}. The term {@code ~} is + * a shorthand for {@code :0} to disable a debug facility for a pattern. + *

+ * The resulting log level of a scope is determined by the last matching term. If no term + * matches, the log level is 0 (disabled). A filter with no terms matches every scope with a log + * level of {@link Debug#BASIC_LOG_LEVEL}. + * + *

Examples of filters

+ * + *
    + *
  • (empty string)
    + * Matches any scope with log level {@link Debug#BASIC_LOG_LEVEL}. + * + *
  • {@code :1}
    + * Matches any scope with log level 1. + * + *
  • {@code *}
    + * Matches any scope with log level {@link Debug#BASIC_LOG_LEVEL}. + * + *
  • {@code CodeGen,CodeInstall}
    + * Matches scopes containing "CodeGen" or "CodeInstall", both with log level + * {@link Debug#BASIC_LOG_LEVEL}. + * + *
  • {@code CodeGen:2,CodeInstall:1}
    + * Matches scopes containing "CodeGen" with log level 2, or "CodeInstall" with log level 1. + * + *
  • {@code :1,Dead:2}
    + * Matches scopes containing "Dead" with log level 2, and all other scopes with log level 1. + * + *
  • {@code :1,Dead:0}
    + * Matches all scopes with log level 1, except those containing "Dead". + * + *
  • {@code Code*}
    + * Matches scopes starting with "Code" with log level {@link Debug#BASIC_LOG_LEVEL}. + * + *
  • {@code Code,~Dead}
    + * Matches scopes containing "Code" but not "Dead", with log level {@link Debug#BASIC_LOG_LEVEL}. + *
+ */ +final class DebugFilter { + + public static DebugFilter parse(String spec) { + if (spec == null) { + return null; + } + return new DebugFilter(spec.split(",")); + } + + private final Term[] terms; + + private DebugFilter(String[] terms) { + if (terms.length == 0) { + this.terms = null; + } else { + this.terms = new Term[terms.length]; + for (int i = 0; i < terms.length; i++) { + String t = terms[i]; + int idx = t.indexOf(':'); + + String pattern; + int level; + if (idx < 0) { + if (t.startsWith("~")) { + pattern = t.substring(1); + level = 0; + } else { + pattern = t; + level = Debug.BASIC_LOG_LEVEL; + } + } else { + pattern = t.substring(0, idx); + if (idx + 1 < t.length()) { + String levelString = t.substring(idx + 1); + try { + level = Integer.parseInt(levelString); + } catch (NumberFormatException e) { + switch (levelString) { + case "basic": + level = Debug.BASIC_LOG_LEVEL; + break; + case "info": + level = Debug.INFO_LOG_LEVEL; + break; + case "verbose": + level = Debug.VERBOSE_LOG_LEVEL; + break; + default: + throw new IllegalArgumentException("Unknown dump level: \"" + levelString + "\" expected basic, info, verbose or an integer"); + } + } + + } else { + level = Debug.BASIC_LOG_LEVEL; + } + } + + this.terms[i] = new Term(pattern, level); + } + } + } + + /** + * Check whether a given input is matched by this filter, and determine the log level. + */ + public int matchLevel(String input) { + if (terms == null) { + return Debug.BASIC_LOG_LEVEL; + } else { + int level = 0; + for (Term t : terms) { + if (t.matches(input)) { + level = t.level; + } + } + return level; + } + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder("DebugFilter"); + if (terms != null) { + buf.append(Arrays.toString(terms)); + } else { + buf.append("[]"); + } + return buf.toString(); + } + + private static class Term { + + private final Pattern pattern; + public final int level; + + Term(String filter, int level) { + this.level = level; + if (filter.isEmpty()) { + this.pattern = null; + } else if (filter.contains("*") || filter.contains("?")) { + this.pattern = Pattern.compile(MethodFilter.createGlobString(filter)); + } else { + this.pattern = Pattern.compile(".*" + MethodFilter.createGlobString(filter) + ".*"); + } + } + + /** + * Determines if a given input is matched by this filter. + */ + public boolean matches(String input) { + return pattern == null || pattern.matcher(input).matches(); + } + + @Override + public String toString() { + return (pattern == null ? ".*" : pattern.toString()) + ":" + level; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugHistogram.java 2016-12-07 13:48:58.358077791 -0800 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.debug; + +import java.util.List; + +/** + * Facility for recording value frequencies. + */ +public interface DebugHistogram { + + /** + * Gets the name specified when this objected was {@linkplain Debug#createHistogram(String) + * created}. + */ + String getName(); + + /** + * Increments the count for a given value. + */ + void add(Object value); + + void add(Object value, long count); + + /** + * A value and a frequency. The ordering imposed by {@link #compareTo(CountedValue)} places + * values with higher frequencies first. + */ + class CountedValue implements Comparable { + + private long count; + private final Object value; + + public CountedValue(long count, Object value) { + this.count = count; + this.value = value; + } + + @Override + public int compareTo(CountedValue o) { + if (count < o.count) { + return 1; + } else if (count > o.count) { + return -1; + } + return 0; + } + + @Override + public String toString() { + return count + " -> " + value; + } + + public void inc() { + count++; + } + + public void add(long n) { + count += n; + } + + public long getCount() { + return count; + } + + public Object getValue() { + return value; + } + } + + /** + * Gets a list of the counted values, sorted in descending order of frequency. + */ + List getValues(); + + /** + * Interface for a service that can render a visualization of a histogram. + */ + public interface Printer { + + void print(DebugHistogram histogram); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugInitializationParticipant.java 2016-12-07 13:48:58.623089440 -0800 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.debug; + +import org.graalvm.compiler.debug.Debug.Params; + +/** + * Defines a service that can modify the {@linkplain Params parameters} for {@link Debug}. + */ +public interface DebugInitializationParticipant { + + /** + * Modifies the given {@link Debug} initialization parameters as necessary. + */ + void apply(Params params); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugMemUseTracker.java 2016-12-07 13:48:58.888101089 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2012, 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.debug; + +import com.sun.management.ThreadMXBean; + +/** + * Tracks memory usage within a scope using {@link ThreadMXBean}. This facility should be employed + * using the try-with-resources pattern: + * + *
+ * try (DebugMemUseTracker.Closeable a = memUseTracker.start()) {
+ *     // the code to measure
+ * }
+ * 
+ */ +public interface DebugMemUseTracker { + + /** + * Creates a point from which memory usage will be recorded if memory use tracking is + * {@linkplain Debug#isMemUseTrackingEnabled() enabled}. + * + * @return an object that must be closed once the activity has completed to add the memory used + * since this call to the total for this tracker + */ + DebugCloseable start(); + + /** + * Gets the current value of this tracker. + */ + long getCurrentValue(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugMethodMetrics.java 2016-12-07 13:48:59.153112737 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015, 2016, 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.debug; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * A set of debug metrics for all compilations of a {@link ResolvedJavaMethod}. A method metrics + * object is a container for several metrics per compilation of a method {@code >}. Metrics are stored on a per-method per-compilation basis. + * + *
+ * DebugMethodMetrics m = Debug.methodMetrics(method);
+ * m.incrementMetric("MyPerCompilationmetric");
+ * 
+ * + * In contrast to global metrics like {@link DebugCounter}, {@link DebugTimer} or + * {@linkplain DebugMemUseTracker}, method compilation metrics are always associated with a + * {@link ResolvedJavaMethod}. + */ +public interface DebugMethodMetrics { + + /** + * Adds {@code value} to the metric for the current compilation associated with + * {@code metricName}. If the metric is yet undefined for the current compilation a new metric + * for the given name is defined and the value for it is set to {@code value}. + * + * @param metricName the name for the metric to be incremented + * @param value the value to add to the metric defined by name + */ + void addToMetric(long value, String metricName); + + /** + * @see #addToMetric(long, String) + */ + void addToMetric(long value, String format, Object arg1); + + /** + * @see #addToMetric(long, String) + */ + void addToMetric(long value, String format, Object arg1, Object arg2); + + /** + * @see #addToMetric(long, String) + */ + void addToMetric(long value, String format, Object arg1, Object arg2, Object arg3); + + /** + * Adds {@code 1} to the metric for the current compilation associated with {@code metricName}. + * If the metric is yet undefined for the current compilation a new metric for the given name is + * defined and the value for it is set to {@code value}. + * + * @param metricName the name for the metric to be incremented + */ + void incrementMetric(String metricName); + + /** + * @see #incrementMetric(String) + */ + void incrementMetric(String format, Object arg1); + + /** + * @see #incrementMetric(String) + */ + void incrementMetric(String format, Object arg1, Object arg2); + + /** + * @see #incrementMetric(String) + */ + void incrementMetric(String format, Object arg1, Object arg2, Object arg3); + + /** + * Gets the value of the metric for the current compilation associated with the + * {@code metricName} . If the metric is yet undefined for the current compilation {@code 0} is + * returned instead. + * + * @param metricName the name of the metric for which the value will be returned + * @return the value of the metric for the given compilation or {@code 0} if it is not defined + */ + long getCurrentMetricValue(String metricName); + + /** + * @see #getCurrentMetricValue(String) + */ + long getCurrentMetricValue(String format, Object arg1); + + /** + * @see #getCurrentMetricValue(String) + */ + long getCurrentMetricValue(String format, Object arg1, Object arg2); + + /** + * @see #getCurrentMetricValue(String) + */ + long getCurrentMetricValue(String format, Object arg1, Object arg2, Object arg3); + + /** + * Gets the {@link ResolvedJavaMethod} associated with this {@linkplain DebugMethodMetrics}. + * + * @return the {@link ResolvedJavaMethod} of the current method metric + */ + ResolvedJavaMethod getMethod(); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugTimer.java 2016-12-07 13:48:59.419124430 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2012, 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.debug; + +import java.util.concurrent.TimeUnit; + +/** + * A timer for some activity of interest. A timer should be deployed using the try-with-resources + * pattern: + * + *
+ * try (TimerCloseable a = timer.start()) {
+ *     // the code to time
+ * }
+ * 
+ */ +public interface DebugTimer { + + /** + * Starts this timer if timing is {@linkplain Debug#isTimeEnabled() enabled} or this is an + * {@linkplain #isConditional() unconditional} timer. + * + * @return an object that must be closed once the activity has completed to add the elapsed time + * since this call to the total for this timer + */ + DebugCloseable start(); + + /** + * Sets a flag determining if this timer is only enabled if timing is + * {@link Debug#isTimeEnabled() enabled}. + */ + void setConditional(boolean flag); + + /** + * Determines if this timer is only enabled if timing is {@link Debug#isTimeEnabled() enabled}. + */ + boolean isConditional(); + + /** + * Gets the current value of this timer. + */ + long getCurrentValue(); + + /** + * Gets the time unit of this timer. + */ + TimeUnit getTimeUnit(); + + /** + * Gets the timer recording the amount time spent within a timed scope minus the time spent in + * any nested timed scopes. + * + * @return null if this timer does not support flat timing + */ + default DebugTimer getFlat() { + return null; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugValueFactory.java 2016-12-07 13:48:59.686136167 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, 2016, 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.debug; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * A factory for creating {@link DebugCounter}s, {@link DebugTimer}s, {@link DebugMemUseTracker}s + * and {@link DebugMethodMetrics}. + */ +public interface DebugValueFactory { + + DebugCounter createCounter(String name, boolean conditional); + + DebugTimer createTimer(String name, boolean conditional); + + DebugMemUseTracker createMemUseTracker(String name, boolean conditional); + + DebugMethodMetrics createMethodMetrics(ResolvedJavaMethod method); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugVerifyHandler.java 2016-12-07 13:48:59.951147816 -0800 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012, 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.debug; + +/** + * Performs some kind of verification on an object. + */ +public interface DebugVerifyHandler { + + /** + * Verifies that a given object satisfies some invariants. + * + * @param object object to verify + * @param message description of verification context + */ + void verify(Object object, String message); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DelegatingDebugConfig.java 2016-12-07 13:49:00.216159465 -0800 @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.debug; + +import java.io.PrintStream; +import java.util.Collection; +import java.util.EnumMap; +import java.util.Map; + +import org.graalvm.compiler.debug.internal.DebugScope; + +public class DelegatingDebugConfig implements DebugConfig { + + protected final DebugConfig delegate; + + /** + * The features of a {@link DelegatingDebugConfig} that can be force + * {@linkplain DelegatingDebugConfig#enable(Feature) enabled}/ + * {@linkplain DelegatingDebugConfig#disable(Feature) disabled} or + * {@linkplain DelegatingDebugConfig#delegate(Feature) delegated}. + */ + public enum Feature { + /** + * @see Debug#isLogEnabledForMethod() + */ + LOG_METHOD, + /** + * @see Debug#isDumpEnabledForMethod() + */ + DUMP_METHOD, + /** + * @see Debug#isVerifyEnabled() + */ + VERIFY, + /** + * @see Debug#isVerifyEnabledForMethod() + */ + VERIFY_METHOD, + /** + * @see Debug#isCountEnabled() + */ + COUNT, + /** + * @see Debug#isMethodMeterEnabled() + */ + METHOD_METRICS, + /** + * @see Debug#isMemUseTrackingEnabled() + */ + TRACK_MEM_USE, + /** + * @see Debug#isTimeEnabled() + */ + TIME, + /** + * @see DebugConfig#interceptException(Throwable) + */ + INTERCEPT + } + + private final Map featureState = new EnumMap<>(Feature.class); + + /** + * The debug levels of a {@link DelegatingDebugConfig} than can be + * {@linkplain DelegatingDebugConfig#override(Level, int) overridden} or + * {@linkplain DelegatingDebugConfig#delegate(Level) delegated}. + */ + public enum Level { + LOG, + DUMP + } + + private final Map levelState = new EnumMap<>(Level.class); + + /** + * Creates a config that delegates to the {@link DebugScope#getConfig() current config}. + */ + public DelegatingDebugConfig() { + this(DebugScope.getConfig()); + } + + /** + * Creates a config that delegates to a given config. + */ + public DelegatingDebugConfig(DebugConfig delegate) { + this.delegate = delegate; + } + + public DelegatingDebugConfig enable(Feature feature) { + featureState.put(feature, Boolean.TRUE); + return this; + } + + public DelegatingDebugConfig disable(Feature feature) { + featureState.put(feature, Boolean.FALSE); + return this; + } + + public DelegatingDebugConfig override(Level level, int newLevel) { + levelState.put(level, newLevel); + return this; + } + + public DelegatingDebugConfig delegate(Feature feature) { + featureState.put(feature, null); + return this; + } + + public DelegatingDebugConfig delegate(Level level) { + levelState.put(level, null); + return this; + } + + @Override + public int getLogLevel() { + Integer ls = levelState.get(Level.LOG); + if (ls == null) { + return delegate.getLogLevel(); + } + return ls.intValue(); + } + + @Override + public boolean isLogEnabledForMethod() { + Boolean fs = featureState.get(Feature.LOG_METHOD); + if (fs == null) { + return delegate.isLogEnabledForMethod(); + } + return fs.booleanValue(); + } + + @Override + public boolean isCountEnabled() { + Boolean fs = featureState.get(Feature.COUNT); + if (fs == null) { + return delegate.isCountEnabled(); + } + return fs.booleanValue(); + } + + @Override + public boolean isMemUseTrackingEnabled() { + Boolean fs = featureState.get(Feature.TRACK_MEM_USE); + if (fs == null) { + return delegate.isMemUseTrackingEnabled(); + } + return fs.booleanValue(); + } + + @Override + public int getDumpLevel() { + Integer ls = levelState.get(Level.DUMP); + if (ls == null) { + return delegate.getDumpLevel(); + } + return ls.intValue(); + } + + @Override + public boolean isDumpEnabledForMethod() { + Boolean fs = featureState.get(Feature.DUMP_METHOD); + if (fs == null) { + return delegate.isDumpEnabledForMethod(); + } + return fs.booleanValue(); + } + + @Override + public boolean isVerifyEnabled() { + Boolean fs = featureState.get(Feature.VERIFY); + if (fs == null) { + return delegate.isVerifyEnabled(); + } + return fs.booleanValue(); + } + + @Override + public boolean isVerifyEnabledForMethod() { + Boolean fs = featureState.get(Feature.VERIFY_METHOD); + if (fs == null) { + return delegate.isVerifyEnabledForMethod(); + } + return fs.booleanValue(); + } + + @Override + public boolean isTimeEnabled() { + Boolean fs = featureState.get(Feature.TIME); + if (fs == null) { + return delegate.isTimeEnabled(); + } + return fs.booleanValue(); + } + + @Override + public boolean isMethodMeterEnabled() { + Boolean fs = featureState.get(Feature.METHOD_METRICS); + if (fs == null) { + return delegate.isMethodMeterEnabled(); + } + return fs.booleanValue(); + } + + @Override + public RuntimeException interceptException(Throwable e) { + Boolean fs = featureState.get(Feature.INTERCEPT); + if (fs == null || fs) { + return delegate.interceptException(e); + } + return null; + } + + @Override + public Collection dumpHandlers() { + return delegate.dumpHandlers(); + } + + @Override + public Collection verifyHandlers() { + return delegate.verifyHandlers(); + } + + @Override + public PrintStream output() { + return delegate.output(); + } + + @Override + public void addToContext(Object o) { + delegate.addToContext(o); + } + + @Override + public void removeFromContext(Object o) { + delegate.removeFromContext(o); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Fingerprint.java 2016-12-07 13:49:00.483171202 -0800 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2015, 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.debug; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionValue; + +/** + * Facility for fingerprinting execution. + */ +public class Fingerprint implements AutoCloseable { + + public static class Options { + @Option(help = "Enables execution fingerprinting.")// + public static final OptionValue UseFingerprinting = new OptionValue<>(false); + + @Option(help = "Limit number of events shown in fingerprinting error message.")// + public static final OptionValue FingerprintErrorEventTailLength = new OptionValue<>(50); + + @Option(help = "Fingerprinting event at which to execute breakpointable code.")// + public static final OptionValue FingerprintingBreakpointEvent = new OptionValue<>(-1); + } + + /** + * Determines whether fingerprinting is enabled. + */ + public static final boolean ENABLED = Options.UseFingerprinting.getValue(); + + private static final ThreadLocal current = ENABLED ? new ThreadLocal<>() : null; + + private final List events; + private int index; + + /** + * Creates an object to record a fingerprint. + */ + public Fingerprint() { + events = new ArrayList<>(); + index = -1; + } + + /** + * Creates an object to verify execution matches a given fingerprint. + * + * @param toVerifyAgainst the fingerprint events to verify against + */ + public Fingerprint(List toVerifyAgainst) { + this.events = toVerifyAgainst; + index = 0; + } + + /** + * Creates an object to verify execution matches a given fingerprint. + * + * @param toVerifyAgainst the fingerprint to verify against + */ + public Fingerprint(Fingerprint toVerifyAgainst) { + this(toVerifyAgainst.events); + } + + public Collection getEvents() { + return Collections.unmodifiableCollection(events); + } + + /** + * Starts fingerprint recording or verification for the current thread. At most one fingerprint + * object can be active for any thread. + */ + public Fingerprint open() { + if (ENABLED) { + assert current.get() == null; + current.set(this); + return this; + } + return null; + } + + /** + * Finishes fingerprint recording or verification for the current thread. + */ + @Override + public void close() { + if (ENABLED) { + assert current.get() == this; + current.set(null); + } + } + + private static final int BREAKPOINT_EVENT = Options.FingerprintingBreakpointEvent.getValue(); + + /** + * Submits an execution event for the purpose of recording or verifying a fingerprint. This must + * only be called if {@link #ENABLED} is {@code true}. + */ + public static void submit(String format, Object... args) { + assert ENABLED : "fingerprinting must be enabled (-Dgraal." + Options.UseFingerprinting.getName() + "=true)"; + Fingerprint fingerprint = current.get(); + if (fingerprint != null) { + int eventId = fingerprint.nextEventId(); + if (eventId == BREAKPOINT_EVENT) { + // Set IDE breakpoint on the following line and set the relevant + // system property to debug a fingerprint verification error. + System.console(); + } + fingerprint.event(String.format(eventId + ": " + format, args)); + } + } + + private int nextEventId() { + return index == -1 ? events.size() : index; + } + + private static final int MAX_EVENT_TAIL_IN_ERROR_MESSAGE = Options.FingerprintErrorEventTailLength.getValue(); + + private String tail() { + int start = Math.max(index - MAX_EVENT_TAIL_IN_ERROR_MESSAGE, 0); + return events.subList(start, index).stream().collect(Collectors.joining(String.format("%n"))); + } + + private void event(String entry) { + if (index == -1) { + events.add(entry); + } else { + if (index > events.size()) { + throw new InternalError(String.format("%s%nOriginal fingerprint limit reached", tail())); + } + String l = events.get(index); + if (!l.equals(entry)) { + throw new InternalError(String.format("%s%nFingerprint differs at event %d%nexpected: %s%n actual: %s", tail(), index, l, entry)); + } + index++; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java 2016-12-07 13:49:00.748182850 -0800 @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2012, 2015, 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.debug; + +import java.io.PrintStream; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.meta.JavaMethod; + +public class GraalDebugConfig implements DebugConfig { + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean assertionsEnabled = false; + assert assertionsEnabled = true; + return assertionsEnabled; + } + + public static class Options { + // @formatter:off + @Option(help = "Pattern for scope(s) in which dumping is enabled (see DebugFilter and Debug.dump)", type = OptionType.Debug) + public static final OptionValue Dump = new OptionValue<>(null); + @Option(help = "Pattern for scope(s) in which counting is enabled (see DebugFilter and Debug.counter). " + + "An empty value enables all counters unconditionally.", type = OptionType.Debug) + public static final OptionValue Count = new OptionValue<>(null); + @Option(help = "Pattern for scope(s) in which verification is enabled (see DebugFilter and Debug.verify).", type = OptionType.Debug) + public static final OptionValue Verify = new OptionValue() { + @Override + protected String defaultValue() { + return assertionsEnabled() ? "" : null; + } + }; + @Option(help = "Pattern for scope(s) in which memory use tracking is enabled (see DebugFilter and Debug.counter). " + + "An empty value enables all memory use trackers unconditionally.", type = OptionType.Debug) + public static final OptionValue TrackMemUse = new OptionValue<>(null); + @Option(help = "Pattern for scope(s) in which timing is enabled (see DebugFilter and Debug.timer). " + + "An empty value enables all timers unconditionally.", type = OptionType.Debug) + public static final OptionValue Time = new OptionValue<>(null); + @Option(help = "Pattern for scope(s) in which logging is enabled (see DebugFilter and Debug.log)", type = OptionType.Debug) + public static final OptionValue Log = new OptionValue<>(null); + @Option(help = "Pattern for filtering debug scope output based on method context (see MethodFilter)", type = OptionType.Debug) + public static final OptionValue MethodFilter = new OptionValue<>(null); + @Option(help = "Only check MethodFilter against the root method in the context if true, otherwise check all methods", type = OptionType.Debug) + public static final OptionValue MethodFilterRootOnly = new OptionValue<>(false); + + @Option(help = "How to print counters and timing values:%n" + + "Name - aggregate by unqualified name%n" + + "Partial - aggregate by partially qualified name (e.g., A.B.C.D.Counter and X.Y.Z.D.Counter will be merged to D.Counter)%n" + + "Complete - aggregate by qualified name%n" + + "Thread - aggregate by qualified name and thread", type = OptionType.Debug) + public static final OptionValue DebugValueSummary = new OptionValue<>("Name"); + @Option(help = "Print counters and timers in a human readable form.", type = OptionType.Debug) + public static final OptionValue DebugValueHumanReadable = new OptionValue<>(true); + @Option(help = "Omit reporting 0-value counters", type = OptionType.Debug) + public static final OptionValue SuppressZeroDebugValues = new OptionValue<>(true); + @Option(help = "Only report debug values for maps which match the regular expression.", type = OptionType.Debug) + public static final OptionValue DebugValueThreadFilter = new OptionValue<>(null); + @Option(help = "Write debug values into a file instead of the terminal. " + + "If DebugValueSummary is Thread, the thread name will be prepended.", type = OptionType.Debug) + public static final OptionValue DebugValueFile = new OptionValue<>(null); + @Option(help = "Send Graal compiler IR to dump handlers on error", type = OptionType.Debug) + public static final OptionValue DumpOnError = new OptionValue<>(false); + @Option(help = "Intercept also bailout exceptions", type = OptionType.Debug) + public static final OptionValue InterceptBailout = new OptionValue<>(false); + @Option(help = "Enable more verbose log output when available", type = OptionType.Debug) + public static final OptionValue LogVerbose = new OptionValue<>(false); + + @Option(help = "The directory where various Graal dump files are written.") + public static final OptionValue DumpPath = new OptionValue<>("."); + + @Option(help = "Enable dumping to the C1Visualizer. Enabling this option implies PrintBackendCFG.", type = OptionType.Debug) + public static final OptionValue PrintCFG = new OptionValue<>(false); + @Option(help = "Enable dumping LIR, register allocation and code generation info to the C1Visualizer.", type = OptionType.Debug) + public static final OptionValue PrintBackendCFG = new OptionValue<>(true); + @Option(help = "Base filename when dumping C1Visualizer output to files.", type = OptionType.Debug) + public static final OptionValue PrintCFGFileName = new OptionValue<>("compilations"); + + @Option(help = "Output probabilities for fixed nodes during binary graph dumping", type = OptionType.Debug) + public static final OptionValue PrintGraphProbabilities = new OptionValue<>(false); + @Option(help = "Enable dumping to the IdealGraphVisualizer.", type = OptionType.Debug) + public static final OptionValue PrintIdealGraph = new OptionValue<>(true); + @Option(help = "Dump IdealGraphVisualizer output in binary format", type = OptionType.Debug) + public static final OptionValue PrintBinaryGraphs = new OptionValue<>(true); + @Option(help = "Print Ideal graphs as opposed to sending them over the network.", type = OptionType.Debug) + public static final OptionValue PrintIdealGraphFile = new OptionValue<>(false); + @Option(help = "Base filename when dumping Ideal graphs to files.", type = OptionType.Debug) + public static final OptionValue PrintIdealGraphFileName = new OptionValue<>("runtime-graphs"); + + @Option(help = "", type = OptionType.Debug) + public static final OptionValue PrintIdealGraphAddress = new OptionValue<>("127.0.0.1"); + @Option(help = "", type = OptionType.Debug) + public static final OptionValue PrintIdealGraphPort = new OptionValue<>(4444); + @Option(help = "", type = OptionType.Debug) + public static final OptionValue PrintBinaryGraphPort = new OptionValue<>(4445); + @Option(help = "", type = OptionType.Debug) + public static final OptionValue PrintIdealGraphSchedule = new OptionValue<>(false); + @Option(help = "Enable dumping Truffle ASTs to the IdealGraphVisualizer.", type = OptionType.Debug) + public static final OptionValue PrintTruffleTrees = new OptionValue<>(true); + + @Option(help = "Enable dumping canonical text from for graphs.", type = OptionType.Debug) + public static final OptionValue PrintCanonicalGraphStrings = new OptionValue<>(false); + @Option(help = "Base directory when dumping graphs strings to files.", type = OptionType.Debug) + public static final OptionValue PrintCanonicalGraphStringsDirectory = new OptionValue<>("graph-strings"); + @Option(help = "Choose format used when dumping canonical text for graphs: " + + "0 gives a scheduled graph (better for spotting changes involving the schedule)" + + "while 1 gives a CFG containing expressions rooted at fixed nodes (better for spotting small structure differences)", type = OptionType.Debug) + public static final OptionValue PrintCanonicalGraphStringFlavor = new OptionValue<>(0); + @Option(help = "Exclude virtual nodes when dumping canonical text for graphs.", type = OptionType.Debug) + public static final OptionValue CanonicalGraphStringsExcludeVirtuals = new OptionValue<>(true); + @Option(help = "Exclude virtual nodes when dumping canonical text for graphs.", type = OptionType.Debug) + public static final OptionValue CanonicalGraphStringsCheckConstants = new OptionValue<>(false); + @Option(help = "Attempts to remove object identity hashes when dumping canonical text for graphs.", type = OptionType.Debug) + public static final OptionValue CanonicalGraphStringsRemoveIdentities = new OptionValue<>(true); + + @Option(help = "Enable per method metrics that are collected across all compilations of a method." + + "Pattern for scope(s) in which method metering is enabled (see DebugFilter and Debug.metric).", type = OptionType.Debug) + public static final OptionValue MethodMeter = new OptionValue<>(null); + @Option(help = "If a global metric (DebugTimer, DebugCounter or DebugMemUseTracker) is enabled in the same scope as a method metric, " + + "use the global metric to update the method metric for the current compilation. " + + "This option enables the re-use of global metrics on per-compilation basis. " + + "Whenever a value is added to a global metric, the value is also added to a MethodMetric under the same name " + + "as the global metric. " + + "This option incurs a small but constant overhead due to the context method lookup at each metric update. " + + "Format to specify GlobalMetric interception:(Timers|Counters|MemUseTrackers)(,Timers|,Counters|,MemUseTrackers)*", type = OptionType.Debug) + public static final OptionValue GlobalMetricsInterceptedByMethodMetrics = new OptionValue<>(null); + @Option(help = "Force-enable debug code paths", type = OptionType.Debug) + public static final OptionValue ForceDebugEnable = new OptionValue<>(false); + @Option(help = "Clear the debug metrics after bootstrap.", type = OptionType.Debug) + public static final OptionValue ClearMetricsAfterBootstrap = new OptionValue<>(false); + @Option(help = "Do not compile anything on bootstrap but just initialize the compiler.", type = OptionType.Debug) + public static final OptionValue BootstrapInitializeOnly = new OptionValue<>(false); + // @formatter:on + } + + public static boolean isNotEmpty(OptionValue option) { + return option.getValue() != null && !option.getValue().isEmpty(); + } + + public static boolean areDebugScopePatternsEnabled() { + return Options.DumpOnError.getValue() || Options.Dump.getValue() != null || Options.Log.getValue() != null || areScopedGlobalMetricsEnabled(); + } + + public static boolean isGlobalMetricsInterceptedByMethodMetricsEnabled() { + return isNotEmpty(Options.GlobalMetricsInterceptedByMethodMetrics); + } + + /** + * Determines if any of {@link Options#Count}, {@link Options#Time} or + * {@link Options#TrackMemUse} has a non-null, non-empty value. + */ + public static boolean areScopedGlobalMetricsEnabled() { + return isNotEmpty(Options.Count) || isNotEmpty(Options.Time) || isNotEmpty(Options.TrackMemUse) || isNotEmpty(Options.MethodMeter); + } + + private final DebugFilter countFilter; + private final DebugFilter logFilter; + private final DebugFilter methodMetricsFilter; + private final DebugFilter trackMemUseFilter; + private final DebugFilter timerFilter; + private final DebugFilter dumpFilter; + private final DebugFilter verifyFilter; + private final MethodFilter[] methodFilter; + private final List dumpHandlers; + private final List verifyHandlers; + private final PrintStream output; + + // Use an identity set to handle context objects that don't support hashCode(). + private final Set extraFilters = Collections.newSetFromMap(new IdentityHashMap<>()); + + public GraalDebugConfig(String logFilter, String countFilter, String trackMemUseFilter, String timerFilter, String dumpFilter, String verifyFilter, String methodFilter, + String methodMetricsFilter, PrintStream output, List dumpHandlers, List verifyHandlers) { + this.logFilter = DebugFilter.parse(logFilter); + this.countFilter = DebugFilter.parse(countFilter); + this.trackMemUseFilter = DebugFilter.parse(trackMemUseFilter); + this.timerFilter = DebugFilter.parse(timerFilter); + this.dumpFilter = DebugFilter.parse(dumpFilter); + this.verifyFilter = DebugFilter.parse(verifyFilter); + this.methodMetricsFilter = DebugFilter.parse(methodMetricsFilter); + if (methodFilter == null || methodFilter.isEmpty()) { + this.methodFilter = null; + } else { + this.methodFilter = org.graalvm.compiler.debug.MethodFilter.parse(methodFilter); + } + + // Report the filters that have been configured so the user can verify it's what they expect + if (logFilter != null || countFilter != null || timerFilter != null || dumpFilter != null || methodFilter != null) { + // TTY.println(Thread.currentThread().getName() + ": " + toString()); + } + this.dumpHandlers = dumpHandlers; + this.verifyHandlers = verifyHandlers; + this.output = output; + } + + @Override + public int getLogLevel() { + return getLevel(logFilter); + } + + @Override + public boolean isLogEnabledForMethod() { + return isEnabledForMethod(logFilter); + } + + @Override + public boolean isCountEnabled() { + return isEnabled(countFilter); + } + + @Override + public boolean isMemUseTrackingEnabled() { + return isEnabled(trackMemUseFilter); + } + + @Override + public int getDumpLevel() { + return getLevel(dumpFilter); + } + + @Override + public boolean isDumpEnabledForMethod() { + return isEnabledForMethod(dumpFilter); + } + + @Override + public boolean isVerifyEnabled() { + return isEnabled(verifyFilter); + } + + @Override + public boolean isVerifyEnabledForMethod() { + return isEnabledForMethod(verifyFilter); + } + + @Override + public boolean isMethodMeterEnabled() { + return isEnabled(methodMetricsFilter); + } + + @Override + public boolean isTimeEnabled() { + return isEnabled(timerFilter); + } + + @Override + public PrintStream output() { + return output; + } + + private boolean isEnabled(DebugFilter filter) { + return getLevel(filter) > 0; + } + + private int getLevel(DebugFilter filter) { + int level; + if (filter == null) { + level = 0; + } else { + level = filter.matchLevel(Debug.currentScope()); + } + if (level > 0 && !checkMethodFilter()) { + level = 0; + } + return level; + } + + private boolean isEnabledForMethod(DebugFilter filter) { + return filter != null && checkMethodFilter(); + } + + /** + * Extracts a {@link JavaMethod} from an opaque debug context. + * + * @return the {@link JavaMethod} represented by {@code context} or null + */ + public static JavaMethod asJavaMethod(Object context) { + if (context instanceof JavaMethodContext) { + return ((JavaMethodContext) context).asJavaMethod(); + } + if (context instanceof JavaMethod) { + return (JavaMethod) context; + } + return null; + } + + private boolean checkMethodFilter() { + if (methodFilter == null && extraFilters.isEmpty()) { + return true; + } else { + JavaMethod lastMethod = null; + for (Object o : Debug.context()) { + if (extraFilters.contains(o)) { + return true; + } else if (methodFilter != null) { + JavaMethod method = asJavaMethod(o); + if (method != null) { + if (!Options.MethodFilterRootOnly.getValue()) { + if (org.graalvm.compiler.debug.MethodFilter.matches(methodFilter, method)) { + return true; + } + } else { + /* + * The context values operate as a stack so if we want MethodFilter to + * only apply to the root method we have to check only the last method + * seen. + */ + lastMethod = method; + } + } + } + } + if (lastMethod != null && org.graalvm.compiler.debug.MethodFilter.matches(methodFilter, lastMethod)) { + return true; + } + return false; + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Debug config:"); + add(sb, "Log", logFilter); + add(sb, "Count", countFilter); + add(sb, "MethodMeter", methodMetricsFilter); + add(sb, "Time", timerFilter); + add(sb, "Dump", dumpFilter); + add(sb, "MethodFilter", methodFilter); + return sb.toString(); + } + + private static void add(StringBuilder sb, String name, Object filter) { + if (filter != null) { + sb.append(' '); + sb.append(name); + sb.append('='); + if (filter instanceof Object[]) { + sb.append(Arrays.toString((Object[]) filter)); + } else { + sb.append(String.valueOf(filter)); + } + } + } + + @Override + public RuntimeException interceptException(Throwable e) { + if (e instanceof BailoutException && !Options.InterceptBailout.getValue()) { + return null; + } + Debug.setConfig(Debug.fixedConfig(Debug.BASIC_LOG_LEVEL, Debug.BASIC_LOG_LEVEL, false, false, false, false, false, dumpHandlers, verifyHandlers, output)); + Debug.log("Exception occurred in scope: %s", Debug.currentScope()); + Map firstSeen = new IdentityHashMap<>(); + for (Object o : Debug.context()) { + // Only dump a context object once. + if (!firstSeen.containsKey(o)) { + firstSeen.put(o, o); + if (Options.DumpOnError.getValue()) { + Debug.dump(Debug.BASIC_LOG_LEVEL, o, "Exception: %s", e); + } else { + Debug.log("Context obj %s", o); + } + } + } + return null; + } + + @Override + public Collection dumpHandlers() { + return dumpHandlers; + } + + @Override + public Collection verifyHandlers() { + return verifyHandlers; + } + + @Override + public void addToContext(Object o) { + extraFilters.add(o); + } + + @Override + public void removeFromContext(Object o) { + extraFilters.remove(o); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java 2016-12-07 13:49:01.014194543 -0800 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2011, 2014, 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.debug; + +import java.util.ArrayList; +import java.util.Locale; + +/** + * Indicates a condition that should never occur during normal operation. + */ +public class GraalError extends Error { + + private static final long serialVersionUID = 531632331813456233L; + private final ArrayList context = new ArrayList<>(); + + public static RuntimeException unimplemented() { + throw new GraalError("unimplemented"); + } + + public static RuntimeException unimplemented(String msg) { + throw new GraalError("unimplemented: %s", msg); + } + + public static RuntimeException shouldNotReachHere() { + throw new GraalError("should not reach here"); + } + + public static RuntimeException shouldNotReachHere(String msg) { + throw new GraalError("should not reach here: %s", msg); + } + + public static RuntimeException shouldNotReachHere(Throwable cause) { + throw new GraalError(cause); + } + + /** + * Checks a given condition and throws a {@link GraalError} if it is false. Guarantees are + * stronger than assertions in that they are always checked. Error messages for guarantee + * violations should clearly indicate the nature of the problem as well as a suggested solution + * if possible. + * + * @param condition the condition to check + * @param msg the message that will be associated with the error, in + * {@link String#format(String, Object...)} syntax + * @param args arguments to the format string + */ + public static void guarantee(boolean condition, String msg, Object... args) { + if (!condition) { + throw new GraalError("failed guarantee: " + msg, args); + } + } + + /** + * This constructor creates a {@link GraalError} with a given message. + * + * @param msg the message that will be associated with the error + */ + public GraalError(String msg) { + super(msg); + } + + /** + * This constructor creates a {@link GraalError} with a message assembled via + * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to + * always generate the same output. + * + * @param msg the message that will be associated with the error, in String.format syntax + * @param args parameters to String.format - parameters that implement {@link Iterable} will be + * expanded into a [x, x, ...] representation. + */ + public GraalError(String msg, Object... args) { + super(format(msg, args)); + } + + /** + * This constructor creates a {@link GraalError} for a given causing Throwable instance. + * + * @param cause the original exception that contains additional information on this error + */ + public GraalError(Throwable cause) { + super(cause); + } + + /** + * This constructor creates a {@link GraalError} and adds all the + * {@linkplain #addContext(String) context} of another {@link GraalError}. + * + * @param e the original {@link GraalError} + */ + public GraalError(GraalError e) { + super(e); + context.addAll(e.context); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append(super.toString()); + for (String s : context) { + str.append("\n\tat ").append(s); + } + return str.toString(); + } + + private static String format(String msg, Object... args) { + if (args != null) { + // expand Iterable parameters into a list representation + for (int i = 0; i < args.length; i++) { + if (args[i] instanceof Iterable) { + ArrayList list = new ArrayList<>(); + for (Object o : (Iterable) args[i]) { + list.add(o); + } + args[i] = list.toString(); + } + } + } + return String.format(Locale.ENGLISH, msg, args); + } + + public GraalError addContext(String newContext) { + this.context.add(newContext); + return this; + } + + public GraalError addContext(String name, Object obj) { + return addContext(format("%s: %s", name, obj)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Indent.java 2016-12-07 13:49:01.278206148 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.debug; + +/** + * Object used to close a debug {@link Debug#indent() indentation} scope. + *

+ * Example usage: + * + *

+ *
+ *      try (Indent i1 = Debug.logAndIndent("header message")) {
+ *          ...
+ *          Debug.log("message");
+ *          ...
+ *          try (Indent i2 = Debug.logAndIndent(sub-header message")) {
+ *              ...
+ *              Debug.log("inner message");
+ *              ...
+ *          }
+ *      }
+ *
+ * 
+ */ +public interface Indent extends AutoCloseable { + + /** + * Closes the current indentation scope. + */ + @Override + void close(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/JavaMethodContext.java 2016-12-07 13:49:01.545217885 -0800 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015, 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.debug; + +import jdk.vm.ci.meta.JavaMethod; + +/** + * Interface for objects used in Debug {@linkplain Debug#context() context} that can provide a + * {@link JavaMethod}. + */ +public interface JavaMethodContext { + JavaMethod asJavaMethod(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/LogStream.java 2016-12-07 13:49:01.809229490 -0800 @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2009, 2011, 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.debug; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; + +/** + * A utility for printing compiler debug and informational output to an output stream. + * + * A {@link LogStream} instance maintains an internal buffer that is flushed to the underlying + * output stream every time one of the {@code println} methods is invoked, or a newline character ( + * {@code '\n'}) is written. + * + * All of the {@code print} and {@code println} methods return the {code LogStream} instance on + * which they were invoked. This allows chaining of these calls to mitigate use of String + * concatenation by the caller. + * + * A {@code LogStream} maintains a current {@linkplain #indentationLevel() indentation} level. Each + * line of output written to this stream has {@code n} spaces prefixed to it where {@code n} is the + * value that would be returned by {@link #indentationLevel()} when the first character of a new + * line is written. + * + * A {@code LogStream} maintains a current {@linkplain #position() position} for the current line + * being written. This position can be advanced to a specified position by + * {@linkplain #fillTo(int, char) filling} this stream with a given character. + */ +public class LogStream { + + /** + * Null output stream that simply swallows any output sent to it. + */ + public static final LogStream SINK = new LogStream(); + + private static final PrintStream SINK_PS = new PrintStream(new OutputStream() { + + @Override + public void write(int b) throws IOException { + } + }); + + private LogStream() { + this.ps = null; + this.lineBuffer = null; + } + + /** + * The output stream to which this log stream writes. + */ + private final PrintStream ps; + + private final StringBuilder lineBuffer; + private int indentationLevel; + private char indentation = ' '; + private boolean indentationDisabled; + + public final PrintStream out() { + if (ps == null) { + return SINK_PS; + } + return ps; + } + + /** + * The system dependent line separator. + */ + public static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + /** + * Creates a new log stream. + * + * @param os the underlying output stream to which prints are sent + */ + public LogStream(OutputStream os) { + ps = os instanceof PrintStream ? (PrintStream) os : new PrintStream(os); + lineBuffer = new StringBuilder(100); + } + + /** + * Creates a new log stream that shares the same {@linkplain #ps output stream} as a given + * {@link LogStream}. + * + * @param log a LogStream whose output stream is shared with this one + */ + public LogStream(LogStream log) { + ps = log.ps; + lineBuffer = new StringBuilder(100); + } + + /** + * Prepends {@link #indentation} to the current output line until its write position is equal to + * the current {@linkplain #indentationLevel()} level. + */ + private void indent() { + if (ps != null) { + if (!indentationDisabled && indentationLevel != 0) { + while (lineBuffer.length() < indentationLevel) { + lineBuffer.append(indentation); + } + } + } + } + + private LogStream flushLine(boolean withNewline) { + if (ps != null) { + if (withNewline) { + lineBuffer.append(LINE_SEPARATOR); + } + ps.print(lineBuffer.toString()); + ps.flush(); + lineBuffer.setLength(0); + } + return this; + } + + /** + * Flushes the stream. This is done by terminating the current line if it is not at position 0 + * and then flushing the underlying output stream. + */ + public void flush() { + if (ps != null) { + if (lineBuffer.length() != 0) { + flushLine(false); + } + ps.flush(); + } + } + + /** + * Gets the current column position of this log stream. + * + * @return the current column position of this log stream + */ + public int position() { + return lineBuffer == null ? 0 : lineBuffer.length(); + + } + + /** + * Gets the current indentation level for this log stream. + * + * @return the current indentation level for this log stream. + */ + public int indentationLevel() { + return indentationLevel; + } + + /** + * Adjusts the current indentation level of this log stream. + * + * @param delta + */ + public void adjustIndentation(int delta) { + if (delta < 0) { + indentationLevel = Math.max(0, indentationLevel + delta); + } else { + indentationLevel += delta; + } + } + + /** + * Gets the current indentation character of this log stream. + */ + public char indentation() { + return indentation; + } + + public void disableIndentation() { + indentationDisabled = true; + } + + public void enableIndentation() { + indentationDisabled = false; + } + + /** + * Sets the character used for indentation. + */ + public void setIndentation(char c) { + indentation = c; + } + + /** + * Advances this stream's {@linkplain #position() position} to a given position by repeatedly + * appending a given character as necessary. + * + * @param position the position to which this stream's position will be advanced + * @param filler the character used to pad the stream + */ + public LogStream fillTo(int position, char filler) { + if (ps != null) { + indent(); + while (lineBuffer.length() < position) { + lineBuffer.append(filler); + } + } + return this; + } + + /** + * Writes a boolean value to this stream as {@code "true"} or {@code "false"}. + * + * @param b the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(boolean b) { + if (ps != null) { + indent(); + lineBuffer.append(b); + } + return this; + } + + /** + * Writes a boolean value to this stream followed by a {@linkplain #LINE_SEPARATOR line + * separator}. + * + * @param b the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(boolean b) { + if (ps != null) { + indent(); + lineBuffer.append(b); + return flushLine(true); + } + return this; + } + + /** + * Writes a character value to this stream. + * + * @param c the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(char c) { + if (ps != null) { + indent(); + lineBuffer.append(c); + if (c == '\n') { + if (lineBuffer.indexOf(LINE_SEPARATOR, lineBuffer.length() - LINE_SEPARATOR.length()) != -1) { + flushLine(false); + } + } + } + return this; + } + + /** + * Writes a character value to this stream followed by a {@linkplain #LINE_SEPARATOR line + * separator}. + * + * @param c the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(char c) { + if (ps != null) { + indent(); + lineBuffer.append(c); + flushLine(true); + } + return this; + } + + /** + * Prints an int value. + * + * @param i the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(int i) { + if (ps != null) { + indent(); + lineBuffer.append(i); + } + return this; + } + + /** + * Writes an int value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param i the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(int i) { + if (ps != null) { + indent(); + lineBuffer.append(i); + return flushLine(true); + } + return this; + } + + /** + * Writes a float value to this stream. + * + * @param f the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(float f) { + if (ps != null) { + indent(); + lineBuffer.append(f); + } + return this; + } + + /** + * Writes a float value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator} + * . + * + * @param f the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(float f) { + if (ps != null) { + indent(); + lineBuffer.append(f); + return flushLine(true); + } + return this; + } + + /** + * Writes a long value to this stream. + * + * @param l the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(long l) { + if (ps != null) { + indent(); + lineBuffer.append(l); + } + return this; + } + + /** + * Writes a long value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param l the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(long l) { + if (ps != null) { + indent(); + lineBuffer.append(l); + return flushLine(true); + } + return this; + } + + /** + * Writes a double value to this stream. + * + * @param d the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(double d) { + if (ps != null) { + indent(); + lineBuffer.append(d); + } + return this; + } + + /** + * Writes a double value to this stream followed by a {@linkplain #LINE_SEPARATOR line + * separator}. + * + * @param d the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(double d) { + if (ps != null) { + indent(); + lineBuffer.append(d); + return flushLine(true); + } + return this; + } + + /** + * Writes a {@code String} value to this stream. This method ensures that the + * {@linkplain #position() position} of this stream is updated correctly with respect to any + * {@linkplain #LINE_SEPARATOR line separators} present in {@code s}. + * + * @param s the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(String s) { + if (ps != null) { + if (s == null) { + indent(); + lineBuffer.append(s); + return this; + } + + int index = 0; + int next = s.indexOf(LINE_SEPARATOR, index); + while (index < s.length()) { + indent(); + if (next > index || next == 0) { + lineBuffer.append(s.substring(index, next)); + flushLine(true); + index = next + LINE_SEPARATOR.length(); + next = s.indexOf(LINE_SEPARATOR, index); + } else { + lineBuffer.append(s.substring(index)); + break; + } + } + } + return this; + } + + /** + * Writes a {@code String} value to this stream followed by a {@linkplain #LINE_SEPARATOR line + * separator}. + * + * @param s the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(String s) { + if (ps != null) { + print(s); + flushLine(true); + } + return this; + } + + /** + * Writes a formatted string to this stream. + * + * @param format a format string as described in {@link String#format(String, Object...)} + * @param args the arguments to be formatted + * @return this {@link LogStream} instance + */ + public LogStream printf(String format, Object... args) { + if (ps != null) { + print(String.format(format, args)); + } + return this; + } + + /** + * Writes a {@linkplain #LINE_SEPARATOR line separator} to this stream. + * + * @return this {@code LogStream} instance + */ + public LogStream println() { + if (ps != null) { + indent(); + flushLine(true); + } + return this; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Management.java 2016-12-07 13:49:02.075241183 -0800 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2015, 2015, 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.debug; + +import static java.lang.Thread.currentThread; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; + +import javax.management.ObjectName; + +public class Management { + + private static final com.sun.management.ThreadMXBean threadMXBean = Management.initThreadMXBean(); + + /** + * The amount of memory allocated by + * {@link com.sun.management.ThreadMXBean#getThreadAllocatedBytes(long)} itself. + */ + private static final long threadMXBeanOverhead = -getCurrentThreadAllocatedBytes() + getCurrentThreadAllocatedBytes(); + + public static long getCurrentThreadAllocatedBytes() { + return threadMXBean.getThreadAllocatedBytes(currentThread().getId()) - threadMXBeanOverhead; + } + + private static com.sun.management.ThreadMXBean initThreadMXBean() { + try { + return (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean(); + } catch (Error err) { + return new UnimplementedBean(); + } + } + + public static ThreadMXBean getThreadMXBean() { + return threadMXBean; + } + + private static class UnimplementedBean implements ThreadMXBean, com.sun.management.ThreadMXBean { + + @Override + public ObjectName getObjectName() { + return null; + } + + @Override + public long getThreadAllocatedBytes(long arg0) { + return 0; + } + + @Override + public long[] getThreadAllocatedBytes(long[] arg0) { + return null; + } + + @Override + public long[] getThreadCpuTime(long[] arg0) { + return null; + } + + @Override + public long[] getThreadUserTime(long[] arg0) { + return null; + } + + @Override + public boolean isThreadAllocatedMemoryEnabled() { + return false; + } + + @Override + public boolean isThreadAllocatedMemorySupported() { + return false; + } + + @Override + public void setThreadAllocatedMemoryEnabled(boolean arg0) { + } + + @Override + public int getThreadCount() { + return 0; + } + + @Override + public int getPeakThreadCount() { + return 0; + } + + @Override + public long getTotalStartedThreadCount() { + return 0; + } + + @Override + public int getDaemonThreadCount() { + return 0; + } + + @Override + public long[] getAllThreadIds() { + return null; + } + + @Override + public ThreadInfo getThreadInfo(long id) { + return null; + } + + @Override + public ThreadInfo[] getThreadInfo(long[] ids) { + return null; + } + + @Override + public ThreadInfo getThreadInfo(long id, int maxDepth) { + return null; + } + + @Override + public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth) { + return null; + } + + @Override + public boolean isThreadContentionMonitoringSupported() { + return false; + } + + @Override + public boolean isThreadContentionMonitoringEnabled() { + return false; + } + + @Override + public void setThreadContentionMonitoringEnabled(boolean enable) { + } + + @Override + public long getCurrentThreadCpuTime() { + return 0; + } + + @Override + public long getCurrentThreadUserTime() { + return 0; + } + + @Override + public long getThreadCpuTime(long id) { + return 0; + } + + @Override + public long getThreadUserTime(long id) { + return 0; + } + + @Override + public boolean isThreadCpuTimeSupported() { + return false; + } + + @Override + public boolean isCurrentThreadCpuTimeSupported() { + return false; + } + + @Override + public boolean isThreadCpuTimeEnabled() { + return false; + } + + @Override + public void setThreadCpuTimeEnabled(boolean enable) { + } + + @Override + public long[] findMonitorDeadlockedThreads() { + return null; + } + + @Override + public void resetPeakThreadCount() { + } + + @Override + public long[] findDeadlockedThreads() { + return null; + } + + @Override + public boolean isObjectMonitorUsageSupported() { + return false; + } + + @Override + public boolean isSynchronizerUsageSupported() { + return false; + } + + @Override + public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers) { + return null; + } + + @Override + public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers) { + return null; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MethodFilter.java 2016-12-07 13:49:02.339252788 -0800 @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2012, 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.debug; + +import java.util.Arrays; +import java.util.regex.Pattern; + +import jdk.vm.ci.meta.JavaMethod; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.Signature; + +/** + * This class implements a method filter that can filter based on class name, method name and + * parameters. The syntax for the source pattern that is passed to the constructor is as follows: + * + *
+ * SourcePatterns = SourcePattern ["," SourcePatterns] .
+ * SourcePattern = [ Class "." ] method [ "(" [ Parameter { ";" Parameter } ] ")" ] .
+ * Parameter = Class | "int" | "long" | "float" | "double" | "short" | "char" | "boolean" .
+ * Class = { package "." } class .
+ * 
+ * + * + * Glob pattern matching (*, ?) is allowed in all parts of the source pattern. Examples for valid + * filters are: + * + *
    + *
  • + * + *
    + * visit(Argument;BlockScope)
    + * 
    + * + * Matches all methods named "visit", with the first parameter of type "Argument", and the second + * parameter of type "BlockScope". The packages of the parameter types are irrelevant.
  • + *
  • + * + *
    + * arraycopy(Object;;;;)
    + * 
    + * + * Matches all methods named "arraycopy", with the first parameter of type "Object", and four more + * parameters of any type. The packages of the parameter types are irrelevant.
  • + *
  • + * + *
    + * org.graalvm.compiler.core.graph.PostOrderNodeIterator.*
    + * 
    + * + * Matches all methods in the class "org.graalvm.compiler.core.graph.PostOrderNodeIterator".
  • + *
  • + * + *
    + * *
    + * 
    + * + * Matches all methods in all classes
  • + *
  • + * + *
    + * org.graalvm.compiler.core.graph.*.visit
    + * 
    + * + * Matches all methods named "visit" in classes in the package "org.graalvm.compiler.core.graph". + *
  • + * + *
    + * arraycopy,toString
    + * 
    + * + * Matches all methods named "arraycopy" or "toString", meaning that ',' acts as an or + * operator.
  • + *
+ */ +public class MethodFilter { + + private final Pattern clazz; + private final Pattern methodName; + private final Pattern[] signature; + + /** + * Parses a string containing list of comma separated filter patterns into an array of + * {@link MethodFilter}s. + */ + public static MethodFilter[] parse(String commaSeparatedPatterns) { + String[] filters = commaSeparatedPatterns.split(","); + MethodFilter[] methodFilters = new MethodFilter[filters.length]; + for (int i = 0; i < filters.length; i++) { + methodFilters[i] = new MethodFilter(filters[i]); + } + return methodFilters; + } + + /** + * Determines if a given method is matched by a given array of filters. + */ + public static boolean matches(MethodFilter[] filters, JavaMethod method) { + for (MethodFilter filter : filters) { + if (filter.matches(method)) { + return true; + } + } + return false; + } + + /** + * Determines if a given class name is matched by a given array of filters. + */ + public static boolean matchesClassName(MethodFilter[] filters, String className) { + for (MethodFilter filter : filters) { + if (filter.matchesClassName(className)) { + return true; + } + } + return false; + } + + public MethodFilter(String sourcePattern) { + String pattern = sourcePattern.trim(); + + // extract parameter part + int pos = pattern.indexOf('('); + if (pos != -1) { + if (pattern.charAt(pattern.length() - 1) != ')') { + throw new IllegalArgumentException("missing ')' at end of method filter pattern: " + pattern); + } + String[] signatureClasses = pattern.substring(pos + 1, pattern.length() - 1).split(";", -1); + signature = new Pattern[signatureClasses.length]; + for (int i = 0; i < signatureClasses.length; i++) { + signature[i] = createClassGlobPattern(signatureClasses[i].trim()); + } + pattern = pattern.substring(0, pos); + } else { + signature = null; + } + + // If there is at least one "." then everything before the last "." is the class name. + // Otherwise, the pattern contains only the method name. + pos = pattern.lastIndexOf('.'); + if (pos != -1) { + clazz = createClassGlobPattern(pattern.substring(0, pos)); + methodName = Pattern.compile(createGlobString(pattern.substring(pos + 1))); + } else { + clazz = null; + methodName = Pattern.compile(createGlobString(pattern)); + } + } + + public static String createGlobString(String pattern) { + return Pattern.quote(pattern).replace("?", "\\E.\\Q").replace("*", "\\E.*\\Q"); + } + + private static Pattern createClassGlobPattern(String pattern) { + if (pattern.length() == 0) { + return null; + } else if (pattern.contains(".")) { + return Pattern.compile(createGlobString(pattern)); + } else { + return Pattern.compile("([^\\.\\$]*[\\.\\$])*" + createGlobString(pattern)); + } + } + + public boolean hasSignature() { + return signature != null; + } + + /** + * Determines if the class part of this filter matches a given class name. + */ + public boolean matchesClassName(String className) { + return clazz == null || clazz.matcher(className).matches(); + } + + public boolean matches(JavaMethod o) { + // check method name first, since MetaUtil.toJavaName is expensive + if (methodName != null && !methodName.matcher(o.getName()).matches()) { + return false; + } + if (clazz != null && !clazz.matcher(o.getDeclaringClass().toJavaName()).matches()) { + return false; + } + return matchesSignature(o.getSignature()); + } + + private boolean matchesSignature(Signature sig) { + if (signature == null) { + return true; + } + if (sig.getParameterCount(false) != signature.length) { + return false; + } + for (int i = 0; i < signature.length; i++) { + JavaType type = sig.getParameterType(i, null); + String javaName = type.toJavaName(); + if (signature[i] != null && !signature[i].matcher(javaName).matches()) { + return false; + } + } + return true; + } + + public boolean matches(String javaClassName, String name, Signature sig) { + assert sig != null || signature == null; + // check method name first, since MetaUtil.toJavaName is expensive + if (methodName != null && !methodName.matcher(name).matches()) { + return false; + } + if (clazz != null && !clazz.matcher(javaClassName).matches()) { + return false; + } + return matchesSignature(sig); + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder("MethodFilter["); + String sep = ""; + if (clazz != null) { + buf.append(sep).append("clazz=").append(clazz); + sep = ", "; + } + if (methodName != null) { + buf.append(sep).append("methodName=").append(methodName); + sep = ", "; + } + if (signature != null) { + buf.append(sep).append("signature=").append(Arrays.toString(signature)); + sep = ", "; + } + return buf.append("]").toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TTY.java 2016-12-07 13:49:02.605264480 -0800 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2009, 2011, 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.debug; + +import java.io.PrintStream; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import org.graalvm.compiler.serviceprovider.GraalServices; + +/** + * A collection of static methods for printing debug and informational output to a global + * {@link LogStream}. The output can be (temporarily) suppressed per thread through use of a + * {@linkplain Filter filter}. + */ +public class TTY { + + /** + * Support for thread-local suppression of {@link TTY}. + */ + public static class Filter { + + private LogStream previous; + private final Thread thread = Thread.currentThread(); + + /** + * Creates an object that will suppress {@link TTY} for the current thread if the given + * filter does not match the given object. To revert the suppression state to how it was + * before this call, the {@link #remove()} method must be called on the suppression object. + * + * @param filter the pattern for matching. If {@code null}, then the match is successful. If + * it starts with "~", then a regular expression + * {@linkplain Pattern#matches(String, CharSequence) match} is performed where + * the regular expression is specified by {@code filter} without the "~" prefix. + * Otherwise, a simple {@linkplain String#contains(CharSequence) substring} match + * is performed where {@code filter} is the substring used. + * @param object an object whose {@linkplain Object#toString() string} value is matched + * against {@code filter} + */ + public Filter(String filter, Object object) { + boolean suppressed = false; + if (filter != null) { + String input = object.toString(); + if (filter.startsWith("~")) { + suppressed = !Pattern.matches(filter.substring(1), input); + } else { + suppressed = !input.contains(filter); + } + if (suppressed) { + previous = out(); + log.set(LogStream.SINK); + } + } + } + + /** + * Creates an object that will suppress {@link TTY} for the current thread. To revert the + * suppression state to how it was before this call, the {@link #remove()} method must be + * called on this filter object. + */ + public Filter() { + previous = out(); + log.set(LogStream.SINK); + } + + /** + * Reverts the suppression state of {@link TTY} to how it was before this object was + * constructed. + */ + public void remove() { + assert thread == Thread.currentThread(); + if (previous != null) { + log.set(previous); + } + } + } + + /** + * The {@link PrintStream} to which all non-suppressed output from {@link TTY} is written. + */ + public static final PrintStream out; + static { + TTYStreamProvider p = GraalServices.loadSingle(TTYStreamProvider.class, false); + out = p == null ? System.out : p.getStream(); + } + + private static final ThreadLocal log = new ThreadLocal() { + + @Override + protected LogStream initialValue() { + return new LogStream(out); + } + }; + + public static boolean isSuppressed() { + return log.get() == LogStream.SINK; + } + + /** + * Gets the thread-local log stream to which the static methods of this class send their output. + * This will either be a global log stream or the global {@linkplain LogStream#SINK sink} + * depending on whether any suppression {@linkplain Filter filters} are in effect for the + * current thread. + */ + public static LogStream out() { + return log.get(); + } + + /** + * @see LogStream#print(String) + */ + public static void print(String s) { + out().print(s); + } + + /** + * @see LogStream#print(int) + */ + public static void print(int i) { + out().print(i); + } + + /** + * @see LogStream#print(long) + */ + public static void print(long i) { + out().print(i); + } + + /** + * @see LogStream#print(char) + */ + public static void print(char c) { + out().print(c); + } + + /** + * @see LogStream#print(boolean) + */ + public static void print(boolean b) { + out().print(b); + } + + /** + * @see LogStream#print(double) + */ + public static void print(double d) { + out().print(d); + } + + /** + * @see LogStream#print(float) + */ + public static void print(float f) { + out().print(f); + } + + /** + * @see LogStream#println(String) + */ + public static void println(String s) { + out().println(s); + } + + /** + * @see LogStream#println() + */ + public static void println() { + out().println(); + } + + /** + * @see LogStream#println(int) + */ + public static void println(int i) { + out().println(i); + } + + /** + * @see LogStream#println(long) + */ + public static void println(long l) { + out().println(l); + } + + /** + * @see LogStream#println(char) + */ + public static void println(char c) { + out().println(c); + } + + /** + * @see LogStream#println(boolean) + */ + public static void println(boolean b) { + out().println(b); + } + + /** + * @see LogStream#println(double) + */ + public static void println(double d) { + out().println(d); + } + + /** + * @see LogStream#println(float) + */ + public static void println(float f) { + out().println(f); + } + + public static void printf(String format, Object... args) { + out().printf(format, args); + } + + public static void println(String format, Object... args) { + out().printf(format + "%n", args); + } + + public static void fillTo(int i) { + out().fillTo(i, ' '); + } + + public static void printFields(Class javaClass) { + final String className = javaClass.getSimpleName(); + TTY.println(className + " {"); + for (final Field field : javaClass.getFields()) { + printField(field, false); + } + TTY.println("}"); + } + + public static void printField(final Field field, boolean tabbed) { + final String fieldName = String.format("%35s", field.getName()); + try { + String prefix = tabbed ? "" : " " + fieldName + " = "; + String postfix = tabbed ? "\t" : "\n"; + if (field.getType() == int.class) { + TTY.print(prefix + field.getInt(null) + postfix); + } else if (field.getType() == boolean.class) { + TTY.print(prefix + field.getBoolean(null) + postfix); + } else if (field.getType() == float.class) { + TTY.print(prefix + field.getFloat(null) + postfix); + } else if (field.getType() == String.class) { + TTY.print(prefix + field.get(null) + postfix); + } else if (field.getType() == Map.class) { + Map m = (Map) field.get(null); + TTY.print(prefix + printMap(m) + postfix); + } else { + TTY.print(prefix + field.get(null) + postfix); + } + } catch (IllegalAccessException e) { + // do nothing. + } + } + + private static String printMap(Map m) { + StringBuilder sb = new StringBuilder(); + + List keys = new ArrayList<>(); + for (Object key : m.keySet()) { + keys.add((String) key); + } + Collections.sort(keys); + + for (String key : keys) { + sb.append(key); + sb.append("\t"); + sb.append(m.get(key)); + sb.append("\n"); + } + + return sb.toString(); + } + + public static void flush() { + out().flush(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TTYStreamProvider.java 2016-12-07 13:49:02.871276173 -0800 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, 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.debug; + +import java.io.PrintStream; + +/** + * Provides a {@link PrintStream} that writes to the underlying log stream of the VM. + */ +public interface TTYStreamProvider { + PrintStream getStream(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimeSource.java 2016-12-07 13:49:03.135287778 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 2016, 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.debug; + +import java.lang.management.ThreadMXBean; + +/** + * A consistent source of timing data that should be used by all facilities in the debug package. + */ +public class TimeSource { + private static final boolean USING_BEAN; + private static final ThreadMXBean threadMXBean; + + static { + threadMXBean = Management.getThreadMXBean(); + if (threadMXBean.isThreadCpuTimeSupported()) { + USING_BEAN = true; + } else { + USING_BEAN = false; + } + } + + /** + * Gets the current time of this thread in nanoseconds from the most accurate timer available on + * the system. The returned value will be the current time in nanoseconds precision but not + * necessarily nanoseconds accuracy. + *

+ * The intended use case of this method is to measure the time a certain action takes by making + * successive calls to it. It should not be used to measure total times in the sense of a time + * stamp. + * + * @return the current thread's time in nanoseconds + */ + public static long getTimeNS() { + return USING_BEAN ? threadMXBean.getCurrentThreadCpuTime() : System.nanoTime(); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TopLevelDebugConfig.java 2016-12-07 13:49:03.403299559 -0800 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014, 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.debug; + +/** + * A marker class for a scoped debug configuration covering a compilation region. Useful for + * programmatically enabling debug config features. + * + */ +public class TopLevelDebugConfig extends DelegatingDebugConfig { +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/AccumulatedDebugValue.java 2016-12-07 13:49:03.667311164 -0800 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, 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.debug.internal; + +public abstract class AccumulatedDebugValue extends DebugValue { + protected final DebugValue flat; + + public AccumulatedDebugValue(String name, boolean conditional, DebugValue flat) { + super(name + "_Accm", conditional); + this.flat = flat; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/CloseableCounterImpl.java 2016-12-07 13:49:03.933322857 -0800 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, 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.debug.internal; + +import org.graalvm.compiler.debug.DebugCloseable; + +/** + * A helper class for DebugValues that can nest and need to split out accumulated and flat values + * for some kind of counter-like measurement. + */ +abstract class CloseableCounterImpl implements DebugCloseable { + + protected final CloseableCounterImpl parent; + protected final AccumulatedDebugValue counter; + protected final long start; + protected long nestedAmountToSubtract; + + CloseableCounterImpl(CloseableCounterImpl parent, AccumulatedDebugValue counter) { + this.parent = parent; + this.start = getCounterValue(); + this.counter = counter; + } + + /** + * A hook for subclasses. Lets them perform custom operations with the value since the last + * invocation of {@link CloseableCounterImpl#close()} of this accumulated + * {@link CloseableCounterImpl#counter}. + * + * @param difference since the last invocation of this counter flat + */ + protected void interceptDifferenceAccm(long difference) { + // hook for subclasses + } + + /** + * A hook for subclasses. Lets them perform custom operations with the value since the last + * invocation of {@link CloseableCounterImpl#close()} of this flat + * {@link CloseableCounterImpl#counter}. + * + * @param difference since the last invocation of this counter flat + */ + protected void interceptDifferenceFlat(long difference) { + // hook for subclasses + } + + @Override + public void close() { + long end = getCounterValue(); + long difference = end - start; + if (parent != null) { + if (!counter.getName().equals(parent.counter.getName())) { + parent.nestedAmountToSubtract += difference; + // Look for our counter in an outer scope and fix up + // the adjustment to the flat count + CloseableCounterImpl ancestor = parent.parent; + while (ancestor != null) { + if (ancestor.counter.getName().equals(counter.getName())) { + ancestor.nestedAmountToSubtract -= difference; + break; + } + ancestor = ancestor.parent; + } + } + } + long flatAmount = difference - nestedAmountToSubtract; + counter.addToCurrentValue(difference); + counter.flat.addToCurrentValue(flatAmount); + interceptDifferenceAccm(difference); + interceptDifferenceFlat(flatAmount); + } + + abstract long getCounterValue(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/CounterImpl.java 2016-12-07 13:49:04.197334462 -0800 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012, 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.debug.internal; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl; + +public abstract class CounterImpl extends DebugValue implements DebugCounter { + + public CounterImpl(String name, boolean conditional) { + super(name, conditional); + if (isEnabled()) { + // Allows for zero counters to be shown + getCurrentValue(); + } + } + + @Override + public void increment() { + add(1); + } + + @Override + public String rawUnit() { + return ""; + } + + @Override + public String toRawString(long value) { + return Long.toString(value); + } + + @Override + public String toString(long value) { + return Long.toString(value); + } + + private static final class InterceptingCounterImpl extends CounterImpl { + + private InterceptingCounterImpl(String name, boolean conditional) { + super(name, conditional); + } + + @Override + public void add(long value) { + if (isEnabled()) { + if (Debug.isMethodMeterEnabled()) { + MethodMetricsImpl.addToCurrentScopeMethodMetrics(getName(), value); + } + super.addToCurrentValue(value); + } + } + } + + private static final class PlainCounterImpl extends CounterImpl { + + private PlainCounterImpl(String name, boolean conditional) { + super(name, conditional); + } + + @Override + public void add(long value) { + if (isEnabled()) { + super.addToCurrentValue(value); + } + } + } + + public static DebugCounter create(String name, boolean conditional, boolean intercepting) { + if (intercepting) { + return new InterceptingCounterImpl(name, conditional); + } + return new PlainCounterImpl(name, conditional); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramAsciiPrinter.java 2016-12-07 13:49:04.463346155 -0800 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.debug.internal; + +import java.io.PrintStream; +import java.util.Arrays; +import java.util.List; + +import org.graalvm.compiler.debug.DebugHistogram; +import org.graalvm.compiler.debug.DebugHistogram.CountedValue; +import org.graalvm.compiler.debug.DebugHistogram.Printer; + +/** + * Renders a textual representation of a histogram to a given print stream. + */ +public class DebugHistogramAsciiPrinter implements Printer { + + public static final int NumberSize = 10; + public static final int DefaultNameSize = 50; + public static final int DefaultBarSize = 100; + public static final int DefaultScale = 1; + + private final PrintStream os; + private final int limit; + private final int nameSize; + private final int barSize; + private final int scale; + + public DebugHistogramAsciiPrinter(PrintStream os) { + this(os, Integer.MAX_VALUE, DefaultNameSize, DefaultBarSize, DefaultScale); + } + + /** + * @param os where to print + * @param limit limits printing to the {@code limit} most frequent values + * @param nameSize the width of the value names column + * @param barSize the width of the value frequency column + * @param scale a factor by which every result is divided + */ + public DebugHistogramAsciiPrinter(PrintStream os, int limit, int nameSize, int barSize, int scale) { + this.os = os; + this.limit = limit; + this.nameSize = nameSize; + this.barSize = barSize; + this.scale = scale; + } + + @Override + public void print(DebugHistogram histogram) { + List list = histogram.getValues(); + if (list.isEmpty()) { + os.printf("%s is empty.%n", histogram.getName()); + return; + } + + // Sum up the total number of elements. + long total = list.stream().mapToLong(CountedValue::getCount).sum(); + + // Print header. + os.printf("%s has %d unique elements and %d total elements:%n", histogram.getName(), list.size(), total / scale); + + long max = list.get(0).getCount() / scale; + final int lineSize = nameSize + NumberSize + barSize + 10; + printLine(os, '-', lineSize); + String formatString = "| %-" + nameSize + "s | %-" + NumberSize + "d | %-" + barSize + "s |\n"; + for (int i = 0; i < list.size() && i < limit; ++i) { + CountedValue cv = list.get(i); + long value = cv.getCount() / scale; + char[] bar = new char[(int) (((double) value / (double) max) * barSize)]; + Arrays.fill(bar, '='); + String objectString = String.valueOf(cv.getValue()); + if (objectString.length() > nameSize) { + objectString = objectString.substring(0, nameSize - 3) + "..."; + } + os.printf(formatString, objectString, value, new String(bar)); + } + printLine(os, '-', lineSize); + } + + private static void printLine(PrintStream printStream, char c, int lineSize) { + char[] charArr = new char[lineSize]; + Arrays.fill(charArr, c); + printStream.printf("%s%n", new String(charArr)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramImpl.java 2016-12-07 13:49:04.728357803 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.debug.internal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import org.graalvm.compiler.debug.DebugHistogram; + +public class DebugHistogramImpl implements DebugHistogram { + + private final String name; + private HashMap map = new HashMap<>(); + + public DebugHistogramImpl(String name) { + this.name = name; + } + + @Override + public void add(Object value) { + CountedValue cv = map.get(value); + if (cv == null) { + map.put(value, new CountedValue(1, value)); + } else { + cv.inc(); + } + } + + @Override + public void add(Object value, long count) { + CountedValue cv = map.get(value); + if (cv == null) { + map.put(value, new CountedValue(count, value)); + } else { + cv.add(count); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public List getValues() { + ArrayList res = new ArrayList<>(map.values()); + Collections.sort(res); + return res; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramRPrinter.java 2016-12-07 13:49:04.994369496 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.debug.internal; + +import java.io.PrintStream; +import java.util.List; + +import org.graalvm.compiler.debug.DebugHistogram; +import org.graalvm.compiler.debug.DebugHistogram.CountedValue; +import org.graalvm.compiler.debug.DebugHistogram.Printer; + +/** + * Renders a histogram as an R script to a given print stream. The R script emitted for a histogram + * is a simple set of statements for defining a vector of named objects. + */ +public class DebugHistogramRPrinter implements Printer { + + private PrintStream os; + private int limit; + + public DebugHistogramRPrinter(PrintStream os) { + this(os, Integer.MAX_VALUE); + } + + /** + * @param os where to print + * @param limit limits printing to the {@code limit} most frequent values + */ + public DebugHistogramRPrinter(PrintStream os, int limit) { + this.os = os; + this.limit = limit; + } + + @Override + public void print(DebugHistogram histogram) { + List list = histogram.getValues(); + if (list.isEmpty()) { + return; + } + + String var = histogram.getName().replace('-', '.').replace(' ', '_'); + os.print(var + " <- c("); + for (int i = 0; i < list.size() && i < limit; ++i) { + CountedValue cv = list.get(i); + if (i != 0) { + os.print(", "); + } + os.print(cv.getCount()); + } + os.println(");"); + + os.print("names(" + var + ") <- c("); + for (int i = 0; i < list.size() && i < limit; ++i) { + CountedValue cv = list.get(i); + if (i != 0) { + os.print(", "); + } + os.print("\"" + cv.getValue() + "\""); + } + os.println(");"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java 2016-12-07 13:49:05.259381145 -0800 @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2012, 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.debug.internal; + +import java.io.PrintStream; +import java.util.Iterator; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicLong; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.debug.DebugDumpHandler; +import org.graalvm.compiler.debug.DebugVerifyHandler; +import org.graalvm.compiler.debug.DelegatingDebugConfig; +import org.graalvm.compiler.debug.Indent; +import org.graalvm.compiler.debug.JavaMethodContext; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.debug.TopLevelDebugConfig; + +import jdk.vm.ci.meta.JavaMethod; + +public final class DebugScope implements Debug.Scope { + + private final class IndentImpl implements Indent { + + private static final String INDENTATION_INCREMENT = " "; + + final String indent; + final IndentImpl parentIndent; + + IndentImpl(IndentImpl parentIndent) { + this.parentIndent = parentIndent; + this.indent = (parentIndent == null ? "" : parentIndent.indent + INDENTATION_INCREMENT); + } + + private boolean logScopeName() { + return logScopeName; + } + + private void printScopeName(StringBuilder str, boolean isCurrent) { + if (logScopeName) { + boolean parentPrinted = false; + if (parentIndent != null) { + parentPrinted = parentIndent.logScopeName(); + parentIndent.printScopeName(str, false); + } + /* + * Always print the current scope, scopes with context and the any scope whose + * parent didn't print. This ensure the first new scope always shows up. + */ + if (isCurrent || printContext(null) != 0 || !parentPrinted) { + str.append(indent).append("[thread:").append(Thread.currentThread().getId()).append("] scope: ").append(getQualifiedName()).append(System.lineSeparator()); + } + printContext(str); + logScopeName = false; + } + } + + /** + * Print or count the context objects for the current scope. + */ + private int printContext(StringBuilder str) { + int count = 0; + if (context != null && context.length > 0) { + // Include some context in the scope output + for (Object contextObj : context) { + if (contextObj instanceof JavaMethodContext || contextObj instanceof JavaMethod) { + if (str != null) { + str.append(indent).append("Context: ").append(contextObj).append(System.lineSeparator()); + } + count++; + } + } + } + return count; + } + + public void log(int logLevel, String msg, Object... args) { + if (isLogEnabled(logLevel)) { + StringBuilder str = new StringBuilder(); + printScopeName(str, true); + str.append(indent); + String result = args.length == 0 ? msg : String.format(msg, args); + String lineSep = System.lineSeparator(); + str.append(result.replace(lineSep, lineSep.concat(indent))); + str.append(lineSep); + output.append(str); + lastUsedIndent = this; + } + } + + IndentImpl indent() { + lastUsedIndent = new IndentImpl(this); + return lastUsedIndent; + } + + @Override + public void close() { + if (parentIndent != null) { + lastUsedIndent = parentIndent; + } + } + } + + /** + * Interface for an additional information object per scope. The information object will be + * given to child scopes, but can be explicitly set with + * {@link DebugScope#enhanceWithExtraInfo(CharSequence, ExtraInfo, boolean, Object...)} + */ + public interface ExtraInfo { + + } + + private static final ThreadLocal instanceTL = new ThreadLocal<>(); + private static final ThreadLocal lastClosedTL = new ThreadLocal<>(); + private static final ThreadLocal configTL = new ThreadLocal<>(); + private static final ThreadLocal lastExceptionThrownTL = new ThreadLocal<>(); + + private final DebugScope parent; + private final DebugConfig parentConfig; + private final boolean sandbox; + private IndentImpl lastUsedIndent; + private boolean logScopeName; + + private final Object[] context; + + private DebugValueMap valueMap; + + private String qualifiedName; + private final String unqualifiedName; + + private final ExtraInfo extraInfo; + + private static final AtomicLong uniqueScopeId = new AtomicLong(); + private final long scopeId; + + private static final char SCOPE_SEP = '.'; + + private boolean countEnabled; + private boolean timeEnabled; + private boolean memUseTrackingEnabled; + private boolean verifyEnabled; + private boolean methodMetricsEnabled; + + private int currentDumpLevel; + private int currentLogLevel; + + private PrintStream output; + + public static long getCurrentGlobalScopeId() { + return uniqueScopeId.get(); + } + + public static DebugScope getInstance() { + DebugScope result = instanceTL.get(); + if (result == null) { + DebugScope topLevelDebugScope = new DebugScope(Thread.currentThread()); + instanceTL.set(topLevelDebugScope); + return topLevelDebugScope; + } else { + return result; + } + } + + public static DebugConfig getConfig() { + return configTL.get(); + } + + static final Object[] EMPTY_CONTEXT = new Object[0]; + + private DebugScope(Thread thread) { + this(thread.getName(), null, uniqueScopeId.incrementAndGet(), null, false); + computeValueMap(thread.getName()); + DebugValueMap.registerTopLevel(getValueMap()); + } + + private DebugScope(String unqualifiedName, DebugScope parent, long scopeId, ExtraInfo metaInfo, boolean sandbox, Object... context) { + this.parent = parent; + this.sandbox = sandbox; + this.parentConfig = getConfig(); + this.context = context; + this.scopeId = scopeId; + this.unqualifiedName = unqualifiedName; + this.extraInfo = metaInfo; + if (parent != null) { + logScopeName = !unqualifiedName.equals(""); + } else { + logScopeName = true; + } + + this.output = TTY.out; + assert context != null; + } + + private void computeValueMap(String name) { + if (parent != null) { + for (DebugValueMap child : parent.getValueMap().getChildren()) { + if (child.getName().equals(name)) { + this.valueMap = child; + return; + } + } + this.valueMap = new DebugValueMap(name); + parent.getValueMap().addChild(this.valueMap); + } else { + this.valueMap = new DebugValueMap(name); + } + } + + @Override + public void close() { + instanceTL.set(parent); + configTL.set(parentConfig); + lastClosedTL.set(this); + } + + public boolean isDumpEnabled(int dumpLevel) { + assert dumpLevel > 0; + return currentDumpLevel >= dumpLevel; + } + + /** + * Enable dumping at the new {@code dumpLevel} for the remainder of enclosing scopes. This only + * works if a {@link TopLevelDebugConfig} was installed at a higher scope. + * + * @param dumpLevel + */ + public static void setDumpLevel(int dumpLevel) { + TopLevelDebugConfig config = fetchTopLevelDebugConfig("setDebugLevel"); + if (config != null) { + config.override(DelegatingDebugConfig.Level.DUMP, dumpLevel); + recursiveUpdateFlags(); + } + } + + /** + * Enable logging at the new {@code logLevel} for the remainder of enclosing scopes. This only + * works if a {@link TopLevelDebugConfig} was installed at a higher scope. + * + * @param logLevel + */ + public static void setLogLevel(int logLevel) { + TopLevelDebugConfig config = fetchTopLevelDebugConfig("setLogLevel"); + if (config != null) { + config.override(DelegatingDebugConfig.Level.LOG, logLevel); + config.delegate(DelegatingDebugConfig.Feature.LOG_METHOD); + recursiveUpdateFlags(); + } + } + + private static void recursiveUpdateFlags() { + DebugScope c = DebugScope.getInstance(); + while (c != null) { + c.updateFlags(); + c = c.parent; + } + } + + private static TopLevelDebugConfig fetchTopLevelDebugConfig(String msg) { + DebugConfig config = getConfig(); + if (config instanceof TopLevelDebugConfig) { + return (TopLevelDebugConfig) config; + } else { + if (config == null) { + TTY.println("DebugScope.%s ignored because debugging is disabled", msg); + } else { + TTY.println("DebugScope.%s ignored because top level delegate config missing", msg); + } + return null; + } + } + + public boolean isVerifyEnabled() { + return verifyEnabled; + } + + public boolean isLogEnabled(int logLevel) { + assert logLevel > 0; + return currentLogLevel >= logLevel; + } + + public boolean isCountEnabled() { + return countEnabled; + } + + public boolean isTimeEnabled() { + return timeEnabled; + } + + public boolean isMethodMeterEnabled() { + return methodMetricsEnabled; + } + + public boolean isMemUseTrackingEnabled() { + return memUseTrackingEnabled; + } + + public void log(int logLevel, String msg, Object... args) { + if (isLogEnabled(logLevel)) { + getLastUsedIndent().log(logLevel, msg, args); + } + } + + public ExtraInfo getExtraInfo() { + return extraInfo; + } + + public long scopeId() { + return scopeId; + } + + public void dump(int dumpLevel, Object object, String formatString, Object... args) { + if (isDumpEnabled(dumpLevel)) { + DebugConfig config = getConfig(); + if (config != null) { + String message = String.format(formatString, args); + for (DebugDumpHandler dumpHandler : config.dumpHandlers()) { + dumpHandler.dump(object, message); + } + } + } + } + + /** + * This method exists mainly to allow a debugger (e.g., Eclipse) to force dump a graph. + */ + public static void forceDump(Object object, String format, Object... args) { + DebugConfig config = getConfig(); + if (config != null) { + String message = String.format(format, args); + for (DebugDumpHandler dumpHandler : config.dumpHandlers()) { + dumpHandler.dump(object, message); + } + } else { + TTY.println("Forced dump ignored because debugging is disabled - use -Dgraal.Dump=xxx"); + } + } + + /** + * @see Debug#verify(Object, String) + */ + public void verify(Object object, String formatString, Object... args) { + if (isVerifyEnabled()) { + DebugConfig config = getConfig(); + if (config != null) { + String message = String.format(formatString, args); + for (DebugVerifyHandler handler : config.verifyHandlers()) { + handler.verify(object, message); + } + } + } + } + + /** + * Creates and enters a new debug scope which is either a child of the current scope or a + * disjoint top level scope. + * + * @param name the name of the new scope + * @param sandboxConfig the configuration to use for a new top level scope, or null if the new + * scope should be a child scope + * @param newContextObjects objects to be appended to the debug context + * @return the new scope which will be exited when its {@link #close()} method is called + */ + public DebugScope scope(CharSequence name, DebugConfig sandboxConfig, Object... newContextObjects) { + DebugScope newScope = null; + if (sandboxConfig != null) { + newScope = new DebugScope(name.toString(), this, uniqueScopeId.incrementAndGet(), null, true, newContextObjects); + configTL.set(sandboxConfig); + } else { + newScope = this.createChild(name.toString(), this.extraInfo, newContextObjects); + } + instanceTL.set(newScope); + newScope.updateFlags(); + return newScope; + } + + public DebugScope enhanceWithExtraInfo(CharSequence name, ExtraInfo newInfo, boolean newId, Object... newContext) { + DebugScope newScope = createChild(name.toString(), newInfo, newId ? uniqueScopeId.incrementAndGet() : this.scopeId, newContext); + instanceTL.set(newScope); + newScope.updateFlags(); + return newScope; + } + + public RuntimeException handle(Throwable e) { + DebugScope lastClosed = lastClosedTL.get(); + assert lastClosed.parent == this : "Debug.handle() used with no matching Debug.scope(...) or Debug.sandbox(...)"; + if (e != lastExceptionThrownTL.get()) { + RuntimeException newException = null; + instanceTL.set(lastClosed); + try (DebugScope s = lastClosed) { + newException = s.interceptException(e); + } + assert instanceTL.get() == this; + assert lastClosed == lastClosedTL.get(); + if (newException == null) { + lastExceptionThrownTL.set(e); + } else { + lastExceptionThrownTL.set(newException); + throw newException; + } + } + if (e instanceof Error) { + throw (Error) e; + } + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } + throw new RuntimeException(e); + } + + private void updateFlags() { + DebugConfig config = getConfig(); + if (config == null) { + countEnabled = false; + memUseTrackingEnabled = false; + timeEnabled = false; + verifyEnabled = false; + currentDumpLevel = 0; + methodMetricsEnabled = false; + // Be pragmatic: provide a default log stream to prevent a crash if the stream is not + // set while logging + output = TTY.out; + } else { + countEnabled = config.isCountEnabled(); + memUseTrackingEnabled = config.isMemUseTrackingEnabled(); + timeEnabled = config.isTimeEnabled(); + verifyEnabled = config.isVerifyEnabled(); + output = config.output(); + currentDumpLevel = config.getDumpLevel(); + currentLogLevel = config.getLogLevel(); + methodMetricsEnabled = config.isMethodMeterEnabled(); + } + } + + @SuppressWarnings("try") + private RuntimeException interceptException(final Throwable e) { + final DebugConfig config = getConfig(); + if (config != null) { + try (DebugScope s = scope("InterceptException", null, e)) { + return config.interceptException(e); + } catch (Throwable t) { + return new RuntimeException("Exception while intercepting exception", t); + } + } + return null; + } + + private DebugValueMap getValueMap() { + if (valueMap == null) { + computeValueMap(unqualifiedName); + } + return valueMap; + } + + long getCurrentValue(int index) { + return getValueMap().getCurrentValue(index); + } + + void setCurrentValue(int index, long l) { + getValueMap().setCurrentValue(index, l); + } + + private DebugScope createChild(String newName, ExtraInfo newInfo, Object[] newContext) { + return new DebugScope(newName, this, this.scopeId, newInfo, false, newContext); + } + + private DebugScope createChild(String newName, ExtraInfo newInfo, long newId, Object[] newContext) { + return new DebugScope(newName, this, newId, newInfo, false, newContext); + } + + public Iterable getCurrentContext() { + final DebugScope scope = this; + return new Iterable() { + + @Override + public Iterator iterator() { + return new Iterator() { + + DebugScope currentScope = scope; + int objectIndex; + + @Override + public boolean hasNext() { + selectScope(); + return currentScope != null; + } + + private void selectScope() { + while (currentScope != null && currentScope.context.length <= objectIndex) { + currentScope = currentScope.sandbox ? null : currentScope.parent; + objectIndex = 0; + } + } + + @Override + public Object next() { + selectScope(); + if (currentScope != null) { + return currentScope.context[objectIndex++]; + } + throw new IllegalStateException("May only be called if there is a next element."); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("This iterator is read only."); + } + }; + } + }; + } + + public static T call(Callable callable) { + try { + return callable.call(); + } catch (Exception e) { + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } else { + throw new RuntimeException(e); + } + } + } + + public void setConfig(DebugConfig newConfig) { + configTL.set(newConfig); + updateFlags(); + } + + public String getQualifiedName() { + if (qualifiedName == null) { + if (parent == null) { + qualifiedName = unqualifiedName; + } else { + qualifiedName = parent.getQualifiedName() + SCOPE_SEP + unqualifiedName; + } + } + return qualifiedName; + } + + public Indent pushIndentLogger() { + lastUsedIndent = getLastUsedIndent().indent(); + return lastUsedIndent; + } + + public IndentImpl getLastUsedIndent() { + if (lastUsedIndent == null) { + if (parent != null) { + lastUsedIndent = new IndentImpl(parent.getLastUsedIndent()); + } else { + lastUsedIndent = new IndentImpl(null); + } + } + return lastUsedIndent; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValue.java 2016-12-07 13:49:05.525392838 -0800 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2012, 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.debug.internal; + +/** + * A name and index for a value managed in a thread local value map. All access to the value is made + * via a {@link DebugValue} instance. + */ +public abstract class DebugValue implements Comparable { + + private final String name; + private int index; + private boolean conditional; + + protected DebugValue(String name, boolean conditional) { + this.name = name; + this.index = -1; + this.conditional = conditional; + } + + public long getCurrentValue() { + ensureInitialized(); + return DebugScope.getInstance().getCurrentValue(index); + } + + protected void setCurrentValue(long l) { + ensureInitialized(); + DebugScope.getInstance().setCurrentValue(index, l); + } + + public void setConditional(boolean flag) { + conditional = flag; + } + + public boolean isConditional() { + return conditional; + } + + private void ensureInitialized() { + if (index == -1) { + index = KeyRegistry.register(this); + } + } + + protected void addToCurrentValue(long value) { + setCurrentValue(getCurrentValue() + value); + } + + /** + * Gets the globally unique index for the value represented by this object. + */ + public int getIndex() { + ensureInitialized(); + return index; + } + + /** + * Gets the globally unique name for the value represented by this object. + */ + public String getName() { + return name; + } + + @Override + public int compareTo(DebugValue o) { + return name.compareTo(o.name); + } + + @Override + public String toString() { + return name + "@" + index; + } + + public abstract String toString(long value); + + /** + * The raw unit of the value (e.g. 'us', 'ms'). Use {@code ""} if there is no unit. + */ + public abstract String rawUnit(); + + /** + * The raw value. + */ + public abstract String toRawString(long value); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValueMap.java 2016-12-07 13:49:05.790404487 -0800 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2012, 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.debug.internal; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A node in a tree of {@link DebugValue}s. + */ +public class DebugValueMap { + + private static final List topLevelMaps = new ArrayList<>(); + + private long[] values; + private List children; + private String name; + + public DebugValueMap(String name) { + this.name = name; + } + + public void setCurrentValue(int index, long l) { + ensureSize(index); + values[index] = l; + } + + public long getCurrentValue(int index) { + ensureSize(index); + return values[index]; + } + + public void clearChildren() { + if (children != null) { + children.clear(); + } + } + + public void reset() { + if (values != null) { + Arrays.fill(values, 0L); + } + if (children != null) { + for (DebugValueMap child : children) { + child.reset(); + } + } + } + + private void ensureSize(int index) { + if (values == null) { + values = new long[index + 1]; + } + if (values.length <= index) { + values = Arrays.copyOf(values, index + 1); + } + } + + private int capacity() { + return (values == null) ? 0 : values.length; + } + + public void addChild(DebugValueMap map) { + if (children == null) { + children = new ArrayList<>(4); + } + children.add(map); + } + + public List getChildren() { + if (children == null) { + return Collections.emptyList(); + } else { + return Collections.unmodifiableList(children); + } + } + + public boolean hasChildren() { + return children != null && !children.isEmpty(); + } + + public String getName() { + return this.name; + } + + @Override + public String toString() { + return "DebugValueMap<" + getName() + ">"; + } + + public static synchronized void registerTopLevel(DebugValueMap map) { + topLevelMaps.add(map); + } + + public static synchronized List getTopLevelMaps() { + return topLevelMaps; + } + + public void normalize() { + if (hasChildren()) { + Map occurred = new HashMap<>(); + for (DebugValueMap map : children) { + String mapName = map.getName(); + if (!occurred.containsKey(mapName)) { + occurred.put(mapName, map); + map.normalize(); + } else { + occurred.get(mapName).mergeWith(map); + occurred.get(mapName).normalize(); + } + } + + if (occurred.values().size() < children.size()) { + // At least one duplicate was found. + children.clear(); + for (DebugValueMap map : occurred.values()) { + addChild(map); + map.normalize(); + } + } + } + } + + private void mergeWith(DebugValueMap map) { + if (map.hasChildren()) { + if (hasChildren()) { + children.addAll(map.children); + } else { + children = map.children; + } + map.children = null; + } + + int size = Math.max(this.capacity(), map.capacity()); + ensureSize(size); + for (int i = 0; i < size; ++i) { + long curValue = getCurrentValue(i); + long otherValue = map.getCurrentValue(i); + setCurrentValue(i, curValue + otherValue); + } + } + + public void group() { + if (this.hasChildren()) { + List oldChildren = new ArrayList<>(this.children); + this.children.clear(); + for (DebugValueMap map : oldChildren) { + mergeWith(map); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValuesPrinter.java 2016-12-07 13:49:06.055416136 -0800 @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2014, 2015, 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.debug.internal; + +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueFile; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueHumanReadable; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueSummary; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueThreadFilter; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.SuppressZeroDebugValues; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.graalvm.compiler.debug.CSVUtil; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.LogStream; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl; +import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter; + +/** + * Facility for printing the {@linkplain KeyRegistry#getDebugValues() values} collected across all + * {@link DebugValueMap#getTopLevelMaps() threads}. + */ +public class DebugValuesPrinter { + private static final String COMPUTER_READABLE_FMT = CSVUtil.buildFormatString("%s", "%s", "%s", "%s"); + private static final char SCOPE_DELIMITER = '.'; + private final MethodMetricsPrinter mmPrinter; + + public DebugValuesPrinter() { + this(null); + } + + public DebugValuesPrinter(MethodMetricsPrinter mmPrinter) { + this.mmPrinter = mmPrinter; + } + + public void printDebugValues() throws GraalError { + TTY.println(); + TTY.println(""); + List topLevelMaps = DebugValueMap.getTopLevelMaps(); + List debugValues = KeyRegistry.getDebugValues(); + if (debugValues.size() > 0) { + try { + ArrayList sortedValues = new ArrayList<>(debugValues); + Collections.sort(sortedValues); + + String summary = DebugValueSummary.getValue(); + if (summary == null) { + summary = "Complete"; + } + if (DebugValueThreadFilter.getValue() != null && topLevelMaps.size() != 0) { + topLevelMaps = topLevelMaps.stream().filter(map -> Pattern.compile(DebugValueThreadFilter.getValue()).matcher(map.getName()).find()).collect(Collectors.toList()); + if (topLevelMaps.size() == 0) { + TTY.println("Warning: DebugValueThreadFilter=%s eliminated all maps so nothing will be printed", DebugValueThreadFilter.getValue()); + } + } + switch (summary) { + case "Name": { + LogStream log = getLogStream(); + printSummary(log, topLevelMaps, sortedValues); + break; + } + case "Partial": { + DebugValueMap globalMap = new DebugValueMap("Global"); + for (DebugValueMap map : topLevelMaps) { + flattenChildren(map, globalMap); + } + globalMap.normalize(); + LogStream log = getLogStream(); + printMap(log, new DebugValueScope(null, globalMap), sortedValues); + break; + } + case "Complete": { + DebugValueMap globalMap = new DebugValueMap("Global"); + for (DebugValueMap map : topLevelMaps) { + globalMap.addChild(map); + } + globalMap.group(); + globalMap.normalize(); + LogStream log = getLogStream(); + printMap(log, new DebugValueScope(null, globalMap), sortedValues); + break; + } + case "Thread": + for (DebugValueMap map : topLevelMaps) { + TTY.println("Showing the results for thread: " + map.getName()); + map.group(); + map.normalize(); + LogStream log = getLogStream(map.getName().replace(' ', '_')); + printMap(log, new DebugValueScope(null, map), sortedValues); + } + break; + default: + throw new GraalError("Unknown summary type: %s", summary); + } + for (DebugValueMap topLevelMap : topLevelMaps) { + topLevelMap.reset(); + } + } catch (Throwable e) { + // Don't want this to change the exit status of the VM + PrintStream err = System.err; + err.println("Error while printing debug values:"); + e.printStackTrace(); + } + } + if (mmPrinter != null) { + mmPrinter.printMethodMetrics(MethodMetricsImpl.collectedMetrics()); + } + TTY.println(""); + } + + private static LogStream getLogStream() { + return getLogStream(null); + } + + private static LogStream getLogStream(String prefix) { + String debugValueFile = DebugValueFile.getValue(); + if (debugValueFile != null) { + try { + final String fileName; + if (prefix != null) { + fileName = prefix + '-' + debugValueFile; + } else { + fileName = debugValueFile; + } + LogStream logStream = new LogStream(new FileOutputStream(fileName)); + TTY.println("Writing debug values to '%s'", fileName); + return logStream; + } catch (FileNotFoundException e) { + TTY.println("Warning: Could not open debug value log file: %s (defaulting to TTY)", e.getMessage()); + } + } + return TTY.out(); + } + + private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) { + globalMap.addChild(map); + for (DebugValueMap child : map.getChildren()) { + flattenChildren(child, globalMap); + } + map.clearChildren(); + } + + private void printSummary(LogStream log, List topLevelMaps, List debugValues) { + DebugValueMap result = new DebugValueMap("Summary"); + for (int i = debugValues.size() - 1; i >= 0; i--) { + DebugValue debugValue = debugValues.get(i); + int index = debugValue.getIndex(); + long total = collectTotal(topLevelMaps, index); + result.setCurrentValue(index, total); + } + printMap(log, new DebugValueScope(null, result), debugValues); + } + + private long collectTotal(List maps, int index) { + long total = 0; + for (int i = 0; i < maps.size(); i++) { + DebugValueMap map = maps.get(i); + total += map.getCurrentValue(index); + total += collectTotal(map.getChildren(), index); + } + return total; + } + + /** + * Tracks the scope when printing a {@link DebugValueMap}, allowing "empty" scopes to be + * omitted. An empty scope is one in which there are no (nested) non-zero debug values. + */ + static class DebugValueScope { + + final DebugValueScope parent; + final int level; + final DebugValueMap map; + private boolean printed; + + DebugValueScope(DebugValueScope parent, DebugValueMap map) { + this.parent = parent; + this.map = map; + this.level = parent == null ? 0 : parent.level + 1; + } + + public void print(LogStream log) { + if (!printed) { + printed = true; + if (parent != null) { + parent.print(log); + } + printIndent(log, level); + log.printf("%s%n", map.getName()); + } + } + + public String toRawString() { + return toRaw(new StringBuilder()).toString(); + } + + private StringBuilder toRaw(StringBuilder stringBuilder) { + final StringBuilder sb = (parent == null) ? stringBuilder : parent.toRaw(stringBuilder).append(SCOPE_DELIMITER); + return sb.append(map.getName()); + } + + } + + private void printMap(LogStream log, DebugValueScope scope, List debugValues) { + if (DebugValueHumanReadable.getValue()) { + printMapHumanReadable(log, scope, debugValues); + } else { + printMapComputerReadable(log, scope, debugValues); + } + } + + private void printMapComputerReadable(LogStream log, DebugValueScope scope, List debugValues) { + + for (DebugValue value : debugValues) { + long l = scope.map.getCurrentValue(value.getIndex()); + if (l != 0 || !SuppressZeroDebugValues.getValue()) { + CSVUtil.Escape.println(log, COMPUTER_READABLE_FMT, scope.toRawString(), value.getName(), value.toRawString(l), value.rawUnit()); + } + } + + List children = scope.map.getChildren(); + for (int i = 0; i < children.size(); i++) { + DebugValueMap child = children.get(i); + printMapComputerReadable(log, new DebugValueScope(scope, child), debugValues); + } + } + + private void printMapHumanReadable(LogStream log, DebugValueScope scope, List debugValues) { + + for (DebugValue value : debugValues) { + long l = scope.map.getCurrentValue(value.getIndex()); + if (l != 0 || !SuppressZeroDebugValues.getValue()) { + scope.print(log); + printIndent(log, scope.level + 1); + log.println(value.getName() + "=" + value.toString(l)); + } + } + + List children = scope.map.getChildren(); + for (int i = 0; i < children.size(); i++) { + DebugValueMap child = children.get(i); + printMapHumanReadable(log, new DebugValueScope(scope, child), debugValues); + } + } + + private static void printIndent(LogStream log, int level) { + for (int i = 0; i < level; ++i) { + log.print(" "); + } + log.print("|-> "); + } + + public void clearDebugValues() { + List topLevelMaps = DebugValueMap.getTopLevelMaps(); + List debugValues = KeyRegistry.getDebugValues(); + if (debugValues.size() > 0) { + for (DebugValueMap map : topLevelMaps) { + map.reset(); + } + } + if (mmPrinter != null) { + MethodMetricsImpl.clearMM(); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/KeyRegistry.java 2016-12-07 13:49:06.320427784 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2012, 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.debug.internal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Registry for allocating a globally unique integer id to each {@link DebugValue}. + */ +public class KeyRegistry { + + private static final Map keyMap = new HashMap<>(); + private static final List debugValues = new ArrayList<>(); + + /** + * Ensures a given debug value is registered. + * + * @return the globally unique id for {@code value} + */ + public static synchronized int register(DebugValue value) { + String name = value.getName(); + if (!keyMap.containsKey(name)) { + keyMap.put(name, debugValues.size()); + debugValues.add(value); + } + return keyMap.get(name); + } + + /** + * Gets a immutable view of the registered debug values. + * + * @return a list where {@code get(i).getIndex() == i} + */ + public static synchronized List getDebugValues() { + return Collections.unmodifiableList(debugValues); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/MemUseTrackerImpl.java 2016-12-07 13:49:06.586439477 -0800 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2012, 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.debug.internal; + +import static org.graalvm.compiler.debug.DebugCloseable.VOID_CLOSEABLE; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugMemUseTracker; +import org.graalvm.compiler.debug.Management; +import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl; + +public class MemUseTrackerImpl extends AccumulatedDebugValue implements DebugMemUseTracker { + private final boolean intercepting; + + public static long getCurrentThreadAllocatedBytes() { + return Management.getCurrentThreadAllocatedBytes(); + } + + /** + * Records the most recent active tracker. + */ + private static final ThreadLocal currentTracker = new ThreadLocal<>(); + + public MemUseTrackerImpl(String name, boolean conditional, boolean intercepting) { + super(name, conditional, new DebugValue(name + "_Flat", conditional) { + + @Override + public String toString(long value) { + return valueToString(value); + } + + @Override + public String rawUnit() { + return "B"; + } + + @Override + public String toRawString(long value) { + return Long.toString(value); + } + }); + this.intercepting = intercepting; + } + + @Override + public DebugCloseable start() { + if (!isConditional() || Debug.isMemUseTrackingEnabled()) { + CloseableCounterImpl result = intercepting ? new MemUseInterceptingCloseableCounterImpl(this) : new MemUseCloseableCounterImpl(this); + currentTracker.set(result); + return result; + } else { + return VOID_CLOSEABLE; + } + } + + public static String valueToString(long value) { + return String.format("%d bytes", value); + } + + @Override + public String toString(long value) { + return valueToString(value); + } + + private static final class MemUseCloseableCounterImpl extends CloseableCounterImpl implements DebugCloseable { + + private MemUseCloseableCounterImpl(AccumulatedDebugValue counter) { + super(currentTracker.get(), counter); + } + + @Override + long getCounterValue() { + return getCurrentThreadAllocatedBytes(); + } + + @Override + public void close() { + super.close(); + currentTracker.set(parent); + } + } + + private static final class MemUseInterceptingCloseableCounterImpl extends CloseableCounterImpl implements DebugCloseable { + + private MemUseInterceptingCloseableCounterImpl(AccumulatedDebugValue counter) { + super(currentTracker.get(), counter); + } + + @Override + long getCounterValue() { + return getCurrentThreadAllocatedBytes(); + } + + @Override + public void close() { + super.close(); + currentTracker.set(parent); + } + + @Override + protected void interceptDifferenceAccm(long difference) { + if (Debug.isMethodMeterEnabled()) { + MethodMetricsImpl.addToCurrentScopeMethodMetrics(counter.getName(), difference); + } + } + + @Override + protected void interceptDifferenceFlat(long difference) { + if (Debug.isMethodMeterEnabled()) { + MethodMetricsImpl.addToCurrentScopeMethodMetrics(counter.flat.getName(), difference); + } + } + } + + @Override + public String rawUnit() { + return "B"; + } + + @Override + public String toRawString(long value) { + return Long.toString(value); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/TimerImpl.java 2016-12-07 13:49:06.850451082 -0800 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2012, 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.debug.internal; + +import static org.graalvm.compiler.debug.DebugCloseable.VOID_CLOSEABLE; + +import java.util.concurrent.TimeUnit; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugTimer; +import org.graalvm.compiler.debug.TimeSource; +import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl; + +public final class TimerImpl extends AccumulatedDebugValue implements DebugTimer { + private final boolean intercepting; + + /** + * Records the most recent active timer. + */ + private static final ThreadLocal currentTimer = new ThreadLocal<>(); + + static class FlatTimer extends DebugValue implements DebugTimer { + private TimerImpl accm; + + FlatTimer(String name, boolean conditional) { + super(name + "_Flat", conditional); + } + + @Override + public String toString(long value) { + return valueToString(value); + } + + @Override + public TimeUnit getTimeUnit() { + return accm.getTimeUnit(); + } + + @Override + public DebugCloseable start() { + return accm.start(); + } + + @Override + public String rawUnit() { + return "us"; + } + + @Override + public String toRawString(long value) { + return valueToRawString(value); + } + } + + public TimerImpl(String name, boolean conditional, boolean intercepting) { + super(name, conditional, new FlatTimer(name, conditional)); + ((FlatTimer) flat).accm = this; + this.intercepting = intercepting; + } + + @Override + public DebugCloseable start() { + if (!isConditional() || Debug.isTimeEnabled()) { + AbstractTimer result = intercepting ? new InterceptingTimer(this) : new Timer(this); + currentTimer.set(result); + return result; + } else { + return VOID_CLOSEABLE; + } + } + + public static String valueToString(long value) { + return String.format("%d.%d ms", value / 1000000, (value / 100000) % 10); + } + + @Override + public DebugTimer getFlat() { + return (FlatTimer) flat; + } + + @Override + public String toString(long value) { + return valueToString(value); + } + + @Override + public TimeUnit getTimeUnit() { + return TimeUnit.NANOSECONDS; + } + + private abstract class AbstractTimer extends CloseableCounterImpl implements DebugCloseable { + + private AbstractTimer(AccumulatedDebugValue counter) { + super(currentTimer.get(), counter); + } + + @Override + public void close() { + super.close(); + currentTimer.set(parent); + } + } + + private final class Timer extends AbstractTimer { + + private Timer(TimerImpl timer) { + super(timer); + } + + @Override + protected long getCounterValue() { + return TimeSource.getTimeNS(); + } + + } + + private final class InterceptingTimer extends AbstractTimer { + + private InterceptingTimer(TimerImpl timer) { + super(timer); + } + + @Override + protected long getCounterValue() { + return TimeSource.getTimeNS(); + } + + @Override + protected void interceptDifferenceAccm(long difference) { + if (Debug.isMethodMeterEnabled()) { + MethodMetricsImpl.addToCurrentScopeMethodMetrics(counter.getName(), difference); + } + } + + @Override + protected void interceptDifferenceFlat(long difference) { + if (Debug.isMethodMeterEnabled()) { + MethodMetricsImpl.addToCurrentScopeMethodMetrics(counter.flat.getName(), difference); + } + } + } + + @Override + public String rawUnit() { + return "us"; + } + + @Override + public String toRawString(long value) { + return valueToRawString(value); + } + + public static String valueToRawString(long value) { + return Long.toString(value / 1000); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsImpl.java 2016-12-07 13:49:07.119462907 -0800 @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2015, 2016, 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.debug.internal.method; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.graalvm.compiler.debug.CSVUtil; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.DebugMethodMetrics; +import org.graalvm.compiler.debug.GraalDebugConfig; +import org.graalvm.compiler.debug.internal.DebugScope; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class MethodMetricsImpl implements DebugMethodMetrics { + + /** + * A list capturing all method metrics data of all the compiler threads. Every thread registers + * a reference to its thread local map of compilation metrics in this list. During metrics + * dumping this list is globally locked and all method entries across all threads are merged to + * a result. + */ + private static final List> threadMaps = new ArrayList<>(); + /** + * Every compiler thread carries its own map of metric data for each method and compilation it + * compiles. This data is stored in {@link ThreadLocal} maps for each compiler thread that are + * merged before metrics are reported. Storing compilation data thread locally reduces the + * locking on access of a method metric object to one point for each thread, the first access + * where the thread local is initialized. + */ + private static final ThreadLocal> threadEntries = new ThreadLocal<>(); + /** + * The lowest debug scope id that should be used during metric dumping. When a bootstrap is run + * all compilations during bootstrap are also collected if the associated debug filters match. + * Data collected during bootstrap should normally not be included in metrics for application + * compilation, thus every compilation lower than this index is ignored during metric dumping. + */ + private static long lowestCompilationDebugScopeId; + + public static class CompilationData { + /** + * A mapping of graph ids (unique ids used for the caching) to compilations. + */ + private final Map> compilations; + /** + * A pointer to a {@code MethodMetricsImpl} object. This reference is created once for every + * compilation of a method (and once for each thread, i.e. if method a is compiled by 8 + * compiler threads there will be 8 metrics objects for the given method, one local to every + * thread, this avoids synchronizing on the metrics object on every access) accessing method + * metrics for a given method. + */ + private final MethodMetricsImpl metrics; + + CompilationData(ResolvedJavaMethod method) { + compilations = new HashMap<>(8); + metrics = new MethodMetricsImpl(method); + } + + public Map> getCompilations() { + return compilations; + } + } + + private static void addThreadCompilationData(Map threadMap) { + synchronized (threadMaps) { + threadMaps.add(threadMap); + } + } + + /** + * A reference to the {@link ResolvedJavaMethod} method object. This object's identity is used + * to store metrics for each compilation. + */ + private final ResolvedJavaMethod method; + /** + * A list of all recorded compilations. This is generated during metric dumping when all thread + * local metrics are merged into one final method metrics object that is than reported + */ + private List>> collected; + /** + * A pointer to the current compilation data for the {@link MethodMetricsImpl#method} method + * which allows to avoid synchronizing over the compilation data. This reference changes for + * each compilation of the given method. It is set on the first access of this + * {@link MethodMetricsImpl} object during the call to + * {@link MethodMetricsImpl#getMethodMetrics(ResolvedJavaMethod)}. + */ + private Map currentCompilation; + + MethodMetricsImpl(ResolvedJavaMethod method) { + this.method = method; + } + + private static void clearData() { + lowestCompilationDebugScopeId = DebugScope.getCurrentGlobalScopeId(); + } + + @Override + public void addToMetric(long value, String metricName) { + if (!Debug.isMethodMeterEnabled() || value == 0) { + return; + } + assert metricName != null; + Long valueStored = currentCompilation.get(metricName); + currentCompilation.put(metricName, valueStored == null ? value : value + valueStored); + } + + @Override + public long getCurrentMetricValue(String metricName) { + assert metricName != null; + Long valueStored = currentCompilation.get(metricName); + return valueStored == null ? 0 : valueStored; + } + + @Override + public void addToMetric(long value, String format, Object arg1) { + addToMetric(value, String.format(format, arg1)); + } + + @Override + public void addToMetric(long value, String format, Object arg1, Object arg2) { + addToMetric(value, String.format(format, arg1, arg2)); + } + + @Override + public void addToMetric(long value, String format, Object arg1, Object arg2, Object arg3) { + addToMetric(value, String.format(format, arg1, arg2, arg3)); + } + + @Override + public void incrementMetric(String metricName) { + addToMetric(1, metricName); + } + + @Override + public void incrementMetric(String format, Object arg1) { + incrementMetric(String.format(format, arg1)); + } + + @Override + public void incrementMetric(String format, Object arg1, Object arg2) { + incrementMetric(String.format(format, arg1, arg2)); + } + + @Override + public void incrementMetric(String format, Object arg1, Object arg2, Object arg3) { + incrementMetric(String.format(format, arg1, arg2, arg3)); + } + + @Override + public long getCurrentMetricValue(String format, Object arg1) { + return getCurrentMetricValue(String.format(format, arg1)); + } + + @Override + public long getCurrentMetricValue(String format, Object arg1, Object arg2) { + return getCurrentMetricValue(String.format(format, arg1, arg2)); + } + + @Override + public long getCurrentMetricValue(String format, Object arg1, Object arg2, Object arg3) { + return getCurrentMetricValue(String.format(format, arg1, arg2, arg3)); + } + + @Override + public ResolvedJavaMethod getMethod() { + return method; + } + + public static DebugMethodMetrics getMethodMetrics(ResolvedJavaMethod method) { + assert method != null; + Map threadCache = threadEntries.get(); + if (threadCache == null) { + // this branch will only be executed once for each compiler thread on the first request + // of a method metric + threadCache = new HashMap<>(GraalDebugConfig.Options.MethodFilter.getValue() == null ? 128 : 16); + threadEntries.set(threadCache); + addThreadCompilationData(threadCache); + } + + CompilationData recorded = threadCache.get(method); + if (recorded == null) { + recorded = new CompilationData(method); + threadCache.put(method, recorded); + } + // pre-generate the current compilation map to avoid doing it later every time we add to a + // metric or read a current metric's value + long compilationId = DebugScope.getInstance().scopeId(); + Map currentCompilation = recorded.compilations.get(compilationId); + if (currentCompilation == null) { + // this map is generated for every distinct compilation of a unique method + currentCompilation = new HashMap<>(32); + recorded.compilations.put(compilationId, currentCompilation); + // we remember a reference to the current compilation to avoid the expensive lookup + recorded.metrics.currentCompilation = currentCompilation; + } + + return recorded.metrics; + } + + public void dumpASCII(PrintStream p) { + // we need to lock the threadmap as a concurrent call to #collectedMetrics can change the + // content of this#collected + synchronized (threadMaps) { + String methodName = method.toString(); + int maxLen = methodName.length(); + int entrySum = 0; + // get the longest entry + for (Map> compilationThreadTable : collected) { + for (Map.Entry> compilationEntry : compilationThreadTable.entrySet()) { + Map table = compilationEntry.getValue(); + if (table != null) { + for (Map.Entry entry : table.entrySet()) { + maxLen = Math.max(maxLen, entry.getKey().length()); + entrySum += entry.getValue(); + } + } + } + } + if (entrySum == 0) { + // nothing to report + return; + } + maxLen += 23; + for (int j = 0; j < maxLen; j++) { + p.print("#"); + } + p.println(); + p.println(methodName); + for (int j = 0; j < maxLen; j++) { + p.print("~"); + } + p.println(); + for (Map> compilationThreadTable : collected) { + for (Map.Entry> compilationEntry : compilationThreadTable.entrySet()) { + Map table = compilationEntry.getValue(); + if (table != null) { + if (table.values().stream().filter(x -> x > 0).count() == 0) { + continue; + } + Set> entries = table.entrySet(); + for (Map.Entry entry : entries.stream().sorted((x, y) -> x.getKey().compareTo(y.getKey())).collect(Collectors.toList())) { + long value = entry.getValue(); + // report timers in ms and memory in mb + if ((entry.getKey().endsWith("Accm") || entry.getKey().endsWith("Flat")) && + !entry.getKey().toLowerCase().contains("mem")) { + value = value / 1000000; + } + if (value == 0) { + continue; + } + p.print(String.format("%-" + String.valueOf(maxLen - 23) + "s = %20d", entry.getKey(), value)); + p.println(); + } + for (int j = 0; j < maxLen; j++) { + p.print("~"); + } + p.println(); + } + } + } + for (int j = 0; j < maxLen; j++) { + p.print("#"); + } + p.println(); + } + } + + private static final String FMT = CSVUtil.buildFormatString("%s", "%s", "%d", "%d", "%s", "%d"); + + public void dumpCSV(PrintStream p) { + // we need to lock the threadmap as a concurrent call to #collectedMetrics can change + // the content of this#collected + synchronized (threadMaps) { + String methodName = method.format("%H.%n(%p)%R"); + /* + * NOTE: the caching mechanism works by caching compilation data based on the identity + * of the resolved java method object. The identity is based on the metaspace address of + * the resolved java method object. If the class was loaded by different class loaders + * or e.g. loaded - unloaded - loaded the identity will be different. Therefore we also + * need to include the identity in the reporting of the data as it is an additional + * dimension to . + */ + String methodIdentity = String.valueOf(System.identityHashCode(method)); + int nrOfCompilations = 0; + for (Map> compilationThreadTable : collected) { + for (Map.Entry> compilationEntry : compilationThreadTable.entrySet()) { + Map table = compilationEntry.getValue(); + if (table != null) { + Set> entries = table.entrySet(); + for (Map.Entry entry : entries.stream().sorted((x, y) -> x.getKey().compareTo(y.getKey())).collect(Collectors.toList())) { + CSVUtil.Escape.println(p, FMT, methodName, methodIdentity, nrOfCompilations, compilationEntry.getKey(), entry.getKey(), entry.getValue()); + } + nrOfCompilations++; + } + } + } + } + } + + public static Collection collectedMetrics() { + synchronized (threadMaps) { + // imprecise excluding all compilations that follow, we simply do not report them + final long lastId = DebugScope.getCurrentGlobalScopeId(); + List finalMetrics = new ArrayList<>(); + Set methods = new HashSet<>(); + + // gather all methods we found + threadMaps.stream().forEach(x -> { + // snapshot the current compilations to only capture all methods compiled until now + HashMap snapShot = new HashMap<>(x); + snapShot.keySet().forEach(y -> methods.add(y)); + }); + + // for each method gather all metrics we want to report + for (ResolvedJavaMethod method : methods) { + MethodMetricsImpl impl = new MethodMetricsImpl(method); + impl.collected = new ArrayList<>(); + for (Map threadMap : threadMaps) { + CompilationData threadMethodData = threadMap.get(method); + + // not every method is necessarily compiled by all threads + if (threadMethodData != null) { + Map> snapshot = new HashMap<>(threadMethodData.compilations); + for (Map.Entry> entry : snapshot.entrySet()) { + if (entry.getKey() < lowestCompilationDebugScopeId || entry.getKey() > lastId) { + entry.setValue(null); + } + } + impl.collected.add(snapshot); + } + } + finalMetrics.add(impl); + } + + return finalMetrics; + } + } + + public static void clearMM() { + clearData(); + } + + private static final String INLINEE_PREFIX = "INLINING_SCOPE_"; + private static final boolean TRACK_INLINED_SCOPES = false; + + public static void recordInlinee(ResolvedJavaMethod root, ResolvedJavaMethod caller, ResolvedJavaMethod inlinee) { + if (TRACK_INLINED_SCOPES) { + Debug.methodMetrics(root).addToMetric(1, "INLINED_METHOD_root: caller:%s inlinee:%s", caller, inlinee); + } + } + + private static final boolean COUNT_CACHE = false; + private static final String HIT_MSG = "InterceptionCache_Hit"; + private static final String MISS_MSG = "InterceptionCache_Miss"; + private static final DebugCounter cacheHit = Debug.counter(HIT_MSG); + private static final DebugCounter cacheMiss = Debug.counter(MISS_MSG); + /** + * To avoid the lookup of a method metrics through the + * {@link MethodMetricsImpl#getMethodMetrics(ResolvedJavaMethod)} method on every global metric + * interception we thread-locally cache the last (through metric interception) + * {@link MethodMetricsImpl} object. This avoids additional map lookups and replaces them with a + * {@link DebugScope#scopeId()} call and a numerical comparison in a cache hit case. + */ + private static final ThreadLocal interceptionCache = new ThreadLocal<>(); + private static final ThreadLocal interceptionMetrics = new ThreadLocal<>(); + + public static void addToCurrentScopeMethodMetrics(String metricName, long value) { + if (COUNT_CACHE) { + if (metricName.equals(HIT_MSG) || metricName.equals(MISS_MSG)) { + return; + } + } + final DebugScope currScope = DebugScope.getInstance(); + final DebugScope.ExtraInfo metaInfo = currScope.getExtraInfo(); + final long currScopeId = currScope.scopeId(); + if (metaInfo instanceof MethodMetricsRootScopeInfo) { + ResolvedJavaMethod rootMethod = ((MethodMetricsRootScopeInfo) metaInfo).getRootMethod(); + if (metaInfo instanceof MethodMetricsInlineeScopeInfo) { + /* + * if we make use of a method filter(s) together with interception we get a problem + * with inlined methods and their scopes. Inlining will put the inlinee(s) on the + * debug scope context thus Debug.areMethodMetricsEnabled() will yield true if an + * inlinee matches a method filter. Thus we must make sure the root is defined as + * this means the root matched a method filter and therefore the inlinee can be + * safely recorded. + */ + if (TRACK_INLINED_SCOPES) { + if (threadEntries.get().get(rootMethod) != null) { + Debug.methodMetrics(rootMethod).addToMetric(value, "%s%s", INLINEE_PREFIX, metricName); + } + } + } else { + // when unboxing the thread local on access it must not be null + Long cachedId = interceptionCache.get(); + if (cachedId != null && cachedId == currScopeId) { + interceptionMetrics.get().addToMetric(value, metricName); + if (COUNT_CACHE) { + cacheHit.increment(); + } + } else { + // avoid the lookup over Debug.methodMetrics + final MethodMetricsImpl impl = (MethodMetricsImpl) getMethodMetrics(rootMethod); + impl.addToMetric(value, metricName); + // cache for next access + interceptionCache.set(currScopeId); + interceptionMetrics.set(impl); + if (COUNT_CACHE) { + cacheMiss.increment(); + } + } + } + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsInlineeScopeInfo.java 2016-12-07 13:49:07.386474643 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015, 2016, 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.debug.internal.method; + +import org.graalvm.compiler.debug.GraalDebugConfig; +import org.graalvm.compiler.debug.internal.DebugScope; +import org.graalvm.compiler.debug.internal.DebugScope.ExtraInfo; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class MethodMetricsInlineeScopeInfo extends MethodMetricsRootScopeInfo { + + MethodMetricsInlineeScopeInfo(ResolvedJavaMethod rootMethod) { + super(rootMethod); + } + + public static MethodMetricsInlineeScopeInfo create(ResolvedJavaMethod rootMethod) { + if (GraalDebugConfig.isGlobalMetricsInterceptedByMethodMetricsEnabled()) { + return new MethodMetricsInlineeScopeInfo(rootMethod); + } + return null; + } + + public static MethodMetricsInlineeScopeInfo create() { + if (GraalDebugConfig.isGlobalMetricsInterceptedByMethodMetricsEnabled()) { + ExtraInfo rootInfo = DebugScope.getInstance().getExtraInfo(); + if (rootInfo instanceof MethodMetricsRootScopeInfo) { + return new MethodMetricsInlineeScopeInfo(((MethodMetricsRootScopeInfo) rootInfo).getRootMethod()); + } + } + return null; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsPrinter.java 2016-12-07 13:49:07.651486292 -0800 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2015, 2016, 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.debug.internal.method; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.graalvm.compiler.debug.DebugMethodMetrics; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +/** + * Interface for printing a collection of method metrics (e.g. during shutdown). + */ +public interface MethodMetricsPrinter { + + class Options { + // @formatter:off + @Option(help = "Dump method metrics to stdout on shutdown.", type = OptionType.Debug) + public static final OptionValue MethodMeterPrintAscii = new OptionValue<>(false); + @Option(help = "Dump method metrics to the given file in CSV format on shutdown.", type = OptionType.Debug) + public static final OptionValue MethodMeterFile = new OptionValue<>(null); + // @formatter:on + } + + static boolean methodMetricsDumpingEnabled() { + return MethodMetricsPrinter.Options.MethodMeterPrintAscii.getValue() || MethodMetricsPrinter.Options.MethodMeterFile.getValue() != null; + } + + /** + * Prints the metrics to a destination specified by the implementor of this interface. + * + * @param metrics the set of collected method metrics during execution as defined by + * {@link DebugMethodMetrics}. + */ + void printMethodMetrics(Collection metrics); + + class MethodMetricsASCIIPrinter implements MethodMetricsPrinter { + private final OutputStream out; + + public MethodMetricsASCIIPrinter(OutputStream out) { + this.out = out; + } + + @Override + public void printMethodMetrics(Collection metrics) { + PrintStream p = new PrintStream(out); + for (DebugMethodMetrics m : metrics) { + ((MethodMetricsImpl) m).dumpASCII(p); + p.println(); + } + } + + } + + class MethodMetricsCompositePrinter implements MethodMetricsPrinter { + private final List printers; + + public MethodMetricsCompositePrinter(MethodMetricsPrinter... p) { + printers = Arrays.asList(p); + } + + public void registerPrinter(MethodMetricsPrinter printer) { + printers.add(printer); + } + + public void unregisterPrinter(MethodMetricsPrinter printer) { + printers.remove(printer); + } + + @Override + public void printMethodMetrics(Collection metrics) { + for (MethodMetricsPrinter p : printers) { + p.printMethodMetrics(metrics); + } + } + + } + + class MethodMetricsCSVFilePrinter implements MethodMetricsPrinter { + private FileOutputStream fw; + + public MethodMetricsCSVFilePrinter() { + try { + fw = new FileOutputStream(new File(Options.MethodMeterFile.getValue())); + } catch (IOException e) { + TTY.println("Cannot create file %s for method metrics dumping:%s", Options.MethodMeterFile.getValue(), e); + throw new Error(e); + } + } + + @Override + public void printMethodMetrics(Collection metrics) { + // mm printing creates simple (R-parsable) csv files in long data format + if (fw != null && metrics != null) { + try (PrintStream p = new PrintStream(fw)) { + for (DebugMethodMetrics m : metrics) { + if (m instanceof MethodMetricsImpl) { + ((MethodMetricsImpl) m).dumpCSV(p); + p.println(); + } + } + } + try { + fw.close(); + } catch (IOException e) { + throw new Error(e); + } + } + } + + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsRootScopeInfo.java 2016-12-07 13:49:07.920498117 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, 2016, 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.debug.internal.method; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.internal.DebugScope; +import org.graalvm.compiler.debug.internal.DebugScope.ExtraInfo; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class MethodMetricsRootScopeInfo implements ExtraInfo { + protected final ResolvedJavaMethod rootMethod; + + MethodMetricsRootScopeInfo(ResolvedJavaMethod rootMethod) { + this.rootMethod = rootMethod; + } + + public ResolvedJavaMethod getRootMethod() { + return rootMethod; + } + + public static MethodMetricsRootScopeInfo create(ResolvedJavaMethod rootMethod) { + return new MethodMetricsRootScopeInfo(rootMethod); + } + + /** + * Creates and returns a {@link org.graalvm.compiler.debug.Debug.Scope scope} iff there is no + * existing {@linkplain org.graalvm.compiler.debug.internal.DebugScope.ExtraInfo extraInfo} + * object of type {@link MethodMetricsRootScopeInfo} present in the current {@link DebugScope + * scope}. + * + * @param method + * @return a new {@link org.graalvm.compiler.debug.Debug.Scope scope} or {@code null} iff there + * is already an existing one on the scope + */ + public static Debug.Scope createRootScopeIfAbsent(ResolvedJavaMethod method) { + /* + * if the current compilation is not triggered from JVMCI we need a valid context root + * method for method metrics + */ + return DebugScope.getInstance().getExtraInfo() instanceof MethodMetricsRootScopeInfo ? null : Debug.methodMetricsScope("GraalCompilerRoot", MethodMetricsRootScopeInfo.create(method), true); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/overview.html 2016-12-07 13:49:08.184509722 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.graph.test project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeMapTest.java 2016-12-07 13:49:08.450521414 -0800 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2014, 2015, 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.graph.test; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.graph.Graph; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeMap; +import org.graalvm.compiler.nodeinfo.NodeInfo; + +public class NodeMapTest { + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static final class TestNode extends Node { + public static final NodeClass TYPE = NodeClass.create(TestNode.class); + + protected TestNode() { + super(TYPE); + } + } + + private Graph graph; + private TestNode[] nodes = new TestNode[100]; + private NodeMap map; + + @Before + public void before() { + // Need to initialize HotSpotGraalRuntime before any Node class is initialized. + Graal.getRuntime(); + + graph = new Graph(); + for (int i = 0; i < nodes.length; i++) { + nodes[i] = graph.add(new TestNode()); + } + map = new NodeMap<>(graph); + for (int i = 0; i < nodes.length; i += 2) { + map.set(nodes[i], i); + } + } + + @Test + public void testEmpty() { + NodeMap emptyMap = new NodeMap<>(graph); + for (TestNode node : nodes) { + assertEquals(null, emptyMap.get(node)); + } + } + + @Test + public void testSimple() { + for (int i = 0; i < nodes.length; i++) { + if ((i & 1) == 0) { + assertEquals((Integer) i, map.get(nodes[i])); + } else { + assertEquals(null, map.get(nodes[i])); + } + } + } + + @Test + public void testSimpleChanged() { + for (TestNode node : nodes) { + map.set(node, 1); + } + for (TestNode node : nodes) { + map.set(node, null); + } + for (int i = 0; i < nodes.length; i += 2) { + map.set(nodes[i], i); + } + + for (int i = 0; i < nodes.length; i++) { + if ((i & 1) == 0) { + assertEquals((Integer) i, map.get(nodes[i])); + } else { + assertEquals(null, map.get(nodes[i])); + } + } + } + + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean assertionsEnabled = false; + assert assertionsEnabled = true; + return assertionsEnabled; + } + + @Test + public void testNewGet() { + /* + * Failing here is not required, but if this behavior changes, usages of get need to be + * checked for compatibility. + */ + TestNode newNode = graph.add(new TestNode()); + try { + map.get(newNode); + fail("expected " + (assertionsEnabled() ? AssertionError.class.getSimpleName() : ArrayIndexOutOfBoundsException.class.getSimpleName())); + } catch (AssertionError ae) { + // thrown when assertions are enabled + } catch (ArrayIndexOutOfBoundsException e) { + // thrown when assertions are disabled + } + } + + @Test + public void testNewSet() { + /* + * Failing here is not required, but if this behavior changes, usages of set need to be + * checked for compatibility. + */ + TestNode newNode = graph.add(new TestNode()); + try { + map.set(newNode, 1); + fail("expected " + (assertionsEnabled() ? AssertionError.class.getSimpleName() : ArrayIndexOutOfBoundsException.class.getSimpleName())); + } catch (AssertionError ae) { + // thrown when assertions are enabled + } catch (ArrayIndexOutOfBoundsException e) { + // thrown when assertions are disabled + } + } + + @Test + public void testNewGetAndGrow() { + TestNode newNode = graph.add(new TestNode()); + assertEquals(null, map.getAndGrow(newNode)); + } + + @Test + public void testNewSetAndGrow() { + TestNode newNode = graph.add(new TestNode()); + map.setAndGrow(newNode, 1); + assertEquals((Integer) 1, map.get(newNode)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeUsagesTests.java 2016-12-07 13:49:08.715533063 -0800 @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2014, 2015, 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.graph.test; + +import static org.graalvm.compiler.graph.test.matchers.NodeIterableContains.contains; +import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isEmpty; +import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isNotEmpty; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +import org.graalvm.compiler.graph.Graph; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; + +public class NodeUsagesTests { + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static final class Def extends Node { + public static final NodeClass TYPE = NodeClass.create(Def.class); + + protected Def() { + super(TYPE); + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static final class Use extends Node { + public static final NodeClass TYPE = NodeClass.create(Use.class); + @Input Def in0; + @Input Def in1; + @Input Def in2; + + protected Use(Def in0, Def in1, Def in2) { + super(TYPE); + this.in0 = in0; + this.in1 = in1; + this.in2 = in2; + } + + } + + @Test + public void testReplaceAtUsages() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + + assertEquals(3, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtUsages(def1); + + assertThat(def0.usages(), isEmpty()); + + assertEquals(3, def1.getUsageCount()); + assertThat(def1.usages(), contains(use0)); + assertThat(def1.usages(), contains(use1)); + assertThat(def1.usages(), contains(use2)); + + assertThat(def1.usages(), isNotEmpty()); + } + + @Test + public void testReplaceAtUsagesWithPredicateAll() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + + assertEquals(3, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtMatchingUsages(def1, u -> true); + + assertThat(def0.usages(), isEmpty()); + + assertEquals(3, def1.getUsageCount()); + assertThat(def1.usages(), contains(use0)); + assertThat(def1.usages(), contains(use1)); + assertThat(def1.usages(), contains(use2)); + + assertThat(def1.usages(), isNotEmpty()); + } + + @Test + public void testReplaceAtUsagesWithPredicateNone() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + + assertEquals(3, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtMatchingUsages(def1, u -> false); + + assertThat(def1.usages(), isEmpty()); + + assertEquals(3, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + } + + @Test + public void testReplaceAtUsagesWithPredicate1() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + + assertEquals(3, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtMatchingUsages(def1, u -> u == use1); + + assertEquals(1, def1.getUsageCount()); + assertThat(def1.usages(), contains(use1)); + + assertThat(def1.usages(), isNotEmpty()); + + assertEquals(2, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + } + + @Test + public void testReplaceAtUsagesWithPredicate2() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + + assertEquals(3, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtMatchingUsages(def1, u -> u == use2); + + assertEquals(1, def1.getUsageCount()); + assertThat(def1.usages(), contains(use2)); + + assertThat(def1.usages(), isNotEmpty()); + + assertEquals(2, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + + assertThat(def0.usages(), isNotEmpty()); + } + + @Test + public void testReplaceAtUsagesWithPredicate0() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + + assertEquals(3, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtMatchingUsages(def1, u -> u == use0); + + assertEquals(1, def1.getUsageCount()); + assertThat(def1.usages(), contains(use0)); + + assertThat(def1.usages(), isNotEmpty()); + + assertEquals(2, def0.getUsageCount()); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + } + + @Test + public void testReplaceAtUsagesWithPredicate02() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + + assertEquals(3, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtMatchingUsages(def1, u -> u != use1); + + assertEquals(1, def0.getUsageCount()); + assertThat(def0.usages(), contains(use1)); + + assertThat(def0.usages(), isNotEmpty()); + + assertEquals(2, def1.getUsageCount()); + assertThat(def1.usages(), contains(use0)); + assertThat(def1.usages(), contains(use2)); + + assertThat(def1.usages(), isNotEmpty()); + } + + @Test + public void testReplaceAtUsagesWithPredicate023() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + Use use3 = graph.add(new Use(null, null, def0)); + + assertEquals(4, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + assertThat(def0.usages(), contains(use3)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtMatchingUsages(def1, u -> u != use1); + + assertEquals(1, def0.getUsageCount()); + assertThat(def0.usages(), contains(use1)); + + assertThat(def0.usages(), isNotEmpty()); + + assertEquals(3, def1.getUsageCount()); + assertThat(def1.usages(), contains(use0)); + assertThat(def1.usages(), contains(use2)); + assertThat(def1.usages(), contains(use3)); + + assertThat(def1.usages(), isNotEmpty()); + } + + @Test + public void testReplaceAtUsagesWithPredicate013() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + Use use3 = graph.add(new Use(null, null, def0)); + + assertEquals(4, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + assertThat(def0.usages(), contains(use3)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtMatchingUsages(def1, u -> u != use2); + + assertEquals(1, def0.getUsageCount()); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + + assertEquals(3, def1.getUsageCount()); + assertThat(def1.usages(), contains(use0)); + assertThat(def1.usages(), contains(use1)); + assertThat(def1.usages(), contains(use3)); + + assertThat(def1.usages(), isNotEmpty()); + } + + @Test + public void testReplaceAtUsagesWithPredicate203() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + Use use3 = graph.add(new Use(null, null, def0)); + + assertEquals(4, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + assertThat(def0.usages(), contains(use3)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtMatchingUsages(def1, u -> u == use2); + + assertEquals(1, def1.getUsageCount()); + assertThat(def1.usages(), contains(use2)); + + assertThat(def1.usages(), isNotEmpty()); + + assertEquals(3, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use3)); + + assertThat(def0.usages(), isNotEmpty()); + } + + @Test + public void testReplaceAtUsagesWithPredicate01() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + + assertEquals(3, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtMatchingUsages(def1, u -> u != use2); + + assertEquals(1, def0.getUsageCount()); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + + assertEquals(2, def1.getUsageCount()); + assertThat(def1.usages(), contains(use0)); + assertThat(def1.usages(), contains(use1)); + + assertThat(def1.usages(), isNotEmpty()); + } + + @Test + public void testReplaceAtUsagesWithPredicate12() { + Graph graph = new Graph(); + Def def0 = graph.add(new Def()); + Def def1 = graph.add(new Def()); + Use use0 = graph.add(new Use(def0, null, null)); + Use use1 = graph.add(new Use(null, def0, null)); + Use use2 = graph.add(new Use(null, null, def0)); + + assertEquals(3, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + assertThat(def0.usages(), contains(use1)); + assertThat(def0.usages(), contains(use2)); + + assertThat(def0.usages(), isNotEmpty()); + assertThat(def1.usages(), isEmpty()); + + def0.replaceAtMatchingUsages(def1, u -> u != use0); + + assertEquals(1, def0.getUsageCount()); + assertThat(def0.usages(), contains(use0)); + + assertThat(def0.usages(), isNotEmpty()); + + assertEquals(2, def1.getUsageCount()); + assertThat(def1.usages(), contains(use1)); + assertThat(def1.usages(), contains(use2)); + + assertThat(def1.usages(), isNotEmpty()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeValidationChecksTest.java 2016-12-07 13:49:08.981544756 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, 2015, 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.graph.test; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.graph.Graph; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; + +public class NodeValidationChecksTest { + + @NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) + static final class TestNode extends Node { + public static final NodeClass TYPE = NodeClass.create(TestNode.class); + + @Input TestNode input; + @Successor TestNode successor; + + protected TestNode(TestNode input, TestNode successor) { + super(TYPE); + this.input = input; + this.successor = successor; + } + } + + @Test + public void testInputNotAlive() { + Graph graph = new Graph(); + TestNode node = new TestNode(null, null); + try { + graph.add(new TestNode(node, null)); + Assert.fail("Exception expected."); + } catch (AssertionError e) { + Assert.assertTrue(e.getMessage().contains("Input")); + Assert.assertTrue(e.getMessage().contains("not alive")); + } + } + + @Test + public void testSuccessorNotAlive() { + Graph graph = new Graph(); + TestNode node = new TestNode(null, null); + try { + graph.add(new TestNode(null, node)); + Assert.fail("Exception expected."); + } catch (AssertionError e) { + Assert.assertTrue(e.getMessage().contains("Successor")); + Assert.assertTrue(e.getMessage().contains("not alive")); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TestNodeInterface.java 2016-12-07 13:49:09.247556449 -0800 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011, 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.graph.test; + +public interface TestNodeInterface { + + String getName(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TypedNodeIteratorTest.java 2016-12-07 13:49:09.513568142 -0800 @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2011, 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.graph.test; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Iterator; + +import org.junit.Test; + +import org.graalvm.compiler.graph.Graph; +import org.graalvm.compiler.graph.IterableNodeType; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; + +public class TypedNodeIteratorTest { + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static final class TestNode extends Node implements IterableNodeType, TestNodeInterface { + + public static final NodeClass TYPE = NodeClass.create(TestNode.class); + protected final String name; + + protected TestNode(String name) { + super(TYPE); + this.name = name; + } + + @Override + public String getName() { + return name; + } + } + + @Test + public void singleNodeTest() { + Graph graph = new Graph(); + graph.add(new TestNode("a")); + assertTrue(graph.hasNode(TestNode.TYPE)); + assertEquals("a", toString(graph.getNodes(TestNode.TYPE))); + } + + @Test + public void deletingNodeTest() { + TestNode testNode = new TestNode("a"); + Graph graph = new Graph(); + graph.add(testNode); + testNode.safeDelete(); + assertEquals("", toString(graph.getNodes(TestNode.TYPE))); + } + + @Test + public void deleteAndAddTest() { + TestNode testNode = new TestNode("b"); + Graph graph = new Graph(); + graph.add(new TestNode("a")); + graph.add(testNode); + testNode.safeDelete(); + assertEquals("a", toString(graph.getNodes(TestNode.TYPE))); + graph.add(new TestNode("c")); + assertEquals("ac", toString(graph.getNodes(TestNode.TYPE))); + } + + @Test + public void iteratorBehaviorTest() { + Graph graph = new Graph(); + graph.add(new TestNode("a")); + Iterator iterator = graph.getNodes(TestNode.TYPE).iterator(); + assertTrue(iterator.hasNext()); + assertEquals("a", iterator.next().getName()); + assertFalse(iterator.hasNext()); + graph.add(new TestNode("b")); + assertTrue(iterator.hasNext()); + assertEquals("b", iterator.next().getName()); + assertFalse(iterator.hasNext()); + TestNode c = new TestNode("c"); + graph.add(c); + assertTrue(iterator.hasNext()); + c.safeDelete(); + assertFalse(iterator.hasNext()); + } + + @Test + public void complicatedIterationTest() { + Graph graph = new Graph(); + graph.add(new TestNode("a")); + for (TestNode tn : graph.getNodes(TestNode.TYPE)) { + String name = tn.getName(); + for (int i = 0; i < name.length(); ++i) { + char c = name.charAt(i); + if (c == 'a') { + tn.safeDelete(); + graph.add(new TestNode("b")); + graph.add(new TestNode("c")); + } else if (c == 'b') { + tn.safeDelete(); + } else if (c == 'c') { + graph.add(new TestNode("d")); + graph.add(new TestNode("e")); + graph.add(new TestNode("d")); + graph.add(new TestNode("e")); + graph.add(new TestNode("e")); + graph.add(new TestNode("d")); + graph.add(new TestNode("e")); + graph.add(new TestNode("d")); + } else if (c == 'd') { + for (TestNode tn2 : graph.getNodes(TestNode.TYPE)) { + if (tn2.getName().equals("e")) { + tn2.safeDelete(); + } else if (tn2.getName().equals("c")) { + tn2.safeDelete(); + } + } + } else if (c == 'e') { + fail("All e nodes must have been deleted by visiting the d node"); + } + } + } + assertEquals("dddd", toString(graph.getNodes(TestNode.TYPE))); + } + + @Test + public void addingNodeDuringIterationTest() { + Graph graph = new Graph(); + graph.add(new TestNode("a")); + StringBuilder sb = new StringBuilder(); + int z = 0; + for (TestNode tn : graph.getNodes(TestNode.TYPE)) { + if (z == 0) { + graph.add(new TestNode("b")); + } + sb.append(tn.getName()); + z++; + } + assertEquals(2, z); + assertEquals("ab", sb.toString()); + z = 0; + for (TestNode tn : graph.getNodes(TestNode.TYPE)) { + if (z == 0) { + graph.add(new TestNode("c")); + } + assertNotNull(tn); + z++; + } + assertEquals(3, z); + } + + public static String toString(Iterable nodes) { + StringBuilder sb = new StringBuilder(); + for (TestNodeInterface tn : nodes) { + sb.append(tn.getName()); + } + return sb.toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TypedNodeIteratorTest2.java 2016-12-07 13:49:09.779579835 -0800 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2013, 2015, 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.graph.test; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.graph.Graph; +import org.graalvm.compiler.graph.IterableNodeType; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; + +public class TypedNodeIteratorTest2 { + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class NodeA extends Node implements TestNodeInterface { + + public static final NodeClass TYPE = NodeClass.create(NodeA.class); + protected final String name; + + protected NodeA(String name) { + this(TYPE, name); + } + + protected NodeA(NodeClass c, String name) { + super(c); + this.name = name; + } + + @Override + public String getName() { + return name; + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class NodeB extends NodeA implements IterableNodeType { + public static final NodeClass TYPE = NodeClass.create(NodeB.class); + + protected NodeB(String name) { + this(TYPE, name); + } + + protected NodeB(NodeClass c, String name) { + super(c, name); + } + + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static class NodeC extends NodeB { + public static final NodeClass TYPE = NodeClass.create(NodeC.class); + + protected NodeC(String name) { + this(TYPE, name); + } + + protected NodeC(NodeClass c, String name) { + super(c, name); + } + + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + static final class NodeD extends NodeC { + public static final NodeClass TYPE = NodeClass.create(NodeD.class); + + protected NodeD(String name) { + super(TYPE, name); + } + + } + + @Test + public void simpleSubclassTest() { + Graph graph = new Graph(); + graph.add(new NodeB("b")); + graph.add(new NodeD("d")); + + Assert.assertEquals("bd", TypedNodeIteratorTest.toString(graph.getNodes(NodeB.TYPE))); + Assert.assertEquals("d", TypedNodeIteratorTest.toString(graph.getNodes(NodeD.TYPE))); + } + + @Test + public void addingNodeDuringIterationTest() { + Graph graph = new Graph(); + graph.add(new NodeB("b1")); + NodeD d1 = graph.add(new NodeD("d1")); + StringBuilder sb = new StringBuilder(); + for (NodeB tn : graph.getNodes(NodeB.TYPE)) { + if (tn == d1) { + graph.add(new NodeB("b2")); + } + sb.append(tn.getName()); + } + assertEquals("b1d1b2", sb.toString()); + for (NodeB tn : graph.getNodes(NodeB.TYPE)) { + if (tn == d1) { + graph.add(new NodeB("b3")); + } + assertNotNull(tn); + } + assertEquals(4, graph.getNodes(NodeB.TYPE).count()); + assertEquals(1, graph.getNodes(NodeD.TYPE).count()); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableContains.java 2016-12-07 13:49:10.044591483 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014, 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.graph.test.matchers; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.iterators.NodeIterable; + +public class NodeIterableContains extends TypeSafeDiagnosingMatcher> { + private T node; + + public NodeIterableContains(T node) { + this.node = node; + } + + @Override + public void describeTo(Description description) { + description.appendText("is a NodeIterable containing ").appendValue(node); + } + + public static NodeIterableContains contains(T node) { + return new NodeIterableContains<>(node); + } + + @Override + protected boolean matchesSafely(NodeIterable iterable, Description mismatchDescription) { + mismatchDescription.appendText("is a NodeIterable that does not contain ").appendValue(node); + return iterable.contains(node); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableCount.java 2016-12-07 13:49:10.310603176 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014, 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.graph.test.matchers; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +import org.graalvm.compiler.graph.iterators.NodeIterable; + +public class NodeIterableCount extends TypeSafeDiagnosingMatcher> { + private int count; + + public NodeIterableCount(int count) { + this.count = count; + } + + @Override + public void describeTo(Description description) { + description.appendText("is a NodeIterable containing ").appendValue(count).appendText(" elements"); + } + + public static NodeIterableCount hasCount(int count) { + return new NodeIterableCount(count); + } + + @Override + protected boolean matchesSafely(NodeIterable iterable, Description mismatchDescription) { + mismatchDescription.appendText("is a NodeIterable containing ").appendValue(iterable.count()).appendText(" elements"); + return iterable.count() == count; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableIsEmpty.java 2016-12-07 13:49:10.577614913 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014, 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.graph.test.matchers; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.hamcrest.core.IsNot; + +import org.graalvm.compiler.graph.iterators.NodeIterable; + +public class NodeIterableIsEmpty extends TypeSafeDiagnosingMatcher> { + + private static final NodeIterableIsEmpty INSTANCE = new NodeIterableIsEmpty(); + + @Override + public boolean matchesSafely(NodeIterable iterable, Description mismatchDescription) { + mismatchDescription.appendText("is a non-empty NodeIterable"); + return iterable.isEmpty(); + } + + @Override + public void describeTo(Description description) { + description.appendText("is an empty NodeIterable"); + } + + public static Matcher> isEmpty() { + return INSTANCE; + } + + public static Matcher> isNotEmpty() { + return IsNot.not(INSTANCE); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml 2016-12-07 13:49:10.842626562 -0800 @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/overview.html 2016-12-07 13:49:11.106638166 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.graph project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java 2016-12-07 13:49:11.372649859 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 2015, 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.graph; + +import java.util.Map; +import java.util.function.Consumer; + +/** + * This class is a container of a graph that needs to be readonly and optionally a lazily created + * mutable copy of the graph. + */ +public final class CachedGraph { + + private final G readonlyCopy; + private G mutableCopy; + + private CachedGraph(G readonlyCopy, G mutableCopy) { + this.readonlyCopy = readonlyCopy; + this.mutableCopy = mutableCopy; + } + + public static CachedGraph fromReadonlyCopy(G graph) { + return new CachedGraph<>(graph, null); + } + + public static CachedGraph fromMutableCopy(G graph) { + return new CachedGraph<>(graph, graph); + } + + public G getReadonlyCopy() { + if (hasMutableCopy()) { + return mutableCopy; + } + return readonlyCopy; + } + + public boolean hasMutableCopy() { + return mutableCopy != null; + } + + @SuppressWarnings("unchecked") + public G getMutableCopy(Consumer> duplicationMapCallback) { + if (!hasMutableCopy()) { + mutableCopy = (G) readonlyCopy.copy(duplicationMapCallback); + } + return mutableCopy; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/DefaultNodeCollectionsProvider.java 2016-12-07 13:49:11.638661552 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, 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.graph; + +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; + +import org.graalvm.compiler.api.collections.DefaultCollectionsProvider; + +/** + * A default implementation of {@link NodeCollectionsProvider} that creates standard JDK collection + * class objects. + */ +public class DefaultNodeCollectionsProvider extends DefaultCollectionsProvider implements NodeCollectionsProvider { + + @Override + public Set newNodeIdentitySet() { + return Collections.newSetFromMap(newNodeIdentityMap()); + } + + @Override + public Map newNodeIdentityMap() { + return new IdentityHashMap<>(); + } + + @Override + public Map newNodeIdentityMap(int expectedMaxSize) { + return new IdentityHashMap<>(expectedMaxSize); + } + + @Override + public Map newNodeIdentityMap(Map initFrom) { + return new IdentityHashMap<>(initFrom); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Edges.java 2016-12-07 13:49:11.902673157 -0800 @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2014, 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.graph; + +import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled; +import static org.graalvm.compiler.graph.Node.NOT_ITERABLE; +import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.graalvm.compiler.core.common.Fields; +import org.graalvm.compiler.core.common.FieldsScanner; +import org.graalvm.compiler.graph.NodeClass.EdgeInfo; + +/** + * Describes {@link Node} fields representing the set of inputs for the node or the set of the + * node's successors. + */ +public abstract class Edges extends Fields { + + /** + * Constants denoting whether a set of edges are inputs or successors. + */ + public enum Type { + Inputs, + Successors; + } + + private final int directCount; + private final Type type; + + public Edges(Type type, int directCount, ArrayList edges) { + super(edges); + this.type = type; + this.directCount = directCount; + } + + public static void translateInto(Edges edges, ArrayList infos) { + for (int index = 0; index < edges.getCount(); index++) { + infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index), edges.getDeclaringClass(index))); + } + } + + public static Node getNodeUnsafe(Node node, long offset) { + return (Node) UNSAFE.getObject(node, offset); + } + + @SuppressWarnings("unchecked") + public static NodeList getNodeListUnsafe(Node node, long offset) { + return (NodeList) UNSAFE.getObject(node, offset); + } + + private static void putNodeUnsafe(Node node, long offset, Node value) { + UNSAFE.putObject(node, offset, value); + } + + private static void putNodeListUnsafe(Node node, long offset, NodeList value) { + UNSAFE.putObject(node, offset, value); + } + + /** + * Get the number of direct edges represented by this object. A direct edge goes directly to + * another {@link Node}. An indirect edge goes via a {@link NodeList}. + */ + public int getDirectCount() { + return directCount; + } + + /** + * Gets the {@link Node} at the end point of a {@linkplain #getDirectCount() direct} edge. + * + * @param node one end point of the edge + * @param index the index of a non-list the edge (must be less than {@link #getDirectCount()}) + * @return the Node at the other edge of the requested edge + */ + public static Node getNode(Node node, long[] offsets, int index) { + return getNodeUnsafe(node, offsets[index]); + } + + /** + * Gets the {@link NodeList} at the end point of a {@linkplain #getDirectCount() direct} edge. + * + * @param node one end point of the edge + * @param index the index of a non-list the edge (must be equal to or greater than + * {@link #getDirectCount()}) + * @return the {@link NodeList} at the other edge of the requested edge + */ + public static NodeList getNodeList(Node node, long[] offsets, int index) { + return getNodeListUnsafe(node, offsets[index]); + } + + /** + * Clear edges in a given node. This is accomplished by setting {@linkplain #getDirectCount() + * direct} edges to null and replacing the lists containing indirect edges with new lists. The + * latter is important so that this method can be used to clear the edges of cloned nodes. + * + * @param node the node whose edges are to be cleared + */ + public void clear(Node node) { + final long[] curOffsets = this.offsets; + final Type curType = this.type; + int index = 0; + int curDirectCount = getDirectCount(); + while (index < curDirectCount) { + initializeNode(node, index++, null); + } + int curCount = getCount(); + while (index < curCount) { + NodeList list = getNodeList(node, curOffsets, index); + if (list != null) { + int size = list.initialSize; + NodeList newList = curType == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size); + + // replacing with a new list object is the expected behavior! + initializeList(node, index, newList); + } + index++; + } + } + + /** + * Initializes the list edges in a given node based on the size of the list edges in a prototype + * node. + * + * @param node the node whose list edges are to be initialized + * @param prototype the node whose list edge sizes are used when creating new edge lists + */ + public void initializeLists(Node node, Node prototype) { + int index = getDirectCount(); + final long[] curOffsets = this.offsets; + final Edges.Type curType = this.type; + while (index < getCount()) { + NodeList list = getNodeList(prototype, curOffsets, index); + if (list != null) { + int size = list.initialSize; + NodeList newList = curType == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size); + initializeList(node, index, newList); + } + index++; + } + } + + /** + * Copies edges from {@code fromNode} to {@code toNode}. The nodes are expected to be of the + * exact same type. + * + * @param fromNode the node from which the edges should be copied. + * @param toNode the node to which the edges should be copied. + */ + public void copy(Node fromNode, Node toNode) { + assert fromNode != toNode; + assert fromNode.getNodeClass().getClazz() == toNode.getNodeClass().getClazz(); + int index = 0; + final long[] curOffsets = this.offsets; + final Type curType = this.type; + int curDirectCount = getDirectCount(); + while (index < curDirectCount) { + initializeNode(toNode, index, getNode(fromNode, curOffsets, index)); + index++; + } + int curCount = getCount(); + while (index < curCount) { + NodeList list = getNodeList(toNode, curOffsets, index); + NodeList fromList = getNodeList(fromNode, curOffsets, index); + if (list == null || list == fromList) { + list = curType == Edges.Type.Inputs ? new NodeInputList<>(toNode, fromList) : new NodeSuccessorList<>(toNode, fromList); + initializeList(toNode, index, list); + } else { + list.copy(fromList); + } + index++; + } + } + + @Override + public void set(Object node, int index, Object value) { + throw new IllegalArgumentException("Cannot call set on " + this); + } + + /** + * Sets the value of a given edge without notifying the new and old nodes on the other end of + * the edge of the change. + * + * @param node the node whose edge is to be updated + * @param index the index of the edge (between 0 and {@link #getCount()}) + * @param value the node to be written to the edge + */ + public void initializeNode(Node node, int index, Node value) { + verifyUpdateValid(node, index, value); + putNodeUnsafe(node, offsets[index], value); + } + + public void initializeList(Node node, int index, NodeList value) { + verifyUpdateValid(node, index, value); + putNodeListUnsafe(node, offsets[index], value); + } + + private void verifyUpdateValid(Node node, int index, Object newValue) { + if (newValue != null && !getType(index).isAssignableFrom(newValue.getClass())) { + throw new IllegalArgumentException("Can not assign " + newValue.getClass() + " to " + getType(index) + " in " + node); + } + } + + /** + * Sets the value of a given edge and notifies the new and old nodes on the other end of the + * edge of the change. + * + * @param node the node whose edge is to be updated + * @param index the index of the edge (between 0 and {@link #getCount()}) + * @param value the node to be written to the edge + */ + public void setNode(Node node, int index, Node value) { + assert index < directCount; + Node old = getNodeUnsafe(node, offsets[index]); + initializeNode(node, index, value); + update(node, old, value); + } + + public abstract void update(Node node, Node oldValue, Node newValue); + + public boolean contains(Node node, Node value) { + final long[] curOffsets = this.offsets; + for (int i = 0; i < directCount; i++) { + if (getNode(node, curOffsets, i) == value) { + return true; + } + } + for (int i = directCount; i < getCount(); i++) { + NodeList curList = getNodeList(node, curOffsets, i); + if (curList != null && curList.contains(value)) { + return true; + } + } + return false; + } + + /** + * An iterator that will iterate over edges. + * + * An iterator of this type will not return null values, unless edges are modified concurrently. + * Concurrent modifications are detected by an assertion on a best-effort basis. + */ + private static class EdgesIterator implements Iterator { + protected final Node node; + protected final Edges edges; + protected int index; + protected int subIndex; + protected boolean needsForward; + protected final int directCount; + protected final long[] offsets; + + /** + * Creates an iterator that will iterate over some given edges in a given node. + */ + EdgesIterator(Node node, Edges edges) { + this.node = node; + this.edges = edges; + index = NOT_ITERABLE; + subIndex = 0; + needsForward = true; + this.directCount = edges.getDirectCount(); + this.offsets = edges.getOffsets(); + } + + void forward() { + needsForward = false; + if (index < directCount) { + index++; + if (index < directCount) { + return; + } + } else { + subIndex++; + } + if (index < edges.getCount()) { + forwardNodeList(); + } + } + + private void forwardNodeList() { + do { + NodeList list = Edges.getNodeList(node, offsets, index); + if (list != null) { + if (subIndex < list.size()) { + return; + } + } + subIndex = 0; + index++; + } while (index < edges.getCount()); + } + + @Override + public boolean hasNext() { + if (needsForward) { + forward(); + } + return index < edges.getCount(); + } + + @Override + public Position next() { + if (needsForward) { + forward(); + } + needsForward = true; + if (index < directCount) { + return new Position(edges, index, NOT_ITERABLE); + } else { + return new Position(edges, index, subIndex); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + private static final class EdgesWithModCountIterator extends EdgesIterator { + private final int modCount; + + private EdgesWithModCountIterator(Node node, Edges edges) { + super(node, edges); + assert isModificationCountsEnabled(); + this.modCount = node.modCount(); + } + + @Override + public boolean hasNext() { + try { + return super.hasNext(); + } finally { + assert modCount == node.modCount() : "must not be modified"; + } + } + + @Override + public Position next() { + try { + return super.next(); + } finally { + assert modCount == node.modCount() : "must not be modified"; + } + } + } + + public Iterable getPositionsIterable(final Node node) { + return new Iterable() { + + @Override + public Iterator iterator() { + if (isModificationCountsEnabled()) { + return new EdgesWithModCountIterator(node, Edges.this); + } else { + return new EdgesIterator(node, Edges.this); + } + } + }; + } + + public Type type() { + return type; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/GraalGraphError.java 2016-12-07 13:49:12.168684849 -0800 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2011, 2014, 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.graph; + +import org.graalvm.compiler.debug.GraalError; + +/** + * This error is the graph/node aware extension of {@link GraalError}. + */ +public class GraalGraphError extends GraalError { + + private static final long serialVersionUID = -989290015525497919L; + private Node node; + private Graph graph; + + /** + * This constructor creates a {@link GraalGraphError} with a message assembled via + * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to + * always generate the same output. + * + * @param msg the message that will be associated with the error, in String.format syntax + * @param args parameters to String.format - parameters that implement {@link Iterable} will be + * expanded into a [x, x, ...] representation. + */ + public GraalGraphError(String msg, Object... args) { + super(msg, args); + } + + /** + * This constructor creates a {@link GraalGraphError} for a given causing Throwable instance. + * + * @param cause the original exception that contains additional information on this error + */ + public GraalGraphError(Throwable cause) { + super(cause); + } + + /** + * This constructor creates a {@link GraalGraphError} from a given GraalError instance. + * + * @param e the original GraalError + */ + protected GraalGraphError(GraalError e) { + super(e); + if (e instanceof GraalGraphError) { + node = ((GraalGraphError) e).node; + graph = ((GraalGraphError) e).graph; + } + } + + /** + * Adds a graph to the context of this VerificationError. The first graph added via this method + * will be returned by {@link #graph()}. + * + * @param newGraph the graph which is in a incorrect state, if the verification error was not + * caused by a specific node + */ + GraalGraphError addContext(Graph newGraph) { + if (newGraph != this.graph) { + addContext("graph", newGraph); + if (this.graph == null) { + this.graph = newGraph; + } + } + return this; + } + + /** + * Adds a node to the context of this VerificationError. The first node added via this method + * will be returned by {@link #node()}. + * + * @param newNode the node which is in a incorrect state, if the verification error was caused + * by a node + */ + public GraalGraphError addContext(Node newNode) { + if (newNode != this.node) { + addContext("node", newNode); + if (this.node == null) { + this.node = newNode; + } + } + return this; + } + + /** + * Transform a GraalError into a GraalGraphInternalError and add a graph to the context. + * + * @param e the previous error + * @param newGraph the graph which is in a incorrect state, if the verification error was not + * caused by a specific node + */ + public static GraalGraphError transformAndAddContext(GraalError e, Graph newGraph) { + GraalGraphError graphError; + if (e instanceof GraalGraphError) { + graphError = (GraalGraphError) e; + } else { + graphError = new GraalGraphError(e); + } + return graphError.addContext(newGraph); + } + + /** + * Transform a GraalError into a GraalGraphInternalError and add a node to the context. + * + * @param e the previous error + * @param newNode the node which is in a incorrect state, if the verification error was caused + * by a node + */ + public static GraalGraphError transformAndAddContext(GraalError e, Node newNode) { + GraalGraphError graphError; + if (e instanceof GraalGraphError) { + graphError = (GraalGraphError) e; + } else { + graphError = new GraalGraphError(e); + } + return graphError.addContext(newNode); + } + + public Node node() { + return node; + } + + public Graph graph() { + return graph; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java 2016-12-07 13:49:12.432696454 -0800 @@ -0,0 +1,1113 @@ +/* + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.graph; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.function.Consumer; + +import org.graalvm.compiler.core.common.CollectionsFactory; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.DebugTimer; +import org.graalvm.compiler.debug.Fingerprint; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node.ValueNumberable; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +/** + * This class is a graph container, it contains the set of nodes that belong to this graph. + */ +public class Graph { + + public static class Options { + @Option(help = "Verify graphs often during compilation when assertions are turned on", type = OptionType.Debug)// + public static final OptionValue VerifyGraalGraphs = new OptionValue<>(true); + @Option(help = "Perform expensive verification of graph inputs, usages, successors and predecessors", type = OptionType.Debug)// + public static final OptionValue VerifyGraalGraphEdges = new OptionValue<>(false); + @Option(help = "Graal graph compression is performed when percent of live nodes falls below this value", type = OptionType.Debug)// + public static final OptionValue GraphCompressionThreshold = new OptionValue<>(70); + @Option(help = "Use Unsafe to clone graph nodes thus avoiding copying fields that will be re-initialized anyway", type = OptionType.Debug)// + public static final OptionValue CloneNodesWithUnsafe = new OptionValue<>(true); + } + + public final String name; + + /** + * The set of nodes in the graph, ordered by {@linkplain #register(Node) registration} time. + */ + Node[] nodes; + + /** + * Source information to associate with newly created nodes. + */ + NodeSourcePosition currentNodeSourcePosition; + + /** + * Records if updating of node source information is required when performing inlining. + */ + boolean seenNodeSourcePosition; + + /** + * The number of valid entries in {@link #nodes}. + */ + int nodesSize; + + /** + * Records the modification count for nodes. This is only used in assertions. + */ + private int[] nodeModCounts; + + /** + * Records the modification count for nodes' usage lists. This is only used in assertions. + */ + private int[] nodeUsageModCounts; + + // these two arrays contain one entry for each NodeClass, indexed by NodeClass.iterableId. + // they contain the first and last pointer to a linked list of all nodes with this type. + private final ArrayList iterableNodesFirst; + private final ArrayList iterableNodesLast; + + private int nodesDeletedSinceLastCompression; + private int nodesDeletedBeforeLastCompression; + + /** + * The number of times this graph has been compressed. + */ + int compressions; + + NodeEventListener nodeEventListener; + + /** + * Used to global value number {@link ValueNumberable} {@linkplain NodeClass#isLeafNode() leaf} + * nodes. + */ + private final HashMap cachedLeafNodes = CollectionsFactory.newMap(); + + /* + * Indicates that the graph should no longer be modified. Frozen graphs can be used my multiple + * threads so it's only safe to read them. + */ + private boolean isFrozen = false; + + /** + * Entry in {@link Graph#cachedLeafNodes}. + */ + private static final class CacheEntry { + + private final Node node; + + CacheEntry(Node node) { + assert node.getNodeClass().valueNumberable(); + assert node.getNodeClass().isLeafNode(); + this.node = node; + } + + @Override + public int hashCode() { + return node.getNodeClass().valueNumber(node); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CacheEntry) { + CacheEntry other = (CacheEntry) obj; + if (other.node.getClass() == node.getClass()) { + return node.valueEquals(other.node); + } + } + return false; + } + + @Override + public String toString() { + return node.toString(); + } + } + + private class NodeSourcePositionScope implements DebugCloseable { + private final NodeSourcePosition previous; + + NodeSourcePositionScope(NodeSourcePosition sourcePosition) { + previous = currentNodeSourcePosition; + currentNodeSourcePosition = sourcePosition; + } + + @Override + public void close() { + currentNodeSourcePosition = previous; + } + } + + public NodeSourcePosition currentNodeSourcePosition() { + return currentNodeSourcePosition; + } + + /** + * Opens a scope in which the source information from {@code node} is copied into nodes created + * within the scope. If {@code node} has no source information information, no scope is opened + * and {@code null} is returned. + * + * @return a {@link DebugCloseable} for managing the opened scope or {@code null} if no scope + * was opened + */ + public DebugCloseable withNodeSourcePosition(Node node) { + return withNodeSourcePosition(node.sourcePosition); + } + + /** + * Opens a scope in which {@code sourcePosition} is copied into nodes created within the scope. + * If {@code sourcePosition == null}, no scope is opened and {@code null} is returned. + * + * @return a {@link DebugCloseable} for managing the opened scope or {@code null} if no scope + * was opened + */ + public DebugCloseable withNodeSourcePosition(NodeSourcePosition sourcePosition) { + return sourcePosition != null ? new NodeSourcePositionScope(sourcePosition) : null; + } + + /** + * Opens a scope in which newly created nodes do not get any source information added. + * + * @return a {@link DebugCloseable} for managing the opened scope + */ + public DebugCloseable withoutNodeSourcePosition() { + return new NodeSourcePositionScope(null); + } + + /** + * Determines if this graph might contain nodes with source information. This is mainly useful + * to short circuit logic for updating those positions after inlining since that requires + * visiting every node in the graph. + */ + public boolean mayHaveNodeSourcePosition() { + assert seenNodeSourcePosition || verifyHasNoSourcePosition(); + return seenNodeSourcePosition; + } + + private boolean verifyHasNoSourcePosition() { + for (Node node : getNodes()) { + assert node.getNodeSourcePosition() == null; + } + return true; + } + + /** + * Creates an empty Graph with no name. + */ + public Graph() { + this(null); + } + + /** + * We only want the expensive modification count tracking when assertions are enabled for the + * {@link Graph} class. + */ + @SuppressWarnings("all") + public static boolean isModificationCountsEnabled() { + boolean enabled = false; + assert enabled = true; + return enabled; + } + + private static final int INITIAL_NODES_SIZE = 32; + + /** + * Creates an empty Graph with a given name. + * + * @param name the name of the graph, used for debugging purposes + */ + public Graph(String name) { + nodes = new Node[INITIAL_NODES_SIZE]; + iterableNodesFirst = new ArrayList<>(NodeClass.allocatedNodeIterabledIds()); + iterableNodesLast = new ArrayList<>(NodeClass.allocatedNodeIterabledIds()); + this.name = name; + if (isModificationCountsEnabled()) { + nodeModCounts = new int[INITIAL_NODES_SIZE]; + nodeUsageModCounts = new int[INITIAL_NODES_SIZE]; + } + } + + int extractOriginalNodeId(Node node) { + int id = node.id; + if (id <= Node.DELETED_ID_START) { + id = Node.DELETED_ID_START - id; + } + return id; + } + + int modCount(Node node) { + int id = extractOriginalNodeId(node); + if (id >= 0 && id < nodeModCounts.length) { + return nodeModCounts[id]; + } + return 0; + } + + void incModCount(Node node) { + int id = extractOriginalNodeId(node); + if (id >= 0) { + if (id >= nodeModCounts.length) { + nodeModCounts = Arrays.copyOf(nodeModCounts, id * 2 + 30); + } + nodeModCounts[id]++; + } else { + assert false; + } + } + + int usageModCount(Node node) { + int id = extractOriginalNodeId(node); + if (id >= 0 && id < nodeUsageModCounts.length) { + return nodeUsageModCounts[id]; + } + return 0; + } + + void incUsageModCount(Node node) { + int id = extractOriginalNodeId(node); + if (id >= 0) { + if (id >= nodeUsageModCounts.length) { + nodeUsageModCounts = Arrays.copyOf(nodeUsageModCounts, id * 2 + 30); + } + nodeUsageModCounts[id]++; + } else { + assert false; + } + } + + /** + * Creates a copy of this graph. + */ + public final Graph copy() { + return copy(name, null); + } + + /** + * Creates a copy of this graph. + * + * @param duplicationMapCallback consumer of the duplication map created during the copying + */ + public final Graph copy(Consumer> duplicationMapCallback) { + return copy(name, duplicationMapCallback); + } + + /** + * Creates a copy of this graph. + * + * @param newName the name of the copy, used for debugging purposes (can be null) + */ + public final Graph copy(String newName) { + return copy(newName, null); + } + + /** + * Creates a copy of this graph. + * + * @param newName the name of the copy, used for debugging purposes (can be null) + * @param duplicationMapCallback consumer of the duplication map created during the copying + */ + protected Graph copy(String newName, Consumer> duplicationMapCallback) { + Graph copy = new Graph(newName); + Map duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), (Map) null); + if (duplicationMapCallback != null) { + duplicationMapCallback.accept(duplicates); + } + return copy; + } + + @Override + public String toString() { + return name == null ? super.toString() : "Graph " + name; + } + + /** + * Gets the number of live nodes in this graph. That is the number of nodes which have been + * added to the graph minus the number of deleted nodes. + * + * @return the number of live nodes in this graph + */ + public int getNodeCount() { + return nodesSize - getNodesDeletedSinceLastCompression(); + } + + /** + * Gets the number of times this graph has been {@linkplain #maybeCompress() compressed}. Node + * identifiers are only stable between compressions. To ensure this constraint is observed, any + * entity relying upon stable node identifiers should use {@link NodeIdAccessor}. + */ + public int getCompressions() { + return compressions; + } + + /** + * Gets the number of nodes which have been deleted from this graph since it was last + * {@linkplain #maybeCompress() compressed}. + */ + public int getNodesDeletedSinceLastCompression() { + return nodesDeletedSinceLastCompression; + } + + /** + * Gets the total number of nodes which have been deleted from this graph. + */ + public int getTotalNodesDeleted() { + return nodesDeletedSinceLastCompression + nodesDeletedBeforeLastCompression; + } + + /** + * Adds a new node to the graph. + * + * @param node the node to be added + * @return the node which was added to the graph + */ + public T add(T node) { + if (node.getNodeClass().valueNumberable()) { + throw new IllegalStateException("Using add for value numberable node. Consider using either unique or addWithoutUnique."); + } + return addHelper(node); + } + + public T addWithoutUnique(T node) { + return addHelper(node); + } + + public T addOrUnique(T node) { + if (node.getNodeClass().valueNumberable()) { + return uniqueHelper(node, true); + } + return add(node); + } + + public T addWithoutUniqueWithInputs(T node) { + addInputs(node); + return addHelper(node); + } + + public T addOrUniqueWithInputs(T node) { + addInputs(node); + if (node.getNodeClass().valueNumberable()) { + return uniqueHelper(node, true); + } + return add(node); + } + + private final class AddInputsFilter extends Node.EdgeVisitor { + + @Override + public Node apply(Node self, Node input) { + if (!input.isAlive()) { + assert !input.isDeleted(); + return addOrUniqueWithInputs(input); + } else { + return input; + } + } + + } + + private AddInputsFilter addInputsFilter = new AddInputsFilter(); + + private void addInputs(T node) { + node.applyInputs(addInputsFilter); + } + + private T addHelper(T node) { + node.initialize(this); + return node; + } + + /** + * The type of events sent to a {@link NodeEventListener}. + */ + public enum NodeEvent { + /** + * A node's input is changed. + */ + INPUT_CHANGED, + + /** + * A node's {@linkplain Node#usages() usages} count dropped to zero. + */ + ZERO_USAGES, + + /** + * A node was added to a graph. + */ + NODE_ADDED; + } + + /** + * Client interested in one or more node related events. + */ + public interface NodeEventListener { + + /** + * Default handler for events. + * + * @param e an event + * @param node the node related to {@code e} + */ + default void event(NodeEvent e, Node node) { + } + + /** + * Notifies this listener of a change in a node's inputs. + * + * @param node a node who has had one of its inputs changed + */ + default void inputChanged(Node node) { + event(NodeEvent.INPUT_CHANGED, node); + } + + /** + * Notifies this listener of a node becoming unused. + * + * @param node a node whose {@link Node#usages()} just became empty + */ + default void usagesDroppedToZero(Node node) { + event(NodeEvent.ZERO_USAGES, node); + } + + /** + * Notifies this listener of an added node. + * + * @param node a node that was just added to the graph + */ + default void nodeAdded(Node node) { + event(NodeEvent.NODE_ADDED, node); + } + } + + /** + * Registers a given {@link NodeEventListener} with the enclosing graph until this object is + * {@linkplain #close() closed}. + */ + public final class NodeEventScope implements AutoCloseable { + NodeEventScope(NodeEventListener listener) { + if (nodeEventListener == null) { + nodeEventListener = listener; + } else { + nodeEventListener = new ChainedNodeEventListener(listener, nodeEventListener); + } + } + + @Override + public void close() { + assert nodeEventListener != null; + if (nodeEventListener instanceof ChainedNodeEventListener) { + nodeEventListener = ((ChainedNodeEventListener) nodeEventListener).next; + } else { + nodeEventListener = null; + } + } + } + + private static class ChainedNodeEventListener implements NodeEventListener { + + NodeEventListener head; + NodeEventListener next; + + ChainedNodeEventListener(NodeEventListener head, NodeEventListener next) { + this.head = head; + this.next = next; + } + + @Override + public void nodeAdded(Node node) { + head.nodeAdded(node); + next.nodeAdded(node); + } + + @Override + public void inputChanged(Node node) { + head.inputChanged(node); + next.inputChanged(node); + } + + @Override + public void usagesDroppedToZero(Node node) { + head.usagesDroppedToZero(node); + next.usagesDroppedToZero(node); + } + } + + /** + * Registers a given {@link NodeEventListener} with this graph. This should be used in + * conjunction with try-with-resources statement as follows: + * + *
+     * try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+     *     // make changes to the graph
+     * }
+     * 
+ */ + public NodeEventScope trackNodeEvents(NodeEventListener listener) { + return new NodeEventScope(listener); + } + + /** + * Looks for a node similar to {@code node} and returns it if found. Otherwise + * {@code node} is added to this graph and returned. + * + * @return a node similar to {@code node} if one exists, otherwise {@code node} + */ + public T unique(T node) { + return uniqueHelper(node, true); + } + + T uniqueHelper(T node, boolean addIfMissing) { + assert node.getNodeClass().valueNumberable(); + T other = this.findDuplicate(node); + if (other != null) { + return other; + } else { + T result = addIfMissing ? addHelper(node) : node; + if (node.getNodeClass().isLeafNode()) { + putNodeIntoCache(result); + } + return result; + } + } + + void putNodeIntoCache(Node node) { + assert node.graph() == this || node.graph() == null; + assert node.getNodeClass().valueNumberable(); + assert node.getNodeClass().isLeafNode() : node.getClass(); + CacheEntry entry = new CacheEntry(node); + cachedLeafNodes.put(entry, node); + } + + Node findNodeInCache(Node node) { + CacheEntry key = new CacheEntry(node); + Node result = cachedLeafNodes.get(key); + if (result != null && result.isDeleted()) { + cachedLeafNodes.remove(key); + return null; + } + return result; + } + + /** + * Returns a possible duplicate for the given node in the graph or {@code null} if no such + * duplicate exists. + */ + @SuppressWarnings("unchecked") + public T findDuplicate(T node) { + NodeClass nodeClass = node.getNodeClass(); + assert nodeClass.valueNumberable(); + if (nodeClass.isLeafNode()) { + // Leaf node: look up in cache + Node cachedNode = findNodeInCache(node); + if (cachedNode != null && cachedNode != node) { + return (T) cachedNode; + } else { + return null; + } + } else { + /* + * Non-leaf node: look for another usage of the node's inputs that has the same data, + * inputs and successors as the node. To reduce the cost of this computation, only the + * input with lowest usage count is considered. If this node is the only user of any + * input then the search can terminate early. The usage count is only incremented once + * the Node is in the Graph, so account for that in the test. + */ + final int earlyExitUsageCount = node.graph() != null ? 1 : 0; + int minCount = Integer.MAX_VALUE; + Node minCountNode = null; + for (Node input : node.inputs()) { + int usageCount = input.getUsageCount(); + if (usageCount == earlyExitUsageCount) { + return null; + } else if (usageCount < minCount) { + minCount = usageCount; + minCountNode = input; + } + } + if (minCountNode != null) { + for (Node usage : minCountNode.usages()) { + if (usage != node && nodeClass == usage.getNodeClass() && node.valueEquals(usage) && nodeClass.equalInputs(node, usage) && + nodeClass.equalSuccessors(node, usage)) { + return (T) usage; + } + } + return null; + } + return null; + } + } + + public boolean isNew(Mark mark, Node node) { + return node.id >= mark.getValue(); + } + + /** + * A snapshot of the {@linkplain Graph#getNodeCount() live node count} in a graph. + */ + public static class Mark extends NodeIdAccessor { + private final int value; + + Mark(Graph graph) { + super(graph); + this.value = graph.nodeIdCount(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Mark) { + Mark other = (Mark) obj; + return other.getValue() == getValue() && other.getGraph() == getGraph(); + } + return false; + } + + @Override + public int hashCode() { + return value ^ (epoch + 11); + } + + /** + * Determines if this mark is positioned at the first live node in the graph. + */ + public boolean isStart() { + return value == 0; + } + + /** + * Gets the {@linkplain Graph#getNodeCount() live node count} of the associated graph when + * this object was created. + */ + int getValue() { + return value; + } + + /** + * Determines if this mark still represents the {@linkplain Graph#getNodeCount() live node + * count} of the graph. + */ + public boolean isCurrent() { + return value == graph.nodeIdCount(); + } + } + + /** + * Gets a mark that can be used with {@link #getNewNodes}. + */ + public Mark getMark() { + return new Mark(this); + } + + /** + * Returns an {@link Iterable} providing all nodes added since the last {@link Graph#getMark() + * mark}. + */ + public NodeIterable getNewNodes(Mark mark) { + final int index = mark == null ? 0 : mark.getValue(); + return new NodeIterable() { + + @Override + public Iterator iterator() { + return new GraphNodeIterator(Graph.this, index); + } + }; + } + + /** + * Returns an {@link Iterable} providing all the live nodes. + * + * @return an {@link Iterable} providing all the live nodes. + */ + public NodeIterable getNodes() { + return new NodeIterable() { + + @Override + public Iterator iterator() { + return new GraphNodeIterator(Graph.this); + } + + @Override + public int count() { + return getNodeCount(); + } + }; + } + + // Fully qualified annotation name is required to satisfy javac + @org.graalvm.compiler.nodeinfo.NodeInfo + static final class PlaceHolderNode extends Node { + + public static final NodeClass TYPE = NodeClass.create(PlaceHolderNode.class); + + protected PlaceHolderNode() { + super(TYPE); + } + + } + + static final Node PLACE_HOLDER = new PlaceHolderNode(); + + public static final int COMPRESSION_THRESHOLD = Options.GraphCompressionThreshold.getValue(); + + private static final DebugCounter GraphCompressions = Debug.counter("GraphCompressions"); + + /** + * If the {@linkplain #COMPRESSION_THRESHOLD compression threshold} is met, the list of nodes is + * compressed such that all non-null entries precede all null entries while preserving the + * ordering between the nodes within the list. + */ + public boolean maybeCompress() { + if (Debug.isDumpEnabledForMethod() || Debug.isLogEnabledForMethod()) { + return false; + } + int liveNodeCount = getNodeCount(); + int liveNodePercent = liveNodeCount * 100 / nodesSize; + if (COMPRESSION_THRESHOLD == 0 || liveNodePercent >= COMPRESSION_THRESHOLD) { + return false; + } + GraphCompressions.increment(); + int nextId = 0; + for (int i = 0; nextId < liveNodeCount; i++) { + Node n = nodes[i]; + if (n != null) { + assert n.id == i; + if (i != nextId) { + assert n.id > nextId; + n.id = nextId; + nodes[nextId] = n; + nodes[i] = null; + } + nextId++; + } + } + if (isModificationCountsEnabled()) { + // This will cause any current iteration to fail with an assertion + Arrays.fill(nodeModCounts, 0); + Arrays.fill(nodeUsageModCounts, 0); + } + nodesSize = nextId; + compressions++; + nodesDeletedBeforeLastCompression += nodesDeletedSinceLastCompression; + nodesDeletedSinceLastCompression = 0; + return true; + } + + /** + * Returns an {@link Iterable} providing all the live nodes whose type is compatible with + * {@code type}. + * + * @param nodeClass the type of node to return + * @return an {@link Iterable} providing all the matching nodes + */ + public NodeIterable getNodes(final NodeClass nodeClass) { + return new NodeIterable() { + + @Override + public Iterator iterator() { + return new TypedGraphNodeIterator<>(nodeClass, Graph.this); + } + }; + } + + /** + * Returns whether the graph contains at least one node of the given type. + * + * @param type the type of node that is checked for occurrence + * @return whether there is at least one such node + */ + public boolean hasNode(final NodeClass type) { + return getNodes(type).iterator().hasNext(); + } + + /** + * @param iterableId + * @return the first live Node with a matching iterableId + */ + Node getIterableNodeStart(int iterableId) { + if (iterableNodesFirst.size() <= iterableId) { + return null; + } + Node start = iterableNodesFirst.get(iterableId); + if (start == null || !start.isDeleted()) { + return start; + } + return findFirstLiveIterable(iterableId, start); + } + + private Node findFirstLiveIterable(int iterableId, Node node) { + Node start = node; + while (start != null && start.isDeleted()) { + start = start.typeCacheNext; + } + /* + * Multiple threads iterating nodes can update this cache simultaneously. This is a benign + * race, since all threads update it to the same value. + */ + iterableNodesFirst.set(iterableId, start); + if (start == null) { + iterableNodesLast.set(iterableId, start); + } + return start; + } + + /** + * @param node + * @return return the first live Node with a matching iterableId starting from {@code node} + */ + Node getIterableNodeNext(Node node) { + if (node == null) { + return null; + } + Node n = node; + if (n == null || !n.isDeleted()) { + return n; + } + + return findNextLiveiterable(node); + } + + private Node findNextLiveiterable(Node start) { + Node n = start; + while (n != null && n.isDeleted()) { + n = n.typeCacheNext; + } + if (n == null) { + // Only dead nodes after this one + start.typeCacheNext = null; + int nodeClassId = start.getNodeClass().iterableId(); + assert nodeClassId != Node.NOT_ITERABLE; + iterableNodesLast.set(nodeClassId, start); + } else { + // Everything in between is dead + start.typeCacheNext = n; + } + return n; + } + + public NodeBitMap createNodeBitMap() { + return new NodeBitMap(this); + } + + public NodeMap createNodeMap() { + return new NodeMap<>(this); + } + + public NodeFlood createNodeFlood() { + return new NodeFlood(this); + } + + public NodeWorkList createNodeWorkList() { + return new NodeWorkList.SingletonNodeWorkList(this); + } + + public NodeWorkList createIterativeNodeWorkList(boolean fill, int iterationLimitPerNode) { + return new NodeWorkList.IterativeNodeWorkList(this, fill, iterationLimitPerNode); + } + + void register(Node node) { + assert !isFrozen(); + assert node.id() == Node.INITIAL_ID; + if (nodes.length == nodesSize) { + Node[] newNodes = new Node[(nodesSize * 2) + 1]; + System.arraycopy(nodes, 0, newNodes, 0, nodesSize); + nodes = newNodes; + } + int id = nodesSize; + nodes[id] = node; + if (currentNodeSourcePosition != null) { + node.setNodeSourcePosition(currentNodeSourcePosition); + } else if (!seenNodeSourcePosition && node.getNodeSourcePosition() != null) { + seenNodeSourcePosition = true; + } + nodesSize++; + + updateNodeCaches(node); + + node.id = id; + if (nodeEventListener != null) { + nodeEventListener.nodeAdded(node); + } + if (!seenNodeSourcePosition && node.sourcePosition != null) { + seenNodeSourcePosition = true; + } + if (Fingerprint.ENABLED) { + Fingerprint.submit("%s: %s", NodeEvent.NODE_ADDED, node); + } + } + + @SuppressWarnings("unused") + private void postDeserialization() { + recomputeIterableNodeLists(); + } + + /** + * Rebuilds the lists used to support {@link #getNodes(NodeClass)}. This is useful for + * serialization where the underlying {@linkplain NodeClass#iterableId() iterable ids} may have + * changed. + */ + private void recomputeIterableNodeLists() { + iterableNodesFirst.clear(); + iterableNodesLast.clear(); + for (Node node : nodes) { + if (node != null && node.isAlive()) { + updateNodeCaches(node); + } + } + } + + private void updateNodeCaches(Node node) { + int nodeClassId = node.getNodeClass().iterableId(); + if (nodeClassId != Node.NOT_ITERABLE) { + while (iterableNodesFirst.size() <= nodeClassId) { + iterableNodesFirst.add(null); + iterableNodesLast.add(null); + } + Node prev = iterableNodesLast.get(nodeClassId); + if (prev != null) { + prev.typeCacheNext = node; + } else { + iterableNodesFirst.set(nodeClassId, node); + } + iterableNodesLast.set(nodeClassId, node); + } + } + + void unregister(Node node) { + assert !isFrozen(); + assert !node.isDeleted() : "cannot delete a node twice! node=" + node; + nodes[node.id] = null; + nodesDeletedSinceLastCompression++; + + // nodes aren't removed from the type cache here - they will be removed during iteration + } + + public boolean verify() { + if (Options.VerifyGraalGraphs.getValue()) { + for (Node node : getNodes()) { + try { + try { + assert node.verify(); + } catch (AssertionError t) { + throw new GraalError(t); + } catch (RuntimeException t) { + throw new GraalError(t); + } + } catch (GraalError e) { + throw GraalGraphError.transformAndAddContext(e, node).addContext(this); + } + } + } + return true; + } + + public Node getNode(int id) { + return nodes[id]; + } + + /** + * Returns the number of node ids generated so far. + * + * @return the number of node ids generated so far + */ + int nodeIdCount() { + return nodesSize; + } + + /** + * Adds duplicates of the nodes in {@code nodes} to this graph. This will recreate any edges + * between the duplicate nodes. The {@code replacement} map can be used to replace a node from + * the source graph by a given node (which must already be in this graph). Edges between + * duplicate and replacement nodes will also be recreated so care should be taken regarding the + * matching of node types in the replacement map. + * + * @param newNodes the nodes to be duplicated + * @param replacementsMap the replacement map (can be null if no replacement is to be performed) + * @return a map which associates the original nodes from {@code nodes} to their duplicates + */ + public Map addDuplicates(Iterable newNodes, final Graph oldGraph, int estimatedNodeCount, Map replacementsMap) { + DuplicationReplacement replacements; + if (replacementsMap == null) { + replacements = null; + } else { + replacements = new MapReplacement(replacementsMap); + } + return addDuplicates(newNodes, oldGraph, estimatedNodeCount, replacements); + } + + public interface DuplicationReplacement { + + Node replacement(Node original); + } + + private static final class MapReplacement implements DuplicationReplacement { + + private final Map map; + + MapReplacement(Map map) { + this.map = map; + } + + @Override + public Node replacement(Node original) { + Node replacement = map.get(original); + return replacement != null ? replacement : original; + } + + } + + private static final DebugTimer DuplicateGraph = Debug.timer("DuplicateGraph"); + + @SuppressWarnings({"all", "try"}) + public Map addDuplicates(Iterable newNodes, final Graph oldGraph, int estimatedNodeCount, DuplicationReplacement replacements) { + try (DebugCloseable s = DuplicateGraph.start()) { + return NodeClass.addGraphDuplicate(this, oldGraph, estimatedNodeCount, newNodes, replacements); + } + } + + /** + * Reverses the usage orders of all nodes. This is used for debugging to make sure an unorthodox + * usage order does not trigger bugs in the compiler. + */ + public void reverseUsageOrder() { + for (Node n : getNodes()) { + n.reverseUsageOrder(); + } + } + + public boolean isFrozen() { + return isFrozen; + } + + public void freeze() { + this.isFrozen = true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/GraphNodeIterator.java 2016-12-07 13:49:12.699708191 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, 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.graph; + +import java.util.Iterator; + +/** + * Iterates over the nodes in a given graph. + */ +class GraphNodeIterator implements Iterator { + + private final Graph graph; + private int index; + + GraphNodeIterator(Graph graph) { + this(graph, 0); + } + + GraphNodeIterator(Graph graph, int index) { + this.graph = graph; + this.index = index - 1; + forward(); + } + + private void forward() { + if (index < graph.nodesSize) { + do { + index++; + } while (index < graph.nodesSize && graph.nodes[index] == null); + } + } + + @Override + public boolean hasNext() { + checkForDeletedNode(); + return index < graph.nodesSize; + } + + private void checkForDeletedNode() { + while (index < graph.nodesSize && graph.nodes[index] == null) { + index++; + } + } + + @Override + public Node next() { + try { + return graph.nodes[index]; + } finally { + forward(); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/InputEdges.java 2016-12-07 13:49:12.965719884 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014, 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.graph; + +import static org.graalvm.compiler.graph.Edges.Type.Inputs; + +import java.util.ArrayList; + +import org.graalvm.compiler.graph.NodeClass.InputInfo; +import org.graalvm.compiler.nodeinfo.InputType; + +public final class InputEdges extends Edges { + + private final InputType[] inputTypes; + private final boolean[] isOptional; + + public InputEdges(int directCount, ArrayList edges) { + super(Inputs, directCount, edges); + + this.inputTypes = new InputType[edges.size()]; + this.isOptional = new boolean[edges.size()]; + for (int i = 0; i < edges.size(); i++) { + this.inputTypes[i] = edges.get(i).inputType; + this.isOptional[i] = edges.get(i).optional; + } + } + + public static void translateInto(InputEdges inputs, ArrayList infos) { + for (int index = 0; index < inputs.getCount(); index++) { + infos.add(new InputInfo(inputs.offsets[index], inputs.getName(index), inputs.getType(index), inputs.getDeclaringClass(index), inputs.inputTypes[index], inputs.isOptional(index))); + } + } + + public InputType getInputType(int index) { + return inputTypes[index]; + } + + public boolean isOptional(int index) { + return isOptional[index]; + } + + @Override + public void update(Node node, Node oldValue, Node newValue) { + node.updateUsages(oldValue, newValue); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/IterableNodeType.java 2016-12-07 13:49:13.228731445 -0800 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.graph; + +/** + * A marker for a node type supporting {@linkplain Graph#getNodes(NodeClass) fast iteration} of its + * instances in a graph. The support for fast iteration comes with a memory cost (e.g., extra data + * structures {@link Graph}) so only node types for which fast iteration provides a compilation + * performance benefit should implement this interface. + */ +public interface IterableNodeType { +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java 2016-12-07 13:49:13.495743181 -0800 @@ -0,0 +1,1190 @@ +/* + * Copyright (c) 2011, 2015, 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.graph; + +import static org.graalvm.compiler.graph.Edges.Type.Inputs; +import static org.graalvm.compiler.graph.Edges.Type.Successors; +import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled; +import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE; + +import java.lang.annotation.ElementType; +import java.lang.annotation.RetentionPolicy; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.Formattable; +import java.util.FormattableFlags; +import java.util.Formatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; + +import org.graalvm.compiler.core.common.CollectionsFactory; +import org.graalvm.compiler.core.common.Fields; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.Fingerprint; +import org.graalvm.compiler.graph.Graph.NodeEvent; +import org.graalvm.compiler.graph.Graph.NodeEventListener; +import org.graalvm.compiler.graph.Graph.Options; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.graph.iterators.NodePredicate; +import org.graalvm.compiler.graph.spi.Simplifiable; +import org.graalvm.compiler.graph.spi.SimplifierTool; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodeinfo.Verbosity; + +import sun.misc.Unsafe; + +/** + * This class is the base class for all nodes. It represents a node that can be inserted in a + * {@link Graph}. + *

+ * Once a node has been added to a graph, it has a graph-unique {@link #id()}. Edges in the + * subclasses are represented with annotated fields. There are two kind of edges : {@link Input} and + * {@link Successor}. If a field, of a type compatible with {@link Node}, annotated with either + * {@link Input} and {@link Successor} is not null, then there is an edge from this node to the node + * this field points to. + *

+ * Nodes which are be value numberable should implement the {@link ValueNumberable} interface. + * + *

Replay Compilation

+ * + * To enable deterministic replay compilation, node sets and node maps should be instantiated with + * the following methods: + *
    + *
  • {@link #newSet()}
  • + *
  • {@link #newSet(Collection)}
  • + *
  • {@link #newMap()}
  • + *
  • {@link #newMap(int)}
  • + *
  • {@link #newMap(Map)}
  • + *
  • {@link #newIdentityMap()}
  • + *
  • {@link #newIdentityMap(int)}
  • + *
  • {@link #newIdentityMap(Map)}
  • + *
+ * + *

Assertions and Verification

+ * + * The Node class supplies the {@link #assertTrue(boolean, String, Object...)} and + * {@link #assertFalse(boolean, String, Object...)} methods, which will check the supplied boolean + * and throw a VerificationError if it has the wrong value. Both methods will always either throw an + * exception or return true. They can thus be used within an assert statement, so that the check is + * only performed if assertions are enabled. + */ +@NodeInfo +public abstract class Node implements Cloneable, Formattable, NodeInterface { + + public static final NodeClass TYPE = null; + public static final boolean USE_UNSAFE_TO_CLONE = Graph.Options.CloneNodesWithUnsafe.getValue(); + + static final int DELETED_ID_START = -1000000000; + static final int INITIAL_ID = -1; + static final int ALIVE_ID_START = 0; + + // The use of fully qualified class names here and in the rest + // of this file works around a problem javac has resolving symbols + + /** + * Denotes a non-optional (non-null) node input. This should be applied to exactly the fields of + * a node that are of type {@link Node} or {@link NodeInputList}. Nodes that update fields of + * type {@link Node} outside of their constructor should call + * {@link Node#updateUsages(Node, Node)} just prior to doing the update of the input. + */ + @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) + @java.lang.annotation.Target(ElementType.FIELD) + public static @interface Input { + InputType value() default InputType.Value; + } + + /** + * Denotes an optional (nullable) node input. This should be applied to exactly the fields of a + * node that are of type {@link Node} or {@link NodeInputList}. Nodes that update fields of type + * {@link Node} outside of their constructor should call {@link Node#updateUsages(Node, Node)} + * just prior to doing the update of the input. + */ + @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) + @java.lang.annotation.Target(ElementType.FIELD) + public static @interface OptionalInput { + InputType value() default InputType.Value; + } + + @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) + @java.lang.annotation.Target(ElementType.FIELD) + public static @interface Successor { + } + + /** + * Denotes that a parameter of an {@linkplain NodeIntrinsic intrinsic} method must be a compile + * time constant at all call sites to the intrinsic method. + */ + @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) + @java.lang.annotation.Target(ElementType.PARAMETER) + public static @interface ConstantNodeParameter { + } + + /** + * Denotes an injected parameter in a {@linkplain NodeIntrinsic node intrinsic} constructor. If + * the constructor is called as part of node intrinsification, the node intrinsifier will inject + * an argument for the annotated parameter. Injected parameters must precede all non-injected + * parameters in a constructor. + */ + @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) + @java.lang.annotation.Target(ElementType.PARAMETER) + public static @interface InjectedNodeParameter { + } + + /** + * Annotates a method that can be replaced by a compiler intrinsic. A (resolved) call to the + * annotated method can be replaced with an instance of the node class denoted by + * {@link #value()}. For this reason, the signature of the annotated method must match the + * signature (excluding a prefix of {@linkplain InjectedNodeParameter injected} parameters) of a + * constructor in the node class. + *

+ * If the node class has a static method {@code intrinsify} with a matching signature plus a + * {@code GraphBuilderContext} as first argument, this method is called instead of creating the + * node. + */ + @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) + @java.lang.annotation.Target(ElementType.METHOD) + public static @interface NodeIntrinsic { + + /** + * Gets the {@link Node} subclass instantiated when intrinsifying a call to the annotated + * method. If not specified, then the class in which the annotated method is declared is + * used (and is assumed to be a {@link Node} subclass). + */ + Class value() default NodeIntrinsic.class; + + /** + * Determines if the stamp of the instantiated intrinsic node has its stamp set from the + * return type of the annotated method. + *

+ * When it is set to true, the stamp that is passed in to the constructor of ValueNode is + * ignored and can therefore safely be {@code null}. + */ + boolean setStampFromReturnType() default false; + + /** + * Determines if the stamp of the instantiated intrinsic node is guaranteed to be non-null. + * Generally used in conjunction with {@link #setStampFromReturnType()}. + */ + boolean returnStampIsNonNull() default false; + } + + /** + * Marker for a node that can be replaced by another node via global value numbering. A + * {@linkplain NodeClass#isLeafNode() leaf} node can be replaced by another node of the same + * type that has exactly the same {@linkplain NodeClass#getData() data} values. A non-leaf node + * can be replaced by another node of the same type that has exactly the same data values as + * well as the same {@linkplain Node#inputs() inputs} and {@linkplain Node#successors() + * successors}. + */ + public interface ValueNumberable { + } + + /** + * Marker interface for nodes that contains other nodes. When the inputs to this node changes, + * users of this node should also be placed on the work list for canonicalization. + */ + public interface IndirectCanonicalization { + } + + private Graph graph; + int id; + + // this next pointer is used in Graph to implement fast iteration over NodeClass types, it + // therefore points to the next Node of the same type. + Node typeCacheNext; + + static final int INLINE_USAGE_COUNT = 2; + private static final Node[] NO_NODES = {}; + + /** + * Head of usage list. The elements of the usage list in order are {@link #usage0}, + * {@link #usage1} and {@link #extraUsages}. The first null entry terminates the list. + */ + Node usage0; + Node usage1; + Node[] extraUsages; + int extraUsagesCount; + + private Node predecessor; + private NodeClass nodeClass; + + public static final int NODE_LIST = -2; + public static final int NOT_ITERABLE = -1; + + public Node(NodeClass c) { + init(c); + } + + final void init(NodeClass c) { + assert c.getJavaClass() == this.getClass(); + this.nodeClass = c; + id = INITIAL_ID; + extraUsages = NO_NODES; + } + + final int id() { + return id; + } + + @Override + public Node asNode() { + return this; + } + + /** + * @see CollectionsFactory#newSet() + */ + public static Set newSet() { + return CollectionsFactory.newSet(); + } + + /** + * @see #newSet() + */ + public static Set newSet(Collection c) { + return CollectionsFactory.newSet(c); + } + + public static Map newMap() { + // Node.equals() and Node.hashCode() are final and are implemented + // purely in terms of identity so HashMap and IdentityHashMap with + // Node's as keys will behave the same. We choose to use the latter + // due to its lighter memory footprint. + return newIdentityMap(); + } + + public static Map newMap(Map m) { + // Node.equals() and Node.hashCode() are final and are implemented + // purely in terms of identity so HashMap and IdentityHashMap with + // Node's as keys will behave the same. We choose to use the latter + // due to its lighter memory footprint. + return newIdentityMap(m); + } + + public static Map newMap(int expectedMaxSize) { + // Node.equals() and Node.hashCode() are final and are implemented + // purely in terms of identity so HashMap and IdentityHashMap with + // Node's as keys will behave the same. We choose to use the latter + // due to its lighter memory footprint. + return newIdentityMap(expectedMaxSize); + } + + public static Map newIdentityMap() { + return CollectionsFactory.newIdentityMap(); + } + + public static Map newIdentityMap(Map m) { + return CollectionsFactory.newIdentityMap(m); + } + + public static Map newIdentityMap(int expectedMaxSize) { + return CollectionsFactory.newIdentityMap(expectedMaxSize); + } + + /** + * Gets the graph context of this node. + */ + public Graph graph() { + return graph; + } + + /** + * Returns an {@link NodeIterable iterable} which can be used to traverse all non-null input + * edges of this node. + * + * @return an {@link NodeIterable iterable} for all non-null input edges. + */ + public NodeIterable inputs() { + return nodeClass.getInputIterable(this); + } + + /** + * Returns an {@link Iterable iterable} which can be used to traverse all non-null input edges + * of this node. + * + * @return an {@link Iterable iterable} for all non-null input edges. + */ + public Iterable inputPositions() { + return nodeClass.getInputEdges().getPositionsIterable(this); + } + + public abstract static class EdgeVisitor { + + public abstract Node apply(Node source, Node target); + + } + + /** + * Applies the given visitor to all inputs of this node. + * + * @param visitor the visitor to be applied to the inputs + */ + public void applyInputs(EdgeVisitor visitor) { + nodeClass.applyInputs(this, visitor); + } + + /** + * Applies the given visitor to all successors of this node. + * + * @param visitor the visitor to be applied to the successors + */ + public void applySuccessors(EdgeVisitor visitor) { + nodeClass.applySuccessors(this, visitor); + } + + /** + * Returns an {@link NodeIterable iterable} which can be used to traverse all non-null successor + * edges of this node. + * + * @return an {@link NodeIterable iterable} for all non-null successor edges. + */ + public NodeIterable successors() { + assert !this.isDeleted(); + return nodeClass.getSuccessorIterable(this); + } + + /** + * Returns an {@link Iterable iterable} which can be used to traverse all successor edge + * positions of this node. + * + * @return an {@link Iterable iterable} for all successor edge positoins. + */ + public Iterable successorPositions() { + return nodeClass.getSuccessorEdges().getPositionsIterable(this); + } + + /** + * Gets the maximum number of usages this node has had at any point in time. + */ + public int getUsageCount() { + if (usage0 == null) { + return 0; + } + if (usage1 == null) { + return 1; + } + return 2 + extraUsagesCount; + } + + /** + * Gets the list of nodes that use this node (i.e., as an input). + */ + public final NodeIterable usages() { + return new NodeUsageIterable(this); + } + + /** + * Checks whether this node has no usages. + */ + public final boolean hasNoUsages() { + return this.usage0 == null; + } + + /** + * Checks whether this node has usages. + */ + public final boolean hasUsages() { + return this.usage0 != null; + } + + void reverseUsageOrder() { + List snapshot = this.usages().snapshot(); + for (Node n : snapshot) { + this.removeUsage(n); + } + Collections.reverse(snapshot); + for (Node n : snapshot) { + this.addUsage(n); + } + } + + /** + * Adds a given node to this node's {@linkplain #usages() usages}. + * + * @param node the node to add + */ + void addUsage(Node node) { + incUsageModCount(); + if (usage0 == null) { + usage0 = node; + } else if (usage1 == null) { + usage1 = node; + } else { + int length = extraUsages.length; + if (length == 0) { + extraUsages = new Node[4]; + } else if (extraUsagesCount == length) { + Node[] newExtraUsages = new Node[length * 2 + 1]; + System.arraycopy(extraUsages, 0, newExtraUsages, 0, length); + extraUsages = newExtraUsages; + } + extraUsages[extraUsagesCount++] = node; + } + } + + private void movUsageFromEndTo(int destIndex) { + int lastIndex = this.getUsageCount() - 1; + if (destIndex == 0) { + if (lastIndex == 0) { + usage0 = null; + return; + } else if (lastIndex == 1) { + usage0 = usage1; + usage1 = null; + return; + } else { + usage0 = extraUsages[lastIndex - INLINE_USAGE_COUNT]; + } + } else if (destIndex == 1) { + if (lastIndex == 1) { + usage1 = null; + return; + } + usage1 = extraUsages[lastIndex - INLINE_USAGE_COUNT]; + } else { + Node n = extraUsages[lastIndex - INLINE_USAGE_COUNT]; + extraUsages[destIndex - INLINE_USAGE_COUNT] = n; + } + extraUsages[lastIndex - INLINE_USAGE_COUNT] = null; + this.extraUsagesCount--; + } + + /** + * Removes a given node from this node's {@linkplain #usages() usages}. + * + * @param node the node to remove + * @return whether or not {@code usage} was in the usage list + */ + public boolean removeUsage(Node node) { + assert node != null; + // It is critical that this method maintains the invariant that + // the usage list has no null element preceding a non-null element + incUsageModCount(); + if (usage0 == node) { + this.movUsageFromEndTo(0); + return true; + } + if (usage1 == node) { + this.movUsageFromEndTo(1); + return true; + } + for (int i = this.extraUsagesCount - 1; i >= 0; i--) { + if (extraUsages[i] == node) { + this.movUsageFromEndTo(i + INLINE_USAGE_COUNT); + return true; + } + } + return false; + } + + public final Node predecessor() { + return predecessor; + } + + public final int modCount() { + if (isModificationCountsEnabled() && graph != null) { + return graph.modCount(this); + } + return 0; + } + + final void incModCount() { + if (isModificationCountsEnabled() && graph != null) { + graph.incModCount(this); + } + } + + final int usageModCount() { + if (isModificationCountsEnabled() && graph != null) { + return graph.usageModCount(this); + } + return 0; + } + + final void incUsageModCount() { + if (isModificationCountsEnabled() && graph != null) { + graph.incUsageModCount(this); + } + } + + public boolean isDeleted() { + return id <= DELETED_ID_START; + } + + public boolean isAlive() { + return id >= ALIVE_ID_START; + } + + /** + * Updates the usages sets of the given nodes after an input slot is changed from + * {@code oldInput} to {@code newInput} by removing this node from {@code oldInput}'s usages and + * adds this node to {@code newInput}'s usages. + */ + protected void updateUsages(Node oldInput, Node newInput) { + assert isAlive() && (newInput == null || newInput.isAlive()) : "adding " + newInput + " to " + this + " instead of " + oldInput; + if (oldInput != newInput) { + if (oldInput != null) { + boolean result = removeThisFromUsages(oldInput); + assert assertTrue(result, "not found in usages, old input: %s", oldInput); + } + maybeNotifyInputChanged(this); + if (newInput != null) { + newInput.addUsage(this); + } + if (oldInput != null && oldInput.hasNoUsages()) { + maybeNotifyZeroUsages(oldInput); + } + } + } + + protected void updateUsagesInterface(NodeInterface oldInput, NodeInterface newInput) { + updateUsages(oldInput == null ? null : oldInput.asNode(), newInput == null ? null : newInput.asNode()); + } + + /** + * Updates the predecessor of the given nodes after a successor slot is changed from + * oldSuccessor to newSuccessor: removes this node from oldSuccessor's predecessors and adds + * this node to newSuccessor's predecessors. + */ + protected void updatePredecessor(Node oldSuccessor, Node newSuccessor) { + assert isAlive() && (newSuccessor == null || newSuccessor.isAlive()) || newSuccessor == null && !isAlive() : "adding " + newSuccessor + " to " + this + " instead of " + oldSuccessor; + assert graph == null || !graph.isFrozen(); + if (oldSuccessor != newSuccessor) { + if (oldSuccessor != null) { + assert assertTrue(newSuccessor == null || oldSuccessor.predecessor == this, "wrong predecessor in old successor (%s): %s, should be %s", oldSuccessor, oldSuccessor.predecessor, this); + oldSuccessor.predecessor = null; + } + if (newSuccessor != null) { + assert assertTrue(newSuccessor.predecessor == null, "unexpected non-null predecessor in new successor (%s): %s, this=%s", newSuccessor, newSuccessor.predecessor, this); + newSuccessor.predecessor = this; + } + } + } + + void initialize(Graph newGraph) { + assert assertTrue(id == INITIAL_ID, "unexpected id: %d", id); + this.graph = newGraph; + newGraph.register(this); + this.getNodeClass().registerAtInputsAsUsage(this); + this.getNodeClass().registerAtSuccessorsAsPredecessor(this); + } + + /** + * The position of the bytecode that generated this node. + */ + NodeSourcePosition sourcePosition; + + /** + * Gets the source position information for this node or null if it doesn't exist. + */ + + public NodeSourcePosition getNodeSourcePosition() { + return sourcePosition; + } + + /** + * Set the source position to {@code sourcePosition}. + */ + public void setNodeSourcePosition(NodeSourcePosition sourcePosition) { + this.sourcePosition = sourcePosition; + if (sourcePosition != null && graph != null && !graph.seenNodeSourcePosition) { + graph.seenNodeSourcePosition = true; + } + } + + public DebugCloseable withNodeSourcePosition() { + return graph.withNodeSourcePosition(this); + } + + public final NodeClass getNodeClass() { + return nodeClass; + } + + public boolean isAllowedUsageType(InputType type) { + if (type == InputType.Value) { + return false; + } + return getNodeClass().getAllowedUsageTypes().contains(type); + } + + private boolean checkReplaceWith(Node other) { + assert assertTrue(graph == null || !graph.isFrozen(), "cannot modify frozen graph"); + assert assertFalse(other == this, "cannot replace a node with itself"); + assert assertFalse(isDeleted(), "cannot replace deleted node"); + assert assertTrue(other == null || !other.isDeleted(), "cannot replace with deleted node %s", other); + return true; + } + + public final void replaceAtUsages(Node other) { + replaceAtUsages(other, null, null); + } + + public final void replaceAtUsages(Node other, Predicate filter) { + replaceAtUsages(other, filter, null); + } + + public final void replaceAtUsagesAndDelete(Node other) { + replaceAtUsages(other, null, this); + safeDelete(); + } + + public final void replaceAtUsagesAndDelete(Node other, Predicate filter) { + replaceAtUsages(other, filter, this); + safeDelete(); + } + + protected void replaceAtUsages(Node other, Predicate filter, Node toBeDeleted) { + assert checkReplaceWith(other); + int i = 0; + while (i < this.getUsageCount()) { + Node usage = this.getUsageAt(i); + if (filter == null || filter.test(usage)) { + boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other); + assert assertTrue(result, "not found in inputs, usage: %s", usage); + /* + * Don't notify for nodes which are about to be deleted. + */ + if (toBeDeleted == null || usage != toBeDeleted) { + maybeNotifyInputChanged(usage); + } + if (other != null) { + other.addUsage(usage); + } + this.movUsageFromEndTo(i); + } else { + ++i; + } + } + } + + public Node getUsageAt(int index) { + if (index == 0) { + return this.usage0; + } else if (index == 1) { + return this.usage1; + } else { + return this.extraUsages[index - INLINE_USAGE_COUNT]; + } + } + + public void replaceAtMatchingUsages(Node other, NodePredicate usagePredicate) { + assert checkReplaceWith(other); + int index = 0; + while (index < this.getUsageCount()) { + Node usage = getUsageAt(index); + if (usagePredicate.apply(usage)) { + boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other); + assert assertTrue(result, "not found in inputs, usage: %s", usage); + if (other != null) { + maybeNotifyInputChanged(usage); + other.addUsage(usage); + } + this.movUsageFromEndTo(index); + } else { + index++; + } + } + } + + public void replaceAtUsages(InputType type, Node other) { + assert checkReplaceWith(other); + for (Node usage : usages().snapshot()) { + for (Position pos : usage.inputPositions()) { + if (pos.getInputType() == type && pos.get(usage) == this) { + pos.set(usage, other); + } + } + } + } + + private void maybeNotifyInputChanged(Node node) { + if (graph != null) { + assert !graph.isFrozen(); + NodeEventListener listener = graph.nodeEventListener; + if (listener != null) { + listener.inputChanged(node); + } + if (Fingerprint.ENABLED) { + Fingerprint.submit("%s: %s", NodeEvent.INPUT_CHANGED, node); + } + } + } + + public void maybeNotifyZeroUsages(Node node) { + if (graph != null) { + assert !graph.isFrozen(); + NodeEventListener listener = graph.nodeEventListener; + if (listener != null && node.isAlive()) { + listener.usagesDroppedToZero(node); + } + if (Fingerprint.ENABLED) { + Fingerprint.submit("%s: %s", NodeEvent.ZERO_USAGES, node); + } + } + } + + public void replaceAtPredecessor(Node other) { + assert checkReplaceWith(other); + if (predecessor != null) { + boolean result = predecessor.getNodeClass().replaceFirstSuccessor(predecessor, this, other); + assert assertTrue(result, "not found in successors, predecessor: %s", predecessor); + predecessor.updatePredecessor(this, other); + } + } + + public void replaceAndDelete(Node other) { + assert checkReplaceWith(other); + assert other != null; + replaceAtUsages(other); + replaceAtPredecessor(other); + this.safeDelete(); + } + + public void replaceFirstSuccessor(Node oldSuccessor, Node newSuccessor) { + if (nodeClass.replaceFirstSuccessor(this, oldSuccessor, newSuccessor)) { + updatePredecessor(oldSuccessor, newSuccessor); + } + } + + public void replaceFirstInput(Node oldInput, Node newInput) { + if (nodeClass.replaceFirstInput(this, oldInput, newInput)) { + updateUsages(oldInput, newInput); + } + } + + public void clearInputs() { + assert assertFalse(isDeleted(), "cannot clear inputs of deleted node"); + getNodeClass().unregisterAtInputsAsUsage(this); + } + + boolean removeThisFromUsages(Node n) { + return n.removeUsage(this); + } + + public void clearSuccessors() { + assert assertFalse(isDeleted(), "cannot clear successors of deleted node"); + getNodeClass().unregisterAtSuccessorsAsPredecessor(this); + } + + private boolean checkDeletion() { + assertTrue(isAlive(), "must be alive"); + assertTrue(hasNoUsages(), "cannot delete node %s because of usages: %s", this, usages()); + assertTrue(predecessor == null, "cannot delete node %s because of predecessor: %s", this, predecessor); + return true; + } + + /** + * Removes this node from its graph. This node must have no {@linkplain Node#usages() usages} + * and no {@linkplain #predecessor() predecessor}. + */ + public void safeDelete() { + assert checkDeletion(); + this.clearInputs(); + this.clearSuccessors(); + markDeleted(); + } + + public void markDeleted() { + graph.unregister(this); + id = DELETED_ID_START - id; + assert isDeleted(); + } + + public final Node copyWithInputs() { + return copyWithInputs(true); + } + + public final Node copyWithInputs(boolean insertIntoGraph) { + Node newNode = clone(insertIntoGraph ? graph : null, WithOnlyInputEdges); + if (insertIntoGraph) { + for (Node input : inputs()) { + input.addUsage(newNode); + } + } + return newNode; + } + + /** + * Must be overridden by subclasses that implement {@link Simplifiable}. The implementation in + * {@link Node} exists to obviate the need to cast a node before invoking + * {@link Simplifiable#simplify(SimplifierTool)}. + * + * @param tool + */ + public void simplify(SimplifierTool tool) { + throw new UnsupportedOperationException(); + } + + /** + * @param newNode the result of cloning this node or {@link Unsafe#allocateInstance(Class) raw + * allocating} a copy of this node + * @param type the type of edges to process + * @param edgesToCopy if {@code type} is in this set, the edges are copied otherwise they are + * cleared + */ + private void copyOrClearEdgesForClone(Node newNode, Edges.Type type, EnumSet edgesToCopy) { + if (edgesToCopy.contains(type)) { + getNodeClass().getEdges(type).copy(this, newNode); + } else { + if (USE_UNSAFE_TO_CLONE) { + // The direct edges are already null + getNodeClass().getEdges(type).initializeLists(newNode, this); + } else { + getNodeClass().getEdges(type).clear(newNode); + } + } + } + + public static final EnumSet WithNoEdges = EnumSet.noneOf(Edges.Type.class); + public static final EnumSet WithAllEdges = EnumSet.allOf(Edges.Type.class); + public static final EnumSet WithOnlyInputEdges = EnumSet.of(Inputs); + public static final EnumSet WithOnlySucessorEdges = EnumSet.of(Successors); + + /** + * Makes a copy of this node in(to) a given graph. + * + * @param into the graph in which the copy will be registered (which may be this node's graph) + * or null if the copy should not be registered in a graph + * @param edgesToCopy specifies the edges to be copied. The edges not specified in this set are + * initialized to their default value (i.e., {@code null} for a direct edge, an empty + * list for an edge list) + * @return the copy of this node + */ + final Node clone(Graph into, EnumSet edgesToCopy) { + final NodeClass nodeClassTmp = getNodeClass(); + boolean useIntoLeafNodeCache = false; + if (into != null) { + if (nodeClassTmp.valueNumberable() && nodeClassTmp.isLeafNode()) { + useIntoLeafNodeCache = true; + Node otherNode = into.findNodeInCache(this); + if (otherNode != null) { + return otherNode; + } + } + } + + Node newNode = null; + try { + if (USE_UNSAFE_TO_CLONE) { + newNode = (Node) UNSAFE.allocateInstance(getClass()); + newNode.nodeClass = nodeClassTmp; + nodeClassTmp.getData().copy(this, newNode); + copyOrClearEdgesForClone(newNode, Inputs, edgesToCopy); + copyOrClearEdgesForClone(newNode, Successors, edgesToCopy); + } else { + newNode = (Node) this.clone(); + newNode.typeCacheNext = null; + newNode.usage0 = null; + newNode.usage1 = null; + newNode.predecessor = null; + newNode.extraUsagesCount = 0; + copyOrClearEdgesForClone(newNode, Inputs, edgesToCopy); + copyOrClearEdgesForClone(newNode, Successors, edgesToCopy); + } + } catch (Exception e) { + throw new GraalGraphError(e).addContext(this); + } + newNode.graph = into; + newNode.id = INITIAL_ID; + if (into != null) { + into.register(newNode); + } + newNode.extraUsages = NO_NODES; + + if (into != null && useIntoLeafNodeCache) { + into.putNodeIntoCache(newNode); + } + if (graph != null && into != null && sourcePosition != null) { + newNode.setNodeSourcePosition(sourcePosition); + } + newNode.afterClone(this); + return newNode; + } + + protected void afterClone(@SuppressWarnings("unused") Node other) { + } + + protected boolean verifyInputs() { + for (Position pos : inputPositions()) { + Node input = pos.get(this); + if (input == null) { + assertTrue(pos.isInputOptional(), "non-optional input %s cannot be null in %s (fix nullness or use @OptionalInput)", pos, this); + } else { + assertFalse(input.isDeleted(), "input was deleted"); + assertTrue(input.isAlive(), "input is not alive yet, i.e., it was not yet added to the graph"); + assertTrue(pos.getInputType() == InputType.Unchecked || input.isAllowedUsageType(pos.getInputType()), "invalid usage type %s %s", input, pos.getInputType()); + } + } + return true; + } + + public boolean verify() { + assertTrue(isAlive(), "cannot verify inactive nodes (id=%d)", id); + assertTrue(graph() != null, "null graph"); + verifyInputs(); + if (Options.VerifyGraalGraphEdges.getValue()) { + verifyEdges(); + } + return true; + } + + /** + * Perform expensive verification of inputs, usages, predecessors and successors. + * + * @return true + */ + public boolean verifyEdges() { + for (Node input : inputs()) { + assertTrue(input == null || input.usages().contains(this), "missing usage of %s in input %s", this, input); + } + + for (Node successor : successors()) { + assertTrue(successor.predecessor() == this, "missing predecessor in %s (actual: %s)", successor, successor.predecessor()); + assertTrue(successor.graph() == graph(), "mismatching graph in successor %s", successor); + } + for (Node usage : usages()) { + assertFalse(usage.isDeleted(), "usage %s must never be deleted", usage); + assertTrue(usage.inputs().contains(this), "missing input in usage %s", usage); + boolean foundThis = false; + for (Position pos : usage.inputPositions()) { + if (pos.get(usage) == this) { + foundThis = true; + if (pos.getInputType() != InputType.Unchecked) { + assertTrue(isAllowedUsageType(pos.getInputType()), "invalid input of type %s from %s to %s (%s)", pos.getInputType(), usage, this, pos.getName()); + } + } + } + assertTrue(foundThis, "missing input in usage %s", usage); + } + + if (predecessor != null) { + assertFalse(predecessor.isDeleted(), "predecessor %s must never be deleted", predecessor); + assertTrue(predecessor.successors().contains(this), "missing successor in predecessor %s", predecessor); + } + return true; + } + + public boolean assertTrue(boolean condition, String message, Object... args) { + if (condition) { + return true; + } else { + throw fail(message, args); + } + } + + public boolean assertFalse(boolean condition, String message, Object... args) { + if (condition) { + throw fail(message, args); + } else { + return true; + } + } + + protected VerificationError fail(String message, Object... args) throws GraalGraphError { + throw new VerificationError(message, args).addContext(this); + } + + public Iterable cfgPredecessors() { + if (predecessor == null) { + return Collections.emptySet(); + } else { + return Collections.singleton(predecessor); + } + } + + /** + * Returns an iterator that will provide all control-flow successors of this node. Normally this + * will be the contents of all fields annotated with {@link Successor}, but some node classes + * (like EndNode) may return different nodes. + */ + public Iterable cfgSuccessors() { + return successors(); + } + + /** + * Nodes always use an {@linkplain System#identityHashCode(Object) identity} hash code. + */ + @Override + public final int hashCode() { + return System.identityHashCode(this); + } + + /** + * Equality tests must rely solely on identity. + */ + @Override + public final boolean equals(Object obj) { + return super.equals(obj); + } + + /** + * Provides a {@link Map} of properties of this node for use in debugging (e.g., to view in the + * ideal graph visualizer). + */ + public final Map getDebugProperties() { + return getDebugProperties(new HashMap<>()); + } + + /** + * Fills a {@link Map} with properties of this node for use in debugging (e.g., to view in the + * ideal graph visualizer). Subclasses overriding this method should also fill the map using + * their superclass. + * + * @param map + */ + public Map getDebugProperties(Map map) { + Fields properties = getNodeClass().getData(); + for (int i = 0; i < properties.getCount(); i++) { + map.put(properties.getName(i), properties.get(this, i)); + } + NodeSourcePosition pos = getNodeSourcePosition(); + if (pos != null) { + map.put("nodeSourcePosition", pos); + } + return map; + } + + /** + * This method is a shortcut for {@link #toString(Verbosity)} with {@link Verbosity#Short}. + */ + @Override + public final String toString() { + return toString(Verbosity.Short); + } + + /** + * Creates a String representation for this node with a given {@link Verbosity}. + */ + public String toString(Verbosity verbosity) { + switch (verbosity) { + case Id: + return Integer.toString(id); + case Name: + return getNodeClass().shortName(); + case Short: + return toString(Verbosity.Id) + "|" + toString(Verbosity.Name); + case Long: + return toString(Verbosity.Short); + case Debugger: + case All: { + StringBuilder str = new StringBuilder(); + str.append(toString(Verbosity.Short)).append(" { "); + for (Map.Entry entry : getDebugProperties().entrySet()) { + str.append(entry.getKey()).append("=").append(entry.getValue()).append(", "); + } + str.append(" }"); + return str.toString(); + } + default: + throw new RuntimeException("unknown verbosity: " + verbosity); + } + } + + @Deprecated + public int getId() { + return id; + } + + @Override + public void formatTo(Formatter formatter, int flags, int width, int precision) { + if ((flags & FormattableFlags.ALTERNATE) == FormattableFlags.ALTERNATE) { + formatter.format("%s", toString(Verbosity.Id)); + } else if ((flags & FormattableFlags.UPPERCASE) == FormattableFlags.UPPERCASE) { + // Use All here since Long is only slightly longer than Short. + formatter.format("%s", toString(Verbosity.All)); + } else { + formatter.format("%s", toString(Verbosity.Short)); + } + + boolean neighborsAlternate = ((flags & FormattableFlags.LEFT_JUSTIFY) == FormattableFlags.LEFT_JUSTIFY); + int neighborsFlags = (neighborsAlternate ? FormattableFlags.ALTERNATE | FormattableFlags.LEFT_JUSTIFY : 0); + if (width > 0) { + if (this.predecessor != null) { + formatter.format(" pred={"); + this.predecessor.formatTo(formatter, neighborsFlags, width - 1, 0); + formatter.format("}"); + } + + for (Position position : this.inputPositions()) { + Node input = position.get(this); + if (input != null) { + formatter.format(" "); + formatter.format(position.getName()); + formatter.format("={"); + input.formatTo(formatter, neighborsFlags, width - 1, 0); + formatter.format("}"); + } + } + } + + if (precision > 0) { + if (!hasNoUsages()) { + formatter.format(" usages={"); + int z = 0; + for (Node usage : usages()) { + if (z != 0) { + formatter.format(", "); + } + usage.formatTo(formatter, neighborsFlags, 0, precision - 1); + ++z; + } + formatter.format("}"); + } + + for (Position position : this.successorPositions()) { + Node successor = position.get(this); + if (successor != null) { + formatter.format(" "); + formatter.format(position.getName()); + formatter.format("={"); + successor.formatTo(formatter, neighborsFlags, 0, precision - 1); + formatter.format("}"); + } + } + } + } + + /** + * Determines if this node's {@link NodeClass#getData() data} fields are equal to the data + * fields of another node of the same type. Primitive fields are compared by value and + * non-primitive fields are compared by {@link Objects#equals(Object, Object)}. + * + * The result of this method undefined if {@code other.getClass() != this.getClass()}. + * + * @param other a node of exactly the same type as this node + * @return true if the data fields of this object and {@code other} are equal + */ + public boolean valueEquals(Node other) { + return getNodeClass().dataEquals(this, other); + } + + public final void pushInputs(NodeStack stack) { + getNodeClass().pushInputs(this, stack); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java 2016-12-07 13:49:13.762754918 -0800 @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2011, 2011, 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.graph; + +import java.util.Arrays; +import java.util.Iterator; + +import org.graalvm.compiler.graph.iterators.NodeIterable; + +public final class NodeBitMap implements NodeIterable { + private static final int SHIFT = 6; + + private long[] bits; + private int nodeCount; + private int counter; + private final Graph graph; + + public NodeBitMap(Graph graph) { + this.nodeCount = graph.nodeIdCount(); + this.bits = new long[sizeForNodeCount(nodeCount)]; + this.graph = graph; + } + + private static int sizeForNodeCount(int nodeCount) { + return (nodeCount + Long.SIZE - 1) >> SHIFT; + } + + public int getCounter() { + return counter; + } + + private NodeBitMap(NodeBitMap other) { + this.bits = other.bits.clone(); + this.nodeCount = other.nodeCount; + this.graph = other.graph; + } + + public Graph graph() { + return graph; + } + + public boolean isNew(Node node) { + return node.id() >= nodeCount; + } + + public boolean isMarked(Node node) { + assert check(node, false); + return isMarked(node.id()); + } + + public boolean checkAndMarkInc(Node node) { + if (!isMarked(node)) { + this.counter++; + this.mark(node); + return true; + } else { + return false; + } + } + + public boolean isMarked(int id) { + return (bits[id >> SHIFT] & (1L << id)) != 0; + } + + public boolean isMarkedAndGrow(Node node) { + assert check(node, true); + int id = node.id(); + checkGrow(id); + return isMarked(id); + } + + public void mark(Node node) { + assert check(node, false); + int id = node.id(); + bits[id >> SHIFT] |= (1L << id); + } + + public void markAndGrow(Node node) { + assert check(node, true); + int id = node.id(); + checkGrow(id); + bits[id >> SHIFT] |= (1L << id); + } + + public void clear(Node node) { + assert check(node, false); + int id = node.id(); + bits[id >> SHIFT] &= ~(1L << id); + } + + public void clearAndGrow(Node node) { + assert check(node, true); + int id = node.id(); + checkGrow(id); + bits[id >> SHIFT] &= ~(1L << id); + } + + private void checkGrow(int id) { + if (id >= nodeCount) { + if ((id >> SHIFT) >= bits.length) { + grow(); + } else { + nodeCount = id + 1; + } + } + } + + public void clearAll() { + Arrays.fill(bits, 0); + } + + public void intersect(NodeBitMap other) { + assert graph() == other.graph(); + int commonLength = Math.min(bits.length, other.bits.length); + for (int i = commonLength; i < bits.length; i++) { + bits[i] = 0; + } + for (int i = 0; i < commonLength; i++) { + bits[i] &= other.bits[i]; + } + } + + public void subtract(NodeBitMap other) { + assert graph() == other.graph(); + int commonLength = Math.min(bits.length, other.bits.length); + for (int i = 0; i < commonLength; i++) { + bits[i] &= ~other.bits[i]; + } + } + + public void union(NodeBitMap other) { + assert graph() == other.graph(); + grow(); + if (bits.length < other.bits.length) { + bits = Arrays.copyOf(bits, other.bits.length); + } + for (int i = 0; i < bits.length; i++) { + bits[i] |= other.bits[i]; + } + } + + public void grow() { + nodeCount = Math.max(nodeCount, graph().nodeIdCount()); + int newLength = sizeForNodeCount(nodeCount); + if (newLength > bits.length) { + newLength = Math.max(newLength, (bits.length * 3 / 2) + 1); + bits = Arrays.copyOf(bits, newLength); + } + } + + private boolean check(Node node, boolean grow) { + assert node.graph() == graph() : "this node is not part of the graph: " + node; + assert grow || !isNew(node) : "node was added to the graph after creating the node bitmap: " + node; + assert node.isAlive() : "node is deleted!" + node; + return true; + } + + public void markAll(Iterable nodes) { + for (Node node : nodes) { + mark(node); + } + } + + private static class MarkedNodeIterator implements Iterator { + + private final NodeBitMap visited; + private Iterator nodes; + private Node nextNode; + + MarkedNodeIterator(NodeBitMap visited, Iterator nodes) { + this.visited = visited; + this.nodes = nodes; + forward(); + } + + private void forward() { + do { + if (!nodes.hasNext()) { + nextNode = null; + return; + } + nextNode = nodes.next(); + if (visited.isNew(nextNode)) { + nextNode = null; + return; + } + } while (!visited.isMarked(nextNode)); + } + + @Override + public boolean hasNext() { + return nextNode != null; + } + + @Override + public Node next() { + try { + return nextNode; + } finally { + forward(); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + } + + @Override + public Iterator iterator() { + return new MarkedNodeIterator(NodeBitMap.this, graph().getNodes().iterator()); + } + + public NodeBitMap copy() { + return new NodeBitMap(this); + } + + @Override + public int count() { + int count = 0; + for (long l : bits) { + count += Long.bitCount(l); + } + return count; + } + + @Override + public boolean contains(Node node) { + return isMarked(node); + } + + @Override + public String toString() { + return snapshot().toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java 2016-12-07 13:49:14.028766611 -0800 @@ -0,0 +1,1360 @@ +/* + * Copyright (c) 2011, 2014, 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.graph; + +import static org.graalvm.compiler.core.common.Fields.translateInto; +import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; +import static org.graalvm.compiler.graph.Edges.translateInto; +import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled; +import static org.graalvm.compiler.graph.InputEdges.translateInto; +import static org.graalvm.compiler.graph.Node.WithAllEdges; +import static org.graalvm.compiler.graph.Node.newIdentityMap; +import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; + +import org.graalvm.compiler.core.common.FieldIntrospection; +import org.graalvm.compiler.core.common.Fields; +import org.graalvm.compiler.core.common.FieldsScanner; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.DebugTimer; +import org.graalvm.compiler.debug.Fingerprint; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Edges.Type; +import org.graalvm.compiler.graph.Graph.DuplicationReplacement; +import org.graalvm.compiler.graph.Node.EdgeVisitor; +import org.graalvm.compiler.graph.Node.Input; +import org.graalvm.compiler.graph.Node.OptionalInput; +import org.graalvm.compiler.graph.Node.Successor; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative; +import org.graalvm.compiler.graph.spi.Simplifiable; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeCycles; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodeinfo.NodeSize; +import org.graalvm.compiler.nodeinfo.Verbosity; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.StableOptionValue; + +/** + * Metadata for every {@link Node} type. The metadata includes: + *

    + *
  • The offsets of fields annotated with {@link Input} and {@link Successor} as well as methods + * for iterating over such fields.
  • + *
  • The identifier for an {@link IterableNodeType} class.
  • + *
+ */ +public final class NodeClass extends FieldIntrospection { + + public static class Options { + // @formatter:off + @Option(help = "Verifies that receivers of NodeInfo#size() and NodeInfo#cycles() do not have UNSET values.") + public static final OptionValue VerifyNodeCostOnAccess = new StableOptionValue<>(false); + // @formatter:on + } + + // Timers for creation of a NodeClass instance + private static final DebugTimer Init_FieldScanning = Debug.timer("NodeClass.Init.FieldScanning"); + private static final DebugTimer Init_FieldScanningInner = Debug.timer("NodeClass.Init.FieldScanning.Inner"); + private static final DebugTimer Init_AnnotationParsing = Debug.timer("NodeClass.Init.AnnotationParsing"); + private static final DebugTimer Init_Edges = Debug.timer("NodeClass.Init.Edges"); + private static final DebugTimer Init_Data = Debug.timer("NodeClass.Init.Data"); + private static final DebugTimer Init_AllowedUsages = Debug.timer("NodeClass.Init.AllowedUsages"); + private static final DebugTimer Init_IterableIds = Debug.timer("NodeClass.Init.IterableIds"); + + public static final long MAX_EDGES = 8; + public static final long MAX_LIST_EDGES = 6; + public static final long OFFSET_MASK = 0xFC; + public static final long LIST_MASK = 0x01; + public static final long NEXT_EDGE = 0x08; + + @SuppressWarnings("try") + private static T getAnnotationTimed(AnnotatedElement e, Class annotationClass) { + try (DebugCloseable s = Init_AnnotationParsing.start()) { + return e.getAnnotation(annotationClass); + } + } + + /** + * Gets the {@link NodeClass} associated with a given {@link Class}. + */ + public static NodeClass create(Class c) { + assert get(c) == null; + Class superclass = c.getSuperclass(); + NodeClass nodeSuperclass = null; + if (superclass != NODE_CLASS) { + nodeSuperclass = get(superclass); + } + return new NodeClass<>(c, nodeSuperclass); + } + + @SuppressWarnings("unchecked") + public static NodeClass get(Class superclass) { + try { + Field field = superclass.getDeclaredField("TYPE"); + field.setAccessible(true); + return (NodeClass) field.get(null); + } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { + throw new RuntimeException(e); + } + } + + private static final Class NODE_CLASS = Node.class; + private static final Class INPUT_LIST_CLASS = NodeInputList.class; + private static final Class SUCCESSOR_LIST_CLASS = NodeSuccessorList.class; + + private static AtomicInteger nextIterableId = new AtomicInteger(); + + private final InputEdges inputs; + private final SuccessorEdges successors; + private final NodeClass superNodeClass; + + private final boolean canGVN; + private final int startGVNNumber; + private final String nameTemplate; + private final int iterableId; + private final EnumSet allowedUsageTypes; + private int[] iterableIds; + private final long inputsIteration; + private final long successorIteration; + + private static final DebugCounter ITERABLE_NODE_TYPES = Debug.counter("IterableNodeTypes"); + private final DebugCounter nodeIterableCount; + + /** + * Determines if this node type implements {@link Canonicalizable}. + */ + private final boolean isCanonicalizable; + + /** + * Determines if this node type implements {@link BinaryCommutative}. + */ + private final boolean isCommutative; + + /** + * Determines if this node type implements {@link Simplifiable}. + */ + private final boolean isSimplifiable; + private final boolean isLeafNode; + + public NodeClass(Class clazz, NodeClass superNodeClass) { + this(clazz, superNodeClass, new FieldsScanner.DefaultCalcOffset(), null, 0); + } + + @SuppressWarnings("try") + public NodeClass(Class clazz, NodeClass superNodeClass, FieldsScanner.CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) { + super(clazz); + this.superNodeClass = superNodeClass; + assert NODE_CLASS.isAssignableFrom(clazz); + + this.isCanonicalizable = Canonicalizable.class.isAssignableFrom(clazz); + this.isCommutative = BinaryCommutative.class.isAssignableFrom(clazz); + if (Canonicalizable.Unary.class.isAssignableFrom(clazz) || Canonicalizable.Binary.class.isAssignableFrom(clazz)) { + assert Canonicalizable.Unary.class.isAssignableFrom(clazz) ^ Canonicalizable.Binary.class.isAssignableFrom(clazz) : clazz + " should implement either Unary or Binary, not both"; + } + + this.isSimplifiable = Simplifiable.class.isAssignableFrom(clazz); + + NodeFieldsScanner fs = new NodeFieldsScanner(calcOffset, superNodeClass); + try (DebugCloseable t = Init_FieldScanning.start()) { + fs.scan(clazz, clazz.getSuperclass(), false); + } + + try (DebugCloseable t1 = Init_Edges.start()) { + successors = new SuccessorEdges(fs.directSuccessors, fs.successors); + successorIteration = computeIterationMask(successors.type(), successors.getDirectCount(), successors.getOffsets()); + inputs = new InputEdges(fs.directInputs, fs.inputs); + inputsIteration = computeIterationMask(inputs.type(), inputs.getDirectCount(), inputs.getOffsets()); + } + try (DebugCloseable t1 = Init_Data.start()) { + data = new Fields(fs.data); + } + + isLeafNode = inputs.getCount() + successors.getCount() == 0; + + canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz); + startGVNNumber = clazz.getName().hashCode(); + + NodeInfo info = getAnnotationTimed(clazz, NodeInfo.class); + assert info != null : "Missing NodeInfo annotation on " + clazz; + this.nameTemplate = info.nameTemplate(); + + try (DebugCloseable t1 = Init_AllowedUsages.start()) { + allowedUsageTypes = superNodeClass == null ? EnumSet.noneOf(InputType.class) : superNodeClass.allowedUsageTypes.clone(); + allowedUsageTypes.addAll(Arrays.asList(info.allowedUsageTypes())); + } + + if (presetIterableIds != null) { + this.iterableIds = presetIterableIds; + this.iterableId = presetIterableId; + } else if (IterableNodeType.class.isAssignableFrom(clazz)) { + ITERABLE_NODE_TYPES.increment(); + try (DebugCloseable t1 = Init_IterableIds.start()) { + this.iterableId = nextIterableId.getAndIncrement(); + + NodeClass snc = superNodeClass; + while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) { + snc.addIterableId(iterableId); + snc = snc.superNodeClass; + } + + this.iterableIds = new int[]{iterableId}; + } + } else { + this.iterableId = Node.NOT_ITERABLE; + this.iterableIds = null; + } + nodeIterableCount = Debug.counter("NodeIterable_%s", clazz); + assert verifyIterableIds(); + + try (Debug.Scope scope = Debug.scope("NodeCosts")) { + /* + * Note: We do not check for the existence of the node cost annotations during + * construction as not every node needs to have them set. However if costs are queried, + * after the construction of the node class, they must be properly set. This is + * important as we can not trust our cost model if there are unspecified nodes. Nodes + * that do not need cost annotations are e.g. abstractions like FixedNode or + * FloatingNode or ValueNode. Sub classes where costs are not specified will ask the + * superclass for their costs during node class initialization. Therefore getters for + * cycles and size can omit verification during creation. + */ + NodeCycles c = info.cycles(); + if (c == NodeCycles.CYCLES_UNSET) { + cycles = superNodeClass != null ? superNodeClass.cycles : NodeCycles.CYCLES_UNSET; + } else { + cycles = c; + } + assert cycles != null; + NodeSize s = info.size(); + if (s == NodeSize.SIZE_UNSET) { + size = superNodeClass != null ? superNodeClass.size : NodeSize.SIZE_UNSET; + } else { + size = s; + } + assert size != null; + Debug.log("Node cost for node of type __| %s |_, cycles:%s,size:%s", clazz, cycles, size); + } + + } + + private final NodeCycles cycles; + private final NodeSize size; + + public NodeCycles cycles() { + if (Options.VerifyNodeCostOnAccess.getValue() && cycles == NodeCycles.CYCLES_UNSET) { + throw new GraalError("Missing NodeCycles specification in the @NodeInfo annotation of the node %s", this); + } + return cycles; + } + + public NodeSize size() { + if (Options.VerifyNodeCostOnAccess.getValue() && size == NodeSize.SIZE_UNSET) { + throw new GraalError("Missing NodeSize specification in the @NodeInfo annotation of the node %s", this); + } + return size; + } + + public static long computeIterationMask(Type type, int directCount, long[] offsets) { + long mask = 0; + if (offsets.length > NodeClass.MAX_EDGES) { + throw new GraalError("Exceeded maximum of %d edges (%s)", NodeClass.MAX_EDGES, type); + } + if (offsets.length - directCount > NodeClass.MAX_LIST_EDGES) { + throw new GraalError("Exceeded maximum of %d list edges (%s)", NodeClass.MAX_LIST_EDGES, type); + } + + for (int i = offsets.length - 1; i >= 0; i--) { + long offset = offsets[i]; + assert ((offset & 0xFF) == offset) : "field offset too large!"; + mask <<= NodeClass.NEXT_EDGE; + mask |= offset; + if (i >= directCount) { + mask |= 0x3; + } + } + return mask; + } + + private synchronized void addIterableId(int newIterableId) { + assert !containsId(newIterableId, iterableIds); + int[] copy = Arrays.copyOf(iterableIds, iterableIds.length + 1); + copy[iterableIds.length] = newIterableId; + iterableIds = copy; + } + + private boolean verifyIterableIds() { + NodeClass snc = superNodeClass; + while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) { + assert containsId(iterableId, snc.iterableIds); + snc = snc.superNodeClass; + } + return true; + } + + private static boolean containsId(int iterableId, int[] iterableIds) { + for (int i : iterableIds) { + if (i == iterableId) { + return true; + } + } + return false; + } + + private String shortName; + + public String shortName() { + if (shortName == null) { + NodeInfo info = getClazz().getAnnotation(NodeInfo.class); + if (!info.shortName().isEmpty()) { + shortName = info.shortName(); + } else { + String localShortName = getClazz().getSimpleName(); + if (localShortName.endsWith("Node") && !localShortName.equals("StartNode") && !localShortName.equals("EndNode")) { + shortName = localShortName.substring(0, localShortName.length() - 4); + } else { + shortName = localShortName; + } + } + } + return shortName; + } + + @Override + public Fields[] getAllFields() { + return new Fields[]{data, inputs, successors}; + } + + public int[] iterableIds() { + nodeIterableCount.increment(); + return iterableIds; + } + + public int iterableId() { + return iterableId; + } + + public boolean valueNumberable() { + return canGVN; + } + + /** + * Determines if this node type implements {@link Canonicalizable}. + */ + public boolean isCanonicalizable() { + return isCanonicalizable; + } + + /** + * Determines if this node type implements {@link BinaryCommutative}. + */ + public boolean isCommutative() { + return isCommutative; + } + + /** + * Determines if this node type implements {@link Simplifiable}. + */ + public boolean isSimplifiable() { + return isSimplifiable; + } + + static int allocatedNodeIterabledIds() { + return nextIterableId.get(); + } + + public EnumSet getAllowedUsageTypes() { + return allowedUsageTypes; + } + + /** + * Describes a field representing an input or successor edge in a node. + */ + protected static class EdgeInfo extends FieldsScanner.FieldInfo { + + public EdgeInfo(long offset, String name, Class type, Class declaringClass) { + super(offset, name, type, declaringClass); + } + + /** + * Sorts non-list edges before list edges. + */ + @Override + public int compareTo(FieldsScanner.FieldInfo o) { + if (NodeList.class.isAssignableFrom(o.type)) { + if (!NodeList.class.isAssignableFrom(type)) { + return -1; + } + } else { + if (NodeList.class.isAssignableFrom(type)) { + return 1; + } + } + return super.compareTo(o); + } + } + + /** + * Describes a field representing an {@linkplain Type#Inputs input} edge in a node. + */ + protected static class InputInfo extends EdgeInfo { + final InputType inputType; + final boolean optional; + + public InputInfo(long offset, String name, Class type, Class declaringClass, InputType inputType, boolean optional) { + super(offset, name, type, declaringClass); + this.inputType = inputType; + this.optional = optional; + } + + @Override + public String toString() { + return super.toString() + "{inputType=" + inputType + ", optional=" + optional + "}"; + } + } + + protected static class NodeFieldsScanner extends FieldsScanner { + + public final ArrayList inputs = new ArrayList<>(); + public final ArrayList successors = new ArrayList<>(); + int directInputs; + int directSuccessors; + + protected NodeFieldsScanner(FieldsScanner.CalcOffset calc, NodeClass superNodeClass) { + super(calc); + if (superNodeClass != null) { + translateInto(superNodeClass.inputs, inputs); + translateInto(superNodeClass.successors, successors); + translateInto(superNodeClass.data, data); + directInputs = superNodeClass.inputs.getDirectCount(); + directSuccessors = superNodeClass.successors.getDirectCount(); + } + } + + @SuppressWarnings("try") + @Override + protected void scanField(Field field, long offset) { + Input inputAnnotation = getAnnotationTimed(field, Node.Input.class); + OptionalInput optionalInputAnnotation = getAnnotationTimed(field, Node.OptionalInput.class); + Successor successorAnnotation = getAnnotationTimed(field, Successor.class); + try (DebugCloseable s = Init_FieldScanningInner.start()) { + Class type = field.getType(); + int modifiers = field.getModifiers(); + + if (inputAnnotation != null || optionalInputAnnotation != null) { + assert successorAnnotation == null : "field cannot be both input and successor"; + if (INPUT_LIST_CLASS.isAssignableFrom(type)) { + // NodeInputList fields should not be final since they are + // written (via Unsafe) in clearInputs() + GraalError.guarantee(!Modifier.isFinal(modifiers), "NodeInputList input field %s should not be final", field); + GraalError.guarantee(!Modifier.isPublic(modifiers), "NodeInputList input field %s should not be public", field); + } else { + GraalError.guarantee(NODE_CLASS.isAssignableFrom(type) || type.isInterface(), "invalid input type: %s", type); + GraalError.guarantee(!Modifier.isFinal(modifiers), "Node input field %s should not be final", field); + directInputs++; + } + InputType inputType; + if (inputAnnotation != null) { + assert optionalInputAnnotation == null : "inputs can either be optional or non-optional"; + inputType = inputAnnotation.value(); + } else { + inputType = optionalInputAnnotation.value(); + } + inputs.add(new InputInfo(offset, field.getName(), type, field.getDeclaringClass(), inputType, field.isAnnotationPresent(Node.OptionalInput.class))); + } else if (successorAnnotation != null) { + if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) { + // NodeSuccessorList fields should not be final since they are + // written (via Unsafe) in clearSuccessors() + GraalError.guarantee(!Modifier.isFinal(modifiers), "NodeSuccessorList successor field % should not be final", field); + GraalError.guarantee(!Modifier.isPublic(modifiers), "NodeSuccessorList successor field %s should not be public", field); + } else { + GraalError.guarantee(NODE_CLASS.isAssignableFrom(type), "invalid successor type: %s", type); + GraalError.guarantee(!Modifier.isFinal(modifiers), "Node successor field %s should not be final", field); + directSuccessors++; + } + successors.add(new EdgeInfo(offset, field.getName(), type, field.getDeclaringClass())); + } else { + GraalError.guarantee(!NODE_CLASS.isAssignableFrom(type) || field.getName().equals("Null"), "suspicious node field: %s", field); + GraalError.guarantee(!INPUT_LIST_CLASS.isAssignableFrom(type), "suspicious node input list field: %s", field); + GraalError.guarantee(!SUCCESSOR_LIST_CLASS.isAssignableFrom(type), "suspicious node successor list field: %s", field); + super.scanField(field, offset); + } + } + } + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append("NodeClass ").append(getClazz().getSimpleName()).append(" ["); + inputs.appendFields(str); + str.append("] ["); + successors.appendFields(str); + str.append("] ["); + data.appendFields(str); + str.append("]"); + return str.toString(); + } + + private static int deepHashCode0(Object o) { + if (o instanceof Object[]) { + return Arrays.deepHashCode((Object[]) o); + } else if (o instanceof byte[]) { + return Arrays.hashCode((byte[]) o); + } else if (o instanceof short[]) { + return Arrays.hashCode((short[]) o); + } else if (o instanceof int[]) { + return Arrays.hashCode((int[]) o); + } else if (o instanceof long[]) { + return Arrays.hashCode((long[]) o); + } else if (o instanceof char[]) { + return Arrays.hashCode((char[]) o); + } else if (o instanceof float[]) { + return Arrays.hashCode((float[]) o); + } else if (o instanceof double[]) { + return Arrays.hashCode((double[]) o); + } else if (o instanceof boolean[]) { + return Arrays.hashCode((boolean[]) o); + } else if (o != null) { + return o.hashCode(); + } else { + return 0; + } + } + + public int valueNumber(Node n) { + int number = 0; + if (canGVN) { + number = startGVNNumber; + for (int i = 0; i < data.getCount(); ++i) { + Class type = data.getType(i); + if (type.isPrimitive()) { + if (type == Integer.TYPE) { + int intValue = data.getInt(n, i); + number += intValue; + } else if (type == Long.TYPE) { + long longValue = data.getLong(n, i); + number += longValue ^ (longValue >>> 32); + } else if (type == Boolean.TYPE) { + boolean booleanValue = data.getBoolean(n, i); + if (booleanValue) { + number += 7; + } + } else if (type == Float.TYPE) { + float floatValue = data.getFloat(n, i); + number += Float.floatToRawIntBits(floatValue); + } else if (type == Double.TYPE) { + double doubleValue = data.getDouble(n, i); + long longValue = Double.doubleToRawLongBits(doubleValue); + number += longValue ^ (longValue >>> 32); + } else if (type == Short.TYPE) { + short shortValue = data.getShort(n, i); + number += shortValue; + } else if (type == Character.TYPE) { + char charValue = data.getChar(n, i); + number += charValue; + } else if (type == Byte.TYPE) { + byte byteValue = data.getByte(n, i); + number += byteValue; + } else { + assert false : "unhandled property type: " + type; + } + } else { + Object o = data.getObject(n, i); + number += deepHashCode0(o); + } + number *= 13; + } + } + return number; + } + + private static boolean deepEquals0(Object e1, Object e2) { + assert e1 != null; + boolean eq; + if (e1 instanceof Object[] && e2 instanceof Object[]) { + eq = Arrays.deepEquals((Object[]) e1, (Object[]) e2); + } else if (e1 instanceof byte[] && e2 instanceof byte[]) { + eq = Arrays.equals((byte[]) e1, (byte[]) e2); + } else if (e1 instanceof short[] && e2 instanceof short[]) { + eq = Arrays.equals((short[]) e1, (short[]) e2); + } else if (e1 instanceof int[] && e2 instanceof int[]) { + eq = Arrays.equals((int[]) e1, (int[]) e2); + } else if (e1 instanceof long[] && e2 instanceof long[]) { + eq = Arrays.equals((long[]) e1, (long[]) e2); + } else if (e1 instanceof char[] && e2 instanceof char[]) { + eq = Arrays.equals((char[]) e1, (char[]) e2); + } else if (e1 instanceof float[] && e2 instanceof float[]) { + eq = Arrays.equals((float[]) e1, (float[]) e2); + } else if (e1 instanceof double[] && e2 instanceof double[]) { + eq = Arrays.equals((double[]) e1, (double[]) e2); + } else if (e1 instanceof boolean[] && e2 instanceof boolean[]) { + eq = Arrays.equals((boolean[]) e1, (boolean[]) e2); + } else { + eq = e1.equals(e2); + } + return eq; + } + + public boolean dataEquals(Node a, Node b) { + assert a.getClass() == b.getClass(); + for (int i = 0; i < data.getCount(); ++i) { + Class type = data.getType(i); + if (type.isPrimitive()) { + if (type == Integer.TYPE) { + int aInt = data.getInt(a, i); + int bInt = data.getInt(b, i); + if (aInt != bInt) { + return false; + } + } else if (type == Boolean.TYPE) { + boolean aBoolean = data.getBoolean(a, i); + boolean bBoolean = data.getBoolean(b, i); + if (aBoolean != bBoolean) { + return false; + } + } else if (type == Long.TYPE) { + long aLong = data.getLong(a, i); + long bLong = data.getLong(b, i); + if (aLong != bLong) { + return false; + } + } else if (type == Float.TYPE) { + float aFloat = data.getFloat(a, i); + float bFloat = data.getFloat(b, i); + if (aFloat != bFloat) { + return false; + } + } else if (type == Double.TYPE) { + double aDouble = data.getDouble(a, i); + double bDouble = data.getDouble(b, i); + if (aDouble != bDouble) { + return false; + } + } else if (type == Short.TYPE) { + short aShort = data.getShort(a, i); + short bShort = data.getShort(b, i); + if (aShort != bShort) { + return false; + } + } else if (type == Character.TYPE) { + char aChar = data.getChar(a, i); + char bChar = data.getChar(b, i); + if (aChar != bChar) { + return false; + } + } else if (type == Byte.TYPE) { + byte aByte = data.getByte(a, i); + byte bByte = data.getByte(b, i); + if (aByte != bByte) { + return false; + } + } else { + assert false : "unhandled type: " + type; + } + } else { + Object objectA = data.getObject(a, i); + Object objectB = data.getObject(b, i); + if (objectA != objectB) { + if (objectA != null && objectB != null) { + if (!deepEquals0(objectA, objectB)) { + return false; + } + } else { + return false; + } + } + } + } + return true; + } + + public boolean isValid(Position pos, NodeClass from, Edges fromEdges) { + if (this == from) { + return true; + } + Edges toEdges = getEdges(fromEdges.type()); + if (pos.getIndex() >= toEdges.getCount()) { + return false; + } + if (pos.getIndex() >= fromEdges.getCount()) { + return false; + } + return toEdges.isSame(fromEdges, pos.getIndex()); + } + + static void updateEdgesInPlace(Node node, InplaceUpdateClosure duplicationReplacement, Edges edges) { + int index = 0; + Type curType = edges.type(); + int directCount = edges.getDirectCount(); + final long[] curOffsets = edges.getOffsets(); + while (index < directCount) { + Node edge = Edges.getNode(node, curOffsets, index); + if (edge != null) { + Node newEdge = duplicationReplacement.replacement(edge, curType); + if (curType == Edges.Type.Inputs) { + node.updateUsages(null, newEdge); + } else { + node.updatePredecessor(null, newEdge); + } + edges.initializeNode(node, index, newEdge); + } + index++; + } + + while (index < edges.getCount()) { + NodeList list = Edges.getNodeList(node, curOffsets, index); + if (list != null) { + edges.initializeList(node, index, updateEdgeListCopy(node, list, duplicationReplacement, curType)); + } + index++; + } + } + + void updateInputSuccInPlace(Node node, InplaceUpdateClosure duplicationReplacement) { + updateEdgesInPlace(node, duplicationReplacement, inputs); + updateEdgesInPlace(node, duplicationReplacement, successors); + } + + private static NodeList updateEdgeListCopy(Node node, NodeList list, InplaceUpdateClosure duplicationReplacement, Edges.Type type) { + NodeList result = type == Edges.Type.Inputs ? new NodeInputList<>(node, list.size()) : new NodeSuccessorList<>(node, list.size()); + + for (int i = 0; i < list.count(); ++i) { + Node oldNode = list.get(i); + if (oldNode != null) { + Node newNode = duplicationReplacement.replacement(oldNode, type); + result.set(i, newNode); + } + } + return result; + } + + /** + * Gets the input or successor edges defined by this node class. + */ + public Edges getEdges(Edges.Type type) { + return type == Edges.Type.Inputs ? inputs : successors; + } + + public Edges getInputEdges() { + return inputs; + } + + public Edges getSuccessorEdges() { + return successors; + } + + /** + * Returns a newly allocated node for which no subclass-specific constructor has been called. + */ + @SuppressWarnings("unchecked") + public Node allocateInstance() { + try { + Node node = (Node) UNSAFE.allocateInstance(getJavaClass()); + node.init((NodeClass) this); + return node; + } catch (InstantiationException ex) { + throw shouldNotReachHere(ex); + } + } + + public Class getJavaClass() { + return getClazz(); + } + + /** + * The template used to build the {@link Verbosity#Name} version. Variable parts are specified + * using {i#inputName} or {p#propertyName}. + */ + public String getNameTemplate() { + return nameTemplate.isEmpty() ? shortName() : nameTemplate; + } + + interface InplaceUpdateClosure { + + Node replacement(Node node, Edges.Type type); + } + + static Map addGraphDuplicate(final Graph graph, final Graph oldGraph, int estimatedNodeCount, Iterable nodes, final DuplicationReplacement replacements) { + final Map newNodes; + int denseThreshold = oldGraph.getNodeCount() + oldGraph.getNodesDeletedSinceLastCompression() >> 4; + if (estimatedNodeCount > denseThreshold) { + // Use dense map + newNodes = new NodeNodeMap(oldGraph); + } else { + // Use sparse map + newNodes = newIdentityMap(); + } + createNodeDuplicates(graph, nodes, replacements, newNodes); + + InplaceUpdateClosure replacementClosure = new InplaceUpdateClosure() { + + @Override + public Node replacement(Node node, Edges.Type type) { + Node target = newNodes.get(node); + if (target == null) { + Node replacement = node; + if (replacements != null) { + replacement = replacements.replacement(node); + } + if (replacement != node) { + target = replacement; + } else if (node.graph() == graph && type == Edges.Type.Inputs) { + // patch to the outer world + target = node; + } + + } + return target; + } + + }; + + // re-wire inputs + for (Node oldNode : nodes) { + Node node = newNodes.get(oldNode); + NodeClass nodeClass = node.getNodeClass(); + if (replacements == null || replacements.replacement(oldNode) == oldNode) { + nodeClass.updateInputSuccInPlace(node, replacementClosure); + } else { + transferEdgesDifferentNodeClass(graph, replacements, newNodes, oldNode, node); + } + } + + return newNodes; + } + + private static void createNodeDuplicates(final Graph graph, Iterable nodes, final DuplicationReplacement replacements, final Map newNodes) { + for (Node node : nodes) { + if (node != null) { + assert !node.isDeleted() : "trying to duplicate deleted node: " + node; + Node replacement = node; + if (replacements != null) { + replacement = replacements.replacement(node); + } + if (replacement != node) { + if (Fingerprint.ENABLED) { + Fingerprint.submit("replacing %s with %s", node, replacement); + } + assert replacement != null; + newNodes.put(node, replacement); + } else { + if (Fingerprint.ENABLED) { + Fingerprint.submit("duplicating %s", node); + } + Node newNode = node.clone(graph, WithAllEdges); + assert newNode.getNodeClass().isLeafNode() || newNode.hasNoUsages(); + assert newNode.getClass() == node.getClass(); + newNodes.put(node, newNode); + } + } + } + } + + private static void transferEdgesDifferentNodeClass(final Graph graph, final DuplicationReplacement replacements, final Map newNodes, Node oldNode, Node node) { + transferEdges(graph, replacements, newNodes, oldNode, node, Edges.Type.Inputs); + transferEdges(graph, replacements, newNodes, oldNode, node, Edges.Type.Successors); + } + + private static void transferEdges(final Graph graph, final DuplicationReplacement replacements, final Map newNodes, Node oldNode, Node node, Edges.Type type) { + NodeClass nodeClass = node.getNodeClass(); + NodeClass oldNodeClass = oldNode.getNodeClass(); + Edges oldEdges = oldNodeClass.getEdges(type); + for (Position pos : oldEdges.getPositionsIterable(oldNode)) { + if (!nodeClass.isValid(pos, oldNodeClass, oldEdges)) { + continue; + } + Node oldEdge = pos.get(oldNode); + if (oldEdge != null) { + Node target = newNodes.get(oldEdge); + if (target == null) { + Node replacement = oldEdge; + if (replacements != null) { + replacement = replacements.replacement(oldEdge); + } + if (replacement != oldEdge) { + target = replacement; + } else if (type == Edges.Type.Inputs && oldEdge.graph() == graph) { + // patch to the outer world + target = oldEdge; + } + } + pos.set(node, target); + } + } + } + + /** + * @returns true if the node has no inputs and no successors + */ + public boolean isLeafNode() { + return isLeafNode; + } + + public long inputsIteration() { + return inputsIteration; + } + + /** + * An iterator that will iterate over edges. + * + * An iterator of this type will not return null values, unless edges are modified concurrently. + * Concurrent modifications are detected by an assertion on a best-effort basis. + */ + private static class RawEdgesIterator implements Iterator { + protected final Node node; + protected long mask; + protected Node nextValue; + + RawEdgesIterator(Node node, long mask) { + this.node = node; + this.mask = mask; + } + + @Override + public boolean hasNext() { + Node next = nextValue; + if (next != null) { + return true; + } else { + nextValue = forward(); + return nextValue != null; + } + } + + private Node forward() { + while (mask != 0) { + Node next = getInput(); + mask = advanceInput(); + if (next != null) { + return next; + } + } + return null; + } + + @Override + public Node next() { + Node next = nextValue; + if (next == null) { + next = forward(); + if (next == null) { + throw new NoSuchElementException(); + } else { + return next; + } + } else { + nextValue = null; + return next; + } + } + + public final long advanceInput() { + int state = (int) mask & 0x03; + if (state == 0) { + // Skip normal field. + return mask >>> NEXT_EDGE; + } else if (state == 1) { + // We are iterating a node list. + if ((mask & 0xFFFF00) != 0) { + // Node list count is non-zero, decrease by 1. + return mask - 0x100; + } else { + // Node list is finished => go to next input. + return mask >>> 24; + } + } else { + // Need to expand node list. + NodeList nodeList = Edges.getNodeListUnsafe(node, mask & 0xFC); + if (nodeList != null) { + int size = nodeList.size(); + if (size != 0) { + // Set pointer to upper most index of node list. + return ((mask >>> NEXT_EDGE) << 24) | (mask & 0xFD) | ((size - 1) << NEXT_EDGE); + } + } + // Node list is empty or null => skip. + return mask >>> NEXT_EDGE; + } + } + + public Node getInput() { + int state = (int) mask & 0x03; + if (state == 0) { + return Edges.getNodeUnsafe(node, mask & 0xFC); + } else if (state == 1) { + // We are iterating a node list. + NodeList nodeList = Edges.getNodeListUnsafe(node, mask & 0xFC); + return nodeList.nodes[nodeList.size() - 1 - (int) ((mask >>> NEXT_EDGE) & 0xFFFF)]; + } else { + // Node list needs to expand first. + return null; + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + public Position nextPosition() { + return null; + } + } + + private static final class RawEdgesWithModCountIterator extends RawEdgesIterator { + private final int modCount; + + private RawEdgesWithModCountIterator(Node node, long mask) { + super(node, mask); + assert isModificationCountsEnabled(); + this.modCount = node.modCount(); + } + + @Override + public boolean hasNext() { + try { + return super.hasNext(); + } finally { + assert modCount == node.modCount() : "must not be modified"; + } + } + + @Override + public Node next() { + try { + return super.next(); + } finally { + assert modCount == node.modCount() : "must not be modified"; + } + } + + @Override + public Position nextPosition() { + try { + return super.nextPosition(); + } finally { + assert modCount == node.modCount(); + } + } + } + + public NodeIterable getSuccessorIterable(final Node node) { + long mask = this.successorIteration; + return new NodeIterable() { + + @Override + public Iterator iterator() { + if (isModificationCountsEnabled()) { + return new RawEdgesWithModCountIterator(node, mask); + } else { + return new RawEdgesIterator(node, mask); + } + } + }; + } + + public NodeIterable getInputIterable(final Node node) { + long mask = this.inputsIteration; + return new NodeIterable() { + + @Override + public Iterator iterator() { + if (isModificationCountsEnabled()) { + return new RawEdgesWithModCountIterator(node, mask); + } else { + return new RawEdgesIterator(node, mask); + } + } + }; + } + + public boolean equalSuccessors(Node node, Node other) { + return equalEdges(node, other, successorIteration); + } + + public boolean equalInputs(Node node, Node other) { + return equalEdges(node, other, inputsIteration); + } + + private boolean equalEdges(Node node, Node other, long mask) { + long myMask = mask; + assert other.getNodeClass() == this; + while (myMask != 0) { + long offset = (myMask & OFFSET_MASK); + Object v1 = UNSAFE.getObject(node, offset); + Object v2 = UNSAFE.getObject(other, offset); + if ((myMask & LIST_MASK) == 0) { + if (v1 != v2) { + return false; + } + } else { + if (!Objects.equals(v1, v2)) { + return false; + } + } + myMask >>>= NEXT_EDGE; + } + return true; + } + + public void pushInputs(Node node, NodeStack stack) { + long myMask = this.inputsIteration; + while (myMask != 0) { + long offset = (myMask & OFFSET_MASK); + if ((myMask & LIST_MASK) == 0) { + Node curNode = Edges.getNodeUnsafe(node, offset); + if (curNode != null) { + stack.push(curNode); + } + } else { + pushAllHelper(stack, node, offset); + } + myMask >>>= NEXT_EDGE; + } + } + + private static void pushAllHelper(NodeStack stack, Node node, long offset) { + NodeList list = Edges.getNodeListUnsafe(node, offset); + if (list != null) { + for (int i = 0; i < list.size(); ++i) { + Node curNode = list.get(i); + if (curNode != null) { + stack.push(curNode); + } + } + } + } + + public void applySuccessors(Node node, EdgeVisitor consumer) { + applyEdges(node, consumer, this.successorIteration); + } + + public void applyInputs(Node node, EdgeVisitor consumer) { + applyEdges(node, consumer, this.inputsIteration); + } + + private static void applyEdges(Node node, EdgeVisitor consumer, long mask) { + long myMask = mask; + while (myMask != 0) { + long offset = (myMask & OFFSET_MASK); + if ((myMask & LIST_MASK) == 0) { + Node curNode = Edges.getNodeUnsafe(node, offset); + if (curNode != null) { + Node newNode = consumer.apply(node, curNode); + if (newNode != curNode) { + UNSAFE.putObject(node, offset, newNode); + } + } + } else { + applyHelper(node, consumer, offset); + } + myMask >>>= NEXT_EDGE; + } + } + + private static void applyHelper(Node node, EdgeVisitor consumer, long offset) { + NodeList list = Edges.getNodeListUnsafe(node, offset); + if (list != null) { + for (int i = 0; i < list.size(); ++i) { + Node curNode = list.get(i); + if (curNode != null) { + Node newNode = consumer.apply(node, curNode); + if (newNode != curNode) { + list.initialize(i, newNode); + } + } + } + } + } + + public void unregisterAtSuccessorsAsPredecessor(Node node) { + long myMask = this.successorIteration; + while (myMask != 0) { + long offset = (myMask & OFFSET_MASK); + if ((myMask & LIST_MASK) == 0) { + Node curNode = Edges.getNodeUnsafe(node, offset); + if (curNode != null) { + node.updatePredecessor(curNode, null); + UNSAFE.putObject(node, offset, null); + } + } else { + unregisterAtSuccessorsAsPredecessorHelper(node, offset); + } + myMask >>>= NEXT_EDGE; + } + } + + private static void unregisterAtSuccessorsAsPredecessorHelper(Node node, long offset) { + NodeList list = Edges.getNodeListUnsafe(node, offset); + if (list != null) { + for (int i = 0; i < list.size(); ++i) { + Node curNode = list.get(i); + if (curNode != null) { + node.updatePredecessor(curNode, null); + } + } + list.clearWithoutUpdate(); + } + } + + public void registerAtSuccessorsAsPredecessor(Node node) { + long myMask = this.successorIteration; + while (myMask != 0) { + long offset = (myMask & OFFSET_MASK); + if ((myMask & LIST_MASK) == 0) { + Node curNode = Edges.getNodeUnsafe(node, offset); + if (curNode != null) { + assert curNode.isAlive() : "Successor not alive"; + node.updatePredecessor(null, curNode); + } + } else { + registerAtSuccessorsAsPredecessorHelper(node, offset); + } + myMask >>>= NEXT_EDGE; + } + } + + private static void registerAtSuccessorsAsPredecessorHelper(Node node, long offset) { + NodeList list = Edges.getNodeListUnsafe(node, offset); + if (list != null) { + for (int i = 0; i < list.size(); ++i) { + Node curNode = list.get(i); + if (curNode != null) { + assert curNode.isAlive() : "Successor not alive"; + node.updatePredecessor(null, curNode); + } + } + } + } + + public boolean replaceFirstInput(Node node, Node key, Node replacement) { + return replaceFirstEdge(node, key, replacement, this.inputsIteration); + } + + public boolean replaceFirstSuccessor(Node node, Node key, Node replacement) { + return replaceFirstEdge(node, key, replacement, this.successorIteration); + } + + public static boolean replaceFirstEdge(Node node, Node key, Node replacement, long mask) { + long myMask = mask; + while (myMask != 0) { + long offset = (myMask & OFFSET_MASK); + if ((myMask & LIST_MASK) == 0) { + Object curNode = UNSAFE.getObject(node, offset); + if (curNode == key) { + UNSAFE.putObject(node, offset, replacement); + return true; + } + } else { + NodeList list = Edges.getNodeListUnsafe(node, offset); + if (list != null && list.replaceFirst(key, replacement)) { + return true; + } + } + myMask >>>= NEXT_EDGE; + } + return false; + } + + public void registerAtInputsAsUsage(Node node) { + long myMask = this.inputsIteration; + while (myMask != 0) { + long offset = (myMask & OFFSET_MASK); + if ((myMask & LIST_MASK) == 0) { + Node curNode = Edges.getNodeUnsafe(node, offset); + if (curNode != null) { + assert curNode.isAlive() : "Input not alive " + curNode; + curNode.addUsage(node); + } + } else { + registerAtInputsAsUsageHelper(node, offset); + } + myMask >>>= NEXT_EDGE; + } + } + + private static void registerAtInputsAsUsageHelper(Node node, long offset) { + NodeList list = Edges.getNodeListUnsafe(node, offset); + if (list != null) { + for (int i = 0; i < list.size(); ++i) { + Node curNode = list.get(i); + if (curNode != null) { + assert curNode.isAlive() : "Input not alive"; + curNode.addUsage(node); + } + } + } + } + + public void unregisterAtInputsAsUsage(Node node) { + long myMask = this.inputsIteration; + while (myMask != 0) { + long offset = (myMask & OFFSET_MASK); + if ((myMask & LIST_MASK) == 0) { + Node curNode = Edges.getNodeUnsafe(node, offset); + if (curNode != null) { + node.removeThisFromUsages(curNode); + if (curNode.hasNoUsages()) { + node.maybeNotifyZeroUsages(curNode); + } + UNSAFE.putObject(node, offset, null); + } + } else { + unregisterAtInputsAsUsageHelper(node, offset); + } + myMask >>>= NEXT_EDGE; + } + } + + private static void unregisterAtInputsAsUsageHelper(Node node, long offset) { + NodeList list = Edges.getNodeListUnsafe(node, offset); + if (list != null) { + for (int i = 0; i < list.size(); ++i) { + Node curNode = list.get(i); + if (curNode != null) { + node.removeThisFromUsages(curNode); + if (curNode.hasNoUsages()) { + node.maybeNotifyZeroUsages(curNode); + } + } + } + list.clearWithoutUpdate(); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeCollectionsProvider.java 2016-12-07 13:49:14.294778303 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, 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.graph; + +import java.util.Map; +import java.util.Set; + +import org.graalvm.compiler.api.collections.CollectionsProvider; + +/** + * Extends {@link CollectionsProvider} with support for creating {@link Node} based collections. + */ +public interface NodeCollectionsProvider extends CollectionsProvider { + + /** + * Creates a set of {@link Node}s that uses reference-equality in place of object-equality when + * comparing entries. + */ + Set newNodeIdentitySet(); + + /** + * Creates a map whose keys are {@link Node}s that uses reference-equality in place of + * object-equality when comparing keys. All {@link Node} keys must be in the same graph. + */ + Map newNodeIdentityMap(); + + /** + * Creates a map whose keys are {@link Node}s that uses reference-equality in place of + * object-equality when comparing keys. All {@link Node} keys must be in the same graph. + */ + Map newNodeIdentityMap(int expectedMaxSize); + + /** + * Creates a map whose keys are {@link Node}s that uses reference-equality in place of + * object-equality when comparing keys. All {@link Node} keys must be in the same graph. + * + * @param initFrom the returned map is populated with the entries in this map + */ + Map newNodeIdentityMap(Map initFrom); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeFlood.java 2016-12-07 13:49:14.558789908 -0800 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2011, 2011, 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.graph; + +import java.util.ArrayDeque; +import java.util.Iterator; +import java.util.Queue; + +public final class NodeFlood implements Iterable { + + private final NodeBitMap visited; + private final Queue worklist; + private int totalMarkedCount; + + public NodeFlood(Graph graph) { + visited = graph.createNodeBitMap(); + worklist = new ArrayDeque<>(); + } + + public void add(Node node) { + if (node != null && !visited.isMarked(node)) { + visited.mark(node); + worklist.add(node); + totalMarkedCount++; + } + } + + public int getTotalMarkedCount() { + return totalMarkedCount; + } + + public void addAll(Iterable nodes) { + for (Node node : nodes) { + this.add(node); + } + } + + public NodeBitMap getVisited() { + return visited; + } + + public boolean isMarked(Node node) { + return visited.isMarked(node); + } + + public boolean isNew(Node node) { + return visited.isNew(node); + } + + private static class QueueConsumingIterator implements Iterator { + + private final Queue queue; + + QueueConsumingIterator(Queue queue) { + this.queue = queue; + } + + @Override + public boolean hasNext() { + return !queue.isEmpty(); + } + + @Override + public Node next() { + return queue.remove(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + @Override + public Iterator iterator() { + return new QueueConsumingIterator(worklist); + } + + private static class UnmarkedNodeIterator implements Iterator { + + private final NodeBitMap visited; + private Iterator nodes; + private Node nextNode; + + UnmarkedNodeIterator(NodeBitMap visited, Iterator nodes) { + this.visited = visited; + this.nodes = nodes; + forward(); + } + + private void forward() { + do { + if (!nodes.hasNext()) { + nextNode = null; + return; + } + nextNode = nodes.next(); + } while (visited.isMarked(nextNode)); + } + + @Override + public boolean hasNext() { + return nextNode != null; + } + + @Override + public Node next() { + try { + return nextNode; + } finally { + forward(); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + public Iterable unmarkedNodes() { + return new Iterable() { + + @Override + public Iterator iterator() { + return new UnmarkedNodeIterator(visited, visited.graph().getNodes().iterator()); + } + }; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeIdAccessor.java 2016-12-07 13:49:14.823801557 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.graph; + +/** + * An entity that depends upon {@linkplain Graph#maybeCompress() stable} node identifiers. + */ +class NodeIdAccessor { + final Graph graph; + final int epoch; + + NodeIdAccessor(Graph graph) { + this.graph = graph; + this.epoch = graph.compressions; + } + + Graph getGraph() { + return graph; + } + + /** + * Verifies that node identifiers have not changed since this object was created. + * + * @return true if the check succeeds + * @throws VerificationError if the check fails + */ + boolean verifyIdsAreStable() { + int compressions = graph.compressions - epoch; + if (compressions != 0) { + throw new VerificationError("accessing node id in %s across %d graph compression%s", graph, compressions, compressions == 1 ? "" : "s"); + } + return true; + } + + /** + * Gets the identifier for a node. If assertions are enabled, this method asserts that the + * identifier is stable. + */ + int getNodeId(Node node) { + assert verifyIdsAreStable(); + return node.id(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInputList.java 2016-12-07 13:49:15.087813162 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011, 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.graph; + +import static org.graalvm.compiler.graph.Edges.Type.Inputs; + +import java.util.Collection; +import java.util.List; + +import org.graalvm.compiler.graph.Edges.Type; + +public final class NodeInputList extends NodeList { + + public NodeInputList(Node self, int initialSize) { + super(self, initialSize); + } + + public NodeInputList(Node self) { + super(self); + } + + public NodeInputList(Node self, T[] elements) { + super(self, elements); + assert self.hasNoUsages(); + } + + public NodeInputList(Node self, List elements) { + super(self, elements); + assert self.hasNoUsages(); + } + + public NodeInputList(Node self, Collection elements) { + super(self, elements); + assert self.hasNoUsages(); + } + + @Override + protected void update(T oldNode, T newNode) { + self.updateUsages(oldNode, newNode); + } + + @Override + public Type getEdgesType() { + return Inputs; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInterface.java 2016-12-07 13:49:15.352824811 -0800 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011, 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.graph; + +public interface NodeInterface { + Node asNode(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeList.java 2016-12-07 13:49:15.618836503 -0800 @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2011, 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.graph; + +import java.util.AbstractList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.RandomAccess; + +import org.graalvm.compiler.graph.iterators.NodeIterable; + +public abstract class NodeList extends AbstractList implements NodeIterable, RandomAccess { + + protected static final Node[] EMPTY_NODE_ARRAY = new Node[0]; + + protected final Node self; + protected Node[] nodes; + private int size; + protected final int initialSize; + + protected NodeList(Node self) { + this.self = self; + this.nodes = EMPTY_NODE_ARRAY; + this.initialSize = 0; + } + + protected NodeList(Node self, int initialSize) { + this.self = self; + this.size = initialSize; + this.initialSize = initialSize; + this.nodes = new Node[initialSize]; + } + + protected NodeList(Node self, T[] elements) { + this.self = self; + if (elements == null || elements.length == 0) { + this.size = 0; + this.nodes = EMPTY_NODE_ARRAY; + this.initialSize = 0; + } else { + this.size = elements.length; + this.initialSize = elements.length; + this.nodes = new Node[elements.length]; + for (int i = 0; i < elements.length; i++) { + this.nodes[i] = elements[i]; + assert this.nodes[i] == null || !this.nodes[i].isDeleted() : "Initializing nodelist with deleted element : " + nodes[i]; + } + } + } + + protected NodeList(Node self, List elements) { + this.self = self; + if (elements == null || elements.isEmpty()) { + this.size = 0; + this.nodes = EMPTY_NODE_ARRAY; + this.initialSize = 0; + } else { + this.size = elements.size(); + this.initialSize = elements.size(); + this.nodes = new Node[elements.size()]; + for (int i = 0; i < elements.size(); i++) { + this.nodes[i] = elements.get(i); + assert this.nodes[i] == null || !this.nodes[i].isDeleted(); + } + } + } + + protected NodeList(Node self, Collection elements) { + this.self = self; + if (elements == null || elements.isEmpty()) { + this.size = 0; + this.nodes = EMPTY_NODE_ARRAY; + this.initialSize = 0; + } else { + this.size = elements.size(); + this.initialSize = elements.size(); + this.nodes = new Node[elements.size()]; + int i = 0; + for (NodeInterface n : elements) { + this.nodes[i] = n.asNode(); + assert this.nodes[i] == null || !this.nodes[i].isDeleted(); + i++; + } + } + } + + public boolean isList() { + return true; + } + + protected abstract void update(T oldNode, T newNode); + + public abstract Edges.Type getEdgesType(); + + @Override + public final int size() { + return size; + } + + @Override + public final boolean isEmpty() { + return size == 0; + } + + @Override + public boolean isNotEmpty() { + return size > 0; + } + + @Override + public int count() { + return size; + } + + protected final void incModCount() { + modCount++; + } + + @SuppressWarnings("unchecked") + @Override + public boolean add(Node node) { + assert node == null || !node.isDeleted(); + self.incModCount(); + incModCount(); + int length = nodes.length; + if (length == 0) { + nodes = new Node[2]; + } else if (size == length) { + Node[] newNodes = new Node[nodes.length * 2 + 1]; + System.arraycopy(nodes, 0, newNodes, 0, length); + nodes = newNodes; + } + nodes[size++] = node; + update(null, (T) node); + return true; + } + + @Override + @SuppressWarnings("unchecked") + public T get(int index) { + assert assertInRange(index); + return (T) nodes[index]; + } + + private boolean assertInRange(int index) { + assert index >= 0 && index < size() : index + " < " + size(); + return true; + } + + public T last() { + return get(size() - 1); + } + + @Override + @SuppressWarnings("unchecked") + public T set(int index, Node node) { + incModCount(); + T oldValue = (T) nodes[index]; + assert assertInRange(index); + update((T) nodes[index], (T) node); + nodes[index] = node; + return oldValue; + } + + public void initialize(int index, Node node) { + incModCount(); + assert index < size(); + nodes[index] = node; + } + + void copy(NodeList other) { + self.incModCount(); + incModCount(); + Node[] newNodes = new Node[other.size]; + System.arraycopy(other.nodes, 0, newNodes, 0, newNodes.length); + nodes = newNodes; + size = other.size; + } + + public boolean equals(NodeList other) { + if (size != other.size) { + return false; + } + for (int i = 0; i < size; i++) { + if (nodes[i] != other.nodes[i]) { + return false; + } + } + return true; + } + + @SuppressWarnings("unchecked") + @Override + public void clear() { + self.incModCount(); + incModCount(); + for (int i = 0; i < size; i++) { + update((T) nodes[i], null); + } + clearWithoutUpdate(); + } + + void clearWithoutUpdate() { + nodes = EMPTY_NODE_ARRAY; + size = 0; + } + + @Override + @SuppressWarnings("unchecked") + public boolean remove(Object node) { + self.incModCount(); + int i = 0; + incModCount(); + while (i < size && nodes[i] != node) { + i++; + } + if (i < size) { + T oldValue = (T) nodes[i]; + i++; + while (i < size) { + nodes[i - 1] = nodes[i]; + i++; + } + nodes[--size] = null; + update(oldValue, null); + return true; + } else { + return false; + } + } + + @Override + @SuppressWarnings("unchecked") + public T remove(int index) { + self.incModCount(); + T oldValue = (T) nodes[index]; + int i = index + 1; + incModCount(); + while (i < size) { + nodes[i - 1] = nodes[i]; + i++; + } + nodes[--size] = null; + update(oldValue, null); + return oldValue; + } + + boolean replaceFirst(Node node, Node other) { + for (int i = 0; i < size; i++) { + if (nodes[i] == node) { + nodes[i] = other; + return true; + } + } + return false; + } + + @Override + public Iterator iterator() { + return new NodeListIterator<>(this, 0); + } + + @Override + public boolean contains(T other) { + for (int i = 0; i < size; i++) { + if (nodes[i] == other) { + return true; + } + } + return false; + } + + @SuppressWarnings("unchecked") + @Override + public List snapshot() { + return (List) Arrays.asList(Arrays.copyOf(this.nodes, this.size)); + } + + @Override + public void snapshotTo(Collection to) { + for (int i = 0; i < size; i++) { + to.add(get(i)); + } + } + + @SuppressWarnings("unchecked") + public void setAll(NodeList values) { + self.incModCount(); + incModCount(); + for (int i = 0; i < size(); i++) { + update((T) nodes[i], null); + } + nodes = Arrays.copyOf(values.nodes, values.size()); + size = values.size(); + + for (int i = 0; i < size(); i++) { + update(null, (T) nodes[i]); + } + } + + @Override + @SuppressWarnings("unchecked") + public A[] toArray(A[] a) { + if (a.length >= size) { + System.arraycopy(nodes, 0, a, 0, size); + return a; + } + return (A[]) Arrays.copyOf(nodes, size, a.getClass()); + } + + @Override + public Object[] toArray() { + return Arrays.copyOf(nodes, size); + } + + protected void replace(T node, T other) { + incModCount(); + for (int i = 0; i < size(); i++) { + if (nodes[i] == node) { + nodes[i] = other; + update(node, other); + } + } + } + + @Override + public int indexOf(Object node) { + for (int i = 0; i < size; i++) { + if (nodes[i] == node) { + return i; + } + } + return -1; + } + + @Override + public boolean contains(Object o) { + return indexOf(o) != -1; + } + + @Override + public boolean containsAll(Collection c) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public boolean addAll(Collection c) { + for (T e : c) { + add(e); + } + return true; + } + + public boolean addAll(T[] c) { + for (T e : c) { + add(e); + } + return true; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('['); + for (int i = 0; i < size; i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(nodes[i]); + } + sb.append(']'); + return sb.toString(); + } + + @Override + public T first() { + if (size() > 0) { + return get(0); + } + return null; + } + + public SubList subList(int startIndex) { + assert assertInRange(startIndex); + return new SubList<>(this, startIndex); + } + + public static final class SubList extends AbstractList implements NodeIterable, RandomAccess { + private final NodeList list; + private final int offset; + + private SubList(NodeList list, int offset) { + this.list = list; + this.offset = offset; + } + + @Override + public R get(int index) { + assert index >= 0 : index; + return list.get(offset + index); + } + + @Override + public int size() { + return list.size() - offset; + } + + public SubList subList(int startIndex) { + assert startIndex >= 0 && startIndex < size() : startIndex; + return new SubList<>(this.list, startIndex + offset); + } + + @Override + public Iterator iterator() { + return new NodeListIterator<>(list, offset); + } + } + + private static final class NodeListIterator implements Iterator { + private final NodeList list; + private final int expectedModCount; + private int index; + + private NodeListIterator(NodeList list, int startIndex) { + this.list = list; + this.expectedModCount = list.modCount; + this.index = startIndex; + } + + @Override + public boolean hasNext() { + assert expectedModCount == list.modCount; + return index < list.size; + } + + @SuppressWarnings("unchecked") + @Override + public R next() { + assert expectedModCount == list.modCount; + return (R) list.nodes[index++]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java 2016-12-07 13:49:15.883848152 -0800 @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2011, 2011, 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.graph; + +import java.util.AbstractMap.SimpleEntry; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map.Entry; + +public class NodeMap extends NodeIdAccessor { + + private static final int MIN_REALLOC_SIZE = 16; + + protected Object[] values; + + public NodeMap(Graph graph) { + super(graph); + this.values = new Object[graph.nodeIdCount()]; + } + + public NodeMap(NodeMap copyFrom) { + super(copyFrom.graph); + this.values = Arrays.copyOf(copyFrom.values, copyFrom.values.length); + } + + @SuppressWarnings("unchecked") + public T get(Node node) { + assert check(node); + return (T) values[getNodeId(node)]; + } + + @SuppressWarnings("unchecked") + public T getAndGrow(Node node) { + checkAndGrow(node); + return (T) values[getNodeId(node)]; + } + + private void checkAndGrow(Node node) { + if (isNew(node)) { + this.values = Arrays.copyOf(values, Math.max(MIN_REALLOC_SIZE, graph.nodeIdCount() * 3 / 2)); + } + assert check(node); + } + + public boolean isEmpty() { + return !entries().iterator().hasNext(); + } + + public boolean containsKey(Object key) { + if (key instanceof Node) { + Node node = (Node) key; + if (node.graph() == graph()) { + return get(node) != null; + } + } + return false; + } + + public boolean containsValue(Object value) { + for (Object o : values) { + if (o == value) { + return true; + } + } + return false; + } + + public Graph graph() { + return graph; + } + + public void set(Node node, T value) { + assert check(node); + values[getNodeId(node)] = value; + } + + public void setAndGrow(Node node, T value) { + checkAndGrow(node); + values[getNodeId(node)] = value; + } + + /** + * @param i + * @return Return the key for the entry at index {@code i} + */ + protected Node getKey(int i) { + return graph.getNode(i); + } + + public int size() { + return values.length; + } + + public boolean isNew(Node node) { + return getNodeId(node) >= size(); + } + + private boolean check(Node node) { + assert node.graph() == graph : String.format("%s is not part of the graph", node); + assert !isNew(node) : "this node was added to the graph after creating the node map : " + node; + return true; + } + + public void clear() { + Arrays.fill(values, null); + } + + public Iterable> entries() { + return new Iterable>() { + + @Override + public Iterator> iterator() { + return new Iterator>() { + + int i = 0; + + @Override + public boolean hasNext() { + forward(); + return i < NodeMap.this.values.length; + } + + @SuppressWarnings("unchecked") + @Override + public Entry next() { + final int pos = i; + Node key = NodeMap.this.getKey(pos); + T value = (T) NodeMap.this.values[pos]; + i++; + forward(); + return new SimpleEntry(key, value) { + + private static final long serialVersionUID = 7813842391085737738L; + + @Override + public T setValue(T v) { + T oldv = super.setValue(v); + NodeMap.this.values[pos] = v; + return oldv; + } + }; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + private void forward() { + while (i < NodeMap.this.values.length && (NodeMap.this.getKey(i) == null || NodeMap.this.values[i] == null)) { + i++; + } + } + }; + } + }; + } + + @Override + public String toString() { + Iterator> i = entries().iterator(); + if (!i.hasNext()) { + return "{}"; + } + + StringBuilder sb = new StringBuilder(); + sb.append('{'); + while (true) { + Entry e = i.next(); + Node key = e.getKey(); + T value = e.getValue(); + sb.append(key); + sb.append('='); + sb.append(value); + if (!i.hasNext()) { + return sb.append('}').toString(); + } + sb.append(',').append(' '); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeNodeMap.java 2016-12-07 13:49:16.148859801 -0800 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2011, 2011, 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.graph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public final class NodeNodeMap extends NodeMap implements Map { + + public NodeNodeMap(Graph graph) { + super(graph); + } + + public NodeNodeMap(NodeNodeMap copyFrom) { + super(copyFrom); + } + + @Override + public Node get(Object key) { + return super.get((Node) key); + } + + @Override + public Node put(Node key, Node value) { + Node oldValue = super.get(key); + super.set(key, value); + return oldValue; + } + + @Override + public Node remove(Object key) { + throw new UnsupportedOperationException("Cannot remove keys from this map"); + } + + @Override + public void putAll(Map m) { + for (Entry entry : m.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + @Override + public Set keySet() { + HashSet entries = new HashSet<>(); + for (int i = 0; i < values.length; ++i) { + Object v = values[i]; + if (v != null) { + Node key = getKey(i); + if (key != null) { + entries.add(key); + } + } + } + /* + * The normal contract for entrySet is that modifications of the set are reflected in the + * underlying data structure. For simplicity don't allow that but complain if someone tries + * to use it that way. + */ + return Collections.unmodifiableSet(entries); + } + + @Override + public Collection values() { + ArrayList result = new ArrayList<>(this.size()); + for (int i = 0; i < values.length; ++i) { + Object v = values[i]; + if (v != null) { + result.add((Node) v); + } + } + return result; + } + + @Override + public Set> entrySet() { + HashSet> entries = new HashSet<>(); + for (Map.Entry entry : entries()) { + entries.add(entry); + } + /* + * The normal contract for entrySet is that modifications of the set are reflected in the + * underlying data structure. For simplicity don't allow that but complain if someone tries + * to use it that way. + */ + return Collections.unmodifiableSet(entries); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java 2016-12-07 13:49:16.413871450 -0800 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016, 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.graph; + +import java.util.Objects; + +import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MetaUtil; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class NodeSourcePosition extends BytecodePosition { + + /** + * The receiver of the method this frame refers to. + */ + private final JavaConstant receiver; + + public NodeSourcePosition(JavaConstant receiver, NodeSourcePosition caller, ResolvedJavaMethod method, int bci) { + super(caller, method, bci); + this.receiver = receiver; + assert receiver == null || method.getDeclaringClass().isInstance(receiver); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && getClass() == obj.getClass()) { + NodeSourcePosition that = (NodeSourcePosition) obj; + if (this.getBCI() == that.getBCI() && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.getCaller(), that.getCaller()) && + Objects.equals(this.receiver, that.receiver)) { + return true; + } + } + return false; + } + + public JavaConstant getReceiver() { + return receiver; + } + + @Override + public NodeSourcePosition getCaller() { + return (NodeSourcePosition) super.getCaller(); + } + + public NodeSourcePosition addCaller(JavaConstant newCallerReceiver, NodeSourcePosition link) { + if (getCaller() == null) { + assert newCallerReceiver == null || receiver == null : "replacing receiver"; + return new NodeSourcePosition(newCallerReceiver, link, getMethod(), getBCI()); + } else { + return new NodeSourcePosition(receiver, getCaller().addCaller(newCallerReceiver, link), getMethod(), getBCI()); + } + } + + public NodeSourcePosition addCaller(NodeSourcePosition link) { + return addCaller(null, link); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(100); + NodeSourcePosition pos = this; + while (pos != null) { + MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI()); + if (pos.receiver != null) { + sb.append("receiver=" + pos.receiver + " "); + } + pos = pos.getCaller(); + if (pos != null) { + sb.append(CodeUtil.NEW_LINE); + } + } + return sb.toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java 2016-12-07 13:49:16.679883142 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015, 2015, 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.graph; + +public final class NodeStack { + + private static final int INITIAL_SIZE = 8; + + protected Node[] values; + public int tos; + + public NodeStack() { + values = new Node[INITIAL_SIZE]; + } + + public void push(Node n) { + int newIndex = tos++; + int valuesLength = values.length; + if (newIndex >= valuesLength) { + grow(); + } + values[newIndex] = n; + } + + private void grow() { + int valuesLength = values.length; + Node[] newValues = new Node[valuesLength << 1]; + System.arraycopy(values, 0, newValues, 0, valuesLength); + values = newValues; + } + + public Node pop() { + assert tos > 0 : "stack must be non-empty"; + return values[--tos]; + } + + public Node peek() { + assert tos > 0 : "stack must be non-empty"; + return values[tos - 1]; + } + + public boolean isEmpty() { + return tos == 0; + } + + @Override + public String toString() { + if (tos == 0) { + return "NodeStack: []"; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < tos; i++) { + sb.append(", "); + sb.append(values[i]); + } + return "NodeStack: [" + sb.substring(2) + "]"; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSuccessorList.java 2016-12-07 13:49:16.942894703 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, 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.graph; + +import static org.graalvm.compiler.graph.Edges.Type.Successors; + +import java.util.List; + +import org.graalvm.compiler.graph.Edges.Type; + +public final class NodeSuccessorList extends NodeList { + + public NodeSuccessorList(Node self, int initialSize) { + super(self, initialSize); + } + + protected NodeSuccessorList(Node self) { + super(self); + } + + public NodeSuccessorList(Node self, T[] elements) { + super(self, elements); + assert self.hasNoUsages(); + } + + public NodeSuccessorList(Node self, List elements) { + super(self, elements); + assert self.hasNoUsages(); + } + + @Override + protected void update(T oldNode, T newNode) { + self.updatePredecessor(oldNode, newNode); + } + + @Override + public Type getEdgesType() { + return Successors; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUnionFind.java 2016-12-07 13:49:17.206906308 -0800 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, 2015, 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.graph; + +/** + * Union-find data structure for {@link Node Nodes}. + * + * All operations have an accumulated worst-case complexity of O(a(n)), where a(n) is the inverse of + * the Ackermann function A(n,n). + */ +public class NodeUnionFind extends NodeIdAccessor { + + private int[] rank; + private int[] parent; + + /** + * Create a new union-find data structure for a {@link Graph}. Initially, all nodes are in their + * own equivalence set. + */ + public NodeUnionFind(Graph graph) { + super(graph); + rank = new int[graph.nodeIdCount()]; + parent = new int[graph.nodeIdCount()]; + for (int i = 0; i < parent.length; i++) { + parent[i] = i; + } + } + + /** + * Merge the equivalence sets of two nodes. + * + * After calling this function, find(a) == find(b). + */ + public void union(Node a, Node b) { + union(getNodeId(a), getNodeId(b)); + } + + /** + * Get a representative element of the equivalence set of a node. + * + * This function returns the same representative element for all members of the same equivalence + * set, i.e., find(a) == find(b) if and only if a and b are in the same set. + */ + public Node find(Node a) { + int id = find(getNodeId(a)); + return graph.getNode(id); + } + + public boolean equiv(Node a, Node b) { + return find(getNodeId(a)) == find(getNodeId(b)); + } + + private void union(int a, int b) { + int aRoot = find(a); + int bRoot = find(b); + if (aRoot != bRoot) { + if (rank[aRoot] < rank[bRoot]) { + parent[aRoot] = bRoot; + } else { + parent[bRoot] = aRoot; + if (rank[aRoot] == rank[bRoot]) { + rank[aRoot]++; + } + } + } + } + + private int find(int a) { + int ret = a; + while (ret != parent[ret]) { + parent[ret] = parent[parent[ret]]; + ret = parent[ret]; + } + return ret; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageIterable.java 2016-12-07 13:49:17.469917869 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014, 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.graph; + +import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled; + +import org.graalvm.compiler.graph.iterators.NodeIterable; + +class NodeUsageIterable implements NodeIterable { + + private final Node node; + + NodeUsageIterable(Node node) { + this.node = node; + } + + @Override + public NodeUsageIterator iterator() { + if (isModificationCountsEnabled()) { + return new NodeUsageWithModCountIterator(node); + } else { + return new NodeUsageIterator(node); + } + } + + @Override + public Node first() { + return node.usage0; + } + + @Override + public boolean isEmpty() { + return node.usage0 == null; + } + + @Override + public boolean isNotEmpty() { + return node.usage0 != null; + } + + @Override + public int count() { + return node.getUsageCount(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageIterator.java 2016-12-07 13:49:17.734929518 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014, 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.graph; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +class NodeUsageIterator implements Iterator { + + final Node node; + int index = -1; + Node current; + + void advance() { + current = null; + index++; + if (index == 0) { + current = node.usage0; + } else if (index == 1) { + current = node.usage1; + } else { + int relativeIndex = index - Node.INLINE_USAGE_COUNT; + if (relativeIndex < node.extraUsagesCount) { + current = node.extraUsages[relativeIndex]; + } + } + } + + NodeUsageIterator(Node node) { + this.node = node; + advance(); + } + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public Node next() { + Node result = current; + if (result == null) { + throw new NoSuchElementException(); + } + advance(); + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageWithModCountIterator.java 2016-12-07 13:49:17.998941122 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014, 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.graph; + +import java.util.ConcurrentModificationException; + +class NodeUsageWithModCountIterator extends NodeUsageIterator { + + NodeUsageWithModCountIterator(Node n) { + super(n); + } + + private final int expectedModCount = node.usageModCount(); + + @Override + public boolean hasNext() { + if (expectedModCount != node.usageModCount()) { + throw new ConcurrentModificationException(); + } + return super.hasNext(); + } + + @Override + public Node next() { + if (expectedModCount != node.usageModCount()) { + throw new ConcurrentModificationException(); + } + return super.next(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeWorkList.java 2016-12-07 13:49:18.260952639 -0800 @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2011, 2011, 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.graph; + +import java.util.ArrayDeque; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; + +public abstract class NodeWorkList implements Iterable { + + protected final Queue worklist; + + private NodeWorkList(Graph graph, boolean fill) { + if (fill) { + ArrayDeque deque = new ArrayDeque<>(graph.getNodeCount()); + for (Node node : graph.getNodes()) { + deque.add(node); + } + worklist = deque; + } else { + worklist = new ArrayDeque<>(); + } + } + + public void addAll(Iterable nodes) { + for (Node node : nodes) { + if (node.isAlive()) { + this.add(node); + } + } + } + + public abstract void add(Node node); + + public abstract boolean contains(Node node); + + private abstract class QueueConsumingIterator implements Iterator { + + protected void dropDeleted() { + while (!worklist.isEmpty() && worklist.peek().isDeleted()) { + worklist.remove(); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + public static final class IterativeNodeWorkList extends NodeWorkList { + + private static final int EXPLICIT_BITMAP_THRESHOLD = 10; + protected NodeBitMap inQueue; + + private int iterationLimit = Integer.MAX_VALUE; + private Node firstNoChange; + private Node lastPull; + private Node lastChain; + + public IterativeNodeWorkList(Graph graph, boolean fill, int iterationLimitPerNode) { + super(graph, fill); + if (iterationLimitPerNode > 0) { + iterationLimit = iterationLimitPerNode * graph.getNodeCount(); + } + } + + @Override + public Iterator iterator() { + return new QueueConsumingIterator() { + @Override + public boolean hasNext() { + dropDeleted(); + return iterationLimit > 0 && !worklist.isEmpty(); + } + + @Override + public Node next() { + if (iterationLimit-- <= 0) { + throw new NoSuchElementException(); + } + dropDeleted(); + Node node = worklist.remove(); + assert updateInfiniteWork(node); + if (inQueue != null) { + inQueue.clearAndGrow(node); + } + return node; + } + + private boolean updateInfiniteWork(Node node) { + if (lastPull != lastChain) { + firstNoChange = null; + } + lastPull = node; + return true; + } + }; + } + + @Override + public void add(Node node) { + if (node != null) { + if (inQueue == null && worklist.size() > EXPLICIT_BITMAP_THRESHOLD) { + inflateToBitMap(node.graph()); + } + + if (inQueue != null) { + if (inQueue.isMarkedAndGrow(node)) { + return; + } + } else { + for (Node queuedNode : worklist) { + if (queuedNode == node) { + return; + } + } + } + assert checkInfiniteWork(node) : "Readded " + node; + if (inQueue != null) { + inQueue.markAndGrow(node); + } + worklist.add(node); + } + } + + @Override + public boolean contains(Node node) { + if (inQueue != null) { + return inQueue.isMarked(node); + } else { + for (Node queuedNode : worklist) { + if (queuedNode == node) { + return true; + } + } + return false; + } + } + + private boolean checkInfiniteWork(Node node) { + if (lastPull == node && !node.hasNoUsages()) { + if (firstNoChange == null) { + firstNoChange = node; + lastChain = node; + } else if (node == firstNoChange) { + return false; + } else { + lastChain = node; + } + } else { + firstNoChange = null; + } + return true; + } + + private void inflateToBitMap(Graph graph) { + assert inQueue == null; + inQueue = graph.createNodeBitMap(); + for (Node queuedNode : worklist) { + if (queuedNode.isAlive()) { + inQueue.mark(queuedNode); + } + } + } + } + + public static final class SingletonNodeWorkList extends NodeWorkList { + protected final NodeBitMap visited; + + public SingletonNodeWorkList(Graph graph) { + super(graph, false); + visited = graph.createNodeBitMap(); + } + + @Override + public void add(Node node) { + if (node != null) { + if (!visited.isMarkedAndGrow(node)) { + visited.mark(node); + worklist.add(node); + } + } + } + + @Override + public boolean contains(Node node) { + return visited.isMarked(node); + } + + @Override + public Iterator iterator() { + return new QueueConsumingIterator() { + @Override + public boolean hasNext() { + dropDeleted(); + return !worklist.isEmpty(); + } + + @Override + public Node next() { + dropDeleted(); + return worklist.remove(); + } + }; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Position.java 2016-12-07 13:49:18.525964288 -0800 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2014, 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.graph; + +import org.graalvm.compiler.nodeinfo.InputType; + +/** + * Describes an edge slot for a {@link NodeClass}. + */ +public final class Position { + + /** + * The edges in which this position lies. + */ + private final Edges edges; + + /** + * Index of the {@link Node} or {@link NodeList} field denoted by this position. + */ + private final int index; + + /** + * Index within a {@link NodeList} if {@link #index} denotes a {@link NodeList} field otherwise + * {@link Node#NOT_ITERABLE}. + */ + private final int subIndex; + + public Position(Edges edges, int index, int subIndex) { + this.edges = edges; + this.index = index; + this.subIndex = subIndex; + } + + public Node get(Node node) { + if (index < edges.getDirectCount()) { + return Edges.getNode(node, edges.getOffsets(), index); + } else { + return Edges.getNodeList(node, edges.getOffsets(), index).get(subIndex); + } + } + + public InputType getInputType() { + return ((InputEdges) edges).getInputType(index); + } + + public String getName() { + return edges.getName(index); + } + + public boolean isInputOptional() { + return ((InputEdges) edges).isOptional(index); + } + + public void set(Node node, Node value) { + if (index < edges.getDirectCount()) { + edges.setNode(node, index, value); + } else { + Edges.getNodeList(node, edges.getOffsets(), index).set(subIndex, value); + } + } + + public void initialize(Node node, Node value) { + if (index < edges.getDirectCount()) { + edges.initializeNode(node, index, value); + } else { + Edges.getNodeList(node, edges.getOffsets(), index).initialize(subIndex, value); + } + } + + @Override + public String toString() { + String res = edges.getType(index).getSimpleName() + ":" + edges.getName(index); + if (subIndex != Node.NOT_ITERABLE) { + res += "[" + subIndex + "]"; + } + return res; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + index; + result = prime * result + edges.hashCode(); + result = prime * result + subIndex; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Position other = (Position) obj; + if (index != other.index) { + return false; + } + if (edges != other.edges) { + return false; + } + if (subIndex != other.subIndex) { + return false; + } + return true; + } + + /** + * Gets the index within a {@link NodeList} if {@link #getIndex()} denotes a {@link NodeList} + * field otherwise {@link Node#NOT_ITERABLE}. + */ + public int getSubIndex() { + return subIndex; + } + + /** + * Gets the index of the {@link Node} or {@link NodeList} field denoted by this position. + */ + public int getIndex() { + return index; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SuccessorEdges.java 2016-12-07 13:49:18.789975893 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, 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.graph; + +import static org.graalvm.compiler.graph.Edges.Type.Successors; + +import java.util.ArrayList; + +import org.graalvm.compiler.graph.NodeClass.EdgeInfo; + +public final class SuccessorEdges extends Edges { + + public SuccessorEdges(int directCount, ArrayList edges) { + super(Successors, directCount, edges); + } + + @Override + public void update(Node node, Node oldValue, Node newValue) { + node.updatePredecessor(oldValue, newValue); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/TypedGraphNodeIterator.java 2016-12-07 13:49:19.053987498 -0800 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011, 2014, 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.graph; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.NoSuchElementException; + +class TypedGraphNodeIterator implements Iterator { + + private final Graph graph; + private final int[] ids; + private final Node[] current; + + private int currentIdIndex; + private boolean needsForward; + + TypedGraphNodeIterator(NodeClass clazz, Graph graph) { + this.graph = graph; + ids = clazz.iterableIds(); + currentIdIndex = 0; + current = new Node[ids.length]; + Arrays.fill(current, Graph.PLACE_HOLDER); + needsForward = true; + } + + private Node findNext() { + if (needsForward) { + forward(); + } else { + Node c = current(); + Node afterDeleted = graph.getIterableNodeNext(c); + if (afterDeleted == null) { + needsForward = true; + } else if (c != afterDeleted) { + setCurrent(afterDeleted); + } + } + if (needsForward) { + return null; + } + return current(); + } + + private void forward() { + needsForward = false; + int startIdx = currentIdIndex; + while (true) { + Node next; + if (current() == Graph.PLACE_HOLDER) { + next = graph.getIterableNodeStart(ids[currentIdIndex]); + } else { + next = graph.getIterableNodeNext(current().typeCacheNext); + } + if (next == null) { + currentIdIndex++; + if (currentIdIndex >= ids.length) { + currentIdIndex = 0; + } + if (currentIdIndex == startIdx) { + needsForward = true; + return; + } + } else { + setCurrent(next); + break; + } + } + } + + private Node current() { + return current[currentIdIndex]; + } + + private void setCurrent(Node n) { + current[currentIdIndex] = n; + } + + @Override + public boolean hasNext() { + return findNext() != null; + } + + @Override + @SuppressWarnings("unchecked") + public T next() { + Node result = findNext(); + if (result == null) { + throw new NoSuchElementException(); + } + needsForward = true; + return (T) result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/UnsafeAccess.java 2016-12-07 13:49:19.316999059 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2012, 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.graph; + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + +/** + * Package private access to the {@link Unsafe} capability. + */ +class UnsafeAccess { + + static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + // Fast path when we are trusted. + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + // Slow path when we are not trusted. + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/VerificationError.java 2016-12-07 13:49:19.583010751 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011, 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.graph; + +/** + * This error represents a failed verification of a node . It must only be used for conditions that + * should never occur during normal operation. + */ +public class VerificationError extends GraalGraphError { + + private static final long serialVersionUID = 8459607567446819822L; + + /** + * This constructor creates a {@link VerificationError} with a message assembled via + * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to + * always generate the same output. + * + * @param msg the message that will be associated with the error, in String.format syntax + * @param args parameters to String.format - parameters that implement {@link Iterable} will be + * expanded into a [x, x, ...] representation. + */ + public VerificationError(String msg, Object... args) { + super(msg, args); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/FilteredNodeIterable.java 2016-12-07 13:49:19.850022488 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, 2016, 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.graph.iterators; + +import java.util.Iterator; + +import org.graalvm.compiler.graph.Node; + +public class FilteredNodeIterable implements NodeIterable { + + protected final NodeIterable nodeIterable; + protected NodePredicate predicate = NodePredicates.alwaysTrue(); + + public FilteredNodeIterable(NodeIterable nodeIterable) { + this.nodeIterable = nodeIterable; + } + + public FilteredNodeIterable and(NodePredicate nodePredicate) { + this.predicate = this.predicate.and(nodePredicate); + return this; + } + + @Override + public Iterator iterator() { + return new PredicatedProxyNodeIterator<>(nodeIterable.iterator(), predicate); + } + + @SuppressWarnings("unchecked") + @Override + public FilteredNodeIterable filter(Class clazz) { + return (FilteredNodeIterable) this.and(NodePredicates.isA(clazz)); + } + + @Override + public FilteredNodeIterable filter(NodePredicate p) { + return this.and(p); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodeIterable.java 2016-12-07 13:49:20.116034180 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2011, 2012, 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.graph.iterators; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.graalvm.compiler.graph.Node; + +public interface NodeIterable extends Iterable { + + @SuppressWarnings("unchecked") + default NodeIterable filter(Class clazz) { + return (NodeIterable) new FilteredNodeIterable<>(this).and(NodePredicates.isA(clazz)); + } + + default FilteredNodeIterable filter(NodePredicate predicate) { + return new FilteredNodeIterable<>(this).and(predicate); + } + + default List snapshot() { + ArrayList list = new ArrayList<>(); + snapshotTo(list); + return list; + } + + default void snapshotTo(Collection to) { + for (T n : this) { + to.add(n); + } + } + + default T first() { + Iterator iterator = iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } + return null; + } + + default int count() { + int count = 0; + Iterator iterator = iterator(); + while (iterator.hasNext()) { + iterator.next(); + count++; + } + return count; + } + + default boolean isEmpty() { + return !iterator().hasNext(); + } + + default boolean isNotEmpty() { + return iterator().hasNext(); + } + + default boolean contains(T node) { + for (T next : this) { + if (next == node) { + return true; + } + } + return false; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodeIterator.java 2016-12-07 13:49:20.381045829 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011, 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.graph.iterators; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.graalvm.compiler.graph.Node; + +public abstract class NodeIterator implements Iterator { + + protected T current; + + protected abstract void forward(); + + @Override + public boolean hasNext() { + forward(); + return current != null; + } + + @Override + public T next() { + forward(); + T ret = current; + if (current == null) { + throw new NoSuchElementException(); + } + current = null; + return ret; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicate.java 2016-12-07 13:49:20.644057390 -0800 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011, 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.graph.iterators; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.iterators.NodePredicates.AndPredicate; + +public interface NodePredicate { + + boolean apply(Node n); + + default NodePredicate and(NodePredicate np) { + return new AndPredicate(this, np); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicates.java 2016-12-07 13:49:20.908068994 -0800 @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2012, 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.graph.iterators; + +import org.graalvm.compiler.graph.Node; + +public abstract class NodePredicates { + + private static final TautologyPredicate TAUTOLOGY = new TautologyPredicate(); + private static final ContradictionPredicate CONTRADICTION = new ContradictionPredicate(); + private static final IsNullPredicate IS_NULL = new IsNullPredicate(); + + public static NodePredicate alwaysTrue() { + return TAUTOLOGY; + } + + public static NodePredicate alwaysFalse() { + return CONTRADICTION; + } + + public static NodePredicate isNull() { + return IS_NULL; + } + + public static NegativeTypePredicate isNotA(Class clazz) { + return new NegativeTypePredicate(clazz); + } + + public static PositiveTypePredicate isA(Class clazz) { + return new PositiveTypePredicate(clazz); + } + + static final class TautologyPredicate implements NodePredicate { + + @Override + public boolean apply(Node n) { + return true; + } + + @Override + public NodePredicate and(NodePredicate np) { + return np; + } + } + + static final class ContradictionPredicate implements NodePredicate { + + @Override + public boolean apply(Node n) { + return false; + } + + @Override + public NodePredicate and(NodePredicate np) { + return this; + } + } + + static final class AndPredicate implements NodePredicate { + + private final NodePredicate a; + private final NodePredicate b; + + AndPredicate(NodePredicate a, NodePredicate b) { + this.a = a; + this.b = b; + } + + @Override + public boolean apply(Node n) { + return a.apply(n) && b.apply(n); + } + } + + static final class NotPredicate implements NodePredicate { + + private final NodePredicate a; + + NotPredicate(NodePredicate n) { + this.a = n; + } + + @Override + public boolean apply(Node n) { + return !a.apply(n); + } + + public NodePredicate negate() { + return a; + } + } + + static final class IsNullPredicate implements NodePredicate { + + @Override + public boolean apply(Node n) { + return n == null; + } + } + + public static final class PositiveTypePredicate implements NodePredicate { + + private final Class type; + private PositiveTypePredicate or; + + PositiveTypePredicate(Class type) { + this.type = type; + } + + public PositiveTypePredicate(NegativeTypePredicate a) { + type = a.type; + if (a.nor != null) { + or = new PositiveTypePredicate(a.nor); + } + } + + @Override + public boolean apply(Node n) { + return type.isInstance(n) || (or != null && or.apply(n)); + } + + public PositiveTypePredicate or(Class clazz) { + if (or == null) { + or = new PositiveTypePredicate(clazz); + } else { + or.or(clazz); + } + return this; + } + + public NodePredicate negate() { + return new NegativeTypePredicate(this); + } + } + + public static final class NegativeTypePredicate implements NodePredicate { + + private final Class type; + private NegativeTypePredicate nor; + + NegativeTypePredicate(Class type) { + this.type = type; + } + + public NegativeTypePredicate(PositiveTypePredicate a) { + type = a.type; + if (a.or != null) { + nor = new NegativeTypePredicate(a.or); + } + } + + @Override + public boolean apply(Node n) { + return !type.isInstance(n) && (nor == null || nor.apply(n)); + } + + public NegativeTypePredicate nor(Class clazz) { + if (nor == null) { + nor = new NegativeTypePredicate(clazz); + } else { + nor.nor(clazz); + } + return this; + } + + public NodePredicate negate() { + return new PositiveTypePredicate(this); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/PredicatedProxyNodeIterator.java 2016-12-07 13:49:21.172080599 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, 2012, 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.graph.iterators; + +import java.util.Iterator; + +import org.graalvm.compiler.graph.Node; + +public class PredicatedProxyNodeIterator extends NodeIterator { + + private final Iterator iterator; + private final NodePredicate predicate; + + public PredicatedProxyNodeIterator(Iterator iterator, NodePredicate predicate) { + this.iterator = iterator; + this.predicate = predicate; + } + + @Override + protected void forward() { + while ((current == null || !current.isAlive() || !predicate.apply(current)) && iterator.hasNext()) { + current = iterator.next(); + } + if (current != null && (!current.isAlive() || !predicate.apply(current))) { + current = null; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/package-info.java 2016-12-07 13:49:21.438092292 -0800 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011, 2011, 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. + */ +/** + * This package contains the Node base class and the Graph container class of the Graal IR. + */ +package org.graalvm.compiler.graph; --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Canonicalizable.java 2016-12-07 13:49:21.704103985 -0800 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2011, 2014, 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.graph.spi; + +import org.graalvm.compiler.graph.Graph; +import org.graalvm.compiler.graph.Node; + +import jdk.vm.ci.meta.MetaAccessProvider; + +/** + * Nodes can implement {@link Canonicalizable} or one of the two sub-interfaces {@link Unary} and + * {@link Binary} to provide local optimizations like constant folding and strength reduction. + * Implementations should return a replacement that is always semantically correct for the given + * inputs, or "this" if they do not see an opportunity for improvement.
+ *
+ * Implementations of {@link Canonicalizable#canonical(CanonicalizerTool)} or the equivalent + * methods of the two sub-interfaces must not have any side effects.
+ * They are not allowed to change inputs, successors or properties of any node (including the + * current one) and they also cannot add new nodes to the graph.
+ *
+ * In addition to pre-existing nodes they can return newly created nodes, which will be added to the + * graph automatically if (and only if) the effects of the canonicalization are committed. + * Non-cyclic graphs (DAGs) of newly created nodes (i.e., one newly created node with an input to + * another newly created node) will be handled correctly. + */ +public interface Canonicalizable { + + /** + * Implementations of this method can provide local optimizations like constant folding and + * strength reduction. Implementations should look at the properties and inputs of the current + * node and determine if there is a more optimal and always semantically correct replacement. + *
+ * The return value determines the effect that the canonicalization will have: + *
    + *
  • Returning an pre-existing node will replace the current node with the given one.
  • + *
  • Returning a newly created node (that was not yet added to the graph) will replace the + * current node with the given one, after adding it to the graph. If both the replacement and + * the replacee are anchored in control flow (fixed nodes), the replacement will be added to the + * control flow. It is invalid to replace a non-fixed node with a newly created fixed node + * (because its placement in the control flow cannot be determined without scheduling).
  • + *
  • Returning {@code null} will delete the current node and replace it with {@code null} at + * all usages. Note that it is not necessary to delete floating nodes that have no more usages + * this way - they will be deleted automatically.
  • + *
+ * + * @param tool provides access to runtime interfaces like {@link MetaAccessProvider} + */ + Node canonical(CanonicalizerTool tool); + + /** + * This sub-interface of {@link Canonicalizable} is intended for nodes that have exactly one + * input. It has an additional {@link #canonical(CanonicalizerTool, Node)} method that looks at + * the given input instead of the current input of the node - which can be used to ask "what if + * this input is changed to this node" - questions. + * + * @param the common supertype of all inputs of this node + */ + public interface Unary extends Canonicalizable { + + /** + * Similar to {@link Canonicalizable#canonical(CanonicalizerTool)}, except that + * implementations should act as if the current input of the node was the given one, i.e., + * they should never look at the inputs via the this pointer. + */ + Node canonical(CanonicalizerTool tool, T forValue); + + /** + * Gets the current value of the input, so that calling + * {@link #canonical(CanonicalizerTool, Node)} with the value returned from this method + * should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}. + */ + T getValue(); + + @SuppressWarnings("unchecked") + @Override + default T canonical(CanonicalizerTool tool) { + return (T) canonical(tool, getValue()); + } + } + + /** + * This sub-interface of {@link Canonicalizable} is intended for nodes that have exactly two + * inputs. It has an additional {@link #canonical(CanonicalizerTool, Node, Node)} method that + * looks at the given inputs instead of the current inputs of the node - which can be used to + * ask "what if this input is changed to this node" - questions. + * + * @param the common supertype of all inputs of this node + */ + public interface Binary extends Canonicalizable { + + /** + * Similar to {@link Canonicalizable#canonical(CanonicalizerTool)}, except that + * implementations should act as if the current input of the node was the given one, i.e., + * they should never look at the inputs via the this pointer. + */ + Node canonical(CanonicalizerTool tool, T forX, T forY); + + /** + * Gets the current value of the input, so that calling + * {@link #canonical(CanonicalizerTool, Node, Node)} with the value returned from this + * method should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}. + */ + T getX(); + + /** + * Gets the current value of the input, so that calling + * {@link #canonical(CanonicalizerTool, Node, Node)} with the value returned from this + * method should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}. + */ + T getY(); + + @SuppressWarnings("unchecked") + @Override + default T canonical(CanonicalizerTool tool) { + return (T) canonical(tool, getX(), getY()); + } + } + + /** + * This sub-interface of {@link Canonicalizable.Binary} is for nodes with two inputs where the + * operation is commutative. It is used to improve GVN by trying to merge nodes with the same + * inputs in different order. + */ + public interface BinaryCommutative extends Binary { + + /** + * Ensure a canonical ordering of inputs for commutative nodes to improve GVN results. Order + * the inputs by increasing {@link Node#id} and call {@link Graph#findDuplicate(Node)} on + * the node if it's currently in a graph. It's assumed that if there was a constant on the + * left it's been moved to the right by other code and that ordering is left alone. + * + * @return the original node or another node with the same input ordering + */ + Node maybeCommuteInputs(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/CanonicalizerTool.java 2016-12-07 13:49:21.969115633 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, 2016, 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.graph.spi; + +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; + +import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; +import org.graalvm.compiler.graph.Node; + +public interface CanonicalizerTool { + + Assumptions getAssumptions(); + + MetaAccessProvider getMetaAccess(); + + ConstantReflectionProvider getConstantReflection(); + + ConstantFieldProvider getConstantFieldProvider(); + + boolean canonicalizeReads(); + + /** + * If this method returns false, not all {@link Node#usages() usages of a node} are yet + * available. So a node must not be canonicalized base on, e.g., information returned from + * {@link Node#hasNoUsages()}. + */ + boolean allUsagesAvailable(); + + /** + * Indicates whether the target platform supports comparison of integers of a particular bit + * width. This check is used by canonicalizations that might introduce subword compares. + */ + boolean supportSubwordCompare(int bits); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Simplifiable.java 2016-12-07 13:49:22.233127238 -0800 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012, 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.graph.spi; + +/** + * This interface allows nodes to perform more complicated simplifications, in contrast to + * {@link Canonicalizable}, which supports only replacing the current node. + * + * Implementors of this interface need to be aware that they need to call + * {@link SimplifierTool#addToWorkList(org.graalvm.compiler.graph.Node)} for each node that might be + * influenced (in terms of simplification and canonicalization) by the actions performed in + * simplify. + */ +public interface Simplifiable { + + void simplify(SimplifierTool tool); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/SimplifierTool.java 2016-12-07 13:49:22.499138931 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 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.graph.spi; + +import org.graalvm.compiler.graph.Node; + +/** + * @see Simplifiable + */ +public interface SimplifierTool extends CanonicalizerTool { + + void deleteBranch(Node branch); + + /** + * Adds a node to the worklist independent of whether it has already been on the worklist. + */ + void addToWorkList(Node node); + + void addToWorkList(Iterable nodes); + + void removeIfUnused(Node node); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java 2016-12-07 13:49:22.765150624 -0800 @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2013, 2016, 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.aarch64; + +import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; +import static java.lang.reflect.Modifier.isStatic; +import static jdk.vm.ci.aarch64.AArch64.lr; +import static jdk.vm.ci.aarch64.AArch64.r10; +import static jdk.vm.ci.aarch64.AArch64.sp; +import static jdk.vm.ci.aarch64.AArch64.zr; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp; + +import java.util.Set; + +import org.graalvm.compiler.asm.Assembler; +import org.graalvm.compiler.asm.Label; +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.ScratchRegister; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.aarch64.AArch64NodeMatchRules; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.hotspot.HotSpotDataBuilder; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.HotSpotHostBackend; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.aarch64.AArch64Call; +import org.graalvm.compiler.lir.aarch64.AArch64FrameMap; +import org.graalvm.compiler.lir.aarch64.AArch64FrameMapBuilder; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.lir.asm.DataBuilder; +import org.graalvm.compiler.lir.asm.FrameContext; +import org.graalvm.compiler.lir.framemap.FrameMap; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.hotspot.HotSpotCallingConventionType; +import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * HotSpot AArch64 specific backend. + */ +public class AArch64HotSpotBackend extends HotSpotHostBackend { + + public AArch64HotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { + super(config, runtime, providers); + } + + @Override + public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) { + RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; + return new AArch64FrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull); + } + + @Override + public FrameMap newFrameMap(RegisterConfig registerConfig) { + return new AArch64FrameMap(getCodeCache(), registerConfig, this); + } + + @Override + public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) { + return new AArch64HotSpotLIRGenerator(getProviders(), config, lirGenRes); + } + + @Override + public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, Object stub) { + return new HotSpotLIRGenerationResult(compilationId, lir, frameMapBuilder, makeCallingConvention(graph, (Stub) stub), stub); + } + + @Override + public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { + return new AArch64HotSpotNodeLIRBuilder(graph, lirGen, new AArch64NodeMatchRules(lirGen)); + } + + @Override + protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) { + AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm; + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + AArch64Address address = masm.makeAddress(sp, -bangOffset, scratch, 8, /* allowOverwrite */false); + masm.str(64, zr, address); + } + } + + private class HotSpotFrameContext implements FrameContext { + final boolean isStub; + + HotSpotFrameContext(boolean isStub) { + this.isStub = isStub; + } + + @Override + public void enter(CompilationResultBuilder crb) { + FrameMap frameMap = crb.frameMap; + final int frameSize = frameMap.frameSize(); + final int totalFrameSize = frameMap.totalFrameSize(); + assert frameSize + 2 * crb.target.arch.getWordSize() == totalFrameSize : "total framesize should be framesize + 2 words"; + AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm; + if (!isStub) { + emitStackOverflowCheck(crb); + } + crb.blockComment("[method prologue]"); + + if (ZapStackOnMethodEntry.getValue()) { + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + int intSize = 4; + AArch64Address address = AArch64Address.createPreIndexedImmediateAddress(scratch, -intSize); + try (ScratchRegister sc2 = masm.getScratchRegister()) { + Register value = sc2.getRegister(); + masm.mov(value, 0xC1C1C1C1); + for (int i = 0; i < frameSize; i += intSize) { + masm.str(32, value, address); + } + } + masm.mov(64, sp, scratch); + } + } else { + if (AArch64MacroAssembler.isArithmeticImmediate(totalFrameSize)) { + masm.sub(64, sp, sp, totalFrameSize); + } else { + try (ScratchRegister sc2 = masm.getScratchRegister()) { + Register scratch2 = sc2.getRegister(); + masm.mov(scratch2, totalFrameSize); + masm.sub(64, sp, sp, scratch2); + } + } + } + + AArch64Address address2 = AArch64Address.createPairUnscaledImmediateAddress(sp, frameSize / 8); // XXX + masm.stp(64, fp, lr, address2); + + crb.blockComment("[code body]"); + } + + @Override + public void leave(CompilationResultBuilder crb) { + AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm; + FrameMap frameMap = crb.frameMap; + final int frameSize = frameMap.frameSize(); + final int totalFrameSize = frameMap.totalFrameSize(); + + crb.blockComment("[method epilogue]"); + + AArch64Address address2 = AArch64Address.createPairUnscaledImmediateAddress(sp, frameSize / 8); // XXX + masm.ldp(64, fp, lr, address2); + + if (AArch64MacroAssembler.isArithmeticImmediate(totalFrameSize)) { + masm.add(64, sp, sp, totalFrameSize); + } else { + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + masm.mov(scratch, totalFrameSize); + masm.add(64, sp, sp, scratch); + } + } + } + + @Override + public boolean hasFrame() { + return true; + } + + } + + @Override + protected Assembler createAssembler(FrameMap frameMap) { + return new AArch64MacroAssembler(getTarget()); + } + + @Override + public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRen, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { + HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRen; + LIR lir = gen.getLIR(); + assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; + + Stub stub = gen.getStub(); + Assembler masm = createAssembler(frameMap); + HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null); + + DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget()); + CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, dataBuilder, frameContext, compilationResult); + crb.setTotalFrameSize(frameMap.totalFrameSize()); + crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize()); + StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot(); + if (deoptimizationRescueSlot != null && stub == null) { + crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot); + } + + if (stub != null) { + Set destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir); + updateStub(stub, destroyedCallerRegisters, gen.getCalleeSaveInfo(), frameMap); + } + return crb; + } + + @Override + public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) { + AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm; + FrameMap frameMap = crb.frameMap; + RegisterConfig regConfig = frameMap.getRegisterConfig(); + Label verifiedStub = new Label(); + + emitCodePrefix(crb, installedCodeOwner, masm, regConfig, verifiedStub); + emitCodeBody(crb, lir, masm); + emitCodeSuffix(crb, masm, frameMap); + } + + private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod installedCodeOwner, AArch64MacroAssembler masm, RegisterConfig regConfig, Label verifiedStub) { + HotSpotProviders providers = getProviders(); + if (installedCodeOwner != null && !isStatic(installedCodeOwner.getModifiers())) { + crb.recordMark(config.MARKID_UNVERIFIED_ENTRY); + CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, this); + // See definition of IC_Klass in c1_LIRAssembler_aarch64.cpp + // equal to scratch(1) careful! + Register inlineCacheKlass = AArch64HotSpotRegisterConfig.inlineCacheRegister; + Register receiver = asRegister(cc.getArgument(0)); + int transferSize = config.useCompressedClassPointers ? 4 : 8; + AArch64Address klassAddress = masm.makeAddress(receiver, config.hubOffset, transferSize); + + // Are r10 and r11 available scratch registers here? One would hope so. + Register klass = r10; + if (config.useCompressedClassPointers) { + masm.ldr(32, klass, klassAddress); + AArch64HotSpotMove.decodeKlassPointer(masm, klass, klass, providers.getRegisters().getHeapBaseRegister(), config.getKlassEncoding()); + } else { + masm.ldr(64, klass, klassAddress); + } + masm.cmp(64, inlineCacheKlass, klass); + /* + * Conditional jumps have a much lower range than unconditional ones, which can be a + * problem because the miss handler could be out of range. + */ + masm.branchConditionally(AArch64Assembler.ConditionFlag.EQ, verifiedStub); + AArch64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(IC_MISS_HANDLER)); + } + masm.align(config.codeEntryAlignment); + crb.recordMark(config.MARKID_OSR_ENTRY); + masm.bind(verifiedStub); + crb.recordMark(config.MARKID_VERIFIED_ENTRY); + } + + private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64MacroAssembler masm) { + /* + * Insert a nop at the start of the prolog so we can patch in a branch if we need to + * invalidate the method later. + */ + crb.blockComment("[nop for method invalidation]"); + masm.nop(); + + crb.emit(lir); + } + + private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, FrameMap frameMap) { + HotSpotProviders providers = getProviders(); + HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; + if (!frameContext.isStub) { + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls(); + crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY); + ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER); + Register helper = AArch64Call.isNearCall(linkage) ? null : scratch; + AArch64Call.directCall(crb, masm, linkage, helper, null); + + crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); + linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER); + helper = AArch64Call.isNearCall(linkage) ? null : scratch; + AArch64Call.directCall(crb, masm, linkage, helper, null); + } + } else { + // No need to emit the stubs for entries back into the method since + // it has no calls that can cause such "return" entries + assert !frameMap.accessesCallerFrame(); + } + } + + @Override + public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) { + RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; + return new AArch64HotSpotRegisterAllocationConfig(registerConfigNonNull); + } + + @Override + public Set translateToCallerRegisters(Set calleeRegisters) { + return calleeRegisters; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java 2016-12-07 13:49:23.033162404 -0800 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2013, 2016, 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.aarch64; + +import static jdk.vm.ci.aarch64.AArch64.sp; +import static jdk.vm.ci.common.InitTimer.timer; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.core.aarch64.AArch64AddressLowering; +import org.graalvm.compiler.core.aarch64.AArch64SuitesProvider; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotBackendFactory; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantFieldProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegisters; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider; +import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider; +import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.spi.NodeCostProvider; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.replacements.aarch64.AArch64GraphBuilderPlugins; +import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider; +import org.graalvm.compiler.serviceprovider.ServiceProvider; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.common.InitTimer; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider; +import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.runtime.JVMCIBackend; + +@ServiceProvider(HotSpotBackendFactory.class) +public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory { + + @Override + public String getName() { + return "core"; + } + + @Override + public Class getArchitecture() { + return AArch64.class; + } + + @Override + @SuppressWarnings("try") + public HotSpotBackend createBackend(HotSpotGraalRuntimeProvider graalRuntime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotBackend host) { + assert host == null; + + JVMCIBackend jvmci = jvmciRuntime.getHostJVMCIBackend(); + GraalHotSpotVMConfig config = graalRuntime.getVMConfig(); + HotSpotProviders providers; + HotSpotRegistersProvider registers; + HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmci.getCodeCache(); + TargetDescription target = codeCache.getTarget(); + HotSpotHostForeignCallsProvider foreignCalls; + Value[] nativeABICallerSaveRegisters; + HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) jvmci.getMetaAccess(); + HotSpotConstantReflectionProvider constantReflection = (HotSpotConstantReflectionProvider) jvmci.getConstantReflection(); + HotSpotConstantFieldProvider constantFieldProvider = new HotSpotGraalConstantFieldProvider(config, metaAccess); + HotSpotLoweringProvider lowerer; + HotSpotSnippetReflectionProvider snippetReflection; + HotSpotReplacementsImpl replacements; + HotSpotSuitesProvider suites; + HotSpotWordTypes wordTypes; + Plugins plugins; + NodeCostProvider nodeCostProvider; + BytecodeProvider bytecodeProvider; + try (InitTimer t = timer("create providers")) { + try (InitTimer rt = timer("create HotSpotRegisters provider")) { + registers = createRegisters(); + } + try (InitTimer rt = timer("create NativeABICallerSaveRegisters")) { + nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig()); + } + try (InitTimer rt = timer("create WordTypes")) { + wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind); + } + try (InitTimer rt = timer("create ForeignCalls provider")) { + foreignCalls = createForeignCalls(jvmciRuntime, graalRuntime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters); + } + try (InitTimer rt = timer("create Lowerer provider")) { + lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, target); + } + try (InitTimer rt = timer("create NodeCost provider")) { + nodeCostProvider = createNodeCostProvider(); + } + HotSpotStampProvider stampProvider = new HotSpotStampProvider(); + Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, nodeCostProvider); + + try (InitTimer rt = timer("create SnippetReflection provider")) { + snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes); + } + try (InitTimer rt = timer("create Bytecode provider")) { + bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection); + } + try (InitTimer rt = timer("create Replacements provider")) { + replacements = createReplacements(p, snippetReflection, bytecodeProvider); + } + try (InitTimer rt = timer("create GraphBuilderPhase plugins")) { + plugins = createGraphBuilderPlugins(config, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider); + replacements.setGraphBuilderPlugins(plugins); + } + try (InitTimer rt = timer("create Suites provider")) { + suites = createSuites(config, graalRuntime, compilerConfiguration, plugins); + } + providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, nodeCostProvider, suites, registers, + snippetReflection, wordTypes, + plugins); + } + try (InitTimer rt = timer("instantiate backend")) { + return createBackend(config, graalRuntime, providers); + } + } + + protected Plugins createGraphBuilderPlugins(GraalHotSpotVMConfig config, HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls, + HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, + HotSpotStampProvider stampProvider) { + Plugins plugins = HotSpotGraphBuilderPlugins.create(config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements); + AArch64GraphBuilderPlugins.register(plugins, foreignCalls, replacements.getReplacementBytecodeProvider()); + return plugins; + } + + protected AArch64HotSpotBackend createBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { + return new AArch64HotSpotBackend(config, runtime, providers); + } + + protected HotSpotRegistersProvider createRegisters() { + return new HotSpotRegisters(AArch64HotSpotRegisterConfig.threadRegister, AArch64HotSpotRegisterConfig.heapBaseRegister, sp); + } + + protected HotSpotReplacementsImpl createReplacements(Providers p, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) { + return new HotSpotReplacementsImpl(p, snippetReflection, bytecodeProvider, p.getCodeCache().getTarget()); + } + + protected HotSpotHostForeignCallsProvider createForeignCalls(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, + HotSpotCodeCacheProvider codeCache, WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) { + return new AArch64HotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters); + } + + protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins) { + return new HotSpotSuitesProvider(new AArch64SuitesProvider(compilerConfiguration, plugins), config, runtime, new AArch64AddressLowering()); + } + + protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) { + return new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes); + } + + protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, + HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, TargetDescription target) { + return new AArch64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target); + } + + protected HotSpotNodeCostProvider createNodeCostProvider() { + return new AArchHotSpotNodeCostProvider(); + } + + protected static Value[] createNativeABICallerSaveRegisters(@SuppressWarnings("unused") GraalHotSpotVMConfig config, RegisterConfig regConfig) { + AArch64HotSpotRegisterConfig conf = (AArch64HotSpotRegisterConfig) regConfig; + RegisterArray callerSavedRegisters = conf.getCallerSaveRegisters(); + int size = callerSavedRegisters.size(); + Value[] nativeABICallerSaveRegisters = new Value[size]; + for (int i = 0; i < size; i++) { + nativeABICallerSaveRegisters[i] = callerSavedRegisters.get(i).asValue(); + } + return nativeABICallerSaveRegisters; + } + + @Override + public String toString() { + return "AArch64"; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallEpilogueOp.java 2016-12-07 13:49:23.299174097 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013, 2016, 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.aarch64; + +import static jdk.vm.ci.aarch64.AArch64.zr; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; + +@Opcode("CRUNTIME_CALL_EPILOGUE") +public class AArch64HotSpotCRuntimeCallEpilogueOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotCRuntimeCallEpilogueOp.class); + + private final int threadLastJavaSpOffset; + private final int threadLastJavaFpOffset; + private final Register thread; + + public AArch64HotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaFpOffset, Register thread) { + super(TYPE); + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.threadLastJavaFpOffset = threadLastJavaFpOffset; + this.thread = thread; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + // Reset last Java frame: + masm.str(64, zr, masm.makeAddress(thread, threadLastJavaSpOffset, 8)); + masm.str(64, zr, masm.makeAddress(thread, threadLastJavaFpOffset, 8)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallPrologueOp.java 2016-12-07 13:49:23.566185833 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013, 2015, 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.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.aarch64.AArch64.sp; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +@Opcode("CRUNTIME_CALL_PROLOGUE") +public class AArch64HotSpotCRuntimeCallPrologueOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotCRuntimeCallPrologueOp.class); + + private final int threadLastJavaSpOffset; + private final int threadLastJavaPcOffset; + private final int threadLastJavaFpOffset; + private final Register thread; + @Temp({REG}) protected AllocatableValue scratch; + private final Label label; + + public AArch64HotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, Register thread, AllocatableValue scratch, Label label) { + super(TYPE); + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.threadLastJavaPcOffset = threadLastJavaPcOffset; + this.threadLastJavaFpOffset = threadLastJavaFpOffset; + this.thread = thread; + this.scratch = scratch; + this.label = label; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + // Save last Java frame. + // We cannot save the SP directly so use a temporary register. + Register scratchRegister = asRegister(scratch); + masm.movx(scratchRegister, sp); + masm.str(64, scratchRegister, masm.makeAddress(thread, threadLastJavaSpOffset, 8)); + + // Get the current PC. Use a label to patch the return address. + masm.adr(scratchRegister, label); + masm.str(64, scratchRegister, masm.makeAddress(thread, threadLastJavaPcOffset, 8)); + + masm.str(64, fp, masm.makeAddress(thread, threadLastJavaFpOffset, 8)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java 2016-12-07 13:49:23.840197878 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.aarch64; + +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.aarch64.AArch64Call; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +/** + * Removes the current frame and tail calls the uncommon trap routine. + */ +@Opcode("DEOPT_CALLER") +public class AArch64HotSpotDeoptimizeCallerOp extends AArch64HotSpotEpilogueOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotDeoptimizeCallerOp.class); + + public AArch64HotSpotDeoptimizeCallerOp(GraalHotSpotVMConfig config) { + super(TYPE, config); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + leaveFrame(crb, masm, /* emitSafepoint */false); + AArch64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java 2016-12-07 13:49:24.106209570 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, 2016, 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.aarch64; + +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp.BlockEndOp; +import org.graalvm.compiler.lir.aarch64.AArch64BlockEndOp; +import org.graalvm.compiler.lir.aarch64.AArch64Call; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +@Opcode("DEOPT") +public class AArch64HotSpotDeoptimizeOp extends AArch64BlockEndOp implements BlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotDeoptimizeOp.class); + + @State private LIRFrameState info; + + public AArch64HotSpotDeoptimizeOp(LIRFrameState info) { + super(TYPE); + this.info = info; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, info); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectStaticCallOp.java 2016-12-07 13:49:24.373221307 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, 2016, 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.aarch64; + +import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.inlineCacheRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.aarch64.AArch64Call.DirectCallOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * A direct call that complies with the conventions for such calls in HotSpot. In particular, for + * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call. + */ +@Opcode("CALL_DIRECT") +final class AArch64HotSpotDirectStaticCallOp extends DirectCallOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotDirectStaticCallOp.class); + + private final InvokeKind invokeKind; + private final GraalHotSpotVMConfig config; + + AArch64HotSpotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) { + super(TYPE, target, result, parameters, temps, state); + assert invokeKind.isDirect(); + this.invokeKind = invokeKind; + this.config = config; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + // The mark for an invocation that uses an inline cache must be placed at the + // instruction that loads the Klass from the inline cache. + // For the first invocation this is set to a bitpattern that is guaranteed to never be a + // valid object which causes the called function to call a handler that installs the + // correct inline cache value here. + crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL); + masm.movNativeAddress(inlineCacheRegister, config.nonOopBits); + super.emitCode(crb, masm); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectVirtualCallOp.java 2016-12-07 13:49:24.641233087 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, 2016, 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.aarch64; + +import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.inlineCacheRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.aarch64.AArch64Call.DirectCallOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * A direct call that complies with the conventions for such calls in HotSpot. In particular, for + * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call. + */ +@Opcode("CALL_DIRECT") +final class AArch64HotSpotDirectVirtualCallOp extends DirectCallOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotDirectVirtualCallOp.class); + + private final InvokeKind invokeKind; + private final GraalHotSpotVMConfig config; + + AArch64HotSpotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) { + super(TYPE, target, result, parameters, temps, state); + assert invokeKind.isIndirect(); + this.invokeKind = invokeKind; + this.config = config; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + // The mark for an invocation that uses an inline cache must be placed at the + // instruction that loads the Klass from the inline cache. + // For the first invocation this is set to a bitpattern that is guaranteed to never be a + // valid object which causes the called function to call a handler that installs the + // correct inline cache value here. + crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE); + masm.movNativeAddress(inlineCacheRegister, config.nonOopBits); + super.emitCode(crb, masm); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java 2016-12-07 13:49:24.908244824 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013, 2016, 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.aarch64; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.aarch64.AArch64BlockEndOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; + +/** + * Superclass for operations that leave a method's frame. + */ +abstract class AArch64HotSpotEpilogueOp extends AArch64BlockEndOp { + + private final GraalHotSpotVMConfig config; + + protected AArch64HotSpotEpilogueOp(LIRInstructionClass c, GraalHotSpotVMConfig config) { + super(c); + this.config = config; + } + + protected void leaveFrame(CompilationResultBuilder crb, AArch64MacroAssembler masm, boolean emitSafepoint) { + assert crb.frameContext != null : "We never elide frames in aarch64"; + crb.frameContext.leave(crb); + if (emitSafepoint) { + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + AArch64HotSpotSafepointOp.emitCode(crb, masm, config, true, scratch, null); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java 2016-12-07 13:49:25.175256561 -0800 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013, 2016, 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.aarch64; + +import static org.graalvm.compiler.core.common.LocationIdentity.any; +import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF; +import static org.graalvm.compiler.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32; +import static jdk.vm.ci.aarch64.AArch64.r0; +import static jdk.vm.ci.aarch64.AArch64.r3; +import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall; +import static jdk.vm.ci.meta.Value.ILLEGAL; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +public class AArch64HotSpotForeignCallsProvider extends HotSpotHostForeignCallsProvider { + + private final Value[] nativeABICallerSaveRegisters; + + public AArch64HotSpotForeignCallsProvider(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache, + WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) { + super(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes); + this.nativeABICallerSaveRegisters = nativeABICallerSaveRegisters; + } + + @Override + public void initialize(HotSpotProviders providers) { + GraalHotSpotVMConfig config = runtime.getVMConfig(); + TargetDescription target = providers.getCodeCache().getTarget(); + PlatformKind word = target.arch.getWordKind(); + + // The calling convention for the exception handler stub is (only?) defined in + // TemplateInterpreterGenerator::generate_throw_exception() + RegisterValue exception = r0.asValue(LIRKind.reference(word)); + RegisterValue exceptionPc = r3.asValue(LIRKind.value(word)); + CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc); + register(new HotSpotForeignCallLinkageImpl(HotSpotBackend.EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF, exceptionCc, null, NOT_REEXECUTABLE, any())); + register(new HotSpotForeignCallLinkageImpl(HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF, exceptionCc, null, NOT_REEXECUTABLE, any())); + + if (PreferGraalStubs.getValue()) { + throw GraalError.unimplemented("PreferGraalStubs"); + } + + // These stubs do callee saving + if (config.useCRC32Intrinsics) { + registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, any()); + } + + super.initialize(providers); + } + + @Override + public Value[] getNativeABICallerSaveRegisters() { + return nativeABICallerSaveRegisters; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotJumpToExceptionHandlerInCallerOp.java 2016-12-07 13:49:25.443268341 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.aarch64.AArch64.sp; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.aarch64.AArch64Address; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Sets up the arguments for an exception handler in the callers frame, removes the current frame + * and jumps to the handler. + */ +@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER") +public class AArch64HotSpotJumpToExceptionHandlerInCallerOp extends AArch64HotSpotEpilogueOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotJumpToExceptionHandlerInCallerOp.class); + + @Use(REG) private AllocatableValue handlerInCallerPc; + @Use(REG) private AllocatableValue exception; + @Use(REG) private AllocatableValue exceptionPc; + private final Register thread; + private final int isMethodHandleReturnOffset; + + public AArch64HotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc, int isMethodHandleReturnOffset, + Register thread, GraalHotSpotVMConfig config) { + super(TYPE, config); + this.handlerInCallerPc = handlerInCallerPc; + this.exception = exception; + this.exceptionPc = exceptionPc; + this.isMethodHandleReturnOffset = isMethodHandleReturnOffset; + this.thread = thread; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + leaveFrame(crb, masm, /* emitSafepoint */false); + + // Restore sp from fp if the exception PC is a method handle call site. + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + AArch64Address address = masm.makeAddress(thread, isMethodHandleReturnOffset, scratch, 4, /* allowOverwrite */false); + masm.ldr(32, scratch, address); + Label noRestore = new Label(); + masm.cbz(32, scratch, noRestore); + masm.mov(64, sp, fp); + masm.bind(noRestore); + } + masm.jmp(asRegister(handlerInCallerPc)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java 2016-12-07 13:49:25.710280078 -0800 @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2015, 2016, 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.aarch64; + +import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; + +import java.util.function.Function; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; +import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator; +import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.CompressEncoding; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.HotSpotLockStack; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; +import org.graalvm.compiler.lir.aarch64.AArch64Call; +import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp; +import org.graalvm.compiler.lir.aarch64.AArch64FrameMapBuilder; +import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp; +import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; + +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.RegisterValue; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +/** + * LIR generator specialized for AArch64 HotSpot. + */ +public class AArch64HotSpotLIRGenerator extends AArch64LIRGenerator implements HotSpotLIRGenerator { + + final GraalHotSpotVMConfig config; + private HotSpotDebugInfoBuilder debugInfoBuilder; + + protected AArch64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) { + this(new AArch64HotSpotLIRKindTool(), new AArch64ArithmeticLIRGenerator(), new AArch64HotSpotMoveFactory(), providers, config, lirGenRes); + } + + protected AArch64HotSpotLIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config, + LIRGenerationResult lirGenRes) { + super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes); + this.config = config; + } + + @Override + public HotSpotProviders getProviders() { + return (HotSpotProviders) super.getProviders(); + } + + @Override + public boolean needOnlyOopMaps() { + // Stubs only need oop maps + return getResult().getStub() != null; + } + + @SuppressWarnings("unused") private LIRFrameState currentRuntimeCallInfo; + + @Override + protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + currentRuntimeCallInfo = info; + if (AArch64Call.isNearCall(linkage)) { + append(new AArch64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info, label)); + } else { + append(new AArch64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info, label)); + } + } + + @Override + public void emitTailcall(Value[] args, Value address) { + throw GraalError.unimplemented(); + } + + @Override + public SaveRegistersOp emitSaveAllRegisters() { + throw GraalError.unimplemented(); + } + + @Override + public VirtualStackSlot getLockSlot(int lockDepth) { + return getLockStack().makeLockSlot(lockDepth); + } + + private HotSpotLockStack getLockStack() { + assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null; + return debugInfoBuilder.lockStack(); + } + + @Override + public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, + double trueDestinationProbability) { + Value localX = x; + Value localY = y; + if (localX instanceof HotSpotObjectConstant) { + localX = load(localX); + } + if (localY instanceof HotSpotObjectConstant) { + localY = load(localY); + } + super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability); + } + + @Override + protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue) { + Value localA = a; + Value localB = b; + if (isConstantValue(a)) { + Constant c = asConstant(a); + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { + localA = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD)); + } else if (c instanceof HotSpotObjectConstant) { + localA = load(localA); + } + } + if (isConstantValue(b)) { + Constant c = asConstant(b); + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { + localB = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD)); + } else if (c instanceof HotSpotObjectConstant) { + localB = load(localB); + } + } + return super.emitCompare(cmpKind, localA, localB, condition, unorderedIsTrue); + } + + @Override + public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) { + LIRKind inputKind = pointer.getValueKind(LIRKind.class); + assert inputKind.getPlatformKind() == AArch64Kind.QWORD; + if (inputKind.isReference(0)) { + // oop + Variable result = newVariable(LIRKind.reference(AArch64Kind.DWORD)); + append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); + return result; + } else { + // metaspace pointer + Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD)); + AllocatableValue base = Value.ILLEGAL; + if (encoding.base != 0) { + base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.base)); + } + append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); + return result; + } + } + + @Override + public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) { + LIRKind inputKind = pointer.getValueKind(LIRKind.class); + assert inputKind.getPlatformKind() == AArch64Kind.DWORD; + if (inputKind.isReference(0)) { + // oop + Variable result = newVariable(LIRKind.reference(AArch64Kind.QWORD)); + append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); + return result; + } else { + // metaspace pointer + Variable result = newVariable(LIRKind.value(AArch64Kind.QWORD)); + AllocatableValue base = Value.ILLEGAL; + if (encoding.base != 0) { + base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.base)); + } + append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); + return result; + } + } + + @Override + public void emitPrefetchAllocate(Value address) { + append(new AArch64PrefetchOp(asAddressValue(address), config.allocatePrefetchInstr)); + } + + @Override + public void beforeRegisterAllocation() { + super.beforeRegisterAllocation(); + boolean hasDebugInfo = getResult().getLIR().hasDebugInfo(); + if (hasDebugInfo) { + getResult().setDeoptimizationRescueSlot(((AArch64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot()); + } + + getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize()); + } + + private Label label; + + @Override + public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) { + HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage; + Variable result; + LIRFrameState debugInfo = null; + if (hotspotLinkage.needsDebugInfo()) { + debugInfo = state; + assert debugInfo != null || getStub() != null; + } + + if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) { + HotSpotRegistersProvider registers = getProviders().getRegisters(); + Register thread = registers.getThreadRegister(); + Variable scratch = newVariable(LIRKind.value(target().arch.getWordKind())); + + // We need a label for the return address. + label = new Label(); + + append(new AArch64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), thread, scratch, label)); + result = super.emitForeignCall(hotspotLinkage, debugInfo, args); + append(new AArch64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread)); + + // Clear it out so it's not being reused later. + label = null; + } else { + result = super.emitForeignCall(hotspotLinkage, debugInfo, args); + } + + return result; + } + + @Override + public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { + Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0)); + Value nullValue = emitConstant(LIRKind.reference(AArch64Kind.QWORD), JavaConstant.NULL_POINTER); + moveDeoptValuesToThread(actionAndReason, nullValue); + append(new AArch64HotSpotDeoptimizeCallerOp(config)); + } + + @Override + public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) { + moveDeoptValuesToThread(actionAndReason, failedSpeculation); + append(new AArch64HotSpotDeoptimizeOp(state)); + } + + private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) { + moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset); + moveValueToThread(speculation, config.pendingFailedSpeculationOffset); + } + + private void moveValueToThread(Value value, int offset) { + LIRKind wordKind = LIRKind.value(target().arch.getWordKind()); + RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind); + final int transferSize = value.getValueKind().getPlatformKind().getSizeInBytes(); + final int scaledDisplacement = offset >> NumUtil.log2Ceil(transferSize); + AArch64AddressValue address = new AArch64AddressValue(value.getValueKind(), thread, Value.ILLEGAL, scaledDisplacement, true, AddressingMode.IMMEDIATE_SCALED); + append(new StoreOp((AArch64Kind) value.getPlatformKind(), address, loadReg(value), null)); + } + + @Override + public void emitUnwind(Value exception) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); + CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); + assert outgoingCc.getArgumentCount() == 2; + RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0); + emitMove(exceptionParameter, exception); + append(new AArch64HotSpotUnwindOp(config, exceptionParameter)); + } + + @Override + public void emitReturn(JavaKind kind, Value input) { + AllocatableValue operand = Value.ILLEGAL; + if (input != null) { + operand = resultOperandFor(kind, input.getValueKind()); + emitMove(operand, input); + } + append(new AArch64HotSpotReturnOp(operand, getStub() != null, config)); + } + + /** + * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not + * being generated. + */ + public Stub getStub() { + return getResult().getStub(); + } + + @Override + public HotSpotLIRGenerationResult getResult() { + return ((HotSpotLIRGenerationResult) super.getResult()); + } + + @Override + protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue, + Function converter) { + return new AArch64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter); + } + + public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) { + this.debugInfoBuilder = debugInfoBuilder; + } + + @Override + public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) { + throw GraalError.unimplemented(); + } + + @Override + public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) { + throw GraalError.unimplemented(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRKindTool.java 2016-12-07 13:49:25.980291946 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 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.aarch64; + +import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool; + +import jdk.vm.ci.aarch64.AArch64Kind; + +public class AArch64HotSpotLIRKindTool extends AArch64LIRKindTool implements HotSpotLIRKindTool { + + @Override + public LIRKind getNarrowOopKind() { + return LIRKind.reference(AArch64Kind.DWORD); + } + + @Override + public LIRKind getNarrowPointerKind() { + return LIRKind.value(AArch64Kind.DWORD); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java 2016-12-07 13:49:26.247303683 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2014, 2015, 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.aarch64; + +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.nodes.calc.FixedBinaryNode; +import org.graalvm.compiler.nodes.calc.FloatConvertNode; +import org.graalvm.compiler.nodes.calc.RemNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.aarch64.AArch64FloatArithmeticSnippets; +import org.graalvm.compiler.replacements.aarch64.AArch64IntegerArithmeticSnippets; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; + +public class AArch64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider { + + private AArch64IntegerArithmeticSnippets integerArithmeticSnippets; + private AArch64FloatArithmeticSnippets floatArithmeticSnippets; + + public AArch64HotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, + HotSpotConstantReflectionProvider constantReflection, TargetDescription target) { + super(runtime, metaAccess, foreignCalls, registers, constantReflection, target); + } + + @Override + public void initialize(HotSpotProviders providers, GraalHotSpotVMConfig config) { + integerArithmeticSnippets = new AArch64IntegerArithmeticSnippets(providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget()); + floatArithmeticSnippets = new AArch64FloatArithmeticSnippets(providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget()); + super.initialize(providers, config); + } + + @Override + public void lower(Node n, LoweringTool tool) { + if (n instanceof FixedBinaryNode) { + integerArithmeticSnippets.lower((FixedBinaryNode) n, tool); + } else if (n instanceof RemNode) { + floatArithmeticSnippets.lower((RemNode) n, tool); + } else if (n instanceof FloatConvertNode) { + // AMD64 has custom lowerings for ConvertNodes, HotSpotLoweringProvider does not expect + // to see a ConvertNode and throws an error, just do nothing here. + } else { + super.lower(n, tool); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java 2016-12-07 13:49:26.515315463 -0800 @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2013, 2015, 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.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64Assembler; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.CompressEncoding; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.StandardOp.LoadConstantOp; +import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; + +public class AArch64HotSpotMove { + + public static class LoadHotSpotObjectConstantInline extends AArch64LIRInstruction implements LoadConstantOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadHotSpotObjectConstantInline.class); + + private HotSpotConstant constant; + @Def({REG, STACK}) AllocatableValue result; + + public LoadHotSpotObjectConstantInline(HotSpotConstant constant, AllocatableValue result) { + super(TYPE); + this.constant = constant; + this.result = result; + } + + @Override + protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + crb.recordInlineDataInCode(constant); + if (constant.isCompressed()) { + // masm.forceMov(asRegister(result), 0); + throw GraalError.unimplemented(); + } else { + masm.movNativeAddress(asRegister(result), 0); + } + } + + @Override + public AllocatableValue getResult() { + return result; + } + + @Override + public Constant getConstant() { + return constant; + } + } + + /** + * Compresses a 8-byte pointer as a 4-byte int. + */ + public static class CompressPointer extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompressPointer.class); + + private final CompressEncoding encoding; + private final boolean nonNull; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue input; + @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; + + public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { + super(TYPE); + this.result = result; + this.input = input; + this.baseRegister = baseRegister; + this.encoding = encoding; + this.nonNull = nonNull; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register resultRegister = asRegister(result); + Register ptr = asRegister(input); + Register base = asRegister(baseRegister); + // result = (ptr - base) >> shift + if (encoding.base == 0) { + if (encoding.shift == 0) { + masm.movx(resultRegister, ptr); + } else { + assert encoding.alignment == encoding.shift : "Encode algorithm is wrong"; + masm.lshr(64, resultRegister, ptr, encoding.shift); + } + } else if (nonNull) { + masm.sub(64, resultRegister, ptr, base); + if (encoding.shift != 0) { + assert encoding.alignment == encoding.shift : "Encode algorithm is wrong"; + masm.shl(64, resultRegister, resultRegister, encoding.shift); + } + } else { + // if ptr is null it still has to be null after compression + masm.cmp(64, ptr, 0); + masm.cmov(64, resultRegister, ptr, base, AArch64Assembler.ConditionFlag.NE); + masm.sub(64, resultRegister, resultRegister, base); + if (encoding.shift != 0) { + assert encoding.alignment == encoding.shift : "Encode algorithm is wrong"; + masm.lshr(64, resultRegister, resultRegister, encoding.shift); + } + } + } + } + + /** + * Decompresses a 4-byte offset into an actual pointer. + */ + public static class UncompressPointer extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(UncompressPointer.class); + + private final CompressEncoding encoding; + private final boolean nonNull; + + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue input; + @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; + + public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { + super(TYPE); + this.result = result; + this.input = input; + this.baseRegister = baseRegister; + this.encoding = encoding; + this.nonNull = nonNull; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register ptr = asRegister(input); + Register resultRegister = asRegister(result); + Register base = asRegister(baseRegister); + // result = base + (ptr << shift) + if (nonNull) { + assert encoding.shift == encoding.alignment; + masm.add(64, resultRegister, base, ptr, AArch64Assembler.ShiftType.ASR, encoding.shift); + } else { + // if ptr is null it has to be null after decompression + // masm.cmp(64, ); + throw GraalError.unimplemented(); + } + + } + } + + // + // private static void decompressPointer(CompilationResultBuilder crb, ARMv8MacroAssembler masm, + // Register result, + // Register ptr, long base, int shift, int alignment) { + // assert base != 0 || shift == 0 || alignment == shift; + // // result = heapBase + ptr << alignment + // Register heapBase = ARMv8.heapBaseRegister; + // // if result == 0, we make sure that it will still be 0 at the end, so that it traps when + // // loading storing a value. + // masm.cmp(32, ptr, 0); + // masm.add(64, result, heapBase, ptr, ARMv8Assembler.ExtendType.UXTX, alignment); + // masm.cmov(64, result, result, ARMv8.zr, ARMv8Assembler.ConditionFlag.NE); + // } + + public static void decodeKlassPointer(AArch64MacroAssembler masm, Register result, Register ptr, Register klassBase, CompressEncoding encoding) { + // result = klassBase + ptr << shift + if (encoding.shift != 0 || encoding.base != 0) { + // (shift != 0 -> shift == alignment) + assert (encoding.shift == 0 || encoding.shift == encoding.alignment) : "Decode algorithm is wrong: " + encoding; + masm.add(64, result, klassBase, ptr, AArch64Assembler.ExtendType.UXTX, encoding.shift); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMoveFactory.java 2016-12-07 13:49:26.801328035 -0800 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015, 2016, 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.aarch64; + +import static jdk.vm.ci.hotspot.HotSpotCompressedNullConstant.COMPRESSED_NULL; +import static jdk.vm.ci.meta.JavaConstant.INT_0; +import static jdk.vm.ci.meta.JavaConstant.LONG_0; + +import org.graalvm.compiler.core.aarch64.AArch64MoveFactory; +import org.graalvm.compiler.lir.LIRInstruction; + +import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; + +public class AArch64HotSpotMoveFactory extends AArch64MoveFactory { + + @Override + public boolean canInlineConstant(JavaConstant c) { + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { + return true; + } else if (c instanceof HotSpotObjectConstant) { + return false; + } else { + return super.canInlineConstant(c); + } + } + + @Override + public LIRInstruction createLoad(AllocatableValue dst, Constant src) { + Constant usedSource; + if (COMPRESSED_NULL.equals(src)) { + usedSource = INT_0; + } else if (src instanceof HotSpotObjectConstant && ((HotSpotObjectConstant) src).isNull()) { + usedSource = LONG_0; + } else { + usedSource = src; + } + if (usedSource instanceof HotSpotConstant) { + HotSpotConstant constant = (HotSpotConstant) usedSource; + if (constant.isCompressed()) { + return new AArch64HotSpotMove.LoadHotSpotObjectConstantInline(constant, dst); + } else { + // XXX Do we need the constant table? + // return new SPARCHotSpotMove.LoadHotSpotObjectConstantFromTable(constant, dst, + // constantTableBaseProvider.getConstantTableBase()); + return new AArch64HotSpotMove.LoadHotSpotObjectConstantInline(constant, dst); + } + } else { + return super.createLoad(dst, usedSource); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotNodeLIRBuilder.java 2016-12-07 13:49:27.071339904 -0800 @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2015, 2016, 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.aarch64; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER; +import static jdk.vm.ci.aarch64.AArch64.lr; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; +import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp; +import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.inlineCacheRegister; +import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.metaspaceMethodRegister; + +import org.graalvm.compiler.core.aarch64.AArch64NodeLIRBuilder; +import org.graalvm.compiler.core.aarch64.AArch64NodeMatchRules; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.gen.DebugInfoBuilder; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.HotSpotLockStack; +import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder; +import org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode; +import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode; +import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.aarch64.AArch64BreakpointOp; +import org.graalvm.compiler.lir.aarch64.AArch64Move.CompareAndSwapOp; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.BreakpointNode; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.DirectCallTargetNode; +import org.graalvm.compiler.nodes.FullInfopointNode; +import org.graalvm.compiler.nodes.IndirectCallTargetNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.SafepointNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.NodeValueMap; + +import jdk.vm.ci.aarch64.AArch64Kind; +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.hotspot.HotSpotCallingConventionType; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; + +/** + * LIR generator specialized for AArch64 HotSpot. + */ +public class AArch64HotSpotNodeLIRBuilder extends AArch64NodeLIRBuilder implements HotSpotNodeLIRBuilder { + + public AArch64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AArch64NodeMatchRules nodeMatchRules) { + super(graph, gen, nodeMatchRules); + assert gen instanceof AArch64HotSpotLIRGenerator; + assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder; + ((AArch64HotSpotLIRGenerator) gen).setDebugInfoBuilder(((HotSpotDebugInfoBuilder) getDebugInfoBuilder())); + } + + @Override + protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) { + HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(AArch64Kind.QWORD)); + return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack, (HotSpotLIRGenerator) gen); + } + + private AArch64HotSpotLIRGenerator getGen() { + return (AArch64HotSpotLIRGenerator) gen; + } + + @Override + protected void emitPrologue(StructuredGraph graph) { + CallingConvention incomingArguments = gen.getResult().getCallingConvention(); + Value[] params = new Value[incomingArguments.getArgumentCount() + 2]; + for (int i = 0; i < incomingArguments.getArgumentCount(); i++) { + params[i] = incomingArguments.getArgument(i); + if (isStackSlot(params[i])) { + StackSlot slot = ValueUtil.asStackSlot(params[i]); + if (slot.isInCallerFrame() && !gen.getResult().getLIR().hasArgInCallerFrame()) { + gen.getResult().getLIR().setHasArgInCallerFrame(); + } + } + } + params[params.length - 2] = fp.asValue(LIRKind.value(AArch64Kind.QWORD)); + params[params.length - 1] = lr.asValue(LIRKind.value(AArch64Kind.QWORD)); + + gen.emitIncomingValues(params); + + for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { + Value paramValue = params[param.index()]; + assert paramValue.getValueKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp())) : paramValue.getValueKind() + " != " + param.stamp(); + setResult(param, gen.emitMove(paramValue)); + } + } + + @Override + public void visitSafepointNode(SafepointNode i) { + LIRFrameState info = state(i); + Variable scratch = gen.newVariable(LIRKind.value(getGen().target().arch.getWordKind())); + append(new AArch64HotSpotSafepointOp(info, getGen().config, scratch)); + } + + @Override + protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); + if (invokeKind.isIndirect()) { + append(new AArch64HotSpotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); + } else { + assert invokeKind.isDirect(); + HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); + assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method."; + append(new AArch64HotSpotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); + } + } + + @Override + protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + Value metaspaceMethodSrc = operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()); + Value targetAddressSrc = operand(callTarget.computedAddress()); + AllocatableValue metaspaceMethodDst = metaspaceMethodRegister.asValue(metaspaceMethodSrc.getValueKind()); + AllocatableValue targetAddressDst = inlineCacheRegister.asValue(targetAddressSrc.getValueKind()); + gen.emitMove(metaspaceMethodDst, metaspaceMethodSrc); + gen.emitMove(targetAddressDst, targetAddressSrc); + append(new AArch64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethodDst, targetAddressDst, callState, getGen().config)); + } + + @Override + public void emitPatchReturnAddress(ValueNode address) { + append(new AArch64HotSpotPatchReturnAddressOp(gen.load(operand(address)))); + } + + @Override + public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + Variable handler = gen.load(operand(handlerInCallerPc)); + ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER); + CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); + assert outgoingCc.getArgumentCount() == 2; + RegisterValue exceptionFixed = (RegisterValue) outgoingCc.getArgument(0); + RegisterValue exceptionPcFixed = (RegisterValue) outgoingCc.getArgument(1); + gen.emitMove(exceptionFixed, operand(exception)); + gen.emitMove(exceptionPcFixed, operand(exceptionPc)); + Register thread = getGen().getProviders().getRegisters().getThreadRegister(); + AArch64HotSpotJumpToExceptionHandlerInCallerOp op = new AArch64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, + getGen().config.threadIsMethodHandleReturnOffset, thread, getGen().config); + append(op); + } + + @Override + public void visitFullInfopointNode(FullInfopointNode i) { + if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) { + Debug.log("Ignoring InfopointNode for AFTER_BCI"); + } else { + super.visitFullInfopointNode(i); + } + } + + @Override + public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { + AllocatableValue address = gen.asAllocatable(operand(x.getAddress())); + AllocatableValue cmpValue = gen.asAllocatable(operand(x.expectedValue())); + AllocatableValue newValue = gen.asAllocatable(operand(x.newValue())); + ValueKind kind = cmpValue.getValueKind(); + assert kind.equals(newValue.getValueKind()); + + Variable result = gen.newVariable(newValue.getValueKind()); + Variable scratch = gen.newVariable(LIRKind.value(AArch64Kind.DWORD)); + append(new CompareAndSwapOp(result, cmpValue, newValue, address, scratch)); + setResult(x, result); + } + + @Override + public void visitBreakpointNode(BreakpointNode node) { + JavaType[] sig = new JavaType[node.arguments().size()]; + for (int i = 0; i < sig.length; i++) { + sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess()); + } + + Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), + node.arguments()); + append(new AArch64BreakpointOp(parameters)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotPatchReturnAddressOp.java 2016-12-07 13:49:27.342351816 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016, 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.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.aarch64.AArch64.sp; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64Address; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AArch64ExceptionCode; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Patch the return address of the current frame. + */ +@Opcode("PATCH_RETURN") +final class AArch64HotSpotPatchReturnAddressOp extends AArch64LIRInstruction { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotPatchReturnAddressOp.class); + + @Use(REG) AllocatableValue address; + + AArch64HotSpotPatchReturnAddressOp(AllocatableValue address) { + super(TYPE); + this.address = address; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + final int frameSize = crb.frameMap.frameSize(); + // XXX where is lr exactly? + AArch64Address lrAddress = AArch64Address.createUnscaledImmediateAddress(sp, frameSize); + masm.brk(AArch64ExceptionCode.BREAKPOINT); // XXX + masm.str(64, asRegister(address), lrAddress); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotRegisterAllocationConfig.java 2016-12-07 13:49:27.615363816 -0800 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2015, 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.aarch64; + +import static jdk.vm.ci.aarch64.AArch64.r0; +import static jdk.vm.ci.aarch64.AArch64.r1; +import static jdk.vm.ci.aarch64.AArch64.r10; +import static jdk.vm.ci.aarch64.AArch64.r11; +import static jdk.vm.ci.aarch64.AArch64.r12; +import static jdk.vm.ci.aarch64.AArch64.r13; +import static jdk.vm.ci.aarch64.AArch64.r14; +import static jdk.vm.ci.aarch64.AArch64.r15; +import static jdk.vm.ci.aarch64.AArch64.r16; +import static jdk.vm.ci.aarch64.AArch64.r17; +import static jdk.vm.ci.aarch64.AArch64.r18; +import static jdk.vm.ci.aarch64.AArch64.r19; +import static jdk.vm.ci.aarch64.AArch64.r2; +import static jdk.vm.ci.aarch64.AArch64.r20; +import static jdk.vm.ci.aarch64.AArch64.r21; +import static jdk.vm.ci.aarch64.AArch64.r22; +import static jdk.vm.ci.aarch64.AArch64.r23; +import static jdk.vm.ci.aarch64.AArch64.r24; +import static jdk.vm.ci.aarch64.AArch64.r25; +import static jdk.vm.ci.aarch64.AArch64.r26; +import static jdk.vm.ci.aarch64.AArch64.r27; +import static jdk.vm.ci.aarch64.AArch64.r28; +import static jdk.vm.ci.aarch64.AArch64.r3; +import static jdk.vm.ci.aarch64.AArch64.r4; +import static jdk.vm.ci.aarch64.AArch64.r5; +import static jdk.vm.ci.aarch64.AArch64.r6; +import static jdk.vm.ci.aarch64.AArch64.r7; +import static jdk.vm.ci.aarch64.AArch64.r8; +import static jdk.vm.ci.aarch64.AArch64.r9; +import static jdk.vm.ci.aarch64.AArch64.v0; +import static jdk.vm.ci.aarch64.AArch64.v1; +import static jdk.vm.ci.aarch64.AArch64.v10; +import static jdk.vm.ci.aarch64.AArch64.v11; +import static jdk.vm.ci.aarch64.AArch64.v12; +import static jdk.vm.ci.aarch64.AArch64.v13; +import static jdk.vm.ci.aarch64.AArch64.v14; +import static jdk.vm.ci.aarch64.AArch64.v15; +import static jdk.vm.ci.aarch64.AArch64.v16; +import static jdk.vm.ci.aarch64.AArch64.v17; +import static jdk.vm.ci.aarch64.AArch64.v18; +import static jdk.vm.ci.aarch64.AArch64.v19; +import static jdk.vm.ci.aarch64.AArch64.v2; +import static jdk.vm.ci.aarch64.AArch64.v20; +import static jdk.vm.ci.aarch64.AArch64.v21; +import static jdk.vm.ci.aarch64.AArch64.v22; +import static jdk.vm.ci.aarch64.AArch64.v23; +import static jdk.vm.ci.aarch64.AArch64.v24; +import static jdk.vm.ci.aarch64.AArch64.v25; +import static jdk.vm.ci.aarch64.AArch64.v26; +import static jdk.vm.ci.aarch64.AArch64.v27; +import static jdk.vm.ci.aarch64.AArch64.v28; +import static jdk.vm.ci.aarch64.AArch64.v29; +import static jdk.vm.ci.aarch64.AArch64.v3; +import static jdk.vm.ci.aarch64.AArch64.v30; +import static jdk.vm.ci.aarch64.AArch64.v31; +import static jdk.vm.ci.aarch64.AArch64.v4; +import static jdk.vm.ci.aarch64.AArch64.v5; +import static jdk.vm.ci.aarch64.AArch64.v6; +import static jdk.vm.ci.aarch64.AArch64.v7; +import static jdk.vm.ci.aarch64.AArch64.v8; +import static jdk.vm.ci.aarch64.AArch64.v9; + +import java.util.ArrayList; +import java.util.BitSet; + +import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterConfig; + +public class AArch64HotSpotRegisterAllocationConfig extends RegisterAllocationConfig { + + // @formatter:off + static final Register[] registerAllocationOrder = { + r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15, + r16, r17, r18, r19, r20, r21, r22, r23, + r24, r25, r26, r27, r28, /* r29, r30, r31 */ + + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31 + }; + // @formatter:on + + public AArch64HotSpotRegisterAllocationConfig(RegisterConfig registerConfig) { + super(registerConfig); + } + + @Override + protected RegisterArray initAllocatable(RegisterArray registers) { + BitSet regMap = new BitSet(registerConfig.getAllocatableRegisters().size()); + for (Register reg : registers) { + regMap.set(reg.number); + } + + ArrayList allocatableRegisters = new ArrayList<>(registers.size()); + for (Register reg : registerAllocationOrder) { + if (regMap.get(reg.number)) { + allocatableRegisters.add(reg); + } + } + + return super.initAllocatable(new RegisterArray(allocatableRegisters)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotReturnOp.java 2016-12-07 13:49:27.885375685 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, 2015, 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.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.aarch64.AArch64.lr; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.meta.Value; + +/** + * Returns from a function. + */ +@Opcode("RETURN") +public final class AArch64HotSpotReturnOp extends AArch64HotSpotEpilogueOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotReturnOp.class); + + @Use({REG, ILLEGAL}) private Value result; + private final boolean isStub; + + public AArch64HotSpotReturnOp(Value result, boolean isStub, GraalHotSpotVMConfig config) { + super(TYPE, config); + assert validReturnValue(result); + this.result = result; + this.isStub = isStub; + } + + private static boolean validReturnValue(Value result) { + if (result.equals(Value.ILLEGAL)) { + return true; + } + return asRegister(result).encoding == 0; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + final boolean emitSafepoint = !isStub; + leaveFrame(crb, masm, emitSafepoint); + masm.ret(lr); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java 2016-12-07 13:49:28.157387641 -0800 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2013, 2016, 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.aarch64; + +import static jdk.vm.ci.aarch64.AArch64.zr; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.aarch64.AArch64Address; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.site.InfopointReason; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Emits a safepoint poll. + */ +@Opcode("SAFEPOINT") +public class AArch64HotSpotSafepointOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotSafepointOp.class); + + @State protected LIRFrameState state; + @Temp protected AllocatableValue scratchValue; + + private final GraalHotSpotVMConfig config; + + public AArch64HotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, AllocatableValue scratch) { + super(TYPE); + this.state = state; + this.config = config; + this.scratchValue = scratch; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register scratch = asRegister(scratchValue); + emitCode(crb, masm, config, false, scratch, state); + } + + /** + * Conservatively checks whether we can load the safepoint polling address with a single ldr + * instruction or not. + * + * @return true if it is guaranteed that polling page offset will always fit into a 21-bit + * signed integer, false otherwise. + */ + private static boolean isPollingPageFar(GraalHotSpotVMConfig config) { + final long pollingPageAddress = config.safepointPollingAddress; + return !NumUtil.isSignedNbit(21, pollingPageAddress - config.codeCacheLowBound) || !NumUtil.isSignedNbit(21, pollingPageAddress - config.codeCacheHighBound); + } + + public static void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register scratch, LIRFrameState state) { + int pos = masm.position(); + if (isPollingPageFar(config)) { + crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); + masm.movNativeAddress(scratch, config.safepointPollingAddress); + if (state != null) { + crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); + } + masm.ldr(32, zr, AArch64Address.createBaseRegisterOnlyAddress(scratch)); + } else { + crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_NEAR : config.MARKID_POLL_NEAR); + if (state != null) { + crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); + } + masm.ldr(32, zr, AArch64Address.createPcLiteralAddress(0)); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotStrategySwitchOp.java 2016-12-07 13:49:28.427399510 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, 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.aarch64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import java.util.function.Function; + +import org.graalvm.compiler.asm.aarch64.AArch64Assembler; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; + +final class AArch64HotSpotStrategySwitchOp extends AArch64ControlFlow.StrategySwitchOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotStrategySwitchOp.class); + + AArch64HotSpotStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, Function converter) { + super(TYPE, strategy, keyTargets, defaultTarget, key, scratch, converter); + } + + @Override + public void emitCode(final CompilationResultBuilder crb, final AArch64MacroAssembler masm) { + strategy.run(new HotSpotSwitchClosure(asRegister(key), crb, masm)); + } + + public class HotSpotSwitchClosure extends SwitchClosure { + + protected HotSpotSwitchClosure(Register keyRegister, CompilationResultBuilder crb, AArch64MacroAssembler masm) { + super(keyRegister, crb, masm); + } + + @Override + protected void emitComparison(Constant c) { + if (c instanceof HotSpotMetaspaceConstant) { + HotSpotMetaspaceConstant meta = (HotSpotMetaspaceConstant) c; + if (meta.isCompressed()) { + crb.recordInlineDataInCode(meta); + // masm.cmpl(keyRegister, 0xDEADDEAD); + throw GraalError.unimplemented(); + } else { + crb.recordInlineDataInCode(meta); + masm.movNativeAddress(asRegister(scratch), 0x0000_DEAD_DEAD_DEADL); + masm.cmp(64, keyRegister, asRegister(scratch)); + } + } else { + super.emitComparison(c); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotUnwindOp.java 2016-12-07 13:49:28.700411510 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013, 2016, 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.aarch64; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER; +import static jdk.vm.ci.aarch64.AArch64.lr; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.aarch64.AArch64Call; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; + +/** + * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}. + */ +@Opcode("UNWIND") +public final class AArch64HotSpotUnwindOp extends AArch64HotSpotEpilogueOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotUnwindOp.class); + + @Use protected RegisterValue exception; + + public AArch64HotSpotUnwindOp(GraalHotSpotVMConfig config, RegisterValue exception) { + super(TYPE, config); + this.exception = exception; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + leaveFrame(crb, masm, /* emitSafepoint */false); + + ForeignCallLinkage linkage = crb.foreignCalls.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER); + CallingConvention cc = linkage.getOutgoingCallingConvention(); + assert cc.getArgumentCount() == 2; + assert exception.equals(cc.getArgument(0)); + + // Get return address (is in lr after frame leave) + Register returnAddress = asRegister(cc.getArgument(1)); + masm.movx(returnAddress, lr); + + AArch64Call.directJmp(crb, masm, linkage); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64IndirectCallOp.java 2016-12-07 13:49:28.972423466 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013, 2015, 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.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.aarch64.AArch64.r12; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.aarch64.AArch64Call; +import org.graalvm.compiler.lir.aarch64.AArch64Call.IndirectCallOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * A register indirect call that complies with the extra conventions for such calls in HotSpot. In + * particular, the metaspace Method of the callee must be in r12 for the case where a vtable entry's + * _from_compiled_entry is the address of an C2I adapter. Such adapters expect the target method to + * be in r12. + */ +@Opcode("CALL_INDIRECT") +final class AArch64IndirectCallOp extends IndirectCallOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64IndirectCallOp.class); + + /** + * Vtable stubs expect the metaspace Method in r12. + */ + public static final Register METHOD = r12; + + @Use({REG}) private Value metaspaceMethod; + + private final GraalHotSpotVMConfig config; + + AArch64IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state, + GraalHotSpotVMConfig config) { + super(TYPE, callTarget, result, parameters, temps, targetAddress, state); + this.metaspaceMethod = metaspaceMethod; + this.config = config; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + crb.recordMark(config.MARKID_INLINE_INVOKE); + Register callReg = asRegister(targetAddress); + assert !callReg.equals(METHOD); + AArch64Call.indirectCall(crb, masm, callReg, callTarget, state); + } + + @Override + public void verify() { + super.verify(); + assert asRegister(metaspaceMethod).equals(METHOD); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArchHotSpotNodeCostProvider.java 2016-12-07 13:49:29.243435379 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, 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.aarch64; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider; +import org.graalvm.compiler.nodeinfo.NodeCycles; +import org.graalvm.compiler.nodeinfo.NodeSize; + +public class AArchHotSpotNodeCostProvider extends HotSpotNodeCostProvider { + + @Override + public NodeCycles cycles(Node n) { + return super.cycles(n); + } + + @Override + public NodeSize size(Node n) { + return super.size(n); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java 2016-12-07 13:49:29.515447335 -0800 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2013, 2015, 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.amd64.test; + +import static jdk.vm.ci.amd64.AMD64.rax; + +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.asm.amd64.AMD64Assembler; +import org.graalvm.compiler.core.test.GraalCompilerTest; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotCallingConventionType; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Ensures that frame omission works in cases where it is expected to. + */ +public class AMD64HotSpotFrameOmissionTest extends GraalCompilerTest { + + interface CodeGenerator { + + void generateCode(AMD64Assembler asm); + } + + public static void test1snippet() { + return; + } + + @Ignore + @Test + public void test1() { + testHelper("test1snippet", new CodeGenerator() { + + @Override + public void generateCode(AMD64Assembler asm) { + asm.nop(5); // padding for mt-safe patching + asm.ret(0); + } + }); + } + + public static int test2snippet(int x) { + return x + 5; + } + + @Ignore + @Test + public void test2() { + testHelper("test2snippet", new CodeGenerator() { + + @Override + public void generateCode(AMD64Assembler asm) { + Register arg = getArgumentRegister(0, JavaKind.Int); + asm.nop(5); // padding for mt-safe patching + asm.addl(arg, 5); + asm.movl(rax, arg); + asm.ret(0); + } + }); + } + + public static long test3snippet(long x) { + return 1 + x; + } + + @Ignore + @Test + public void test3() { + testHelper("test3snippet", new CodeGenerator() { + + @Override + public void generateCode(AMD64Assembler asm) { + Register arg = getArgumentRegister(0, JavaKind.Long); + asm.nop(5); // padding for mt-safe patching + asm.addq(arg, 1); + asm.movq(rax, arg); + asm.ret(0); + } + }); + } + + private void testHelper(String name, CodeGenerator gen) { + ResolvedJavaMethod javaMethod = getResolvedJavaMethod(name); + InstalledCode installedCode = getCode(javaMethod); + + TargetDescription target = getCodeCache().getTarget(); + AMD64Assembler asm = new AMD64Assembler(target); + + gen.generateCode(asm); + byte[] expectedCode = asm.close(true); + + // Only compare up to expectedCode.length bytes to ignore + // padding instructions adding during code installation + byte[] actualCode = Arrays.copyOf(installedCode.getCode(), expectedCode.length); + + Assert.assertArrayEquals(expectedCode, actualCode); + } + + private Register getArgumentRegister(int index, JavaKind kind) { + RegisterArray regs = getCodeCache().getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCall, kind); + return regs.get(index); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/CompressedNullCheckTest.java 2016-12-07 13:49:29.780458984 -0800 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2014, 2015, 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.amd64.test; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.hotspot.nodes.CompressionNode; +import org.graalvm.compiler.hotspot.test.HotSpotGraalCompilerTest; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.IsNullNode; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Ensures that frame omission works in cases where it is expected to. + */ +public class CompressedNullCheckTest extends HotSpotGraalCompilerTest { + + private static final class Container { + Integer i; + } + + public static void testSnippet(Container c) { + c.i.intValue(); + } + + @SuppressWarnings("try") + private void testImplicit(Integer i) { + Assume.assumeTrue(runtime().getVMConfig().useCompressedOops); + + Container c = new Container(); + c.i = i; + + try (OverrideScope s = OptionValue.override(GraalOptions.OptImplicitNullChecks, true)) { + ResolvedJavaMethod method = getResolvedJavaMethod("testSnippet"); + Result expect = executeExpected(method, null, c); + + // make sure we don't get a profile that removes the implicit null check + method.reprofile(); + + Result actual = executeActual(method, null, c); + assertEquals(expect, actual); + } + } + + @SuppressWarnings("try") + private void testExplicit(Integer i) { + Assume.assumeTrue(runtime().getVMConfig().useCompressedOops); + + Container c = new Container(); + c.i = i; + + try (OverrideScope s = OptionValue.override(GraalOptions.OptImplicitNullChecks, false)) { + test("testSnippet", c); + } + } + + @Test + public void implicit() { + testImplicit(new Integer(1)); + } + + @Test + public void implicitNull() { + testImplicit(null); + } + + @Test + public void explicit() { + testExplicit(new Integer(1)); + } + + @Test + public void explicitNull() { + testExplicit(null); + } + + @Override + protected boolean checkMidTierGraph(StructuredGraph graph) { + int count = 0; + for (IsNullNode isNull : graph.getNodes().filter(IsNullNode.class).snapshot()) { + ValueNode value = isNull.getValue(); + if (value instanceof CompressionNode) { + count++; + isNull.replaceFirstInput(value, ((CompressionNode) value).getValue()); + } + } + Assert.assertEquals("graph should contain exactly one IsNullNode", 1, count); + return super.checkMidTierGraph(graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/DataPatchInConstantsTest.java 2016-12-07 13:49:30.045470632 -0800 @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2014, 2015, 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.amd64.test; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.junit.Assume; +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.graph.NodeClass; +import org.graalvm.compiler.hotspot.nodes.CompressionNode; +import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp; +import org.graalvm.compiler.hotspot.test.HotSpotGraalCompilerTest; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class DataPatchInConstantsTest extends HotSpotGraalCompilerTest { + + @Before + public void checkAMD64() { + Assume.assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + } + + private static final Object object = new Object() { + + @Override + public String toString() { + return "testObject"; + } + }; + + private static Object loadThroughPatch(Object obj) { + return obj; + } + + public static Object oopSnippet() { + Object patch = loadThroughPatch(object); + if (object != patch) { + return "invalid patch"; + } + System.gc(); + patch = loadThroughPatch(object); + if (object != patch) { + return "failed after gc"; + } + return patch; + } + + @Test + public void oopTest() { + test("oopSnippet"); + } + + private static Object loadThroughCompressedPatch(Object obj) { + return obj; + } + + public static Object narrowOopSnippet() { + Object patch = loadThroughCompressedPatch(object); + if (object != patch) { + return "invalid patch"; + } + System.gc(); + patch = loadThroughCompressedPatch(object); + if (object != patch) { + return "failed after gc"; + } + return patch; + } + + @Test + public void narrowOopTest() { + Assume.assumeTrue("skipping narrow oop data patch test", runtime().getVMConfig().useCompressedOops); + test("narrowOopSnippet"); + } + + public static Object compareSnippet() { + Object uncompressed = loadThroughPatch(object); + Object compressed = loadThroughCompressedPatch(object); + if (object != uncompressed) { + return "uncompressed failed"; + } + if (object != compressed) { + return "compressed failed"; + } + if (uncompressed != compressed) { + return "uncompressed != compressed"; + } + return object; + } + + @Test + public void compareTest() { + Assume.assumeTrue("skipping narrow oop data patch test", runtime().getVMConfig().useCompressedOops); + test("compareSnippet"); + } + + @Override + protected Plugins getDefaultGraphBuilderPlugins() { + Plugins plugins = super.getDefaultGraphBuilderPlugins(); + Registration r = new Registration(plugins.getInvocationPlugins(), DataPatchInConstantsTest.class); + + r.register1("loadThroughPatch", Object.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + b.addPush(JavaKind.Object, new LoadThroughPatchNode(arg)); + return true; + } + }); + + r.register1("loadThroughCompressedPatch", Object.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + ValueNode compressed = b.add(CompressionNode.compress(arg, runtime().getVMConfig().getOopEncoding())); + ValueNode patch = b.add(new LoadThroughPatchNode(compressed)); + b.addPush(JavaKind.Object, CompressionNode.uncompress(patch, runtime().getVMConfig().getOopEncoding())); + return true; + } + }); + + return plugins; + } + + @NodeInfo(cycles = CYCLES_2, size = SIZE_1) + private static final class LoadThroughPatchNode extends FixedWithNextNode implements LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(LoadThroughPatchNode.class); + + @Input protected ValueNode input; + + protected LoadThroughPatchNode(ValueNode input) { + super(TYPE, input.stamp()); + this.input = input; + } + + @Override + public void generate(NodeLIRBuilderTool generator) { + assert input.isConstant(); + + LIRGeneratorTool gen = generator.getLIRGeneratorTool(); + Variable ret = gen.newVariable(gen.getLIRKind(stamp())); + + gen.append(new LoadThroughPatchOp(input.asConstant(), stamp() instanceof NarrowOopStamp, ret)); + generator.setResult(this, ret); + } + } + + private static final class LoadThroughPatchOp extends LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadThroughPatchOp.class); + + final Constant c; + final boolean compressed; + @Def({REG}) AllocatableValue result; + + LoadThroughPatchOp(Constant c, boolean compressed, AllocatableValue result) { + super(TYPE); + this.c = c; + this.compressed = compressed; + this.result = result; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + AMD64Address address = (AMD64Address) crb.recordDataReferenceInCode(c, compressed ? 4 : 8); + AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm; + if (compressed) { + asm.movl(asRegister(result), address); + } else { + asm.movq(asRegister(result), address); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/StubAVXTest.java 2016-12-07 13:49:30.311482325 -0800 @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2016, 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.amd64.test; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; + +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.type.DataPointerConstant; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.stubs.SnippetStub; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.ArrayDataPointerConstant; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.jtt.LIRTest; +import org.graalvm.compiler.lir.jtt.LIRTestSpecification; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +public class StubAVXTest extends LIRTest { + + @Before + public void checkAMD64() { + Assume.assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + Assume.assumeTrue("skipping AVX test", ((AMD64) getTarget().arch).getFeatures().contains(CPUFeature.AVX)); + } + + private static final DataPointerConstant avxConstant = new ArrayDataPointerConstant(new float[]{1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f}, 32); + + private static class LoadAVXConstant extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadAVXConstant.class); + + @Def({REG}) AllocatableValue result; + + LoadAVXConstant(AllocatableValue result) { + super(TYPE); + this.result = result; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + masm.vmovdqu(ValueUtil.asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(avxConstant)); + } + } + + private static final LIRTestSpecification loadAVXConstant = new LIRTestSpecification() { + + @Override + public void generate(LIRGeneratorTool gen) { + Variable ret = gen.newVariable(LIRKind.value(AMD64Kind.V256_SINGLE)); + gen.append(new LoadAVXConstant(ret)); + setResult(ret); + } + }; + + @LIRIntrinsic + public static Object loadAVXConstant(@SuppressWarnings("unused") LIRTestSpecification spec) { + return null; + } + + private static class CompareAVXRegister extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareAVXRegister.class); + + @Def({REG}) AllocatableValue result; + @Use({REG}) AllocatableValue left; + @Use({REG}) AllocatableValue right; + @Temp({REG}) AllocatableValue temp; + + CompareAVXRegister(AllocatableValue result, AllocatableValue left, AllocatableValue right, AllocatableValue temp) { + super(TYPE); + this.result = result; + this.left = left; + this.right = right; + this.temp = temp; + } + + private static int getRXB(Register reg, Register rm) { + int rxb = (reg.encoding & 0x08) >> 1; + rxb |= (rm.encoding & 0x08) >> 3; + return rxb; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Register res = ValueUtil.asRegister(result); + Register x = ValueUtil.asRegister(left); + Register y = ValueUtil.asRegister(right); + Register tmp = ValueUtil.asRegister(temp); + + // VEX.NDS.256.0F.WIG C2 /r ib(0) + // VCMPPS tmp, x, y, EQ + masm.emitByte(0xC4); // VEX 3-byte + masm.emitByte((~getRXB(tmp, y) & 0x7) << 5 | 0x01); // RXB m-mmmmm (0F) + masm.emitByte(((~x.encoding & 0x0f) << 3) | 0b1_00); // W(0) vvvv L(1) pp(0) + masm.emitByte(0xC2); + masm.emitByte(0xC0 | ((tmp.encoding & 0x07) << 3) | (y.encoding & 0x07)); + masm.emitByte(0); + + // VEX.256.0F.WIG 50 /r + // VMOVMSKPS res, tmp + masm.emitByte(0xC4); // VEX 3-byte + masm.emitByte((~getRXB(res, tmp) & 0x7) << 5 | 0x01); // RXB m-mmmmm (0F) + masm.emitByte(0b0_1111_1_00); // W(0) vvvv L(1) pp(0) + masm.emitByte(0x50); + masm.emitByte(0xC0 | ((res.encoding & 0x07) << 3) | (tmp.encoding & 0x07)); + } + } + + private static final LIRTestSpecification compareAVXRegister = new LIRTestSpecification() { + + @Override + public void generate(LIRGeneratorTool gen, Value arg0, Value arg1) { + Variable ret = gen.newVariable(LIRKind.value(AMD64Kind.DWORD)); + gen.append(new CompareAVXRegister(ret, gen.asAllocatable(arg0), gen.asAllocatable(arg1), gen.newVariable(LIRKind.value(AMD64Kind.V256_QWORD)))); + setResult(ret); + } + }; + + private static class TestStub extends SnippetStub { + + TestStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super("testStub", providers, linkage); + } + + @Snippet + static void testStub() { + } + } + + public static final ForeignCallDescriptor TEST_STUB = new ForeignCallDescriptor("test_stub", void.class); + + @LIRIntrinsic + public static int compareAVXRegister(@SuppressWarnings("unused") LIRTestSpecification spec, Object left, Object right) { + return left == right ? 0xff : 0; + } + + @Override + protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) { + InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins(); + InvocationPlugins.Registration r = new InvocationPlugins.Registration(invocationPlugins, TestStub.class); + r.register0("testStub", new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver) { + b.add(new ForeignCallNode(getProviders().getForeignCalls(), TEST_STUB)); + return true; + } + }); + return super.editGraphBuilderConfiguration(conf); + } + + public static int testStub() { + Object preStub = loadAVXConstant(loadAVXConstant); + + // do something to potentially destroy the value + TestStub.testStub(); + + Object postStub = loadAVXConstant(loadAVXConstant); + return compareAVXRegister(compareAVXRegister, preStub, postStub); + } + + @Test + public void test() { + HotSpotProviders providers = (HotSpotProviders) getProviders(); + HotSpotForeignCallsProviderImpl foreignCalls = (HotSpotForeignCallsProviderImpl) providers.getForeignCalls(); + HotSpotForeignCallLinkage linkage = foreignCalls.registerStubCall(TEST_STUB, true, HotSpotForeignCallLinkage.Transition.LEAF_NOFP); + linkage.setCompiledStub(new TestStub(providers, linkage)); + runTest("testStub"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizationStub.java 2016-12-07 13:49:30.577494018 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, 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.amd64; + +import static jdk.vm.ci.amd64.AMD64.r10; +import static jdk.vm.ci.amd64.AMD64.r11; +import static jdk.vm.ci.amd64.AMD64.r13; +import static jdk.vm.ci.amd64.AMD64.r14; +import static jdk.vm.ci.amd64.AMD64.r8; +import static jdk.vm.ci.amd64.AMD64.r9; +import static jdk.vm.ci.amd64.AMD64.rbx; +import static jdk.vm.ci.amd64.AMD64.rcx; +import static jdk.vm.ci.amd64.AMD64.rdi; +import static jdk.vm.ci.amd64.AMD64.rdx; +import static jdk.vm.ci.amd64.AMD64.rsi; + +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.stubs.DeoptimizationStub; + +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.amd64.AMD64HotSpotRegisterConfig; + +final class AMD64DeoptimizationStub extends DeoptimizationStub { + + private RegisterConfig registerConfig; + + AMD64DeoptimizationStub(HotSpotProviders providers, TargetDescription target, GraalHotSpotVMConfig config, HotSpotForeignCallLinkage linkage) { + super(providers, target, linkage); + registerConfig = new AMD64HotSpotRegisterConfig(target, new RegisterArray(rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14), config.windowsOs); + } + + @Override + public RegisterConfig getRegisterConfig() { + return registerConfig; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizeOp.java 2016-12-07 13:49:30.841505622 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2015, 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.amd64; + +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp.BlockEndOp; +import org.graalvm.compiler.lir.amd64.AMD64BlockEndOp; +import org.graalvm.compiler.lir.amd64.AMD64Call; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +@Opcode("DEOPT") +final class AMD64DeoptimizeOp extends AMD64BlockEndOp implements BlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64DeoptimizeOp.class); + + @State private LIRFrameState info; + + AMD64DeoptimizeOp(LIRFrameState info) { + super(TYPE); + this.info = info; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, false, info); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java 2016-12-07 13:49:31.106517271 -0800 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2015, 2016, 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.amd64; + +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; +import org.graalvm.compiler.core.amd64.AMD64AddressLowering; +import org.graalvm.compiler.core.amd64.AMD64AddressNode; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.CompressEncoding; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.nodes.CompressionNode; +import org.graalvm.compiler.hotspot.nodes.CompressionNode.CompressionOp; +import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.JavaKind; + +public class AMD64HotSpotAddressLowering extends AMD64AddressLowering { + + private final long heapBase; + private final Register heapBaseRegister; + private final GraalHotSpotVMConfig config; + + @NodeInfo(cycles = CYCLES_0, size = SIZE_0) + public static class HeapBaseNode extends FloatingNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(HeapBaseNode.class); + + private final Register heapBaseRegister; + + public HeapBaseNode(Register heapBaseRegister) { + super(TYPE, StampFactory.pointer()); + this.heapBaseRegister = heapBaseRegister; + } + + @Override + public void generate(NodeLIRBuilderTool generator) { + LIRKind kind = generator.getLIRGeneratorTool().getLIRKind(stamp()); + generator.setResult(this, heapBaseRegister.asValue(kind)); + } + } + + public AMD64HotSpotAddressLowering(GraalHotSpotVMConfig config, Register heapBaseRegister) { + this.heapBase = config.getOopEncoding().base; + this.config = config; + if (heapBase == 0 && !GeneratePIC.getValue()) { + this.heapBaseRegister = null; + } else { + this.heapBaseRegister = heapBaseRegister; + } + } + + @Override + protected boolean improve(AMD64AddressNode addr) { + if (addr.getScale() == Scale.Times1) { + if (addr.getBase() == null && addr.getIndex() instanceof CompressionNode) { + if (improveUncompression(addr, (CompressionNode) addr.getIndex())) { + return true; + } + } + + if (addr.getIndex() == null && addr.getBase() instanceof CompressionNode) { + if (improveUncompression(addr, (CompressionNode) addr.getBase())) { + return true; + } + } + } + + return super.improve(addr); + } + + private boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression) { + if (compression.getOp() == CompressionOp.Uncompress) { + CompressEncoding encoding = compression.getEncoding(); + Scale scale = Scale.fromShift(encoding.shift); + if (scale == null) { + return false; + } + + if (heapBaseRegister != null && encoding.base == heapBase) { + if (!GeneratePIC.getValue() || compression.stamp() instanceof ObjectStamp) { + // With PIC it is only legal to do for oops since the base value may be + // different at runtime. + ValueNode base = compression.graph().unique(new HeapBaseNode(heapBaseRegister)); + addr.setBase(base); + } else { + return false; + } + } else if (encoding.base != 0 || (GeneratePIC.getValue() && compression.stamp() instanceof KlassPointerStamp)) { + if (GeneratePIC.getValue()) { + ValueNode base = compression.graph().unique(new GraalHotSpotVMConfigNode(config, config.MARKID_NARROW_KLASS_BASE_ADDRESS, JavaKind.Long)); + addr.setBase(base); + } else { + long disp = addr.getDisplacement() + encoding.base; + if (NumUtil.isInt(disp)) { + addr.setDisplacement((int) disp); + addr.setBase(null); + } else { + return false; + } + } + } else { + addr.setBase(null); + } + + addr.setScale(scale); + addr.setIndex(compression.getValue()); + return true; + } else { + return false; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotArithmeticLIRGenerator.java 2016-12-07 13:49:31.371528919 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, 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.amd64; + +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.COS; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.LOG; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.LOG10; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.SIN; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.TAN; + +import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.Variable; +import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs; + +import jdk.vm.ci.meta.Value; + +public class AMD64HotSpotArithmeticLIRGenerator extends AMD64ArithmeticLIRGenerator { + + @Override + public Value emitMathLog(Value input, boolean base10) { + if (GraalArithmeticStubs.getValue()) { + return super.emitMathLog(input, base10); + } + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input))); + return result; + } + + @Override + public Value emitMathCos(Value input) { + if (GraalArithmeticStubs.getValue()) { + return super.emitMathCos(input); + } + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(COS, result, getLIRGen().asAllocatable(input))); + return result; + } + + @Override + public Value emitMathSin(Value input) { + if (GraalArithmeticStubs.getValue()) { + return super.emitMathSin(input); + } + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(SIN, result, getLIRGen().asAllocatable(input))); + return result; + } + + @Override + public Value emitMathTan(Value input) { + if (GraalArithmeticStubs.getValue()) { + return super.emitMathTan(input); + } + Variable result = getLIRGen().newVariable(LIRKind.combine(input)); + getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(TAN, result, getLIRGen().asAllocatable(input))); + return result; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java 2016-12-07 13:49:31.637540612 -0800 @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2012, 2016, 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.amd64; + +import static org.graalvm.compiler.core.common.GraalOptions.CanOmitFrame; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; +import static jdk.vm.ci.amd64.AMD64.r10; +import static jdk.vm.ci.amd64.AMD64.rax; +import static jdk.vm.ci.amd64.AMD64.rsp; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import java.util.Set; + +import org.graalvm.compiler.asm.Assembler; +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.amd64.AMD64NodeMatchRules; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; +import org.graalvm.compiler.core.target.Backend; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotDataBuilder; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.HotSpotHostBackend; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; +import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.amd64.AMD64Call; +import org.graalvm.compiler.lir.amd64.AMD64FrameMap; +import org.graalvm.compiler.lir.amd64.AMD64FrameMapBuilder; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.lir.asm.DataBuilder; +import org.graalvm.compiler.lir.asm.FrameContext; +import org.graalvm.compiler.lir.framemap.FrameMap; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.hotspot.HotSpotCallingConventionType; +import jdk.vm.ci.hotspot.HotSpotSentinelConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * HotSpot AMD64 specific backend. + */ +public class AMD64HotSpotBackend extends HotSpotHostBackend { + + public AMD64HotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { + super(config, runtime, providers); + } + + @Override + public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) { + RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; + return new AMD64FrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull); + } + + @Override + public FrameMap newFrameMap(RegisterConfig registerConfig) { + return new AMD64FrameMap(getCodeCache(), registerConfig, this); + } + + @Override + public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) { + return new AMD64HotSpotLIRGenerator(getProviders(), config, lirGenRes); + } + + @Override + public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, Object stub) { + return new HotSpotLIRGenerationResult(compilationId, lir, frameMapBuilder, makeCallingConvention(graph, (Stub) stub), stub); + } + + @Override + public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { + return new AMD64HotSpotNodeLIRBuilder(graph, lirGen, new AMD64NodeMatchRules(lirGen)); + } + + @Override + protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) { + AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm; + int pos = asm.position(); + asm.movl(new AMD64Address(rsp, -bangOffset), AMD64.rax); + assert asm.position() - pos >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; + } + + /** + * The size of the instruction used to patch the verified entry point of an nmethod when the + * nmethod is made non-entrant or a zombie (e.g. during deopt or class unloading). The first + * instruction emitted at an nmethod's verified entry point must be at least this length to + * ensure mt-safe patching. + */ + public static final int PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE = 5; + + /** + * Emits code at the verified entry point and return point(s) of a method. + */ + class HotSpotFrameContext implements FrameContext { + + final boolean isStub; + final boolean omitFrame; + + HotSpotFrameContext(boolean isStub, boolean omitFrame) { + this.isStub = isStub; + this.omitFrame = omitFrame; + } + + @Override + public boolean hasFrame() { + return !omitFrame; + } + + @Override + public void enter(CompilationResultBuilder crb) { + FrameMap frameMap = crb.frameMap; + int frameSize = frameMap.frameSize(); + AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm; + if (omitFrame) { + if (!isStub) { + asm.nop(PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE); + } + } else { + int verifiedEntryPointOffset = asm.position(); + if (!isStub) { + emitStackOverflowCheck(crb); + // assert asm.position() - verifiedEntryPointOffset >= + // PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; + } + if (!isStub && asm.position() == verifiedEntryPointOffset) { + asm.subqWide(rsp, frameSize); + assert asm.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; + } else { + asm.decrementq(rsp, frameSize); + } + if (ZapStackOnMethodEntry.getValue()) { + final int intSize = 4; + for (int i = 0; i < frameSize / intSize; ++i) { + asm.movl(new AMD64Address(rsp, i * intSize), 0xC1C1C1C1); + } + } + assert frameMap.getRegisterConfig().getCalleeSaveRegisters() == null; + } + } + + @Override + public void leave(CompilationResultBuilder crb) { + if (!omitFrame) { + AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm; + assert crb.frameMap.getRegisterConfig().getCalleeSaveRegisters() == null; + + int frameSize = crb.frameMap.frameSize(); + asm.incrementq(rsp, frameSize); + } + } + } + + @Override + protected Assembler createAssembler(FrameMap frameMap) { + return new AMD64MacroAssembler(getTarget()); + } + + @Override + public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRen, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { + // Omit the frame if the method: + // - has no spill slots or other slots allocated during register allocation + // - has no callee-saved registers + // - has no incoming arguments passed on the stack + // - has no deoptimization points + // - makes no foreign calls (which require an aligned stack) + HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRen; + LIR lir = gen.getLIR(); + assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; + boolean omitFrame = CanOmitFrame.getValue() && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame() && !gen.hasForeignCall(); + + Stub stub = gen.getStub(); + Assembler masm = createAssembler(frameMap); + HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null, omitFrame); + DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget()); + CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, dataBuilder, frameContext, compilationResult); + crb.setTotalFrameSize(frameMap.totalFrameSize()); + crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize()); + StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot(); + if (deoptimizationRescueSlot != null && stub == null) { + crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot); + } + + if (stub != null) { + Set destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir); + updateStub(stub, destroyedCallerRegisters, gen.getCalleeSaveInfo(), frameMap); + } + + return crb; + } + + @Override + public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) { + AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm; + FrameMap frameMap = crb.frameMap; + RegisterConfig regConfig = frameMap.getRegisterConfig(); + Label verifiedEntry = new Label(); + + // Emit the prefix + emitCodePrefix(installedCodeOwner, crb, asm, regConfig, verifiedEntry); + + // Emit code for the LIR + emitCodeBody(installedCodeOwner, crb, lir); + + // Emit the suffix + emitCodeSuffix(installedCodeOwner, crb, asm, frameMap); + + // Profile assembler instructions + profileInstructions(lir, crb); + } + + /** + * Emits the code prior to the verified entry point. + * + * @param installedCodeOwner see {@link Backend#emitCode} + */ + public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, RegisterConfig regConfig, Label verifiedEntry) { + HotSpotProviders providers = getProviders(); + if (installedCodeOwner != null && !installedCodeOwner.isStatic()) { + crb.recordMark(config.MARKID_UNVERIFIED_ENTRY); + CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, this); + Register inlineCacheKlass = rax; // see definition of IC_Klass in + // c1_LIRAssembler_x86.cpp + Register receiver = asRegister(cc.getArgument(0)); + AMD64Address src = new AMD64Address(receiver, config.hubOffset); + + if (config.useCompressedClassPointers) { + Register register = r10; + AMD64HotSpotMove.decodeKlassPointer(asm, register, providers.getRegisters().getHeapBaseRegister(), src, config.getKlassEncoding()); + if (config.narrowKlassBase != 0) { + // The heap base register was destroyed above, so restore it + asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase); + } + asm.cmpq(inlineCacheKlass, register); + } else { + asm.cmpq(inlineCacheKlass, src); + } + AMD64Call.directConditionalJmp(crb, asm, getForeignCalls().lookupForeignCall(IC_MISS_HANDLER), ConditionFlag.NotEqual); + } + + asm.align(config.codeEntryAlignment); + crb.recordMark(config.MARKID_OSR_ENTRY); + asm.bind(verifiedEntry); + crb.recordMark(config.MARKID_VERIFIED_ENTRY); + + if (GeneratePIC.getValue()) { + // Check for method state + HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; + if (!frameContext.isStub) { + crb.recordInlineDataInCodeWithNote(new HotSpotSentinelConstant(LIRKind.value(AMD64Kind.QWORD), JavaKind.Long), HotSpotConstantLoadAction.MAKE_NOT_ENTRANT); + asm.movq(AMD64.rax, asm.getPlaceholder(-1)); + asm.testq(AMD64.rax, AMD64.rax); + AMD64Call.directConditionalJmp(crb, asm, getForeignCalls().lookupForeignCall(WRONG_METHOD_HANDLER), ConditionFlag.NotZero); + } + } + } + + /** + * Emits the code which starts at the verified entry point. + * + * @param installedCodeOwner see {@link Backend#emitCode} + */ + public void emitCodeBody(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, LIR lir) { + crb.emit(lir); + } + + /** + * @param installedCodeOwner see {@link Backend#emitCode} + */ + public void emitCodeSuffix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, FrameMap frameMap) { + HotSpotProviders providers = getProviders(); + HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; + if (!frameContext.isStub) { + HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls(); + crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY); + AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null); + crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); + AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null); + } else { + // No need to emit the stubs for entries back into the method since + // it has no calls that can cause such "return" entries + + if (frameContext.omitFrame) { + // Cannot access slots in caller's frame if my frame is omitted + assert !frameMap.accessesCallerFrame(); + } + } + } + + @Override + public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) { + RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; + return new AMD64HotSpotRegisterAllocationConfig(registerConfigNonNull); + } + + @Override + public Set translateToCallerRegisters(Set calleeRegisters) { + return calleeRegisters; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java 2016-12-07 13:49:31.903552305 -0800 @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2012, 2016, 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.amd64; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs; +import static jdk.vm.ci.common.InitTimer.timer; + +import java.util.ArrayList; +import java.util.List; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotBackendFactory; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl; +import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegisters; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider; +import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider; +import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.spi.NodeCostProvider; +import org.graalvm.compiler.nodes.spi.Replacements; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.replacements.amd64.AMD64GraphBuilderPlugins; +import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider; +import org.graalvm.compiler.serviceprovider.ServiceProvider; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.common.InitTimer; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.runtime.JVMCIBackend; + +@ServiceProvider(HotSpotBackendFactory.class) +public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory { + + @Override + public String getName() { + return "core"; + } + + @Override + public Class getArchitecture() { + return AMD64.class; + } + + @Override + @SuppressWarnings("try") + public HotSpotBackend createBackend(HotSpotGraalRuntimeProvider graalRuntime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotBackend host) { + assert host == null; + + JVMCIBackend jvmci = jvmciRuntime.getHostJVMCIBackend(); + GraalHotSpotVMConfig config = graalRuntime.getVMConfig(); + HotSpotProviders providers; + HotSpotRegistersProvider registers; + HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmci.getCodeCache(); + TargetDescription target = codeCache.getTarget(); + HotSpotHostForeignCallsProvider foreignCalls; + Value[] nativeABICallerSaveRegisters; + HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) jvmci.getMetaAccess(); + HotSpotConstantReflectionProvider constantReflection = (HotSpotConstantReflectionProvider) jvmci.getConstantReflection(); + ConstantFieldProvider constantFieldProvider = new HotSpotGraalConstantFieldProvider(config, metaAccess); + HotSpotLoweringProvider lowerer; + HotSpotSnippetReflectionProvider snippetReflection; + HotSpotReplacementsImpl replacements; + HotSpotSuitesProvider suites; + HotSpotWordTypes wordTypes; + Plugins plugins; + NodeCostProvider nodeCostProvider; + BytecodeProvider bytecodeProvider; + try (InitTimer t = timer("create providers")) { + try (InitTimer rt = timer("create HotSpotRegisters provider")) { + registers = createRegisters(); + } + try (InitTimer rt = timer("create NativeABICallerSaveRegisters")) { + nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig()); + } + try (InitTimer rt = timer("create WordTypes")) { + wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind); + } + try (InitTimer rt = timer("create ForeignCalls provider")) { + foreignCalls = createForeignCalls(jvmciRuntime, graalRuntime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters); + } + try (InitTimer rt = timer("create Lowerer provider")) { + lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, target); + } + try (InitTimer rt = timer("create NodeCost provider")) { + nodeCostProvider = createNodeCostProvider(target); + } + HotSpotStampProvider stampProvider = new HotSpotStampProvider(); + Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, nodeCostProvider); + + try (InitTimer rt = timer("create SnippetReflection provider")) { + snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes); + } + try (InitTimer rt = timer("create Bytecode provider")) { + bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection); + } + try (InitTimer rt = timer("create Replacements provider")) { + replacements = createReplacements(p, snippetReflection, bytecodeProvider); + } + try (InitTimer rt = timer("create GraphBuilderPhase plugins")) { + plugins = createGraphBuilderPlugins(config, target, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider); + replacements.setGraphBuilderPlugins(plugins); + } + try (InitTimer rt = timer("create Suites provider")) { + suites = createSuites(config, graalRuntime, compilerConfiguration, plugins, registers, replacements); + } + providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, nodeCostProvider, suites, registers, + snippetReflection, wordTypes, + plugins); + } + try (InitTimer rt = timer("instantiate backend")) { + return createBackend(config, graalRuntime, providers); + } + } + + protected Plugins createGraphBuilderPlugins(GraalHotSpotVMConfig config, TargetDescription target, HotSpotConstantReflectionProvider constantReflection, + HotSpotHostForeignCallsProvider foreignCalls, + HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, + HotSpotStampProvider stampProvider) { + Plugins plugins = HotSpotGraphBuilderPlugins.create(config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements); + AMD64GraphBuilderPlugins.register(plugins, replacements.getReplacementBytecodeProvider(), (AMD64) target.arch, GraalArithmeticStubs.getValue()); + return plugins; + } + + protected AMD64HotSpotBackend createBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { + return new AMD64HotSpotBackend(config, runtime, providers); + } + + protected HotSpotRegistersProvider createRegisters() { + return new HotSpotRegisters(AMD64.r15, AMD64.r12, AMD64.rsp); + } + + protected HotSpotReplacementsImpl createReplacements(Providers p, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) { + return new HotSpotReplacementsImpl(p, snippetReflection, bytecodeProvider, p.getCodeCache().getTarget()); + } + + protected AMD64HotSpotForeignCallsProvider createForeignCalls(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, + HotSpotCodeCacheProvider codeCache, WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) { + return new AMD64HotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters); + } + + /** + * @param replacements + */ + protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins, + HotSpotRegistersProvider registers, Replacements replacements) { + return new HotSpotSuitesProvider(new AMD64HotSpotSuitesProvider(compilerConfiguration, plugins), config, runtime, new AMD64HotSpotAddressLowering(config, registers.getHeapBaseRegister())); + } + + protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) { + return new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes); + } + + protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, + HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, TargetDescription target) { + return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target); + } + + protected HotSpotNodeCostProvider createNodeCostProvider(TargetDescription target) { + return new AMD64HotSpotNodeCostProvider(target); + } + + protected Value[] createNativeABICallerSaveRegisters(GraalHotSpotVMConfig config, RegisterConfig regConfig) { + List callerSave = new ArrayList<>(regConfig.getAllocatableRegisters().asList()); + if (config.windowsOs) { + // http://msdn.microsoft.com/en-us/library/9z1stfyw.aspx + callerSave.remove(AMD64.rdi); + callerSave.remove(AMD64.rsi); + callerSave.remove(AMD64.rbx); + callerSave.remove(AMD64.rbp); + callerSave.remove(AMD64.rsp); + callerSave.remove(AMD64.r12); + callerSave.remove(AMD64.r13); + callerSave.remove(AMD64.r14); + callerSave.remove(AMD64.r15); + callerSave.remove(AMD64.xmm6); + callerSave.remove(AMD64.xmm7); + callerSave.remove(AMD64.xmm8); + callerSave.remove(AMD64.xmm9); + callerSave.remove(AMD64.xmm10); + callerSave.remove(AMD64.xmm11); + callerSave.remove(AMD64.xmm12); + callerSave.remove(AMD64.xmm13); + callerSave.remove(AMD64.xmm14); + callerSave.remove(AMD64.xmm15); + } else { + /* + * System V Application Binary Interface, AMD64 Architecture Processor Supplement + * + * Draft Version 0.96 + * + * http://www.uclibc.org/docs/psABI-x86_64.pdf + * + * 3.2.1 + * + * ... + * + * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12 + * through %r15 "belong" to the calling function and the called function is required to + * preserve their values. In other words, a called function must preserve these + * registers' values for its caller. Remaining registers "belong" to the called + * function. If a calling function wants to preserve such a register value across a + * function call, it must save the value in its local stack frame. + */ + callerSave.remove(AMD64.rbp); + callerSave.remove(AMD64.rbx); + callerSave.remove(AMD64.r12); + callerSave.remove(AMD64.r13); + callerSave.remove(AMD64.r14); + callerSave.remove(AMD64.r15); + } + Value[] nativeABICallerSaveRegisters = new Value[callerSave.size()]; + for (int i = 0; i < callerSave.size(); i++) { + nativeABICallerSaveRegisters[i] = callerSave.get(i).asValue(); + } + return nativeABICallerSaveRegisters; + } + + @Override + public String toString() { + return "AMD64"; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java 2016-12-07 13:49:32.167563909 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, 2016, 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.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; + +@Opcode("CRUNTIME_CALL_EPILOGUE") +final class AMD64HotSpotCRuntimeCallEpilogueOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotCRuntimeCallEpilogueOp.class); + + private final int threadLastJavaSpOffset; + private final int threadLastJavaFpOffset; + private final int threadLastJavaPcOffset; + private final Register thread; + + AMD64HotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaFpOffset, int threadLastJavaPcOffset, Register thread) { + super(TYPE); + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.threadLastJavaFpOffset = threadLastJavaFpOffset; + this.threadLastJavaPcOffset = threadLastJavaPcOffset; + this.thread = thread; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + // reset last Java frame: + masm.movslq(new AMD64Address(thread, threadLastJavaSpOffset), 0); + masm.movslq(new AMD64Address(thread, threadLastJavaFpOffset), 0); + masm.movslq(new AMD64Address(thread, threadLastJavaPcOffset), 0); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java 2016-12-07 13:49:32.432575558 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012, 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.amd64; + +import static jdk.vm.ci.amd64.AMD64.rsp; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; + +@Opcode +final class AMD64HotSpotCRuntimeCallPrologueOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotCRuntimeCallPrologueOp.class); + + private final int threadLastJavaSpOffset; + private final Register thread; + + AMD64HotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, Register thread) { + super(TYPE); + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.thread = thread; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + // save last Java frame + masm.movq(new AMD64Address(thread, threadLastJavaSpOffset), rsp); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotConstantRetrievalOp.java 2016-12-07 13:49:32.697587207 -0800 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015, 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.amd64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import java.util.ArrayList; +import java.util.EnumSet; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.LIRValueUtil; +import org.graalvm.compiler.lir.ValueProcedure; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +public final class AMD64HotSpotConstantRetrievalOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotConstantRetrievalOp.class); + + @Def protected AllocatableValue result; + protected final Constant[] constants; + @Alive protected AllocatableValue[] constantDescriptions; + @Temp protected AllocatableValue[] gotSlotOffsetParameters; + @Temp protected AllocatableValue[] descriptionParameters; + @Temp protected Value[] callTemps; + @State protected LIRFrameState frameState; + private final ForeignCallLinkage callLinkage; + private final Object[] notes; + + private class CollectTemporaries implements ValueProcedure { + ArrayList values = new ArrayList<>(); + + CollectTemporaries() { + forEachTemp(this); + } + + public Value[] asArray() { + Value[] copy = new Value[values.size()]; + return values.toArray(copy); + } + + @Override + public Value doValue(Value value, OperandMode mode, EnumSet flags) { + values.add(value); + return value; + } + } + + public AMD64HotSpotConstantRetrievalOp(Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState, ForeignCallLinkage callLinkage, Object[] notes) { + super(TYPE); + this.constantDescriptions = constantDescriptions; + this.constants = constants; + this.frameState = frameState; + this.notes = notes; + assert constants.length == notes.length; + + // call arguments + CallingConvention callingConvention = callLinkage.getOutgoingCallingConvention(); + this.gotSlotOffsetParameters = new AllocatableValue[constants.length]; + int argIndex = 0; + for (int i = 0; i < constants.length; i++, argIndex++) { + this.gotSlotOffsetParameters[i] = callingConvention.getArgument(argIndex); + } + this.descriptionParameters = new AllocatableValue[constantDescriptions.length]; + for (int i = 0; i < constantDescriptions.length; i++, argIndex++) { + this.descriptionParameters[i] = callingConvention.getArgument(argIndex); + } + this.result = callingConvention.getReturn(); + + this.callLinkage = callLinkage; + + // compute registers that are killed by the stub, but are not used as other temps. + this.callTemps = new Value[0]; + this.callTemps = LIRValueUtil.subtractRegisters(callLinkage.getTemporaries(), new CollectTemporaries().asArray()); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + // metadata_adr + for (int i = 0; i < constants.length; i++) { + crb.recordInlineDataInCodeWithNote(constants[i], notes[i]); + masm.leaq(asRegister(gotSlotOffsetParameters[i]), masm.getPlaceholder(-1)); + } + + for (int i = 0; i < constantDescriptions.length; i++) { + masm.movq(asRegister(descriptionParameters[i]), asRegister(constantDescriptions[i])); + } + + final int before = masm.position(); + masm.call(); + final int after = masm.position(); + crb.recordDirectCall(before, after, callLinkage, frameState); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCounterOp.java 2016-12-07 13:49:32.962598855 -0800 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015, 2015, 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.amd64; + +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static jdk.vm.ci.amd64.AMD64.rax; +import static jdk.vm.ci.amd64.AMD64.rbx; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.HotSpotCounterOp; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; + +@Opcode("BenchMarkCounter") +public class AMD64HotSpotCounterOp extends HotSpotCounterOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotCounterOp.class); + + @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private AllocatableValue backupSlot; + + public AMD64HotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config, AllocatableValue backupSlot) { + super(TYPE, name, group, increment, registers, config); + this.backupSlot = backupSlot; + } + + public AMD64HotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config, AllocatableValue backupSlot) { + super(TYPE, names, groups, increments, registers, config); + this.backupSlot = backupSlot; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + AMD64MacroAssembler masm = (AMD64MacroAssembler) crb.asm; + TargetDescription target = crb.target; + + Register scratch; + // It can happen that the rax register is the increment register, in this case we do not + // want to spill it to the stack. + if (!contains(increments, rax)) { + scratch = rax; + } else if (!contains(increments, rbx)) { + scratch = rbx; + } else { + // In this case rax and rbx are used as increment. Either we implement a third register + // or we implement a spillover the value from rax to rbx or vice versa during + // emitIncrement(). + throw GraalError.unimplemented("RAX and RBX are increment registers at the same time, spilling over the scratch register is not supported right now"); + } + + // address for counters array + AMD64Address countersArrayAddr = new AMD64Address(thread, config.jvmciCountersThreadOffset); + Register countersArrayReg = scratch; + + // backup scratch register + masm.movq((AMD64Address) crb.asAddress(backupSlot), scratch); + + // load counters array + masm.movptr(countersArrayReg, countersArrayAddr); + CounterProcedure emitProcedure = (counterIndex, increment, displacement) -> emitIncrement(masm, countersArrayReg, increment, displacement); + forEachCounter(emitProcedure, target); + + // restore scratch register + masm.movq(scratch, (AMD64Address) crb.asAddress(backupSlot)); + } + + /** + * Tests if the array contains the register. + */ + private static boolean contains(Value[] increments, Register register) { + for (Value increment : increments) { + if (isRegister(increment) && asRegister(increment).equals(register)) { + return true; + } + } + return false; + } + + private static void emitIncrement(AMD64MacroAssembler masm, Register countersArrayReg, Value incrementValue, int displacement) { + // address for counter value + AMD64Address counterAddr = new AMD64Address(countersArrayReg, displacement); + // increment counter (in memory) + if (isJavaConstant(incrementValue)) { + int increment = asInt(asJavaConstant(incrementValue)); + masm.incrementq(counterAddr, increment); + } else { + masm.addq(counterAddr, asRegister(incrementValue)); + } + + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java 2016-12-07 13:49:33.227610504 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 2014, 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.amd64; + +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64Call; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +/** + * Removes the current frame and tail calls the uncommon trap routine. + */ +@Opcode("DEOPT_CALLER") +final class AMD64HotSpotDeoptimizeCallerOp extends AMD64HotSpotEpilogueBlockEndOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotDeoptimizeCallerOp.class); + + protected AMD64HotSpotDeoptimizeCallerOp() { + super(TYPE); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + leaveFrameAndRestoreRbp(crb, masm); + AMD64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDirectStaticCallOp.java 2016-12-07 13:49:33.493622196 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012, 2015, 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.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64Call.DirectCallOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * A direct call that complies with the conventions for such calls in HotSpot. It doesn't use an + * inline cache so it's just a patchable call site. + */ +@Opcode("CALL_DIRECT") +final class AMD64HotSpotDirectStaticCallOp extends DirectCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotDirectStaticCallOp.class); + + private final InvokeKind invokeKind; + private final GraalHotSpotVMConfig config; + + AMD64HotSpotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) { + super(TYPE, target, result, parameters, temps, state); + assert invokeKind.isDirect(); + this.invokeKind = invokeKind; + this.config = config; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL); + super.emitCode(crb, masm); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java 2016-12-07 13:49:33.758633845 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2013, 2015, 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.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.amd64.AMD64.rax; +import static jdk.vm.ci.amd64.AMD64.rbp; +import static jdk.vm.ci.amd64.AMD64.rip; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.framemap.FrameMap; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.RegisterSaveLayout; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaKind; + +/** + * Emits code that enters a stack frame which is tailored to call the C++ method + * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}. + */ +@Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME") +final class AMD64HotSpotEnterUnpackFramesStackFrameOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotEnterUnpackFramesStackFrameOp.class); + + private final Register threadRegister; + private final int threadLastJavaSpOffset; + private final int threadLastJavaPcOffset; + private final int threadLastJavaFpOffset; + @Alive(REG) AllocatableValue framePc; + @Alive(REG) AllocatableValue senderSp; + @Alive(REG) AllocatableValue senderFp; + + private final SaveRegistersOp saveRegisterOp; + + AMD64HotSpotEnterUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc, + AllocatableValue senderSp, AllocatableValue senderFp, SaveRegistersOp saveRegisterOp) { + super(TYPE); + this.threadRegister = threadRegister; + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.threadLastJavaPcOffset = threadLastJavaPcOffset; + this.threadLastJavaFpOffset = threadLastJavaFpOffset; + this.framePc = framePc; + this.senderSp = senderSp; + this.senderFp = senderFp; + this.saveRegisterOp = saveRegisterOp; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + FrameMap frameMap = crb.frameMap; + RegisterConfig registerConfig = frameMap.getRegisterConfig(); + RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap); + Register stackPointerRegister = registerConfig.getFrameRegister(); + final int totalFrameSize = frameMap.totalFrameSize(); + + // Push return address. + masm.push(asRegister(framePc)); + + // Push base pointer. + masm.push(asRegister(senderFp)); + masm.movq(rbp, stackPointerRegister); + + /* + * Allocate a full sized frame. Since return address and base pointer are already in place + * (see above) we allocate two words less. + */ + masm.decrementq(stackPointerRegister, totalFrameSize - 2 * crb.target.wordSize); + + // Save return registers after moving the frame. + final int stackSlotSize = frameMap.getTarget().wordSize; + Register integerResultRegister = registerConfig.getReturnRegister(JavaKind.Long); + masm.movptr(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize), integerResultRegister); + + Register floatResultRegister = registerConfig.getReturnRegister(JavaKind.Double); + masm.movdbl(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize), floatResultRegister); + + // Set up last Java values. + masm.movq(new AMD64Address(threadRegister, threadLastJavaSpOffset), stackPointerRegister); + + /* + * Save the PC since it cannot easily be retrieved using the last Java SP after we aligned + * SP. Don't need the precise return PC here, just precise enough to point into this code + * blob. + */ + masm.leaq(rax, new AMD64Address(rip, 0)); + masm.movq(new AMD64Address(threadRegister, threadLastJavaPcOffset), rax); + + // Use BP because the frames look interpreted now. + masm.movq(new AMD64Address(threadRegister, threadLastJavaFpOffset), rbp); + + // Align the stack for the following unpackFrames call. + masm.andq(stackPointerRegister, -(crb.target.stackAlignment)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueBlockEndOp.java 2016-12-07 13:49:34.024645538 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012, 2014, 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.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.amd64.AMD64BlockEndOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.meta.AllocatableValue; + +/** + * @see AMD64HotSpotEpilogueOp + */ +abstract class AMD64HotSpotEpilogueBlockEndOp extends AMD64BlockEndOp implements AMD64HotSpotRestoreRbpOp { + + protected AMD64HotSpotEpilogueBlockEndOp(LIRInstructionClass c) { + super(c); + } + + @Use({REG, STACK}) protected AllocatableValue savedRbp = PLACEHOLDER; + + protected void leaveFrameAndRestoreRbp(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64HotSpotEpilogueOp.leaveFrameAndRestoreRbp(savedRbp, crb, masm); + } + + @Override + public void setSavedRbp(AllocatableValue value) { + savedRbp = value; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueOp.java 2016-12-07 13:49:34.289657186 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012, 2014, 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.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.amd64.AMD64.rbp; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Superclass for operations that use the value of RBP saved in a method's prologue. + */ +abstract class AMD64HotSpotEpilogueOp extends AMD64LIRInstruction implements AMD64HotSpotRestoreRbpOp { + + protected AMD64HotSpotEpilogueOp(LIRInstructionClass c) { + super(c); + } + + @Use({REG, STACK}) private AllocatableValue savedRbp = PLACEHOLDER; + + protected void leaveFrameAndRestoreRbp(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + leaveFrameAndRestoreRbp(savedRbp, crb, masm); + } + + static void leaveFrameAndRestoreRbp(AllocatableValue savedRbp, CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isStackSlot(savedRbp)) { + // Restoring RBP from the stack must be done before the frame is removed + masm.movq(rbp, (AMD64Address) crb.asAddress(savedRbp)); + } else { + Register framePointer = asRegister(savedRbp); + if (!framePointer.equals(rbp)) { + masm.movq(rbp, framePointer); + } + } + crb.frameContext.leave(crb); + } + + @Override + public void setSavedRbp(AllocatableValue value) { + savedRbp = value; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java 2016-12-07 13:49:34.555668879 -0800 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2013, 2016, 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.amd64; + +import static org.graalvm.compiler.core.common.LocationIdentity.any; +import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER; +import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER; +import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NOFP; +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPTIMIZATION_HANDLER; +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; +import static org.graalvm.compiler.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32; +import static jdk.vm.ci.amd64.AMD64.rax; +import static jdk.vm.ci.amd64.AMD64.rdx; +import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall; +import static jdk.vm.ci.meta.Value.ILLEGAL; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +public class AMD64HotSpotForeignCallsProvider extends HotSpotHostForeignCallsProvider { + + public static final ForeignCallDescriptor ARITHMETIC_SIN_STUB = new ForeignCallDescriptor("arithmeticSinStub", double.class, double.class); + public static final ForeignCallDescriptor ARITHMETIC_COS_STUB = new ForeignCallDescriptor("arithmeticCosStub", double.class, double.class); + public static final ForeignCallDescriptor ARITHMETIC_TAN_STUB = new ForeignCallDescriptor("arithmeticTanStub", double.class, double.class); + public static final ForeignCallDescriptor ARITHMETIC_EXP_STUB = new ForeignCallDescriptor("arithmeticExpStub", double.class, double.class); + public static final ForeignCallDescriptor ARITHMETIC_POW_STUB = new ForeignCallDescriptor("arithmeticPowStub", double.class, double.class, double.class); + public static final ForeignCallDescriptor ARITHMETIC_LOG_STUB = new ForeignCallDescriptor("arithmeticLogStub", double.class, double.class); + public static final ForeignCallDescriptor ARITHMETIC_LOG10_STUB = new ForeignCallDescriptor("arithmeticLog10Stub", double.class, double.class); + + private final Value[] nativeABICallerSaveRegisters; + + public AMD64HotSpotForeignCallsProvider(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache, + WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) { + super(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes); + this.nativeABICallerSaveRegisters = nativeABICallerSaveRegisters; + } + + @Override + public void initialize(HotSpotProviders providers) { + GraalHotSpotVMConfig config = runtime.getVMConfig(); + TargetDescription target = providers.getCodeCache().getTarget(); + PlatformKind word = target.arch.getWordKind(); + + // The calling convention for the exception handler stub is (only?) defined in + // TemplateInterpreterGenerator::generate_throw_exception() + // in templateInterpreter_x86_64.cpp around line 1923 + RegisterValue exception = rax.asValue(LIRKind.reference(word)); + RegisterValue exceptionPc = rdx.asValue(LIRKind.value(word)); + CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc); + register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, any())); + register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, any())); + + if (PreferGraalStubs.getValue()) { + link(new AMD64DeoptimizationStub(providers, target, config, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS))); + link(new AMD64UncommonTrapStub(providers, target, config, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS))); + } + link(new AMD64MathStub(ARITHMETIC_LOG_STUB, providers, registerStubCall(ARITHMETIC_LOG_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS))); + link(new AMD64MathStub(ARITHMETIC_LOG10_STUB, providers, registerStubCall(ARITHMETIC_LOG10_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS))); + link(new AMD64MathStub(ARITHMETIC_SIN_STUB, providers, registerStubCall(ARITHMETIC_SIN_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS))); + link(new AMD64MathStub(ARITHMETIC_COS_STUB, providers, registerStubCall(ARITHMETIC_COS_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS))); + link(new AMD64MathStub(ARITHMETIC_TAN_STUB, providers, registerStubCall(ARITHMETIC_TAN_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS))); + link(new AMD64MathStub(ARITHMETIC_EXP_STUB, providers, registerStubCall(ARITHMETIC_EXP_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS))); + link(new AMD64MathStub(ARITHMETIC_POW_STUB, providers, registerStubCall(ARITHMETIC_POW_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS))); + + if (config.useCRC32Intrinsics) { + // This stub does callee saving + registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any()); + } + + super.initialize(providers); + } + + @Override + public Value[] getNativeABICallerSaveRegisters() { + return nativeABICallerSaveRegisters; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java 2016-12-07 13:49:34.820680527 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012, 2014, 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.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.amd64.AMD64.rbp; +import static jdk.vm.ci.amd64.AMD64.rsp; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Sets up the arguments for an exception handler in the callers frame, removes the current frame + * and jumps to the handler. + */ +@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER") +final class AMD64HotSpotJumpToExceptionHandlerInCallerOp extends AMD64HotSpotEpilogueBlockEndOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotJumpToExceptionHandlerInCallerOp.class); + + @Use(REG) AllocatableValue handlerInCallerPc; + @Use(REG) AllocatableValue exception; + @Use(REG) AllocatableValue exceptionPc; + private final Register thread; + private final int isMethodHandleReturnOffset; + + AMD64HotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc, int isMethodHandleReturnOffset, Register thread) { + super(TYPE); + this.handlerInCallerPc = handlerInCallerPc; + this.exception = exception; + this.exceptionPc = exceptionPc; + this.isMethodHandleReturnOffset = isMethodHandleReturnOffset; + this.thread = thread; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + leaveFrameAndRestoreRbp(crb, masm); + + // Discard the return address, thus completing restoration of caller frame + masm.incrementq(rsp, 8); + + if (System.getProperty("java.specification.version").compareTo("1.8") < 0) { + // Restore rsp from rbp if the exception PC is a method handle call site. + AMD64Address dst = new AMD64Address(thread, isMethodHandleReturnOffset); + masm.cmpl(dst, 0); + masm.cmovq(ConditionFlag.NotEqual, rsp, rbp); + } + + masm.jmp(asRegister(handlerInCallerPc)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java 2016-12-07 13:49:35.085692176 -0800 @@ -0,0 +1,738 @@ +/* + * Copyright (c) 2012, 2016, 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.amd64; + +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL; +import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL; +import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS; +import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL; +import static org.graalvm.compiler.hotspot.HotSpotBackend.FETCH_UNROLL_INFO; +import static org.graalvm.compiler.hotspot.HotSpotBackend.UNCOMMON_TRAP; +import static jdk.vm.ci.amd64.AMD64.rbp; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; +import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator; +import org.graalvm.compiler.core.amd64.AMD64LIRGenerator; +import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.CompressEncoding; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.HotSpotLockStack; +import org.graalvm.compiler.hotspot.debug.BenchmarkCounters; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.StandardOp.NoOp; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.amd64.AMD64AddressValue; +import org.graalvm.compiler.lir.amd64.AMD64CCall; +import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp; +import org.graalvm.compiler.lir.amd64.AMD64FrameMapBuilder; +import org.graalvm.compiler.lir.amd64.AMD64Move; +import org.graalvm.compiler.lir.amd64.AMD64Move.MoveFromRegOp; +import org.graalvm.compiler.lir.amd64.AMD64PrefetchOp; +import org.graalvm.compiler.lir.amd64.AMD64ReadTimestampCounter; +import org.graalvm.compiler.lir.amd64.AMD64RestoreRegistersOp; +import org.graalvm.compiler.lir.amd64.AMD64SaveRegistersOp; +import org.graalvm.compiler.lir.amd64.AMD64VZeroUpper; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.PrimitiveConstant; +import jdk.vm.ci.meta.Value; + +/** + * LIR generator specialized for AMD64 HotSpot. + */ +public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator { + + final GraalHotSpotVMConfig config; + private HotSpotDebugInfoBuilder debugInfoBuilder; + + protected AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) { + this(providers, config, lirGenRes, new BackupSlotProvider(lirGenRes.getFrameMapBuilder())); + } + + private AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, BackupSlotProvider backupSlotProvider) { + this(new AMD64HotSpotLIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes); + } + + protected AMD64HotSpotLIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config, + LIRGenerationResult lirGenRes) { + super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes); + assert config.basicLockSize == 8; + this.config = config; + } + + @Override + public HotSpotProviders getProviders() { + return (HotSpotProviders) super.getProviders(); + } + + /** + * Utility for emitting the instruction to save RBP. + */ + class SaveRbp { + + final NoOp placeholder; + + /** + * The slot reserved for saving RBP. + */ + final StackSlot reservedSlot; + + SaveRbp(NoOp placeholder) { + this.placeholder = placeholder; + AMD64FrameMapBuilder frameMapBuilder = (AMD64FrameMapBuilder) getResult().getFrameMapBuilder(); + this.reservedSlot = frameMapBuilder.allocateRBPSpillSlot(); + } + + /** + * Replaces this operation with the appropriate move for saving rbp. + * + * @param useStack specifies if rbp must be saved to the stack + */ + public AllocatableValue finalize(boolean useStack) { + AllocatableValue dst; + if (useStack) { + dst = reservedSlot; + } else { + ((AMD64FrameMapBuilder) getResult().getFrameMapBuilder()).freeRBPSpillSlot(); + dst = newVariable(LIRKind.value(AMD64Kind.QWORD)); + } + + placeholder.replace(getResult().getLIR(), new MoveFromRegOp(AMD64Kind.QWORD, dst, rbp.asValue(LIRKind.value(AMD64Kind.QWORD)))); + return dst; + } + } + + private SaveRbp saveRbp; + + protected void emitSaveRbp() { + NoOp placeholder = new NoOp(getCurrentBlock(), getResult().getLIR().getLIRforBlock(getCurrentBlock()).size()); + append(placeholder); + saveRbp = new SaveRbp(placeholder); + } + + protected SaveRbp getSaveRbp() { + return saveRbp; + } + + /** + * Helper instruction to reserve a stack slot for the whole method. Note that the actual users + * of the stack slot might be inserted after stack slot allocation. This dummy instruction + * ensures that the stack slot is alive and gets a real stack slot assigned. + */ + private static final class RescueSlotDummyOp extends LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(RescueSlotDummyOp.class); + + @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private AllocatableValue slot; + + RescueSlotDummyOp(FrameMapBuilder frameMapBuilder, LIRKind kind) { + super(TYPE); + slot = frameMapBuilder.allocateSpillSlot(kind); + } + + public AllocatableValue getSlot() { + return slot; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + } + } + + private RescueSlotDummyOp rescueSlotOp; + + private AllocatableValue getOrInitRescueSlot() { + RescueSlotDummyOp op = getOrInitRescueSlotOp(); + return op.getSlot(); + } + + private RescueSlotDummyOp getOrInitRescueSlotOp() { + if (rescueSlotOp == null) { + // create dummy instruction to keep the rescue slot alive + rescueSlotOp = new RescueSlotDummyOp(getResult().getFrameMapBuilder(), getLIRKindTool().getWordKind()); + } + return rescueSlotOp; + } + + /** + * List of epilogue operations that need to restore RBP. + */ + List epilogueOps = new ArrayList<>(2); + + @Override + public I append(I op) { + I ret = super.append(op); + if (op instanceof AMD64HotSpotRestoreRbpOp) { + epilogueOps.add((AMD64HotSpotRestoreRbpOp) op); + } + return ret; + } + + @Override + public VirtualStackSlot getLockSlot(int lockDepth) { + return getLockStack().makeLockSlot(lockDepth); + } + + private HotSpotLockStack getLockStack() { + assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null; + return debugInfoBuilder.lockStack(); + } + + private Register findPollOnReturnScratchRegister() { + RegisterConfig regConfig = getProviders().getCodeCache().getRegisterConfig(); + for (Register r : regConfig.getAllocatableRegisters()) { + if (!r.equals(regConfig.getReturnRegister(JavaKind.Long)) && !r.equals(AMD64.rbp)) { + return r; + } + } + throw GraalError.shouldNotReachHere(); + } + + private Register pollOnReturnScratchRegister; + + @Override + public void emitReturn(JavaKind kind, Value input) { + AllocatableValue operand = Value.ILLEGAL; + if (input != null) { + operand = resultOperandFor(kind, input.getValueKind()); + emitMove(operand, input); + } + if (pollOnReturnScratchRegister == null) { + pollOnReturnScratchRegister = findPollOnReturnScratchRegister(); + } + append(new AMD64HotSpotReturnOp(operand, getStub() != null, pollOnReturnScratchRegister, config)); + } + + @Override + public boolean needOnlyOopMaps() { + // Stubs only need oop maps + return getResult().getStub() != null; + } + + private LIRFrameState currentRuntimeCallInfo; + + @Override + protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + currentRuntimeCallInfo = info; + HotSpotForeignCallLinkage hsLinkage = (HotSpotForeignCallLinkage) linkage; + AMD64 arch = (AMD64) target().arch; + if (arch.getFeatures().contains(AMD64.CPUFeature.AVX) && hsLinkage.mayContainFP() && !hsLinkage.isCompiledStub()) { + /* + * If the target may contain FP ops, and it is not compiled by us, we may have an + * AVX-SSE transition. + * + * We exclude the argument registers from the zeroing LIR instruction since it violates + * the LIR semantics of @Temp that values must not be live. Note that the emitted + * machine instruction actually zeros _all_ XMM registers which is fine since we know + * that their upper half is not used. + */ + append(new AMD64VZeroUpper(arguments)); + } + super.emitForeignCallOp(linkage, result, arguments, temps, info); + } + + @Override + public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) { + append(new AMD64HotSpotLeaveCurrentStackFrameOp(saveRegisterOp)); + } + + @Override + public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) { + Variable frameSizeVariable = load(frameSize); + Variable initialInfoVariable = load(initialInfo); + append(new AMD64HotSpotLeaveDeoptimizedStackFrameOp(frameSizeVariable, initialInfoVariable)); + } + + @Override + public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) { + Register threadRegister = getProviders().getRegisters().getThreadRegister(); + Variable framePcVariable = load(framePc); + Variable senderSpVariable = load(senderSp); + Variable senderFpVariable = load(senderFp); + append(new AMD64HotSpotEnterUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), framePcVariable, + senderSpVariable, senderFpVariable, saveRegisterOp)); + } + + @Override + public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) { + Register threadRegister = getProviders().getRegisters().getThreadRegister(); + append(new AMD64HotSpotLeaveUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), saveRegisterOp)); + } + + /** + * @param savedRegisters the registers saved by this operation which may be subject to pruning + * @param savedRegisterLocations the slots to which the registers are saved + * @param supportsRemove determines if registers can be pruned + */ + protected AMD64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) { + AMD64SaveRegistersOp save = new AMD64SaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove); + append(save); + return save; + } + + /** + * Allocate a stack slot for saving a register. + */ + protected VirtualStackSlot allocateSaveRegisterLocation(Register register) { + PlatformKind kind = target().arch.getLargestStorableKind(register.getRegisterCategory()); + if (kind.getVectorLength() > 1) { + // we don't use vector registers, so there is no need to save them + kind = AMD64Kind.DOUBLE; + } + return getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind)); + } + + /** + * Adds a node to the graph that saves all allocatable registers to the stack. + * + * @param supportsRemove determines if registers can be pruned + * @return the register save node + */ + private AMD64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters, boolean supportsRemove) { + AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length]; + for (int i = 0; i < savedRegisters.length; i++) { + savedRegisterLocations[i] = allocateSaveRegisterLocation(savedRegisters[i]); + } + return emitSaveRegisters(savedRegisters, savedRegisterLocations, supportsRemove); + } + + @Override + public SaveRegistersOp emitSaveAllRegisters() { + // We are saving all registers. + // TODO Save upper half of YMM registers. + return emitSaveAllRegisters(target().arch.getAvailableValueRegisters().toArray(), false); + } + + protected void emitRestoreRegisters(AMD64SaveRegistersOp save) { + append(new AMD64RestoreRegistersOp(save.getSlots().clone(), save)); + } + + /** + * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not + * being generated. + */ + public Stub getStub() { + return getResult().getStub(); + } + + @Override + public HotSpotLIRGenerationResult getResult() { + return ((HotSpotLIRGenerationResult) super.getResult()); + } + + public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) { + this.debugInfoBuilder = debugInfoBuilder; + } + + @Override + public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) { + HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage; + boolean destroysRegisters = hotspotLinkage.destroysRegisters(); + + AMD64SaveRegistersOp save = null; + Stub stub = getStub(); + if (destroysRegisters) { + if (stub != null && stub.preservesRegisters()) { + Register[] savedRegisters = getResult().getFrameMapBuilder().getRegisterConfig().getAllocatableRegisters().toArray(); + save = emitSaveAllRegisters(savedRegisters, true); + } + } + + Variable result; + LIRFrameState debugInfo = null; + if (hotspotLinkage.needsDebugInfo()) { + debugInfo = state; + assert debugInfo != null || stub != null; + } + + if (hotspotLinkage.needsJavaFrameAnchor()) { + Register thread = getProviders().getRegisters().getThreadRegister(); + append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread)); + result = super.emitForeignCall(hotspotLinkage, debugInfo, args); + append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), config.threadLastJavaPcOffset(), thread)); + } else { + result = super.emitForeignCall(hotspotLinkage, debugInfo, args); + } + + if (destroysRegisters) { + if (stub != null) { + if (stub.preservesRegisters()) { + HotSpotLIRGenerationResult generationResult = getResult(); + assert !generationResult.getCalleeSaveInfo().containsKey(currentRuntimeCallInfo); + generationResult.getCalleeSaveInfo().put(currentRuntimeCallInfo, save); + emitRestoreRegisters(save); + } + } + } + + return result; + } + + @Override + public Value emitLoadObjectAddress(Constant constant) { + HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant; + HotSpotLIRKindTool kindTool = (HotSpotLIRKindTool) getLIRKindTool(); + LIRKind kind = objectConstant.isCompressed() ? kindTool.getNarrowOopKind() : kindTool.getObjectKind(); + Variable result = newVariable(kind); + append(new AMD64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE)); + return result; + } + + @Override + public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) { + HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant; + HotSpotLIRKindTool kindTool = (HotSpotLIRKindTool) getLIRKindTool(); + LIRKind kind = metaspaceConstant.isCompressed() ? kindTool.getNarrowPointerKind() : kindTool.getWordKind(); + Variable result = newVariable(kind); + append(new AMD64HotSpotLoadAddressOp(result, constant, action)); + return result; + } + + @Override + public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_STRING_BY_SYMBOL); + Constant[] constants = new Constant[]{constant}; + AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; + Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE}; + append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); + AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); + return emitMove(result); + } + + @Override + public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_KLASS_BY_SYMBOL); + Constant[] constants = new Constant[]{constant}; + AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; + Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE}; + append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); + AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); + return emitMove(result); + } + + @Override + public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS); + Constant[] constants = new Constant[]{method}; + AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)}; + Object[] notes = new Object[]{HotSpotConstantLoadAction.LOAD_COUNTERS}; + append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); + AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); + return emitMove(result); + + } + + @Override + public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(INITIALIZE_KLASS_BY_SYMBOL); + Constant[] constants = new Constant[]{constant}; + AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; + Object[] notes = new Object[]{HotSpotConstantLoadAction.INITIALIZE}; + append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); + AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); + return emitMove(result); + } + + @Override + public Value emitLoadConfigValue(int markId) { + // Globals are always full-pointer width. + Variable result = newVariable(LIRKind.value(target().arch.getWordKind())); + append(new AMD64HotSpotLoadConfigValueOp(markId, result)); + return result; + } + + @Override + public Value emitRandomSeed() { + AMD64ReadTimestampCounter timestamp = new AMD64ReadTimestampCounter(); + append(timestamp); + return emitMove(timestamp.getLowResult()); + } + + @Override + public Value emitUncommonTrapCall(Value trapRequest, Value mode, SaveRegistersOp saveRegisterOp) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP); + + Register thread = getProviders().getRegisters().getThreadRegister(); + append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread)); + Variable result = super.emitForeignCall(linkage, null, thread.asValue(LIRKind.value(AMD64Kind.QWORD)), trapRequest, mode); + append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), config.threadLastJavaPcOffset(), thread)); + + Map calleeSaveInfo = getResult().getCalleeSaveInfo(); + assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); + calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp); + + return result; + } + + @Override + public Value emitDeoptimizationFetchUnrollInfoCall(Value mode, SaveRegistersOp saveRegisterOp) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(FETCH_UNROLL_INFO); + + Register thread = getProviders().getRegisters().getThreadRegister(); + append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread)); + Variable result = super.emitForeignCall(linkage, null, thread.asValue(LIRKind.value(AMD64Kind.QWORD)), mode); + append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), config.threadLastJavaPcOffset(), thread)); + + Map calleeSaveInfo = getResult().getCalleeSaveInfo(); + assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); + calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp); + + return result; + } + + @Override + public void emitTailcall(Value[] args, Value address) { + append(new AMD64TailcallOp(args, address)); + } + + @Override + public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments) { + Value[] argLocations = new Value[args.length]; + getResult().getFrameMapBuilder().callsMethod(nativeCallingConvention); + // TODO(mg): in case a native function uses floating point varargs, the ABI requires that + // RAX contains the length of the varargs + PrimitiveConstant intConst = JavaConstant.forInt(numberOfFloatingPointArguments); + AllocatableValue numberOfFloatingPointArgumentsRegister = AMD64.rax.asValue(LIRKind.value(AMD64Kind.DWORD)); + emitMoveConstant(numberOfFloatingPointArgumentsRegister, intConst); + for (int i = 0; i < args.length; i++) { + Value arg = args[i]; + AllocatableValue loc = nativeCallingConvention.getArgument(i); + emitMove(loc, arg); + argLocations[i] = loc; + } + Value ptr = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(address)); + append(new AMD64CCall(nativeCallingConvention.getReturn(), ptr, numberOfFloatingPointArgumentsRegister, argLocations)); + } + + @Override + public void emitUnwind(Value exception) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); + CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); + assert outgoingCc.getArgumentCount() == 2; + RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0); + emitMove(exceptionParameter, exception); + append(new AMD64HotSpotUnwindOp(exceptionParameter)); + } + + private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) { + moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset); + moveValueToThread(speculation, config.pendingFailedSpeculationOffset); + } + + private void moveValueToThread(Value v, int offset) { + LIRKind wordKind = LIRKind.value(target().arch.getWordKind()); + RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind); + AMD64AddressValue address = new AMD64AddressValue(wordKind, thread, offset); + arithmeticLIRGen.emitStore(v.getValueKind(), address, v, null); + } + + @Override + public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) { + moveDeoptValuesToThread(actionAndReason, speculation); + append(new AMD64DeoptimizeOp(state)); + } + + @Override + public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { + Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0)); + Value nullValue = emitConstant(LIRKind.reference(AMD64Kind.QWORD), JavaConstant.NULL_POINTER); + moveDeoptValuesToThread(actionAndReason, nullValue); + append(new AMD64HotSpotDeoptimizeCallerOp()); + } + + @Override + public void beforeRegisterAllocation() { + super.beforeRegisterAllocation(); + boolean hasDebugInfo = getResult().getLIR().hasDebugInfo(); + AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo); + if (hasDebugInfo) { + getResult().setDeoptimizationRescueSlot(((AMD64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot()); + } + + getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize()); + + for (AMD64HotSpotRestoreRbpOp op : epilogueOps) { + op.setSavedRbp(savedRbp); + } + if (BenchmarkCounters.enabled) { + // ensure that the rescue slot is available + LIRInstruction op = getOrInitRescueSlotOp(); + // insert dummy instruction into the start block + LIR lir = getResult().getLIR(); + List instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock()); + instructions.add(1, op); + Debug.dump(Debug.INFO_LOG_LEVEL, lir, "created rescue dummy op"); + } + } + + @Override + public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) { + Variable frameSizeVariable = load(frameSize); + Variable framePcVariable = load(framePc); + Variable senderSpVariable = load(senderSp); + Variable initialInfoVariable = load(initialInfo); + append(new AMD64HotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable, config)); + } + + @Override + public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) { + LIRKind inputKind = pointer.getValueKind(LIRKind.class); + assert inputKind.getPlatformKind() == AMD64Kind.QWORD; + if (inputKind.isReference(0)) { + // oop + Variable result = newVariable(LIRKind.reference(AMD64Kind.DWORD)); + append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); + return result; + } else { + // metaspace pointer + Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD)); + AllocatableValue base = Value.ILLEGAL; + if (encoding.base != 0 || GeneratePIC.getValue()) { + if (GeneratePIC.getValue()) { + Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD)); + AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config); + append(move); + base = baseAddress; + } else { + base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.base)); + } + } + append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); + return result; + } + } + + @Override + public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) { + LIRKind inputKind = pointer.getValueKind(LIRKind.class); + assert inputKind.getPlatformKind() == AMD64Kind.DWORD; + if (inputKind.isReference(0)) { + // oop + Variable result = newVariable(LIRKind.reference(AMD64Kind.QWORD)); + append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); + return result; + } else { + // metaspace pointer + Variable result = newVariable(LIRKind.value(AMD64Kind.QWORD)); + AllocatableValue base = Value.ILLEGAL; + if (encoding.base != 0 || GeneratePIC.getValue()) { + if (GeneratePIC.getValue()) { + Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD)); + AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config); + append(move); + base = baseAddress; + } else { + base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.base)); + } + } + append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); + return result; + } + } + + @Override + public void emitNullCheck(Value address, LIRFrameState state) { + if (address.getValueKind().getPlatformKind() == AMD64Kind.DWORD) { + CompressEncoding encoding = config.getOopEncoding(); + Value uncompressed; + if (encoding.shift <= 3) { + LIRKind wordKind = LIRKind.unknownReference(target().arch.getWordKind()); + uncompressed = new AMD64AddressValue(wordKind, getProviders().getRegisters().getHeapBaseRegister().asValue(wordKind), asAllocatable(address), Scale.fromInt(1 << encoding.shift), 0); + } else { + uncompressed = emitUncompress(address, encoding, false); + } + append(new AMD64Move.NullCheckOp(asAddressValue(uncompressed), state)); + } else { + super.emitNullCheck(address, state); + } + } + + @Override + public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) { + if (BenchmarkCounters.enabled) { + return new AMD64HotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config, getOrInitRescueSlot()); + } + throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!"); + } + + @Override + public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) { + if (BenchmarkCounters.enabled) { + return new AMD64HotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config, getOrInitRescueSlot()); + } + throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!"); + } + + @Override + public void emitPrefetchAllocate(Value address) { + append(new AMD64PrefetchOp(asAddressValue(address), config.allocatePrefetchInstr)); + } + + @Override + protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue temp) { + return new AMD64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, temp); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRKindTool.java 2016-12-07 13:49:35.352703913 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 2015, 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.amd64; + +import org.graalvm.compiler.core.amd64.AMD64LIRKindTool; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool; + +import jdk.vm.ci.amd64.AMD64Kind; + +public class AMD64HotSpotLIRKindTool extends AMD64LIRKindTool implements HotSpotLIRKindTool { + + @Override + public LIRKind getNarrowOopKind() { + return LIRKind.reference(AMD64Kind.DWORD); + } + + @Override + public LIRKind getNarrowPointerKind() { + return LIRKind.value(AMD64Kind.DWORD); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java 2016-12-07 13:49:35.617715561 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013, 2015, 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.amd64; + +import static jdk.vm.ci.amd64.AMD64.rdx; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.framemap.FrameMap; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.RegisterSaveLayout; +import jdk.vm.ci.meta.JavaKind; + +/** + * Pops the current frame off the stack including the return address and restores the return + * registers stored on the stack. + */ +@Opcode("LEAVE_CURRENT_STACK_FRAME") +final class AMD64HotSpotLeaveCurrentStackFrameOp extends AMD64HotSpotEpilogueOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotLeaveCurrentStackFrameOp.class); + + private final SaveRegistersOp saveRegisterOp; + + AMD64HotSpotLeaveCurrentStackFrameOp(SaveRegistersOp saveRegisterOp) { + super(TYPE); + this.saveRegisterOp = saveRegisterOp; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + FrameMap frameMap = crb.frameMap; + RegisterConfig registerConfig = frameMap.getRegisterConfig(); + RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap); + Register stackPointer = registerConfig.getFrameRegister(); + + // Restore integer result register. + final int stackSlotSize = frameMap.getTarget().wordSize; + Register integerResultRegister = registerConfig.getReturnRegister(JavaKind.Long); + masm.movptr(integerResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize)); + masm.movptr(rdx, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(rdx) * stackSlotSize)); + + // Restore float result register. + Register floatResultRegister = registerConfig.getReturnRegister(JavaKind.Double); + masm.movdbl(floatResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize)); + + /* + * All of the register save area will be popped of the stack. Only the return address + * remains. + */ + leaveFrameAndRestoreRbp(crb, masm); + + // Remove return address. + masm.addq(stackPointer, crb.target.arch.getReturnAddressSize()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java 2016-12-07 13:49:35.886727386 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2013, 2014, 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.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.amd64.AMD64.rbp; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Pops a deoptimized stack frame off the stack including the return address. + */ +@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME") +final class AMD64HotSpotLeaveDeoptimizedStackFrameOp extends AMD64HotSpotEpilogueOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotLeaveDeoptimizedStackFrameOp.class); + @Use(REG) AllocatableValue frameSize; + @Use(REG) AllocatableValue framePointer; + + AMD64HotSpotLeaveDeoptimizedStackFrameOp(AllocatableValue frameSize, AllocatableValue initialInfo) { + super(TYPE); + this.frameSize = frameSize; + this.framePointer = initialInfo; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Register stackPointer = crb.frameMap.getRegisterConfig().getFrameRegister(); + masm.addq(stackPointer, asRegister(frameSize)); + + /* + * Restore the frame pointer before stack bang because if a stack overflow is thrown it + * needs to be pushed (and preserved). + */ + masm.movq(rbp, asRegister(framePointer)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java 2016-12-07 13:49:36.150738990 -0800 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013, 2015, 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.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.framemap.FrameMap; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.RegisterSaveLayout; +import jdk.vm.ci.meta.JavaKind; + +/** + * Emits code that leaves a stack frame which is tailored to call the C++ method + * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}. + */ +@Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME") +final class AMD64HotSpotLeaveUnpackFramesStackFrameOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotLeaveUnpackFramesStackFrameOp.class); + + private final Register threadRegister; + private final int threadLastJavaSpOffset; + private final int threadLastJavaPcOffset; + private final int threadLastJavaFpOffset; + + private final SaveRegistersOp saveRegisterOp; + + AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, SaveRegistersOp saveRegisterOp) { + super(TYPE); + this.threadRegister = threadRegister; + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.threadLastJavaPcOffset = threadLastJavaPcOffset; + this.threadLastJavaFpOffset = threadLastJavaFpOffset; + this.saveRegisterOp = saveRegisterOp; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + FrameMap frameMap = crb.frameMap; + RegisterConfig registerConfig = frameMap.getRegisterConfig(); + RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap); + Register stackPointerRegister = registerConfig.getFrameRegister(); + + // Restore stack pointer. + masm.movq(stackPointerRegister, new AMD64Address(threadRegister, threadLastJavaSpOffset)); + + // Clear last Java frame values. + masm.movslq(new AMD64Address(threadRegister, threadLastJavaSpOffset), 0); + masm.movslq(new AMD64Address(threadRegister, threadLastJavaPcOffset), 0); + masm.movslq(new AMD64Address(threadRegister, threadLastJavaFpOffset), 0); + + // Restore return values. + final int stackSlotSize = frameMap.getTarget().wordSize; + Register integerResultRegister = registerConfig.getReturnRegister(JavaKind.Long); + masm.movptr(integerResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize)); + + Register floatResultRegister = registerConfig.getReturnRegister(JavaKind.Double); + masm.movdbl(floatResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoadAddressOp.java 2016-12-07 13:49:36.444751913 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, 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.amd64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +public final class AMD64HotSpotLoadAddressOp extends AMD64LIRInstruction { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotLoadAddressOp.class); + + @Def({OperandFlag.REG}) protected AllocatableValue result; + private final Constant constant; + private final Object note; + + public AMD64HotSpotLoadAddressOp(AllocatableValue result, Constant constant, Object note) { + super(TYPE); + this.result = result; + this.constant = constant; + this.note = note; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + crb.recordInlineDataInCodeWithNote(constant, note); + AMD64Kind kind = (AMD64Kind) result.getPlatformKind(); + switch (kind) { + case DWORD: + masm.movl(asRegister(result), masm.getPlaceholder(-1)); + break; + case QWORD: + masm.movq(asRegister(result), masm.getPlaceholder(-1)); + break; + default: + throw GraalError.shouldNotReachHere("unexpected kind: " + kind); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoadConfigValueOp.java 2016-12-07 13:49:36.710763606 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 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.amd64; + +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import jdk.vm.ci.meta.AllocatableValue; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +public final class AMD64HotSpotLoadConfigValueOp extends AMD64LIRInstruction { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotLoadConfigValueOp.class); + + @Def({OperandFlag.REG}) protected AllocatableValue result; + private final int markId; + + public AMD64HotSpotLoadConfigValueOp(int markId, AllocatableValue result) { + super(TYPE); + this.result = result; + this.markId = markId; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (GeneratePIC.getValue()) { + masm.movq(asRegister(result), masm.getPlaceholder(-1)); + } else { + throw GraalError.unimplemented(); + } + crb.recordMark(markId); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java 2016-12-07 13:49:36.975775255 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2013, 2016, 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.amd64; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_COS_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_EXP_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_LOG10_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_LOG_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_SIN_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_POW_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_TAN_STUB; + +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; +import org.graalvm.compiler.hotspot.replacements.profiling.ProbabilisticProfileSnippets; +import org.graalvm.compiler.nodes.calc.FloatConvertNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.amd64.AMD64ConvertSnippets; +import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation; +import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; + +public class AMD64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider { + + private AMD64ConvertSnippets.Templates convertSnippets; + private ProbabilisticProfileSnippets.Templates profileSnippets; + + public AMD64HotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, + HotSpotConstantReflectionProvider constantReflection, TargetDescription target) { + super(runtime, metaAccess, foreignCalls, registers, constantReflection, target); + } + + @Override + public void initialize(HotSpotProviders providers, GraalHotSpotVMConfig config) { + convertSnippets = new AMD64ConvertSnippets.Templates(providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget()); + profileSnippets = ProfileNode.Options.ProbabilisticProfiling.getValue() ? new ProbabilisticProfileSnippets.Templates(providers, providers.getCodeCache().getTarget()) : null; + super.initialize(providers, config); + } + + @Override + public void lower(Node n, LoweringTool tool) { + if (n instanceof FloatConvertNode) { + convertSnippets.lower((FloatConvertNode) n, tool); + } else if (profileSnippets != null && n instanceof ProfileNode) { + profileSnippets.lower((ProfileNode) n, tool); + } else { + super.lower(n, tool); + } + } + + @Override + protected ForeignCallDescriptor toForeignCall(UnaryOperation operation) { + if (GraalArithmeticStubs.getValue()) { + switch (operation) { + case LOG: + return ARITHMETIC_LOG_STUB; + case LOG10: + return ARITHMETIC_LOG10_STUB; + case SIN: + return ARITHMETIC_SIN_STUB; + case COS: + return ARITHMETIC_COS_STUB; + case TAN: + return ARITHMETIC_TAN_STUB; + case EXP: + return ARITHMETIC_EXP_STUB; + } + } else if (operation == UnaryOperation.EXP) { + return operation.foreignCallDescriptor; + } + // Lower only using LIRGenerator + return null; + } + + @Override + protected ForeignCallDescriptor toForeignCall(BinaryOperation operation) { + if (GraalArithmeticStubs.getValue()) { + switch (operation) { + case POW: + return ARITHMETIC_POW_STUB; + } + } else if (operation == BinaryOperation.POW) { + return operation.foreignCallDescriptor; + } + // Lower only using LIRGenerator + return null; + } + + @Override + public boolean supportSubwordCompare(int bits) { + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMathIntrinsicOp.java 2016-12-07 13:49:37.239786859 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011, 2016, 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.amd64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.meta.Value; + +/** + * This provides the default implementation expected by some HotSpot based lowerings of Math + * intrinsics. Depending on the release different patterns might be used. + */ +public final class AMD64HotSpotMathIntrinsicOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotMathIntrinsicOp.class); + + public enum IntrinsicOpcode { + SIN, + COS, + TAN, + LOG, + LOG10 + } + + @Opcode private final IntrinsicOpcode opcode; + @Def protected Value result; + @Use protected Value input; + + public AMD64HotSpotMathIntrinsicOp(IntrinsicOpcode opcode, Value result, Value input) { + super(TYPE); + this.opcode = opcode; + this.result = result; + this.input = input; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + switch (opcode) { + case LOG: + masm.flog(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), false); + break; + case LOG10: + masm.flog(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), true); + break; + case SIN: + masm.fsin(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE)); + break; + case COS: + masm.fcos(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE)); + break; + case TAN: + masm.ftan(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java 2016-12-07 13:49:37.506798596 -0800 @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2013, 2015, 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.amd64; + +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.CompressEncoding; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.StandardOp.LoadConstantOp; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.amd64.AMD64Move; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; + +public class AMD64HotSpotMove { + + public static final class HotSpotLoadObjectConstantOp extends AMD64LIRInstruction implements LoadConstantOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(HotSpotLoadObjectConstantOp.class); + + @Def({REG, STACK}) private AllocatableValue result; + private final HotSpotObjectConstant input; + + public HotSpotLoadObjectConstantOp(AllocatableValue result, HotSpotObjectConstant input) { + super(TYPE); + this.result = result; + this.input = input; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (GeneratePIC.getValue()) { + throw GraalError.shouldNotReachHere("Object constant load should not be happening directly"); + } + boolean compressed = input.isCompressed(); + if (crb.target.inlineObjects) { + crb.recordInlineDataInCode(input); + if (isRegister(result)) { + if (compressed) { + masm.movl(asRegister(result), 0xDEADDEAD); + } else { + masm.movq(asRegister(result), 0xDEADDEADDEADDEADL); + } + } else { + assert isStackSlot(result); + if (compressed) { + masm.movl((AMD64Address) crb.asAddress(result), 0xDEADDEAD); + } else { + throw GraalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); + } + } + } else { + if (isRegister(result)) { + AMD64Address address = (AMD64Address) crb.recordDataReferenceInCode(input, compressed ? 4 : 8); + if (compressed) { + masm.movl(asRegister(result), address); + } else { + masm.movq(asRegister(result), address); + } + } else { + throw GraalError.shouldNotReachHere("Cannot directly store data patch to memory"); + } + } + } + + @Override + public Constant getConstant() { + return input; + } + + @Override + public AllocatableValue getResult() { + return result; + } + } + + public static final class BaseMove extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BaseMove.class); + + @Def({REG, HINT}) protected AllocatableValue result; + private final GraalHotSpotVMConfig config; + + public BaseMove(AllocatableValue result, GraalHotSpotVMConfig config) { + super(TYPE); + this.result = result; + this.config = config; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + masm.movq(asRegister(result), masm.getPlaceholder(-1)); + crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS); + } + + } + + public static final class HotSpotLoadMetaspaceConstantOp extends AMD64LIRInstruction implements LoadConstantOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(HotSpotLoadMetaspaceConstantOp.class); + + @Def({REG, STACK}) private AllocatableValue result; + private final HotSpotMetaspaceConstant input; + + public HotSpotLoadMetaspaceConstantOp(AllocatableValue result, HotSpotMetaspaceConstant input) { + super(TYPE); + this.result = result; + this.input = input; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (GeneratePIC.getValue()) { + throw GraalError.shouldNotReachHere("Metaspace constant load should not be happening directly"); + } + boolean compressed = input.isCompressed(); + if (isRegister(result)) { + if (compressed) { + crb.recordInlineDataInCode(input); + masm.movl(asRegister(result), 0xDEADDEAD); + } else { + crb.recordInlineDataInCode(input); + masm.movq(asRegister(result), 0xDEADDEADDEADDEADL); + } + } else { + assert isStackSlot(result); + if (compressed) { + crb.recordInlineDataInCode(input); + masm.movl((AMD64Address) crb.asAddress(result), 0xDEADDEAD); + } else { + throw GraalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); + } + } + } + + @Override + public Constant getConstant() { + return input; + } + + @Override + public AllocatableValue getResult() { + return result; + } + } + + public static final class CompressPointer extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompressPointer.class); + + private final CompressEncoding encoding; + private final boolean nonNull; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue input; + @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; + + public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { + super(TYPE); + this.result = result; + this.input = input; + this.baseRegister = baseRegister; + this.encoding = encoding; + this.nonNull = nonNull; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(AMD64Kind.QWORD, crb, masm, result, input); + + Register resReg = asRegister(result); + if (encoding.base != 0 || GeneratePIC.getValue()) { + Register baseReg = asRegister(baseRegister); + if (!nonNull) { + masm.testq(resReg, resReg); + masm.cmovq(ConditionFlag.Equal, resReg, baseReg); + } + masm.subq(resReg, baseReg); + } + + if (encoding.shift != 0) { + masm.shrq(resReg, encoding.shift); + } + } + } + + public static final class UncompressPointer extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(UncompressPointer.class); + + private final CompressEncoding encoding; + private final boolean nonNull; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue input; + @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; + + public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { + super(TYPE); + this.result = result; + this.input = input; + this.baseRegister = baseRegister; + this.encoding = encoding; + this.nonNull = nonNull; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(AMD64Kind.DWORD, crb, masm, result, input); + + Register resReg = asRegister(result); + if (encoding.shift != 0) { + masm.shlq(resReg, encoding.shift); + } + + if (encoding.base != 0 || GeneratePIC.getValue()) { + if (nonNull) { + masm.addq(resReg, asRegister(baseRegister)); + } else { + if (encoding.shift == 0) { + // if encoding.shift != 0, the flags are already set by the shlq + masm.testq(resReg, resReg); + } + + Label done = new Label(); + masm.jccb(ConditionFlag.Equal, done); + masm.addq(resReg, asRegister(baseRegister)); + masm.bind(done); + } + } + } + } + + public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, CompressEncoding encoding) { + masm.movl(register, address); + if (encoding.shift != 0) { + assert encoding.alignment == encoding.shift : "Decode algorithm is wrong"; + masm.shlq(register, encoding.alignment); + } + if (encoding.base != 0) { + masm.movq(scratch, encoding.base); + masm.addq(register, scratch); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMoveFactory.java 2016-12-07 13:49:37.771810244 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 2016, 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.amd64; + +import org.graalvm.compiler.core.amd64.AMD64MoveFactory; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; + +import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; + +public class AMD64HotSpotMoveFactory extends AMD64MoveFactory { + + public AMD64HotSpotMoveFactory(BackupSlotProvider backupSlotProvider) { + super(backupSlotProvider); + } + + @Override + public boolean canInlineConstant(JavaConstant c) { + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { + return true; + } else if (c instanceof HotSpotObjectConstant) { + return ((HotSpotObjectConstant) c).isCompressed(); + } else { + return super.canInlineConstant(c); + } + } + + @Override + public boolean allowConstantToStackMove(Constant value) { + if (value instanceof HotSpotConstant) { + return ((HotSpotConstant) value).isCompressed(); + } + return true; + } + + @Override + public AMD64LIRInstruction createLoad(AllocatableValue dst, Constant src) { + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(src)) { + return super.createLoad(dst, JavaConstant.INT_0); + } else if (src instanceof HotSpotObjectConstant) { + return new AMD64HotSpotMove.HotSpotLoadObjectConstantOp(dst, (HotSpotObjectConstant) src); + } else if (src instanceof HotSpotMetaspaceConstant) { + return new AMD64HotSpotMove.HotSpotLoadMetaspaceConstantOp(dst, (HotSpotMetaspaceConstant) src); + } else { + return super.createLoad(dst, src); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeCostProvider.java 2016-12-07 13:49:38.037821937 -0800 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, 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.amd64; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_6; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_80; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider; +import org.graalvm.compiler.nodeinfo.NodeCycles; +import org.graalvm.compiler.nodeinfo.NodeSize; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode; +import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.code.TargetDescription; + +public class AMD64HotSpotNodeCostProvider extends HotSpotNodeCostProvider { + private final boolean avx2; + private final boolean sse41; + + public AMD64HotSpotNodeCostProvider(TargetDescription target) { + this.avx2 = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX2); + this.sse41 = ((AMD64) target.arch).getFeatures().contains(CPUFeature.SSE4_1); + } + + @Override + public NodeCycles cycles(Node n) { + if (n instanceof UnaryMathIntrinsicNode) { + UnaryMathIntrinsicNode u = (UnaryMathIntrinsicNode) n; + switch (u.getOperation()) { + case LOG: + case LOG10: + return CYCLES_15; + default: + break; + } + } else if (n instanceof ReturnNode) { + return CYCLES_6; + } else if (n instanceof ArrayEqualsNode) { + if (avx2) { + return CYCLES_50; + } else if (sse41) { + return CYCLES_80; + } + } + return super.cycles(n); + } + + @Override + public NodeSize size(Node n) { + if (n instanceof UnaryMathIntrinsicNode) { + UnaryMathIntrinsicNode u = (UnaryMathIntrinsicNode) n; + switch (u.getOperation()) { + case LOG: + case LOG10: + return SIZE_30; + default: + break; + } + } else if (n instanceof ReturnNode) { + return SIZE_4; + } + return super.size(n); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java 2016-12-07 13:49:38.302833586 -0800 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2012, 2015, 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.amd64; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER; +import static jdk.vm.ci.amd64.AMD64.rbp; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder; +import org.graalvm.compiler.core.amd64.AMD64NodeMatchRules; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.gen.DebugInfoBuilder; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.HotSpotLockStack; +import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder; +import org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode; +import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode; +import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.amd64.AMD64BreakpointOp; +import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.BreakpointNode; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.DirectCallTargetNode; +import org.graalvm.compiler.nodes.FullInfopointNode; +import org.graalvm.compiler.nodes.IndirectCallTargetNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.SafepointNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.NodeValueMap; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.hotspot.HotSpotCallingConventionType; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.Value; + +/** + * LIR generator specialized for AMD64 HotSpot. + */ +public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements HotSpotNodeLIRBuilder { + + public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) { + super(graph, gen, nodeMatchRules); + assert gen instanceof AMD64HotSpotLIRGenerator; + assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder; + ((AMD64HotSpotLIRGenerator) gen).setDebugInfoBuilder(((HotSpotDebugInfoBuilder) getDebugInfoBuilder())); + } + + private AMD64HotSpotLIRGenerator getGen() { + return (AMD64HotSpotLIRGenerator) gen; + } + + @Override + protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) { + HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(AMD64Kind.QWORD)); + return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack, (HotSpotLIRGenerator) gen); + } + + @Override + protected void emitPrologue(StructuredGraph graph) { + + CallingConvention incomingArguments = gen.getResult().getCallingConvention(); + + Value[] params = new Value[incomingArguments.getArgumentCount() + 1]; + for (int i = 0; i < params.length - 1; i++) { + params[i] = incomingArguments.getArgument(i); + if (isStackSlot(params[i])) { + StackSlot slot = ValueUtil.asStackSlot(params[i]); + if (slot.isInCallerFrame() && !gen.getResult().getLIR().hasArgInCallerFrame()) { + gen.getResult().getLIR().setHasArgInCallerFrame(); + } + } + } + params[params.length - 1] = rbp.asValue(LIRKind.value(AMD64Kind.QWORD)); + + gen.emitIncomingValues(params); + + getGen().emitSaveRbp(); + + getGen().append(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack()); + + for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { + Value paramValue = params[param.index()]; + assert paramValue.getValueKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp())) : paramValue.getValueKind() + " != " + param.stamp(); + setResult(param, gen.emitMove(paramValue)); + } + } + + @Override + public void visitSafepointNode(SafepointNode i) { + LIRFrameState info = state(i); + append(new AMD64HotSpotSafepointOp(info, getGen().config, this)); + } + + @Override + protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); + if (invokeKind.isIndirect()) { + append(new AMD64HotspotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); + } else { + assert invokeKind.isDirect(); + HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); + assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method."; + append(new AMD64HotSpotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); + } + } + + @Override + protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + if (callTarget instanceof HotSpotIndirectCallTargetNode) { + Value metaspaceMethodSrc = operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()); + Value targetAddressSrc = operand(callTarget.computedAddress()); + AllocatableValue metaspaceMethodDst = AMD64.rbx.asValue(metaspaceMethodSrc.getValueKind()); + AllocatableValue targetAddressDst = AMD64.rax.asValue(targetAddressSrc.getValueKind()); + gen.emitMove(metaspaceMethodDst, metaspaceMethodSrc); + gen.emitMove(targetAddressDst, targetAddressSrc); + append(new AMD64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethodDst, targetAddressDst, callState, getGen().config)); + } else { + super.emitIndirectCall(callTarget, result, parameters, temps, callState); + } + } + + @Override + public void emitPatchReturnAddress(ValueNode address) { + append(new AMD64HotSpotPatchReturnAddressOp(gen.load(operand(address)))); + } + + @Override + public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + Variable handler = gen.load(operand(handlerInCallerPc)); + ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER); + CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); + assert outgoingCc.getArgumentCount() == 2; + RegisterValue exceptionFixed = (RegisterValue) outgoingCc.getArgument(0); + RegisterValue exceptionPcFixed = (RegisterValue) outgoingCc.getArgument(1); + gen.emitMove(exceptionFixed, operand(exception)); + gen.emitMove(exceptionPcFixed, operand(exceptionPc)); + Register thread = getGen().getProviders().getRegisters().getThreadRegister(); + AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, getGen().config.threadIsMethodHandleReturnOffset, + thread); + append(op); + } + + @Override + public void visitFullInfopointNode(FullInfopointNode i) { + if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) { + Debug.log("Ignoring InfopointNode for AFTER_BCI"); + } else { + super.visitFullInfopointNode(i); + } + } + + @Override + public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { + Value expected = gen.loadNonConst(operand(x.expectedValue())); + Variable newVal = gen.load(operand(x.newValue())); + assert expected.getValueKind().equals(newVal.getValueKind()); + + RegisterValue raxLocal = AMD64.rax.asValue(expected.getValueKind()); + gen.emitMove(raxLocal, expected); + append(new CompareAndSwapOp((AMD64Kind) expected.getPlatformKind(), raxLocal, getGen().asAddressValue(operand(x.getAddress())), raxLocal, newVal)); + + setResult(x, gen.emitMove(raxLocal)); + } + + @Override + public void visitBreakpointNode(BreakpointNode node) { + JavaType[] sig = new JavaType[node.arguments().size()]; + for (int i = 0; i < sig.length; i++) { + sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess()); + } + + Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), + node.arguments()); + append(new AMD64BreakpointOp(parameters)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotPatchReturnAddressOp.java 2016-12-07 13:49:38.568845278 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, 2015, 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.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.amd64.AMD64.rsp; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Patch the return address of the current frame. + */ +@Opcode("PATCH_RETURN") +final class AMD64HotSpotPatchReturnAddressOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotPatchReturnAddressOp.class); + + @Use(REG) AllocatableValue address; + + AMD64HotSpotPatchReturnAddressOp(AllocatableValue address) { + super(TYPE); + this.address = address; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + int frameSize = crb.frameMap.frameSize(); + masm.movq(new AMD64Address(rsp, frameSize), asRegister(address)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotPushInterpreterFrameOp.java 2016-12-07 13:49:38.833856927 -0800 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.amd64.AMD64.rsp; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Pushes an interpreter frame to the stack. + */ +@Opcode("PUSH_INTERPRETER_FRAME") +final class AMD64HotSpotPushInterpreterFrameOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotPushInterpreterFrameOp.class); + + @Alive(REG) AllocatableValue frameSize; + @Alive(REG) AllocatableValue framePc; + @Alive(REG) AllocatableValue senderSp; + @Alive(REG) AllocatableValue initialInfo; + private final GraalHotSpotVMConfig config; + + AMD64HotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo, GraalHotSpotVMConfig config) { + super(TYPE); + this.frameSize = frameSize; + this.framePc = framePc; + this.senderSp = senderSp; + this.initialInfo = initialInfo; + this.config = config; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + final Register frameSizeRegister = asRegister(frameSize); + final Register framePcRegister = asRegister(framePc); + final Register senderSpRegister = asRegister(senderSp); + final Register initialInfoRegister = asRegister(initialInfo); + final int wordSize = 8; + + // We'll push PC and BP by hand. + masm.subq(frameSizeRegister, 2 * wordSize); + + // Push return address. + masm.push(framePcRegister); + + // Prolog + masm.push(initialInfoRegister); + masm.movq(initialInfoRegister, rsp); + masm.subq(rsp, frameSizeRegister); + + // This value is corrected by layout_activation_impl. + masm.movptr(new AMD64Address(initialInfoRegister, config.frameInterpreterFrameLastSpOffset * wordSize), 0); + + // Make the frame walkable. + masm.movq(new AMD64Address(initialInfoRegister, config.frameInterpreterFrameSenderSpOffset * wordSize), senderSpRegister); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRegisterAllocationConfig.java 2016-12-07 13:49:39.097868531 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015, 2015, 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.amd64; + +import static jdk.vm.ci.amd64.AMD64.r10; +import static jdk.vm.ci.amd64.AMD64.r11; +import static jdk.vm.ci.amd64.AMD64.r12; +import static jdk.vm.ci.amd64.AMD64.r13; +import static jdk.vm.ci.amd64.AMD64.r14; +import static jdk.vm.ci.amd64.AMD64.r8; +import static jdk.vm.ci.amd64.AMD64.r9; +import static jdk.vm.ci.amd64.AMD64.rax; +import static jdk.vm.ci.amd64.AMD64.rbp; +import static jdk.vm.ci.amd64.AMD64.rbx; +import static jdk.vm.ci.amd64.AMD64.rcx; +import static jdk.vm.ci.amd64.AMD64.rdi; +import static jdk.vm.ci.amd64.AMD64.rdx; +import static jdk.vm.ci.amd64.AMD64.rsi; +import static jdk.vm.ci.amd64.AMD64.xmm0; +import static jdk.vm.ci.amd64.AMD64.xmm1; +import static jdk.vm.ci.amd64.AMD64.xmm10; +import static jdk.vm.ci.amd64.AMD64.xmm11; +import static jdk.vm.ci.amd64.AMD64.xmm12; +import static jdk.vm.ci.amd64.AMD64.xmm13; +import static jdk.vm.ci.amd64.AMD64.xmm14; +import static jdk.vm.ci.amd64.AMD64.xmm15; +import static jdk.vm.ci.amd64.AMD64.xmm2; +import static jdk.vm.ci.amd64.AMD64.xmm3; +import static jdk.vm.ci.amd64.AMD64.xmm4; +import static jdk.vm.ci.amd64.AMD64.xmm5; +import static jdk.vm.ci.amd64.AMD64.xmm6; +import static jdk.vm.ci.amd64.AMD64.xmm7; +import static jdk.vm.ci.amd64.AMD64.xmm8; +import static jdk.vm.ci.amd64.AMD64.xmm9; + +import java.util.ArrayList; +import java.util.BitSet; + +import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterConfig; + +class AMD64HotSpotRegisterAllocationConfig extends RegisterAllocationConfig { + /** + * Specify priority of register selection within phases of register allocation. Highest priority + * is first. A useful heuristic is to give registers a low priority when they are required by + * machine instructions, like EAX and EDX on I486, and choose no-save registers before + * save-on-call, & save-on-call before save-on-entry. Registers which participate in fixed + * calling sequences should come last. Registers which are used as pairs must fall on an even + * boundary. + * + * Adopted from x86_64.ad. + */ + // @formatter:off + static final Register[] registerAllocationOrder = { + r10, r11, r8, r9, r12, rcx, rbx, rdi, rdx, rsi, rax, rbp, r13, r14, /*r15,*/ /*rsp,*/ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + // @formatter:on + + AMD64HotSpotRegisterAllocationConfig(RegisterConfig registerConfig) { + super(registerConfig); + } + + @Override + protected RegisterArray initAllocatable(RegisterArray registers) { + BitSet regMap = new BitSet(registerConfig.getAllocatableRegisters().size()); + for (Register reg : registers) { + regMap.set(reg.number); + } + + ArrayList allocatableRegisters = new ArrayList<>(registers.size()); + for (Register reg : registerAllocationOrder) { + if (regMap.get(reg.number)) { + allocatableRegisters.add(reg); + } + } + + return super.initAllocatable(new RegisterArray(allocatableRegisters)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRestoreRbpOp.java 2016-12-07 13:49:39.365880312 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 2015, 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.amd64; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.Variable; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.meta.AllocatableValue; + +public interface AMD64HotSpotRestoreRbpOp { + + /** + * The type of location (i.e., stack or register) in which RBP is saved is not known until + * initial LIR generation is finished. Until then, we use a placeholder variable so that LIR + * verification is successful. + */ + Variable PLACEHOLDER = new Variable(LIRKind.value(AMD64Kind.QWORD), Integer.MAX_VALUE); + + void setSavedRbp(AllocatableValue value); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotReturnOp.java 2016-12-07 13:49:39.629891916 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2012, 2016, 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.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool.ZapStackArgumentSpaceBeforeInstruction; + +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.Value; + +/** + * Returns from a function. + */ +@Opcode("RETURN") +final class AMD64HotSpotReturnOp extends AMD64HotSpotEpilogueBlockEndOp implements ZapStackArgumentSpaceBeforeInstruction { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotReturnOp.class); + @Use({REG, ILLEGAL}) protected Value value; + private final boolean isStub; + private final Register scratchForSafepointOnReturn; + private final GraalHotSpotVMConfig config; + + AMD64HotSpotReturnOp(Value value, boolean isStub, Register scratchForSafepointOnReturn, GraalHotSpotVMConfig config) { + super(TYPE); + this.value = value; + this.isStub = isStub; + this.scratchForSafepointOnReturn = scratchForSafepointOnReturn; + this.config = config; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + leaveFrameAndRestoreRbp(crb, masm); + if (!isStub) { + // Every non-stub compile method must have a poll before the return. + AMD64HotSpotSafepointOp.emitCode(crb, masm, config, true, null, scratchForSafepointOnReturn); + + /* + * We potentially return to the interpreter, and that's an AVX-SSE transition. The only + * live value at this point should be the return value in either rax, or in xmm0 with + * the upper half of the register unused, so we don't destroy any value here. + */ + if (masm.supports(CPUFeature.AVX)) { + masm.vzeroupper(); + } + } + masm.ret(0); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java 2016-12-07 13:49:39.894903565 -0800 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2011, 2016, 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.amd64; + +import static org.graalvm.compiler.asm.NumUtil.isInt; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; +import static jdk.vm.ci.amd64.AMD64.rax; +import static jdk.vm.ci.amd64.AMD64.rip; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.site.InfopointReason; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; + +/** + * Emits a safepoint poll. + */ +@Opcode("SAFEPOINT") +public final class AMD64HotSpotSafepointOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotSafepointOp.class); + + @State protected LIRFrameState state; + @Temp({OperandFlag.REG, OperandFlag.ILLEGAL}) private AllocatableValue temp; + + private final GraalHotSpotVMConfig config; + + public AMD64HotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, NodeLIRBuilderTool tool) { + super(TYPE); + this.state = state; + this.config = config; + if (isPollingPageFar(config) || ImmutableCode.getValue()) { + temp = tool.getLIRGeneratorTool().newVariable(LIRKind.value(tool.getLIRGeneratorTool().target().arch.getWordKind())); + } else { + // Don't waste a register if it's unneeded + temp = Value.ILLEGAL; + } + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) { + emitCode(crb, asm, config, false, state, temp instanceof RegisterValue ? ((RegisterValue) temp).getRegister() : null); + } + + /** + * Tests if the polling page address can be reached from the code cache with 32-bit + * displacements. + */ + private static boolean isPollingPageFar(GraalHotSpotVMConfig config) { + final long pollingPageAddress = config.safepointPollingAddress; + return config.forceUnreachable || !isInt(pollingPageAddress - config.codeCacheLowBound) || !isInt(pollingPageAddress - config.codeCacheHighBound); + } + + public static void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) { + assert !atReturn || state == null : "state is unneeded at return"; + if (ImmutableCode.getValue()) { + JavaKind hostWordKind = JavaKind.Long; + int alignment = hostWordKind.getBitCount() / Byte.SIZE; + JavaConstant pollingPageAddress = JavaConstant.forIntegerKind(hostWordKind, config.safepointPollingAddress); + // This move will be patched to load the safepoint page from a data segment + // co-located with the immutable code. + if (GeneratePIC.getValue()) { + asm.movq(scratch, asm.getPlaceholder(-1)); + } else { + asm.movq(scratch, (AMD64Address) crb.recordDataReferenceInCode(pollingPageAddress, alignment)); + } + final int pos = asm.position(); + crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); + if (state != null) { + crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); + } + asm.testl(rax, new AMD64Address(scratch)); + } else if (isPollingPageFar(config)) { + asm.movq(scratch, config.safepointPollingAddress); + crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); + final int pos = asm.position(); + if (state != null) { + crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); + } + asm.testl(rax, new AMD64Address(scratch)); + } else { + crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_NEAR : config.MARKID_POLL_NEAR); + final int pos = asm.position(); + if (state != null) { + crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); + } + // The C++ code transforms the polling page offset into an RIP displacement + // to the real address at that offset in the polling page. + asm.testl(rax, new AMD64Address(rip, 0)); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotStrategySwitchOp.java 2016-12-07 13:49:40.159915213 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 2015, 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.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.amd64.AMD64ControlFlow; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; + +final class AMD64HotSpotStrategySwitchOp extends AMD64ControlFlow.StrategySwitchOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotStrategySwitchOp.class); + + AMD64HotSpotStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { + super(TYPE, strategy, keyTargets, defaultTarget, key, scratch); + } + + @Override + public void emitCode(final CompilationResultBuilder crb, final AMD64MacroAssembler masm) { + strategy.run(new HotSpotSwitchClosure(ValueUtil.asRegister(key), crb, masm)); + } + + public class HotSpotSwitchClosure extends SwitchClosure { + + protected HotSpotSwitchClosure(Register keyRegister, CompilationResultBuilder crb, AMD64MacroAssembler masm) { + super(keyRegister, crb, masm); + } + + @Override + protected void emitComparison(Constant c) { + if (c instanceof HotSpotMetaspaceConstant) { + HotSpotMetaspaceConstant meta = (HotSpotMetaspaceConstant) c; + if (meta.isCompressed()) { + crb.recordInlineDataInCode(meta); + masm.cmpl(keyRegister, 0xDEADDEAD); + } else { + AMD64Address addr = (AMD64Address) crb.recordDataReferenceInCode(meta, 8); + masm.cmpq(keyRegister, addr); + } + } else { + super.emitComparison(c); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSuitesProvider.java 2016-12-07 13:49:40.424926862 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, 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.amd64; + +import org.graalvm.compiler.core.amd64.AMD64SuitesProvider; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.hotspot.lir.HotSpotZapRegistersPhase; +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; + +public class AMD64HotSpotSuitesProvider extends AMD64SuitesProvider { + + public AMD64HotSpotSuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) { + super(compilerConfiguration, plugins); + } + + @Override + public LIRSuites createLIRSuites() { + LIRSuites lirSuites = super.createLIRSuites(); + if (GraalOptions.DetailedAsserts.getValue()) { + lirSuites.getPostAllocationOptimizationStage().appendPhase(new HotSpotZapRegistersPhase()); + } + return lirSuites; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotUnwindOp.java 2016-12-07 13:49:40.691938598 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012, 2014, 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.amd64; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.amd64.AMD64.rsp; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64Call; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; + +/** + * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}. + */ +@Opcode("UNWIND") +final class AMD64HotSpotUnwindOp extends AMD64HotSpotEpilogueBlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotUnwindOp.class); + + @Use({REG}) protected RegisterValue exception; + + AMD64HotSpotUnwindOp(RegisterValue exception) { + super(TYPE); + this.exception = exception; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + leaveFrameAndRestoreRbp(crb, masm); + + ForeignCallLinkage linkage = crb.foreignCalls.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER); + CallingConvention cc = linkage.getOutgoingCallingConvention(); + assert cc.getArgumentCount() == 2; + assert exception.equals(cc.getArgument(0)); + + // Get return address (is on top of stack after leave). + Register returnAddress = asRegister(cc.getArgument(1)); + masm.movq(returnAddress, new AMD64Address(rsp, 0)); + + AMD64Call.directJmp(crb, masm, linkage); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java 2016-12-07 13:49:40.955950203 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 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.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64Call.DirectCallOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * A direct call that complies with the conventions for such calls in HotSpot. In particular, for + * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call. + */ +@Opcode("CALL_DIRECT") +final class AMD64HotspotDirectVirtualCallOp extends DirectCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotspotDirectVirtualCallOp.class); + + private final InvokeKind invokeKind; + private final GraalHotSpotVMConfig config; + + AMD64HotspotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) { + super(TYPE, target, result, parameters, temps, state); + this.invokeKind = invokeKind; + this.config = config; + assert invokeKind.isIndirect(); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + // The mark for an invocation that uses an inline cache must be placed at the + // instruction that loads the Klass from the inline cache. + crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE); + // This must be emitted exactly like this to ensure it's patchable + masm.movq(AMD64.rax, config.nonOopBits); + super.emitCode(crb, masm); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java 2016-12-07 13:49:41.221961896 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, 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.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64Call; +import org.graalvm.compiler.lir.amd64.AMD64Call.IndirectCallOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * A register indirect call that complies with the extra conventions for such calls in HotSpot. In + * particular, the metaspace Method of the callee must be in RBX for the case where a vtable entry's + * _from_compiled_entry is the address of an C2I adapter. Such adapters expect the target method to + * be in RBX. + */ +@Opcode("CALL_INDIRECT") +final class AMD64IndirectCallOp extends IndirectCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64IndirectCallOp.class); + + /** + * Vtable stubs expect the metaspace Method in RBX. + */ + public static final Register METHOD = AMD64.rbx; + + @Use({REG}) protected Value metaspaceMethod; + + private final GraalHotSpotVMConfig config; + + AMD64IndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state, + GraalHotSpotVMConfig config) { + super(TYPE, targetMethod, result, parameters, temps, targetAddress, state); + this.metaspaceMethod = metaspaceMethod; + this.config = config; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + crb.recordMark(config.MARKID_INLINE_INVOKE); + Register callReg = asRegister(targetAddress); + assert !callReg.equals(METHOD); + AMD64Call.indirectCall(crb, masm, callReg, callTarget, state); + } + + @Override + public void verify() { + super.verify(); + assert asRegister(metaspaceMethod).equals(METHOD); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64MathStub.java 2016-12-07 13:49:41.487973588 -0800 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016, 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.amd64; + +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_COS_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_EXP_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_LOG10_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_LOG_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_POW_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_SIN_STUB; +import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_TAN_STUB; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.stubs.SnippetStub; +import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode; +import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation; +import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode; +import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; + +/** + * Stub called to support {@link Math}. + */ +public class AMD64MathStub extends SnippetStub { + + public AMD64MathStub(ForeignCallDescriptor descriptor, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super(snippetName(descriptor), providers, linkage); + } + + private static String snippetName(ForeignCallDescriptor descriptor) { + if (descriptor == ARITHMETIC_LOG_STUB) { + return "log"; + } + if (descriptor == ARITHMETIC_LOG10_STUB) { + return "log10"; + } + if (descriptor == ARITHMETIC_SIN_STUB) { + return "sin"; + } + if (descriptor == ARITHMETIC_COS_STUB) { + return "cos"; + } + if (descriptor == ARITHMETIC_TAN_STUB) { + return "tan"; + } + if (descriptor == ARITHMETIC_EXP_STUB) { + return "exp"; + } + if (descriptor == ARITHMETIC_POW_STUB) { + return "pow"; + } + throw new InternalError("Unknown operation " + descriptor); + } + + @Snippet + private static double log(double value) { + return UnaryMathIntrinsicNode.compute(value, UnaryOperation.LOG); + } + + @Snippet + private static double log10(double value) { + return UnaryMathIntrinsicNode.compute(value, UnaryOperation.LOG10); + } + + @Snippet + private static double sin(double value) { + return UnaryMathIntrinsicNode.compute(value, UnaryOperation.SIN); + } + + @Snippet + private static double cos(double value) { + return UnaryMathIntrinsicNode.compute(value, UnaryOperation.COS); + } + + @Snippet + private static double tan(double value) { + return UnaryMathIntrinsicNode.compute(value, UnaryOperation.TAN); + } + + @Snippet + private static double exp(double value) { + return UnaryMathIntrinsicNode.compute(value, UnaryOperation.EXP); + } + + @Snippet + private static double pow(double value1, double value2) { + return BinaryMathIntrinsicNode.compute(value1, value2, BinaryOperation.POW); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64RawNativeCallNode.java 2016-12-07 13:49:41.755985369 -0800 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014, 2016, 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.amd64; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20; + +import org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder; +import org.graalvm.compiler.core.common.type.RawPointerStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.hotspot.HotSpotCallingConventionType; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Value; + +@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = SIZE_20) +public final class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(AMD64RawNativeCallNode.class); + + protected final JavaConstant functionPointer; + @Input NodeInputList args; + + public AMD64RawNativeCallNode(JavaKind returnType, JavaConstant functionPointer, ValueNode[] args) { + super(TYPE, StampFactory.forKind(returnType)); + this.functionPointer = functionPointer; + this.args = new NodeInputList<>(this, args); + } + + private static class PointerType implements JavaType { + + @Override + public String getName() { + return "void*"; + } + + @Override + public JavaType getComponentType() { + return null; + } + + @Override + public JavaType getArrayClass() { + return null; + } + + @Override + public JavaKind getJavaKind() { + // native pointers and java objects use the same registers in the calling convention + return JavaKind.Object; + } + + @Override + public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { + return null; + } + } + + private static JavaType toJavaType(Stamp stamp, MetaAccessProvider metaAccess) { + if (stamp instanceof RawPointerStamp) { + return new PointerType(); + } else { + return stamp.javaType(metaAccess); + } + } + + @Override + public void generate(NodeLIRBuilderTool generator) { + AMD64NodeLIRBuilder gen = (AMD64NodeLIRBuilder) generator; + Value[] parameter = new Value[args.count()]; + JavaType[] parameterTypes = new JavaType[args.count()]; + for (int i = 0; i < args.count(); i++) { + parameter[i] = generator.operand(args.get(i)); + parameterTypes[i] = toJavaType(args.get(i).stamp(), gen.getLIRGeneratorTool().getMetaAccess()); + } + JavaType returnType = toJavaType(stamp(), gen.getLIRGeneratorTool().getMetaAccess()); + CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.NativeCall, returnType, parameterTypes, + generator.getLIRGeneratorTool()); + gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args)); + if (this.getStackKind() != JavaKind.Void) { + generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn())); + } + } + + private static int countFloatingTypeArguments(NodeInputList args) { + int count = 0; + for (ValueNode n : args) { + if (n.getStackKind() == JavaKind.Double || n.getStackKind() == JavaKind.Float) { + count++; + } + } + if (count > 8) { + return 8; + } + return count; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64TailcallOp.java 2016-12-07 13:49:42.021997061 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011, 2015, 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.amd64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.Value; + +/** + * Performs a hard-coded tail call to the specified target, which normally should be an + * {@link InstalledCode} instance. + */ +@Opcode("TAILCALL") +public final class AMD64TailcallOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64TailcallOp.class); + + @Use protected Value target; + @Alive protected Value[] parameters; + + public AMD64TailcallOp(Value[] parameters, Value target) { + super(TYPE); + this.target = target; + this.parameters = parameters; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + // destroy the current frame (now the return address is the top of stack) + masm.leave(); + + // jump to the target method + masm.jmp(asRegister(target)); + masm.ensureUniquePC(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64UncommonTrapStub.java 2016-12-07 13:49:42.287008710 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014, 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.amd64; + +import static jdk.vm.ci.amd64.AMD64.r10; +import static jdk.vm.ci.amd64.AMD64.r11; +import static jdk.vm.ci.amd64.AMD64.r13; +import static jdk.vm.ci.amd64.AMD64.r14; +import static jdk.vm.ci.amd64.AMD64.r8; +import static jdk.vm.ci.amd64.AMD64.r9; +import static jdk.vm.ci.amd64.AMD64.rbx; +import static jdk.vm.ci.amd64.AMD64.rcx; +import static jdk.vm.ci.amd64.AMD64.rdi; +import static jdk.vm.ci.amd64.AMD64.rdx; +import static jdk.vm.ci.amd64.AMD64.rsi; + +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.stubs.UncommonTrapStub; + +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.amd64.AMD64HotSpotRegisterConfig; + +final class AMD64UncommonTrapStub extends UncommonTrapStub { + + private RegisterConfig registerConfig; + + AMD64UncommonTrapStub(HotSpotProviders providers, TargetDescription target, GraalHotSpotVMConfig config, HotSpotForeignCallLinkage linkage) { + super(providers, target, linkage); + RegisterArray allocatable = new RegisterArray(rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14); + registerConfig = new AMD64HotSpotRegisterConfig(target, allocatable, config.windowsOs); + } + + @Override + public RegisterConfig getRegisterConfig() { + return registerConfig; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/ExceedMaxOopMapStackOffset.java 2016-12-07 13:49:42.554020446 -0800 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2016, 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.lir.test; + +import org.junit.Test; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.jtt.LIRTest; +import org.graalvm.compiler.lir.jtt.LIRTestSpecification; +import org.graalvm.compiler.nodes.SafepointNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; + +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class ExceedMaxOopMapStackOffset extends LIRTest { + + /** + * Allocate lots of stacks slots and initialize them with a constant. + */ + private static class WriteStackSlotsSpec extends LIRTestSpecification { + private final JavaConstant constant; + + WriteStackSlotsSpec(JavaConstant constant) { + this.constant = constant; + } + + @Override + public void generate(LIRGeneratorTool gen) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + LIRKind lirKind = LIRKind.reference(gen.target().arch.getPlatformKind(constant.getJavaKind())); + // create slots + for (int i = 0; i < slots.length; i++) { + AllocatableValue src = gen.emitLoadConstant(lirKind, constant); + slots[i] = frameMapBuilder.allocateSpillSlot(lirKind); + gen.emitMove(slots[i], src); + } + } + } + + /** + * Read stacks slots and move their content into a blackhole. + */ + private static class ReadStackSlotsSpec extends LIRTestSpecification { + + ReadStackSlotsSpec() { + } + + @Override + public void generate(LIRGeneratorTool gen) { + for (int i = 0; i < slots.length; i++) { + gen.emitBlackhole(gen.emitMove(slots[i])); + } + } + } + + @Override + protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) { + InvocationPlugin safepointPlugin = new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + b.add(new SafepointNode()); + return true; + } + }; + conf.getPlugins().getInvocationPlugins().register(safepointPlugin, getClass(), "safepoint"); + return super.editGraphBuilderConfiguration(conf); + } + + /* + * Safepoint Snippet + */ + private static void safepoint() { + } + + private static AllocatableValue[] slots; + + private static final LIRTestSpecification readStackObjects = new ReadStackSlotsSpec(); + + @SuppressWarnings("unused") + @LIRIntrinsic + public static void instrinsic(LIRTestSpecification spec) { + } + + private static final LIRTestSpecification writeStackObjects = new WriteStackSlotsSpec(JavaConstant.NULL_POINTER); + + public void testStackObjects() { + instrinsic(writeStackObjects); + safepoint(); + instrinsic(readStackObjects); + } + + @Test + public void runStackObjects() throws Throwable { + int max = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig().maxOopMapStackOffset; + if (max == Integer.MAX_VALUE) { + max = 16 * 1024 - 64; + } + try { + int numSlots = (max / 8) + 1; + slots = new AllocatableValue[numSlots]; + runTest("testStackObjects"); + } catch (BailoutException e) { + return; + } + fail("Expected exception BailoutException wasn't thrown"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizationStub.java 2016-12-07 13:49:42.819032095 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, 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.sparc; + +import static jdk.vm.ci.sparc.SPARC.g1; +import static jdk.vm.ci.sparc.SPARC.g3; +import static jdk.vm.ci.sparc.SPARC.g4; +import static jdk.vm.ci.sparc.SPARC.g5; +import static jdk.vm.ci.sparc.SPARC.o0; +import static jdk.vm.ci.sparc.SPARC.o1; +import static jdk.vm.ci.sparc.SPARC.o2; +import static jdk.vm.ci.sparc.SPARC.o3; +import static jdk.vm.ci.sparc.SPARC.o4; + +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.stubs.DeoptimizationStub; + +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.sparc.SPARCHotSpotRegisterConfig; + +final class SPARCDeoptimizationStub extends DeoptimizationStub { + + private RegisterConfig registerConfig; + + SPARCDeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) { + super(providers, target, linkage); + // This is basically the maximum we can spare. All other G and O register are used. + RegisterArray allocatable = new RegisterArray(g1, g3, g4, g5, o0, o1, o2, o3, o4); + registerConfig = new SPARCHotSpotRegisterConfig(target, allocatable); + } + + @Override + public RegisterConfig getRegisterConfig() { + return registerConfig; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizeOp.java 2016-12-07 13:49:43.085043787 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 2015, 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.sparc; + +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCBlockEndOp; +import org.graalvm.compiler.lir.sparc.SPARCCall; + +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.sparc.SPARC; + +@Opcode("DEOPT") +final class SPARCDeoptimizeOp extends SPARCBlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCDeoptimizeOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(1); + @Temp AllocatableValue pcRegister; + @State private LIRFrameState info; + + SPARCDeoptimizeOp(LIRFrameState info, PlatformKind wordKind) { + super(TYPE, SIZE); + this.info = info; + pcRegister = SPARC.o7.asValue(LIRKind.value(wordKind)); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + // TODO the patched call address looks odd (and is invalid) compared to other runtime calls: + // 0xffffffff749bb5fc: call 0xffffffff415a720c ; {runtime_call} + // [Exception Handler] + // 0xffffffff749bb604: call 0xffffffff749bb220 ; {runtime_call} + // 0xffffffff749bb608: nop + // [Deopt Handler Code] + // 0xffffffff749bb60c: call 0xffffffff748da540 ; {runtime_call} + // 0xffffffff749bb610: nop + SPARCCall.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, info); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java 2016-12-07 13:49:43.351055480 -0800 @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2013, 2016, 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.sparc; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isGlobalRegister; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual; +import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARC.g5; +import static jdk.vm.ci.sparc.SPARC.i0; +import static jdk.vm.ci.sparc.SPARC.i7; +import static jdk.vm.ci.sparc.SPARC.l0; +import static jdk.vm.ci.sparc.SPARC.l7; +import static jdk.vm.ci.sparc.SPARC.o0; +import static jdk.vm.ci.sparc.SPARC.o7; +import static jdk.vm.ci.sparc.SPARC.sp; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.graalvm.compiler.asm.Assembler; +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.code.DataSection; +import org.graalvm.compiler.code.DataSection.Data; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.core.sparc.SPARCNodeMatchRules; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.hotspot.HotSpotDataBuilder; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.HotSpotHostBackend; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.lir.InstructionValueConsumer; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.lir.asm.DataBuilder; +import org.graalvm.compiler.lir.asm.FrameContext; +import org.graalvm.compiler.lir.framemap.FrameMap; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.sparc.SPARCCall; +import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer; +import org.graalvm.compiler.lir.sparc.SPARCFrameMap; +import org.graalvm.compiler.lir.sparc.SPARCFrameMapBuilder; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate; +import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.hotspot.HotSpotCallingConventionType; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * HotSpot SPARC specific backend. + */ +public class SPARCHotSpotBackend extends HotSpotHostBackend { + + private static final SizeEstimateStatistics CONSTANT_ESTIMATED_STATS = new SizeEstimateStatistics("ESTIMATE"); + private static final SizeEstimateStatistics CONSTANT_ACTUAL_STATS = new SizeEstimateStatistics("ACTUAL"); + + public SPARCHotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { + super(config, runtime, providers); + } + + private static class SizeEstimateStatistics { + private static final ConcurrentHashMap counters = new ConcurrentHashMap<>(); + private final String suffix; + + SizeEstimateStatistics(String suffix) { + super(); + this.suffix = suffix; + } + + public void add(Class c, int count) { + String name = SizeEstimateStatistics.class.getSimpleName() + "_" + c.getSimpleName() + "." + suffix; + DebugCounter m = counters.computeIfAbsent(name, (n) -> Debug.counter(n)); + m.add(count); + } + } + + @Override + public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) { + RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; + return new SPARCFrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull); + } + + @Override + public FrameMap newFrameMap(RegisterConfig registerConfig) { + return new SPARCFrameMap(getCodeCache(), registerConfig, this); + } + + @Override + public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) { + return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getVMConfig(), lirGenRes); + } + + @Override + public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, Object stub) { + return new HotSpotLIRGenerationResult(compilationId, lir, frameMapBuilder, makeCallingConvention(graph, (Stub) stub), stub); + } + + @Override + public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { + return new SPARCHotSpotNodeLIRBuilder(graph, lirGen, new SPARCNodeMatchRules(lirGen)); + } + + @Override + protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) { + // Use SPARCAddress to get the final displacement including the stack bias. + SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; + SPARCAddress address = new SPARCAddress(sp, -bangOffset); + if (SPARCAssembler.isSimm13(address.getDisplacement())) { + masm.stx(g0, address); + } else { + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + assert isGlobalRegister(scratch) : "Only global (g1-g7) registers are allowed if the frame was not initialized here. Got register " + scratch; + masm.setx(address.getDisplacement(), scratch, false); + masm.stx(g0, new SPARCAddress(sp, scratch)); + } + } + } + + public class HotSpotFrameContext implements FrameContext { + + final boolean isStub; + + HotSpotFrameContext(boolean isStub) { + this.isStub = isStub; + } + + @Override + public boolean hasFrame() { + return true; + } + + @Override + public void enter(CompilationResultBuilder crb) { + final int frameSize = crb.frameMap.totalFrameSize(); + final int stackpoinerChange = -frameSize; + SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; + emitStackOverflowCheck(crb); + + if (SPARCAssembler.isSimm13(stackpoinerChange)) { + masm.save(sp, stackpoinerChange, sp); + } else { + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + assert isGlobalRegister(scratch) : "Only global registers are allowed before save. Got register " + scratch; + masm.setx(stackpoinerChange, scratch, false); + masm.save(sp, scratch, sp); + } + } + + if (ZapStackOnMethodEntry.getValue()) { + final int slotSize = 8; + for (int i = 0; i < frameSize / slotSize; ++i) { + // 0xC1C1C1C1 + masm.stx(g0, new SPARCAddress(sp, i * slotSize)); + } + } + } + + @Override + public void leave(CompilationResultBuilder crb) { + SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; + masm.restoreWindow(); + } + } + + @Override + protected Assembler createAssembler(FrameMap frameMap) { + return new SPARCMacroAssembler(getTarget()); + } + + @Override + public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { + HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRes; + LIR lir = gen.getLIR(); + assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; + + Stub stub = gen.getStub(); + Assembler masm = createAssembler(frameMap); + // On SPARC we always use stack frames. + HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null); + DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget()); + CompilationResultBuilder crb = factory.createBuilder(getProviders().getCodeCache(), getProviders().getForeignCalls(), frameMap, masm, dataBuilder, frameContext, compilationResult); + crb.setTotalFrameSize(frameMap.totalFrameSize()); + crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize()); + StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot(); + if (deoptimizationRescueSlot != null && stub == null) { + crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot); + } + + if (stub != null) { + // Even on sparc we need to save floating point registers + Set destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir); + Map calleeSaveInfo = gen.getCalleeSaveInfo(); + updateStub(stub, destroyedCallerRegisters, calleeSaveInfo, frameMap); + } + assert registerSizePredictionValidator(crb); + return crb; + } + + /** + * Registers a verifier which checks if the LIRInstructions estimate of constants size is + * greater or equal to the actual one. + */ + private static boolean registerSizePredictionValidator(final CompilationResultBuilder crb) { + /** + * Used to hold state between beforeOp and afterOp + */ + class ValidationState { + LIRInstruction op; + int constantSizeBefore; + + public void before(LIRInstruction before) { + assert op == null : "LIRInstruction " + op + " no after call received"; + op = before; + constantSizeBefore = calculateDataSectionSize(crb.compilationResult.getDataSection()); + } + + public void after(LIRInstruction after) { + assert after.equals(op) : "Instructions before/after don't match " + op + "/" + after; + int constantSizeAfter = calculateDataSectionSize(crb.compilationResult.getDataSection()); + int actual = constantSizeAfter - constantSizeBefore; + if (op instanceof SPARCLIRInstructionMixin) { + org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate size = ((SPARCLIRInstructionMixin) op).estimateSize(); + assert size != null : "No size prediction available for op: " + op; + Class c = op.getClass(); + CONSTANT_ESTIMATED_STATS.add(c, size.constantSize); + CONSTANT_ACTUAL_STATS.add(c, actual); + assert size.constantSize >= actual : "Op " + op + " exceeded estimated constant size; predicted: " + size.constantSize + " actual: " + actual; + } else { + assert actual == 0 : "Op " + op + " emitted to DataSection without any estimate."; + } + op = null; + constantSizeBefore = 0; + } + } + final ValidationState state = new ValidationState(); + crb.setOpCallback(op -> state.before(op), op -> state.after(op)); + return true; + } + + private static int calculateDataSectionSize(DataSection ds) { + int sum = 0; + for (Data d : ds) { + sum += d.getSize(); + } + return sum; + } + + @Override + public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) { + SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; + // TODO: (sa) Fold the two traversals into one + stuffDelayedControlTransfers(lir); + int constantSize = calculateConstantSize(lir); + boolean canUseImmediateConstantLoad = constantSize < (1 << 13); + masm.setImmediateConstantLoad(canUseImmediateConstantLoad); + FrameMap frameMap = crb.frameMap; + RegisterConfig regConfig = frameMap.getRegisterConfig(); + Label unverifiedStub = installedCodeOwner == null || installedCodeOwner.isStatic() ? null : new Label(); + for (int i = 0; i < 2; i++) { + if (i > 0) { + crb.resetForEmittingCode(); + lir.resetLabels(); + resetDelayedControlTransfers(lir); + } + + // Emit the prefix + if (unverifiedStub != null) { + crb.recordMark(config.MARKID_UNVERIFIED_ENTRY); + // We need to use JavaCall here because we haven't entered the frame yet. + CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCall, null, new JavaType[]{getProviders().getMetaAccess().lookupJavaType(Object.class)}, this); + Register inlineCacheKlass = g5; // see MacroAssembler::ic_call + + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + Register receiver = asRegister(cc.getArgument(0)); + SPARCAddress src = new SPARCAddress(receiver, config.hubOffset); + + masm.ldx(src, scratch); + masm.cmp(scratch, inlineCacheKlass); + } + BPCC.emit(masm, Xcc, NotEqual, NOT_ANNUL, PREDICT_NOT_TAKEN, unverifiedStub); + masm.nop(); // delay slot + } + + masm.align(config.codeEntryAlignment); + crb.recordMark(config.MARKID_OSR_ENTRY); + crb.recordMark(config.MARKID_VERIFIED_ENTRY); + + // Emit code for the LIR + crb.emit(lir); + } + profileInstructions(lir, crb); + + HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; + HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls(); + if (!frameContext.isStub) { + crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY); + SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, null); + crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); + SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, null); + } else { + // No need to emit the stubs for entries back into the method since + // it has no calls that can cause such "return" entries + } + + if (unverifiedStub != null) { + masm.bind(unverifiedStub); + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER)); + } + } + masm.peephole(); + } + + private static int calculateConstantSize(LIR lir) { + int size = 0; + for (AbstractBlockBase block : lir.codeEmittingOrder()) { + if (block == null) { + continue; + } + for (LIRInstruction inst : lir.getLIRforBlock(block)) { + if (inst instanceof SPARCLIRInstructionMixin) { + SizeEstimate pred = ((SPARCLIRInstructionMixin) inst).estimateSize(); + if (pred != null) { + size += pred.constantSize; + } + } + } + } + return size; + } + + private static void resetDelayedControlTransfers(LIR lir) { + for (AbstractBlockBase block : lir.codeEmittingOrder()) { + if (block == null) { + continue; + } + for (LIRInstruction inst : lir.getLIRforBlock(block)) { + if (inst instanceof SPARCDelayedControlTransfer) { + ((SPARCDelayedControlTransfer) inst).resetState(); + } + } + } + } + + /** + * Fix-up over whole LIR. + * + * @see #stuffDelayedControlTransfers(LIR, AbstractBlockBase) + * @param l + */ + private static void stuffDelayedControlTransfers(LIR l) { + for (AbstractBlockBase b : l.codeEmittingOrder()) { + if (b != null) { + stuffDelayedControlTransfers(l, b); + } + } + } + + /** + * Tries to put DelayedControlTransfer instructions and DelayableLIRInstructions together. Also + * it tries to move the DelayedLIRInstruction to the DelayedControlTransfer instruction, if + * possible. + */ + private static void stuffDelayedControlTransfers(LIR l, AbstractBlockBase block) { + List instructions = l.getLIRforBlock(block); + if (instructions.size() >= 2) { + LIRDependencyAccumulator acc = new LIRDependencyAccumulator(); + SPARCDelayedControlTransfer delayedTransfer = null; + int delayTransferPosition = -1; + for (int i = instructions.size() - 1; i >= 0; i--) { + LIRInstruction inst = instructions.get(i); + boolean adjacent = delayTransferPosition - i == 1; + if (!adjacent || inst.destroysCallerSavedRegisters() || leavesRegisterWindow(inst)) { + delayedTransfer = null; + } + if (inst instanceof SPARCDelayedControlTransfer) { + delayedTransfer = (SPARCDelayedControlTransfer) inst; + acc.start(inst); + delayTransferPosition = i; + } else if (delayedTransfer != null) { + boolean overlap = acc.add(inst); + if (!overlap && inst instanceof SPARCTailDelayedLIRInstruction) { + // We have found a non overlapping LIR instruction which can be delayed + ((SPARCTailDelayedLIRInstruction) inst).setDelayedControlTransfer(delayedTransfer); + delayedTransfer = null; + } + } + } + } + } + + private static boolean leavesRegisterWindow(LIRInstruction inst) { + return inst instanceof SPARCLIRInstructionMixin && ((SPARCLIRInstructionMixin) inst).leavesRegisterWindow(); + } + + /** + * Accumulates inputs/outputs/temp/alive in a set along we walk back the LIRInstructions and + * detects, if there is any overlap. In this way LIRInstructions can be detected, which can be + * moved nearer to the DelayedControlTransfer instruction. + */ + private static class LIRDependencyAccumulator { + private final Set inputs = new HashSet<>(10); + private boolean overlap = false; + + private final InstructionValueConsumer valueConsumer = (instruction, value, mode, flags) -> { + Object valueObject = value; + if (isRegister(value)) { // Canonicalize registers + valueObject = asRegister(value); + } + if (!inputs.add(valueObject)) { + overlap = true; + } + }; + + public void start(LIRInstruction initial) { + inputs.clear(); + overlap = false; + initial.visitEachInput(valueConsumer); + initial.visitEachTemp(valueConsumer); + initial.visitEachAlive(valueConsumer); + } + + /** + * Adds the inputs of lir instruction to the accumulator and returns, true if there was any + * overlap of parameters. + * + * @param inst + * @return true if an overlap was found + */ + public boolean add(LIRInstruction inst) { + overlap = false; + inst.visitEachOutput(valueConsumer); + inst.visitEachTemp(valueConsumer); + inst.visitEachInput(valueConsumer); + inst.visitEachAlive(valueConsumer); + return overlap; + } + } + + @Override + public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) { + RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; + return new SPARCHotSpotRegisterAllocationConfig(registerConfigNonNull); + } + + @Override + public Set translateToCallerRegisters(Set calleeRegisters) { + HashSet callerRegisters = new HashSet<>(calleeRegisters.size()); + for (Register register : calleeRegisters) { + if (l0.number <= register.number && register.number <= l7.number) { + // do nothing + } else if (o0.number <= register.number && register.number <= o7.number) { + // do nothing + } else if (i0.number <= register.number && register.number <= i7.number) { + // translate input to output registers + callerRegisters.add(translateInputToOutputRegister(register)); + } else { + callerRegisters.add(register); + } + } + return callerRegisters; + } + + private Register translateInputToOutputRegister(Register register) { + assert i0.number <= register.number && register.number <= i7.number : "Not an input register " + register; + return getTarget().arch.getRegisters().get(o0.number + register.number - i0.number); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java 2016-12-07 13:49:43.615067084 -0800 @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2012, 2016, 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.sparc; + +import java.util.HashSet; +import java.util.Set; + +import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.core.sparc.SPARCAddressLowering; +import org.graalvm.compiler.core.sparc.SPARCSuitesProvider; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotBackendFactory; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantFieldProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins; +import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegisters; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider; +import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider; +import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.spi.LoweringProvider; +import org.graalvm.compiler.nodes.spi.NodeCostProvider; +import org.graalvm.compiler.nodes.spi.Replacements; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider; +import org.graalvm.compiler.replacements.sparc.SPARCGraphBuilderPlugins; +import org.graalvm.compiler.serviceprovider.ServiceProvider; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.runtime.JVMCIBackend; +import jdk.vm.ci.sparc.SPARC; + +@ServiceProvider(HotSpotBackendFactory.class) +public class SPARCHotSpotBackendFactory implements HotSpotBackendFactory { + + @Override + public String getName() { + return "core"; + } + + @Override + public Class getArchitecture() { + return SPARC.class; + } + + @Override + public HotSpotBackend createBackend(HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotBackend host) { + assert host == null; + + GraalHotSpotVMConfig config = runtime.getVMConfig(); + JVMCIBackend jvmci = jvmciRuntime.getHostJVMCIBackend(); + HotSpotRegistersProvider registers = createRegisters(); + HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) jvmci.getMetaAccess(); + HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmci.getCodeCache(); + TargetDescription target = codeCache.getTarget(); + HotSpotConstantReflectionProvider constantReflection = (HotSpotConstantReflectionProvider) jvmci.getConstantReflection(); + HotSpotConstantFieldProvider constantFieldProvider = new HotSpotGraalConstantFieldProvider(config, metaAccess); + Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig()); + HotSpotWordTypes wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind); + HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters); + LoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, constantReflection, target); + HotSpotStampProvider stampProvider = new HotSpotStampProvider(); + NodeCostProvider nodeCostProvider = new SPARCHotSpotNodeCostProvider(); + Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, nodeCostProvider); + HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes); + BytecodeProvider bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection); + HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, bytecodeProvider, target); + Plugins plugins = createGraphBuilderPlugins(config, metaAccess, constantReflection, foreignCalls, stampProvider, snippetReflection, replacements, wordTypes); + replacements.setGraphBuilderPlugins(plugins); + HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, replacements); + HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, nodeCostProvider, suites, registers, + snippetReflection, + wordTypes, plugins); + + return createBackend(config, runtime, providers); + } + + protected Plugins createGraphBuilderPlugins(GraalHotSpotVMConfig config, HotSpotMetaAccessProvider metaAccess, HotSpotConstantReflectionProvider constantReflection, + HotSpotForeignCallsProvider foreignCalls, HotSpotStampProvider stampProvider, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, + HotSpotWordTypes wordTypes) { + Plugins plugins = HotSpotGraphBuilderPlugins.create(config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements); + SPARCGraphBuilderPlugins.register(plugins, replacements.getReplacementBytecodeProvider()); + return plugins; + } + + /** + * @param replacements + */ + protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins, + Replacements replacements) { + return new HotSpotSuitesProvider(new SPARCSuitesProvider(compilerConfiguration, plugins), config, runtime, new SPARCAddressLowering()); + } + + protected SPARCHotSpotBackend createBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { + return new SPARCHotSpotBackend(config, runtime, providers); + } + + protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, + HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, TargetDescription target) { + return new SPARCHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target); + } + + protected HotSpotRegistersProvider createRegisters() { + return new HotSpotRegisters(SPARC.g2, SPARC.g6, SPARC.sp); + } + + protected HotSpotNodeCostProvider createNodeCostProvider() { + return new SPARCHotSpotNodeCostProvider(); + } + + @SuppressWarnings("unused") + private static Value[] createNativeABICallerSaveRegisters(GraalHotSpotVMConfig config, RegisterConfig regConfig) { + Set callerSavedRegisters = new HashSet<>(); + SPARC.fpusRegisters.addTo(callerSavedRegisters); + SPARC.fpudRegisters.addTo(callerSavedRegisters); + callerSavedRegisters.add(SPARC.g1); + callerSavedRegisters.add(SPARC.g4); + callerSavedRegisters.add(SPARC.g5); + Value[] nativeABICallerSaveRegisters = new Value[callerSavedRegisters.size()]; + int i = 0; + for (Register reg : callerSavedRegisters) { + nativeABICallerSaveRegisters[i] = reg.asValue(); + i++; + } + return nativeABICallerSaveRegisters; + } + + @Override + public String toString() { + return "SPARC"; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java 2016-12-07 13:49:43.881078777 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2012, 2015, 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.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; + +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; +import org.graalvm.compiler.lir.sparc.SPARCMove; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.Value; + +@Opcode("CRUNTIME_CALL_EPILOGUE") +final class SPARCHotSpotCRuntimeCallEpilogueOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotCRuntimeCallEpilogueOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(11); + + private final int threadLastJavaSpOffset; + private final int threadLastJavaPcOffset; + private final int threadJavaFrameAnchorFlagsOffset; + private final Register thread; + @Use({REG, STACK}) protected Value threadTemp; + + SPARCHotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset, Register thread, Value threadTemp) { + super(TYPE, SIZE); + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.threadLastJavaPcOffset = threadLastJavaPcOffset; + this.threadJavaFrameAnchorFlagsOffset = threadJavaFrameAnchorFlagsOffset; + this.thread = thread; + this.threadTemp = threadTemp; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + + // Restore the thread register when coming back from the runtime. + SPARCMove.move(crb, masm, thread.asValue(LIRKind.value(XWORD)), threadTemp, SPARCDelayedControlTransfer.DUMMY); + + // Reset last Java frame, last Java PC and flags. + masm.stx(g0, new SPARCAddress(thread, threadLastJavaSpOffset)); + masm.stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)); + masm.stw(g0, new SPARCAddress(thread, threadJavaFrameAnchorFlagsOffset)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java 2016-12-07 13:49:44.145090381 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013, 2015, 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.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.STACK_BIAS; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; + +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; +import org.graalvm.compiler.lir.sparc.SPARCMove; +import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; + +@Opcode("CRUNTIME_CALL_PROLOGUE") +final class SPARCHotSpotCRuntimeCallPrologueOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotCRuntimeCallPrologueOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(10); + + private final int threadLastJavaSpOffset; + private final Register thread; + private final Register stackPointer; + @Def({REG, STACK}) protected Value threadTemp; + @Temp({REG}) protected AllocatableValue spScratch; + + SPARCHotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, Register thread, Register stackPointer, Value threadTemp, AllocatableValue spScratch) { + super(TYPE, SIZE); + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.thread = thread; + this.stackPointer = stackPointer; + this.threadTemp = threadTemp; + this.spScratch = spScratch; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + // Save last Java frame. + Register scratchRegister = asRegister(spScratch); + masm.add(stackPointer, STACK_BIAS, scratchRegister); + masm.stx(scratchRegister, new SPARCAddress(thread, threadLastJavaSpOffset)); + + // Save the thread register when calling out to the runtime. + SPARCMove.move(crb, masm, threadTemp, thread.asValue(LIRKind.value(XWORD)), getDelayedControlTransfer()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCounterOp.java 2016-12-07 13:49:44.411102074 -0800 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2015, 2015, 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.sparc; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13; +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.Assembler; +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import org.graalvm.compiler.hotspot.HotSpotCounterOp; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.Value; + +@Opcode("BenchMarkCounter") +public class SPARCHotSpotCounterOp extends HotSpotCounterOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotCounterOp.class); + + private int[] counterPatchOffsets; + + public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config) { + super(TYPE, name, group, increment, registers, config); + this.counterPatchOffsets = new int[1]; + } + + public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config) { + super(TYPE, names, groups, increments, registers, config); + this.counterPatchOffsets = new int[names.length]; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; + TargetDescription target = crb.target; + + // address for counters array + SPARCAddress countersArrayAddr = new SPARCAddress(thread, config.jvmciCountersThreadOffset); + try (ScratchRegister scratch = masm.getScratchRegister()) { + Register countersArrayReg = scratch.getRegister(); + + // load counters array + masm.ldx(countersArrayAddr, countersArrayReg); + IncrementEmitter emitter = new IncrementEmitter(countersArrayReg, masm); + forEachCounter(emitter, target); + } + } + + private void emitIncrement(int counterIndex, SPARCMacroAssembler masm, SPARCAddress counterAddr, Value increment) { + try (ScratchRegister scratch = masm.getScratchRegister()) { + Register counterReg = scratch.getRegister(); + // load counter value + masm.ldx(counterAddr, counterReg); + counterPatchOffsets[counterIndex] = masm.position(); + // increment counter + if (isJavaConstant(increment)) { + masm.add(counterReg, asInt(asJavaConstant(increment)), counterReg); + } else { + masm.add(counterReg, asRegister(increment), counterReg); + } + // store counter value + masm.stx(counterReg, counterAddr); + } + } + + /** + * Patches the increment value in the instruction emitted by the + * {@link #emitIncrement(int, SPARCMacroAssembler, SPARCAddress, Value)} method. This method is + * used if patching is needed after assembly. + * + * @param asm + * @param increment + */ + @Override + public void patchCounterIncrement(Assembler asm, int[] increment) { + for (int i = 0; i < increment.length; i++) { + int inst = counterPatchOffsets[i]; + ((SPARCAssembler) asm).patchAddImmediate(inst, increment[i]); + } + } + + public int[] getCounterPatchOffsets() { + return counterPatchOffsets; + } + + private class IncrementEmitter implements CounterProcedure { + private int lastDisplacement = 0; + private final Register countersArrayReg; + private final SPARCMacroAssembler masm; + + IncrementEmitter(Register countersArrayReg, SPARCMacroAssembler masm) { + super(); + this.countersArrayReg = countersArrayReg; + this.masm = masm; + } + + @Override + public void apply(int counterIndex, Value increment, int displacement) { + SPARCAddress counterAddr; + int relativeDisplacement = displacement - lastDisplacement; + if (isSimm13(relativeDisplacement)) { // Displacement fits into ld instruction + counterAddr = new SPARCAddress(countersArrayReg, relativeDisplacement); + } else { + try (ScratchRegister scratch = masm.getScratchRegister()) { + Register tempOffsetRegister = scratch.getRegister(); + masm.setx(relativeDisplacement, tempOffsetRegister, false); + masm.add(countersArrayReg, tempOffsetRegister, countersArrayReg); + } + lastDisplacement = displacement; + counterAddr = new SPARCAddress(countersArrayReg, 0); + } + emitIncrement(counterIndex, masm, counterAddr, increment); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java 2016-12-07 13:49:44.677113766 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.sparc; + +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCCall; + +import jdk.vm.ci.code.Register; + +/** + * Removes the current frame and tail calls the uncommon trap routine. + */ +@Opcode("DEOPT_CALLER") +final class SPARCHotSpotDeoptimizeCallerOp extends SPARCHotSpotEpilogueOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotDeoptimizeCallerOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(32); + + protected SPARCHotSpotDeoptimizeCallerOp() { + super(TYPE, SIZE); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + leaveFrame(crb); + + // SPARCHotSpotBackend backend = (SPARCHotSpotBackend) + // HotSpotGraalRuntime.runtime().getBackend(); + // final boolean isStub = true; + // HotSpotFrameContext frameContext = backend.new HotSpotFrameContext(isStub); + // frameContext.enter(crb); + + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + SPARCCall.indirectJmp(crb, masm, scratch, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER)); + } + + // frameContext.leave(crb); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java 2016-12-07 13:49:44.941125371 -0800 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2014, 2015, 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.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.STACK_BIAS; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARC.i0; +import static jdk.vm.ci.sparc.SPARC.i1; +import static jdk.vm.ci.sparc.SPARC.i2; +import static jdk.vm.ci.sparc.SPARC.i3; +import static jdk.vm.ci.sparc.SPARC.i4; +import static jdk.vm.ci.sparc.SPARC.l7; +import static jdk.vm.ci.sparc.SPARC.o0; +import static jdk.vm.ci.sparc.SPARC.o1; +import static jdk.vm.ci.sparc.SPARC.o2; +import static jdk.vm.ci.sparc.SPARC.o3; +import static jdk.vm.ci.sparc.SPARC.o4; +import static jdk.vm.ci.sparc.SPARC.o5; +import static jdk.vm.ci.sparc.SPARC.o7; +import static jdk.vm.ci.sparc.SPARC.sp; + +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.PlatformKind; + +/** + * Emits code that enters a stack frame which is tailored to call the C++ method + * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}. + */ +@Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME") +final class SPARCHotSpotEnterUnpackFramesStackFrameOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotEnterUnpackFramesStackFrameOp.class); + + private final Register thread; + private final int threadLastJavaSpOffset; + private final int threadLastJavaPcOffset; + @Alive(REG) AllocatableValue framePc; + @Alive(REG) AllocatableValue senderSp; + @Temp(REG) AllocatableValue scratch; + @Temp(REG) AllocatableValue callerReturnPc; + + SPARCHotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue scratch, + PlatformKind wordKind) { + super(TYPE); + this.thread = thread; + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.threadLastJavaPcOffset = threadLastJavaPcOffset; + this.framePc = framePc; + this.senderSp = senderSp; + this.scratch = scratch; + callerReturnPc = o7.asValue(LIRKind.value(wordKind)); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + final int totalFrameSize = crb.frameMap.totalFrameSize(); + Register framePcRegister = asRegister(framePc); + Register senderSpRegister = asRegister(senderSp); + Register scratchRegister = asRegister(scratch); + + // Save final sender SP to O5_savedSP. + masm.mov(senderSpRegister, o5); + + // Load final frame PC. + masm.mov(framePcRegister, asRegister(callerReturnPc)); + + // Allocate a full sized frame. + masm.save(sp, -totalFrameSize, sp); + + masm.mov(i0, o0); + masm.mov(i1, o1); + masm.mov(i2, o2); + masm.mov(i3, o3); + masm.mov(i4, o4); + + // Set up last Java values. + masm.add(sp, STACK_BIAS, scratchRegister); + masm.stx(scratchRegister, new SPARCAddress(thread, threadLastJavaSpOffset)); + + // Clear last Java PC. + masm.stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)); + + /* + * Safe thread register manually since we are not using LEAF_SP for {@link + * DeoptimizationStub#UNPACK_FRAMES}. + */ + masm.mov(thread, l7); + } + + @Override + public boolean leavesRegisterWindow() { + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotEpilogueOp.java 2016-12-07 13:49:45.208137107 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 2015, 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.sparc; + +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCBlockEndOp; + +/** + * Superclass for operations that leave a method's frame. + */ +abstract class SPARCHotSpotEpilogueOp extends SPARCBlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotEpilogueOp.class); + + protected SPARCHotSpotEpilogueOp(LIRInstructionClass c, SizeEstimate size) { + super(c, size); + } + + protected void leaveFrame(CompilationResultBuilder crb) { + crb.frameContext.leave(crb); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java 2016-12-07 13:49:45.473148756 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2013, 2016, 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.sparc; + +import static org.graalvm.compiler.core.common.LocationIdentity.any; +import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER; +import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER; +import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NOFP; +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPTIMIZATION_HANDLER; +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; +import static org.graalvm.compiler.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32; +import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall; +import static jdk.vm.ci.meta.Value.ILLEGAL; +import static jdk.vm.ci.sparc.SPARC.i0; +import static jdk.vm.ci.sparc.SPARC.i1; +import static jdk.vm.ci.sparc.SPARC.o0; +import static jdk.vm.ci.sparc.SPARC.o1; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +public class SPARCHotSpotForeignCallsProvider extends HotSpotHostForeignCallsProvider { + + private final Value[] nativeABICallerSaveRegisters; + + public SPARCHotSpotForeignCallsProvider(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache, + WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) { + super(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes); + this.nativeABICallerSaveRegisters = nativeABICallerSaveRegisters; + } + + @Override + public void initialize(HotSpotProviders providers) { + GraalHotSpotVMConfig config = runtime.getVMConfig(); + TargetDescription target = providers.getCodeCache().getTarget(); + PlatformKind word = target.arch.getWordKind(); + + // The calling convention for the exception handler stub is (only?) defined in + // TemplateInterpreterGenerator::generate_throw_exception() + // in templateInterpreter_sparc.cpp around line 1925 + RegisterValue outgoingException = o0.asValue(LIRKind.fromJavaKind(target.arch, JavaKind.Object)); + RegisterValue outgoingExceptionPc = o1.asValue(LIRKind.value(word)); + RegisterValue incomingException = i0.asValue(LIRKind.fromJavaKind(target.arch, JavaKind.Object)); + RegisterValue incomingExceptionPc = i1.asValue(LIRKind.value(word)); + CallingConvention outgoingExceptionCc = new CallingConvention(0, ILLEGAL, outgoingException, outgoingExceptionPc); + CallingConvention incomingExceptionCc = new CallingConvention(0, ILLEGAL, incomingException, incomingExceptionPc); + register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, any())); + register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, any())); + + if (PreferGraalStubs.getValue()) { + link(new SPARCDeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS))); + link(new SPARCUncommonTrapStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS))); + } + + if (config.useCRC32Intrinsics) { + // This stub does callee saving + registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any()); + } + + super.initialize(providers); + } + + @Override + public Value[] getNativeABICallerSaveRegisters() { + return nativeABICallerSaveRegisters; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java 2016-12-07 13:49:45.739160448 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, 2015, 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.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARC.l7; +import static jdk.vm.ci.sparc.SPARC.sp; + +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Sets up the arguments for an exception handler in the callers frame, removes the current frame + * and jumps to the handler. + */ +@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER") +final class SPARCHotSpotJumpToExceptionHandlerInCallerOp extends SPARCHotSpotEpilogueOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotJumpToExceptionHandlerInCallerOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(5); + + @Use(REG) AllocatableValue handlerInCallerPc; + @Use(REG) AllocatableValue exception; + @Use(REG) AllocatableValue exceptionPc; + private final Register thread; + private final int isMethodHandleReturnOffset; + + SPARCHotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc, int isMethodHandleReturnOffset, Register thread) { + super(TYPE, SIZE); + this.handlerInCallerPc = handlerInCallerPc; + this.exception = exception; + this.exceptionPc = exceptionPc; + this.isMethodHandleReturnOffset = isMethodHandleReturnOffset; + this.thread = thread; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + // Restore SP from L7 if the exception PC is a method handle call site. + SPARCAddress dst = new SPARCAddress(thread, isMethodHandleReturnOffset); + try (ScratchRegister scratch = masm.getScratchRegister()) { + Register scratchReg = scratch.getRegister(); + masm.lduw(dst, scratchReg); + masm.cmp(scratchReg, scratchReg); + masm.movcc(ConditionFlag.NotZero, CC.Icc, l7, sp); + } + masm.jmpl(asRegister(handlerInCallerPc), 0, g0); + leaveFrame(crb); // Delay slot + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerOp.java 2016-12-07 13:49:46.003172053 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, 2015, 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.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.sparc.SPARCKind; + +/** + * Jumps to the exception handler specified by {@link #address} and leaves the current window. It + * does not modify the i7 register, as the exception handler stub expects the throwing pc in it. + *

+ * See also: + *

  • Runtime1::generate_handle_exception c1_Runtime1_sparc.cpp + *
  • SharedRuntime::generate_deopt_blob at exception_in_tls_offset (sharedRuntime_sparc.cpp) + */ +@Opcode("JUMP_TO_EXCEPTION_HANDLER") +final class SPARCHotSpotJumpToExceptionHandlerOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotJumpToExceptionHandlerOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(2); + + @Use(REG) AllocatableValue address; + + SPARCHotSpotJumpToExceptionHandlerOp(AllocatableValue address) { + super(TYPE, SIZE); + this.address = address; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Register addrRegister = asRegister(address, SPARCKind.XWORD); + masm.jmp(addrRegister); + masm.restoreWindow(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java 2016-12-07 13:49:46.267183657 -0800 @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2013, 2016, 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.sparc; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.FETCH_UNROLL_INFO; +import static org.graalvm.compiler.hotspot.HotSpotBackend.UNCOMMON_TRAP; +import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; +import static jdk.vm.ci.sparc.SPARC.d32; +import static jdk.vm.ci.sparc.SPARC.d34; +import static jdk.vm.ci.sparc.SPARC.d36; +import static jdk.vm.ci.sparc.SPARC.d38; +import static jdk.vm.ci.sparc.SPARC.d40; +import static jdk.vm.ci.sparc.SPARC.d42; +import static jdk.vm.ci.sparc.SPARC.d44; +import static jdk.vm.ci.sparc.SPARC.d46; +import static jdk.vm.ci.sparc.SPARC.d48; +import static jdk.vm.ci.sparc.SPARC.d50; +import static jdk.vm.ci.sparc.SPARC.d52; +import static jdk.vm.ci.sparc.SPARC.d54; +import static jdk.vm.ci.sparc.SPARC.d56; +import static jdk.vm.ci.sparc.SPARC.d58; +import static jdk.vm.ci.sparc.SPARC.d60; +import static jdk.vm.ci.sparc.SPARC.d62; +import static jdk.vm.ci.sparc.SPARC.f0; +import static jdk.vm.ci.sparc.SPARC.f10; +import static jdk.vm.ci.sparc.SPARC.f12; +import static jdk.vm.ci.sparc.SPARC.f14; +import static jdk.vm.ci.sparc.SPARC.f16; +import static jdk.vm.ci.sparc.SPARC.f18; +import static jdk.vm.ci.sparc.SPARC.f2; +import static jdk.vm.ci.sparc.SPARC.f20; +import static jdk.vm.ci.sparc.SPARC.f22; +import static jdk.vm.ci.sparc.SPARC.f24; +import static jdk.vm.ci.sparc.SPARC.f26; +import static jdk.vm.ci.sparc.SPARC.f28; +import static jdk.vm.ci.sparc.SPARC.f30; +import static jdk.vm.ci.sparc.SPARC.f4; +import static jdk.vm.ci.sparc.SPARC.f6; +import static jdk.vm.ci.sparc.SPARC.f8; +import static jdk.vm.ci.sparc.SPARC.g1; +import static jdk.vm.ci.sparc.SPARC.g3; +import static jdk.vm.ci.sparc.SPARC.g4; +import static jdk.vm.ci.sparc.SPARC.g5; +import static jdk.vm.ci.sparc.SPARCKind.WORD; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; + +import java.util.Map; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.core.sparc.SPARCArithmeticLIRGenerator; +import org.graalvm.compiler.core.sparc.SPARCLIRGenerator; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.CompressEncoding; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.HotSpotLockStack; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.debug.BenchmarkCounters; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.sparc.SPARCAddressValue; +import org.graalvm.compiler.lir.sparc.SPARCControlFlow.StrategySwitchOp; +import org.graalvm.compiler.lir.sparc.SPARCFrameMapBuilder; +import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue; +import org.graalvm.compiler.lir.sparc.SPARCMove.CompareAndSwapOp; +import org.graalvm.compiler.lir.sparc.SPARCMove.NullCheckOp; +import org.graalvm.compiler.lir.sparc.SPARCMove.StoreOp; +import org.graalvm.compiler.lir.sparc.SPARCPrefetchOp; +import org.graalvm.compiler.lir.sparc.SPARCSaveRegistersOp; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; +import jdk.vm.ci.sparc.SPARC; +import jdk.vm.ci.sparc.SPARCKind; + +public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator { + + final GraalHotSpotVMConfig config; + private HotSpotDebugInfoBuilder debugInfoBuilder; + private LIRFrameState currentRuntimeCallInfo; + + public SPARCHotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) { + this(providers, config, lirGenRes, new ConstantTableBaseProvider()); + } + + private SPARCHotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) { + this(new SPARCHotSpotLIRKindTool(), new SPARCArithmeticLIRGenerator(), new SPARCHotSpotMoveFactory(constantTableBaseProvider), providers, config, lirGenRes, constantTableBaseProvider); + } + + public SPARCHotSpotLIRGenerator(LIRKindTool lirKindTool, SPARCArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config, + LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) { + super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes, constantTableBaseProvider); + assert config.basicLockSize == 8; + this.config = config; + } + + @Override + public HotSpotProviders getProviders() { + return (HotSpotProviders) super.getProviders(); + } + + /** + * The slot reserved for storing the original return address when a frame is marked for + * deoptimization. The return address slot in the callee is overwritten with the address of a + * deoptimization stub. + */ + private StackSlot deoptimizationRescueSlot; + + /** + * Value where the address for safepoint poll is kept. + */ + private AllocatableValue safepointAddressValue; + + @Override + public VirtualStackSlot getLockSlot(int lockDepth) { + return getLockStack().makeLockSlot(lockDepth); + } + + private HotSpotLockStack getLockStack() { + assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null; + return debugInfoBuilder.lockStack(); + } + + @Override + public boolean needOnlyOopMaps() { + // Stubs only need oop maps + return getStub() != null; + } + + public Stub getStub() { + return getResult().getStub(); + } + + @Override + public HotSpotLIRGenerationResult getResult() { + return ((HotSpotLIRGenerationResult) super.getResult()); + } + + @Override + public void beforeRegisterAllocation() { + super.beforeRegisterAllocation(); + boolean hasDebugInfo = getResult().getLIR().hasDebugInfo(); + if (hasDebugInfo) { + getResult().setDeoptimizationRescueSlot(((SPARCFrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot()); + } + + getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize()); + } + + @Override + protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + currentRuntimeCallInfo = info; + super.emitForeignCallOp(linkage, result, arguments, temps, info); + } + + @Override + public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) { + HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage; + Variable result; + LIRFrameState debugInfo = null; + if (hotspotLinkage.needsDebugInfo()) { + debugInfo = state; + assert debugInfo != null || getStub() != null; + } + + if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) { + HotSpotRegistersProvider registers = getProviders().getRegisters(); + Register thread = registers.getThreadRegister(); + Value threadTemp = newVariable(LIRKind.value(SPARCKind.XWORD)); + Register stackPointer = registers.getStackPointerRegister(); + Variable spScratch = newVariable(LIRKind.value(target().arch.getWordKind())); + append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread, stackPointer, threadTemp, spScratch)); + result = super.emitForeignCall(hotspotLinkage, debugInfo, args); + append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), thread, threadTemp)); + } else { + result = super.emitForeignCall(hotspotLinkage, debugInfo, args); + } + + return result; + } + + @Override + public void emitReturn(JavaKind javaKind, Value input) { + AllocatableValue operand = Value.ILLEGAL; + if (input != null) { + operand = resultOperandFor(javaKind, input.getValueKind()); + emitMove(operand, input); + } + append(new SPARCHotSpotReturnOp(operand, getStub() != null, config, getSafepointAddressValue())); + } + + @Override + public void emitTailcall(Value[] args, Value address) { + throw GraalError.unimplemented(); + } + + @Override + public void emitUnwind(Value exception) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); + CallingConvention linkageCc = linkage.getOutgoingCallingConvention(); + assert linkageCc.getArgumentCount() == 2; + RegisterValue exceptionParameter = (RegisterValue) linkageCc.getArgument(0); + emitMove(exceptionParameter, exception); + append(new SPARCHotSpotUnwindOp(exceptionParameter)); + } + + private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) { + moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset); + moveValueToThread(speculation, config.pendingFailedSpeculationOffset); + } + + private void moveValueToThread(Value v, int offset) { + LIRKind wordKind = LIRKind.value(target().arch.getWordKind()); + RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind); + SPARCAddressValue pendingDeoptAddress = new SPARCImmediateAddressValue(wordKind, thread, offset); + append(new StoreOp(v.getPlatformKind(), pendingDeoptAddress, load(v), null)); + } + + @Override + public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) { + moveDeoptValuesToThread(actionAndReason, speculation); + append(new SPARCDeoptimizeOp(state, target().arch.getWordKind())); + } + + @Override + public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { + Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0)); + Value nullValue = emitJavaConstant(JavaConstant.NULL_POINTER); + moveDeoptValuesToThread(actionAndReason, nullValue); + append(new SPARCHotSpotDeoptimizeCallerOp()); + } + + @Override + public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { + ValueKind kind = newValue.getValueKind(); + assert kind.equals(expectedValue.getValueKind()); + SPARCKind memKind = (SPARCKind) kind.getPlatformKind(); + Variable result = newVariable(newValue.getValueKind()); + append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue))); + return emitConditionalMove(memKind, expectedValue, result, Condition.EQ, true, trueValue, falseValue); + } + + @Override + public void emitPrefetchAllocate(Value address) { + SPARCAddressValue addr = asAddressValue(address); + append(new SPARCPrefetchOp(addr, config.allocatePrefetchInstr)); + } + + public StackSlot getDeoptimizationRescueSlot() { + return deoptimizationRescueSlot; + } + + @Override + public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, + double trueDestinationProbability) { + Value localX = x; + Value localY = y; + if (localX instanceof HotSpotObjectConstant) { + localX = load(localX); + } + if (localY instanceof HotSpotObjectConstant) { + localY = load(localY); + } + super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability); + } + + @Override + protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) { + Value localA = a; + Value localB = b; + if (isConstantValue(a)) { + Constant c = asConstant(a); + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { + localA = SPARC.g0.asValue(LIRKind.value(WORD)); + } else if (c instanceof HotSpotObjectConstant) { + localA = load(localA); + } + } + if (isConstantValue(b)) { + Constant c = asConstant(b); + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { + localB = SPARC.g0.asValue(LIRKind.value(WORD)); + } else if (c instanceof HotSpotObjectConstant) { + localB = load(localB); + } + } + return super.emitCompare(cmpKind, localA, localB); + } + + @Override + public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) { + LIRKind inputKind = pointer.getValueKind(LIRKind.class); + assert inputKind.getPlatformKind() == XWORD : inputKind; + if (inputKind.isReference(0)) { + // oop + Variable result = newVariable(LIRKind.reference(WORD)); + append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); + return result; + } else { + // metaspace pointer + Variable result = newVariable(LIRKind.value(WORD)); + AllocatableValue base = Value.ILLEGAL; + if (encoding.base != 0) { + base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.base)); + } + append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); + return result; + } + } + + @Override + public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) { + LIRKind inputKind = pointer.getValueKind(LIRKind.class); + assert inputKind.getPlatformKind() == WORD; + if (inputKind.isReference(0)) { + // oop + Variable result = newVariable(LIRKind.reference(XWORD)); + append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); + return result; + } else { + // metaspace pointer + Variable result = newVariable(LIRKind.value(XWORD)); + AllocatableValue base = Value.ILLEGAL; + if (encoding.base != 0) { + base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.base)); + } + append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); + return result; + } + } + + /** + * @param savedRegisters the registers saved by this operation which may be subject to pruning + * @param savedRegisterLocations the slots to which the registers are saved + * @param supportsRemove determines if registers can be pruned + */ + protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) { + SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove); + append(save); + return save; + } + + @Override + public SaveRegistersOp emitSaveAllRegisters() { + // We save all registers that were not saved by the save instruction. + // @formatter:off + Register[] savedRegisters = { + // CPU + g1, g3, g4, g5, + // FPU, use only every second register as doubles are stored anyways + f0, /*f1, */ f2, /*f3, */ f4, /*f5, */ f6, /*f7, */ + f8, /*f9, */ f10, /*f11,*/ f12, /*f13,*/ f14, /*f15,*/ + f16, /*f17,*/ f18, /*f19,*/ f20, /*f21,*/ f22, /*f23,*/ + f24, /*f25,*/ f26, /*f27,*/ f28, /*f29,*/ f30, /*f31 */ + d32, d34, d36, d38, + d40, d42, d44, d46, + d48, d50, d52, d54, + d56, d58, d60, d62 + }; + // @formatter:on + AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length]; + for (int i = 0; i < savedRegisters.length; i++) { + PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory()); + VirtualStackSlot spillSlot = getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind)); + savedRegisterLocations[i] = spillSlot; + } + return emitSaveRegisters(savedRegisters, savedRegisterLocations, false); + } + + @Override + public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) { + append(new SPARCHotSpotLeaveCurrentStackFrameOp()); + } + + @Override + public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) { + append(new SPARCHotSpotLeaveDeoptimizedStackFrameOp()); + } + + @Override + public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) { + Register thread = getProviders().getRegisters().getThreadRegister(); + Variable framePcVariable = load(framePc); + Variable senderSpVariable = load(senderSp); + Variable scratchVariable = newVariable(LIRKind.value(target().arch.getWordKind())); + append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable, + target().arch.getWordKind())); + } + + @Override + public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) { + Register thread = getProviders().getRegisters().getThreadRegister(); + append(new SPARCHotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset())); + } + + @Override + public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) { + Variable frameSizeVariable = load(frameSize); + Variable framePcVariable = load(framePc); + Variable senderSpVariable = load(senderSp); + Variable initialInfoVariable = load(initialInfo); + append(new SPARCHotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable)); + } + + @Override + public Value emitUncommonTrapCall(Value trapRequest, Value mode, SaveRegistersOp saveRegisterOp) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP); + + Register threadRegister = getProviders().getRegisters().getThreadRegister(); + Value threadTemp = newVariable(LIRKind.value(target().arch.getWordKind())); + Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister(); + Variable spScratch = newVariable(LIRKind.value(target().arch.getWordKind())); + append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp, spScratch)); + Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(target().arch.getWordKind())), trapRequest, mode); + append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister, threadTemp)); + + Map calleeSaveInfo = getResult().getCalleeSaveInfo(); + assert currentRuntimeCallInfo != null; + assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); + calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp); + + return result; + } + + @Override + public Value emitDeoptimizationFetchUnrollInfoCall(Value mode, SaveRegistersOp saveRegisterOp) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(FETCH_UNROLL_INFO); + + Register threadRegister = getProviders().getRegisters().getThreadRegister(); + Value threadTemp = newVariable(LIRKind.value(target().arch.getWordKind())); + Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister(); + Variable spScratch = newVariable(LIRKind.value(target().arch.getWordKind())); + append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp, spScratch)); + Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(target().arch.getWordKind())), mode); + append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister, threadTemp)); + + Map calleeSaveInfo = getResult().getCalleeSaveInfo(); + assert currentRuntimeCallInfo != null; + assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); + calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp); + + return result; + } + + @Override + public void emitNullCheck(Value address, LIRFrameState state) { + PlatformKind kind = address.getPlatformKind(); + if (kind == WORD) { + CompressEncoding encoding = config.getOopEncoding(); + Value uncompressed = emitUncompress(address, encoding, false); + append(new NullCheckOp(asAddressValue(uncompressed), state)); + } else { + super.emitNullCheck(address, state); + } + } + + @Override + public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) { + if (BenchmarkCounters.enabled) { + return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config); + } + throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!"); + } + + @Override + public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) { + if (BenchmarkCounters.enabled) { + return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config); + } + throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!"); + } + + public AllocatableValue getSafepointAddressValue() { + if (this.safepointAddressValue == null) { + this.safepointAddressValue = newVariable(LIRKind.value(target().arch.getWordKind())); + } + return this.safepointAddressValue; + } + + @Override + protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue) { + return new SPARCHotSpotStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue); + } + + public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) { + this.debugInfoBuilder = debugInfoBuilder; + } + + @Override + public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) { + throw GraalError.unimplemented(); + } + + @Override + public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) { + throw GraalError.unimplemented(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRKindTool.java 2016-12-07 13:49:46.534195394 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 2015, 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.sparc; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.sparc.SPARCLIRKindTool; +import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool; + +import jdk.vm.ci.sparc.SPARCKind; + +public class SPARCHotSpotLIRKindTool extends SPARCLIRKindTool implements HotSpotLIRKindTool { + + @Override + public LIRKind getNarrowOopKind() { + return LIRKind.reference(SPARCKind.WORD); + } + + @Override + public LIRKind getNarrowPointerKind() { + return LIRKind.value(SPARCKind.WORD); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java 2016-12-07 13:49:46.798206999 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014, 2015, 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.sparc; + +import static jdk.vm.ci.sparc.SPARC.i0; +import static jdk.vm.ci.sparc.SPARC.i1; +import static jdk.vm.ci.sparc.SPARC.i2; +import static jdk.vm.ci.sparc.SPARC.i3; +import static jdk.vm.ci.sparc.SPARC.i4; +import static jdk.vm.ci.sparc.SPARC.o0; +import static jdk.vm.ci.sparc.SPARC.o1; +import static jdk.vm.ci.sparc.SPARC.o2; +import static jdk.vm.ci.sparc.SPARC.o3; +import static jdk.vm.ci.sparc.SPARC.o4; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; + +/** + * Pops the current frame off the stack. + */ +@Opcode("LEAVE_CURRENT_STACK_FRAME") +final class SPARCHotSpotLeaveCurrentStackFrameOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotLeaveCurrentStackFrameOp.class); + + SPARCHotSpotLeaveCurrentStackFrameOp() { + super(TYPE); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + // Save O registers over restore. + masm.mov(o0, i0); + masm.mov(o1, i1); + masm.mov(o2, i2); + masm.mov(o3, i3); + masm.mov(o4, i4); + + crb.frameContext.leave(crb); + } + + @Override + public boolean leavesRegisterWindow() { + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java 2016-12-07 13:49:47.063218647 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014, 2015, 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.sparc; + +import static jdk.vm.ci.sparc.SPARC.i0; +import static jdk.vm.ci.sparc.SPARC.i1; +import static jdk.vm.ci.sparc.SPARC.i2; +import static jdk.vm.ci.sparc.SPARC.i3; +import static jdk.vm.ci.sparc.SPARC.i4; +import static jdk.vm.ci.sparc.SPARC.o0; +import static jdk.vm.ci.sparc.SPARC.o1; +import static jdk.vm.ci.sparc.SPARC.o2; +import static jdk.vm.ci.sparc.SPARC.o3; +import static jdk.vm.ci.sparc.SPARC.o4; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; + +/** + * Pops the current frame off the stack including the return address. + */ +@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME") +final class SPARCHotSpotLeaveDeoptimizedStackFrameOp extends SPARCLIRInstruction { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotLeaveDeoptimizedStackFrameOp.class); + + protected SPARCHotSpotLeaveDeoptimizedStackFrameOp() { + super(TYPE); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + // Save O registers over restore. + masm.mov(o0, i0); + masm.mov(o1, i1); + masm.mov(o2, i2); + masm.mov(o3, i3); + masm.mov(o4, i4); + + masm.restoreWindow(); + } + + @Override + public boolean leavesRegisterWindow() { + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java 2016-12-07 13:49:47.328230295 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014, 2015, 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.sparc; + +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARC.i0; +import static jdk.vm.ci.sparc.SPARC.l7; + +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; +import org.graalvm.compiler.lir.sparc.SPARCSaveRegistersOp; + +import jdk.vm.ci.code.Register; + +/** + * Emits code that leaves a stack frame which is tailored to call the C++ method + * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}. + */ +@Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME") +final class SPARCHotSpotLeaveUnpackFramesStackFrameOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotLeaveUnpackFramesStackFrameOp.class); + + private final Register thread; + private final int threadLastJavaSpOffset; + private final int threadLastJavaPcOffset; + private final int threadJavaFrameAnchorFlagsOffset; + + SPARCHotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset) { + super(TYPE); + this.thread = thread; + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.threadLastJavaPcOffset = threadLastJavaPcOffset; + this.threadJavaFrameAnchorFlagsOffset = threadJavaFrameAnchorFlagsOffset; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + /* + * Safe thread register manually since we are not using LEAF_SP for {@link + * DeoptimizationStub#UNPACK_FRAMES}. + */ + masm.mov(l7, thread); + + SPARCAddress lastJavaPc = new SPARCAddress(thread, threadLastJavaPcOffset); + + // We borrow the threads lastJavaPC to transfer the value from float to i0 + masm.stdf(SPARCSaveRegistersOp.RETURN_REGISTER_STORAGE, lastJavaPc); + masm.ldx(lastJavaPc, i0); + + // Clear last Java frame values. + masm.stx(g0, lastJavaPc); + masm.stx(g0, new SPARCAddress(thread, threadLastJavaSpOffset)); + masm.stw(g0, new SPARCAddress(thread, threadJavaFrameAnchorFlagsOffset)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLoweringProvider.java 2016-12-07 13:49:47.594241988 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, 2015, 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.sparc; + +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.nodes.calc.FloatConvertNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; + +public class SPARCHotSpotLoweringProvider extends DefaultHotSpotLoweringProvider { + + public SPARCHotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, + HotSpotConstantReflectionProvider constantReflection, TargetDescription target) { + super(runtime, metaAccess, foreignCalls, registers, constantReflection, target); + } + + @Override + public void lower(Node n, LoweringTool tool) { + if (n instanceof FloatConvertNode) { + // FloatConvertNodes are handled in SPARCLIRGenerator.emitConvert + } else { + super.lower(n, tool); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java 2016-12-07 13:49:47.859253636 -0800 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2013, 2016, 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.sparc; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPR; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static org.graalvm.compiler.lir.sparc.SPARCMove.loadFromConstantTable; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import org.graalvm.compiler.hotspot.CompressEncoding; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.StandardOp.LoadConstantOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; +import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; + +public class SPARCHotSpotMove { + + public static class LoadHotSpotObjectConstantInline extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction, LoadConstantOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadHotSpotObjectConstantInline.class); + + public static final SizeEstimate SIZE = SizeEstimate.create(8); + private HotSpotConstant constant; + @Def({REG, STACK}) AllocatableValue result; + + public LoadHotSpotObjectConstantInline(HotSpotConstant constant, AllocatableValue result) { + super(TYPE, SIZE); + this.constant = constant; + this.result = result; + } + + @Override + protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + crb.recordInlineDataInCode(constant); + if (constant.isCompressed()) { + masm.setw(0, asRegister(result), true); + } else { + masm.setx(0, asRegister(result), true); + } + } + + @Override + public AllocatableValue getResult() { + return result; + } + + @Override + public Constant getConstant() { + return constant; + } + } + + public static class LoadHotSpotObjectConstantFromTable extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadHotSpotObjectConstantFromTable.class); + + public static final SizeEstimate SIZE = SizeEstimate.create(2, 8); + private final HotSpotConstant constant; + @Use({REG}) private AllocatableValue constantTableBase; + @Def({REG, STACK}) AllocatableValue result; + + public LoadHotSpotObjectConstantFromTable(HotSpotConstant constant, AllocatableValue result, AllocatableValue constantTableBase) { + super(TYPE, SIZE); + this.constant = constant; + this.result = result; + this.constantTableBase = constantTableBase; + } + + @Override + protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + try (ScratchRegister scratch = masm.getScratchRegister()) { + boolean isStack = ValueUtil.isStackSlot(result); + Register register; + if (isStack) { + register = scratch.getRegister(); + } else { + register = asRegister(result); + } + int bytes = result.getPlatformKind().getSizeInBytes(); + loadFromConstantTable(crb, masm, bytes, asRegister(constantTableBase), constant, register, SPARCDelayedControlTransfer.DUMMY); + if (isStack) { + masm.st(register, (SPARCAddress) crb.asAddress(result), bytes); + } + } + } + } + + public static final class CompressPointer extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompressPointer.class); + public static final SizeEstimate SIZE = SizeEstimate.create(5); + + private final CompressEncoding encoding; + private final boolean nonNull; + + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue input; + @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; + + public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { + super(TYPE, SIZE); + this.result = result; + this.input = input; + this.baseRegister = baseRegister; + this.encoding = encoding; + this.nonNull = nonNull; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Register inputRegister = asRegister(input); + Register resReg = asRegister(result); + if (encoding.base != 0) { + Register baseReg = asRegister(baseRegister); + if (!nonNull) { + masm.cmp(inputRegister, baseReg); + masm.movcc(ConditionFlag.Equal, CC.Xcc, baseReg, resReg); + masm.sub(resReg, baseReg, resReg); + } else { + masm.sub(inputRegister, baseReg, resReg); + } + if (encoding.shift != 0) { + masm.srlx(resReg, encoding.shift, resReg); + } + } else { + masm.srlx(inputRegister, encoding.shift, resReg); + } + } + } + + public static final class UncompressPointer extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(UncompressPointer.class); + public static final SizeEstimate SIZE = SizeEstimate.create(4); + + private final CompressEncoding encoding; + private final boolean nonNull; + + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue input; + @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; + + public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { + super(TYPE, SIZE); + this.result = result; + this.input = input; + this.baseRegister = baseRegister; + this.encoding = encoding; + this.nonNull = nonNull; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Register inputRegister = asRegister(input); + Register resReg = asRegister(result); + Register secondaryInput; + if (encoding.shift != 0) { + masm.sll(inputRegister, encoding.shift, resReg); + secondaryInput = resReg; + } else { + secondaryInput = inputRegister; + } + + if (encoding.base != 0) { + if (nonNull) { + masm.add(secondaryInput, asRegister(baseRegister), resReg); + } else { + Label done = new Label(); + BPR.emit(masm, Rc_z, ANNUL, PREDICT_TAKEN, secondaryInput, done); + masm.add(asRegister(baseRegister), secondaryInput, resReg); + masm.bind(done); + } + } + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMoveFactory.java 2016-12-07 13:49:48.124265285 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015, 2016, 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.sparc; + +import static jdk.vm.ci.hotspot.HotSpotCompressedNullConstant.COMPRESSED_NULL; +import static jdk.vm.ci.meta.JavaConstant.INT_0; +import static jdk.vm.ci.meta.JavaConstant.LONG_0; + +import org.graalvm.compiler.core.sparc.SPARCLIRGenerator.ConstantTableBaseProvider; +import org.graalvm.compiler.core.sparc.SPARCMoveFactory; +import org.graalvm.compiler.lir.LIRInstruction; + +import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; + +public class SPARCHotSpotMoveFactory extends SPARCMoveFactory { + + public SPARCHotSpotMoveFactory(ConstantTableBaseProvider constantTableBaseProvider) { + super(constantTableBaseProvider); + } + + @Override + public boolean canInlineConstant(JavaConstant c) { + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { + return true; + } else if (c instanceof HotSpotObjectConstant) { + return false; + } else { + return super.canInlineConstant(c); + } + } + + @Override + public LIRInstruction createLoad(AllocatableValue dst, Constant src) { + Constant usedSource; + if (COMPRESSED_NULL.equals(src)) { + usedSource = INT_0; + } else if (src instanceof HotSpotObjectConstant && ((HotSpotObjectConstant) src).isNull()) { + usedSource = LONG_0; + } else { + usedSource = src; + } + if (usedSource instanceof HotSpotConstant) { + HotSpotConstant constant = (HotSpotConstant) usedSource; + if (constant.isCompressed()) { + return new SPARCHotSpotMove.LoadHotSpotObjectConstantInline(constant, dst); + } else { + return new SPARCHotSpotMove.LoadHotSpotObjectConstantFromTable(constant, dst, constantTableBaseProvider.getConstantTableBase()); + } + } else { + return super.createLoad(dst, usedSource); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeCostProvider.java 2016-12-07 13:49:48.389276933 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, 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.sparc; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider; +import org.graalvm.compiler.hotspot.nodes.JumpToExceptionHandlerNode; +import org.graalvm.compiler.nodeinfo.NodeCycles; +import org.graalvm.compiler.nodeinfo.NodeSize; +import org.graalvm.compiler.nodes.ReturnNode; + +public class SPARCHotSpotNodeCostProvider extends HotSpotNodeCostProvider { + + @Override + public NodeCycles cycles(Node n) { + if (n instanceof ReturnNode) { + return NodeCycles.CYCLES_6; + } else if (n instanceof JumpToExceptionHandlerNode) { + // restore caller window + return NodeCycles.CYCLES_3; + } + return super.cycles(n); + } + + @Override + public NodeSize size(Node n) { + if (n instanceof ReturnNode) { + return NodeSize.SIZE_4; + } else if (n instanceof JumpToExceptionHandlerNode) { + // restore caller window + return NodeSize.SIZE_3; + } + return super.size(n); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java 2016-12-07 13:49:48.654288582 -0800 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2013, 2015, 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.sparc; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER; +import static jdk.vm.ci.sparc.SPARC.g5; +import static jdk.vm.ci.sparc.SPARC.o7; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.gen.DebugInfoBuilder; +import org.graalvm.compiler.core.sparc.SPARCNodeLIRBuilder; +import org.graalvm.compiler.core.sparc.SPARCNodeMatchRules; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.HotSpotLockStack; +import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder; +import org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode; +import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode; +import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.sparc.SPARCBreakpointOp; +import org.graalvm.compiler.lir.sparc.SPARCMove.CompareAndSwapOp; +import org.graalvm.compiler.nodes.BreakpointNode; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.DirectCallTargetNode; +import org.graalvm.compiler.nodes.FullInfopointNode; +import org.graalvm.compiler.nodes.IndirectCallTargetNode; +import org.graalvm.compiler.nodes.SafepointNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.NodeValueMap; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.hotspot.HotSpotCallingConventionType; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.sparc.SPARCKind; + +public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements HotSpotNodeLIRBuilder { + + public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, SPARCNodeMatchRules nodeMatchRules) { + super(graph, lirGen, nodeMatchRules); + assert gen instanceof SPARCHotSpotLIRGenerator; + assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder; + ((SPARCHotSpotLIRGenerator) gen).setDebugInfoBuilder(((HotSpotDebugInfoBuilder) getDebugInfoBuilder())); + } + + @Override + protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) { + HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(SPARCKind.XWORD)); + return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack, (HotSpotLIRGenerator) gen); + } + + private SPARCHotSpotLIRGenerator getGen() { + return (SPARCHotSpotLIRGenerator) gen; + } + + @Override + public void visitSafepointNode(SafepointNode i) { + LIRFrameState info = state(i); + append(new SPARCHotSpotSafepointOp(info, getGen().config, gen)); + } + + @Override + public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { + AllocatableValue address = gen.asAllocatable(operand(x.getAddress())); + AllocatableValue cmpValue = gen.asAllocatable(operand(x.expectedValue())); + AllocatableValue newValue = gen.asAllocatable(operand(x.newValue())); + assert cmpValue.getValueKind().equals(newValue.getValueKind()); + + Variable result = gen.newVariable(newValue.getValueKind()); + append(new CompareAndSwapOp(result, address, cmpValue, newValue)); + setResult(x, result); + } + + @Override + protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); + if (invokeKind.isIndirect()) { + append(new SPARCHotspotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); + } else { + assert invokeKind.isDirect(); + HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); + assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method."; + append(new SPARCHotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); + } + } + + @Override + protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + Value metaspaceMethodSrc = operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()); + AllocatableValue metaspaceMethod = g5.asValue(metaspaceMethodSrc.getValueKind()); + gen.emitMove(metaspaceMethod, metaspaceMethodSrc); + + Value targetAddressSrc = operand(callTarget.computedAddress()); + AllocatableValue targetAddress = o7.asValue(targetAddressSrc.getValueKind()); + gen.emitMove(targetAddress, targetAddressSrc); + append(new SPARCIndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethod, targetAddress, callState, getGen().config)); + } + + @Override + public void emitPatchReturnAddress(ValueNode address) { + append(new SPARCHotSpotPatchReturnAddressOp(gen.load(operand(address)))); + } + + @Override + public void emitJumpToExceptionHandler(ValueNode address) { + append(new SPARCHotSpotJumpToExceptionHandlerOp(gen.load(operand(address)))); + } + + @Override + public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + Variable handler = gen.load(operand(handlerInCallerPc)); + ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER); + CallingConvention linkageCc = linkage.getOutgoingCallingConvention(); + assert linkageCc.getArgumentCount() == 2; + RegisterValue exceptionFixed = (RegisterValue) linkageCc.getArgument(0); + RegisterValue exceptionPcFixed = (RegisterValue) linkageCc.getArgument(1); + gen.emitMove(exceptionFixed, operand(exception)); + gen.emitMove(exceptionPcFixed, operand(exceptionPc)); + Register thread = getGen().getProviders().getRegisters().getThreadRegister(); + SPARCHotSpotJumpToExceptionHandlerInCallerOp op = new SPARCHotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, getGen().config.threadIsMethodHandleReturnOffset, + thread); + append(op); + } + + @Override + protected void emitPrologue(StructuredGraph graph) { + super.emitPrologue(graph); + AllocatableValue var = getGen().getSafepointAddressValue(); + append(new SPARCHotSpotSafepointOp.SPARCLoadSafepointPollAddress(var, getGen().config)); + getGen().append(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack()); + } + + @Override + public void visitFullInfopointNode(FullInfopointNode i) { + if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) { + Debug.log("Ignoring InfopointNode for AFTER_BCI"); + } else { + super.visitFullInfopointNode(i); + } + } + + @Override + public void visitBreakpointNode(BreakpointNode node) { + JavaType[] sig = new JavaType[node.arguments().size()]; + for (int i = 0; i < sig.length; i++) { + sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess()); + } + + Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), + node.arguments()); + append(new SPARCBreakpointOp(parameters)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java 2016-12-07 13:49:48.920300274 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012, 2015, 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.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.i7; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; + +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Patch the return address of the current frame. + */ +@Opcode("PATCH_RETURN") +final class SPARCHotSpotPatchReturnAddressOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotPatchReturnAddressOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(1); + + @Use(REG) AllocatableValue address; + + SPARCHotSpotPatchReturnAddressOp(AllocatableValue address) { + super(TYPE, SIZE); + this.address = address; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Register addrRegister = asRegister(address, XWORD); + masm.sub(addrRegister, SPARCAssembler.PC_RETURN_OFFSET, i7); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java 2016-12-07 13:49:49.186311967 -0800 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2013, 2015, 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.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.i0; +import static jdk.vm.ci.sparc.SPARC.i1; +import static jdk.vm.ci.sparc.SPARC.i2; +import static jdk.vm.ci.sparc.SPARC.i3; +import static jdk.vm.ci.sparc.SPARC.i4; +import static jdk.vm.ci.sparc.SPARC.i7; +import static jdk.vm.ci.sparc.SPARC.o0; +import static jdk.vm.ci.sparc.SPARC.o1; +import static jdk.vm.ci.sparc.SPARC.o2; +import static jdk.vm.ci.sparc.SPARC.o3; +import static jdk.vm.ci.sparc.SPARC.o4; +import static jdk.vm.ci.sparc.SPARC.o5; +import static jdk.vm.ci.sparc.SPARC.sp; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Pushes an interpreter frame to the stack. + */ +@Opcode("PUSH_INTERPRETER_FRAME") +final class SPARCHotSpotPushInterpreterFrameOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotPushInterpreterFrameOp.class); + + @Alive(REG) AllocatableValue frameSize; + @Alive(REG) AllocatableValue framePc; + @Alive(REG) AllocatableValue senderSp; + @Alive(REG) AllocatableValue initialInfo; + + SPARCHotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo) { + super(TYPE); + this.frameSize = frameSize; + this.framePc = framePc; + this.senderSp = senderSp; + this.initialInfo = initialInfo; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + final Register frameSizeRegister = asRegister(frameSize); + final Register framePcRegister = asRegister(framePc); + final Register senderSpRegister = asRegister(senderSp); + + // Save sender SP to O5_savedSP. + masm.mov(senderSpRegister, o5); + + masm.neg(frameSizeRegister); + masm.save(sp, frameSizeRegister, sp); + + masm.mov(i0, o0); + masm.mov(i1, o1); + masm.mov(i2, o2); + masm.mov(i3, o3); + masm.mov(i4, o4); + + // NOTE: Don't touch I5 as it contains valuable saved SP! + + // Move frame's new PC into i7 + masm.mov(framePcRegister, i7); + } + + @Override + public boolean leavesRegisterWindow() { + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotRegisterAllocationConfig.java 2016-12-07 13:49:49.451323615 -0800 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2015, 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.sparc; + +import static jdk.vm.ci.sparc.SPARC.d32; +import static jdk.vm.ci.sparc.SPARC.d34; +import static jdk.vm.ci.sparc.SPARC.d36; +import static jdk.vm.ci.sparc.SPARC.d38; +import static jdk.vm.ci.sparc.SPARC.d40; +import static jdk.vm.ci.sparc.SPARC.d42; +import static jdk.vm.ci.sparc.SPARC.d44; +import static jdk.vm.ci.sparc.SPARC.d46; +import static jdk.vm.ci.sparc.SPARC.d48; +import static jdk.vm.ci.sparc.SPARC.d50; +import static jdk.vm.ci.sparc.SPARC.d52; +import static jdk.vm.ci.sparc.SPARC.d54; +import static jdk.vm.ci.sparc.SPARC.d56; +import static jdk.vm.ci.sparc.SPARC.d58; +import static jdk.vm.ci.sparc.SPARC.d60; +import static jdk.vm.ci.sparc.SPARC.d62; +import static jdk.vm.ci.sparc.SPARC.f10; +import static jdk.vm.ci.sparc.SPARC.f11; +import static jdk.vm.ci.sparc.SPARC.f12; +import static jdk.vm.ci.sparc.SPARC.f13; +import static jdk.vm.ci.sparc.SPARC.f14; +import static jdk.vm.ci.sparc.SPARC.f15; +import static jdk.vm.ci.sparc.SPARC.f16; +import static jdk.vm.ci.sparc.SPARC.f17; +import static jdk.vm.ci.sparc.SPARC.f18; +import static jdk.vm.ci.sparc.SPARC.f19; +import static jdk.vm.ci.sparc.SPARC.f20; +import static jdk.vm.ci.sparc.SPARC.f21; +import static jdk.vm.ci.sparc.SPARC.f22; +import static jdk.vm.ci.sparc.SPARC.f23; +import static jdk.vm.ci.sparc.SPARC.f24; +import static jdk.vm.ci.sparc.SPARC.f25; +import static jdk.vm.ci.sparc.SPARC.f26; +import static jdk.vm.ci.sparc.SPARC.f27; +import static jdk.vm.ci.sparc.SPARC.f28; +import static jdk.vm.ci.sparc.SPARC.f29; +import static jdk.vm.ci.sparc.SPARC.f30; +import static jdk.vm.ci.sparc.SPARC.f31; +import static jdk.vm.ci.sparc.SPARC.f8; +import static jdk.vm.ci.sparc.SPARC.f9; +import static jdk.vm.ci.sparc.SPARC.g1; +import static jdk.vm.ci.sparc.SPARC.g4; +import static jdk.vm.ci.sparc.SPARC.g5; +import static jdk.vm.ci.sparc.SPARC.i0; +import static jdk.vm.ci.sparc.SPARC.i1; +import static jdk.vm.ci.sparc.SPARC.i2; +import static jdk.vm.ci.sparc.SPARC.i3; +import static jdk.vm.ci.sparc.SPARC.i4; +import static jdk.vm.ci.sparc.SPARC.i5; +import static jdk.vm.ci.sparc.SPARC.l0; +import static jdk.vm.ci.sparc.SPARC.l1; +import static jdk.vm.ci.sparc.SPARC.l2; +import static jdk.vm.ci.sparc.SPARC.l3; +import static jdk.vm.ci.sparc.SPARC.l4; +import static jdk.vm.ci.sparc.SPARC.l5; +import static jdk.vm.ci.sparc.SPARC.l6; +import static jdk.vm.ci.sparc.SPARC.l7; +import static jdk.vm.ci.sparc.SPARC.o0; +import static jdk.vm.ci.sparc.SPARC.o1; +import static jdk.vm.ci.sparc.SPARC.o2; +import static jdk.vm.ci.sparc.SPARC.o3; +import static jdk.vm.ci.sparc.SPARC.o4; +import static jdk.vm.ci.sparc.SPARC.o5; + +import java.util.ArrayList; +import java.util.BitSet; + +import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterConfig; + +public class SPARCHotSpotRegisterAllocationConfig extends RegisterAllocationConfig { + + // @formatter:off + static final Register[] registerAllocationOrder = { + l0, l1, l2, l3, l4, l5, l6, l7, + i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ + o0, o1, o2, o3, o4, o5, /*o6, o7,*/ + g1, g4, g5, + // f0, f1, f2, f3, f4, f5, f6, f7 + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + + public SPARCHotSpotRegisterAllocationConfig(RegisterConfig registerConfig) { + super(registerConfig); + } + + @Override + protected RegisterArray initAllocatable(RegisterArray registers) { + BitSet regMap = new BitSet(registerConfig.getAllocatableRegisters().size()); + for (Register reg : registers) { + regMap.set(reg.number); + } + + ArrayList allocatableRegisters = new ArrayList<>(registers.size()); + for (Register reg : registerAllocationOrder) { + if (regMap.get(reg.number)) { + allocatableRegisters.add(reg); + } + } + + return super.initAllocatable(new RegisterArray(allocatableRegisters)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotReturnOp.java 2016-12-07 13:49:49.717335308 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012, 2015, 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.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCControlFlow.ReturnOp; + +import jdk.vm.ci.meta.Value; + +/** + * Returns from a function. + */ +@Opcode("RETURN") +final class SPARCHotSpotReturnOp extends SPARCHotSpotEpilogueOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotReturnOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(2); + + @Use({REG, ILLEGAL}) protected Value value; + @Use({REG}) protected Value safepointPollAddress; + private final boolean isStub; + private final GraalHotSpotVMConfig config; + + SPARCHotSpotReturnOp(Value value, boolean isStub, GraalHotSpotVMConfig config, Value safepointPoll) { + super(TYPE, SIZE); + this.value = value; + this.isStub = isStub; + this.config = config; + this.safepointPollAddress = safepointPoll; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + if (!isStub) { + // Every non-stub compile method must have a poll before the return. + SPARCHotSpotSafepointOp.emitCode(crb, masm, config, true, null, asRegister(safepointPollAddress)); + } + ReturnOp.emitCodeHelper(crb, masm); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java 2016-12-07 13:49:49.983347000 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011, 2016, 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.sparc; + +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.g0; + +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.code.site.InfopointReason; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Emits a safepoint poll. + */ +@Opcode("SAFEPOINT") +public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotSafepointOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(9); + + @State protected LIRFrameState state; + @Use({OperandFlag.REG}) AllocatableValue safepointPollAddress; + private final GraalHotSpotVMConfig config; + + public SPARCHotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, LIRGeneratorTool tool) { + super(TYPE, SIZE); + this.state = state; + this.config = config; + SPARCHotSpotLIRGenerator lirGen = (SPARCHotSpotLIRGenerator) tool; + safepointPollAddress = lirGen.getSafepointAddressValue(); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + emitCode(crb, masm, config, false, state, asRegister(safepointPollAddress)); + } + + public static void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register safepointPollAddress) { + crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); + if (state != null) { + final int pos = masm.position(); + crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); + } + masm.ldx(new SPARCAddress(safepointPollAddress, 0), g0); + } + + public static class SPARCLoadSafepointPollAddress extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCLoadSafepointPollAddress.class); + public static final SizeEstimate SIZE = SizeEstimate.create(2); + + @Def({OperandFlag.REG}) protected AllocatableValue result; + private final GraalHotSpotVMConfig config; + + public SPARCLoadSafepointPollAddress(AllocatableValue result, GraalHotSpotVMConfig config) { + super(TYPE, SIZE); + this.result = result; + this.config = config; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + masm.setx(config.safepointPollingAddress, ValueUtil.asRegister(result), false); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotStrategySwitchOp.java 2016-12-07 13:49:50.248358649 -0800 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015, 2016, 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.sparc; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.INSTRUCTION_SIZE; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; +import static org.graalvm.compiler.lir.sparc.SPARCMove.loadFromConstantTable; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.g0; + +import org.graalvm.compiler.asm.Assembler.LabelHint; +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCControlFlow; +import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.sparc.SPARC.CPUFeature; + +final class SPARCHotSpotStrategySwitchOp extends SPARCControlFlow.StrategySwitchOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotStrategySwitchOp.class); + + SPARCHotSpotStrategySwitchOp(Value constantTableBase, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { + super(TYPE, constantTableBase, strategy, keyTargets, defaultTarget, key, scratch); + } + + public class HotSpotSwitchClosure extends SwitchClosure { + protected HotSpotSwitchClosure(Register keyRegister, Register constantBaseRegister, CompilationResultBuilder crb, SPARCMacroAssembler masm) { + super(keyRegister, constantBaseRegister, crb, masm); + } + + @Override + protected void conditionalJump(int index, Condition condition, Label target) { + if (keyConstants[index] instanceof HotSpotMetaspaceConstant) { + HotSpotMetaspaceConstant constant = (HotSpotMetaspaceConstant) keyConstants[index]; + CC conditionCode = constant.isCompressed() ? CC.Icc : CC.Xcc; + ConditionFlag conditionFlag = SPARCControlFlow.fromCondition(true, condition, false); + LabelHint hint = requestHint(masm, target); + + // Load constant takes one instruction + int cbCondPosition = masm.position() + INSTRUCTION_SIZE; + boolean canUseShortBranch = masm.hasFeature(CPUFeature.CBCOND) && SPARCControlFlow.isShortBranch(masm, cbCondPosition, hint, target); + + Register scratchRegister = asRegister(scratch); + final int byteCount = constant.isCompressed() ? 4 : 8; + loadFromConstantTable(crb, masm, byteCount, asRegister(constantTableBase), constant, scratchRegister, SPARCDelayedControlTransfer.DUMMY); + + if (canUseShortBranch) { + CBCOND.emit(masm, conditionFlag, conditionCode == CC.Xcc, keyRegister, scratchRegister, target); + } else { + masm.cmp(keyRegister, scratchRegister); + BPCC.emit(masm, conditionCode, conditionFlag, ANNUL, PREDICT_TAKEN, target); + masm.nop(); // delay slot + } + } else { + super.conditionalJump(index, condition, target); + } + } + } + + @Override + protected int estimateEmbeddedSize(Constant c) { + if (c instanceof HotSpotMetaspaceConstant) { + return ((HotSpotMetaspaceConstant) c).isCompressed() ? 4 : 8; + } else { + return super.estimateEmbeddedSize(c); + } + } + + @Override + public void emitCode(final CompilationResultBuilder crb, final SPARCMacroAssembler masm) { + final Register keyRegister = asRegister(key); + final Register constantBaseRegister = AllocatableValue.ILLEGAL.equals(constantTableBase) ? g0 : asRegister(constantTableBase); + strategy.run(new HotSpotSwitchClosure(keyRegister, constantBaseRegister, crb, masm)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotUnwindOp.java 2016-12-07 13:49:50.513370297 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2012, 2015, 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.sparc; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.g5; +import static jdk.vm.ci.sparc.SPARC.i0; +import static jdk.vm.ci.sparc.SPARC.o0; +import static jdk.vm.ci.sparc.SPARC.o7; + +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCCall; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; + +/** + * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}. + */ +@Opcode("UNWIND") +final class SPARCHotSpotUnwindOp extends SPARCHotSpotEpilogueOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotUnwindOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(32); + + @Use({REG}) protected RegisterValue exception; + + SPARCHotSpotUnwindOp(RegisterValue exception) { + super(TYPE, SIZE); + this.exception = exception; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + // This Frame is left but the called unwind (which is sibling) method needs the exception as + // input in i0 + masm.mov(o0, i0); + leaveFrame(crb); + + ForeignCallLinkage linkage = crb.foreignCalls.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER); + CallingConvention cc = linkage.getOutgoingCallingConvention(); + assert cc.getArgumentCount() == 2; + assert exception.equals(cc.getArgument(0)); + + // Get return address (is in o7 after leave). + Register returnAddress = asRegister(cc.getArgument(1)); + masm.add(o7, SPARCAssembler.PC_RETURN_OFFSET, returnAddress); + Register scratch = g5; + SPARCCall.indirectJmp(crb, masm, scratch, linkage); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java 2016-12-07 13:49:50.783382165 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, 2015, 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.sparc; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCCall.DirectCallOp; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * A direct call that complies with the conventions for such calls in HotSpot. It doesn't use an + * inline cache so it's just a patchable call site. + */ +@Opcode("CALL_DIRECT") +final class SPARCHotspotDirectStaticCallOp extends DirectCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotspotDirectStaticCallOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(8); + + private final InvokeKind invokeKind; + private final GraalHotSpotVMConfig config; + + SPARCHotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) { + super(TYPE, SIZE, target, result, parameters, temps, state); + assert invokeKind.isDirect(); + this.invokeKind = invokeKind; + this.config = config; + } + + @Override + public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java 2016-12-07 13:49:51.048393814 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012, 2015, 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.sparc; + +import static jdk.vm.ci.sparc.SPARC.g5; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCCall.DirectCallOp; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * A direct call that complies with the conventions for such calls in HotSpot. In particular, for + * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call. + */ +@Opcode("CALL_DIRECT") +final class SPARCHotspotDirectVirtualCallOp extends DirectCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotspotDirectVirtualCallOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(8); + + private final InvokeKind invokeKind; + private final GraalHotSpotVMConfig config; + + SPARCHotspotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) { + super(TYPE, SIZE, target, result, parameters, temps, state); + this.invokeKind = invokeKind; + this.config = config; + assert invokeKind.isIndirect(); + } + + @Override + public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + // The mark for an invocation that uses an inline cache must be placed at the + // instruction that loads the Klass from the inline cache. + crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE); + Register scratchRegister = g5; + masm.setx(config.nonOopBits, scratchRegister, true); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCIndirectCallOp.java 2016-12-07 13:49:51.312405419 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.g5; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.sparc.SPARCCall; +import org.graalvm.compiler.lir.sparc.SPARCCall.IndirectCallOp; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * A register indirect call that complies with the extra conventions for such calls in HotSpot. In + * particular, the metaspace Method of the callee must be in g5 for the case where a vtable entry's + * _from_compiled_entry is the address of an C2I adapter. Such adapters expect the target method to + * be in g5. + */ +@Opcode("CALL_INDIRECT") +final class SPARCIndirectCallOp extends IndirectCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCIndirectCallOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(2); + + /** + * Vtable stubs expect the metaspace Method in g5. + */ + public static final Register METHOD = g5; + + @Use({REG}) protected Value metaspaceMethod; + + private final GraalHotSpotVMConfig config; + + SPARCIndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state, + GraalHotSpotVMConfig config) { + super(TYPE, SIZE, targetMethod, result, parameters, temps, targetAddress, state); + this.metaspaceMethod = metaspaceMethod; + this.config = config; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + crb.recordMark(config.MARKID_INLINE_INVOKE); + Register callReg = asRegister(targetAddress); + assert !callReg.equals(METHOD); + SPARCCall.indirectCall(crb, masm, callReg, callTarget, state); + } + + @Override + public void verify() { + super.verify(); + assert asRegister(metaspaceMethod).equals(METHOD); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCUncommonTrapStub.java 2016-12-07 13:49:51.580417199 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, 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.sparc; + +import static jdk.vm.ci.sparc.SPARC.g1; +import static jdk.vm.ci.sparc.SPARC.g3; +import static jdk.vm.ci.sparc.SPARC.g4; +import static jdk.vm.ci.sparc.SPARC.g5; +import static jdk.vm.ci.sparc.SPARC.o0; +import static jdk.vm.ci.sparc.SPARC.o1; +import static jdk.vm.ci.sparc.SPARC.o2; +import static jdk.vm.ci.sparc.SPARC.o3; +import static jdk.vm.ci.sparc.SPARC.o4; + +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.stubs.UncommonTrapStub; + +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.sparc.SPARCHotSpotRegisterConfig; + +final class SPARCUncommonTrapStub extends UncommonTrapStub { + + private RegisterConfig registerConfig; + + SPARCUncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) { + super(providers, target, linkage); + // This is basically the maximum we can spare. All other G and O register are used. + RegisterArray allocatable = new RegisterArray(g1, g3, g4, g5, o0, o1, o2, o3, o4); + registerConfig = new SPARCHotSpotRegisterConfig(target, allocatable); + } + + @Override + public RegisterConfig getRegisterConfig() { + return registerConfig; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/AheadOfTimeCompilationTest.java 2016-12-07 13:49:51.846428891 -0800 @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2013, 2016, 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.test; + +import static org.graalvm.compiler.core.GraalCompiler.compileGraph; +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; +import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.memory.FloatingReadNode; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.tiers.Suites; +import org.graalvm.compiler.phases.tiers.SuitesProvider; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * use + * + *
    + * mx unittest AheadOfTimeCompilationTest @-XX:CompileCommand='print,*AheadOfTimeCompilationTest.*'
    + * 
    + * + * to print disassembly. + */ +public class AheadOfTimeCompilationTest extends GraalCompilerTest { + + public static final Object STATICFINALOBJECT = new Object(); + public static final String STATICFINALSTRING = "test string"; + + public static Object getStaticFinalObject() { + return AheadOfTimeCompilationTest.STATICFINALOBJECT; + } + + @Test + public void testStaticFinalObjectAOT() { + StructuredGraph result = compile("getStaticFinalObject", true); + assertDeepEquals(1, getConstantNodes(result).count()); + Stamp constantStamp = getConstantNodes(result).first().stamp(); + Assert.assertTrue(constantStamp.toString(), constantStamp instanceof KlassPointerStamp); + assertDeepEquals(2, result.getNodes().filter(FloatingReadNode.class).count()); + assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count()); + } + + @Test + public void testStaticFinalObject() { + StructuredGraph result = compile("getStaticFinalObject", false); + assertDeepEquals(1, getConstantNodes(result).count()); + assertDeepEquals(JavaKind.Object, getConstantNodes(result).first().getStackKind()); + assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count()); + assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count()); + } + + public static Class getClassObject() { + return AheadOfTimeCompilationTest.class; + } + + @Test + public void testClassObjectAOT() { + StructuredGraph result = compile("getClassObject", true); + + NodeIterable filter = getConstantNodes(result); + assertDeepEquals(1, filter.count()); + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(AheadOfTimeCompilationTest.class); + assertDeepEquals(type.klass(), filter.first().asConstant()); + + assertDeepEquals(1, result.getNodes().filter(FloatingReadNode.class).count()); + assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count()); + } + + @Test + public void testClassObject() { + StructuredGraph result = compile("getClassObject", false); + + NodeIterable filter = getConstantNodes(result); + assertDeepEquals(1, filter.count()); + JavaConstant c = filter.first().asJavaConstant(); + Assert.assertEquals(getSnippetReflection().asObject(Class.class, c), AheadOfTimeCompilationTest.class); + + assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count()); + assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count()); + } + + public static Class getPrimitiveClassObject() { + return int.class; + } + + @Test + public void testPrimitiveClassObjectAOT() { + StructuredGraph result = compile("getPrimitiveClassObject", true); + NodeIterable filter = getConstantNodes(result); + assertDeepEquals(1, filter.count()); + Stamp constantStamp = filter.first().stamp(); + Assert.assertTrue(constantStamp instanceof KlassPointerStamp); + + assertDeepEquals(2, result.getNodes().filter(FloatingReadNode.class).count()); + assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count()); + } + + @Test + public void testPrimitiveClassObject() { + StructuredGraph result = compile("getPrimitiveClassObject", false); + NodeIterable filter = getConstantNodes(result); + assertDeepEquals(1, filter.count()); + JavaConstant c = filter.first().asJavaConstant(); + Assert.assertEquals(getSnippetReflection().asObject(Class.class, c), Integer.TYPE); + + assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count()); + assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count()); + } + + public static String getStringObject() { + return AheadOfTimeCompilationTest.STATICFINALSTRING; + } + + @Test + public void testStringObjectAOT() { + // embedded strings are fine + testStringObjectCommon(true); + } + + @Test + public void testStringObject() { + testStringObjectCommon(false); + } + + private void testStringObjectCommon(boolean compileAOT) { + StructuredGraph result = compile("getStringObject", compileAOT); + + NodeIterable filter = getConstantNodes(result); + assertDeepEquals(1, filter.count()); + JavaConstant c = filter.first().asJavaConstant(); + Assert.assertEquals(getSnippetReflection().asObject(String.class, c), "test string"); + + assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count()); + assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count()); + } + + public static Boolean getBoxedBoolean() { + return Boolean.valueOf(true); + } + + @Ignore("ImmutableCode override may not work reliably in non-hosted mode") + @Test + public void testBoxedBooleanAOT() { + StructuredGraph result = compile("getBoxedBoolean", true); + + assertDeepEquals(2, result.getNodes().filter(FloatingReadNode.class).count()); + assertDeepEquals(1, result.getNodes(PiNode.TYPE).count()); + assertDeepEquals(1, getConstantNodes(result).count()); + ConstantNode constant = getConstantNodes(result).first(); + assertDeepEquals(JavaKind.Long, constant.getStackKind()); + assertDeepEquals(((HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(Boolean.class)).klass(), constant.asConstant()); + } + + @Test + public void testBoxedBoolean() { + StructuredGraph result = compile("getBoxedBoolean", false); + assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count()); + assertDeepEquals(0, result.getNodes(PiNode.TYPE).count()); + assertDeepEquals(1, getConstantNodes(result).count()); + ConstantNode constant = getConstantNodes(result).first(); + assertDeepEquals(JavaKind.Object, constant.getStackKind()); + + JavaConstant c = constant.asJavaConstant(); + Assert.assertEquals(getSnippetReflection().asObject(Boolean.class, c), Boolean.TRUE); + } + + @SuppressWarnings("try") + private StructuredGraph compile(String test, boolean compileAOT) { + try (OverrideScope s = OptionValue.override(ImmutableCode, compileAOT)) { + StructuredGraph graph = parseEager(test, AllowAssumptions.YES); + ResolvedJavaMethod method = graph.method(); + // create suites everytime, as we modify options for the compiler + SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites(); + final Suites suitesLocal = suitesProvider.getDefaultSuites(); + final LIRSuites lirSuitesLocal = suitesProvider.getDefaultLIRSuites(); + final CompilationResult compResult = compileGraph(graph, method, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(), + suitesLocal, lirSuitesLocal, new CompilationResult(), CompilationResultBuilderFactory.Default); + addMethod(method, compResult); + return graph; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayCopyIntrinsificationTest.java 2016-12-07 13:49:52.111440540 -0800 @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2011, 2015, 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.test; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.HashMap; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySnippets; +import org.graalvm.compiler.nodes.DirectCallTargetNode; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.LoweredCallTargetNode; +import org.graalvm.compiler.nodes.StructuredGraph; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.JavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Tests intrinsification of {@link System#arraycopy(Object, int, Object, int, int)}. + */ +public class ArrayCopyIntrinsificationTest extends GraalCompilerTest { + + @Override + protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph g) { + StructuredGraph graph = g == null ? parseForCompile(method) : g; + int nodeCount = graph.getNodeCount(); + InstalledCode result = super.getCode(method, graph); + boolean graphWasProcessed = nodeCount != graph.getNodeCount(); + if (graphWasProcessed) { + if (mustIntrinsify) { + for (Node node : graph.getNodes()) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode); + LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget(); + JavaMethod callee = directCall.targetMethod(); + if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) { + // A partial snippet (e.g., ArrayCopySnippets.checkcastArraycopy) may + // call the original arraycopy method + } else { + Assert.assertTrue(callee.toString(), callee.getName().equals("")); + Assert.assertTrue(getMetaAccess().lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) || + getMetaAccess().lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass())); + } + } + } + } else { + boolean found = false; + for (Node node : graph.getNodes()) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget(); + JavaMethod callee = directCall.targetMethod(); + if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) { + found = true; + } else { + fail("found invoke to some method other than arraycopy: " + callee); + } + } + } + Assert.assertTrue("did not find invoke to arraycopy", found); + } + } + return result; + } + + boolean mustIntrinsify = true; + + @Test + public void test0() { + // Array store checks + test("genericArraycopy", new Object(), 0, new Object[0], 0, 0); + test("genericArraycopy", new Object[0], 0, new Object(), 0, 0); + } + + @Test + public void test1() { + String name = "intArraycopy"; + int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + // Null checks + test(name, null, 0, src, 0, 0); + test(name, src, 0, null, 0, 0); + // Bounds checks + test(name, src, 0, src, 0, -1); + test(name, src, 0, src, 0, src.length + 1); + } + + @Test + public void testByte() { + byte[] src = {-1, 0, 1, 2, 3, 4}; + testHelper("byteArraycopy", src); + } + + @Test + public void testChar() { + char[] src = "some string of chars".toCharArray(); + testHelper("charArraycopy", src); + } + + @Test + public void testShort() { + short[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("shortArraycopy", src); + } + + @Test + public void testInt() { + int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("intArraycopy", src); + } + + @Test + public void testFloat() { + float[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("floatArraycopy", src); + } + + @Test + public void testLong() { + long[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("longArraycopy", src); + } + + @Test + public void testDouble() { + double[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("doubleArraycopy", src); + } + + @Test + public void testObject() { + Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()}; + testHelper("objectArraycopy", src); + } + + /** + * Tests {@link ArrayCopySnippets#checkcastArraycopyWork(Object, int, Object, int, int)}. + */ + @Test + public void testArrayStoreException() { + Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()}; + Object[] dst = new CharSequence[src.length]; + // Will throw ArrayStoreException for 4th element + test("objectArraycopy", src, 0, dst, 0, src.length); + } + + @Test + public void testDisjointObject() { + Integer[] src1 = {1, 2, 3, 4}; + test("objectArraycopy", src1, 0, src1, 1, src1.length - 1); + + Integer[] src2 = {1, 2, 3, 4}; + test("objectArraycopy", src2, 1, src2, 0, src2.length - 1); + } + + @Test + public void testObjectExact() { + Integer[] src = {1, 2, 3, 4}; + testHelper("objectArraycopyExact", src); + } + + private static Object newArray(Object proto, int length) { + assert proto != null; + assert proto.getClass().isArray(); + return Array.newInstance(proto.getClass().getComponentType(), length); + } + + private void testHelper(String name, Object src) { + int srcLength = Array.getLength(src); + + // Complete array copy + test(name, src, 0, newArray(src, srcLength), 0, srcLength); + + for (int length : new int[]{0, 1, srcLength - 1, srcLength}) { + // Partial array copying + test(name, src, 0, newArray(src, length), 0, length); + test(name, src, srcLength - length, newArray(src, length), 0, length); + test(name, src, 0, newArray(src, srcLength), 0, length); + } + + if (srcLength > 1) { + test(name, src, 0, src, 1, srcLength - 1); + } + } + + public static Object genericArraycopy(Object src, int srcPos, Object dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static Object[] objectArraycopy(Object[] src, int srcPos, Object[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static Object[] objectArraycopyExact(Integer[] src, int srcPos, Integer[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static boolean[] booleanArraycopy(boolean[] src, int srcPos, boolean[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static byte[] byteArraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static char[] charArraycopy(char[] src, int srcPos, char[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static short[] shortArraycopy(short[] src, int srcPos, short[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static int[] intArraycopy(int[] src, int srcPos, int[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static float[] floatArraycopy(float[] src, int srcPos, float[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static long[] longArraycopy(long[] src, int srcPos, long[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static double[] doubleArraycopy(double[] src, int srcPos, double[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + /** + * Test case derived from assertion while compiling com.google.common.collect.ArrayTable(ArrayTable other). + */ + @Test + public void testCopyRows() { + Object[][] rows = {{"a1", "a2", "a3", "a4"}, {"b1", "b2", "b3", "b4"}, {"c1", "c2", "c3", "c4"}}; + test("copyRows", rows, 4, new Integer(rows.length)); + } + + public static Object[][] copyRows(Object[][] rows, int rowSize, Integer rowCount) { + Object[][] copy = new Object[rows.length][rowSize]; + for (int i = 0; i < rowCount.intValue(); i++) { + System.arraycopy(rows[i], 0, copy[i], 0, rows[i].length); + } + return copy; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CRC32SubstitutionsTest.java 2016-12-07 13:49:52.376452188 -0800 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2007, 2012, 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.test; + +import java.io.DataInputStream; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.zip.CRC32; + +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; + +/** + * Tests compiled call to {@link CRC32#update(int, int)}. + */ +@SuppressWarnings("javadoc") +public class CRC32SubstitutionsTest extends GraalCompilerTest { + + public static long update(byte[] input) { + CRC32 crc = new CRC32(); + for (byte b : input) { + crc.update(b); + } + return crc.getValue(); + } + + @Test + public void test1() { + test("update", "some string".getBytes()); + } + + public static long updateBytes(byte[] input, int offset, int length) { + CRC32 crc = new CRC32(); + crc.update(input, offset, length); + return crc.getValue(); + } + + @Test + public void test2() { + byte[] buf = "some string".getBytes(); + int off = 0; + int len = buf.length; + test("updateBytes", buf, off, len); + } + + @Test + public void test3() throws Throwable { + String classfileName = CRC32SubstitutionsTest.class.getSimpleName().replace('.', '/') + ".class"; + InputStream s = CRC32SubstitutionsTest.class.getResourceAsStream(classfileName); + byte[] buf = new byte[s.available()]; + new DataInputStream(s).readFully(buf); + test("updateBytes", buf, 0, buf.length); + for (int offset = 1; offset < buf.length; offset++) { + test("updateBytes", buf, offset, buf.length - offset); + } + } + + public static long updateByteBuffer(ByteBuffer buffer) { + CRC32 crc = new CRC32(); + buffer.rewind(); + crc.update(buffer); + return crc.getValue(); + } + + @Test + public void test4() throws Throwable { + String classfileName = CRC32SubstitutionsTest.class.getSimpleName().replace('.', '/') + ".class"; + InputStream s = CRC32SubstitutionsTest.class.getResourceAsStream(classfileName); + byte[] buf = new byte[s.available()]; + new DataInputStream(s).readFully(buf); + + ByteBuffer directBuf = ByteBuffer.allocateDirect(buf.length); + directBuf.put(buf); + ByteBuffer heapBuf = ByteBuffer.wrap(buf); + + test("updateByteBuffer", directBuf); + test("updateByteBuffer", heapBuf); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java 2016-12-07 13:49:52.642463881 -0800 @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2014, 2016, 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.test; + +import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import org.junit.Test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.runtime.RuntimeProvider; +import org.graalvm.compiler.test.GraalTest; + +import jdk.vm.ci.hotspot.HotSpotVMConfigStore; +import jdk.vm.ci.hotspot.VMIntrinsicMethod; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Checks the set of intrinsics implemented by Graal against the set of intrinsics declared by + * HotSpot. The purpose of this test is to detect when new intrinsics are added to HotSpot and + * process them appropriately in Graal. This will be achieved by working through + * {@link #TO_BE_INVESTIGATED} and either implementing the intrinsic or moving it to {@link #IGNORE} + * . + */ +public class CheckGraalIntrinsics extends GraalTest { + + public static boolean match(ResolvedJavaMethod method, VMIntrinsicMethod intrinsic) { + if (intrinsic.name.equals(method.getName())) { + if (intrinsic.descriptor.equals(method.getSignature().toMethodDescriptor())) { + String declaringClass = method.getDeclaringClass().toClassName().replace('.', '/'); + if (declaringClass.equals(intrinsic.declaringClass)) { + return true; + } + } + } + return false; + } + + private static ResolvedJavaMethod findMethod(Set methods, VMIntrinsicMethod intrinsic) { + for (ResolvedJavaMethod method : methods) { + if (match(method, intrinsic)) { + return method; + } + } + return null; + } + + private static ResolvedJavaMethod resolveIntrinsic(MetaAccessProvider metaAccess, VMIntrinsicMethod intrinsic) throws ClassNotFoundException { + Class c = Class.forName(intrinsic.declaringClass.replace('/', '.'), false, CheckGraalIntrinsics.class.getClassLoader()); + for (Method javaMethod : c.getDeclaredMethods()) { + if (javaMethod.getName().equals(intrinsic.name)) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(javaMethod); + if (intrinsic.descriptor.equals("*")) { + // Signature polymorphic method - name match is enough + return method; + } else { + if (method.getSignature().toMethodDescriptor().equals(intrinsic.descriptor)) { + return method; + } + } + } + } + return null; + } + + /** + * The HotSpot intrinsics implemented without {@link InvocationPlugin}s or whose + * {@link InvocationPlugin} registration is guarded by a condition that is false in the current + * VM context. + */ + private static final Set IGNORE = new TreeSet<>(); + + /** + * The HotSpot intrinsics yet to be implemented or moved to {@link #IGNORE}. + */ + private static final Set TO_BE_INVESTIGATED = new TreeSet<>(); + + private static Collection add(Collection c, String... elements) { + String[] sorted = elements.clone(); + Arrays.sort(sorted); + for (int i = 0; i < elements.length; i++) { + if (!elements[i].equals(sorted[i])) { + // Let's keep the list sorted for easier visual inspection + fail("Element %d is out of order, \"%s\"", i, elements[i]); + } + } + c.addAll(Arrays.asList(elements)); + return c; + } + + static { + add(IGNORE, + // dead + "java/lang/Math.atan2(DD)D", + // Used during stack walking + "java/lang/Throwable.fillInStackTrace()Ljava/lang/Throwable;", + // Marker intrinsic id + "java/lang/invoke/MethodHandle.*", + // Marker intrinsic id + "java/lang/invoke/MethodHandle.invoke*", + // Implemented through lowering + "java/lang/ref/Reference.get()Ljava/lang/Object;", + // Used during stack walk + "java/lang/reflect/Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", + // Only used by C1 + "java/nio/Buffer.checkIndex(I)I", + // dead + "sun/misc/Unsafe.park(ZJ)V", + // dead + "sun/misc/Unsafe.prefetchRead(Ljava/lang/Object;J)V", + // dead + "sun/misc/Unsafe.prefetchReadStatic(Ljava/lang/Object;J)V", + // dead + "sun/misc/Unsafe.prefetchWrite(Ljava/lang/Object;J)V", + // dead + "sun/misc/Unsafe.prefetchWriteStatic(Ljava/lang/Object;J)V", + // dead + "sun/misc/Unsafe.unpark(Ljava/lang/Object;)V"); + + add(TO_BE_INVESTIGATED, + // JDK 8 + "java/lang/Double.doubleToLongBits(D)J", + "java/lang/Float.floatToIntBits(F)I", + "java/lang/Integer.toString(I)Ljava/lang/String;", + "java/lang/Math.decrementExact(I)I", + "java/lang/Math.decrementExact(J)J", + "java/lang/Math.incrementExact(I)I", + "java/lang/Math.incrementExact(J)J", + "java/lang/Math.max(II)I", + "java/lang/Math.min(II)I", + "java/lang/Math.negateExact(I)I", + "java/lang/Math.negateExact(J)J", + "java/lang/String.(Ljava/lang/String;)V", + "java/lang/String.compareTo(Ljava/lang/String;)I", + "java/lang/String.indexOf(Ljava/lang/String;)I", + "java/lang/StringBuffer.()V", + "java/lang/StringBuffer.(I)V", + "java/lang/StringBuffer.(Ljava/lang/String;)V", + "java/lang/StringBuffer.append(C)Ljava/lang/StringBuffer;", + "java/lang/StringBuffer.append(I)Ljava/lang/StringBuffer;", + "java/lang/StringBuffer.append(Ljava/lang/String;)Ljava/lang/StringBuffer;", + "java/lang/StringBuffer.toString()Ljava/lang/String;", + "java/lang/StringBuilder.()V", + "java/lang/StringBuilder.(I)V", + "java/lang/StringBuilder.(Ljava/lang/String;)V", + "java/lang/StringBuilder.append(C)Ljava/lang/StringBuilder;", + "java/lang/StringBuilder.append(I)Ljava/lang/StringBuilder;", + "java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;", + "java/lang/StringBuilder.toString()Ljava/lang/String;", + "java/lang/reflect/Array.newArray(Ljava/lang/Class;I)Ljava/lang/Object;", + "java/util/Arrays.copyOf([Ljava/lang/Object;ILjava/lang/Class;)[Ljava/lang/Object;", + "java/util/Arrays.copyOfRange([Ljava/lang/Object;IILjava/lang/Class;)[Ljava/lang/Object;", + "oracle/jrockit/jfr/Timing.counterTime()J", + "oracle/jrockit/jfr/VMJFR.classID0(Ljava/lang/Class;)J", + "oracle/jrockit/jfr/VMJFR.threadID()I", + "sun/misc/Unsafe.copyMemory(Ljava/lang/Object;JLjava/lang/Object;JJ)V", + "sun/nio/cs/ISO_8859_1$Encoder.encodeISOArray([CI[BII)I", + "sun/security/provider/DigestBase.implCompressMultiBlock([BII)I", + "sun/security/provider/SHA.implCompress([BI)V", + "sun/security/provider/SHA2.implCompress([BI)V", + "sun/security/provider/SHA5.implCompress([BI)V"); + + add(TO_BE_INVESTIGATED, + // JDK 9 + "com/sun/crypto/provider/CounterMode.implCrypt([BII[BI)I", + "com/sun/crypto/provider/GHASH.processBlocks([BII[J[J)V", + "java/lang/Math.fma(DDD)D", + "java/lang/Math.fma(FFF)F", + "java/lang/Object.notify()V", + "java/lang/Object.notifyAll()V", + "java/lang/StringCoding.hasNegatives([BII)Z", + "java/lang/StringCoding.implEncodeISOArray([BI[BII)I", + "java/lang/StringLatin1.compareTo([B[B)I", + "java/lang/StringLatin1.compareToUTF16([B[B)I", + "java/lang/StringLatin1.equals([B[B)Z", + "java/lang/StringLatin1.indexOf([BI[BII)I", + "java/lang/StringLatin1.indexOf([B[B)I", + "java/lang/StringLatin1.inflate([BI[BII)V", + "java/lang/StringLatin1.inflate([BI[CII)V", + "java/lang/StringUTF16.compareTo([B[B)I", + "java/lang/StringUTF16.compareToLatin1([B[B)I", + "java/lang/StringUTF16.compress([BI[BII)I", + "java/lang/StringUTF16.compress([CI[BII)I", + "java/lang/StringUTF16.equals([B[B)Z", + "java/lang/StringUTF16.getChar([BI)C", + "java/lang/StringUTF16.getChars([BII[CI)V", + "java/lang/StringUTF16.indexOf([BI[BII)I", + "java/lang/StringUTF16.indexOf([B[B)I", + "java/lang/StringUTF16.indexOfChar([BIII)I", + "java/lang/StringUTF16.indexOfLatin1([BI[BII)I", + "java/lang/StringUTF16.indexOfLatin1([B[B)I", + "java/lang/StringUTF16.putChar([BII)V", + "java/lang/StringUTF16.toBytes([CII)[B", + "java/lang/Thread.onSpinWait()V", + "java/lang/invoke/MethodHandleImpl.isCompileConstant(Ljava/lang/Object;)Z", + "java/math/BigInteger.implMontgomeryMultiply([I[I[IIJ[I)[I", + "java/math/BigInteger.implMontgomerySquare([I[IIJ[I)[I", + "java/math/BigInteger.implMulAdd([I[IIII)I", + "java/math/BigInteger.implSquareToLen([II[II)[I", + "java/util/ArraysSupport.vectorizedMismatch(Ljava/lang/Object;JLjava/lang/Object;JII)I", + "java/util/stream/Streams$RangeIntSpliterator.forEachRemaining(Ljava/util/function/IntConsumer;)V", + "java/util/zip/Adler32.updateByteBuffer(IJII)I", + "java/util/zip/Adler32.updateBytes(I[BII)I", + "jdk/internal/misc/Unsafe.allocateUninitializedArray0(Ljava/lang/Class;I)Ljava/lang/Object;", + "jdk/internal/misc/Unsafe.compareAndExchangeByteAcquire(Ljava/lang/Object;JBB)B", + "jdk/internal/misc/Unsafe.compareAndExchangeByteRelease(Ljava/lang/Object;JBB)B", + "jdk/internal/misc/Unsafe.compareAndExchangeByteVolatile(Ljava/lang/Object;JBB)B", + "jdk/internal/misc/Unsafe.compareAndExchangeIntAcquire(Ljava/lang/Object;JII)I", + "jdk/internal/misc/Unsafe.compareAndExchangeIntRelease(Ljava/lang/Object;JII)I", + "jdk/internal/misc/Unsafe.compareAndExchangeIntVolatile(Ljava/lang/Object;JII)I", + "jdk/internal/misc/Unsafe.compareAndExchangeLongAcquire(Ljava/lang/Object;JJJ)J", + "jdk/internal/misc/Unsafe.compareAndExchangeLongRelease(Ljava/lang/Object;JJJ)J", + "jdk/internal/misc/Unsafe.compareAndExchangeLongVolatile(Ljava/lang/Object;JJJ)J", + "jdk/internal/misc/Unsafe.compareAndExchangeObjectAcquire(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + "jdk/internal/misc/Unsafe.compareAndExchangeObjectRelease(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + "jdk/internal/misc/Unsafe.compareAndExchangeObjectVolatile(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + "jdk/internal/misc/Unsafe.compareAndExchangeShortAcquire(Ljava/lang/Object;JSS)S", + "jdk/internal/misc/Unsafe.compareAndExchangeShortRelease(Ljava/lang/Object;JSS)S", + "jdk/internal/misc/Unsafe.compareAndExchangeShortVolatile(Ljava/lang/Object;JSS)S", + "jdk/internal/misc/Unsafe.compareAndSwapByte(Ljava/lang/Object;JBB)Z", + "jdk/internal/misc/Unsafe.compareAndSwapShort(Ljava/lang/Object;JSS)Z", + "jdk/internal/misc/Unsafe.copyMemory0(Ljava/lang/Object;JLjava/lang/Object;JJ)V", + "jdk/internal/misc/Unsafe.getAndAddByte(Ljava/lang/Object;JB)B", + "jdk/internal/misc/Unsafe.getAndAddShort(Ljava/lang/Object;JS)S", + "jdk/internal/misc/Unsafe.getAndSetByte(Ljava/lang/Object;JB)B", + "jdk/internal/misc/Unsafe.getAndSetShort(Ljava/lang/Object;JS)S", + "jdk/internal/misc/Unsafe.getBooleanAcquire(Ljava/lang/Object;J)Z", + "jdk/internal/misc/Unsafe.getBooleanOpaque(Ljava/lang/Object;J)Z", + "jdk/internal/misc/Unsafe.getByteAcquire(Ljava/lang/Object;J)B", + "jdk/internal/misc/Unsafe.getByteOpaque(Ljava/lang/Object;J)B", + "jdk/internal/misc/Unsafe.getCharAcquire(Ljava/lang/Object;J)C", + "jdk/internal/misc/Unsafe.getCharOpaque(Ljava/lang/Object;J)C", + "jdk/internal/misc/Unsafe.getDoubleAcquire(Ljava/lang/Object;J)D", + "jdk/internal/misc/Unsafe.getDoubleOpaque(Ljava/lang/Object;J)D", + "jdk/internal/misc/Unsafe.getFloatAcquire(Ljava/lang/Object;J)F", + "jdk/internal/misc/Unsafe.getFloatOpaque(Ljava/lang/Object;J)F", + "jdk/internal/misc/Unsafe.getIntAcquire(Ljava/lang/Object;J)I", + "jdk/internal/misc/Unsafe.getIntOpaque(Ljava/lang/Object;J)I", + "jdk/internal/misc/Unsafe.getLongAcquire(Ljava/lang/Object;J)J", + "jdk/internal/misc/Unsafe.getLongOpaque(Ljava/lang/Object;J)J", + "jdk/internal/misc/Unsafe.getObjectAcquire(Ljava/lang/Object;J)Ljava/lang/Object;", + "jdk/internal/misc/Unsafe.getObjectOpaque(Ljava/lang/Object;J)Ljava/lang/Object;", + "jdk/internal/misc/Unsafe.getShortAcquire(Ljava/lang/Object;J)S", + "jdk/internal/misc/Unsafe.getShortOpaque(Ljava/lang/Object;J)S", + "jdk/internal/misc/Unsafe.park(ZJ)V", + "jdk/internal/misc/Unsafe.putBooleanOpaque(Ljava/lang/Object;JZ)V", + "jdk/internal/misc/Unsafe.putByteOpaque(Ljava/lang/Object;JB)V", + "jdk/internal/misc/Unsafe.putCharOpaque(Ljava/lang/Object;JC)V", + "jdk/internal/misc/Unsafe.putDoubleOpaque(Ljava/lang/Object;JD)V", + "jdk/internal/misc/Unsafe.putFloatOpaque(Ljava/lang/Object;JF)V", + "jdk/internal/misc/Unsafe.putIntOpaque(Ljava/lang/Object;JI)V", + "jdk/internal/misc/Unsafe.putLongOpaque(Ljava/lang/Object;JJ)V", + "jdk/internal/misc/Unsafe.putObjectOpaque(Ljava/lang/Object;JLjava/lang/Object;)V", + "jdk/internal/misc/Unsafe.putShortOpaque(Ljava/lang/Object;JS)V", + "jdk/internal/misc/Unsafe.unpark(Ljava/lang/Object;)V", + "jdk/internal/misc/Unsafe.weakCompareAndSwapByte(Ljava/lang/Object;JBB)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapByteAcquire(Ljava/lang/Object;JBB)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapByteRelease(Ljava/lang/Object;JBB)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapByteVolatile(Ljava/lang/Object;JBB)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapInt(Ljava/lang/Object;JII)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapIntAcquire(Ljava/lang/Object;JII)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapIntRelease(Ljava/lang/Object;JII)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapIntVolatile(Ljava/lang/Object;JII)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapLong(Ljava/lang/Object;JJJ)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapLongAcquire(Ljava/lang/Object;JJJ)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapLongRelease(Ljava/lang/Object;JJJ)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapLongVolatile(Ljava/lang/Object;JJJ)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapObject(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapObjectAcquire(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapObjectRelease(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapObjectVolatile(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapShort(Ljava/lang/Object;JSS)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapShortAcquire(Ljava/lang/Object;JSS)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapShortRelease(Ljava/lang/Object;JSS)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSwapShortVolatile(Ljava/lang/Object;JSS)Z", + "jdk/internal/util/Preconditions.checkIndex(IILjava/util/function/BiFunction;)I", + "jdk/jfr/internal/JVM.counterTime()J", + "jdk/jfr/internal/JVM.getBufferWriter()Ljava/lang/Object;", + "jdk/jfr/internal/JVM.getClassId(Ljava/lang/Class;)J", + "sun/nio/cs/ISO_8859_1$Encoder.implEncodeISOArray([CI[BII)I", + "sun/security/provider/DigestBase.implCompressMultiBlock0([BII)I", + "sun/security/provider/SHA.implCompress0([BI)V", + "sun/security/provider/SHA2.implCompress0([BI)V", + "sun/security/provider/SHA5.implCompress0([BI)V"); + + if (!getHostArchitectureName().equals("amd64")) { + add(TO_BE_INVESTIGATED, + // Can we implement these on non-AMD64 platforms? C2 seems to. + "sun/misc/Unsafe.getAndAddInt(Ljava/lang/Object;JI)I", + "sun/misc/Unsafe.getAndAddLong(Ljava/lang/Object;JJ)J", + "sun/misc/Unsafe.getAndSetInt(Ljava/lang/Object;JI)I", + "sun/misc/Unsafe.getAndSetLong(Ljava/lang/Object;JJ)J", + "sun/misc/Unsafe.getAndSetObject(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;"); + // JDK 9 + add(TO_BE_INVESTIGATED, + "jdk/internal/misc/Unsafe.getAndAddInt(Ljava/lang/Object;JI)I", + "jdk/internal/misc/Unsafe.getAndAddLong(Ljava/lang/Object;JJ)J", + "jdk/internal/misc/Unsafe.getAndSetInt(Ljava/lang/Object;JI)I", + "jdk/internal/misc/Unsafe.getAndSetLong(Ljava/lang/Object;JJ)J", + "jdk/internal/misc/Unsafe.getAndSetObject(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;", + "jdk/internal/misc/Unsafe.getCharUnaligned(Ljava/lang/Object;J)C", + "jdk/internal/misc/Unsafe.getIntUnaligned(Ljava/lang/Object;J)I", + "jdk/internal/misc/Unsafe.getLongUnaligned(Ljava/lang/Object;J)J", + "jdk/internal/misc/Unsafe.getShortUnaligned(Ljava/lang/Object;J)S", + "jdk/internal/misc/Unsafe.putCharUnaligned(Ljava/lang/Object;JC)V", + "jdk/internal/misc/Unsafe.putIntUnaligned(Ljava/lang/Object;JI)V", + "jdk/internal/misc/Unsafe.putLongUnaligned(Ljava/lang/Object;JJ)V", + "jdk/internal/misc/Unsafe.putShortUnaligned(Ljava/lang/Object;JS)V"); + } + + HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class); + GraalHotSpotVMConfig config = rt.getVMConfig(); + + /* + * These are known to be implemented but the platform dependent conditions for when they are + * enabled are complex so just ignore them all the time. + */ + add(IGNORE, + "java/lang/Integer.bitCount(I)I", + "java/lang/Integer.numberOfLeadingZeros(I)I", + "java/lang/Integer.numberOfTrailingZeros(I)I", + "java/lang/Long.bitCount(J)I", + "java/lang/Long.numberOfLeadingZeros(J)I", + "java/lang/Long.numberOfTrailingZeros(J)I"); + + if (!config.useCRC32Intrinsics) { + // Registration of the CRC32 plugins is guarded by UseCRC32Intrinsics + add(IGNORE, "java/util/zip/CRC32.update(II)I"); + if (JAVA_SPECIFICATION_VERSION < 9) { + add(IGNORE, + "java/util/zip/CRC32.updateByteBuffer(IJII)I", + "java/util/zip/CRC32.updateBytes(I[BII)I"); + } else { + add(IGNORE, + "java/util/zip/CRC32.updateByteBuffer0(IJII)I", + "java/util/zip/CRC32.updateBytes0(I[BII)I", + "java/util/zip/CRC32C.updateBytes(I[BII)I", + "java/util/zip/CRC32C.updateDirectByteBuffer(IJII)I"); + } + } else { + if (JAVA_SPECIFICATION_VERSION >= 9) { + add(TO_BE_INVESTIGATED, + "java/util/zip/CRC32C.updateBytes(I[BII)I", + "java/util/zip/CRC32C.updateDirectByteBuffer(IJII)I"); + } + } + + if (!config.useAESIntrinsics) { + // Registration of the AES plugins is guarded by UseAESIntrinsics + if (JAVA_SPECIFICATION_VERSION < 9) { + add(IGNORE, + "com/sun/crypto/provider/AESCrypt.decryptBlock([BI[BI)V", + "com/sun/crypto/provider/AESCrypt.encryptBlock([BI[BI)V", + "com/sun/crypto/provider/CipherBlockChaining.decrypt([BII[BI)I", + "com/sun/crypto/provider/CipherBlockChaining.encrypt([BII[BI)I"); + } else { + add(IGNORE, + "com/sun/crypto/provider/AESCrypt.implDecryptBlock([BI[BI)V", + "com/sun/crypto/provider/AESCrypt.implEncryptBlock([BI[BI)V", + "com/sun/crypto/provider/CipherBlockChaining.implDecrypt([BII[BI)I", + "com/sun/crypto/provider/CipherBlockChaining.implEncrypt([BII[BI)I"); + } + } + if (!config.useMultiplyToLenIntrinsic()) { + // Registration of the AES plugins is guarded by UseAESIntrinsics + if (JAVA_SPECIFICATION_VERSION < 9) { + add(IGNORE, "java/math/BigInteger.multiplyToLen([II[II[I)[I"); + } else { + add(IGNORE, "java/math/BigInteger.implMultiplyToLen([II[II[I)[I"); + } + } + } + + private static String getHostArchitectureName() { + String arch = System.getProperty("os.arch"); + if (arch.equals("x86_64")) { + arch = "amd64"; + } else if (arch.equals("sparcv9")) { + arch = "sparc"; + } + return arch; + } + + @Test + @SuppressWarnings("try") + public void test() throws ClassNotFoundException { + HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class); + HotSpotProviders providers = rt.getHostBackend().getProviders(); + Map impl = new HashMap<>(); + Plugins graphBuilderPlugins = providers.getGraphBuilderPlugins(); + InvocationPlugins invocationPlugins = graphBuilderPlugins.getInvocationPlugins(); + for (ResolvedJavaMethod method : invocationPlugins.getMethods()) { + InvocationPlugin plugin = invocationPlugins.lookupInvocation(method); + assert plugin != null; + impl.put(method, plugin); + } + + Set methods = invocationPlugins.getMethods(); + HotSpotVMConfigStore store = rt.getVMConfig().getStore(); + List intrinsics = store.getIntrinsics(); + + List missing = new ArrayList<>(); + for (VMIntrinsicMethod intrinsic : intrinsics) { + ResolvedJavaMethod method = findMethod(methods, intrinsic); + if (method == null) { + method = resolveIntrinsic(providers.getMetaAccess(), intrinsic); + + IntrinsicMethod intrinsicMethod = null; + if (method != null) { + intrinsicMethod = providers.getConstantReflection().getMethodHandleAccess().lookupMethodHandleIntrinsic(method); + if (intrinsicMethod != null) { + continue; + } + } + String m = String.format("%s.%s%s", intrinsic.declaringClass, intrinsic.name, intrinsic.descriptor); + if (!TO_BE_INVESTIGATED.contains(m) && !IGNORE.contains(m)) { + missing.add(m); + } + } + } + + if (!missing.isEmpty()) { + Collections.sort(missing); + String missingString = missing.stream().collect(Collectors.joining(String.format("%n "))); + fail("missing Graal intrinsics for:%n %s", missingString); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java 2016-12-07 13:49:52.908475573 -0800 @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2014, 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.test; + +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +public class ClassSubstitutionsTests extends GraalCompilerTest { + + public Number instanceField; + + public Object[] arrayField; + + public String[] stringArrayField; + + @SuppressWarnings("try") + protected StructuredGraph test(final String snippet) { + try (Scope s = Debug.scope("ClassSubstitutionsTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + compile(graph.method(), graph); + assertNotInGraph(graph, Invoke.class); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet); + return graph; + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class clazz) { + for (Node node : graph.getNodes()) { + if (clazz.isInstance(node)) { + fail(node.toString()); + } + } + return graph; + } + + public boolean constantIsArray() { + return "".getClass().isArray(); + } + + public boolean constantIsInterface() { + return "".getClass().isInterface(); + } + + public boolean constantIsPrimitive() { + return "".getClass().isPrimitive(); + } + + @Test + public void testIsArray() { + testConstantReturn("constantIsArray", 0); + } + + @Test + public void testIsInterface() { + testConstantReturn("constantIsInterface", 0); + } + + @Test + public void testIsPrimitive() { + testConstantReturn("constantIsPrimitive", 0); + } + + public boolean fieldIsNotArray() { + if (instanceField != null) { + // The base type of instanceField is not Object or an Interface, so it's provably an + // instance type, so isArray will always return false. + return instanceField.getClass().isArray(); + } + return false; + } + + @Test + public void testFieldIsNotArray() { + testConstantReturn("fieldIsNotArray", 0); + } + + public boolean foldComponentType() { + return stringArrayField.getClass().getComponentType() == String.class; + } + + @Test + public void testFoldComponentType() { + testConstantReturn("foldComponentType", 1); + } + + @Test + public void testFieldIsArray() { + testConstantReturn("fieldIsArray", 1); + } + + public boolean fieldIsArray() { + if (arrayField != null) { + // The base type of arrayField is an array of some sort so isArray will always return + // true. + return arrayField.getClass().isArray(); + } + return true; + } + + private static class A { + } + + private static class B extends A { + } + + private static class C { + } + + private static final A a = new A(); + private static final B b = new B(); + private static final C c = new C(); + + public boolean classIsAssignable1() { + return a.getClass().isAssignableFrom(a.getClass()); + } + + public boolean classIsAssignable2() { + return a.getClass().isAssignableFrom(b.getClass()); + } + + public boolean classIsAssignable3() { + return a.getClass().isAssignableFrom(c.getClass()); + } + + public boolean classIsAssignable4() { + return b.getClass().isAssignableFrom(a.getClass()); + } + + public boolean classIsAssignable5() { + return c.getClass().isAssignableFrom(b.getClass()); + } + + public boolean classIsAssignable6() { + return int.class.isAssignableFrom(b.getClass()); + } + + public boolean classIsAssignable7() { + return int.class.isAssignableFrom(int.class); + } + + @Test + public void testClassIsAssignable() { + testConstantReturn("classIsAssignable1", 1); + testConstantReturn("classIsAssignable2", 1); + testConstantReturn("classIsAssignable3", 0); + testConstantReturn("classIsAssignable4", 0); + testConstantReturn("classIsAssignable5", 0); + testConstantReturn("classIsAssignable6", 0); + testConstantReturn("classIsAssignable7", 1); + } + + private void testConstantReturn(String name, Object value) { + StructuredGraph result = test(name); + ReturnNode ret = result.getNodes(ReturnNode.TYPE).first(); + assertDeepEquals(1, result.getNodes(ReturnNode.TYPE).count()); + + assertDeepEquals(true, ret.result().isConstant()); + assertDeepEquals(value, ret.result().asJavaConstant().asBoxedPrimitive()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java 2016-12-07 13:49:53.173487222 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.test; + +import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException; + +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.hotspot.CompileTheWorld; +import org.graalvm.compiler.hotspot.CompileTheWorld.Config; +import org.graalvm.compiler.hotspot.HotSpotGraalCompiler; + +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; + +/** + * Tests {@link CompileTheWorld} functionality. + */ +public class CompileTheWorldTest extends GraalCompilerTest { + + @Test + public void testJDK() throws Throwable { + boolean originalSetting = ExitVMOnException.getValue(); + // Compile a couple classes in rt.jar + HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime(); + System.setProperty(CompileTheWorld.LIMITMODS_PROPERTY_NAME, "java.base"); + new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), CompileTheWorld.SUN_BOOT_CLASS_PATH, new Config("Inline=false"), 1, 5, null, null, true).compile(); + assert ExitVMOnException.getValue() == originalSetting; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompressedOopTest.java 2016-12-07 13:49:53.439498914 -0800 @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.graalvm.compiler.hotspot.test; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; + +import jdk.vm.ci.hotspot.HotSpotInstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * The following tests perform object/array equality and assignments in various ways. The selected + * cases have been the problematic ones while implementing the Compressed Oops support. + */ +public class CompressedOopTest extends GraalCompilerTest { + + private HotSpotInstalledCode getInstalledCode(String name, Class... parameterTypes) throws Exception { + final ResolvedJavaMethod javaMethod = getResolvedJavaMethod(getClass(), name, parameterTypes); + final HotSpotInstalledCode installedBenchmarkCode = (HotSpotInstalledCode) getCode(javaMethod); + return installedBenchmarkCode; + } + + @Test + public void test() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("fieldTest", Object.class); + Container c1 = new Container(); + Assert.assertEquals(c1.b, installedBenchmarkCode.executeVarargs(c1)); + } + + public static Object fieldTest(Object c1) { + ((Container) c1).a = ((Container) c1).b; + return ((Container) c1).a; + } + + @Test + public void test1() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("arrayTest", Object.class, Object.class, Object.class); + ArrayContainer ac = new ArrayContainer(); + Assert.assertEquals(ac.a[9], installedBenchmarkCode.executeVarargs(ac.a, 0, 9)); + Assert.assertEquals(ac.a[8], installedBenchmarkCode.executeVarargs(ac.a, 1, 8)); + Assert.assertEquals(ac.a[7], installedBenchmarkCode.executeVarargs(ac.a, 2, 7)); + Assert.assertEquals(ac.a[6], installedBenchmarkCode.executeVarargs(ac.a, 3, 6)); + Assert.assertEquals(ac.a[5], installedBenchmarkCode.executeVarargs(ac.a, 4, 5)); + Assert.assertEquals(ac.a[4], installedBenchmarkCode.executeVarargs(ac.a, 5, 4)); + Assert.assertEquals(ac.a[3], installedBenchmarkCode.executeVarargs(ac.a, 6, 3)); + Assert.assertEquals(ac.a[2], installedBenchmarkCode.executeVarargs(ac.a, 7, 2)); + Assert.assertEquals(ac.a[1], installedBenchmarkCode.executeVarargs(ac.a, 8, 1)); + Assert.assertEquals(ac.a[0], installedBenchmarkCode.executeVarargs(ac.a, 9, 0)); + } + + public static Object arrayTest(Object c1, Object c2, Object c3) { + Object[] array = (Object[]) c1; + int initialIndex = ((Integer) c2).intValue(); + int replacingIndex = ((Integer) c3).intValue(); + array[initialIndex] = array[replacingIndex]; + return array[initialIndex]; + } + + @Test + public void test2() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("arrayCopyTest", Object.class, Object.class); + ArrayContainer source = new ArrayContainer(); + ArrayContainer destination = new ArrayContainer(); + Assert.assertEquals(source.a.length, destination.a.length); + Assert.assertFalse(Arrays.equals(source.a, destination.a)); + installedBenchmarkCode.executeVarargs(source.a, destination.a); + Assert.assertArrayEquals(source.a, destination.a); + } + + public static void arrayCopyTest(Object c1, Object c2) { + Object[] source = (Object[]) c1; + Object[] destination = (Object[]) c2; + System.arraycopy(source, 0, destination, 0, source.length); + } + + @Test + public void test3() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("compareAndSwapTest", Object.class, Object.class, Object.class); + Object initial = new Object(); + Object replacement = new Object(); + AtomicReference cas = new AtomicReference<>(); + Assert.assertEquals(cas.get(), null); + installedBenchmarkCode.executeVarargs(cas, null, initial); + Assert.assertEquals(cas.get(), initial); + installedBenchmarkCode.executeVarargs(cas, initial, replacement); + Assert.assertEquals(cas.get(), replacement); + } + + @SuppressWarnings("unchecked") + public static void compareAndSwapTest(Object c1, Object c2, Object c3) throws ClassCastException { + AtomicReference cas = (AtomicReference) c1; + cas.compareAndSet(c2, c3); + } + + @Test + public void test4() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("charArrayCopyTest", Object.class, Object.class, Object.class); + StringContainer1 source1 = new StringContainer1(); + StringContainer2 source2 = new StringContainer2(); + char[] result = new char[source1.value.length + source2.value.length]; + installedBenchmarkCode.executeVarargs(source1.value, source2.value, result); + Assert.assertArrayEquals(new char[]{'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'}, result); + } + + public static char[] charArrayCopyTest(Object c1, Object c2, Object c3) { + char[] source1 = (char[]) c1; + char[] source2 = (char[]) c2; + char[] result = (char[]) c3; + for (int i = 0; i < source1.length; i++) { + result[i] = source1[i]; + } + + for (int i = 0; i < source2.length; i++) { + result[source1.length + i] = source2[i]; + } + return result; + } + + @Test + public void test5() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("charContainerArrayCopyTest", Object.class, Object.class, Object.class); + StringContainer1 source1 = new StringContainer1(); + StringContainer2 source2 = new StringContainer2(); + char[] result = new char[source1.value.length + source2.value.length]; + installedBenchmarkCode.executeVarargs(source1, source2, result); + Assert.assertArrayEquals(new char[]{'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'}, result); + } + + public static char[] charContainerArrayCopyTest(Object c1, Object c2, Object c3) { + char[] source1 = ((StringContainer1) c1).value; + char[] source2 = ((StringContainer2) c2).value; + char[] result = (char[]) c3; + for (int i = 0; i < source1.length; i++) { + result[i] = source1[i]; + } + for (int i = 0; i < source2.length; i++) { + result[source1.length + i] = source2[i]; + } + return result; + } + + @Test + public void test6() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringCopyTest", Object.class, Object.class); + String a = new String("Test "); + String b = new String("String"); + String c = (String) installedBenchmarkCode.executeVarargs(a, b); + Assert.assertTrue(c.equals("Test String")); + } + + public static String stringCopyTest(Object c1, Object c2) { + String source = (String) c1; + String destination = (String) c2; + return source + destination; + } + + @Test + public void test7() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("queueTest", Object.class, Object.class); + ArrayDeque q = new ArrayDeque<>(); + Object[] objects = new Object[512]; + for (int i = 0; i < objects.length; i++) { + objects[i] = new Object(); + } + int j = 0; + while (j < objects.length) { + if (!installedBenchmarkCode.isValid()) { + // This can get invalidated due to lack of MDO update + installedBenchmarkCode = getInstalledCode("queueTest", Object.class, Object.class); + } + installedBenchmarkCode.executeVarargs(q, objects[j]); + j++; + } + + System.gc(); + Assert.assertTrue(q.size() == objects.length); + Assert.assertTrue(!q.isEmpty()); + j = 0; + while (j < objects.length) { + Assert.assertTrue(objects[j] == q.remove()); + j++; + } + + Assert.assertTrue(q.size() == 0); + Assert.assertTrue(q.isEmpty()); + } + + @SuppressWarnings("unchecked") + public static void queueTest(Object c1, Object c2) { + ArrayDeque queue = (ArrayDeque) c1; + queue.add(c2); + } + + @Test + public void test8() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("unmodListTest", Object.class); + List list = new ArrayList<>(); + for (int i = 0; i < 512; i++) { + list.add(new Object()); + } + Object[] array = (Object[]) installedBenchmarkCode.executeVarargs(list); + Assert.assertTrue(list.size() == array.length); + int i = 0; + for (Object obj : list) { + Assert.assertTrue(obj == array[i]); + i++; + } + } + + @SuppressWarnings("unchecked") + public static Object[] unmodListTest(Object c1) { + List queue = (ArrayList) c1; + Object[] result = Collections.unmodifiableCollection(queue).toArray(new Object[queue.size()]); + return result; + } + + @Test + public void test9() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("unmodListTest", Object.class); + List list = new ArrayList<>(); + Object[] array = (Object[]) installedBenchmarkCode.executeVarargs(list); + Assert.assertTrue(list.size() == array.length); + } + + public void test10() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("constantTest", Object.class); + Container c = new Container(); + Assert.assertFalse((boolean) installedBenchmarkCode.executeVarargs(c)); + } + + public static Boolean constantTest(Object c1) { + ConstantContainer container = (ConstantContainer) c1; + return container.a.equals(container.b); + } + + @Test + public void test11() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringEqualsTest", Object.class, Object.class); + String s1 = new String("Test"); + String s2 = new String("Test"); + boolean result = ((Boolean) (installedBenchmarkCode.executeVarargs(s1, s2))).booleanValue(); + Assert.assertTrue(result); + } + + public static Boolean stringEqualsTest(Object c1, Object c2) { + return ((String) c1).equals(c2); + } + + @Test + public void test12() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringConstantEqualsTest", Object.class); + String s1 = new String("Test"); + boolean result = ((Boolean) (installedBenchmarkCode.executeVarargs(s1))).booleanValue(); + Assert.assertTrue(result); + } + + public static Boolean stringConstantEqualsTest(Object c1) { + return "Test".equals(c1); + } + + @SuppressWarnings("unchecked") + public static Object[] unmodListTestByte(Object c1) { + List queue = (ArrayList) c1; + Byte[] result = Collections.unmodifiableCollection(queue).toArray(new Byte[queue.size()]); + return result; + } + + @Test + public void test13() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("unmodListTestByte", Object.class); + List list = new ArrayList<>(); + Byte[] array = (Byte[]) installedBenchmarkCode.executeVarargs(list); + Assert.assertTrue(list.size() == array.length); + } + + @Test + public void test14() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilderTest", Object.class, Object.class); + StringBuilder buffer = new StringBuilder("TestTestTestTestTestTestTest"); + Assert.assertTrue(buffer.length() == 28); + String a = new String("TestTestTestTestTestTestTest"); + installedBenchmarkCode.executeVarargs(buffer, a.toCharArray()); + Assert.assertTrue(buffer.length() == 56); + Assert.assertTrue(buffer.toString().equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest")); + } + + public static void stringBuilderTest(Object c1, Object c2) { + StringBuilder source = (StringBuilder) c1; + char[] add = (char[]) c2; + for (int i = 0; i < add.length; i++) { + source.append(add[i]); + } + } + + @Test + public void test15() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilderTestIn"); + installedBenchmarkCode.executeVarargs(); + } + + public static void stringBuilderTestIn() { + StringBuilder buffer = new StringBuilder("TestTestTestTestTestTestTest"); + Assert.assertTrue(buffer.length() == 28); + String a = new String("TestTestTestTestTestTestTest"); + char[] add = a.toCharArray(); + for (int i = 0; i < add.length; i++) { + buffer.append(add[i]); + } + Assert.assertTrue(buffer.length() == 56); + Assert.assertTrue(buffer.toString().equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest")); + } + + @Test + public void test16() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilderArrayCopy"); + installedBenchmarkCode.executeVarargs(); + } + + public static void stringBuilderArrayCopy() { + StringBuilder buffer = new StringBuilder("TestTestTestTestTestTestTest"); + Assert.assertTrue(buffer.length() == 28); + String a = new String("TestTestTestTestTestTestTest"); + char[] dst = new char[buffer.length() * 2]; + System.arraycopy(buffer.toString().toCharArray(), 0, dst, 0, buffer.length()); + System.arraycopy(a.toCharArray(), 0, dst, buffer.length(), buffer.length()); + Assert.assertTrue(dst.length == 56); + Assert.assertTrue(new String(dst).equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest")); + } + + @Test + public void test17() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringFormat"); + installedBenchmarkCode.executeVarargs(); + } + + public static void stringFormat() { + String.format("Hello %d", 0); + String.format("Hello %d", -11); + String.format("Hello %d", -2147483648); + } + + @Test + public void test18() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilder"); + StringBuilder b = (StringBuilder) installedBenchmarkCode.executeVarargs(); + Assert.assertTrue(b.capacity() == 16); + Assert.assertTrue(b.length() == 0); + } + + public static Object stringBuilder() { + return new StringBuilder(); + } + + static class Container { + + public Object a = new Object(); + public Object b = new Object(); + } + + static class ArrayContainer { + + public Object[] a = new Object[10]; + + ArrayContainer() { + for (int i = 0; i < 10; i++) { + a[i] = new Object(); + } + } + } + + static class HashMapContainer { + + public HashMap a = new HashMap<>(); + + HashMapContainer() { + for (int i = 0; i < 10; i++) { + a.put(new Object(), new Object()); + } + } + } + + static class StringContainer1 { + + public char[] value = new char[5]; + + StringContainer1() { + value[0] = 'T'; + value[1] = 'e'; + value[2] = 's'; + value[3] = 't'; + value[4] = ' '; + + } + } + + static class StringContainer2 { + + public char[] value = new char[6]; + + StringContainer2() { + value[0] = 'S'; + value[1] = 't'; + value[2] = 'r'; + value[3] = 'i'; + value[4] = 'n'; + value[5] = 'g'; + } + } + + static class ConstantContainer { + + public final Object a = new Object(); + public final Object b = new Object(); + + ConstantContainer() { + + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java 2016-12-07 13:49:53.705510606 -0800 @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2015, 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.test; + +import static org.graalvm.compiler.core.common.util.ModuleAPI.addExports; +import static org.graalvm.compiler.core.common.util.ModuleAPI.getModule; + +import java.lang.reflect.Method; + +import org.graalvm.compiler.core.common.util.Util; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.junit.BeforeClass; +import org.junit.Test; + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class ConstantPoolSubstitutionsTests extends GraalCompilerTest implements Opcodes { + + @SuppressWarnings("try") + protected StructuredGraph test(final String snippet) { + ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(getMethod(snippet)); + try (Scope s = Debug.scope("ConstantPoolSubstitutionsTests", method)) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + compile(graph.method(), graph); + assertNotInGraph(graph, Invoke.class); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet); + return graph; + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class clazz) { + for (Node node : graph.getNodes()) { + if (clazz.isInstance(node)) { + fail(node.toString()); + } + } + return graph; + } + + private static Object getConstantPoolForObject() { + String miscPackage = Java8OrEarlier ? "sun.misc" : "jdk.internal.misc"; + try { + Class sharedSecretsClass = Class.forName(miscPackage + ".SharedSecrets"); + Class javaLangAccessClass = Class.forName(miscPackage + ".JavaLangAccess"); + Object jla = sharedSecretsClass.getDeclaredMethod("getJavaLangAccess").invoke(null); + return javaLangAccessClass.getDeclaredMethod("getConstantPool", Class.class).invoke(jla, Object.class); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + /** + * Get the test methods from the generated class. + */ + @Override + protected Method getMethod(String methodName) { + Class cl; + try { + cl = LOADER.findClass(AsmLoader.NAME); + addExports(cl); + } catch (ClassNotFoundException e) { + throw new AssertionError(e); + } + return getMethod(cl, methodName); + } + + @BeforeClass + public static void beforeClass() { + addExports(AsmLoader.class); + } + + /** + * This test uses some API hidden by the JDK9 module system. + */ + private static void addExports(Class c) { + if (!Util.Java8OrEarlier) { + Object javaBaseModule = getModule.invoke(String.class); + Object cModule = getModule.invoke(c); + addExports.invokeStatic(javaBaseModule, "jdk.internal.reflect", cModule); + addExports.invokeStatic(javaBaseModule, "jdk.internal.misc", cModule); + } + } + + /** + * Disables these tests until we know how to dynamically export the {@code jdk.internal.reflect} + * package from the {@code java.base} module to the unnamed module associated with + * {@link AsmLoader}. Without such an export, the test fails as follows: + * + *
    +     * Caused by: java.lang.IllegalAccessError: class org.graalvm.compiler.hotspot.test.ConstantPoolTest
    +     * (in unnamed module @0x57599b23) cannot access class jdk.internal.reflect.ConstantPool (in
    +     * module java.base) because module java.base does not export jdk.internal.reflect to unnamed
    +     * module @0x57599b23
    +     * 
    + */ + private static void assumeJDK8() { + // Assume.assumeTrue(Java8OrEarlier); + } + + @Test + public void testGetSize() { + assumeJDK8(); + Object cp = getConstantPoolForObject(); + test("getSize", cp); + } + + @Test + public void testGetIntAt() { + assumeJDK8(); + test("getIntAt"); + } + + @Test + public void testGetLongAt() { + assumeJDK8(); + test("getLongAt"); + } + + @Test + public void testGetFloatAt() { + assumeJDK8(); + test("getFloatAt"); + } + + @Test + public void testGetDoubleAt() { + assumeJDK8(); + test("getDoubleAt"); + } + + // @Test + public void testGetUTF8At() { + assumeJDK8(); + test("getUTF8At"); + } + + private static final String PACKAGE_NAME = ConstantPoolSubstitutionsTests.class.getPackage().getName(); + private static final String PACKAGE_NAME_INTERNAL = PACKAGE_NAME.replace('.', '/'); + + private static AsmLoader LOADER = new AsmLoader(ConstantPoolSubstitutionsTests.class.getClassLoader()); + + public static class AsmLoader extends ClassLoader { + Class loaded; + + static final String NAME = PACKAGE_NAME + ".ConstantPoolTest"; + + public AsmLoader(ClassLoader parent) { + super(parent); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals(NAME)) { + if (loaded != null) { + return loaded; + } + byte[] bytes = generateClass(); + return (loaded = defineClass(name, bytes, 0, bytes.length)); + } else { + return super.findClass(name); + } + } + } + + // @formatter:off + /* + static class ConstantPoolTest { + public static int getSize(Object o) { + ConstantPool cp = (ConstantPool) o; + return cp.getSize(); + } + + public static int getIntAt(Object o) { + ConstantPool cp = (ConstantPool) o; + return cp.getIntAt(0); + } + + public static long getLongAt(Object o) { + ConstantPool cp = (ConstantPool) o; + return cp.getLongAt(0); + } + + public static float getFloatAt(Object o) { + ConstantPool cp = (ConstantPool) o; + return cp.getFloatAt(0); + } + + public static double getDoubleAt(Object o) { + ConstantPool cp = (ConstantPool) o; + return cp.getDoubleAt(0); + } + + public static String getUTF8At(Object o) { + ConstantPool cp = (ConstantPool) o; + return cp.getUTF8At(0); + } + } + */ + // @formatter:on + private static byte[] generateClass() { + + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + + cw.visit(52, ACC_SUPER, PACKAGE_NAME_INTERNAL + "/ConstantPoolTest", null, "java/lang/Object", null); + cw.visitInnerClass(PACKAGE_NAME_INTERNAL + "/ConstantPoolTest", PACKAGE_NAME_INTERNAL + "/ConstantPoolSubstitutionsTests", "ConstantPoolTest", + ACC_STATIC); + String constantPool = Java8OrEarlier ? "sun/reflect/ConstantPool" : "jdk/internal/reflect/ConstantPool"; + + mv = cw.visitMethod(0, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getSize", "(Ljava/lang/Object;)I", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, constantPool); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getSize", "()I", false); + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 3); + mv.visitEnd(); + + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getIntAt", "(Ljava/lang/Object;)I", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, constantPool); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getIntAt", "(I)I", false); + mv.visitInsn(IRETURN); + mv.visitMaxs(2, 3); + mv.visitEnd(); + + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getLongAt", "(Ljava/lang/Object;)J", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, constantPool); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getLongAt", "(I)J", false); + mv.visitInsn(LRETURN); + mv.visitMaxs(2, 3); + mv.visitEnd(); + + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getFloatAt", "(Ljava/lang/Object;)F", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, constantPool); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getFloatAt", "(I)F", false); + mv.visitInsn(FRETURN); + mv.visitMaxs(2, 3); + mv.visitEnd(); + + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getDoubleAt", "(Ljava/lang/Object;)D", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, constantPool); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getDoubleAt", "(I)D", false); + mv.visitInsn(DRETURN); + mv.visitMaxs(2, 3); + mv.visitEnd(); + + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getUTF8At", "(Ljava/lang/Object;)Ljava/lang/String;", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, constantPool); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getUTF8At", "(I)Ljava/lang/String;", false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 3); + mv.visitEnd(); + cw.visitEnd(); + + return cw.toByteArray(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DataPatchTest.java 2016-12-07 13:49:53.969522211 -0800 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014, 2015, 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.test; + +import org.junit.Assume; +import org.junit.Test; + +import org.graalvm.compiler.hotspot.CompressEncoding; +import org.graalvm.compiler.hotspot.nodes.CompressionNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.debug.OpaqueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class DataPatchTest extends HotSpotGraalCompilerTest { + + public static double doubleSnippet() { + return 84.72; + } + + @Test + public void doubleTest() { + test("doubleSnippet"); + } + + public static Object oopSnippet() { + return "asdf"; + } + + @Test + public void oopTest() { + test("oopSnippet"); + } + + private static Object compressUncompress(Object obj) { + return obj; + } + + public static Object narrowOopSnippet() { + return compressUncompress("narrowAsdf"); + } + + @Test + public void narrowOopTest() { + Assume.assumeTrue("skipping narrow oop data patch test", runtime().getVMConfig().useCompressedOops); + test("narrowOopSnippet"); + } + + @Override + protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) { + InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins(); + Registration r = new Registration(invocationPlugins, DataPatchTest.class); + r.register1("compressUncompress", Object.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + CompressEncoding encoding = runtime().getVMConfig().getOopEncoding(); + ValueNode compressed = b.add(CompressionNode.compress(arg, encoding)); + ValueNode proxy = b.add(new OpaqueNode(compressed)); + b.addPush(JavaKind.Object, CompressionNode.uncompress(proxy, encoding)); + return true; + } + }); + return super.editGraphBuilderConfiguration(conf); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ExplicitExceptionTest.java 2016-12-07 13:49:54.235533903 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011, 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.test; + +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class ExplicitExceptionTest extends GraalCompilerTest { + + private int expectedForeignCallCount; + + @Override + protected InstalledCode getCode(ResolvedJavaMethod method) { + InstalledCode installedCode = super.getCode(method); + assertDeepEquals(expectedForeignCallCount, lastCompiledGraph.getNodes().filter(ForeignCallNode.class).count()); + return installedCode; + } + + public static int testAIOOBESnippet(int[] array) { + return array[10]; + } + + @Test + public void testAIOOBE() { + int[] array = new int[4]; + for (int i = 0; i < 10000; i++) { + try { + testAIOOBESnippet(array); + } catch (ArrayIndexOutOfBoundsException e) { + // nothing to do + } + } + expectedForeignCallCount = 2; + test("testAIOOBESnippet", array); + } + + public static int testNPEArraySnippet(int[] array) { + return array[10]; + } + + @Test + public void testNPEArray() { + int[] array = null; + for (int i = 0; i < 10000; i++) { + try { + testNPEArraySnippet(array); + } catch (NullPointerException e) { + // nothing to do + } + } + expectedForeignCallCount = 2; + test("testNPEArraySnippet", array); + } + + private static class TestClass { + int field; + } + + public static int testNPESnippet(TestClass obj) { + return obj.field; + } + + @SuppressWarnings("unused") + @Test + public void testNPE() { + new TestClass(); + TestClass obj = null; + for (int i = 0; i < 10000; i++) { + try { + testNPESnippet(obj); + } catch (NullPointerException e) { + // nothing to do + } + } + expectedForeignCallCount = 1; + test("testNPESnippet", obj); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ForeignCallDeoptimizeTest.java 2016-12-07 13:49:54.500545552 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2014, 2015, 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.test; + +import org.junit.Test; + +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Tests that deoptimization upon exception handling works. + */ +public class ForeignCallDeoptimizeTest extends GraalCompilerTest { + + @Override + protected Plugins getDefaultGraphBuilderPlugins() { + ForeignCallsProvider foreignCalls = ((HotSpotProviders) getProviders()).getForeignCalls(); + + Plugins ret = super.getDefaultGraphBuilderPlugins(); + ret.getInvocationPlugins().register(new InvocationPlugin() { + + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + ForeignCallNode node = new ForeignCallNode(foreignCalls, HotSpotForeignCallsProviderImpl.TEST_DEOPTIMIZE_CALL_INT, arg); + b.addPush(JavaKind.Int, node); + return true; + } + }, ForeignCallDeoptimizeTest.class, "testCallInt", int.class); + return ret; + } + + public static int testCallInt(int value) { + return value; + } + + public static int testForeignCall(int value) { + if (testCallInt(value) != value) { + throw new InternalError(); + } + return value; + } + + @Test + public void test1() { + test("testForeignCall", 0); + } + + @Test + public void test2() { + test("testForeignCall", -1); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java 2016-12-07 13:49:54.767557288 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, 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.test; + +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; + +/** + * Test on-stack-replacement with locks. + */ +public class GraalOSRLockTest extends GraalOSRTestBase { + + @Ignore("OSR with locks not supported") + @Test + public void testOSR() { + testOSR("test"); + } + + static int limit = 10000; + + private static Object lock = new Object(); + + public static ReturnValue test() { + synchronized (lock) { + for (int i = 0; i < limit * limit; i++) { + GraalDirectives.blackhole(i); + if (GraalDirectives.inCompiledCode()) { + return ReturnValue.SUCCESS; + } + } + return ReturnValue.FAILURE; + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTest.java 2016-12-07 13:49:55.033568980 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016, 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.test; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; + +/** + * Test on-stack-replacement with Graal. The test manually triggers a Graal OSR-compilation which is + * later invoked when hitting the backedge counter overflow. + */ +public class GraalOSRTest extends GraalOSRTestBase { + + @Test + public void testOSR() { + testOSR("test"); + } + + static int limit = 10000; + + public static ReturnValue test() { + for (int i = 0; i < limit * limit; i++) { + GraalDirectives.blackhole(i); + if (GraalDirectives.inCompiledCode()) { + return ReturnValue.SUCCESS; + } + } + return ReturnValue.FAILURE; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTestBase.java 2016-12-07 13:49:55.297580585 -0800 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016, 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.test; + +import org.junit.Assert; + +import org.graalvm.compiler.bytecode.Bytecode; +import org.graalvm.compiler.bytecode.BytecodeStream; +import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; +import org.graalvm.compiler.core.target.Backend; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.CompilationTask; +import org.graalvm.compiler.hotspot.HotSpotGraalCompiler; +import org.graalvm.compiler.java.BciBlockMapping; +import org.graalvm.compiler.java.BciBlockMapping.BciBlock; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.hotspot.HotSpotCompilationRequest; +import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public abstract class GraalOSRTestBase extends GraalCompilerTest { + + protected void testOSR(String methodName) { + ResolvedJavaMethod method = getResolvedJavaMethod(methodName); + testOSR(method); + } + + protected void testOSR(ResolvedJavaMethod method) { + // invalidate any existing compiled code + method.reprofile(); + compileOSR(method); + Result result = executeExpected(method, null); + checkResult(result); + } + + private static void compile(ResolvedJavaMethod method, int bci) { + HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime(); + long jvmciEnv = 0L; + HotSpotCompilationRequest request = new HotSpotCompilationRequest((HotSpotResolvedJavaMethod) method, bci, jvmciEnv); + HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) runtime.getCompiler(); + CompilationTask task = new CompilationTask(runtime, compiler, request, true, true); + HotSpotCompilationRequestResult result = task.runCompilation(); + if (result.getFailure() != null) { + throw new GraalError(result.getFailureMessage()); + } + } + + /** + * Returns the target BCI of the first bytecode backedge. This is where HotSpot triggers + * on-stack-replacement in case the backedge counter overflows. + */ + private static int getBackedgeBCI(ResolvedJavaMethod method) { + Bytecode code = new ResolvedJavaMethodBytecode(method); + BytecodeStream stream = new BytecodeStream(code.getCode()); + BciBlockMapping bciBlockMapping = BciBlockMapping.create(stream, code); + assert bciBlockMapping.getLoopCount() == 1 : "Expected exactly one loop " + method; + + for (BciBlock block : bciBlockMapping.getBlocks()) { + int bci = block.startBci; + for (BciBlock succ : block.getSuccessors()) { + int succBci = succ.startBci; + if (succBci < bci) { + // back edge + return succBci; + } + } + } + return -1; + } + + private static void checkResult(Result result) { + Assert.assertNull("Unexpected exception", result.exception); + Assert.assertNotNull(result.returnValue); + Assert.assertTrue(result.returnValue instanceof ReturnValue); + Assert.assertEquals(ReturnValue.SUCCESS, result.returnValue); + } + + private void compileOSR(ResolvedJavaMethod method) { + int bci = getBackedgeBCI(method); + assert bci != -1; + // ensure eager resolving + parseEager(method, AllowAssumptions.YES); + compile(method, bci); + } + + protected enum ReturnValue { + SUCCESS, + FAILURE + } + + public GraalOSRTestBase() { + super(); + } + + public GraalOSRTestBase(Class arch) { + super(arch); + } + + public GraalOSRTestBase(Backend backend) { + super(backend); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotCryptoSubstitutionTest.java 2016-12-07 13:49:55.563592277 -0800 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2013, 2016, 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.test; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.AlgorithmParameters; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Tests the intrinsification of certain crypto methods. + */ +public class HotSpotCryptoSubstitutionTest extends HotSpotGraalCompilerTest { + + @Override + protected InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) { + return getBackend().createDefaultInstalledCode(method, compResult); + } + + SecretKey aesKey; + SecretKey desKey; + byte[] input; + ByteArrayOutputStream aesExpected = new ByteArrayOutputStream(); + ByteArrayOutputStream desExpected = new ByteArrayOutputStream(); + + public HotSpotCryptoSubstitutionTest() throws Exception { + byte[] seed = {0x4, 0x7, 0x1, 0x1}; + SecureRandom random = new SecureRandom(seed); + KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES"); + KeyGenerator desKeyGen = KeyGenerator.getInstance("DESede"); + aesKeyGen.init(128, random); + desKeyGen.init(168, random); + aesKey = aesKeyGen.generateKey(); + desKey = desKeyGen.generateKey(); + input = readClassfile16(getClass()); + + aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding")); + aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding")); + + desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding")); + desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding")); + } + + @Test + public void testAESCryptIntrinsics() throws Exception { + if (compileAndInstall("com.sun.crypto.provider.AESCrypt", HotSpotGraphBuilderPlugins.aesEncryptName, HotSpotGraphBuilderPlugins.aesDecryptName)) { + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding")); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding")); + Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray()); + } + } + + @Test + public void testCipherBlockChainingIntrinsics() throws Exception { + if (compileAndInstall("com.sun.crypto.provider.CipherBlockChaining", HotSpotGraphBuilderPlugins.cbcEncryptName, HotSpotGraphBuilderPlugins.cbcDecryptName)) { + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding")); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding")); + Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray()); + + actual.reset(); + actual.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding")); + actual.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding")); + Assert.assertArrayEquals(desExpected.toByteArray(), actual.toByteArray()); + } + } + + /** + * Compiles and installs the substitution for some specified methods. Once installed, the next + * execution of the methods will use the newly installed code. + * + * @param className the name of the class for which substitutions are available + * @param methodNames the names of the substituted methods + * @return true if at least one substitution was compiled and installed + */ + private boolean compileAndInstall(String className, String... methodNames) { + if (!runtime().getVMConfig().useAESIntrinsics) { + return false; + } + Class c; + try { + c = Class.forName(className); + } catch (ClassNotFoundException e) { + // It's ok to not find the class - a different security provider + // may have been installed + return false; + } + boolean atLeastOneCompiled = false; + for (String methodName : methodNames) { + if (compileAndInstallSubstitution(c, methodName) != null) { + atLeastOneCompiled = true; + } + } + return atLeastOneCompiled; + } + + AlgorithmParameters algorithmParameters; + + private byte[] encrypt(byte[] indata, SecretKey key, String algorithm) throws Exception { + + byte[] result = indata; + + Cipher c = Cipher.getInstance(algorithm); + c.init(Cipher.ENCRYPT_MODE, key); + algorithmParameters = c.getParameters(); + + byte[] r1 = c.update(result); + byte[] r2 = c.doFinal(); + + result = new byte[r1.length + r2.length]; + System.arraycopy(r1, 0, result, 0, r1.length); + System.arraycopy(r2, 0, result, r1.length, r2.length); + + return result; + } + + private byte[] decrypt(byte[] indata, SecretKey key, String algorithm) throws Exception { + + byte[] result = indata; + + Cipher c = Cipher.getInstance(algorithm); + c.init(Cipher.DECRYPT_MODE, key, algorithmParameters); + + byte[] r1 = c.update(result); + byte[] r2 = c.doFinal(); + + result = new byte[r1.length + r2.length]; + System.arraycopy(r1, 0, result, 0, r1.length); + System.arraycopy(r2, 0, result, r1.length, r2.length); + return result; + } + + private static byte[] readClassfile16(Class c) throws IOException { + String classFilePath = "/" + c.getName().replace('.', '/') + ".class"; + InputStream stream = c.getResourceAsStream(classFilePath); + int bytesToRead = stream.available(); + bytesToRead -= bytesToRead % 16; + byte[] classFile = new byte[bytesToRead]; + new DataInputStream(stream).readFully(classFile); + return classFile; + } + + public byte[] runEncryptDecrypt(SecretKey key, String algorithm) throws Exception { + byte[] indata = input.clone(); + byte[] cipher = encrypt(indata, key, algorithm); + byte[] plain = decrypt(cipher, key, algorithm); + Assert.assertArrayEquals(indata, plain); + return plain; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalCompilerTest.java 2016-12-07 13:49:55.827603882 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, 2016, 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.test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotGraalCompiler; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.runtime.JVMCI; + +/** + * A Graal compiler test that needs access to the {@link HotSpotGraalRuntimeProvider}. + */ +public abstract class HotSpotGraalCompilerTest extends GraalCompilerTest { + + /** + * Gets the {@link HotSpotGraalRuntimeProvider}. + */ + protected HotSpotGraalRuntimeProvider runtime() { + return ((HotSpotBackend) getBackend()).getRuntime(); + } + + protected InstalledCode compileAndInstallSubstitution(Class c, String methodName) { + ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(getMethod(c, methodName)); + HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) JVMCI.getRuntime().getCompiler(); + HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class); + HotSpotProviders providers = rt.getHostBackend().getProviders(); + CompilationIdentifier compilationId = runtime().getHostBackend().getCompilationIdentifier(method); + StructuredGraph graph = compiler.getIntrinsicGraph(method, providers, compilationId); + if (graph != null) { + return getCode(method, graph, true, true); + } + return null; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java 2016-12-07 13:49:56.092615530 -0800 @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2012, 2015, 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.test; + +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.replacements.test.MethodSubstitutionTest; + +/** + * Tests HotSpot specific {@link MethodSubstitution}s. + */ +public class HotSpotMethodSubstitutionTest extends MethodSubstitutionTest { + + @Test + public void testObjectSubstitutions() { + TestClassA obj = new TestClassA(); + + testGraph("getClass0"); + testGraph("objectHashCode"); + + test("getClass0", "a string"); + test("objectHashCode", obj); + } + + @SuppressWarnings("all") + public static Class getClass0(Object obj) { + return obj.getClass(); + } + + @SuppressWarnings("all") + public static int objectHashCode(TestClassA obj) { + return obj.hashCode(); + } + + @Test + public void testClassSubstitutions() { + testGraph("getModifiers"); + testGraph("isInterface"); + testGraph("isArray"); + testGraph("isPrimitive"); + testGraph("getSuperClass"); + testGraph("getComponentType"); + + for (Class c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) { + test("getModifiers", c); + test("isInterface", c); + test("isArray", c); + test("isPrimitive", c); + test("getSuperClass", c); + test("getComponentType", c); + } + } + + @SuppressWarnings("all") + public static int getModifiers(Class clazz) { + return clazz.getModifiers(); + } + + @SuppressWarnings("all") + public static boolean isInterface(Class clazz) { + return clazz.isInterface(); + } + + @SuppressWarnings("all") + public static boolean isArray(Class clazz) { + return clazz.isArray(); + } + + @SuppressWarnings("all") + public static boolean isPrimitive(Class clazz) { + return clazz.isPrimitive(); + } + + @SuppressWarnings("all") + public static Class getSuperClass(Class clazz) { + return clazz.getSuperclass(); + } + + @SuppressWarnings("all") + public static Class getComponentType(Class clazz) { + return clazz.getComponentType(); + } + + @Test + public void testThreadSubstitutions() { + testGraph("currentThread"); + testGraph("threadIsInterrupted"); + testGraph("threadInterrupted"); + + Thread currentThread = Thread.currentThread(); + test("currentThread", currentThread); + test("threadIsInterrupted", currentThread); + } + + @SuppressWarnings("all") + public static boolean currentThread(Thread other) { + return Thread.currentThread() == other; + } + + @SuppressWarnings("all") + public static boolean threadIsInterrupted(Thread thread) { + return thread.isInterrupted(); + } + + @SuppressWarnings("all") + public static boolean threadInterrupted() { + return Thread.interrupted(); + } + + @Test + public void testSystemSubstitutions() { + testGraph("systemTime"); + testGraph("systemIdentityHashCode"); + + for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) { + test("systemIdentityHashCode", o); + } + } + + @SuppressWarnings("all") + public static long systemTime() { + return System.currentTimeMillis() + System.nanoTime(); + } + + @SuppressWarnings("all") + public static int systemIdentityHashCode(Object obj) { + return System.identityHashCode(obj); + } + + private static class TestClassA { + } + + public static String testCallSiteGetTargetSnippet(int i) throws Exception { + ConstantCallSite site; + MethodHandles.Lookup lookup = MethodHandles.lookup(); + switch (i) { + case 1: + site = GraalDirectives.opaque(new ConstantCallSite(lookup.findVirtual(String.class, "replace", MethodType.methodType(String.class, char.class, char.class)))); + break; + default: + site = GraalDirectives.opaque(new ConstantCallSite(lookup.findStatic(java.util.Arrays.class, "asList", MethodType.methodType(java.util.List.class, Object[].class)))); + } + return site.getTarget().toString(); + } + + public static String testCastSnippet(int i, Object obj) throws Exception { + Class c; + switch (i) { + case 1: + c = GraalDirectives.opaque(Number.class); + break; + default: + c = GraalDirectives.opaque(Integer.class); + break; + } + return c.cast(obj).toString(); + } + + public static String testGetClassSnippet(int i) { + Object c; + switch (i) { + case 1: + c = GraalDirectives.opaque(new Object()); + break; + default: + c = GraalDirectives.opaque("TEST"); + break; + } + return c.getClass().toString(); + } + + /** + * Tests ambiguous receiver of CallSite.getTarget. + */ + @Test + public void testCallSiteGetTarget() { + test("testCallSiteGetTargetSnippet", 1); + } + + /** + * Tests ambiguous receiver of Class.cast. + */ + @Test + public void testCast() { + test("testCastSnippet", 1, new Integer(1)); + } + + /** + * Tests ambiguous receiver of Object.getClass. + */ + @Test + public void testGetClass() { + test("testGetClassSnippet", 1); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMonitorValueTest.java 2016-12-07 13:49:56.360627311 -0800 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011, 2016, 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.test; + +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.StackLockValue; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class HotSpotMonitorValueTest extends GraalCompilerTest { + + @Override + protected InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) { + for (Infopoint i : compResult.getInfopoints()) { + if (i instanceof Call) { + Call call = (Call) i; + if (call.target instanceof ResolvedJavaMethod) { + ResolvedJavaMethod target = (ResolvedJavaMethod) call.target; + if (target.equals(lookupObjectWait())) { + BytecodeFrame frame = call.debugInfo.frame(); + BytecodeFrame caller = frame.caller(); + assertNotNull(caller); + assertNull(caller.caller()); + assertDeepEquals(2, frame.numLocks); + assertDeepEquals(2, caller.numLocks); + StackLockValue lock1 = (StackLockValue) frame.getLockValue(0); + StackLockValue lock2 = (StackLockValue) frame.getLockValue(1); + StackLockValue lock3 = (StackLockValue) caller.getLockValue(0); + StackLockValue lock4 = (StackLockValue) caller.getLockValue(1); + + List locks = Arrays.asList(lock1, lock2, lock3, lock4); + for (StackLockValue lock : locks) { + for (StackLockValue other : locks) { + if (other != lock) { + // Every lock must have a different stack slot + assertThat(lock.getSlot(), not(other.getSlot())); + } + } + } + assertDeepEquals(lock3.getOwner(), lock4.getOwner()); + assertThat(lock1.getOwner(), not(lock2.getOwner())); + return super.addMethod(method, compResult); + } + } + } + } + throw new AssertionError("Could not find debug info for call to Object.wait(long)"); + } + + private ResolvedJavaMethod lookupObjectWait() { + try { + return getMetaAccess().lookupJavaMethod(Object.class.getDeclaredMethod("wait", long.class)); + } catch (Exception e) { + throw new GraalError("Could not find Object.wait(long): %s", e); + } + } + + @Test + public void test() { + test("testSnippet", "a", "b"); + } + + private static void locks2(Object a, Object b) throws InterruptedException { + synchronized (a) { + synchronized (b) { + a.wait(5); + } + } + } + + public static void testSnippet(Object a, Object b) throws InterruptedException { + synchronized (a) { + synchronized (a) { + locks2(a, b); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotNmethodTest.java 2016-12-07 13:49:56.627639047 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.test; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.hotspot.HotSpotNmethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class HotSpotNmethodTest extends GraalCompilerTest { + + private static final int ITERATION_COUNT = 100000; + + @Test + public void testInstallCodeInvalidation() { + final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo"); + final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", AllowAssumptions.YES)); + Assert.assertTrue(nmethod.isValid()); + Object result; + try { + result = nmethod.executeVarargs(null, "b", "c"); + assertDeepEquals(43, result); + } catch (InvalidInstalledCodeException e) { + Assert.fail("Code was invalidated"); + } + Assert.assertTrue(nmethod.isValid()); + nmethod.invalidate(); + Assert.assertFalse(nmethod.isValid()); + try { + result = nmethod.executeVarargs(null, null, null); + Assert.fail("Code was not invalidated"); + } catch (InvalidInstalledCodeException e) { + } + Assert.assertFalse(nmethod.isValid()); + } + + @Test + public void testInstallCodeInvalidationWhileRunning() { + final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo"); + final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", AllowAssumptions.YES)); + Object result; + try { + result = nmethod.executeVarargs(nmethod, null, null); + assertDeepEquals(43, result); + } catch (InvalidInstalledCodeException e) { + Assert.fail("Code was invalidated"); + } + Assert.assertFalse(nmethod.isValid()); + } + + @Test + public void testInstalledCodeCalledFromCompiledCode() { + final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo"); + final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", AllowAssumptions.YES)); + Assert.assertTrue(nmethod.isValid()); + try { + for (int i = 0; i < ITERATION_COUNT; ++i) { + nmethod.executeVarargs(null, "b", "c"); + } + } catch (InvalidInstalledCodeException e) { + Assert.fail("Code was invalidated"); + } + } + + @SuppressWarnings("unused") + public static Object foo(HotSpotNmethod method, Object a2, Object a3) { + return 42; + } + + @SuppressWarnings("unused") + public static Object otherFoo(HotSpotNmethod method, Object a2, Object a3) { + if (method != null) { + method.invalidate(); + } + return 43; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotNodeSubstitutionsTest.java 2016-12-07 13:49:56.892650695 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 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.test; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; + +import org.junit.Test; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.replacements.test.MethodSubstitutionTest; + +/** + * Tests HotSpot specific substitutions for {@link Node}. + */ +public class HotSpotNodeSubstitutionsTest extends MethodSubstitutionTest { + + @Test + public void test() { + StructuredGraph graph = new StructuredGraph(AllowAssumptions.YES, INVALID_COMPILATION_ID); + test("getNodeClass", ConstantNode.forInt(42, graph)); + } + + public static NodeClass getNodeClass(Node n) { + return n.getNodeClass(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotResolvedJavaFieldTest.java 2016-12-07 13:49:57.157662344 -0800 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013, 2015, 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.test; + +import static java.lang.reflect.Modifier.FINAL; +import static java.lang.reflect.Modifier.PRIVATE; +import static java.lang.reflect.Modifier.PROTECTED; +import static java.lang.reflect.Modifier.PUBLIC; +import static java.lang.reflect.Modifier.STATIC; +import static java.lang.reflect.Modifier.TRANSIENT; +import static java.lang.reflect.Modifier.VOLATILE; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; + +import jdk.vm.ci.hotspot.HotSpotResolvedJavaField; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaField; + +/** + * Tests {@link HotSpotResolvedJavaField} functionality. + */ +public class HotSpotResolvedJavaFieldTest extends HotSpotGraalCompilerTest { + + private static final Class[] classesWithInternalFields = {Class.class, ClassLoader.class}; + + private static final Method createFieldMethod; + + static { + Method ret = null; + try { + Class typeImpl = Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl"); + ret = typeImpl.getDeclaredMethod("createField", String.class, JavaType.class, long.class, int.class); + ret.setAccessible(true); + } catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) { + e.printStackTrace(); + } + + createFieldMethod = ret; + } + + /** + * Same as {@code HotSpotModifiers.jvmFieldModifiers()} but works when using a JVMCI version + * prior to the introduction of that method. + */ + private int jvmFieldModifiers() { + GraalHotSpotVMConfig config = runtime().getVMConfig(); + int accEnum = config.getConstant("JVM_ACC_ENUM", Integer.class, 0x4000); + int accSynthetic = config.getConstant("JVM_ACC_SYNTHETIC", Integer.class, 0x1000); + return PUBLIC | PRIVATE | PROTECTED | STATIC | FINAL | VOLATILE | TRANSIENT | accEnum | accSynthetic; + } + + /** + * Tests that {@link HotSpotResolvedJavaField#getModifiers()} only includes the modifiers + * returned by {@link Field#getModifiers()}. Namely, it must not include + * {@code HotSpotResolvedJavaField#FIELD_INTERNAL_FLAG}. + */ + @Test + public void testModifiersForInternal() { + for (Class c : classesWithInternalFields) { + HotSpotResolvedObjectType type = HotSpotResolvedObjectType.fromObjectClass(c); + for (ResolvedJavaField field : type.getInstanceFields(false)) { + if (field.isInternal()) { + Assert.assertEquals(0, ~jvmFieldModifiers() & field.getModifiers()); + } + } + } + } + + /** + * Tests that {@code HotSpotResolvedObjectType#createField(String, JavaType, long, int)} always + * returns the same object for an internal field. + * + * @throws InvocationTargetException + * @throws IllegalArgumentException + * @throws IllegalAccessException + */ + @Test + public void testCachingForInternalFields() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Assert.assertTrue("HotSpotResolvedObjectTypeImpl.createField method not found", createFieldMethod != null); + for (Class c : classesWithInternalFields) { + HotSpotResolvedObjectType type = HotSpotResolvedObjectType.fromObjectClass(c); + for (ResolvedJavaField field : type.getInstanceFields(false)) { + if (field.isInternal()) { + HotSpotResolvedJavaField expected = (HotSpotResolvedJavaField) field; + ResolvedJavaField actual = (ResolvedJavaField) createFieldMethod.invoke(type, expected.getName(), expected.getType(), expected.offset(), expected.getModifiers()); + Assert.assertEquals(expected, actual); + } + } + } + } + + @Test + public void testIsInObject() { + for (Field f : String.class.getDeclaredFields()) { + HotSpotResolvedJavaField rf = (HotSpotResolvedJavaField) getMetaAccess().lookupJavaField(f); + Assert.assertEquals(rf.toString(), rf.isInObject("a string"), !rf.isStatic()); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotResolvedObjectTypeTest.java 2016-12-07 13:49:57.423674036 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, 2015, 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.test; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; + +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.PrimitiveConstant; + +/** + * Tests {@link HotSpotResolvedJavaMethod} functionality. + */ +public class HotSpotResolvedObjectTypeTest extends HotSpotGraalCompilerTest { + + @Test + public void testGetSourceFileName() throws Throwable { + Assert.assertEquals("Object.java", HotSpotResolvedObjectType.fromObjectClass(Object.class).getSourceFileName()); + Assert.assertEquals("HotSpotResolvedObjectTypeTest.java", HotSpotResolvedObjectType.fromObjectClass(this.getClass()).getSourceFileName()); + } + + @Test + public void testKlassLayoutHelper() { + Constant klass = HotSpotResolvedObjectType.fromObjectClass(this.getClass()).klass(); + MemoryAccessProvider memoryAccess = getProviders().getConstantReflection().getMemoryAccessProvider(); + GraalHotSpotVMConfig config = runtime().getVMConfig(); + Constant c = StampFactory.forKind(JavaKind.Int).readConstant(memoryAccess, klass, config.klassLayoutHelperOffset); + assertTrue(c.toString(), c.getClass() == PrimitiveConstant.class); + PrimitiveConstant pc = (PrimitiveConstant) c; + assertTrue(pc.toString(), pc.getJavaKind() == JavaKind.Int); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/InstalledCodeExecuteHelperTest.java 2016-12-07 13:49:57.687685641 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, 2015, 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.test; + +import static java.lang.reflect.Modifier.isStatic; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.hotspot.HotSpotInstalledCode; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class InstalledCodeExecuteHelperTest extends GraalCompilerTest { + + private static final int ITERATIONS = 100000; + Object[] argsToBind; + + @Test + public void test1() throws InvalidInstalledCodeException { + final ResolvedJavaMethod fooMethod = getResolvedJavaMethod("foo"); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooMethod); + + argsToBind = new Object[]{fooCode}; + + final ResolvedJavaMethod benchmarkMethod = getResolvedJavaMethod("benchmark"); + final HotSpotInstalledCode installedBenchmarkCode = (HotSpotInstalledCode) getCode(benchmarkMethod); + + Assert.assertEquals(Integer.valueOf(42), benchmark(fooCode)); + + Assert.assertEquals(Integer.valueOf(42), installedBenchmarkCode.executeVarargs(argsToBind[0])); + + } + + public static Integer benchmark(HotSpotInstalledCode code) throws InvalidInstalledCodeException { + int val = 0; + for (int j = 0; j < 100; j++) { + for (int i = 0; i < ITERATIONS; i++) { + val = (Integer) code.executeVarargs(); + } + } + return val; + } + + public static Integer foo() { + return 42; + } + + @Override + protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) { + StructuredGraph graph = super.parseEager(m, allowAssumptions, compilationId); + if (argsToBind != null) { + Object receiver = isStatic(m.getModifiers()) ? null : this; + Object[] args = argsWithReceiver(receiver, argsToBind); + JavaType[] parameterTypes = m.toParameterTypes(); + assert parameterTypes.length == args.length; + for (int i = 0; i < argsToBind.length; i++) { + ParameterNode param = graph.getParameter(i); + JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[i].getJavaKind(), argsToBind[i]); + ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph); + param.replaceAtUsages(replacement); + } + } + return graph; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java 2016-12-07 13:49:57.951697245 -0800 @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2015, 2016, 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.test; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; + +import java.util.function.Consumer; + +import org.junit.Test; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugConfigScope; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder; +import org.graalvm.compiler.lir.FullInfopointOp; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.VirtualObject; +import jdk.vm.ci.code.site.InfopointReason; +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.hotspot.HotSpotCompiledCode; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaValue; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Value; + +public class JVMCIInfopointErrorTest extends GraalCompilerTest { + + private static class ValueDef extends LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(ValueDef.class); + + @Def({REG, STACK}) AllocatableValue value; + + ValueDef(AllocatableValue value) { + super(TYPE); + this.value = value; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + } + } + + private static class ValueUse extends LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(ValueUse.class); + + @Use({REG, STACK}) AllocatableValue value; + + ValueUse(AllocatableValue value) { + super(TYPE); + this.value = value; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + private static class TestNode extends DeoptimizingFixedWithNextNode implements LIRLowerable { + private static final NodeClass TYPE = NodeClass.create(TestNode.class); + + private final TestSpec spec; + + protected TestNode(TestSpec spec) { + super(TYPE, StampFactory.forVoid()); + this.spec = spec; + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + LIRGeneratorTool tool = gen.getLIRGeneratorTool(); + LIRFrameState state = gen.state(this); + spec.spec(tool, state, st -> { + tool.append(new FullInfopointOp(st, InfopointReason.SAFEPOINT)); + }); + } + } + + @FunctionalInterface + private interface TestSpec { + void spec(LIRGeneratorTool tool, LIRFrameState state, Consumer safepoint); + } + + public static void testMethod() { + } + + private void test(TestSpec spec) { + ResolvedJavaMethod method = getResolvedJavaMethod("testMethod"); + + StructuredGraph graph = parseForCompile(method); + TestNode test = graph.add(new TestNode(spec)); + graph.addAfterFixed(graph.start(), test); + + CompilationResult compResult = compile(method, graph); + HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(method, null, compResult); + getCodeCache().addCode(method, compiledCode, null, null); + } + + @Test(expected = JVMCIError.class) + public void testInvalidShortOop() { + test((tool, state, safepoint) -> { + PlatformKind kind = tool.target().arch.getPlatformKind(JavaKind.Short); + LIRKind lirKind = LIRKind.reference(kind); + + Variable var = tool.newVariable(lirKind); + tool.append(new ValueDef(var)); + safepoint.accept(state); + tool.append(new ValueUse(var)); + }); + } + + @Test(expected = JVMCIError.class) + public void testInvalidShortDerivedOop() { + test((tool, state, safepoint) -> { + Variable baseOop = tool.newVariable(LIRKind.fromJavaKind(tool.target().arch, JavaKind.Object)); + tool.append(new ValueDef(baseOop)); + + PlatformKind kind = tool.target().arch.getPlatformKind(JavaKind.Short); + LIRKind lirKind = LIRKind.derivedReference(kind, baseOop); + + Variable var = tool.newVariable(lirKind); + tool.append(new ValueDef(var)); + safepoint.accept(state); + tool.append(new ValueUse(var)); + }); + } + + private static LIRFrameState modifyTopFrame(LIRFrameState state, JavaValue[] values, JavaKind[] slotKinds, int locals, int stack, int locks) { + return modifyTopFrame(state, null, values, slotKinds, locals, stack, locks); + } + + private static LIRFrameState modifyTopFrame(LIRFrameState state, VirtualObject[] vobj, JavaValue[] values, JavaKind[] slotKinds, int locals, int stack, int locks) { + BytecodeFrame top = state.topFrame; + top = new BytecodeFrame(top.caller(), top.getMethod(), top.getBCI(), top.rethrowException, top.duringCall, values, slotKinds, locals, stack, locks); + return new LIRFrameState(top, vobj, state.exceptionEdge); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedScopeValuesLength() { + test((tool, state, safepoint) -> { + LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.FALSE}, new JavaKind[0], 0, 0, 0); + safepoint.accept(newState); + }); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedScopeSlotKindsLength() { + test((tool, state, safepoint) -> { + LIRFrameState newState = modifyTopFrame(state, new JavaValue[0], new JavaKind[]{JavaKind.Boolean}, 0, 0, 0); + safepoint.accept(newState); + }); + } + + @Test(expected = JVMCIError.class) + public void testWrongMonitorType() { + test((tool, state, safepoint) -> { + LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.INT_0}, new JavaKind[]{}, 0, 0, 1); + safepoint.accept(newState); + }); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedIllegalValue() { + test((tool, state, safepoint) -> { + LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{Value.ILLEGAL}, new JavaKind[]{JavaKind.Int}, 1, 0, 0); + safepoint.accept(newState); + }); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedTypeInRegister() { + test((tool, state, safepoint) -> { + Variable var = tool.newVariable(LIRKind.fromJavaKind(tool.target().arch, JavaKind.Int)); + tool.append(new ValueDef(var)); + LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{var}, new JavaKind[]{JavaKind.Illegal}, 1, 0, 0); + safepoint.accept(newState); + }); + } + + @Test(expected = JVMCIError.class) + public void testWrongConstantType() { + test((tool, state, safepoint) -> { + LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.INT_0}, new JavaKind[]{JavaKind.Object}, 1, 0, 0); + safepoint.accept(newState); + }); + } + + @Test(expected = JVMCIError.class) + public void testUnsupportedConstantType() { + test((tool, state, safepoint) -> { + LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.forShort((short) 0)}, new JavaKind[]{JavaKind.Short}, 1, 0, 0); + safepoint.accept(newState); + }); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedNull() { + test((tool, state, safepoint) -> { + LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.NULL_POINTER}, new JavaKind[]{JavaKind.Int}, 1, 0, 0); + safepoint.accept(newState); + }); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedObject() { + JavaValue wrapped = getSnippetReflection().forObject(this); + test((tool, state, safepoint) -> { + LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{wrapped}, new JavaKind[]{JavaKind.Int}, 1, 0, 0); + safepoint.accept(newState); + }); + } + + private static class UnknownJavaValue implements JavaValue { + } + + @SuppressWarnings("try") + @Test(expected = Error.class) + public void testUnknownJavaValue() { + try (DebugConfigScope s = Debug.setConfig(Debug.silentConfig())) { + /* + * Expected: either AssertionError or GraalError, depending on whether the unit test run + * is with assertions enabled or disabled. + */ + test((tool, state, safepoint) -> { + LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{new UnknownJavaValue()}, new JavaKind[]{JavaKind.Int}, 1, 0, 0); + safepoint.accept(newState); + }); + } + } + + @Test(expected = Error.class) + public void testMissingIllegalAfterDouble() { + /* + * Expected: either AssertionError or GraalError, depending on whether the unit test run is + * with assertions enabled or disabled. + */ + test((tool, state, safepoint) -> { + LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.DOUBLE_0, JavaConstant.INT_0}, new JavaKind[]{JavaKind.Double, JavaKind.Int}, 2, 0, 0); + safepoint.accept(newState); + }); + } + + @Test(expected = JVMCIError.class) + public void testInvalidVirtualObjectId() { + ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class); + test((tool, state, safepoint) -> { + VirtualObject o = VirtualObject.get(obj, 5); + o.setValues(new JavaValue[0], new JavaKind[0]); + + safepoint.accept(new LIRFrameState(state.topFrame, new VirtualObject[]{o}, state.exceptionEdge)); + }); + } + + @Test(expected = JVMCIError.class) + public void testDuplicateVirtualObject() { + ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class); + test((tool, state, safepoint) -> { + VirtualObject o1 = VirtualObject.get(obj, 0); + o1.setValues(new JavaValue[0], new JavaKind[0]); + + VirtualObject o2 = VirtualObject.get(obj, 0); + o2.setValues(new JavaValue[0], new JavaKind[0]); + + safepoint.accept(new LIRFrameState(state.topFrame, new VirtualObject[]{o1, o2}, state.exceptionEdge)); + }); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedVirtualObject() { + ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class); + test((tool, state, safepoint) -> { + VirtualObject o = VirtualObject.get(obj, 0); + o.setValues(new JavaValue[0], new JavaKind[0]); + + LIRFrameState newState = modifyTopFrame(state, new VirtualObject[]{o}, new JavaValue[]{o}, new JavaKind[]{JavaKind.Int}, 1, 0, 0); + safepoint.accept(newState); + }); + } + + @Test(expected = JVMCIError.class) + public void testUndefinedVirtualObject() { + ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class); + test((tool, state, safepoint) -> { + VirtualObject o0 = VirtualObject.get(obj, 0); + o0.setValues(new JavaValue[0], new JavaKind[0]); + + VirtualObject o1 = VirtualObject.get(obj, 1); + o1.setValues(new JavaValue[0], new JavaKind[0]); + + LIRFrameState newState = modifyTopFrame(state, new VirtualObject[]{o0}, new JavaValue[]{o1}, new JavaKind[]{JavaKind.Object}, 1, 0, 0); + safepoint.accept(newState); + }); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java 2016-12-07 13:49:58.216708893 -0800 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015, 2015, 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.test; + +import java.util.Objects; + +import org.junit.Test; + +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.phases.tiers.Suites; + +import jdk.vm.ci.meta.JavaKind; + +public class LoadJavaMirrorWithKlassTest extends GraalCompilerTest { + + private static class Wrapper { + private Class clazz; + + @Override + public boolean equals(Object obj) { + if (obj instanceof Wrapper) { + return Objects.equals(this.clazz, ((Wrapper) obj).clazz); + } else { + return false; + } + } + + @Override + public int hashCode() { + return clazz.hashCode(); + } + } + + @Override + @SuppressWarnings("try") + protected Suites createSuites() { + try (OverrideScope s = OptionValue.override(GraalOptions.ImmutableCode, true)) { + return super.createSuites(); + } + } + + @Override + protected boolean checkLowTierGraph(StructuredGraph graph) { + for (ConstantNode constantNode : graph.getNodes().filter(ConstantNode.class)) { + assert constantNode.asJavaConstant() == null || constantNode.asJavaConstant().getJavaKind() != JavaKind.Object || + constantNode.asJavaConstant().isDefaultForKind() : "Found unexpected object constant " + + constantNode + ", this should have been removed by the LoadJavaMirrorWithKlassPhase."; + } + return true; + } + + public static Class classConstant() { + return Wrapper.class; + } + + @Test + public void testClassConstant() { + test("classConstant"); + } + + public static Class primitiveClassConstant() { + return int.class; + } + + @Test + public void testPrimitiveClassConstant() { + test("primitiveClassConstant"); + } + + public static Wrapper compressedClassConstant(Wrapper w) { + w.clazz = Wrapper.class; + return w; + } + + @Test + public void testCompressedClassConstant() { + ArgSupplier arg = () -> new Wrapper(); + test("compressedClassConstant", arg); + } + + public static Wrapper compressedPrimitiveClassConstant(Wrapper w) { + w.clazz = int.class; + return w; + } + + @Test + public void testCompressedPrimitiveClassConstant() { + ArgSupplier arg = () -> new Wrapper(); + test("compressedPrimitiveClassConstant", arg); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MemoryUsageBenchmark.java 2016-12-07 13:49:58.482720586 -0800 @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2011, 2015, 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.test; + +import static org.graalvm.compiler.debug.internal.MemUseTrackerImpl.getCurrentThreadAllocatedBytes; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.core.test.AllocSpy; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugEnvironment; +import org.graalvm.compiler.debug.internal.DebugScope; +import org.graalvm.compiler.hotspot.CompilationTask; +import org.graalvm.compiler.hotspot.CompileTheWorld; +import org.graalvm.compiler.hotspot.CompileTheWorldOptions; +import org.graalvm.compiler.hotspot.HotSpotGraalCompiler; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +import jdk.vm.ci.hotspot.HotSpotCompilationRequest; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.runtime.JVMCICompiler; + +/** + * Used to benchmark memory usage during Graal compilation. + * + * To benchmark: + * + *
    + *     mx vm -XX:-UseJVMCIClassLoader -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark
    + * 
    + * + * Memory analysis for a {@link CompileTheWorld} execution can also be performed. For example: + * + *
    + *     mx --vm server vm -XX:-UseJVMCIClassLoader -Dgraal.CompileTheWorldClasspath=$HOME/SPECjvm2008/SPECjvm2008.jar -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark
    + * 
    + */ +public class MemoryUsageBenchmark extends HotSpotGraalCompilerTest { + + public static int simple(int a, int b) { + return a + b; + } + + public static synchronized int complex(CharSequence cs) { + if (cs instanceof String) { + return cs.hashCode(); + } + + if (cs instanceof StringBuilder) { + int[] hash = {0}; + cs.chars().forEach(c -> hash[0] += c); + return hash[0]; + } + + int res = 0; + + // Exercise lock elimination + synchronized (cs) { + res = cs.length(); + } + synchronized (cs) { + res = cs.hashCode() ^ 31; + } + + for (int i = 0; i < cs.length(); i++) { + res *= cs.charAt(i); + } + + // A fixed length loop with some canonicalizable arithmetics will + // activate loop unrolling and more canonicalization + int sum = 0; + for (int i = 0; i < 5; i++) { + sum += i * 2; + } + res += sum; + + // Activates escape-analysis + res += new String("asdf").length(); + + return res; + } + + static class MemoryUsageCloseable implements AutoCloseable { + + private final long start; + private final String name; + + MemoryUsageCloseable(String name) { + this.name = name; + this.start = getCurrentThreadAllocatedBytes(); + } + + @Override + public void close() { + long end = getCurrentThreadAllocatedBytes(); + long allocated = end - start; + System.out.println(name + ": " + allocated); + } + } + + public static void main(String[] args) { + // Ensure a Graal runtime is initialized prior to Debug being initialized as the former + // may include processing command line options used by the latter. + Graal.getRuntime(); + + // Ensure a debug configuration for this thread is initialized + if (Debug.isEnabled() && DebugScope.getConfig() == null) { + DebugEnvironment.initialize(System.out); + } + new MemoryUsageBenchmark().run(); + } + + @SuppressWarnings("try") + private void doCompilation(String methodName, String label) { + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(methodName); + + // invalidate any existing compiled code + method.reprofile(); + + long jvmciEnv = 0L; + + try (MemoryUsageCloseable c = label == null ? null : new MemoryUsageCloseable(label)) { + HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime(); + int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI; + HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, jvmciEnv); + CompilationTask task = new CompilationTask(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), request, true, false); + task.runCompilation(); + } + } + + @SuppressWarnings("try") + private void allocSpyCompilation(String methodName) { + if (AllocSpy.isEnabled()) { + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(methodName); + + // invalidate any existing compiled code + method.reprofile(); + + long jvmciEnv = 0L; + try (AllocSpy as = AllocSpy.open(methodName)) { + HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime(); + HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, JVMCICompiler.INVOCATION_ENTRY_BCI, jvmciEnv); + CompilationTask task = new CompilationTask(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), request, true, false); + task.runCompilation(); + } + } + } + + private static final boolean verbose = Boolean.getBoolean("verbose"); + + private void compileAndTime(String methodName) { + + // Parse in eager mode to resolve methods/fields/classes + parseEager(methodName, AllowAssumptions.YES); + + // Warm up and initialize compiler phases used by this compilation + for (int i = 0; i < 10; i++) { + doCompilation(methodName, verbose ? methodName + "[warmup-" + i + "]" : null); + } + + doCompilation(methodName, methodName); + } + + public void run() { + compileAndTime("simple"); + compileAndTime("complex"); + if (CompileTheWorldOptions.CompileTheWorldClasspath.getValue() != CompileTheWorld.SUN_BOOT_CLASS_PATH) { + HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime(); + CompileTheWorld ctw = new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler()); + try { + ctw.compile(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + allocSpyCompilation("simple"); + allocSpyCompilation("complex"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java 2016-12-07 13:49:58.747732234 -0800 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2014, 2016, 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.test; + +import java.util.List; +import java.util.Set; + +import org.junit.Test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.hotspot.HotSpotGraalCompiler; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.hotspot.HotSpotVMConfigStore; +import jdk.vm.ci.hotspot.VMIntrinsicMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.runtime.JVMCI; + +/** + * Exercise the compilation of intrinsic method substitutions. + */ +public class TestIntrinsicCompiles extends GraalCompilerTest { + + private static boolean match(ResolvedJavaMethod method, VMIntrinsicMethod intrinsic) { + if (intrinsic.name.equals(method.getName())) { + if (intrinsic.descriptor.equals(method.getSignature().toMethodDescriptor())) { + String declaringClass = method.getDeclaringClass().toClassName().replace('.', '/'); + if (declaringClass.equals(intrinsic.declaringClass)) { + return true; + } + } + } + return false; + } + + private static ResolvedJavaMethod findMethod(Set methods, VMIntrinsicMethod intrinsic) { + for (ResolvedJavaMethod method : methods) { + if (match(method, intrinsic)) { + return method; + } + } + return null; + } + + @Test + @SuppressWarnings("try") + public void test() { + HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) JVMCI.getRuntime().getCompiler(); + HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class); + HotSpotProviders providers = rt.getHostBackend().getProviders(); + Plugins graphBuilderPlugins = providers.getGraphBuilderPlugins(); + InvocationPlugins invocationPlugins = graphBuilderPlugins.getInvocationPlugins(); + + Set pluginMethods = invocationPlugins.getMethods(); + HotSpotVMConfigStore store = rt.getVMConfig().getStore(); + List intrinsics = store.getIntrinsics(); + for (VMIntrinsicMethod intrinsic : intrinsics) { + ResolvedJavaMethod method = findMethod(pluginMethods, intrinsic); + if (method != null) { + InvocationPlugin plugin = invocationPlugins.lookupInvocation(method); + if (plugin instanceof MethodSubstitutionPlugin && !method.isNative()) { + StructuredGraph graph = compiler.getIntrinsicGraph(method, providers, CompilationIdentifier.INVALID_COMPILATION_ID); + getCode(method, graph); + } + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestSHASubstitutions.java 2016-12-07 13:49:59.014743971 -0800 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2016, 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.test; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; + +import org.junit.Test; +import org.junit.internal.AssumptionViolatedException; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions; +import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions; +import org.graalvm.compiler.hotspot.replacements.SHASubstitutions; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Exercise the execution of the SHA digest substitutions. + */ +public class TestSHASubstitutions extends HotSpotGraalCompilerTest { + + public byte[] testDigest(String name, byte[] data) throws NoSuchAlgorithmException { + MessageDigest digest; + try { + digest = MessageDigest.getInstance(name, "SUN"); + digest.update(data); + return digest.digest(); + } catch (NoSuchProviderException e) { + return null; + } + } + + byte[] getData() { + byte[] data = new byte[1024 * 16]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) i; + } + return data; + } + + GraalHotSpotVMConfig getConfig() { + HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class); + return rt.getVMConfig(); + } + + @Test + public void testSha1() { + if (getConfig().useSHA1Intrinsics()) { + testWithInstalledIntrinsic("sun.security.provider.SHA", SHASubstitutions.implCompressName, "testDigest", "SHA-1", getData()); + } + } + + void testWithInstalledIntrinsic(String className, String methodName, String testSnippetName, Object... args) { + Class c; + try { + c = Class.forName(className); + } catch (ClassNotFoundException e) { + // It's ok to not find the class - a different security provider + // may have been installed + return; + } + InstalledCode code = null; + try { + ResolvedJavaMethod method = getResolvedJavaMethod(testSnippetName); + Object receiver = method.isStatic() ? null : this; + Result expect = executeExpected(method, receiver, args); + code = compileAndInstallSubstitution(c, methodName); + assertTrue("Failed to install " + methodName, code != null); + testAgainstExpected(method, expect, receiver, args); + } catch (AssumptionViolatedException e) { + // Suppress so that subsequent calls to this method within the + // same Junit @Test annotated method can proceed. + } + if (code != null) { + code.invalidate(); + } + } + + @Test + public void testSha256() { + if (getConfig().useSHA256Intrinsics()) { + testWithInstalledIntrinsic("sun.security.provider.SHA2", SHA2Substitutions.implCompressName, "testDigest", "SHA-256", getData()); + } + } + + @Test + public void testSha512() { + if (getConfig().useSHA512Intrinsics()) { + testWithInstalledIntrinsic("sun.security.provider.SHA5", SHA5Substitutions.implCompressName, "testDigest", "SHA-512", getData()); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java 2016-12-07 13:49:59.278755575 -0800 @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2013, 2015, 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.test; + +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.referentOffset; + +import java.lang.ref.WeakReference; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier; +import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier; +import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.WriteNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.GuardLoweringPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.MidTierContext; + +import jdk.vm.ci.hotspot.HotSpotInstalledCode; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import sun.misc.Unsafe; + +/** + * The following unit tests assert the presence of write barriers for both Serial and G1 GCs. + * Normally, the tests check for compile time inserted barriers. However, there are the cases of + * unsafe loads of the java.lang.ref.Reference.referent field where runtime checks have to be + * performed also. For those cases, the unit tests check the presence of the compile-time inserted + * barriers. Concerning the runtime checks, the results of variable inputs (object types and + * offsets) passed as input parameters can be checked against printed output from the G1 write + * barrier snippets. The runtime checks have been validated offline. + */ +public class WriteBarrierAdditionTest extends HotSpotGraalCompilerTest { + + private final GraalHotSpotVMConfig config = runtime().getVMConfig(); + private static final long referentOffset = referentOffset(); + + public static class Container { + + public Container a; + public Container b; + } + + /** + * Expected 2 barriers for the Serial GC and 4 for G1 (2 pre + 2 post). + */ + @Test + public void test1() throws Exception { + testHelper("test1Snippet", (config.useG1GC) ? 4 : 2); + } + + public static void test1Snippet() { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + main.a = temp1; + main.b = temp2; + } + + /** + * Expected 4 barriers for the Serial GC and 8 for G1 (4 pre + 4 post). + */ + @Test + public void test2() throws Exception { + testHelper("test2Snippet", config.useG1GC ? 8 : 4); + } + + public static void test2Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + for (int i = 0; i < 10; i++) { + if (test) { + main.a = temp1; + main.b = temp2; + } else { + main.a = temp2; + main.b = temp1; + } + } + } + + /** + * Expected 4 barriers for the Serial GC and 8 for G1 (4 pre + 4 post). + */ + @Test + public void test3() throws Exception { + testHelper("test3Snippet", config.useG1GC ? 8 : 4); + } + + public static void test3Snippet() { + Container[] main = new Container[10]; + Container temp1 = new Container(); + Container temp2 = new Container(); + for (int i = 0; i < 10; i++) { + main[i].a = main[i].b = temp1; + } + + for (int i = 0; i < 10; i++) { + main[i].a = main[i].b = temp2; + } + } + + /** + * Expected 2 barriers for the Serial GC and 5 for G1 (3 pre + 2 post) The (2 or 4) barriers are + * emitted while initializing the fields of the WeakReference instance. The extra pre barrier of + * G1 concerns the read of the referent field. + */ + @Test + public void test4() throws Exception { + testHelper("test4Snippet", config.useG1GC ? 5 : 2); + } + + public static Object test4Snippet() { + WeakReference weakRef = new WeakReference<>(new Object()); + return weakRef.get(); + } + + static WeakReference wr = new WeakReference<>(new Object()); + static Container con = new Container(); + + /** + * Expected 4 barriers for the Serial GC and 9 for G1 (1 ref + 4 pre + 4 post). In this test, we + * load the correct offset of the WeakReference object so naturally we assert the presence of + * the pre barrier. + */ + @Test + public void test5() throws Exception { + testHelper("test5Snippet", config.useG1GC ? 1 : 0); + } + + public static Object test5Snippet() throws Exception { + return UNSAFE.getObject(wr, config(null).useCompressedOops ? 12L : 16L); + } + + /** + * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely + * load the java.lang.ref.Reference.referent field so the pre barier has to be executed. + */ + @Test + public void test6() throws Exception { + test2("testUnsafeLoad", UNSAFE, wr, new Long(referentOffset), null); + } + + /** + * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely + * load a matching offset of a wrong object so the pre barier must not be executed. + */ + @Test + public void test7() throws Exception { + test2("testUnsafeLoad", UNSAFE, con, new Long(referentOffset), null); + } + + /** + * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely + * load a non-matching offset field of the java.lang.ref.Reference object so the pre barier must + * not be executed. + */ + @Test + public void test8() throws Exception { + test2("testUnsafeLoad", UNSAFE, wr, new Long(config.useCompressedOops ? 20 : 32), null); + } + + /** + * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely + * load a matching offset+disp field of the java.lang.ref.Reference object so the pre barier + * must be executed. + */ + @Test + public void test10() throws Exception { + test2("testUnsafeLoad", UNSAFE, wr, new Long(config.useCompressedOops ? 6 : 8), new Integer(config.useCompressedOops ? 6 : 8)); + } + + /** + * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely + * load a non-matching offset+disp field of the java.lang.ref.Reference object so the pre barier + * must not be executed. + */ + @Test + public void test9() throws Exception { + test2("testUnsafeLoad", UNSAFE, wr, new Long(config.useCompressedOops ? 10 : 16), new Integer(config.useCompressedOops ? 10 : 16)); + } + + static Object[] src = new Object[1]; + static Object[] dst = new Object[1]; + + static { + for (int i = 0; i < src.length; i++) { + src[i] = new Object(); + } + for (int i = 0; i < dst.length; i++) { + dst[i] = new Object(); + } + } + + public static void testArrayCopy(Object a, Object b, Object c) throws Exception { + System.arraycopy(a, 0, b, 0, (int) c); + } + + @Test + public void test11() throws Exception { + test2("testArrayCopy", src, dst, dst.length); + } + + public static Object testUnsafeLoad(Unsafe theUnsafe, Object a, Object b, Object c) throws Exception { + final int offset = (c == null ? 0 : ((Integer) c).intValue()); + final long displacement = (b == null ? 0 : ((Long) b).longValue()); + return theUnsafe.getObject(a, offset + displacement); + } + + private HotSpotInstalledCode getInstalledCode(String name, boolean withUnsafePrefix) throws Exception { + final ResolvedJavaMethod javaMethod = withUnsafePrefix ? getResolvedJavaMethod(WriteBarrierAdditionTest.class, name, Unsafe.class, Object.class, Object.class, Object.class) + : getResolvedJavaMethod(WriteBarrierAdditionTest.class, name, Object.class, Object.class, Object.class); + final HotSpotInstalledCode installedCode = (HotSpotInstalledCode) getCode(javaMethod); + return installedCode; + } + + @SuppressWarnings("try") + private void testHelper(final String snippetName, final int expectedBarriers) throws Exception, SecurityException { + ResolvedJavaMethod snippet = getResolvedJavaMethod(snippetName); + try (Scope s = Debug.scope("WriteBarrierAdditionTest", snippet)) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); + HighTierContext highContext = getDefaultHighTierContext(); + MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); + new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase()).apply(graph, highContext); + new CanonicalizerPhase().apply(graph, highContext); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext); + new GuardLoweringPhase().apply(graph, midContext); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext); + new WriteBarrierAdditionPhase(config).apply(graph); + Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After Write Barrier Addition"); + + int barriers = 0; + if (config.useG1GC) { + barriers = graph.getNodes().filter(G1ReferentFieldReadBarrier.class).count() + graph.getNodes().filter(G1PreWriteBarrier.class).count() + + graph.getNodes().filter(G1PostWriteBarrier.class).count(); + } else { + barriers = graph.getNodes().filter(SerialWriteBarrier.class).count(); + } + if (expectedBarriers != barriers) { + Assert.assertEquals(getScheduledGraphString(graph), expectedBarriers, barriers); + } + for (WriteNode write : graph.getNodes().filter(WriteNode.class)) { + if (config.useG1GC) { + if (write.getBarrierType() != BarrierType.NONE) { + Assert.assertEquals(1, write.successors().count()); + Assert.assertTrue(write.next() instanceof G1PostWriteBarrier); + Assert.assertTrue(write.predecessor() instanceof G1PreWriteBarrier); + } + } else { + if (write.getBarrierType() != BarrierType.NONE) { + Assert.assertEquals(1, write.successors().count()); + Assert.assertTrue(write.next() instanceof SerialWriteBarrier); + } + } + } + + for (ReadNode read : graph.getNodes().filter(ReadNode.class)) { + if (read.getBarrierType() != BarrierType.NONE) { + Assert.assertTrue(read.getAddress() instanceof OffsetAddressNode); + JavaConstant constDisp = ((OffsetAddressNode) read.getAddress()).getOffset().asJavaConstant(); + Assert.assertNotNull(constDisp); + Assert.assertEquals(referentOffset, constDisp.asLong()); + Assert.assertTrue(config.useG1GC); + Assert.assertEquals(BarrierType.PRECISE, read.getBarrierType()); + Assert.assertTrue(read.next() instanceof G1ReferentFieldReadBarrier); + } + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + private void test2(final String snippet, Object... args) throws Exception { + HotSpotInstalledCode code = getInstalledCode(snippet, args[0] instanceof Unsafe); + code.executeVarargs(args); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java 2016-12-07 13:49:59.543767223 -0800 @@ -0,0 +1,748 @@ +/* + * Copyright (c) 2013, 2016, 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.test; + +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugConfig; +import org.graalvm.compiler.debug.DebugConfigScope; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.debug.internal.DebugScope; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier; +import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase; +import org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase; +import org.graalvm.compiler.hotspot.replacements.arraycopy.UnsafeArrayCopyNode; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.FieldLocationIdentity; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.LoopExitNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.memory.WriteNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.GuardLoweringPhase; +import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; +import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.MidTierContext; + +import jdk.vm.ci.meta.ResolvedJavaField; + +/** + * The following tests validate the write barrier verification phase. For every tested snippet, an + * array of write barrier indices and the total write barrier number are passed as parameters. The + * indices denote the barriers that will be manually removed. The write barrier verification phase + * runs after the write barrier removal and depending on the result an assertion might be generated. + * The tests anticipate the presence or not of an assertion generated by the verification phase. + */ +public class WriteBarrierVerificationTest extends HotSpotGraalCompilerTest { + + public static int barrierIndex; + + private final GraalHotSpotVMConfig config = runtime().getVMConfig(); + + public static class Container { + + public Container a; + public Container b; + } + + private static native void safepoint(); + + public static void test1Snippet(Container main) { + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + barrierIndex = 1; + main.a = temp1; + safepoint(); + barrierIndex = 2; + main.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test1() { + test("test1Snippet", 2, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test2() { + test("test1Snippet", 2, new int[]{2}); + } + + public static void test2Snippet(Container main) { + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + barrierIndex = 1; + main.a = temp1; + barrierIndex = 2; + main.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test3() { + test("test2Snippet", 2, new int[]{1}); + } + + @Test + public void test4() { + test("test2Snippet", 2, new int[]{2}); + } + + public static void test3Snippet(Container main, boolean test) { + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + for (int i = 0; i < 10; i++) { + if (test) { + barrierIndex = 1; + main.a = temp1; + barrierIndex = 2; + main.b = temp2; + } else { + barrierIndex = 3; + main.a = temp1; + barrierIndex = 4; + main.b = temp2; + } + } + } + + @Test(expected = AssertionError.class) + public void test5() { + test("test3Snippet", 4, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test6() { + test("test3Snippet", 4, new int[]{3, 4}); + } + + @Test(expected = AssertionError.class) + public void test7() { + test("test3Snippet", 4, new int[]{1}); + } + + @Test + public void test8() { + test("test3Snippet", 4, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test9() { + test("test3Snippet", 4, new int[]{3}); + } + + @Test + public void test10() { + test("test3Snippet", 4, new int[]{4}); + } + + public static void test4Snippet(Container main, boolean test) { + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + for (int i = 0; i < 10; i++) { + if (test) { + barrierIndex = 2; + main.a = temp1; + barrierIndex = 3; + main.b = temp2; + } else { + barrierIndex = 4; + main.a = temp2; + barrierIndex = 5; + main.b = temp1; + } + } + } + + @Test(expected = AssertionError.class) + public void test11() { + test("test4Snippet", 5, new int[]{2, 3}); + } + + @Test(expected = AssertionError.class) + public void test12() { + test("test4Snippet", 5, new int[]{4, 5}); + } + + @Test(expected = AssertionError.class) + public void test13() { + test("test4Snippet", 5, new int[]{1}); + } + + public static void test5Snippet(Container main) { + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + if (main.a == main.b) { + barrierIndex = 2; + main.a = temp1; + barrierIndex = 3; + main.b = temp2; + } else { + barrierIndex = 4; + main.a = temp2; + barrierIndex = 5; + main.b = temp1; + } + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test14() { + test("test5Snippet", 5, new int[]{1}); + } + + @Test + public void test15() { + test("test5Snippet", 5, new int[]{2}); + } + + @Test + public void test16() { + test("test5Snippet", 5, new int[]{4}); + } + + @Test + public void test17() { + test("test5Snippet", 5, new int[]{3}); + } + + @Test + public void test18() { + test("test5Snippet", 5, new int[]{5}); + } + + @Test + public void test19() { + test("test5Snippet", 5, new int[]{2, 3}); + } + + @Test + public void test20() { + test("test5Snippet", 5, new int[]{4, 5}); + } + + public static void test6Snippet(Container main, boolean test) { + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + if (test) { + barrierIndex = 2; + main.a = temp1; + barrierIndex = 3; + main.b = temp1.a.a; + } else { + barrierIndex = 4; + main.a = temp2; + barrierIndex = 5; + main.b = temp2.a.a; + } + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test21() { + test("test6Snippet", 5, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test22() { + test("test6Snippet", 5, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test23() { + test("test6Snippet", 5, new int[]{3}); + } + + @Test + public void test24() { + test("test6Snippet", 5, new int[]{4}); + } + + public static void test7Snippet(Container main, boolean test) { + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + if (test) { + barrierIndex = 2; + main.a = temp1; + } + barrierIndex = 3; + main.b = temp2; + safepoint(); + } + + @Test + public void test25() { + test("test7Snippet", 3, new int[]{2}); + } + + @Test + public void test26() { + test("test7Snippet", 3, new int[]{3}); + } + + @Test + public void test27() { + test("test7Snippet", 3, new int[]{2, 3}); + } + + @Test(expected = AssertionError.class) + public void test28() { + test("test7Snippet", 3, new int[]{1}); + } + + public static void test8Snippet(Container main, boolean test) { + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main.a = temp1; + } + barrierIndex = 2; + main.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test29() { + test("test8Snippet", 2, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test30() { + test("test8Snippet", 2, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test31() { + test("test8Snippet", 2, new int[]{1, 2}); + } + + public static void test9Snippet(Container main1, Container main2, boolean test) { + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main1.a = temp1; + } else { + barrierIndex = 2; + main2.a = temp1; + } + barrierIndex = 3; + main1.b = temp2; + barrierIndex = 4; + main2.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test32() { + test("test9Snippet", 4, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test33() { + test("test9Snippet", 4, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test34() { + test("test9Snippet", 4, new int[]{3}); + } + + @Test(expected = AssertionError.class) + public void test35() { + test("test9Snippet", 4, new int[]{4}); + } + + @Test(expected = AssertionError.class) + public void test36() { + test("test9Snippet", 4, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test37() { + test("test9Snippet", 4, new int[]{3, 4}); + } + + public static void test10Snippet(Container main1, Container main2, boolean test) { + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main1.a = temp1; + barrierIndex = 2; + main2.a = temp2; + } else { + barrierIndex = 3; + main2.a = temp1; + } + barrierIndex = 4; + main1.b = temp2; + barrierIndex = 5; + main2.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test38() { + test("test10Snippet", 5, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test39() { + test("test10Snippet", 5, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test40() { + test("test10Snippet", 5, new int[]{3}); + } + + @Test(expected = AssertionError.class) + public void test41() { + test("test10Snippet", 5, new int[]{4}); + } + + @Test + public void test42() { + test("test10Snippet", 5, new int[]{5}); + } + + @Test(expected = AssertionError.class) + public void test43() { + test("test10Snippet", 5, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test44() { + test("test10Snippet", 5, new int[]{1, 2, 3}); + } + + @Test(expected = AssertionError.class) + public void test45() { + test("test10Snippet", 5, new int[]{3, 4}); + } + + public static void test11Snippet(Container main1, Container main2, Container main3, boolean test) { + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main1.a = temp1; + barrierIndex = 2; + main3.a = temp1; + if (!test) { + barrierIndex = 3; + main2.a = temp2; + } else { + barrierIndex = 4; + main1.a = temp2; + barrierIndex = 5; + main3.a = temp2; + } + } else { + barrierIndex = 6; + main1.b = temp2; + for (int i = 0; i < 10; i++) { + barrierIndex = 7; + main3.a = temp1; + } + barrierIndex = 8; + main3.b = temp2; + } + barrierIndex = 9; + main1.b = temp2; + barrierIndex = 10; + main2.b = temp2; + barrierIndex = 11; + main3.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test46() { + test("test11Snippet", 11, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test47() { + test("test11Snippet", 11, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test48() { + test("test11Snippet", 11, new int[]{3}); + } + + @Test(expected = AssertionError.class) + public void test49() { + test("test11Snippet", 11, new int[]{6}); + } + + @Test(expected = AssertionError.class) + public void test50() { + test("test11Snippet", 11, new int[]{7}); + } + + @Test(expected = AssertionError.class) + public void test51() { + test("test11Snippet", 11, new int[]{8}); + } + + @Test(expected = AssertionError.class) + public void test52() { + test("test11Snippet", 11, new int[]{9}); + } + + @Test(expected = AssertionError.class) + public void test53() { + test("test11Snippet", 11, new int[]{10}); + } + + @Test + public void test54() { + test("test11Snippet", 11, new int[]{4}); + } + + @Test + public void test55() { + test("test11Snippet", 11, new int[]{5}); + } + + @Test + public void test56() { + test("test11Snippet", 11, new int[]{11}); + } + + public static void test12Snippet(Container main, Container main1, boolean test) { + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + barrierIndex = 7; + main1.a = temp1; + for (int i = 0; i < 10; i++) { + if (test) { + barrierIndex = 1; + main.a = temp1; + barrierIndex = 2; + main.b = temp2; + } else { + barrierIndex = 3; + main.a = temp1; + barrierIndex = 4; + main.b = temp2; + } + } + barrierIndex = 5; + main.a = temp1; + barrierIndex = 6; + main.b = temp1; + barrierIndex = 8; + main1.b = temp1; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test57() { + test("test12Snippet", 8, new int[]{5}); + } + + @Test + public void test58() { + test("test12Snippet", 8, new int[]{6}); + } + + @Test(expected = AssertionError.class) + public void test59() { + test("test12Snippet", 8, new int[]{7}); + } + + @Test(expected = AssertionError.class) + public void test60() { + test("test12Snippet", 8, new int[]{8}); + } + + public static void test13Snippet(Object[] a, Object[] b) { + System.arraycopy(a, 0, b, 0, a.length); + } + + @Test + public void test61() { + GraphPredicate checkForUnsafeArrayCopy = graph -> graph.getNodes().filter(UnsafeArrayCopyNode.class).count() > 0 ? 1 : 0; + testPredicate("test13Snippet", checkForUnsafeArrayCopy, new int[]{}); + } + + private interface GraphPredicate { + int apply(StructuredGraph graph); + } + + private void test(final String snippet, final int expectedBarriers, final int... removedBarrierIndices) { + GraphPredicate noCheck = noArg -> expectedBarriers; + testPredicate(snippet, noCheck, removedBarrierIndices); + } + + @SuppressWarnings("try") + private void testPredicate(final String snippet, final GraphPredicate expectedBarriers, final int... removedBarrierIndices) { + try (Scope d = Debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet))) { + final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + HighTierContext highTierContext = getDefaultHighTierContext(); + new InliningPhase(new CanonicalizerPhase()).apply(graph, highTierContext); + + MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); + + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext); + new GuardLoweringPhase().apply(graph, midTierContext); + new LoopSafepointInsertionPhase().apply(graph); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, highTierContext); + + new WriteBarrierAdditionPhase(config).apply(graph); + + int barriers = 0; + // First, the total number of expected barriers is checked. + if (config.useG1GC) { + barriers = graph.getNodes().filter(G1PreWriteBarrier.class).count() + graph.getNodes().filter(G1PostWriteBarrier.class).count() + + graph.getNodes().filter(G1ArrayRangePreWriteBarrier.class).count() + graph.getNodes().filter(G1ArrayRangePostWriteBarrier.class).count(); + Assert.assertTrue(expectedBarriers.apply(graph) * 2 == barriers); + } else { + barriers = graph.getNodes().filter(SerialWriteBarrier.class).count() + graph.getNodes().filter(SerialArrayRangeWriteBarrier.class).count(); + Assert.assertTrue(expectedBarriers.apply(graph) == barriers); + } + ResolvedJavaField barrierIndexField = getMetaAccess().lookupJavaField(WriteBarrierVerificationTest.class.getDeclaredField("barrierIndex")); + LocationIdentity barrierIdentity = new FieldLocationIdentity(barrierIndexField); + // Iterate over all write nodes and remove barriers according to input indices. + NodeIteratorClosure closure = new NodeIteratorClosure() { + + @Override + protected Boolean processNode(FixedNode node, Boolean currentState) { + if (node instanceof WriteNode) { + WriteNode write = (WriteNode) node; + LocationIdentity obj = write.getLocationIdentity(); + if (obj.equals(barrierIdentity)) { + /* + * A "barrierIndex" variable was found and is checked against the input + * barrier array. + */ + if (eliminateBarrier(write.value().asJavaConstant().asInt(), removedBarrierIndices)) { + return true; + } + } + } else if (node instanceof SerialWriteBarrier || node instanceof G1PostWriteBarrier) { + // Remove flagged write barriers. + if (currentState) { + graph.removeFixed(((FixedWithNextNode) node)); + return false; + } + } + return currentState; + } + + private boolean eliminateBarrier(int index, int[] map) { + for (int i = 0; i < map.length; i++) { + if (map[i] == index) { + return true; + } + } + return false; + } + + @Override + protected Map processLoop(LoopBeginNode loop, Boolean initialState) { + return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates; + } + + @Override + protected Boolean merge(AbstractMergeNode merge, List states) { + return false; + } + + @Override + protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) { + return false; + } + }; + + DebugConfig debugConfig = DebugScope.getConfig(); + DebugConfig fixedConfig = debugConfig == null ? null + : Debug.fixedConfig(0, 0, false, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.verifyHandlers(), debugConfig.output()); + try (DebugConfigScope s = Debug.setConfig(fixedConfig)) { + ReentrantNodeIterator.apply(closure, graph.start(), false); + new WriteBarrierVerificationPhase(config).apply(graph); + } catch (AssertionError error) { + /* + * Catch assertion, test for expected one and re-throw in order to validate unit + * test. + */ + Assert.assertTrue(error.getMessage().contains("Write barrier must be present")); + throw error; + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/overview.html 2016-12-07 13:49:59.809778916 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.hotspot project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/BootstrapWatchDog.java 2016-12-07 13:50:00.074790564 -0800 @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2016, 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; + +import static org.graalvm.compiler.hotspot.HotSpotGraalCompiler.fmt; +import static org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory.GRAAL_OPTION_PROPERTY_PREFIX; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +import jdk.vm.ci.code.CompilationRequest; + +/** + * A watch dog that monitors the duration and compilation rate during a + * {@linkplain HotSpotGraalRuntimeProvider#isBootstrapping() bootstrap}. If time spent bootstrapping + * exceeds a specified timeout or the compilation rate falls below a given ratio of the maximum + * observed compilation rate (i.e., compilation slows down too much), the compiler will ignore all + * subsequent compilation requests, effectively draining the bootstrap completion queue and + * expediting completion of bootstrap. Note that the compilation rate is computed over the whole + * execution, not just the most recent measurement period. This means a sudden but temporary drop in + * any given measurement period won't cause bootstrapping to terminate early. + * + * This mechanism is based on past observations that a significantly falling bootstrap compilation + * rate implies a configuration where bootstrapping will take an unreasonably long time and it's + * better to drain the bootstrap compilation queue at some point that risk triggering timeouts in + * external harnesses such as integration tests. + */ +final class BootstrapWatchDog extends Thread { + + public static class Options { + // @formatter:off + @Option(help = "Ratio of the maximum compilation rate below which the bootstrap compilation rate must not fall " + + "(0 or less disables monitoring).", type = OptionType.Debug) + public static final OptionValue BootstrapWatchDogCriticalRateRatio = new OptionValue<>(0.25D); + @Option(help = "Maximum time in minutes to spend bootstrapping (0 to disable this limit).", type = OptionType.Debug) + public static final OptionValue BootstrapTimeout = new OptionValue<>(15D); + // @formatter:on + } + + /** + * Count of completed compilations. This is updated by the compiler threads and read by the + * watch dog thread. + */ + private final AtomicInteger compilations = new AtomicInteger(); + + /** + * Set to true once the compilation rate drops too low or bootstrapping times out. + */ + private boolean hitCriticalRateOrTimeout; + + /** + * The maximum compilation rate seen during execution. + */ + private double maxRate; + + private final HotSpotGraalRuntimeProvider graalRuntime; + + /** + * Creates and returns a {@link BootstrapWatchDog} if + * {@link Options#BootstrapWatchDogCriticalRateRatio} is not set to 0 otherwise returns + * {@code null}. + */ + static BootstrapWatchDog maybeCreate(HotSpotGraalRuntimeProvider graalRuntime) { + return MAX_RATE_DECREASE <= 0.0D && TIMEOUT == 0 ? null : new BootstrapWatchDog(graalRuntime); + } + + private BootstrapWatchDog(HotSpotGraalRuntimeProvider graalRuntime) { + this.setName(getClass().getSimpleName()); + this.start(); + this.graalRuntime = graalRuntime; + } + + /** + * Set to true to debug the watch dog. + */ + private static final boolean DEBUG = Boolean.getBoolean("debug.graal.BootstrapWatchDog"); + + /** + * Seconds to delay before starting to measure the compilation rate. + */ + private static final int INITIAL_DELAY = 10; + + /** + * Seconds between each compilation rate measurement. + */ + private static final long EPOCH = 5; + + /** + * Time in seconds before stopping a bootstrap. + */ + private static final int TIMEOUT = (int) (Options.BootstrapTimeout.getValue() * 60); + + /** + * The watch dog {@link #hitCriticalCompilationRateOrTimeout() hits} a critical compilation rate + * if the current compilation rate falls below this ratio of the maximum compilation rate. + */ + private static final double MAX_RATE_DECREASE = Options.BootstrapWatchDogCriticalRateRatio.getValue(); + + @Override + public void run() { + if (DEBUG) { + TTY.printf("%nStarted %s%n", this); + } + long start = System.currentTimeMillis(); + Map requestsAtTimeout = null; + Map stacksAtTimeout = null; + try { + Thread.sleep(INITIAL_DELAY * 1000); + while (true) { + int currentCompilations = compilations.get(); + long elapsed = System.currentTimeMillis() - start; + double rate = currentCompilations / seconds(elapsed); + if (DEBUG) { + TTY.printf("%.2f: compilation rate is %.2f/sec%n", seconds(elapsed), rate); + } + if (rate > maxRate) { + maxRate = rate; + } else if (rate < (maxRate * MAX_RATE_DECREASE)) { + TTY.printf("%nAfter %.2f seconds bootstrapping, compilation rate is %.2f compilations per second " + + "which is below %.2f times the max compilation rate of %.2f%n", seconds(elapsed), rate, MAX_RATE_DECREASE, maxRate); + TTY.printf("To enable monitoring of long running individual compilations, re-run with -D%s%s=%.2f%n", + GRAAL_OPTION_PROPERTY_PREFIX, CompilationWatchDog.Options.CompilationWatchDogStartDelay.getName(), + seconds(elapsed) - 5); + hitCriticalRateOrTimeout = true; + return; + } + if (elapsed > TIMEOUT * 1000) { + if (requestsAtTimeout == null) { + requestsAtTimeout = snapshotRequests(); + stacksAtTimeout = new HashMap<>(); + for (Thread t : requestsAtTimeout.keySet()) { + stacksAtTimeout.put(t, t.getStackTrace()); + } + } else { + TTY.printf("%nHit bootstrapping timeout after %.2f seconds%n", seconds(elapsed)); + Map requestsNow = snapshotRequests(); + for (Map.Entry e : requestsAtTimeout.entrySet()) { + Thread t = e.getKey(); + CompilationRequest request1 = requestsAtTimeout.get(t).request; + CompilationRequest request2 = requestsNow.get(t).request; + if (request1 != null && request1 == request2) { + StackTraceElement[] stackTraceNow = t.getStackTrace(); + TTY.printf("Printing stack trace for current compilation of %s lasting more than %d seconds:%n%s", + fmt(request1.getMethod()), EPOCH, fmt(stackTraceNow)); + if (Arrays.equals(stacksAtTimeout.get(t), stackTraceNow)) { + TTY.printf("\t** Identical stack trace %d seconds ago, implying a hung compilation **%n", + EPOCH); + } + } else { + if (DEBUG) { + TTY.printf("%s was compiling %s%n", t, fmt(request1.getMethod())); + } + } + } + hitCriticalRateOrTimeout = true; + return; + } + } + if (!graalRuntime.isBootstrapping()) { + return; + } + + Thread.sleep(EPOCH * 1000); + } + } catch (InterruptedException e) { + e.printStackTrace(TTY.out); + } + } + + private Map snapshotRequests() { + synchronized (requests) { + return new HashMap<>(requests); + } + } + + private static double seconds(long ms) { + return (double) ms / 1000; + } + + /** + * Queries whether a critically low compilation rate or {@link #TIMEOUT} occurred. + */ + boolean hitCriticalCompilationRateOrTimeout() { + return hitCriticalRateOrTimeout; + } + + private final Map requests = new HashMap<>(); + private final ThreadLocal requestForThread = new ThreadLocal<>(); + + /** + * Opens a scope for watching the compilation of a given method. + * + * @param request a compilation request about to be processed + * @return {@code null} if the compilation watch dog is disabled otherwise this object. The + * returned value should be used in a {@code try}-with-resources statement whose scope + * is the whole compilation so that leaving the scope will cause {@link Watch#close()} + * to be called. + */ + Watch watch(CompilationRequest request) { + Watch watch = requestForThread.get(); + if (watch == null) { + watch = new Watch(); + synchronized (requests) { + requests.put(Thread.currentThread(), watch); + } + } + watch.open(request); + return watch; + } + + /** + * Object for watching the compilations requests of a single compiler thread. + */ + class Watch implements AutoCloseable { + CompilationRequest request; + + void open(CompilationRequest r) { + assert this.request == null; + this.request = r; + } + + @Override + public void close() { + compilations.incrementAndGet(); + request = null; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationCounters.java 2016-12-07 13:50:00.339802213 -0800 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, 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; + +import static org.graalvm.compiler.hotspot.HotSpotGraalCompiler.fmt; +import static org.graalvm.compiler.hotspot.HotSpotGraalCompiler.str; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.StableOptionValue; + +import jdk.vm.ci.code.CompilationRequest; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +class CompilationCounters { + + public static class Options { + // @formatter:off + @Option(help = "The number of compilations allowed for any method before " + + "the VM exits (a value of 0 means there is no limit).", type = OptionType.Debug) + public static final OptionValue CompilationCountLimit = new StableOptionValue<>(0); + // @formatter:on + } + + CompilationCounters() { + TTY.println("Warning: Compilation counters enabled, excessive recompilation of a method will cause a failure!"); + } + + private final Map counters = new HashMap<>(); + + /** + * Counts the number of compilations for the {@link ResolvedJavaMethod} of the + * {@link CompilationRequest}. If the number of compilations exceeds + * {@link Options#CompilationCountLimit} this method prints an error message and exits the VM. + * + * @param method the method about to be compiled + */ + synchronized void countCompilation(ResolvedJavaMethod method) { + Integer val = counters.get(method); + val = val != null ? val + 1 : 1; + counters.put(method, val); + if (val > Options.CompilationCountLimit.getValue()) { + TTY.printf("Error. Method %s was compiled too many times. Number of compilations: %d\n", fmt(method), + CompilationCounters.Options.CompilationCountLimit.getValue()); + TTY.println("==================================== High compilation counters ===================================="); + SortedSet> sortedCounters = new TreeSet<>(new CounterComparator()); + for (Map.Entry e : counters.entrySet()) { + sortedCounters.add(e); + } + for (Map.Entry entry : sortedCounters) { + if (entry.getValue() >= Options.CompilationCountLimit.getValue() / 2) { + TTY.out.printf("%d\t%s%n", entry.getValue(), str(entry.getKey())); + } + } + TTY.flush(); + System.exit(-1); + } + } + + static final class CounterComparator implements Comparator> { + @Override + public int compare(Entry o1, Entry o2) { + if (o1.getValue() < o2.getValue()) { + return -1; + } + if (o1.getValue() > o2.getValue()) { + return 1; + } + return str(o1.getKey()).compareTo(str(o2.getKey())); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java 2016-12-07 13:50:00.604813861 -0800 @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2012, 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; + +import static java.lang.Thread.currentThread; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.Deque; +import java.util.Locale; +import java.util.concurrent.ConcurrentLinkedDeque; + +import org.graalvm.compiler.debug.CSVUtil; +import org.graalvm.compiler.debug.Management; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionValue; +import com.sun.management.ThreadMXBean; + +import jdk.vm.ci.hotspot.HotSpotInstalledCode; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; + +@SuppressWarnings("unused") +public final class CompilationStatistics { + + public static class Options { + // @formatter:off + @Option(help = "Enables CompilationStatistics.") + public static final OptionValue UseCompilationStatistics = new OptionValue<>(false); + // @formatter:on + } + + private static final long RESOLUTION = 100000000; + private static final boolean ENABLED = Options.UseCompilationStatistics.getValue(); + + private static final CompilationStatistics DUMMY = new CompilationStatistics(null, false); + + private static ConcurrentLinkedDeque list = new ConcurrentLinkedDeque<>(); + + private static final ThreadLocal> current = new ThreadLocal>() { + + @Override + protected Deque initialValue() { + return new ArrayDeque<>(); + } + }; + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + private static @interface NotReported { + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + private static @interface TimeValue { + } + + private static long zeroTime = System.nanoTime(); + + private static long getThreadAllocatedBytes() { + ThreadMXBean thread = (ThreadMXBean) Management.getThreadMXBean(); + return thread.getThreadAllocatedBytes(currentThread().getId()); + } + + @NotReported private final long startTime; + @NotReported private long threadAllocatedBytesStart; + + private int bytecodeCount; + private int codeSize; + @TimeValue private long duration; + private long memoryUsed; + private final boolean osr; + private final String holder; + private final String name; + private final String signature; + + private CompilationStatistics(HotSpotResolvedJavaMethod method, boolean osr) { + this.osr = osr; + if (method != null) { + holder = method.getDeclaringClass().getName(); + name = method.getName(); + signature = method.getSignature().toMethodDescriptor(); + startTime = System.nanoTime(); + bytecodeCount = method.getCodeSize(); + threadAllocatedBytesStart = getThreadAllocatedBytes(); + } else { + holder = ""; + name = ""; + signature = ""; + startTime = 0; + } + } + + public void finish(HotSpotResolvedJavaMethod method, HotSpotInstalledCode code) { + if (ENABLED) { + duration = System.nanoTime() - startTime; + codeSize = (int) code.getCodeSize(); + memoryUsed = getThreadAllocatedBytes() - threadAllocatedBytesStart; + if (current.get().getLast() != this) { + throw new RuntimeException("mismatch in finish()"); + } + current.get().removeLast(); + } + } + + public static CompilationStatistics current() { + return current.get().isEmpty() ? null : current.get().getLast(); + } + + public static CompilationStatistics create(HotSpotResolvedJavaMethod method, boolean isOSR) { + if (ENABLED) { + CompilationStatistics stats = new CompilationStatistics(method, isOSR); + list.add(stats); + current.get().addLast(stats); + return stats; + } else { + return DUMMY; + } + } + + @SuppressWarnings("deprecation") + public static void clear(String dumpName) { + if (!ENABLED) { + return; + } + try { + ConcurrentLinkedDeque snapshot = list; + long snapshotZeroTime = zeroTime; + + list = new ConcurrentLinkedDeque<>(); + zeroTime = System.nanoTime(); + + Date now = new Date(); + String dateString = (now.getYear() + 1900) + "-" + (now.getMonth() + 1) + "-" + now.getDate() + "-" + now.getHours() + "" + now.getMinutes(); + + dumpCompilations(snapshot, dumpName, dateString); + + try (FileOutputStream fos = new FileOutputStream("timeline_" + dateString + "_" + dumpName + ".csv", true); PrintStream out = new PrintStream(fos)) { + + long[] timeSpent = new long[10000]; + int maxTick = 0; + for (CompilationStatistics stats : snapshot) { + long start = stats.startTime - snapshotZeroTime; + long duration = stats.duration; + if (start < 0) { + duration -= -start; + start = 0; + } + + int tick = (int) (start / RESOLUTION); + long timeLeft = RESOLUTION - (start % RESOLUTION); + + while (tick < timeSpent.length && duration > 0) { + if (tick > maxTick) { + maxTick = tick; + } + timeSpent[tick] += Math.min(timeLeft, duration); + duration -= timeLeft; + tick++; + timeLeft = RESOLUTION; + } + } + String timelineName = System.getProperty("stats.timeline.name"); + if (timelineName != null && !timelineName.isEmpty()) { + out.printf("%s%c", CSVUtil.Escape.escape(timelineName), CSVUtil.SEPARATOR); + } + for (int i = 0; i < maxTick; i++) { + out.printf("%d%c", normalize(timeSpent[i]), CSVUtil.SEPARATOR); + } + // print last column + out.printf("%d", normalize(timeSpent[maxTick])); + out.println(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static long normalize(long time) { + return time * 100 / RESOLUTION; + } + + protected static void dumpCompilations(ConcurrentLinkedDeque snapshot, String dumpName, String dateString) throws IllegalAccessException, FileNotFoundException { + String fileName = "compilations_" + dateString + "_" + dumpName + ".csv"; + char separator = '\t'; + try (PrintStream out = new PrintStream(fileName)) { + // output the list of all compilations + + Field[] declaredFields = CompilationStatistics.class.getDeclaredFields(); + ArrayList fields = new ArrayList<>(); + for (Field field : declaredFields) { + if (!Modifier.isStatic(field.getModifiers()) && !field.isAnnotationPresent(NotReported.class)) { + fields.add(field); + } + } + String format = CSVUtil.buildFormatString("%s", separator, fields.size()); + CSVUtil.Escape.println(out, separator, CSVUtil.QUOTE, CSVUtil.ESCAPE, format, fields.toArray()); + for (CompilationStatistics stats : snapshot) { + Object[] values = new Object[fields.size()]; + for (int i = 0; i < fields.size(); i++) { + Field field = fields.get(i); + if (field.isAnnotationPresent(TimeValue.class)) { + double value = field.getLong(stats) / 1000000d; + values[i] = String.format(Locale.ENGLISH, "%.3f", value); + } else { + values[i] = field.get(stats); + } + } + CSVUtil.Escape.println(out, separator, CSVUtil.QUOTE, CSVUtil.ESCAPE, format, values); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java 2016-12-07 13:50:00.869825510 -0800 @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2012, 2016, 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; + +import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnBailout; +import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException; +import static org.graalvm.compiler.core.GraalCompilerOptions.PrintAfterCompilation; +import static org.graalvm.compiler.core.GraalCompilerOptions.PrintBailout; +import static org.graalvm.compiler.core.GraalCompilerOptions.PrintCompilation; +import static org.graalvm.compiler.core.GraalCompilerOptions.PrintFilter; +import static org.graalvm.compiler.core.GraalCompilerOptions.PrintStackTraceOnException; +import static org.graalvm.compiler.core.phases.HighTier.Options.Inline; + +import java.util.List; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.debug.DebugTimer; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.Management; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.debug.TimeSource; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; + +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.hotspot.EventProvider; +import jdk.vm.ci.hotspot.HotSpotCompilationRequest; +import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult; +import jdk.vm.ci.hotspot.HotSpotCompiledCode; +import jdk.vm.ci.hotspot.HotSpotInstalledCode; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.hotspot.HotSpotNmethod; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.runtime.JVMCICompiler; +import jdk.vm.ci.services.JVMCIServiceLocator; + +//JaCoCo Exclude + +public class CompilationTask { + + private static final DebugCounter BAILOUTS = Debug.counter("Bailouts"); + + private static final EventProvider eventProvider; + + static { + List providers = JVMCIServiceLocator.getProviders(EventProvider.class); + if (providers.size() > 1) { + throw new GraalError("Multiple %s providers found: %s", EventProvider.class.getName(), providers); + } else if (providers.isEmpty()) { + eventProvider = EventProvider.createEmptyEventProvider(); + } else { + eventProvider = providers.get(0); + } + } + + private final HotSpotJVMCIRuntimeProvider jvmciRuntime; + + private final HotSpotGraalCompiler compiler; + private final HotSpotCompilationIdentifier compilationId; + + private HotSpotInstalledCode installedCode; + + /** + * Specifies whether the compilation result is installed as the + * {@linkplain HotSpotNmethod#isDefault() default} nmethod for the compiled method. + */ + private final boolean installAsDefault; + + private final boolean useProfilingInfo; + + static class Lazy { + /** + * A {@link com.sun.management.ThreadMXBean} to be able to query some information about the + * current compiler thread, e.g. total allocated bytes. + */ + static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) Management.getThreadMXBean(); + } + + public CompilationTask(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, HotSpotCompilationRequest request, boolean useProfilingInfo, boolean installAsDefault) { + this.jvmciRuntime = jvmciRuntime; + this.compiler = compiler; + this.compilationId = new HotSpotCompilationIdentifier(request); + this.useProfilingInfo = useProfilingInfo; + this.installAsDefault = installAsDefault; + } + + public HotSpotResolvedJavaMethod getMethod() { + return getRequest().getMethod(); + } + + /** + * Returns the compilation id of this task. + * + * @return compile id + */ + public int getId() { + return getRequest().getId(); + } + + public int getEntryBCI() { + return getRequest().getEntryBCI(); + } + + /** + * @return the compilation id plus a trailing '%' is the compilation is an OSR to match + * PrintCompilation style output + */ + public String getIdString() { + if (getEntryBCI() != JVMCICompiler.INVOCATION_ENTRY_BCI) { + return getId() + "%"; + } else { + return Integer.toString(getId()); + } + } + + public HotSpotInstalledCode getInstalledCode() { + return installedCode; + } + + /** + * Time spent in compilation. + */ + private static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); + + /** + * Counts the number of compiled {@linkplain CompilationResult#getBytecodeSize() bytecodes}. + */ + private static final DebugCounter CompiledBytecodes = Debug.counter("CompiledBytecodes"); + + /** + * Counts the number of compiled {@linkplain CompilationResult#getBytecodeSize() bytecodes} for + * which {@linkplain CompilationResult#getTargetCode()} code was installed. + */ + private static final DebugCounter CompiledAndInstalledBytecodes = Debug.counter("CompiledAndInstalledBytecodes"); + + /** + * Counts the number of installed {@linkplain CompilationResult#getTargetCodeSize()} bytes. + */ + private static final DebugCounter InstalledCodeSize = Debug.counter("InstalledCodeSize"); + + /** + * Time spent in code installation. + */ + public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation"); + + @SuppressWarnings("try") + public HotSpotCompilationRequestResult runCompilation() { + HotSpotGraalRuntimeProvider graalRuntime = compiler.getGraalRuntime(); + GraalHotSpotVMConfig config = graalRuntime.getVMConfig(); + final long threadId = Thread.currentThread().getId(); + int entryBCI = getEntryBCI(); + final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI; + HotSpotResolvedJavaMethod method = getMethod(); + + // register the compilation id in the method metrics + if (Debug.isMethodMeterEnabled()) { + if (getEntryBCI() != JVMCICompiler.INVOCATION_ENTRY_BCI) { + Debug.methodMetrics(method).addToMetric(getId(), "CompilationIdOSR"); + } else { + Debug.methodMetrics(method).addToMetric(getId(), "CompilationId"); + } + } + + // Log a compilation event. + EventProvider.CompilationEvent compilationEvent = eventProvider.newCompilationEvent(); + + // If there is already compiled code for this method on our level we simply return. + // JVMCI compiles are always at the highest compile level, even in non-tiered mode so we + // only need to check for that value. + if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) { + return null; + } + + CompilationResult result = null; + try (DebugCloseable a = CompilationTime.start()) { + CompilationStatistics stats = CompilationStatistics.create(method, isOSR); + final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed(); + final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed(); + if (printCompilation) { + TTY.println(getMethodDescription() + "..."); + } + + TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); + final long start; + final long allocatedBytesBefore; + if (printAfterCompilation || printCompilation) { + start = TimeSource.getTimeNS(); + allocatedBytesBefore = printAfterCompilation || printCompilation ? Lazy.threadMXBean.getThreadAllocatedBytes(threadId) : 0L; + } else { + start = 0L; + allocatedBytesBefore = 0L; + } + + try (Scope s = Debug.scope("Compiling", new DebugDumpScope(getIdString(), true))) { + // Begin the compilation event. + compilationEvent.begin(); + /* + * Disable inlining if HotSpot has it disabled unless it's been explicitly set in + * Graal. + */ + boolean disableInlining = !config.inline && !Inline.hasBeenSet(); + try (OverrideScope s1 = disableInlining ? OptionValue.override(Inline, false) : null) { + result = compiler.compile(method, entryBCI, useProfilingInfo, compilationId); + } + } catch (Throwable e) { + throw Debug.handle(e); + } finally { + // End the compilation event. + compilationEvent.end(); + + filter.remove(); + + if (printAfterCompilation || printCompilation) { + final long stop = TimeSource.getTimeNS(); + final long duration = (stop - start) / 1000000; + final int targetCodeSize = result != null ? result.getTargetCodeSize() : -1; + final int bytecodeSize = result != null ? result.getBytecodeSize() : 0; + final long allocatedBytesAfter = Lazy.threadMXBean.getThreadAllocatedBytes(threadId); + final long allocatedKBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024; + + if (printAfterCompilation) { + TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dB %5dkB", duration, bytecodeSize, targetCodeSize, allocatedKBytes)); + } else if (printCompilation) { + TTY.println(String.format("%-6d JVMCI %-70s %-45s %-50s | %4dms %5dB %5dB %5dkB", getId(), "", "", "", duration, bytecodeSize, targetCodeSize, allocatedKBytes)); + } + } + } + + if (result != null) { + try (DebugCloseable b = CodeInstallationTime.start()) { + installMethod(result); + } + } + stats.finish(method, installedCode); + if (result != null) { + return HotSpotCompilationRequestResult.success(result.getBytecodeSize() - method.getCodeSize()); + } + return null; + } catch (BailoutException bailout) { + BAILOUTS.increment(); + if (ExitVMOnBailout.getValue()) { + TTY.out.println(method.format("Bailout in %H.%n(%p)")); + bailout.printStackTrace(TTY.out); + System.exit(-1); + } else if (PrintBailout.getValue()) { + TTY.out.println(method.format("Bailout in %H.%n(%p)")); + bailout.printStackTrace(TTY.out); + } + /* + * Handling of permanent bailouts: Permanent bailouts that can happen for example due to + * unsupported unstructured control flow in the bytecodes of a method must not be + * retried. Hotspot compile broker will ensure that no recompilation at the given tier + * will happen if retry is false. + */ + final boolean permanentBailout = bailout.isPermanent(); + if (permanentBailout && PrintBailout.getValue()) { + TTY.println("Permanent bailout %s compiling method %s %s.", bailout.getMessage(), HotSpotGraalCompiler.str(method), (isOSR ? "OSR" : "")); + } + return HotSpotCompilationRequestResult.failure(bailout.getMessage(), !permanentBailout); + } catch (Throwable t) { + // Log a failure event. + EventProvider.CompilerFailureEvent event = eventProvider.newCompilerFailureEvent(); + if (event.shouldWrite()) { + event.setCompileId(getId()); + event.setMessage(t.getMessage()); + event.commit(); + } + + handleException(t); + /* + * Treat random exceptions from the compiler as indicating a problem compiling this + * method. Report the result of toString instead of getMessage to ensure that the + * exception type is included in the output in case there's no detail mesage. + */ + return HotSpotCompilationRequestResult.failure(t.toString(), false); + } finally { + try { + int compiledBytecodes = 0; + int codeSize = 0; + if (result != null) { + compiledBytecodes = result.getBytecodeSize(); + CompiledBytecodes.add(compiledBytecodes); + if (installedCode != null) { + codeSize = installedCode.getSize(); + CompiledAndInstalledBytecodes.add(compiledBytecodes); + InstalledCodeSize.add(codeSize); + } + } + + // Log a compilation event. + if (compilationEvent.shouldWrite()) { + compilationEvent.setMethod(method.format("%H.%n(%p)")); + compilationEvent.setCompileId(getId()); + compilationEvent.setCompileLevel(config.compilationLevelFullOptimization); + compilationEvent.setSucceeded(result != null && installedCode != null); + compilationEvent.setIsOsr(isOSR); + compilationEvent.setCodeSize(codeSize); + compilationEvent.setInlinedBytes(compiledBytecodes); + compilationEvent.commit(); + } + } catch (Throwable t) { + handleException(t); + } + } + } + + protected void handleException(Throwable t) { + /* + * Automatically enable ExitVMOnException during bootstrap or when asserts are enabled but + * respect ExitVMOnException if it's been explicitly set. + */ + boolean exitVMOnException = ExitVMOnException.getValue(); + if (!ExitVMOnException.hasBeenSet()) { + assert (exitVMOnException = true) == true; + if (!exitVMOnException) { + HotSpotGraalRuntimeProvider runtime = compiler.getGraalRuntime(); + if (runtime.isBootstrapping()) { + exitVMOnException = true; + } + } + } + + if (PrintStackTraceOnException.getValue() || exitVMOnException) { + try { + t.printStackTrace(TTY.out); + } catch (Throwable throwable) { + // Don't let an exception here change the other control flow + } + } + + if (exitVMOnException) { + System.exit(-1); + } + } + + private String getMethodDescription() { + HotSpotResolvedJavaMethod method = getMethod(); + return String.format("%-6d JVMCI %-70s %-45s %-50s %s", getId(), method.getDeclaringClass().getName(), method.getName(), method.getSignature().toMethodDescriptor(), + getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + getEntryBCI() + ") "); + } + + @SuppressWarnings("try") + private void installMethod(final CompilationResult compResult) { + final CodeCacheProvider codeCache = jvmciRuntime.getHostJVMCIBackend().getCodeCache(); + installedCode = null; + Object[] context = {new DebugDumpScope(getIdString(), true), codeCache, getMethod(), compResult}; + try (Scope s = Debug.scope("CodeInstall", context)) { + HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(getRequest().getMethod(), getRequest(), compResult); + installedCode = (HotSpotInstalledCode) codeCache.installCode(getRequest().getMethod(), compiledCode, null, getRequest().getMethod().getSpeculationLog(), installAsDefault); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + @Override + public String toString() { + return "Compilation[id=" + getId() + ", " + getMethod().format("%H.%n(%p)") + (getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI ? "" : "@" + getEntryBCI()) + "]"; + } + + private HotSpotCompilationRequest getRequest() { + return compilationId.getRequest(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationWatchDog.java 2016-12-07 13:50:01.144837597 -0800 @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2016, 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; + +import static org.graalvm.compiler.hotspot.HotSpotGraalCompiler.fmt; + +import java.util.Arrays; + +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * A watch dog for reporting long running compilations. This is designed to be an always on + * mechanism for the purpose of getting better reports from customer sites. As such, it only exits + * the VM when it is very sure about a stuck compilation as opposed to only observing a long running + * compilation. In both cases, it logs messages to {@link TTY}. + * + * A watch dog thread is associated with each compiler thread. It wakes up every + * {@value #SPIN_TIMEOUT_MS} milliseconds to observe the state of the compiler thread. After the + * first {@link Options#CompilationWatchDogStartDelay} seconds of a specific compilation, the watch + * dog reports a long running compilation. Every + * {@link Options#CompilationWatchDogStackTraceInterval} seconds after that point in time where the + * same compilation is still executing, the watch dog takes a stack trace of the compiler thread. If + * more than {@value Options#NonFatalIdenticalCompilationSnapshots} contiguous identical stack + * traces are seen, the watch dog reports a stuck compilation and exits the VM. + */ +class CompilationWatchDog extends Thread implements AutoCloseable { + + public static class Options { + // @formatter:off + @Option(help = "Delay in seconds before watch dog monitoring a compilation (0 disables monitoring).", type = OptionType.Debug) + public static final OptionValue CompilationWatchDogStartDelay = new OptionValue<>(30.0D); + @Option(help = "Interval in seconds between a watch dog reporting stack traces for long running compilations.", type = OptionType.Debug) + public static final OptionValue CompilationWatchDogStackTraceInterval = new OptionValue<>(30.0D); + @Option(help = "Number of contiguous identical compiler thread stack traces allowed before the VM exits " + + "on the basis of a stuck compilation.", type = OptionType.Debug) + public static final OptionValue NonFatalIdenticalCompilationSnapshots = new OptionValue<>(10); + // @formatter:on + } + + private enum WatchDogState { + /** + * The watch dog thread sleeps currently, either no method is currently compiled, or no + * method is compiled long enough to be monitored. + */ + SLEEPING, + /** + * The watch dog thread identified a compilation that already takes long enough to be + * interesting. It will sleep and wake up periodically and check if the current compilation + * takes too long. If it takes too long it will start collecting stack traces from the + * compiler thread. + */ + WATCHING_WITHOUT_STACK_INSPECTION, + /** + * The watch dog thread is fully monitoring the compiler thread. It takes stack traces + * periodically and sleeps again until the next period. If the number of stack traces + * reaches a certain upper bound and those stack traces are equal it will shut down the + * entire VM with an error. + */ + WATCHING_WITH_STACK_INSPECTION + } + + /** + * The number of milliseconds a watch dog thread sleeps between observing the state of the + * compilation thread it is associated with. Most compilations are expected to complete within + * this time period and thus not be actively monitored by the watch dog. + */ + private static final int SPIN_TIMEOUT_MS = 1000; + private static final long START_DELAY_MS = ms(Options.CompilationWatchDogStartDelay.getValue()); + private static final long STACK_TRACE_INTERVAL_MS = ms(Options.CompilationWatchDogStackTraceInterval.getValue()); + private static final boolean ENABLED = START_DELAY_MS > 0.0D; + + private WatchDogState state = WatchDogState.SLEEPING; + private final Thread compilerThread; + private volatile ResolvedJavaMethod currentMethod; + private volatile int currentId; + private ResolvedJavaMethod lastWatched; + + // The 4 fields below are for a single compilation being watched + private long elapsed; + private int traceIntervals; + private int numberOfIdenticalStackTraces; + private StackTraceElement[] lastStackTrace; + + CompilationWatchDog(Thread compilerThread) { + this.compilerThread = compilerThread; + this.setName("WatchDog" + getId() + "[" + compilerThread.getName() + "]"); + this.setPriority(Thread.MAX_PRIORITY); + this.setDaemon(true); + } + + public void startCompilation(ResolvedJavaMethod method, int id) { + trace("start %s", fmt(method)); + this.currentMethod = method; + this.currentId = id; + } + + public void stopCompilation() { + trace(" stop %s", fmt(currentMethod)); + this.currentMethod = null; + } + + private void reset() { + elapsed = 0; + traceIntervals = 0; + numberOfIdenticalStackTraces = 0; + lastWatched = null; + lastStackTrace = null; + state = WatchDogState.SLEEPING; + } + + private void tick(WatchDogState newState) { + state = newState; + } + + /** + * Saves the current stack trace {@link StackTraceElement} of the monitored compiler thread + * {@link CompilationWatchDog#compilerThread}. + * + * @param newStackTrace the current stack trace of the monitored compiler thread + * @return {@code true} if the stack trace is equal to the last stack trace (or if it is the + * first one) and {@code false} if it is not equal to the last one. + */ + private boolean recordStackTrace(StackTraceElement[] newStackTrace) { + if (lastStackTrace == null) { + lastStackTrace = newStackTrace; + return true; + } + if (!Arrays.equals(lastStackTrace, newStackTrace)) { + lastStackTrace = newStackTrace; + return false; + } + return true; + } + + /** + * Set to true to debug the watch dog. + */ + private static final boolean DEBUG = Boolean.getBoolean("debug.graal.CompilationWatchDog"); + + private void trace(String format, Object... args) { + if (DEBUG) { + TTY.println(this + ": " + String.format(format, args)); + } + } + + private static long ms(double seconds) { + return (long) seconds * 1000; + } + + private static double secs(long ms) { + return (double) ms / 1000; + } + + @Override + public String toString() { + return getName(); + } + + @Override + public void run() { + trace("Started%n", this); + try { + while (true) { + // get a copy of the last set method + final ResolvedJavaMethod currentlyCompiling = currentMethod; + if (currentlyCompiling == null) { + // continue sleeping, compilation is either over before starting + // to watch the compiler thread or no compilation at all started + reset(); + } else { + switch (state) { + case SLEEPING: + lastWatched = currentlyCompiling; + elapsed = 0; + tick(WatchDogState.WATCHING_WITHOUT_STACK_INSPECTION); + break; + case WATCHING_WITHOUT_STACK_INSPECTION: + if (currentlyCompiling == lastWatched) { + if (elapsed >= START_DELAY_MS) { + // we looked at the same compilation for a certain time + // so now we start to collect stack traces + tick(WatchDogState.WATCHING_WITH_STACK_INSPECTION); + trace("changes mode to watching with stack traces"); + } else { + // we still compile the same method but won't collect traces yet + trace("watching without stack traces [%.2f seconds]", secs(elapsed)); + } + elapsed += SPIN_TIMEOUT_MS; + } else { + // compilation finished before we exceeded initial watching period + reset(); + } + break; + case WATCHING_WITH_STACK_INSPECTION: + if (currentlyCompiling == lastWatched) { + if (elapsed >= START_DELAY_MS + (traceIntervals * STACK_TRACE_INTERVAL_MS)) { + trace("took a stack trace"); + boolean newStackTrace = recordStackTrace(compilerThread.getStackTrace()); + if (!newStackTrace) { + trace("%d identical stack traces in a row", numberOfIdenticalStackTraces); + numberOfIdenticalStackTraces = 0; + } + numberOfIdenticalStackTraces++; + if (numberOfIdenticalStackTraces > Options.NonFatalIdenticalCompilationSnapshots.getValue()) { + synchronized (CompilationWatchDog.class) { + TTY.printf("======================= WATCH DOG THREAD =======================%n" + + "%s took %d identical stack traces, which indicates a stuck compilation (id=%d) of %s%n%sExiting VM%n", this, + numberOfIdenticalStackTraces, currentId, fmt(currentMethod), fmt(lastStackTrace)); + System.exit(-1); + } + } else if (newStackTrace) { + synchronized (CompilationWatchDog.class) { + TTY.printf("======================= WATCH DOG THREAD =======================%n" + + "%s detected long running compilation (id=%d) of %s [%.2f seconds]%n%s", this, currentId, fmt(currentMethod), + secs(elapsed), fmt(lastStackTrace)); + } + } + traceIntervals++; + } else { + // we still watch the compilation in the same trace interval + trace("watching with stack traces [%.2f seconds]", secs(elapsed)); + } + elapsed += SPIN_TIMEOUT_MS; + } else { + // compilation finished before we are able to collect stack traces + reset(); + } + break; + default: + break; + } + } + Thread.sleep(SPIN_TIMEOUT_MS); + } + } catch (Throwable t) { + synchronized (CompilationWatchDog.class) { + TTY.printf("%s encountered an exception%n%s%n", this, fmt(t)); + } + } + } + + private static final ThreadLocal WATCH_DOGS = ENABLED ? new ThreadLocal<>() : null; + + /** + * Opens a scope for watching the compilation of a given method. + * + * @param method a method about to be compiled + * @param id compilation request identifier + * @return {@code null} if the compilation watch dog is disabled otherwise this object. The + * returned value should be used in a {@code try}-with-resources statement whose scope + * is the whole compilation so that leaving the scope will cause {@link #close()} to be + * called. + */ + static CompilationWatchDog watch(ResolvedJavaMethod method, int id) { + if (ENABLED) { + // Lazily get a watch dog thread for the current compiler thread + CompilationWatchDog watchDog = WATCH_DOGS.get(); + if (watchDog == null) { + Thread currentThread = currentThread(); + watchDog = new CompilationWatchDog(currentThread); + WATCH_DOGS.set(watchDog); + watchDog.start(); + } + watchDog.startCompilation(method, id); + return watchDog; + } + return null; + } + + @Override + public void close() { + stopCompilation(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorld.java 2016-12-07 13:50:01.409849246 -0800 @@ -0,0 +1,792 @@ +/* + * Copyright (c) 2013, 2015, 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; + +import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException; +import static org.graalvm.compiler.core.GraalCompilerOptions.PrintBailout; +import static org.graalvm.compiler.core.GraalCompilerOptions.PrintStackTraceOnException; +import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier; +import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldClasspath; +import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldConfig; +import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldExcludeMethodFilter; +import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldMethodFilter; +import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldStartAt; +import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldStopAt; +import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldVerbose; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.stream.Collectors; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.bytecode.Bytecodes; +import org.graalvm.compiler.core.CompilerThreadFactory; +import org.graalvm.compiler.core.CompilerThreadFactory.DebugConfigAccess; +import org.graalvm.compiler.core.common.util.Util; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugEnvironment; +import org.graalvm.compiler.debug.GraalDebugConfig; +import org.graalvm.compiler.debug.MethodFilter; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.debug.internal.DebugScope; +import org.graalvm.compiler.debug.internal.MemUseTrackerImpl; +import org.graalvm.compiler.options.OptionDescriptor; +import org.graalvm.compiler.options.OptionDescriptors; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.options.OptionsParser; +import org.graalvm.compiler.options.OptionsParser.OptionConsumer; + +import jdk.vm.ci.hotspot.HotSpotCompilationRequest; +import jdk.vm.ci.hotspot.HotSpotInstalledCode; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ConstantPool; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.runtime.JVMCI; +import jdk.vm.ci.runtime.JVMCICompiler; +import jdk.vm.ci.services.Services; + +/** + * This class implements compile-the-world functionality with JVMCI. + */ +public final class CompileTheWorld { + + /** + * Magic token to denote that JDK classes are to be compiled. If {@link Util#Java8OrEarlier}, + * then the classes in {@code rt.jar} are compiled. Otherwise the classes in {@code + * /lib/modules} are compiled. + */ + public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path"; + + /** + * A mechanism for overriding JVMCI options that affect compilation. A {@link Config} object + * should be used in a try-with-resources statement to ensure overriding of options is scoped + * properly. For example: + * + *
    +     *     Config config = ...;
    +     *     try (AutoCloseable s = config == null ? null : config.apply()) {
    +     *         // perform a JVMCI compilation
    +     *     }
    +     * 
    + */ + @SuppressWarnings("serial") + public static class Config extends HashMap, Object> implements OptionConsumer { + /** + * Creates a {@link Config} object by parsing a set of space separated override options. + * + * @param options a space separated set of option value settings with each option setting in + * a {@code -Dgraal.=} format but without the leading + * {@code -Dgraal.}. Ignored if null. + */ + public Config(String options) { + if (options != null) { + Map optionSettings = new HashMap<>(); + for (String optionSetting : options.split("\\s+|#")) { + OptionsParser.parseOptionSettingTo(optionSetting, optionSettings); + } + OptionsParser.parseOptions(optionSettings, this, ServiceLoader.load(OptionDescriptors.class, OptionDescriptors.class.getClassLoader())); + } + } + + /** + * Applies the overrides represented by this object. The overrides are in effect until + * {@link OverrideScope#close()} is called on the returned object. + */ + OverrideScope apply() { + return OptionValue.override(this); + } + + @Override + public void set(OptionDescriptor desc, Object value) { + put(desc.getOptionValue(), value); + } + } + + private final HotSpotJVMCIRuntimeProvider jvmciRuntime; + + private final HotSpotGraalCompiler compiler; + + /** + * Class path denoting classes to compile. + * + * @see CompileTheWorldOptions#CompileTheWorldClasspath + */ + private final String inputClassPath; + + /** + * Class index to start compilation at. + * + * @see CompileTheWorldOptions#CompileTheWorldStartAt + */ + private final int startAt; + + /** + * Class index to stop compilation at. + * + * @see CompileTheWorldOptions#CompileTheWorldStopAt + */ + private final int stopAt; + + /** Only compile methods matching one of the filters in this array if the array is non-null. */ + private final MethodFilter[] methodFilters; + + /** Exclude methods matching one of the filters in this array if the array is non-null. */ + private final MethodFilter[] excludeMethodFilters; + + // Counters + private int classFileCounter = 0; + private AtomicLong compiledMethodsCounter = new AtomicLong(); + private AtomicLong compileTime = new AtomicLong(); + private AtomicLong memoryUsed = new AtomicLong(); + + private boolean verbose; + private final Config config; + + /** + * Signal that the threads should start compiling in multithreaded mode. + */ + private boolean running; + + private ThreadPoolExecutor threadPool; + + /** + * Creates a compile-the-world instance. + * + * @param files {@link File#pathSeparator} separated list of Zip/Jar files to compile + * @param startAt index of the class file to start compilation at + * @param stopAt index of the class file to stop compilation at + * @param methodFilters + * @param excludeMethodFilters + */ + public CompileTheWorld(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, String files, Config config, int startAt, int stopAt, String methodFilters, + String excludeMethodFilters, boolean verbose) { + this.jvmciRuntime = jvmciRuntime; + this.compiler = compiler; + this.inputClassPath = files; + this.startAt = startAt; + this.stopAt = stopAt; + this.methodFilters = methodFilters == null || methodFilters.isEmpty() ? null : MethodFilter.parse(methodFilters); + this.excludeMethodFilters = excludeMethodFilters == null || excludeMethodFilters.isEmpty() ? null : MethodFilter.parse(excludeMethodFilters); + this.verbose = verbose; + this.config = config; + + // We don't want the VM to exit when a method fails to compile... + config.putIfAbsent(ExitVMOnException, false); + + // ...but we want to see exceptions. + config.putIfAbsent(PrintBailout, true); + config.putIfAbsent(PrintStackTraceOnException, true); + } + + public CompileTheWorld(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler) { + this(jvmciRuntime, compiler, CompileTheWorldClasspath.getValue(), new Config(CompileTheWorldConfig.getValue()), CompileTheWorldStartAt.getValue(), CompileTheWorldStopAt.getValue(), + CompileTheWorldMethodFilter.getValue(), CompileTheWorldExcludeMethodFilter.getValue(), CompileTheWorldVerbose.getValue()); + } + + /** + * Compiles all methods in all classes in {@link #inputClassPath}. If {@link #inputClassPath} + * equals {@link #SUN_BOOT_CLASS_PATH} the boot class path is used. + */ + public void compile() throws Throwable { + // By default only report statistics for the CTW threads themselves + if (!GraalDebugConfig.Options.DebugValueThreadFilter.hasBeenSet()) { + GraalDebugConfig.Options.DebugValueThreadFilter.setValue("^CompileTheWorld"); + } + if (SUN_BOOT_CLASS_PATH.equals(inputClassPath)) { + String bcpEntry = null; + if (Java8OrEarlier) { + final String[] entries = System.getProperty(SUN_BOOT_CLASS_PATH).split(File.pathSeparator); + for (int i = 0; i < entries.length && bcpEntry == null; i++) { + String entry = entries[i]; + File entryFile = new File(entry); + // We stop at rt.jar, unless it is the first boot class path entry. + if (entryFile.getName().endsWith("rt.jar") && entryFile.isFile()) { + bcpEntry = entry; + } + } + } else { + bcpEntry = System.getProperty("java.home") + "/lib/modules".replace('/', File.separatorChar); + } + compile(bcpEntry); + } else { + compile(inputClassPath); + } + } + + public void println() { + println(""); + } + + public void println(String format, Object... args) { + println(String.format(format, args)); + } + + public void println(String s) { + println(verbose, s); + } + + public static void println(boolean cond, String s) { + if (cond) { + TTY.println(s); + } + } + + public void printStackTrace(Throwable t) { + if (verbose) { + t.printStackTrace(TTY.out); + } + } + + @SuppressWarnings("unused") + private static void dummy() { + } + + /** + * Abstraction over different types of class path entries. + */ + abstract static class ClassPathEntry implements Closeable { + final String name; + + ClassPathEntry(String name) { + this.name = name; + } + + /** + * Creates a {@link ClassLoader} for loading classes from this entry. + */ + public abstract ClassLoader createClassLoader() throws IOException; + + /** + * Gets the list of classes available under this entry. + */ + public abstract List getClassNames() throws IOException; + + @Override + public String toString() { + return name; + } + + @Override + public void close() throws IOException { + } + } + + /** + * A class path entry that is a normal file system directory. + */ + static class DirClassPathEntry extends ClassPathEntry { + + private final File dir; + + DirClassPathEntry(String name) { + super(name); + dir = new File(name); + assert dir.isDirectory(); + } + + @Override + public ClassLoader createClassLoader() throws IOException { + URL url = dir.toURI().toURL(); + return new URLClassLoader(new URL[]{url}); + } + + @Override + public List getClassNames() throws IOException { + List classNames = new ArrayList<>(); + String root = dir.getPath(); + SimpleFileVisitor visitor = new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (attrs.isRegularFile()) { + File path = file.toFile(); + if (path.getName().endsWith(".class")) { + String pathString = path.getPath(); + assert pathString.startsWith(root); + String classFile = pathString.substring(root.length() + 1); + String className = classFile.replace(File.separatorChar, '.'); + classNames.add(className.replace('/', '.').substring(0, className.length() - ".class".length())); + } + } + return super.visitFile(file, attrs); + } + }; + Files.walkFileTree(dir.toPath(), visitor); + return classNames; + } + } + + /** + * A class path entry that is a jar or zip file. + */ + static class JarClassPathEntry extends ClassPathEntry { + + private final JarFile jarFile; + + JarClassPathEntry(String name) throws IOException { + super(name); + jarFile = new JarFile(name); + } + + @Override + public ClassLoader createClassLoader() throws IOException { + URL url = new URL("jar", "", "file:" + name + "!/"); + return new URLClassLoader(new URL[]{url}); + } + + @Override + public List getClassNames() throws IOException { + Enumeration e = jarFile.entries(); + List classNames = new ArrayList<>(jarFile.size()); + while (e.hasMoreElements()) { + JarEntry je = e.nextElement(); + if (je.isDirectory() || !je.getName().endsWith(".class")) { + continue; + } + String className = je.getName().substring(0, je.getName().length() - ".class".length()); + classNames.add(className.replace('/', '.')); + } + return classNames; + } + + @Override + public void close() throws IOException { + jarFile.close(); + } + } + + /** + * Name of the property that limits the set of modules processed by CompileTheWorld. + */ + public static final String LIMITMODS_PROPERTY_NAME = "CompileTheWorld.limitmods"; + + /** + * A class path entry that is a jimage file. + */ + static class ImageClassPathEntry extends ClassPathEntry { + + private final File jimage; + + ImageClassPathEntry(String name) { + super(name); + jimage = new File(name); + assert jimage.isFile(); + } + + @Override + public ClassLoader createClassLoader() throws IOException { + URL url = jimage.toURI().toURL(); + return new URLClassLoader(new URL[]{url}); + } + + @Override + public List getClassNames() throws IOException { + String prop = System.getProperty(LIMITMODS_PROPERTY_NAME); + Set limitmods = prop == null ? null : new HashSet<>(Arrays.asList(prop.split(","))); + List classNames = new ArrayList<>(); + String[] entries = readJimageEntries(); + for (String e : entries) { + if (e.endsWith(".class") && !e.endsWith("module-info.class")) { + assert e.charAt(0) == '/' : e; + int endModule = e.indexOf('/', 1); + assert endModule != -1 : e; + if (limitmods != null) { + String module = e.substring(1, endModule); + if (!limitmods.contains(module)) { + continue; + } + } + // Strip the module prefix and convert to dotted form + String className = e.substring(endModule + 1).replace('/', '.'); + // Strip ".class" suffix + className = className.replace('/', '.').substring(0, className.length() - ".class".length()); + classNames.add(className); + } + } + return classNames; + } + + private String[] readJimageEntries() { + try { + // Use reflection so this can be compiled on JDK8 + Path path = FileSystems.getDefault().getPath(name); + Method open = Class.forName("jdk.internal.jimage.BasicImageReader").getDeclaredMethod("open", Path.class); + Object reader = open.invoke(null, path); + Method getEntryNames = reader.getClass().getDeclaredMethod("getEntryNames"); + getEntryNames.setAccessible(true); + String[] entries = (String[]) getEntryNames.invoke(reader); + return entries; + } catch (Exception e) { + TTY.println("Error reading entries from " + name + ": " + e); + return new String[0]; + } + } + } + + /** + * Determines if a given path denotes a jimage file. + * + * @param path file path + * @return {@code true} if the 4 byte integer (in native endianness) at the start of + * {@code path}'s contents is {@code 0xCAFEDADA} + */ + static boolean isJImage(String path) { + try { + FileChannel channel = FileChannel.open(Paths.get(path), StandardOpenOption.READ); + ByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); + map.order(ByteOrder.nativeOrder()).asIntBuffer().get(0); + int magic = map.asIntBuffer().get(0); + if (magic == 0xCAFEDADA) { + return true; + } + } catch (IOException e) { + } + return false; + } + + /** + * Compiles all methods in all classes in a given class path. + * + * @param classPath class path denoting classes to compile + * @throws IOException + */ + @SuppressWarnings("try") + private void compile(String classPath) throws IOException { + final String[] entries = classPath.split(File.pathSeparator); + long start = System.currentTimeMillis(); + + CompilerThreadFactory factory = new CompilerThreadFactory("CompileTheWorld", new DebugConfigAccess() { + @Override + public GraalDebugConfig getDebugConfig() { + if (Debug.isEnabled() && DebugScope.getConfig() == null) { + return DebugEnvironment.initialize(System.out, compiler.getGraalRuntime().getHostProviders().getSnippetReflection()); + } + return null; + } + }); + + try { + // compile dummy method to get compiler initialized outside of the + // config debug override. + HotSpotResolvedJavaMethod dummyMethod = (HotSpotResolvedJavaMethod) JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod( + CompileTheWorld.class.getDeclaredMethod("dummy")); + int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI; + boolean useProfilingInfo = false; + boolean installAsDefault = false; + CompilationTask task = new CompilationTask(jvmciRuntime, compiler, new HotSpotCompilationRequest(dummyMethod, entryBCI, 0L), useProfilingInfo, installAsDefault); + task.runCompilation(); + } catch (NoSuchMethodException | SecurityException e1) { + printStackTrace(e1); + } + + /* + * Always use a thread pool, even for single threaded mode since it simplifies the use of + * DebugValueThreadFilter to filter on the thread names. + */ + int threadCount = 1; + if (CompileTheWorldOptions.CompileTheWorldMultiThreaded.getValue()) { + threadCount = CompileTheWorldOptions.CompileTheWorldThreads.getValue(); + if (threadCount == 0) { + threadCount = Runtime.getRuntime().availableProcessors(); + } + } else { + running = true; + } + threadPool = new ThreadPoolExecutor(threadCount, threadCount, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), factory); + + try (OverrideScope s = config.apply()) { + for (int i = 0; i < entries.length; i++) { + final String entry = entries[i]; + + ClassPathEntry cpe; + if (entry.endsWith(".zip") || entry.endsWith(".jar")) { + cpe = new JarClassPathEntry(entry); + } else if (isJImage(entry)) { + assert !Java8OrEarlier; + cpe = new ImageClassPathEntry(entry); + } else { + if (!new File(entry).isDirectory()) { + println("CompileTheWorld : Skipped classes in " + entry); + println(); + continue; + } + cpe = new DirClassPathEntry(entry); + } + + if (methodFilters == null || methodFilters.length == 0) { + println("CompileTheWorld : Compiling all classes in " + entry); + } else { + String include = Arrays.asList(methodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", ")); + println("CompileTheWorld : Compiling all methods in " + entry + " matching one of the following filters: " + include); + } + if (excludeMethodFilters != null && excludeMethodFilters.length > 0) { + String exclude = Arrays.asList(excludeMethodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", ")); + println("CompileTheWorld : Excluding all methods matching one of the following filters: " + exclude); + } + println(); + + ClassLoader loader = cpe.createClassLoader(); + + for (String className : cpe.getClassNames()) { + + // Are we done? + if (classFileCounter >= stopAt) { + break; + } + + classFileCounter++; + + if (className.startsWith("jdk.management.") || className.startsWith("jdk.internal.cmm.*")) { + continue; + } + + try { + // Load and initialize class + Class javaClass = Class.forName(className, true, loader); + + // Pre-load all classes in the constant pool. + try { + HotSpotResolvedObjectType objectType = HotSpotResolvedObjectType.fromObjectClass(javaClass); + ConstantPool constantPool = objectType.getConstantPool(); + for (int cpi = 1; cpi < constantPool.length(); cpi++) { + constantPool.loadReferencedType(cpi, Bytecodes.LDC); + } + } catch (Throwable t) { + // If something went wrong during pre-loading we just ignore it. + println("Preloading failed for (%d) %s: %s", classFileCounter, className, t); + } + + /* + * Only check filters after class loading and resolution to mitigate impact + * on reproducibility. + */ + if (methodFilters != null && !MethodFilter.matchesClassName(methodFilters, className)) { + continue; + } + if (excludeMethodFilters != null && MethodFilter.matchesClassName(excludeMethodFilters, className)) { + continue; + } + + // Are we compiling this class? + MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + if (classFileCounter >= startAt) { + println("CompileTheWorld (%d) : %s", classFileCounter, className); + + // Compile each constructor/method in the class. + for (Constructor constructor : javaClass.getDeclaredConstructors()) { + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(constructor); + if (canBeCompiled(javaMethod, constructor.getModifiers())) { + compileMethod(javaMethod); + } + } + for (Method method : javaClass.getDeclaredMethods()) { + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(method); + if (canBeCompiled(javaMethod, method.getModifiers())) { + compileMethod(javaMethod); + } + } + + // Also compile the class initializer if it exists + HotSpotResolvedJavaMethod clinit = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaType(javaClass).getClassInitializer(); + if (clinit != null && canBeCompiled(clinit, clinit.getModifiers())) { + compileMethod(clinit); + } + } + } catch (Throwable t) { + println("CompileTheWorld (%d) : Skipping %s %s", classFileCounter, className, t.toString()); + printStackTrace(t); + } + } + cpe.close(); + } + } + + if (!running) { + startThreads(); + } + int wakeups = 0; + while (threadPool.getCompletedTaskCount() != threadPool.getTaskCount()) { + if (wakeups % 15 == 0) { + TTY.println("CompileTheWorld : Waiting for " + (threadPool.getTaskCount() - threadPool.getCompletedTaskCount()) + " compiles"); + } + try { + threadPool.awaitTermination(1, TimeUnit.SECONDS); + wakeups++; + } catch (InterruptedException e) { + } + } + threadPool = null; + + long elapsedTime = System.currentTimeMillis() - start; + + println(); + if (CompileTheWorldOptions.CompileTheWorldMultiThreaded.getValue()) { + TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms elapsed, %d ms compile time, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), elapsedTime, + compileTime.get(), memoryUsed.get()); + } else { + TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), compileTime.get(), memoryUsed.get()); + } + } + + private synchronized void startThreads() { + running = true; + // Wake up any waiting threads + notifyAll(); + } + + private synchronized void waitToRun() { + while (!running) { + try { + wait(); + } catch (InterruptedException e) { + } + } + } + + @SuppressWarnings("try") + private void compileMethod(HotSpotResolvedJavaMethod method) throws InterruptedException, ExecutionException { + if (methodFilters != null && !MethodFilter.matches(methodFilters, method)) { + return; + } + if (excludeMethodFilters != null && MethodFilter.matches(excludeMethodFilters, method)) { + return; + } + Future task = threadPool.submit(new Runnable() { + @Override + public void run() { + waitToRun(); + try (OverrideScope s = config.apply()) { + compileMethod(method, classFileCounter); + } + } + }); + if (threadPool.getCorePoolSize() == 1) { + task.get(); + } + } + + /** + * Compiles a method and gathers some statistics. + */ + private void compileMethod(HotSpotResolvedJavaMethod method, int counter) { + try { + long start = System.currentTimeMillis(); + long allocatedAtStart = MemUseTrackerImpl.getCurrentThreadAllocatedBytes(); + int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI; + HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, 0L); + // For more stable CTW execution, disable use of profiling information + boolean useProfilingInfo = false; + boolean installAsDefault = false; + CompilationTask task = new CompilationTask(jvmciRuntime, compiler, request, useProfilingInfo, installAsDefault); + task.runCompilation(); + + // Invalidate the generated code so the code cache doesn't fill up + HotSpotInstalledCode installedCode = task.getInstalledCode(); + if (installedCode != null) { + installedCode.invalidate(); + } + + memoryUsed.getAndAdd(MemUseTrackerImpl.getCurrentThreadAllocatedBytes() - allocatedAtStart); + compileTime.getAndAdd(System.currentTimeMillis() - start); + compiledMethodsCounter.incrementAndGet(); + } catch (Throwable t) { + // Catch everything and print a message + println("CompileTheWorld (%d) : Error compiling method: %s", counter, method.format("%H.%n(%p):%r")); + printStackTrace(t); + } + } + + /** + * Determines if a method should be compiled (Cf. CompilationPolicy::can_be_compiled). + * + * @return true if it can be compiled, false otherwise + */ + private boolean canBeCompiled(HotSpotResolvedJavaMethod javaMethod, int modifiers) { + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + return false; + } + GraalHotSpotVMConfig c = compiler.getGraalRuntime().getVMConfig(); + if (c.dontCompileHugeMethods && javaMethod.getCodeSize() > c.hugeMethodLimit) { + println(verbose || methodFilters != null, + String.format("CompileTheWorld (%d) : Skipping huge method %s (use -XX:-DontCompileHugeMethods or -XX:HugeMethodLimit=%d to include it)", classFileCounter, + javaMethod.format("%H.%n(%p):%r"), + javaMethod.getCodeSize())); + return false; + } + // Allow use of -XX:CompileCommand=dontinline to exclude problematic methods + if (!javaMethod.canBeInlined()) { + return false; + } + // Skip @Snippets for now + for (Annotation annotation : javaMethod.getAnnotations()) { + if (annotation.annotationType().equals(Snippet.class)) { + return false; + } + } + return true; + } + + public static void main(String[] args) throws Throwable { + Services.exportJVMCITo(CompileTheWorld.class); + HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) HotSpotJVMCIRuntime.runtime().getCompiler(); + compiler.compileTheWorld(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorldOptions.java 2016-12-07 13:50:01.680861158 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, 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; + +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +/** + * Options related to {@link CompileTheWorld}. + * + * Note: This must be a top level class to work around for + * Eclipse bug 477597. + */ +public class CompileTheWorldOptions { + // @formatter:off + @Option(help = "Class path denoting methods to compile", type = OptionType.Debug) + public static final OptionValue CompileTheWorldClasspath = new OptionValue<>(CompileTheWorld.SUN_BOOT_CLASS_PATH); + @Option(help = "Verbose CompileTheWorld operation", type = OptionType.Debug) + public static final OptionValue CompileTheWorldVerbose = new OptionValue<>(true); + @Option(help = "The number of CompileTheWorld iterations to perform", type = OptionType.Debug) + public static final OptionValue CompileTheWorldIterations = new OptionValue<>(1); + @Option(help = "Only compile methods matching this filter", type = OptionType.Debug) + public static final OptionValue CompileTheWorldMethodFilter = new OptionValue<>(null); + @Option(help = "Exclude methods matching this filter from compilation", type = OptionType.Debug) + public static final OptionValue CompileTheWorldExcludeMethodFilter = new OptionValue<>(null); + @Option(help = "First class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug) + public static final OptionValue CompileTheWorldStartAt = new OptionValue<>(1); + @Option(help = "Last class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug) + public static final OptionValue CompileTheWorldStopAt = new OptionValue<>(Integer.MAX_VALUE); + @Option(help = "Option value overrides to use during compile the world. For example, " + + "to disable inlining and partial escape analysis specify 'PartialEscapeAnalysis=false Inline=false'. " + + "The format for each option is the same as on the command line just without the '-Dgraal.' prefix.", type = OptionType.Debug) + public static final OptionValue CompileTheWorldConfig = new OptionValue<>(null); + + @Option(help = "Run CTW using as many threads as there are processors on the system", type = OptionType.Debug) + public static final OptionValue CompileTheWorldMultiThreaded = new OptionValue<>(false); + @Option(help = "Number of threads to use for multithreaded CTW. Defaults to Runtime.getRuntime().availableProcessors()", type = OptionType.Debug) + public static final OptionValue CompileTheWorldThreads = new OptionValue<>(0); + // @formatter:on + + /** + * Overrides {@link #CompileTheWorldStartAt} and {@link #CompileTheWorldStopAt} from {@code -XX} + * HotSpot options of the same name if the latter have non-default values. + */ + public static void overrideWithNativeOptions(GraalHotSpotVMConfig c) { + if (c.compileTheWorldStartAt != 1) { + CompileTheWorldStartAt.setValue(c.compileTheWorldStartAt); + } + if (c.compileTheWorldStopAt != Integer.MAX_VALUE) { + CompileTheWorldStopAt.setValue(c.compileTheWorldStopAt); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java 2016-12-07 13:50:01.945872806 -0800 @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2016, 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; + +import static jdk.vm.ci.common.InitTimer.timer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.stream.Collectors; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.serviceprovider.GraalServices; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.common.InitTimer; + +/** + * A factory that creates the {@link CompilerConfiguration} the Graal compiler will use. Each + * factory must have a unique {@link #name} and {@link #autoSelectionPriority}. The latter imposes a + * total ordering between factories for the purpose of auto-selecting the factory to use. + */ +public abstract class CompilerConfigurationFactory implements Comparable { + + static class Options { + // @formatter:off + @Option(help = "Names the Graal compiler configuration to use. If ommitted, the compiler configuration " + + "with the highest auto-selection priority is used. To see the set of available configurations, " + + "supply the value 'help' to this option.", type = OptionType.Expert) + public static final OptionValue CompilerConfiguration = new OptionValue<>(null); + // @formatter:on + } + + /** + * The name of this factory. This must be unique across all factory instances and is used when + * selecting a factory based on the value of {@link Options#CompilerConfiguration}. + */ + private final String name; + + /** + * The priority of this factory. This must be unique across all factory instances and is used + * when selecting a factory when {@link Options#CompilerConfiguration} is omitted + */ + private final int autoSelectionPriority; + + protected CompilerConfigurationFactory(String name, int autoSelectionPriority) { + this.name = name; + this.autoSelectionPriority = autoSelectionPriority; + assert checkAndAddNewFactory(this); + } + + public abstract CompilerConfiguration createCompilerConfiguration(); + + /** + * Collect the set of available {@linkplain HotSpotBackendFactory backends} for this compiler + * configuration. + */ + public BackendMap createBackendMap() { + // default to backend with the same name as the compiler configuration + return new DefaultBackendMap(name); + } + + public interface BackendMap { + HotSpotBackendFactory getBackendFactory(Architecture arch); + } + + public static class DefaultBackendMap implements BackendMap { + + private final IdentityHashMap, HotSpotBackendFactory> backends = new IdentityHashMap<>(); + + @SuppressWarnings("try") + public DefaultBackendMap(String backendName) { + try (InitTimer t = timer("HotSpotBackendFactory.register")) { + for (HotSpotBackendFactory backend : GraalServices.load(HotSpotBackendFactory.class)) { + if (backend.getName().equals(backendName)) { + Class arch = backend.getArchitecture(); + HotSpotBackendFactory oldEntry = backends.put(arch, backend); + assert oldEntry == null || oldEntry == backend : "duplicate Graal backend"; + } + } + } + } + + @Override + public final HotSpotBackendFactory getBackendFactory(Architecture arch) { + return backends.get(arch.getClass()); + } + } + + @Override + public int compareTo(CompilerConfigurationFactory o) { + if (autoSelectionPriority > o.autoSelectionPriority) { + return -1; + } + if (autoSelectionPriority < o.autoSelectionPriority) { + return 1; + } + assert this == o : "distinct compiler configurations cannot have the same auto selection priority"; + return 0; + } + + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean assertionsEnabled = false; + assert assertionsEnabled = true; + return assertionsEnabled; + } + + /** + * List used to assert uniqueness of {@link #name} and {@link #autoSelectionPriority} across all + * {@link CompilerConfigurationFactory} instances. + */ + private static final List factories = assertionsEnabled() ? new ArrayList<>() : null; + + private static boolean checkAndAddNewFactory(CompilerConfigurationFactory factory) { + for (CompilerConfigurationFactory other : factories) { + assert !other.name.equals(factory.name) : factory.getClass().getName() + " cannot have the same selector as " + other.getClass().getName() + ": " + factory.name; + assert other.autoSelectionPriority != factory.autoSelectionPriority : factory.getClass().getName() + " cannot have the same auto-selection priority as " + other.getClass().getName() + + ": " + factory.autoSelectionPriority; + } + factories.add(factory); + return true; + } + + /** + * @return sorted list of {@link CompilerConfigurationFactory}s + */ + private static List getAllCandidates() { + List candidates = new ArrayList<>(); + for (CompilerConfigurationFactory candidate : GraalServices.load(CompilerConfigurationFactory.class)) { + candidates.add(candidate); + } + Collections.sort(candidates); + return candidates; + } + + /** + * Selects and instantiates a {@link CompilerConfigurationFactory}. The selection algorithm is + * as follows: if {@code name} is non-null, then select the factory with the same name else if + * {@link Options#CompilerConfiguration}{@code .getValue()} is non-null then select the factory + * whose name matches the value else select the factory with the highest + * {@link #autoSelectionPriority} value. + * + * @param name the name of the compiler configuration to select (optional) + */ + @SuppressWarnings("try") + public static CompilerConfigurationFactory selectFactory(String name) { + CompilerConfigurationFactory factory = null; + try (InitTimer t = timer("CompilerConfigurationFactory.selectFactory")) { + String value = name == null ? Options.CompilerConfiguration.getValue() : name; + if ("help".equals(value)) { + System.out.println("The available Graal compiler configurations are:"); + for (CompilerConfigurationFactory candidate : getAllCandidates()) { + System.out.println(" " + candidate.name); + } + System.exit(0); + } else if (value != null) { + for (CompilerConfigurationFactory candidate : GraalServices.load(CompilerConfigurationFactory.class)) { + if (candidate.name.equals(value)) { + factory = candidate; + break; + } + } + if (factory == null) { + throw new GraalError("Graal compiler configuration '%s' not found. Available configurations are: %s", value, + getAllCandidates().stream().map(c -> c.name).collect(Collectors.joining(", "))); + } + } else { + List candidates = getAllCandidates(); + if (candidates.isEmpty()) { + throw new GraalError("No %s providers found", CompilerConfigurationFactory.class.getName()); + } + factory = candidates.get(0); + } + } + return factory; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java 2016-12-07 13:50:02.210884455 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, 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; + +import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; +import jdk.vm.ci.hotspot.HotSpotVMConfigStore; + +/** + * Used to access native configuration details for static compilation support. + */ +public class CompilerRuntimeHotSpotVMConfig extends HotSpotVMConfigAccess { + + public CompilerRuntimeHotSpotVMConfig(HotSpotVMConfigStore store) { + super(store); + } + + public final long resolveStringBySymbol = getAddress("CompilerRuntime::resolve_string_by_symbol"); + public final long resolveKlassBySymbol = getAddress("CompilerRuntime::resolve_klass_by_symbol"); + public final long resolveMethodBySymbolAndLoadCounters = getAddress("CompilerRuntime::resolve_method_by_symbol_and_load_counters"); + public final long initializeKlassBySymbol = getAddress("CompilerRuntime::initialize_klass_by_symbol"); + public final long invocationEvent = getAddress("CompilerRuntime::invocation_event"); + public final long backedgeEvent = getAddress("CompilerRuntime::backedge_event"); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompressEncoding.java 2016-12-07 13:50:02.475896103 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016, 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; + +/** + * A compact representation of the different encoding strategies for Objects and metadata. + */ +public class CompressEncoding { + public final long base; + public final int shift; + public final int alignment; + + CompressEncoding(long base, int shift, int alignment) { + this.base = base; + this.shift = shift; + this.alignment = alignment; + } + + public int compress(long ptr) { + if (ptr == 0L) { + return 0; + } else { + return (int) ((ptr - base) >>> shift); + } + } + + public long uncompress(int ptr) { + if (ptr == 0) { + return 0L; + } else { + return ((ptr & 0xFFFFFFFFL) << shift) + base; + } + } + + @Override + public String toString() { + return "base: " + base + " shift: " + shift + " alignment: " + alignment; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + alignment; + result = prime * result + (int) (base ^ (base >>> 32)); + result = prime * result + shift; + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CompressEncoding) { + CompressEncoding other = (CompressEncoding) obj; + return alignment == other.alignment && base == other.base && shift == other.shift; + } else { + return false; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CoreCompilerConfigurationFactory.java 2016-12-07 13:50:02.739907708 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, 2016, 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; + +import org.graalvm.compiler.core.phases.CoreCompilerConfiguration; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.serviceprovider.ServiceProvider; + +@ServiceProvider(CompilerConfigurationFactory.class) +public class CoreCompilerConfigurationFactory extends CompilerConfigurationFactory { + + public static final String NAME = "core"; + + public static final int AUTO_SELECTION_PRIORITY = 2; + + public CoreCompilerConfigurationFactory() { + super(NAME, AUTO_SELECTION_PRIORITY); + } + + @Override + public CompilerConfiguration createCompilerConfiguration() { + return new CoreCompilerConfiguration(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EconomyCompilerConfigurationFactory.java 2016-12-07 13:50:03.004919356 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 2016, 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; + +import org.graalvm.compiler.core.phases.EconomyCompilerConfiguration; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.serviceprovider.ServiceProvider; + +@ServiceProvider(CompilerConfigurationFactory.class) +public class EconomyCompilerConfigurationFactory extends CompilerConfigurationFactory { + + public static final String NAME = "economy"; + + public static final int AUTO_SELECTION_PRIORITY = 1; + + public EconomyCompilerConfigurationFactory() { + super(NAME, AUTO_SELECTION_PRIORITY); + } + + @Override + public CompilerConfiguration createCompilerConfiguration() { + return new EconomyCompilerConfiguration(); + } + + @Override + public BackendMap createBackendMap() { + // the economy configuration only differs in the frontend, it reuses the "core" backend + return new DefaultBackendMap(CoreCompilerConfigurationFactory.NAME); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/FingerprintUtil.java 2016-12-07 13:50:03.268930960 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016, 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; + +import java.lang.reflect.Method; + +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; + +/** + * Reflective wrapper around the fingerprint generation functionality in JDK9. + */ +public class FingerprintUtil { + private static Method getFingerprint; + static { + try { + getFingerprint = HotSpotResolvedObjectType.class.getMethod("getFingerprint"); + } catch (Exception e) { + } + } + + public static long getFingerprint(HotSpotResolvedObjectType type) { + if (getFingerprint != null) { + try { + return ((Long) getFingerprint.invoke(type)).longValue(); + } catch (Exception e) { + } + } + return 0; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java 2016-12-07 13:50:03.532942565 -0800 @@ -0,0 +1,793 @@ +/* + * Copyright (c) 2011, 2016, 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; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; +import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; + +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; +import jdk.vm.ci.hotspot.HotSpotVMConfigStore; + +/** + * Used to access native configuration details. + */ +public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { + + /** + * Sentinel value to use for an {@linkplain InjectedParameter injected} + * {@link GraalHotSpotVMConfig} parameter to a {@linkplain Fold foldable} method. + */ + public static final GraalHotSpotVMConfig INJECTED_VMCONFIG = null; + + private final boolean isJDK8 = System.getProperty("java.specification.version").compareTo("1.9") < 0; + public final String osName = getHostOSName(); + public final String osArch = getHostArchitectureName(); + public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows"); + public final boolean linuxOs = System.getProperty("os.name", "").startsWith("Linux"); + + GraalHotSpotVMConfig(HotSpotVMConfigStore store) { + super(store); + + oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift, logMinObjAlignment()); + klassEncoding = new CompressEncoding(narrowKlassBase, narrowKlassShift, logKlassAlignment); + + assert check(); + } + + /** + * Gets the value of a static C++ field under two possible names. {@code name} is the preferred + * name and will be checked first. + * + * @param name fully qualified name of the field + * @param alternateName fully qualified alternate name of the field + * @param type the boxed type to which the constant value will be converted + * @param cppType if non-null, the expected C++ type of the field (e.g., {@code "HeapWord*"}) + * @return the value of the requested field + * @throws JVMCIError if the field is not static or not present + */ + public T getFieldValueWithAlternate(String name, String alternateName, Class type, String cppType) { + try { + return getFieldValue(name, type, cppType); + } catch (JVMCIError e) { + try { + return getFieldValue(alternateName, type, cppType); + } catch (JVMCIError e2) { + throw new JVMCIError("expected VM field not found: " + name + " or " + alternateName); + } + } + } + + private final CompressEncoding oopEncoding; + private final CompressEncoding klassEncoding; + + public CompressEncoding getOopEncoding() { + return oopEncoding; + } + + public CompressEncoding getKlassEncoding() { + return klassEncoding; + } + + /** + * Gets the host operating system name. + */ + private static String getHostOSName() { + String osName = System.getProperty("os.name"); + switch (osName) { + case "Linux": + osName = "linux"; + break; + case "SunOS": + osName = "solaris"; + break; + case "Mac OS X": + osName = "bsd"; + break; + default: + // Of course Windows is different... + if (osName.startsWith("Windows")) { + osName = "windows"; + } else { + throw new JVMCIError("Unexpected OS name: " + osName); + } + } + return osName; + } + + private static String getHostArchitectureName() { + String arch = System.getProperty("os.arch"); + switch (arch) { + case "x86_64": + arch = "amd64"; + break; + case "sparcv9": + arch = "sparc"; + break; + } + return arch; + } + + private final Integer intRequiredOnAMD64 = osArch.equals("amd64") ? null : 0; + private final Integer intNotPresentInJDK8 = isJDK8 ? 0 : null; + private final Long longNotPresentInJDK8 = isJDK8 ? 0L : null; + + public final boolean cAssertions = getConstant("ASSERT", Boolean.class); + + public final int codeEntryAlignment = getFlag("CodeEntryAlignment", Integer.class); + public final boolean enableContended = getFlag("EnableContended", Boolean.class); + public final boolean restrictContended = getFlag("RestrictContended", Boolean.class); + public final int contendedPaddingWidth = getFlag("ContendedPaddingWidth", Integer.class); + public final int fieldsAllocationStyle = getFlag("FieldsAllocationStyle", Integer.class); + public final boolean compactFields = getFlag("CompactFields", Boolean.class); + public final boolean verifyOops = getFlag("VerifyOops", Boolean.class); + public final boolean ciTime = getFlag("CITime", Boolean.class); + public final boolean ciTimeEach = getFlag("CITimeEach", Boolean.class); + public final int compileTheWorldStartAt = getFlag("CompileTheWorldStartAt", Integer.class, 1); + public final int compileTheWorldStopAt = getFlag("CompileTheWorldStopAt", Integer.class, Integer.MAX_VALUE); + public final boolean dontCompileHugeMethods = getFlag("DontCompileHugeMethods", Boolean.class); + public final int hugeMethodLimit = getFlag("HugeMethodLimit", Integer.class); + public final boolean printInlining = getFlag("PrintInlining", Boolean.class); + public final boolean inline = getFlag("Inline", Boolean.class); + public final boolean useFastLocking = getFlag("JVMCIUseFastLocking", Boolean.class); + public final boolean forceUnreachable = getFlag("ForceUnreachable", Boolean.class); + public final int codeSegmentSize = getFlag("CodeCacheSegmentSize", Integer.class); + public final boolean foldStableValues = getFlag("FoldStableValues", Boolean.class); + + public final boolean useTLAB = getFlag("UseTLAB", Boolean.class); + public final boolean useBiasedLocking = getFlag("UseBiasedLocking", Boolean.class); + public final boolean usePopCountInstruction = getFlag("UsePopCountInstruction", Boolean.class); + public final boolean useAESIntrinsics = getFlag("UseAESIntrinsics", Boolean.class); + public final boolean useCRC32Intrinsics = getFlag("UseCRC32Intrinsics", Boolean.class); + + private final boolean useMultiplyToLenIntrinsic = getFlag("UseMultiplyToLenIntrinsic", Boolean.class); + private final boolean useSHA1Intrinsics = getFlag("UseSHA1Intrinsics", Boolean.class); + private final boolean useSHA256Intrinsics = getFlag("UseSHA256Intrinsics", Boolean.class); + private final boolean useSHA512Intrinsics = getFlag("UseSHA512Intrinsics", Boolean.class); + private final boolean useMontgomeryMultiplyIntrinsic = getFlag("UseMontgomeryMultiplyIntrinsic", Boolean.class, false); + private final boolean useMontgomerySquareIntrinsic = getFlag("UseMontgomerySquareIntrinsic", Boolean.class, false); + private final boolean useMulAddIntrinsic = getFlag("UseMulAddIntrinsic", Boolean.class, false); + private final boolean useSquareToLenIntrinsic = getFlag("UseSquareToLenIntrinsic", Boolean.class, false); + + /* + * These are methods because in some JDKs the flags are visible but the stubs themselves haven't + * been exported so we have to check both if the flag is on and if we have the stub. + */ + public boolean useMultiplyToLenIntrinsic() { + return useMultiplyToLenIntrinsic && multiplyToLen != 0; + } + + public boolean useSHA1Intrinsics() { + return useSHA1Intrinsics && sha1ImplCompress != 0; + } + + public boolean useSHA256Intrinsics() { + return useSHA256Intrinsics && sha256ImplCompress != 0; + } + + public boolean useSHA512Intrinsics() { + return useSHA512Intrinsics && sha512ImplCompress != 0; + } + + public boolean useMontgomeryMultiplyIntrinsic() { + return useMontgomeryMultiplyIntrinsic && montgomeryMultiply != 0; + } + + public boolean useMontgomerySquareIntrinsic() { + return useMontgomerySquareIntrinsic && montgomerySquare != 0; + } + + public boolean useMulAddIntrinsic() { + return useMulAddIntrinsic && mulAdd != 0; + } + + public boolean useSquareToLenIntrinsic() { + return useSquareToLenIntrinsic && squareToLen != 0; + } + + public final boolean useG1GC = getFlag("UseG1GC", Boolean.class); + public final boolean useCMSGC = getFlag("UseConcMarkSweepGC", Boolean.class); + + public final int allocatePrefetchStyle = getFlag("AllocatePrefetchStyle", Integer.class); + public final int allocatePrefetchInstr = getFlag("AllocatePrefetchInstr", Integer.class); + public final int allocatePrefetchLines = getFlag("AllocatePrefetchLines", Integer.class); + public final int allocateInstancePrefetchLines = getFlag("AllocateInstancePrefetchLines", Integer.class); + public final int allocatePrefetchStepSize = getFlag("AllocatePrefetchStepSize", Integer.class); + public final int allocatePrefetchDistance = getFlag("AllocatePrefetchDistance", Integer.class); + + private final long universeCollectedHeap = getFieldValue("CompilerToVM::Data::Universe_collectedHeap", Long.class, "CollectedHeap*"); + private final int collectedHeapTotalCollectionsOffset = getFieldOffset("CollectedHeap::_total_collections", Integer.class, "unsigned int"); + + public long gcTotalCollectionsAddress() { + return universeCollectedHeap + collectedHeapTotalCollectionsOffset; + } + + public final boolean useDeferredInitBarriers = getFlag("ReduceInitialCardMarks", Boolean.class); + + // Compressed Oops related values. + public final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); + public final boolean useCompressedClassPointers = getFlag("UseCompressedClassPointers", Boolean.class); + + public final long narrowOopBase = getFieldValue("CompilerToVM::Data::Universe_narrow_oop_base", Long.class, "address"); + public final int narrowOopShift = getFieldValue("CompilerToVM::Data::Universe_narrow_oop_shift", Integer.class, "int"); + public final int objectAlignment = getFlag("ObjectAlignmentInBytes", Integer.class); + + public final int minObjAlignment() { + return objectAlignment / heapWordSize; + } + + public final int logMinObjAlignment() { + return (int) (Math.log(objectAlignment) / Math.log(2)); + } + + public final int narrowKlassSize = getTypeSize("narrowKlass"); + public final long narrowKlassBase = getFieldValue("CompilerToVM::Data::Universe_narrow_klass_base", Long.class, "address"); + public final int narrowKlassShift = getFieldValue("CompilerToVM::Data::Universe_narrow_klass_shift", Integer.class, "int"); + public final int logKlassAlignment = getConstant("LogKlassAlignmentInBytes", Integer.class); + + public final int stackShadowPages = getFlag("StackShadowPages", Integer.class); + public final int stackReservedPages = getFlag("StackReservedPages", Integer.class, 0); + public final boolean useStackBanging = getFlag("UseStackBanging", Boolean.class); + public final int stackBias = getConstant("STACK_BIAS", Integer.class); + public final int vmPageSize = getFieldValue("CompilerToVM::Data::vm_page_size", Integer.class, "int"); + + public final int markOffset = getFieldOffset("oopDesc::_mark", Integer.class, "markOop"); + public final int hubOffset = getFieldOffset("oopDesc::_metadata._klass", Integer.class, "Klass*"); + + public final int prototypeMarkWordOffset = getFieldOffset("Klass::_prototype_header", Integer.class, "markOop"); + public final int subklassOffset = getFieldOffset("Klass::_subklass", Integer.class, "Klass*"); + public final int nextSiblingOffset = getFieldOffset("Klass::_next_sibling", Integer.class, "Klass*"); + public final int superCheckOffsetOffset = getFieldOffset("Klass::_super_check_offset", Integer.class, "juint"); + public final int secondarySuperCacheOffset = getFieldOffset("Klass::_secondary_super_cache", Integer.class, "Klass*"); + public final int secondarySupersOffset = getFieldOffset("Klass::_secondary_supers", Integer.class, "Array*"); + + public final int classMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "oop"); + + public final int klassSuperKlassOffset = getFieldOffset("Klass::_super", Integer.class, "Klass*"); + public final int klassModifierFlagsOffset = getFieldOffset("Klass::_modifier_flags", Integer.class, "jint"); + public final int klassAccessFlagsOffset = getFieldOffset("Klass::_access_flags", Integer.class, "AccessFlags"); + public final int klassLayoutHelperOffset = getFieldOffset("Klass::_layout_helper", Integer.class, "jint"); + + public final int klassLayoutHelperNeutralValue = getConstant("Klass::_lh_neutral_value", Integer.class); + public final int layoutHelperLog2ElementSizeShift = getConstant("Klass::_lh_log2_element_size_shift", Integer.class); + public final int layoutHelperLog2ElementSizeMask = getConstant("Klass::_lh_log2_element_size_mask", Integer.class); + public final int layoutHelperElementTypeShift = getConstant("Klass::_lh_element_type_shift", Integer.class); + public final int layoutHelperElementTypeMask = getConstant("Klass::_lh_element_type_mask", Integer.class); + public final int layoutHelperHeaderSizeShift = getConstant("Klass::_lh_header_size_shift", Integer.class); + public final int layoutHelperHeaderSizeMask = getConstant("Klass::_lh_header_size_mask", Integer.class); + public final int layoutHelperArrayTagShift = getConstant("Klass::_lh_array_tag_shift", Integer.class); + public final int layoutHelperArrayTagTypeValue = getConstant("Klass::_lh_array_tag_type_value", Integer.class); + public final int layoutHelperArrayTagObjectValue = getConstant("Klass::_lh_array_tag_obj_value", Integer.class); + + /** + * This filters out the bit that differentiates a type array from an object array. + */ + public int layoutHelperElementTypePrimitiveInPlace() { + return (layoutHelperArrayTagTypeValue & ~layoutHelperArrayTagObjectValue) << layoutHelperArrayTagShift; + } + + public final int vtableEntrySize = getTypeSize("vtableEntry"); + public final int vtableEntryMethodOffset = getFieldOffset("vtableEntry::_method", Integer.class, "Method*"); + + public final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "u1"); + public final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*"); + public final int instanceKlassFieldsOffset = getFieldOffset("InstanceKlass::_fields", Integer.class, "Array*"); + public final int klassVtableStartOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_start_offset", Integer.class, "int"); + public final int klassVtableLengthOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_length_offset", Integer.class, "int"); + + public final int instanceKlassStateLinked = getConstant("InstanceKlass::linked", Integer.class); + public final int instanceKlassStateFullyInitialized = getConstant("InstanceKlass::fully_initialized", Integer.class); + + public final int arrayOopDescSize = getTypeSize("arrayOopDesc"); + + /** + * The offset of the array length word in an array object's header. + * + * See {@code arrayOopDesc::length_offset_in_bytes()}. + */ + public final int arrayOopDescLengthOffset() { + return useCompressedClassPointers ? hubOffset + narrowKlassSize : arrayOopDescSize; + } + + public final int arrayU1LengthOffset = getFieldOffset("Array::_length", Integer.class, "int"); + public final int arrayU1DataOffset = getFieldOffset("Array::_data", Integer.class); + public final int arrayU2DataOffset = getFieldOffset("Array::_data", Integer.class); + public final int metaspaceArrayLengthOffset = getFieldOffset("Array::_length", Integer.class, "int"); + public final int metaspaceArrayBaseOffset = getFieldOffset("Array::_data[0]", Integer.class, "Klass*"); + + public final int arrayClassElementOffset = getFieldOffset("ObjArrayKlass::_element_klass", Integer.class, "Klass*"); + + public final int fieldInfoAccessFlagsOffset = getConstant("FieldInfo::access_flags_offset", Integer.class); + public final int fieldInfoNameIndexOffset = getConstant("FieldInfo::name_index_offset", Integer.class); + public final int fieldInfoSignatureIndexOffset = getConstant("FieldInfo::signature_index_offset", Integer.class); + public final int fieldInfoInitvalIndexOffset = getConstant("FieldInfo::initval_index_offset", Integer.class); + public final int fieldInfoLowPackedOffset = getConstant("FieldInfo::low_packed_offset", Integer.class); + public final int fieldInfoHighPackedOffset = getConstant("FieldInfo::high_packed_offset", Integer.class); + public final int fieldInfoFieldSlots = getConstant("FieldInfo::field_slots", Integer.class); + + public final int fieldInfoTagSize = getConstant("FIELDINFO_TAG_SIZE", Integer.class); + + public final int jvmAccMonitorMatch = getConstant("JVM_ACC_MONITOR_MATCH", Integer.class); + public final int jvmAccHasMonitorBytecodes = getConstant("JVM_ACC_HAS_MONITOR_BYTECODES", Integer.class); + public final int jvmAccHasFinalizer = getConstant("JVM_ACC_HAS_FINALIZER", Integer.class); + public final int jvmAccFieldInternal = getConstant("JVM_ACC_FIELD_INTERNAL", Integer.class); + public final int jvmAccFieldStable = getConstant("JVM_ACC_FIELD_STABLE", Integer.class); + public final int jvmAccFieldHasGenericSignature = getConstant("JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE", Integer.class); + public final int jvmAccWrittenFlags = getConstant("JVM_ACC_WRITTEN_FLAGS", Integer.class); + public final int jvmAccSynthetic = getConstant("JVM_ACC_SYNTHETIC", Integer.class); + + public final int threadTlabOffset = getFieldOffset("Thread::_tlab", Integer.class, "ThreadLocalAllocBuffer"); + public final int javaThreadAnchorOffset = getFieldOffset("JavaThread::_anchor", Integer.class, "JavaFrameAnchor"); + public final int threadObjectOffset = getFieldOffset("JavaThread::_threadObj", Integer.class, "oop"); + public final int osThreadOffset = getFieldOffset("JavaThread::_osthread", Integer.class, "OSThread*"); + public final int javaThreadDirtyCardQueueOffset = getFieldOffset("JavaThread::_dirty_card_queue", Integer.class, "DirtyCardQueue"); + public final int threadIsMethodHandleReturnOffset = getFieldOffset("JavaThread::_is_method_handle_return", Integer.class, "int"); + public final int javaThreadSatbMarkQueueOffset = getFieldOffset("JavaThread::_satb_mark_queue", Integer.class); + public final int threadObjectResultOffset = getFieldOffset("JavaThread::_vm_result", Integer.class, "oop"); + public final int jvmciCountersThreadOffset = getFieldOffset("JavaThread::_jvmci_counters", Integer.class, "jlong*"); + public final int javaThreadReservedStackActivationOffset = getFieldOffset("JavaThread::_reserved_stack_activation", Integer.class, "address", intNotPresentInJDK8); + + /** + * An invalid value for {@link #rtldDefault}. + */ + public static final long INVALID_RTLD_DEFAULT_HANDLE = 0xDEADFACE; + + /** + * Address of the library lookup routine. The C signature of this routine is: + * + *
    +     *     void* (const char *filename, char *ebuf, int ebuflen)
    +     * 
    + */ + public final long dllLoad = getAddress("os::dll_load"); + + /** + * Address of the library lookup routine. The C signature of this routine is: + * + *
    +     *     void* (void* handle, const char* name)
    +     * 
    + */ + public final long dllLookup = getAddress("os::dll_lookup"); + + /** + * A pseudo-handle which when used as the first argument to {@link #dllLookup} means lookup will + * return the first occurrence of the desired symbol using the default library search order. If + * this field is {@value #INVALID_RTLD_DEFAULT_HANDLE}, then this capability is not supported on + * the current platform. + */ + public final long rtldDefault = getAddress("RTLD_DEFAULT", osName.equals("bsd") || osName.equals("linux") ? null : INVALID_RTLD_DEFAULT_HANDLE); + + /** + * This field is used to pass exception objects into and out of the runtime system during + * exception handling for compiled code. + */ + public final int threadExceptionOopOffset = getFieldOffset("JavaThread::_exception_oop", Integer.class, "oop"); + public final int threadExceptionPcOffset = getFieldOffset("JavaThread::_exception_pc", Integer.class, "address"); + public final int pendingExceptionOffset = getFieldOffset("ThreadShadow::_pending_exception", Integer.class, "oop"); + + public final int pendingDeoptimizationOffset = getFieldOffset("JavaThread::_pending_deoptimization", Integer.class, "int"); + public final int pendingFailedSpeculationOffset = getFieldOffset("JavaThread::_pending_failed_speculation", Integer.class, "oop"); + public final int pendingTransferToInterpreterOffset = getFieldOffset("JavaThread::_pending_transfer_to_interpreter", Integer.class, "bool"); + + private final int javaFrameAnchorLastJavaSpOffset = getFieldOffset("JavaFrameAnchor::_last_Java_sp", Integer.class, "intptr_t*"); + private final int javaFrameAnchorLastJavaPcOffset = getFieldOffset("JavaFrameAnchor::_last_Java_pc", Integer.class, "address"); + + public int threadLastJavaSpOffset() { + return javaThreadAnchorOffset + javaFrameAnchorLastJavaSpOffset; + } + + public int threadLastJavaPcOffset() { + return javaThreadAnchorOffset + javaFrameAnchorLastJavaPcOffset; + } + + public int threadLastJavaFpOffset() { + assert osArch.equals("aarch64") || osArch.equals("amd64"); + return javaThreadAnchorOffset + getFieldOffset("JavaFrameAnchor::_last_Java_fp", Integer.class, "intptr_t*"); + } + + public int threadJavaFrameAnchorFlagsOffset() { + assert osArch.equals("sparc"); + return javaThreadAnchorOffset + getFieldOffset("JavaFrameAnchor::_flags", Integer.class, "int"); + } + + public final int runtimeCallStackSize = getConstant("frame::arg_reg_save_area_bytes", Integer.class, intRequiredOnAMD64); + public final int frameInterpreterFrameSenderSpOffset = getConstant("frame::interpreter_frame_sender_sp_offset", Integer.class, intRequiredOnAMD64); + public final int frameInterpreterFrameLastSpOffset = getConstant("frame::interpreter_frame_last_sp_offset", Integer.class, intRequiredOnAMD64); + + private final int dirtyCardQueueBufferOffset = isJDK8 ? getFieldOffset("PtrQueue::_buf", Integer.class, "void**") : getConstant("dirtyCardQueueBufferOffset", Integer.class); + private final int dirtyCardQueueIndexOffset = isJDK8 ? getFieldOffset("PtrQueue::_index", Integer.class, "size_t") : getConstant("dirtyCardQueueIndexOffset", Integer.class); + + private final int satbMarkQueueBufferOffset = getConstant("satbMarkQueueBufferOffset", Integer.class, intNotPresentInJDK8); + private final int satbMarkQueueIndexOffset = getConstant("satbMarkQueueIndexOffset", Integer.class, intNotPresentInJDK8); + private final int satbMarkQueueActiveOffset = isJDK8 ? getFieldOffset("PtrQueue::_active", Integer.class, "bool") : getConstant("satbMarkQueueActiveOffset", Integer.class, intNotPresentInJDK8); + + public final int osThreadInterruptedOffset = getFieldOffset("OSThread::_interrupted", Integer.class, "jint"); + + public final long markOopDescHashShift = getConstant("markOopDesc::hash_shift", Long.class); + + public final int biasedLockMaskInPlace = getConstant("markOopDesc::biased_lock_mask_in_place", Integer.class); + public final int ageMaskInPlace = getConstant("markOopDesc::age_mask_in_place", Integer.class); + public final int epochMaskInPlace = getConstant("markOopDesc::epoch_mask_in_place", Integer.class); + public final long markOopDescHashMask = getConstant("markOopDesc::hash_mask", Long.class); + public final long markOopDescHashMaskInPlace = getConstant("markOopDesc::hash_mask_in_place", Long.class); + + public final int unlockedMask = getConstant("markOopDesc::unlocked_value", Integer.class); + public final int biasedLockPattern = getConstant("markOopDesc::biased_lock_pattern", Integer.class); + + public final int markWordNoHashInPlace = getConstant("markOopDesc::no_hash_in_place", Integer.class); + public final int markWordNoLockInPlace = getConstant("markOopDesc::no_lock_in_place", Integer.class); + + /** + * See {@code markOopDesc::prototype()}. + */ + public long arrayPrototypeMarkWord() { + return markWordNoHashInPlace | markWordNoLockInPlace; + } + + /** + * See {@code markOopDesc::copy_set_hash()}. + */ + public long tlabIntArrayMarkWord() { + long tmp = arrayPrototypeMarkWord() & (~markOopDescHashMaskInPlace); + tmp |= ((0x2 & markOopDescHashMask) << markOopDescHashShift); + return tmp; + } + + /** + * Mark word right shift to get identity hash code. + */ + public final int identityHashCodeShift = getConstant("markOopDesc::hash_shift", Integer.class); + + /** + * Identity hash code value when uninitialized. + */ + public final int uninitializedIdentityHashCodeValue = getConstant("markOopDesc::no_hash", Integer.class); + + public final int methodAccessFlagsOffset = getFieldOffset("Method::_access_flags", Integer.class, "AccessFlags"); + public final int methodConstMethodOffset = getFieldOffset("Method::_constMethod", Integer.class, "ConstMethod*"); + public final int methodIntrinsicIdOffset = getFieldOffset("Method::_intrinsic_id", Integer.class, isJDK8 ? "u1" : "u2"); + public final int methodFlagsOffset = getFieldOffset("Method::_flags", Integer.class, isJDK8 ? "u1" : "u2"); + public final int methodVtableIndexOffset = getFieldOffset("Method::_vtable_index", Integer.class, "int"); + + public final int methodCountersOffset = getFieldOffset("Method::_method_counters", Integer.class, "MethodCounters*"); + public final int methodDataOffset = getFieldOffset("Method::_method_data", Integer.class, "MethodData*"); + public final int methodCompiledEntryOffset = getFieldOffset("Method::_from_compiled_entry", Integer.class, "address"); + public final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, isJDK8 ? "nmethod*" : "CompiledMethod*"); + + public final int methodFlagsJfrTowrite = getConstant("Method::_jfr_towrite", Integer.class); + public final int methodFlagsCallerSensitive = getConstant("Method::_caller_sensitive", Integer.class); + public final int methodFlagsForceInline = getConstant("Method::_force_inline", Integer.class); + public final int methodFlagsDontInline = getConstant("Method::_dont_inline", Integer.class); + public final int methodFlagsHidden = getConstant("Method::_hidden", Integer.class); + public final int nonvirtualVtableIndex = getConstant("Method::nonvirtual_vtable_index", Integer.class); + public final int invalidVtableIndex = getConstant("Method::invalid_vtable_index", Integer.class); + + public final int invocationCounterOffset = getFieldOffset("MethodCounters::_invocation_counter", Integer.class, "InvocationCounter"); + public final int backedgeCounterOffset = getFieldOffset("MethodCounters::_backedge_counter", Integer.class, "InvocationCounter"); + public final int invocationCounterIncrement = getConstant("InvocationCounter::count_increment", Integer.class, intNotPresentInJDK8); + public final int invocationCounterShift = getConstant("InvocationCounter::count_shift", Integer.class, intNotPresentInJDK8); + + public final int nmethodEntryOffset = getFieldOffset("nmethod::_verified_entry_point", + Integer.class, "address"); + public final int compilationLevelFullOptimization = getConstant("CompLevel_full_optimization", + Integer.class); + + public final int constantPoolSize = getTypeSize("ConstantPool"); + public final int constantPoolLengthOffset = getFieldOffset("ConstantPool::_length", + Integer.class, "int"); + + public final int heapWordSize = getConstant("HeapWordSize", Integer.class); + + /** + * Bit pattern that represents a non-oop. Neither the high bits nor the low bits of this value + * are allowed to look like (respectively) the high or low bits of a real oop. + */ + public final long nonOopBits = getFieldValue("CompilerToVM::Data::Universe_non_oop_bits", Long.class, "void*"); + + public final long verifyOopCounterAddress = getFieldAddress("StubRoutines::_verify_oop_count", "jint"); + public final long verifyOopMask = getFieldValue("CompilerToVM::Data::Universe_verify_oop_mask", Long.class, "uintptr_t"); + public final long verifyOopBits = getFieldValue("CompilerToVM::Data::Universe_verify_oop_bits", Long.class, "uintptr_t"); + + public final int logOfHRGrainBytes = getFieldValue("HeapRegion::LogOfHRGrainBytes", Integer.class, "int"); + + public final byte dirtyCardValue = isJDK8 ? getFieldValue("CompilerToVM::Data::dirty_card", Byte.class, "int") : getConstant("CardTableModRefBS::dirty_card", Byte.class); + public final byte g1YoungCardValue = isJDK8 ? getFieldValue("CompilerToVM::Data::g1_young_card", Byte.class, "int") : getConstant("G1SATBCardTableModRefBS::g1_young_gen", Byte.class); + + public final long cardtableStartAddress = getFieldValue("CompilerToVM::Data::cardtable_start_address", Long.class, "jbyte*"); + public final int cardtableShift = getFieldValue("CompilerToVM::Data::cardtable_shift", Integer.class, "int"); + + /** + * This is the largest stack offset encodeable in an OopMapValue. Offsets larger than this will + * throw an exception during code installation. + */ + public final int maxOopMapStackOffset = getFieldValueWithAlternate("CompilerToVM::Data::_max_oop_map_stack_offset", "JVMCIRuntime::max_oop_map_stack_offset", Integer.class, "int"); + + public final long safepointPollingAddress = getFieldValue("os::_polling_page", Long.class, "address"); + + // G1 Collector Related Values. + + public int g1CardQueueIndexOffset() { + return javaThreadDirtyCardQueueOffset + dirtyCardQueueIndexOffset; + } + + public int g1CardQueueBufferOffset() { + return javaThreadDirtyCardQueueOffset + dirtyCardQueueBufferOffset; + } + + public int g1SATBQueueMarkingOffset() { + return javaThreadSatbMarkQueueOffset + satbMarkQueueActiveOffset; + } + + public int g1SATBQueueIndexOffset() { + return javaThreadSatbMarkQueueOffset + (isJDK8 ? dirtyCardQueueIndexOffset : satbMarkQueueIndexOffset); + } + + public int g1SATBQueueBufferOffset() { + return javaThreadSatbMarkQueueOffset + (isJDK8 ? dirtyCardQueueBufferOffset : satbMarkQueueBufferOffset); + } + + public final int klassOffset = getFieldValue("java_lang_Class::_klass_offset", Integer.class, "int"); + public final int arrayKlassOffset = getFieldValue("java_lang_Class::_array_klass_offset", Integer.class, "int"); + + public final int basicLockSize = getTypeSize("BasicLock"); + public final int basicLockDisplacedHeaderOffset = getFieldOffset("BasicLock::_displaced_header", Integer.class, "markOop"); + + public final int threadAllocatedBytesOffset = getFieldOffset("Thread::_allocated_bytes", Integer.class, "jlong"); + + public final int tlabRefillWasteIncrement = getFlag("TLABWasteIncrement", Integer.class); + + private final int threadLocalAllocBufferStartOffset = getFieldOffset("ThreadLocalAllocBuffer::_start", Integer.class, "HeapWord*"); + private final int threadLocalAllocBufferEndOffset = getFieldOffset("ThreadLocalAllocBuffer::_end", Integer.class, "HeapWord*"); + private final int threadLocalAllocBufferTopOffset = getFieldOffset("ThreadLocalAllocBuffer::_top", Integer.class, "HeapWord*"); + private final int threadLocalAllocBufferPfTopOffset = getFieldOffset("ThreadLocalAllocBuffer::_pf_top", Integer.class, "HeapWord*"); + private final int threadLocalAllocBufferSlowAllocationsOffset = getFieldOffset("ThreadLocalAllocBuffer::_slow_allocations", Integer.class, "unsigned"); + private final int threadLocalAllocBufferFastRefillWasteOffset = getFieldOffset("ThreadLocalAllocBuffer::_fast_refill_waste", Integer.class, "unsigned"); + private final int threadLocalAllocBufferNumberOfRefillsOffset = getFieldOffset("ThreadLocalAllocBuffer::_number_of_refills", Integer.class, "unsigned"); + private final int threadLocalAllocBufferRefillWasteLimitOffset = getFieldOffset("ThreadLocalAllocBuffer::_refill_waste_limit", Integer.class, "size_t"); + private final int threadLocalAllocBufferDesiredSizeOffset = getFieldOffset("ThreadLocalAllocBuffer::_desired_size", Integer.class, "size_t"); + + public int tlabSlowAllocationsOffset() { + return threadTlabOffset + threadLocalAllocBufferSlowAllocationsOffset; + } + + public int tlabFastRefillWasteOffset() { + return threadTlabOffset + threadLocalAllocBufferFastRefillWasteOffset; + } + + public int tlabNumberOfRefillsOffset() { + return threadTlabOffset + threadLocalAllocBufferNumberOfRefillsOffset; + } + + public int tlabRefillWasteLimitOffset() { + return threadTlabOffset + threadLocalAllocBufferRefillWasteLimitOffset; + } + + public int threadTlabSizeOffset() { + return threadTlabOffset + threadLocalAllocBufferDesiredSizeOffset; + } + + public int threadTlabStartOffset() { + return threadTlabOffset + threadLocalAllocBufferStartOffset; + } + + public int threadTlabEndOffset() { + return threadTlabOffset + threadLocalAllocBufferEndOffset; + } + + public int threadTlabTopOffset() { + return threadTlabOffset + threadLocalAllocBufferTopOffset; + } + + public int threadTlabPfTopOffset() { + return threadTlabOffset + threadLocalAllocBufferPfTopOffset; + } + + public final int tlabAlignmentReserve = getFieldValue("CompilerToVM::Data::ThreadLocalAllocBuffer_alignment_reserve", Integer.class, "size_t"); + + public final boolean tlabStats = getFlag("TLABStats", Boolean.class); + + // FIXME This is only temporary until the GC code is changed. + public final boolean inlineContiguousAllocationSupported = getFieldValue("CompilerToVM::Data::_supports_inline_contig_alloc", Boolean.class); + public final long heapEndAddress = getFieldValue("CompilerToVM::Data::_heap_end_addr", Long.class, "HeapWord**"); + public final long heapTopAddress = getFieldValue("CompilerToVM::Data::_heap_top_addr", Long.class, isJDK8 ? "HeapWord**" : "HeapWord* volatile*"); + + public final long inlineCacheMissStub = getFieldValue("CompilerToVM::Data::SharedRuntime_ic_miss_stub", Long.class, "address"); + public final long handleWrongMethodStub = getFieldValue("CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", Long.class, "address"); + + public final long handleDeoptStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", Long.class, "address"); + public final long uncommonTrapStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", Long.class, "address"); + + public final long codeCacheLowBound = getFieldValue(isJDK8 ? "CompilerToVM::Data::CodeCache_low_bound" : "CodeCache::_low_bound", Long.class, "address"); + public final long codeCacheHighBound = getFieldValue(isJDK8 ? "CompilerToVM::Data::CodeCache_high_bound" : "CodeCache::_high_bound", Long.class, "address"); + + public final long aescryptEncryptBlockStub = getFieldValue("StubRoutines::_aescrypt_encryptBlock", Long.class, "address"); + public final long aescryptDecryptBlockStub = getFieldValue("StubRoutines::_aescrypt_decryptBlock", Long.class, "address"); + public final long cipherBlockChainingEncryptAESCryptStub = getFieldValue("StubRoutines::_cipherBlockChaining_encryptAESCrypt", Long.class, "address"); + public final long cipherBlockChainingDecryptAESCryptStub = getFieldValue("StubRoutines::_cipherBlockChaining_decryptAESCrypt", Long.class, "address"); + public final long updateBytesCRC32Stub = getFieldValue("StubRoutines::_updateBytesCRC32", Long.class, "address"); + public final long crcTableAddress = getFieldValue("StubRoutines::_crc_table_adr", Long.class, "address"); + + public final long sha1ImplCompress = getFieldValue("StubRoutines::_sha1_implCompress", Long.class, "address", 0L); + public final long sha1ImplCompressMB = getFieldValue("StubRoutines::_sha1_implCompressMB", Long.class, "address", 0L); + public final long sha256ImplCompress = getFieldValue("StubRoutines::_sha256_implCompress", Long.class, "address", 0L); + public final long sha256ImplCompressMB = getFieldValue("StubRoutines::_sha256_implCompressMB", Long.class, "address", 0L); + public final long sha512ImplCompress = getFieldValue("StubRoutines::_sha512_implCompress", Long.class, "address", 0L); + public final long sha512ImplCompressMB = getFieldValue("StubRoutines::_sha512_implCompressMB", Long.class, "address", 0L); + public final long multiplyToLen = getFieldValue("StubRoutines::_multiplyToLen", Long.class, "address", 0L); + + public final long counterModeAESCrypt = getFieldValue("StubRoutines::_counterMode_AESCrypt", Long.class, "address", 0L); + public final long ghashProcessBlocks = getFieldValue("StubRoutines::_ghash_processBlocks", Long.class, "address", 0L); + public final long crc32cTableTddr = getFieldValue("StubRoutines::_crc32c_table_addr", Long.class, "address", 0L); + public final long updateBytesCRC32C = getFieldValue("StubRoutines::_updateBytesCRC32C", Long.class, "address", 0L); + public final long updateBytesAdler32 = getFieldValue("StubRoutines::_updateBytesAdler32", Long.class, "address", 0L); + public final long squareToLen = getFieldValue("StubRoutines::_squareToLen", Long.class, "address", 0L); + public final long mulAdd = getFieldValue("StubRoutines::_mulAdd", Long.class, "address", 0L); + public final long montgomeryMultiply = getFieldValue("StubRoutines::_montgomeryMultiply", Long.class, "address", 0L); + public final long montgomerySquare = getFieldValue("StubRoutines::_montgomerySquare", Long.class, "address", 0L); + public final long vectorizedMismatch = getFieldValue("StubRoutines::_vectorizedMismatch", Long.class, "address", 0L); + + public final long throwDelayedStackOverflowErrorEntry = getFieldValue("StubRoutines::_throw_delayed_StackOverflowError_entry", Long.class, "address", longNotPresentInJDK8); + + public final long jbyteArraycopy = getFieldValue("StubRoutines::_jbyte_arraycopy", Long.class, "address"); + public final long jshortArraycopy = getFieldValue("StubRoutines::_jshort_arraycopy", Long.class, "address"); + public final long jintArraycopy = getFieldValue("StubRoutines::_jint_arraycopy", Long.class, "address"); + public final long jlongArraycopy = getFieldValue("StubRoutines::_jlong_arraycopy", Long.class, "address"); + public final long oopArraycopy = getFieldValue("StubRoutines::_oop_arraycopy", Long.class, "address"); + public final long oopArraycopyUninit = getFieldValue("StubRoutines::_oop_arraycopy_uninit", Long.class, "address"); + public final long jbyteDisjointArraycopy = getFieldValue("StubRoutines::_jbyte_disjoint_arraycopy", Long.class, "address"); + public final long jshortDisjointArraycopy = getFieldValue("StubRoutines::_jshort_disjoint_arraycopy", Long.class, "address"); + public final long jintDisjointArraycopy = getFieldValue("StubRoutines::_jint_disjoint_arraycopy", Long.class, "address"); + public final long jlongDisjointArraycopy = getFieldValue("StubRoutines::_jlong_disjoint_arraycopy", Long.class, "address"); + public final long oopDisjointArraycopy = getFieldValue("StubRoutines::_oop_disjoint_arraycopy", Long.class, "address"); + public final long oopDisjointArraycopyUninit = getFieldValue("StubRoutines::_oop_disjoint_arraycopy_uninit", Long.class, "address"); + public final long jbyteAlignedArraycopy = getFieldValue("StubRoutines::_arrayof_jbyte_arraycopy", Long.class, "address"); + public final long jshortAlignedArraycopy = getFieldValue("StubRoutines::_arrayof_jshort_arraycopy", Long.class, "address"); + public final long jintAlignedArraycopy = getFieldValue("StubRoutines::_arrayof_jint_arraycopy", Long.class, "address"); + public final long jlongAlignedArraycopy = getFieldValue("StubRoutines::_arrayof_jlong_arraycopy", Long.class, "address"); + public final long oopAlignedArraycopy = getFieldValue("StubRoutines::_arrayof_oop_arraycopy", Long.class, "address"); + public final long oopAlignedArraycopyUninit = getFieldValue("StubRoutines::_arrayof_oop_arraycopy_uninit", Long.class, "address"); + public final long jbyteAlignedDisjointArraycopy = getFieldValue("StubRoutines::_arrayof_jbyte_disjoint_arraycopy", Long.class, "address"); + public final long jshortAlignedDisjointArraycopy = getFieldValue("StubRoutines::_arrayof_jshort_disjoint_arraycopy", Long.class, "address"); + public final long jintAlignedDisjointArraycopy = getFieldValue("StubRoutines::_arrayof_jint_disjoint_arraycopy", Long.class, "address"); + public final long jlongAlignedDisjointArraycopy = getFieldValue("StubRoutines::_arrayof_jlong_disjoint_arraycopy", Long.class, "address"); + public final long oopAlignedDisjointArraycopy = getFieldValue("StubRoutines::_arrayof_oop_disjoint_arraycopy", Long.class, "address"); + public final long oopAlignedDisjointArraycopyUninit = getFieldValue("StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", Long.class, "address"); + public final long checkcastArraycopy = getFieldValue("StubRoutines::_checkcast_arraycopy", Long.class, "address"); + public final long checkcastArraycopyUninit = getFieldValue("StubRoutines::_checkcast_arraycopy_uninit", Long.class, "address"); + public final long unsafeArraycopy = getFieldValue("StubRoutines::_unsafe_arraycopy", Long.class, "address"); + public final long genericArraycopy = getFieldValue("StubRoutines::_generic_arraycopy", Long.class, "address"); + + public final long newInstanceAddress = getAddress("JVMCIRuntime::new_instance"); + public final long newArrayAddress = getAddress("JVMCIRuntime::new_array"); + public final long newMultiArrayAddress = getAddress("JVMCIRuntime::new_multi_array"); + public final long dynamicNewArrayAddress = getAddress("JVMCIRuntime::dynamic_new_array"); + public final long dynamicNewInstanceAddress = getAddress("JVMCIRuntime::dynamic_new_instance"); + + public final long threadIsInterruptedAddress = getAddress("JVMCIRuntime::thread_is_interrupted"); + public final long vmMessageAddress = getAddress("JVMCIRuntime::vm_message"); + public final long identityHashCodeAddress = getAddress("JVMCIRuntime::identity_hash_code"); + public final long exceptionHandlerForPcAddress = getAddress("JVMCIRuntime::exception_handler_for_pc"); + public final long monitorenterAddress = getAddress("JVMCIRuntime::monitorenter"); + public final long monitorexitAddress = getAddress("JVMCIRuntime::monitorexit"); + public final long throwAndPostJvmtiExceptionAddress = getAddress("JVMCIRuntime::throw_and_post_jvmti_exception"); + public final long throwKlassExternalNameExceptionAddress = getAddress("JVMCIRuntime::throw_klass_external_name_exception"); + public final long throwClassCastExceptionAddress = getAddress("JVMCIRuntime::throw_class_cast_exception"); + public final long logPrimitiveAddress = getAddress("JVMCIRuntime::log_primitive"); + public final long logObjectAddress = getAddress("JVMCIRuntime::log_object"); + public final long logPrintfAddress = getAddress("JVMCIRuntime::log_printf"); + public final long vmErrorAddress = getAddress("JVMCIRuntime::vm_error"); + public final long loadAndClearExceptionAddress = getAddress("JVMCIRuntime::load_and_clear_exception"); + public final long writeBarrierPreAddress = getAddress("JVMCIRuntime::write_barrier_pre"); + public final long writeBarrierPostAddress = getAddress("JVMCIRuntime::write_barrier_post"); + public final long validateObject = getAddress("JVMCIRuntime::validate_object"); + + public final long testDeoptimizeCallInt = getAddress("JVMCIRuntime::test_deoptimize_call_int"); + + public final long registerFinalizerAddress = getAddress("SharedRuntime::register_finalizer"); + public final long exceptionHandlerForReturnAddressAddress = getAddress("SharedRuntime::exception_handler_for_return_address"); + public final long osrMigrationEndAddress = getAddress("SharedRuntime::OSR_migration_end"); + public final long enableStackReservedZoneAddress = getAddress("SharedRuntime::enable_stack_reserved_zone", longNotPresentInJDK8); + + public final long javaTimeMillisAddress = getAddress("os::javaTimeMillis"); + public final long javaTimeNanosAddress = getAddress("os::javaTimeNanos"); + public final long arithmeticSinAddress = getFieldValue("CompilerToVM::Data::dsin", Long.class, "address"); + public final long arithmeticCosAddress = getFieldValue("CompilerToVM::Data::dcos", Long.class, "address"); + public final long arithmeticTanAddress = getFieldValue("CompilerToVM::Data::dtan", Long.class, "address"); + public final long arithmeticExpAddress = getFieldValue("CompilerToVM::Data::dexp", Long.class, "address"); + public final long arithmeticLogAddress = getFieldValue("CompilerToVM::Data::dlog", Long.class, "address"); + public final long arithmeticLog10Address = getFieldValue("CompilerToVM::Data::dlog10", Long.class, "address"); + public final long arithmeticPowAddress = getFieldValue("CompilerToVM::Data::dpow", Long.class, "address"); + + public final long fremAddress = getAddress("SharedRuntime::frem"); + public final long dremAddress = getAddress("SharedRuntime::drem"); + + public final int jvmciCountersSize = getFlag("JVMCICounterSize", Integer.class); + + public final long deoptimizationFetchUnrollInfo = getAddress("Deoptimization::fetch_unroll_info"); + public final long deoptimizationUncommonTrap = getAddress("Deoptimization::uncommon_trap"); + public final long deoptimizationUnpackFrames = getAddress("Deoptimization::unpack_frames"); + + public final int deoptimizationUnpackDeopt = getConstant("Deoptimization::Unpack_deopt", Integer.class); + public final int deoptimizationUnpackException = getConstant("Deoptimization::Unpack_exception", Integer.class); + public final int deoptimizationUnpackUncommonTrap = getConstant("Deoptimization::Unpack_uncommon_trap", Integer.class); + public final int deoptimizationUnpackReexecute = getConstant("Deoptimization::Unpack_reexecute", Integer.class); + + public final int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset = getFieldOffset("Deoptimization::UnrollBlock::_size_of_deoptimized_frame", Integer.class, "int"); + public final int deoptimizationUnrollBlockCallerAdjustmentOffset = getFieldOffset("Deoptimization::UnrollBlock::_caller_adjustment", Integer.class, "int"); + public final int deoptimizationUnrollBlockNumberOfFramesOffset = getFieldOffset("Deoptimization::UnrollBlock::_number_of_frames", Integer.class, "int"); + public final int deoptimizationUnrollBlockTotalFrameSizesOffset = getFieldOffset("Deoptimization::UnrollBlock::_total_frame_sizes", Integer.class, "int"); + public final int deoptimizationUnrollBlockUnpackKindOffset = getFieldOffset("Deoptimization::UnrollBlock::_unpack_kind", Integer.class, "int"); + public final int deoptimizationUnrollBlockFrameSizesOffset = getFieldOffset("Deoptimization::UnrollBlock::_frame_sizes", Integer.class, "intptr_t*"); + public final int deoptimizationUnrollBlockFramePcsOffset = getFieldOffset("Deoptimization::UnrollBlock::_frame_pcs", Integer.class, "address*"); + public final int deoptimizationUnrollBlockInitialInfoOffset = getFieldOffset("Deoptimization::UnrollBlock::_initial_info", Integer.class, "intptr_t"); + + // Checkstyle: stop + public final int MARKID_VERIFIED_ENTRY = getConstant("CodeInstaller::VERIFIED_ENTRY", Integer.class); + public final int MARKID_UNVERIFIED_ENTRY = getConstant("CodeInstaller::UNVERIFIED_ENTRY", Integer.class); + public final int MARKID_OSR_ENTRY = getConstant("CodeInstaller::OSR_ENTRY", Integer.class); + public final int MARKID_EXCEPTION_HANDLER_ENTRY = getConstant("CodeInstaller::EXCEPTION_HANDLER_ENTRY", Integer.class); + public final int MARKID_DEOPT_HANDLER_ENTRY = getConstant("CodeInstaller::DEOPT_HANDLER_ENTRY", Integer.class); + public final int MARKID_INVOKEINTERFACE = getConstant("CodeInstaller::INVOKEINTERFACE", Integer.class); + public final int MARKID_INVOKEVIRTUAL = getConstant("CodeInstaller::INVOKEVIRTUAL", Integer.class); + public final int MARKID_INVOKESTATIC = getConstant("CodeInstaller::INVOKESTATIC", Integer.class); + public final int MARKID_INVOKESPECIAL = getConstant("CodeInstaller::INVOKESPECIAL", Integer.class); + public final int MARKID_INLINE_INVOKE = getConstant("CodeInstaller::INLINE_INVOKE", Integer.class); + public final int MARKID_POLL_NEAR = getConstant("CodeInstaller::POLL_NEAR", Integer.class); + public final int MARKID_POLL_RETURN_NEAR = getConstant("CodeInstaller::POLL_RETURN_NEAR", Integer.class); + public final int MARKID_POLL_FAR = getConstant("CodeInstaller::POLL_FAR", Integer.class); + public final int MARKID_POLL_RETURN_FAR = getConstant("CodeInstaller::POLL_RETURN_FAR", Integer.class); + public final int MARKID_CARD_TABLE_SHIFT = getConstant("CodeInstaller::CARD_TABLE_SHIFT", Integer.class); + public final int MARKID_CARD_TABLE_ADDRESS = getConstant("CodeInstaller::CARD_TABLE_ADDRESS", Integer.class); + public final int MARKID_INVOKE_INVALID = getConstant("CodeInstaller::INVOKE_INVALID", Integer.class); + + /** + * The following constants are given default values here since they are missing in the native + * JVMCI-8 code but are still required for {@link GraalHotSpotVMConfigNode#canonical} to work in + * a JDK8 environment. + */ + public final int MARKID_HEAP_TOP_ADDRESS = getConstant("CodeInstaller::HEAP_TOP_ADDRESS", Integer.class, 17); + public final int MARKID_HEAP_END_ADDRESS = getConstant("CodeInstaller::HEAP_END_ADDRESS", Integer.class, 18); + public final int MARKID_NARROW_KLASS_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_KLASS_BASE_ADDRESS", Integer.class, 19); + public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 20); + public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 21); + public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 22); + + // Checkstyle: resume + + private boolean check() { + for (Field f : getClass().getDeclaredFields()) { + int modifiers = f.getModifiers(); + if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) { + assert Modifier.isFinal(modifiers) : "field should be final: " + f; + } + } + + assert codeEntryAlignment > 0 : codeEntryAlignment; + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java 2016-12-07 13:50:03.799954301 -0800 @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2012, 2016, 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; + +import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor; + +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.target.Backend; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.DeoptimizationFetchUnrollInfoCallNode; +import org.graalvm.compiler.hotspot.nodes.UncommonTrapCallNode; +import org.graalvm.compiler.hotspot.nodes.VMErrorNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall; +import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions; +import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions; +import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions; +import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions; +import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions; +import org.graalvm.compiler.hotspot.replacements.SHASubstitutions; +import org.graalvm.compiler.hotspot.stubs.DeoptimizationStub; +import org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; +import org.graalvm.compiler.lir.LIRInstruction.OperandMode; +import org.graalvm.compiler.lir.StandardOp.LabelOp; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.ValueConsumer; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.framemap.FrameMap; +import org.graalvm.compiler.nodes.UnwindNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.phases.tiers.SuitesProvider; +import org.graalvm.compiler.word.Pointer; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.CompilationRequest; +import jdk.vm.ci.code.CompiledCode; +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterSaveLayout; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.hotspot.HotSpotCompilationRequest; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.runtime.JVMCICompiler; + +/** + * HotSpot specific backend. + */ +public abstract class HotSpotBackend extends Backend implements FrameMap.ReferenceMapBuilderFactory { + + public static class Options { + // @formatter:off + @Option(help = "Use Graal stubs instead of HotSpot stubs where possible") + public static final OptionValue PreferGraalStubs = new OptionValue<>(false); + @Option(help = "Use Graal arithmetic stubs instead of HotSpot stubs where possible") + public static final OptionValue GraalArithmeticStubs = new OptionValue<>(true); + @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." + + " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug) + public static final OptionValue ASMInstructionProfiling = new OptionValue<>(null); + // @formatter:on + } + + /** + * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the + * {@linkplain GraalHotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception handler} in a + * compiled method. + */ + public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class); + + /** + * Descriptor for SharedRuntime::get_ic_miss_stub(). + */ + public static final ForeignCallDescriptor IC_MISS_HANDLER = new ForeignCallDescriptor("icMissHandler", void.class); + + /** + * Descriptor for SharedRuntime::get_handle_wrong_method_stub(). + */ + public static final ForeignCallDescriptor WRONG_METHOD_HANDLER = new ForeignCallDescriptor("wrongMethodHandler", void.class); + + /** + * Descriptor for {@link UnwindExceptionToCallerStub}. This stub is called by code generated + * from {@link UnwindNode}. + */ + public static final ForeignCallDescriptor UNWIND_EXCEPTION_TO_CALLER = new ForeignCallDescriptor("unwindExceptionToCaller", void.class, Object.class, Word.class); + + /** + * Descriptor for the arguments when unwinding to an exception handler in a caller. + */ + public static final ForeignCallDescriptor EXCEPTION_HANDLER_IN_CALLER = new ForeignCallDescriptor("exceptionHandlerInCaller", void.class, Object.class, Word.class); + + private final HotSpotGraalRuntimeProvider runtime; + + /** + * @see DeoptimizationFetchUnrollInfoCallNode + */ + public static final ForeignCallDescriptor FETCH_UNROLL_INFO = new ForeignCallDescriptor("fetchUnrollInfo", Word.class, long.class, int.class); + + /** + * @see DeoptimizationStub#unpackFrames(ForeignCallDescriptor, Word, int) + */ + public static final ForeignCallDescriptor UNPACK_FRAMES = newDescriptor(DeoptimizationStub.class, "unpackFrames", int.class, Word.class, int.class); + + /** + * @see AESCryptSubstitutions#encryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) + */ + public static final ForeignCallDescriptor ENCRYPT_BLOCK = new ForeignCallDescriptor("encrypt_block", void.class, Word.class, Word.class, Pointer.class); + + /** + * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) + */ + public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Pointer.class); + + /** + * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) + */ + public static final ForeignCallDescriptor DECRYPT_BLOCK_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_block_with_original_key", void.class, Word.class, Word.class, Pointer.class, + Pointer.class); + + /** + * @see CipherBlockChainingSubstitutions#crypt + */ + public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class); + + /** + * @see CipherBlockChainingSubstitutions#crypt + */ + public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class); + + /** + * @see CipherBlockChainingSubstitutions#crypt + */ + public static final ForeignCallDescriptor DECRYPT_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_with_original_key", void.class, Word.class, Word.class, Pointer.class, Pointer.class, + int.class, Pointer.class); + + /** + * @see BigIntegerSubstitutions#multiplyToLen + */ + public static final ForeignCallDescriptor MULTIPLY_TO_LEN = new ForeignCallDescriptor("multiplyToLen", void.class, Word.class, int.class, Word.class, int.class, Word.class, int.class); + + public static void multiplyToLenStub(Word xAddr, int xlen, Word yAddr, int ylen, Word zAddr, int zLen) { + multiplyToLenStub(HotSpotBackend.MULTIPLY_TO_LEN, xAddr, xlen, yAddr, ylen, zAddr, zLen); + } + + @NodeIntrinsic(ForeignCallNode.class) + private static native void multiplyToLenStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word xIn, int xLen, Word yIn, int yLen, Word zIn, int zLen); + + /** + * @see BigIntegerSubstitutions#mulAdd + */ + public static final ForeignCallDescriptor MUL_ADD = new ForeignCallDescriptor("mulAdd", int.class, Word.class, Word.class, int.class, int.class, int.class); + + public static int mulAddStub(Word inAddr, Word outAddr, int newOffset, int len, int k) { + return mulAddStub(HotSpotBackend.MUL_ADD, inAddr, outAddr, newOffset, len, k); + } + + @NodeIntrinsic(ForeignCallNode.class) + private static native int mulAddStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word inAddr, Word outAddr, int newOffset, int len, int k); + + /** + * @see BigIntegerSubstitutions#implMontgomeryMultiply + */ + public static final ForeignCallDescriptor MONTGOMERY_MULTIPLY = new ForeignCallDescriptor("implMontgomeryMultiply", void.class, Word.class, Word.class, Word.class, int.class, long.class, + Word.class); + + public static void implMontgomeryMultiply(Word aAddr, Word bAddr, Word nAddr, int len, long inv, Word productAddr) { + implMontgomeryMultiply(HotSpotBackend.MONTGOMERY_MULTIPLY, aAddr, bAddr, nAddr, len, inv, productAddr); + } + + @NodeIntrinsic(ForeignCallNode.class) + private static native void implMontgomeryMultiply(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word aAddr, Word bAddr, Word nAddr, int len, long inv, Word productAddr); + + /** + * @see BigIntegerSubstitutions#implMontgomerySquare + */ + public static final ForeignCallDescriptor MONTGOMERY_SQUARE = new ForeignCallDescriptor("implMontgomerySquare", void.class, Word.class, Word.class, int.class, long.class, Word.class); + + public static void implMontgomerySquare(Word aAddr, Word nAddr, int len, long inv, Word productAddr) { + implMontgomerySquare(HotSpotBackend.MONTGOMERY_SQUARE, aAddr, nAddr, len, inv, productAddr); + } + + @NodeIntrinsic(ForeignCallNode.class) + private static native void implMontgomerySquare(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word aAddr, Word nAddr, int len, long inv, Word productAddr); + + /** + * @see BigIntegerSubstitutions#implSquareToLen + */ + public static final ForeignCallDescriptor SQUARE_TO_LEN = new ForeignCallDescriptor("implSquareToLen", void.class, Word.class, int.class, Word.class, int.class); + + public static void implSquareToLen(Word xAddr, int len, Word zAddr, int zLen) { + implSquareToLen(SQUARE_TO_LEN, xAddr, len, zAddr, zLen); + } + + @NodeIntrinsic(ForeignCallNode.class) + private static native void implSquareToLen(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word xAddr, int len, Word zAddr, int zLen); + + /** + * @see SHASubstitutions#implCompress0 + */ + public static final ForeignCallDescriptor SHA_IMPL_COMPRESS = new ForeignCallDescriptor("shaImplCompress", void.class, Word.class, Object.class); + + public static void shaImplCompressStub(Word bufAddr, Object state) { + shaImplCompressStub(HotSpotBackend.SHA_IMPL_COMPRESS, bufAddr, state); + } + + @NodeIntrinsic(ForeignCallNode.class) + private static native void shaImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state); + + /** + * @see SHA2Substitutions#implCompress0 + */ + public static final ForeignCallDescriptor SHA2_IMPL_COMPRESS = new ForeignCallDescriptor("sha2ImplCompress", void.class, Word.class, Object.class); + + public static void sha2ImplCompressStub(Word bufAddr, Object state) { + sha2ImplCompressStub(HotSpotBackend.SHA2_IMPL_COMPRESS, bufAddr, state); + } + + @NodeIntrinsic(ForeignCallNode.class) + private static native void sha2ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state); + + /** + * @see SHA5Substitutions#implCompress0 + */ + public static final ForeignCallDescriptor SHA5_IMPL_COMPRESS = new ForeignCallDescriptor("sha5ImplCompress", void.class, Word.class, Object.class); + + public static void sha5ImplCompressStub(Word bufAddr, Object state) { + sha5ImplCompressStub(HotSpotBackend.SHA5_IMPL_COMPRESS, bufAddr, state); + } + + @NodeIntrinsic(ForeignCallNode.class) + private static native void sha5ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state); + + /** + * @see VMErrorNode + */ + public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class); + + /** + * New multi array stub call. + */ + public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, KlassPointer.class, int.class, Word.class); + + /** + * New array stub. + */ + public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, KlassPointer.class, int.class, boolean.class); + + /** + * New instance stub. + */ + public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, KlassPointer.class); + + /** + * @see ResolveConstantStubCall + */ + public static final ForeignCallDescriptor RESOLVE_STRING_BY_SYMBOL = new ForeignCallDescriptor("resolve_string_by_symbol", Object.class, Word.class, Word.class); + + /** + * @see ResolveConstantStubCall + */ + public static final ForeignCallDescriptor RESOLVE_KLASS_BY_SYMBOL = new ForeignCallDescriptor("resolve_klass_by_symbol", Word.class, Word.class, Word.class); + + /** + * @see ResolveConstantStubCall + */ + public static final ForeignCallDescriptor INITIALIZE_KLASS_BY_SYMBOL = new ForeignCallDescriptor("initialize_klass_by_symbol", Word.class, Word.class, Word.class); + + /** + * @see ResolveConstantStubCall + */ + public static final ForeignCallDescriptor RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS = new ForeignCallDescriptor("resolve_method_by_symbol_and_load_counters", Word.class, Word.class, Word.class, + Word.class); + + /** + * Tiered support. + */ + public static final ForeignCallDescriptor INVOCATION_EVENT = new ForeignCallDescriptor("invocation_event", void.class, Word.class); + public static final ForeignCallDescriptor BACKEDGE_EVENT = new ForeignCallDescriptor("backedge_event", void.class, Word.class, int.class, int.class); + + /** + * @see UncommonTrapCallNode + */ + public static final ForeignCallDescriptor UNCOMMON_TRAP = new ForeignCallDescriptor("uncommonTrap", Word.class, Word.class, int.class, int.class); + + public HotSpotBackend(HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { + super(providers); + this.runtime = runtime; + } + + public HotSpotGraalRuntimeProvider getRuntime() { + return runtime; + } + + /** + * Performs any remaining initialization that was deferred until the {@linkplain #getRuntime() + * runtime} object was initialized and this backend was registered with it. + * + * @param jvmciRuntime + */ + public void completeInitialization(HotSpotJVMCIRuntime jvmciRuntime) { + } + + /** + * Finds all the registers that are defined by some given LIR. + * + * @param lir the LIR to examine + * @return the registers that are defined by or used as temps for any instruction in {@code lir} + */ + protected final Set gatherDestroyedCallerRegisters(LIR lir) { + final Set destroyedRegisters = new HashSet<>(); + ValueConsumer defConsumer = new ValueConsumer() { + + @Override + public void visitValue(Value value, OperandMode mode, EnumSet flags) { + if (ValueUtil.isRegister(value)) { + final Register reg = ValueUtil.asRegister(value); + destroyedRegisters.add(reg); + } + } + }; + for (AbstractBlockBase block : lir.codeEmittingOrder()) { + if (block == null) { + continue; + } + for (LIRInstruction op : lir.getLIRforBlock(block)) { + if (op instanceof LabelOp) { + // Don't consider this as a definition + } else { + op.visitEachTemp(defConsumer); + op.visitEachOutput(defConsumer); + } + } + } + return translateToCallerRegisters(destroyedRegisters); + } + + /** + * Updates a given stub with respect to the registers it destroys. + *

    + * Any entry in {@code calleeSaveInfo} that {@linkplain SaveRegistersOp#supportsRemove() + * supports} pruning will have {@code destroyedRegisters} + * {@linkplain SaveRegistersOp#remove(Set) removed} as these registers are declared as + * temporaries in the stub's {@linkplain ForeignCallLinkage linkage} (and thus will be saved by + * the stub's caller). + * + * @param stub the stub to update + * @param destroyedRegisters the registers destroyed by the stub + * @param calleeSaveInfo a map from debug infos to the operations that provide their + * {@linkplain RegisterSaveLayout callee-save information} + * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a virtual + * slot to a frame slot index + */ + protected void updateStub(Stub stub, Set destroyedRegisters, Map calleeSaveInfo, FrameMap frameMap) { + stub.initDestroyedCallerRegisters(destroyedRegisters); + + for (Map.Entry e : calleeSaveInfo.entrySet()) { + SaveRegistersOp save = e.getValue(); + if (save.supportsRemove()) { + save.remove(destroyedRegisters); + } + DebugInfo info = e.getKey() == null ? null : e.getKey().debugInfo(); + if (info != null) { + info.setCalleeSaveInfo(save.getMap(frameMap)); + } + } + } + + @Override + public HotSpotProviders getProviders() { + return (HotSpotProviders) super.getProviders(); + } + + @Override + public SuitesProvider getSuites() { + return getProviders().getSuites(); + } + + protected void profileInstructions(LIR lir, CompilationResultBuilder crb) { + if (HotSpotBackend.Options.ASMInstructionProfiling.getValue() != null) { + HotSpotInstructionProfiling.countInstructions(lir, crb.asm); + } + } + + @Override + public CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compResult) { + HotSpotCompilationRequest compRequest = compilationRequest instanceof HotSpotCompilationRequest ? (HotSpotCompilationRequest) compilationRequest : null; + return HotSpotCompiledCodeBuilder.createCompiledCode(method, compRequest, compResult); + } + + @Override + public CompilationIdentifier getCompilationIdentifier(ResolvedJavaMethod resolvedJavaMethod) { + if (resolvedJavaMethod instanceof HotSpotResolvedJavaMethod) { + HotSpotCompilationRequest request = new HotSpotCompilationRequest((HotSpotResolvedJavaMethod) resolvedJavaMethod, JVMCICompiler.INVOCATION_ENTRY_BCI, 0L); + return new HotSpotCompilationIdentifier(request); + } + return super.getCompilationIdentifier(resolvedJavaMethod); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackendFactory.java 2016-12-07 13:50:04.064965950 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013, 2016, 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; + +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; + +public interface HotSpotBackendFactory { + + /** + * Gets the name of this backend factory. This should not include the {@link #getArchitecture() + * architecture}. The {@link CompilerConfigurationFactory} can select alternative backends based + * on this name. + */ + String getName(); + + /** + * Gets the class describing the architecture the backend created by this factory is associated + * with. + */ + Class getArchitecture(); + + HotSpotBackend createBackend(HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotBackend host); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompilationIdentifier.java 2016-12-07 13:50:04.329977598 -0800 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016, 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; + +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.common.CompilationRequestIdentifier; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.hotspot.HotSpotCompilationRequest; +import jdk.vm.ci.runtime.JVMCICompiler; + +/** + * {@link CompilationIdentifier} for a {@linkplain HotSpotCompilationRequest hotspot compilation + * request}. + */ +public class HotSpotCompilationIdentifier implements CompilationRequestIdentifier { + private final HotSpotCompilationRequest request; + + public HotSpotCompilationIdentifier(HotSpotCompilationRequest request) { + this.request = request; + } + + public boolean isOsrCompilation() { + return request.getEntryBCI() != JVMCICompiler.INVOCATION_ENTRY_BCI; + } + + @Override + public final String toString() { + return toString(Verbosity.DETAILED); + } + + @Override + public String toString(Verbosity verbosity) { + return buildString(new StringBuilder(), verbosity).toString(); + } + + protected StringBuilder buildString(StringBuilder sb, Verbosity verbosity) { + switch (verbosity) { + case ID: + buildID(sb); + break; + case NAME: + buildName(sb); + break; + case DETAILED: + buildID(sb); + sb.append('['); + buildName(sb); + if (isOsrCompilation()) { + sb.append("@"); + sb.append(request.getEntryBCI()); + } + sb.append(']'); + break; + default: + throw new GraalError("unknown verbosity: " + verbosity); + } + return sb; + } + + protected StringBuilder buildName(StringBuilder sb) { + return sb.append(request.getMethod().format("%H.%n(%p)")); + } + + protected StringBuilder buildID(StringBuilder sb) { + if (isOsrCompilation()) { + sb.append("HotSpotOSRCompilation-"); + } else { + sb.append("HotSpotCompilation-"); + } + return sb.append(request.getId()); + } + + @Override + public HotSpotCompilationRequest getRequest() { + return request; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java 2016-12-07 13:50:04.594989246 -0800 @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2012, 2016, 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; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import java.util.stream.Stream.Builder; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.code.CompilationResult.CodeAnnotation; +import org.graalvm.compiler.code.CompilationResult.CodeComment; +import org.graalvm.compiler.code.CompilationResult.JumpTable; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.code.DataSection; +import org.graalvm.compiler.code.SourceMapping; +import org.graalvm.compiler.graph.NodeSourcePosition; + +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.site.ConstantReference; +import jdk.vm.ci.code.site.DataPatch; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.code.site.InfopointReason; +import jdk.vm.ci.code.site.Mark; +import jdk.vm.ci.code.site.Site; +import jdk.vm.ci.hotspot.HotSpotCompilationRequest; +import jdk.vm.ci.hotspot.HotSpotCompiledCode; +import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; +import jdk.vm.ci.hotspot.HotSpotCompiledNmethod; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.Assumptions.Assumption; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class HotSpotCompiledCodeBuilder { + + public static HotSpotCompiledCode createCompiledCode(ResolvedJavaMethod method, HotSpotCompilationRequest compRequest, CompilationResult compResult) { + String name = compResult.getName(); + + byte[] targetCode = compResult.getTargetCode(); + int targetCodeSize = compResult.getTargetCodeSize(); + + Site[] sites = getSortedSites(compResult); + + Assumption[] assumptions = compResult.getAssumptions(); + + ResolvedJavaMethod[] methods = compResult.getMethods(); + + List annotations = compResult.getAnnotations(); + Comment[] comments = new Comment[annotations.size()]; + if (!annotations.isEmpty()) { + for (int i = 0; i < comments.length; i++) { + CodeAnnotation annotation = annotations.get(i); + String text; + if (annotation instanceof CodeComment) { + CodeComment codeComment = (CodeComment) annotation; + text = codeComment.value; + } else if (annotation instanceof JumpTable) { + JumpTable jumpTable = (JumpTable) annotation; + text = "JumpTable [" + jumpTable.low + " .. " + jumpTable.high + "]"; + } else { + text = annotation.toString(); + } + comments[i] = new Comment(annotation.position, text); + } + } + + DataSection data = compResult.getDataSection(); + byte[] dataSection = new byte[data.getSectionSize()]; + + ByteBuffer buffer = ByteBuffer.wrap(dataSection).order(ByteOrder.nativeOrder()); + Builder patchBuilder = Stream.builder(); + data.buildDataSection(buffer, vmConstant -> { + patchBuilder.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant))); + }); + + int dataSectionAlignment = data.getSectionAlignment(); + DataPatch[] dataSectionPatches = patchBuilder.build().toArray(len -> new DataPatch[len]); + + int totalFrameSize = compResult.getTotalFrameSize(); + StackSlot customStackArea = compResult.getCustomStackArea(); + boolean isImmutablePIC = compResult.isImmutablePIC(); + + if (method instanceof HotSpotResolvedJavaMethod) { + HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; + int entryBCI = compResult.getEntryBCI(); + boolean hasUnsafeAccess = compResult.hasUnsafeAccess(); + + int id; + long jvmciEnv; + if (compRequest != null) { + id = compRequest.getId(); + jvmciEnv = compRequest.getJvmciEnv(); + } else { + id = hsMethod.allocateCompileId(entryBCI); + jvmciEnv = 0L; + } + return new HotSpotCompiledNmethod(name, targetCode, targetCodeSize, sites, assumptions, methods, comments, dataSection, dataSectionAlignment, dataSectionPatches, isImmutablePIC, + totalFrameSize, customStackArea, hsMethod, entryBCI, id, jvmciEnv, hasUnsafeAccess); + } else { + return new HotSpotCompiledCode(name, targetCode, targetCodeSize, sites, assumptions, methods, comments, dataSection, dataSectionAlignment, dataSectionPatches, isImmutablePIC, + totalFrameSize, customStackArea); + } + } + + static class SiteComparator implements Comparator { + + /** + * Defines an order for sorting {@link Infopoint}s based on their + * {@linkplain Infopoint#reason reasons}. This is used to choose which infopoint to preserve + * when multiple infopoints collide on the same PC offset. A negative order value implies a + * non-optional infopoint (i.e., must be preserved). + */ + static final Map HOTSPOT_INFOPOINT_SORT_ORDER = new EnumMap<>(InfopointReason.class); + + static { + HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.SAFEPOINT, -4); + HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.CALL, -3); + HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.IMPLICIT_EXCEPTION, -2); + HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.METHOD_START, 2); + HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.METHOD_END, 3); + HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.BYTECODE_POSITION, 4); + } + + static int ord(Infopoint info) { + return HOTSPOT_INFOPOINT_SORT_ORDER.get(info.reason); + } + + static int checkCollision(Infopoint i1, Infopoint i2) { + int o1 = ord(i1); + int o2 = ord(i2); + if (o1 < 0 && o2 < 0) { + throw new GraalError("Non optional infopoints cannot collide: %s and %s", i1, i2); + } + return o1 - o2; + } + + /** + * Records whether any two {@link Infopoint}s had the same {@link Infopoint#pcOffset}. + */ + boolean sawCollidingInfopoints; + + @Override + public int compare(Site s1, Site s2) { + if (s1.pcOffset == s2.pcOffset) { + // Marks must come first since patching a call site + // may need to know the mark denoting the call type + // (see uses of CodeInstaller::_next_call_type). + boolean s1IsMark = s1 instanceof Mark; + boolean s2IsMark = s2 instanceof Mark; + if (s1IsMark != s2IsMark) { + return s1IsMark ? -1 : 1; + } + + // Infopoints must group together so put them after + // other Site types. + boolean s1IsInfopoint = s1 instanceof Infopoint; + boolean s2IsInfopoint = s2 instanceof Infopoint; + if (s1IsInfopoint != s2IsInfopoint) { + return s1IsInfopoint ? 1 : -1; + } + + if (s1IsInfopoint) { + sawCollidingInfopoints = true; + return checkCollision((Infopoint) s1, (Infopoint) s2); + } + } + return s1.pcOffset - s2.pcOffset; + } + } + + /** + * HotSpot expects sites to be presented in ascending order of PC (see + * {@code DebugInformationRecorder::add_new_pc_offset}). In addition, it expects + * {@link Infopoint} PCs to be unique. + */ + private static Site[] getSortedSites(CompilationResult target) { + List sites = new ArrayList<>( + target.getExceptionHandlers().size() + target.getInfopoints().size() + target.getDataPatches().size() + target.getMarks().size() + target.getSourceMappings().size()); + sites.addAll(target.getExceptionHandlers()); + sites.addAll(target.getInfopoints()); + sites.addAll(target.getDataPatches()); + sites.addAll(target.getMarks()); + + /* + * Translate the source mapping into appropriate info points. In HotSpot only one position + * can really be represented and recording the end PC seems to give the best results and + * corresponds with what C1 and C2 do. + */ + for (SourceMapping source : target.getSourceMappings()) { + sites.add(new Infopoint(source.getEndOffset(), new DebugInfo(source.getSourcePosition()), InfopointReason.BYTECODE_POSITION)); + assert verifySourcePositionReceivers(source.getSourcePosition()); + } + + SiteComparator c = new SiteComparator(); + Collections.sort(sites, c); + if (c.sawCollidingInfopoints) { + Infopoint lastInfopoint = null; + List copy = new ArrayList<>(sites.size()); + for (Site site : sites) { + if (site instanceof Infopoint) { + Infopoint info = (Infopoint) site; + if (lastInfopoint == null || lastInfopoint.pcOffset != info.pcOffset) { + lastInfopoint = info; + copy.add(info); + } else { + // Omit this colliding infopoint + assert lastInfopoint.reason.compareTo(info.reason) <= 0; + } + } else { + copy.add(site); + } + } + sites = copy; + } + return sites.toArray(new Site[sites.size()]); + } + + /** + * Verifies that the captured receiver type agrees with the declared type of the method. + */ + private static boolean verifySourcePositionReceivers(NodeSourcePosition start) { + NodeSourcePosition pos = start; + while (pos != null) { + if (pos.getReceiver() != null) { + assert ((HotSpotObjectConstant) pos.getReceiver()).asObject(pos.getMethod().getDeclaringClass()) != null; + } + pos = pos.getCaller(); + } + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java 2016-12-07 13:50:04.859000851 -0800 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2015, 2015, 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; + +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static jdk.vm.ci.code.ValueUtil.isRegister; + +import java.util.Arrays; +import java.util.HashMap; + +import org.graalvm.compiler.asm.Assembler; +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.debug.BenchmarkCounters; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstructionClass; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; + +public abstract class HotSpotCounterOp extends LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(HotSpotCounterOp.class); + + private final String[] names; + private final String[] groups; + protected final Register thread; + protected final GraalHotSpotVMConfig config; + @Alive({OperandFlag.CONST, OperandFlag.REG}) protected Value[] increments; + + public HotSpotCounterOp(LIRInstructionClass c, String name, String group, Value increment, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config) { + this(c, new String[]{name}, new String[]{group}, new Value[]{increment}, registers, config); + } + + public HotSpotCounterOp(LIRInstructionClass c, String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config) { + super(c); + + assert names.length == groups.length; + assert groups.length == increments.length; + + this.names = names; + this.groups = groups; + this.increments = increments; + this.thread = registers.getThreadRegister(); + this.config = config; + } + + protected static int getDisplacementForLongIndex(TargetDescription target, long index) { + long finalDisp = index * target.arch.getPlatformKind(JavaKind.Long).getSizeInBytes(); + if (!NumUtil.isInt(finalDisp)) { + throw GraalError.unimplemented("cannot deal with indices that big: " + index); + } + return (int) finalDisp; + } + + protected interface CounterProcedure { + /** + * Lambda interface for iterating over counters declared in this op. + * + * @param counterIndex Index in this CounterOp object. + * @param increment Value for increment + * @param displacement Displacement in bytes in the counter array + */ + void apply(int counterIndex, Value increment, int displacement); + } + + /** + * Calls the {@link CounterProcedure} for each counter in ascending order of their displacement + * in the counter array. + * + * @param proc The procedure to be called + * @param target Target architecture (used to calculate the array displacements) + */ + protected void forEachCounter(CounterProcedure proc, TargetDescription target) { + if (names.length == 1) { // fast path + int arrayIndex = getIndex(names[0], groups[0], increments[0]); + int displacement = getDisplacementForLongIndex(target, arrayIndex); + proc.apply(0, increments[0], displacement); + } else { // Slow path with sort by displacements ascending + int[] displacements = new int[names.length]; + HashMap offsetMap = new HashMap<>(names.length); + for (int i = 0; i < names.length; i++) { + int arrayIndex = getIndex(names[i], groups[i], increments[i]); + displacements[i] = getDisplacementForLongIndex(target, arrayIndex); + offsetMap.put(displacements[i], i); + } + Arrays.sort(displacements); + // Now apply in order + for (int offset : displacements) { + int idx = offsetMap.get(offset); + proc.apply(idx, increments[idx], displacements[idx]); + } + } + } + + protected int getIndex(String name, String group, Value increment) { + if (isJavaConstant(increment)) { + // get index for the counter + return BenchmarkCounters.getIndexConstantIncrement(name, group, config, asLong(asJavaConstant(increment))); + } + assert isRegister(increment) : "Unexpected Value: " + increment; + // get index for the counter + return BenchmarkCounters.getIndex(name, group, config); + } + + /** + * Patches the increment value in the instruction emitted by this instruction. Use only, if + * patching is needed after assembly. + * + * @param asm + * @param increment + */ + public void patchCounterIncrement(Assembler asm, int[] increment) { + throw GraalError.unimplemented(); + } + + private static long asLong(JavaConstant value) { + JavaKind kind = value.getJavaKind(); + switch (kind) { + case Byte: + case Short: + case Char: + case Int: + return value.asInt(); + case Long: + return value.asLong(); + default: + throw new IllegalArgumentException("not an integer kind: " + kind); + } + } + + protected static int asInt(JavaConstant value) { + long l = asLong(value); + if (!NumUtil.isInt(l)) { + throw GraalError.shouldNotReachHere("value does not fit into int: " + l); + } + return (int) l; + } + + public String[] getNames() { + return names; + } + + public String[] getGroups() { + return groups; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDataBuilder.java 2016-12-07 13:50:05.125012543 -0800 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, 2016, 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; + +import static jdk.vm.ci.hotspot.HotSpotCompressedNullConstant.COMPRESSED_NULL; + +import java.nio.ByteBuffer; + +import org.graalvm.compiler.code.DataSection.Data; +import org.graalvm.compiler.code.DataSection.Patches; +import org.graalvm.compiler.code.DataSection.SerializableData; +import org.graalvm.compiler.code.DataSection.ZeroData; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.asm.DataBuilder; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.SerializableConstant; +import jdk.vm.ci.meta.VMConstant; + +public class HotSpotDataBuilder extends DataBuilder { + + private final TargetDescription target; + + public HotSpotDataBuilder(TargetDescription target) { + this.target = target; + } + + @Override + public boolean needDetailedPatchingInformation() { + /* The HotSpot VM finds operands that need patching by decoding the instruction. */ + return false; + } + + @Override + public Data createDataItem(Constant constant) { + int size; + if (constant instanceof VMConstant) { + VMConstant vmConstant = (VMConstant) constant; + boolean compressed; + if (constant instanceof HotSpotConstant) { + HotSpotConstant c = (HotSpotConstant) vmConstant; + compressed = c.isCompressed(); + } else { + throw new GraalError(String.valueOf(constant)); + } + + size = compressed ? 4 : target.wordSize; + if (size == 4) { + return new Data(size, size) { + + @Override + protected void emit(ByteBuffer buffer, Patches patches) { + patches.registerPatch(vmConstant); + buffer.putInt(0xDEADDEAD); + } + }; + } else { + return new Data(size, size) { + + @Override + protected void emit(ByteBuffer buffer, Patches patches) { + patches.registerPatch(vmConstant); + buffer.putLong(0xDEADDEADDEADDEADL); + } + }; + } + } else if (JavaConstant.isNull(constant)) { + boolean compressed = COMPRESSED_NULL.equals(constant); + size = compressed ? 4 : target.wordSize; + return ZeroData.create(size, size); + } else if (constant instanceof SerializableConstant) { + SerializableConstant s = (SerializableConstant) constant; + return new SerializableData(s); + } else { + throw new GraalError(String.valueOf(constant)); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java 2016-12-07 13:50:05.393024324 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013, 2015, 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; + +import static jdk.vm.ci.code.BytecodeFrame.isPlaceholderBci; + +import org.graalvm.compiler.core.gen.DebugInfoBuilder; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.NodeValueMap; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.StackLockValue; +import jdk.vm.ci.code.VirtualObject; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.meta.JavaValue; + +/** + * Extends {@link DebugInfoBuilder} to allocate the extra debug information required for locks. + */ +public class HotSpotDebugInfoBuilder extends DebugInfoBuilder { + + private final HotSpotLockStack lockStack; + + private int maxInterpreterFrameSize; + + private HotSpotCodeCacheProvider codeCacheProvider; + + public HotSpotDebugInfoBuilder(NodeValueMap nodeValueMap, HotSpotLockStack lockStack, HotSpotLIRGenerator gen) { + super(nodeValueMap); + this.lockStack = lockStack; + this.codeCacheProvider = gen.getProviders().getCodeCache(); + } + + public HotSpotLockStack lockStack() { + return lockStack; + } + + public int maxInterpreterFrameSize() { + return maxInterpreterFrameSize; + } + + @Override + protected JavaValue computeLockValue(FrameState state, int lockIndex) { + int lockDepth = lockIndex; + if (state.outerFrameState() != null) { + lockDepth += state.outerFrameState().nestedLockDepth(); + } + VirtualStackSlot slot = lockStack.makeLockSlot(lockDepth); + ValueNode lock = state.lockAt(lockIndex); + JavaValue object = toJavaValue(lock); + boolean eliminated = object instanceof VirtualObject || state.monitorIdAt(lockIndex) == null; + assert state.monitorIdAt(lockIndex) == null || state.monitorIdAt(lockIndex).getLockDepth() == lockDepth; + return new StackLockValue(object, slot, eliminated); + } + + @Override + protected BytecodeFrame computeFrameForState(FrameState state) { + if (isPlaceholderBci(state.bci) && state.bci != BytecodeFrame.BEFORE_BCI) { + // This is really a hard error since an incorrect state could crash hotspot + throw GraalError.shouldNotReachHere("Invalid state " + BytecodeFrame.getPlaceholderBciName(state.bci) + " " + state); + } + BytecodeFrame result = super.computeFrameForState(state); + maxInterpreterFrameSize = Math.max(maxInterpreterFrameSize, codeCacheProvider.interpreterFrameSize(result)); + return result; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkage.java 2016-12-07 13:50:05.657035928 -0800 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2012, 2016, 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; + +import jdk.vm.ci.meta.InvokeTarget; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.target.Backend; +import org.graalvm.compiler.hotspot.stubs.Stub; + +/** + * The details required to link a HotSpot runtime or stub call. + */ +public interface HotSpotForeignCallLinkage extends ForeignCallLinkage, InvokeTarget { + + /** + * Constants for specifying whether a foreign call destroys or preserves registers. A foreign + * call will always destroy {@link HotSpotForeignCallLinkage#getOutgoingCallingConvention() its} + * {@linkplain ForeignCallLinkage#getTemporaries() temporary} registers. + */ + enum RegisterEffect { + DESTROYS_REGISTERS, + PRESERVES_REGISTERS + } + + /** + * Constants for specifying whether a call is a leaf or not and whether a + * {@code JavaFrameAnchor} prologue and epilogue is required around the call. A leaf function + * does not lock, GC or throw exceptions. + */ + enum Transition { + /** + * A call to a leaf function that is guaranteed to not use floating point registers and will + * never have its caller stack inspected by the VM. That is, {@code JavaFrameAnchor} + * management around the call can be omitted. + */ + LEAF_NOFP, + + /** + * A call to a leaf function that might use floating point registers but will never have its + * caller stack inspected. That is, {@code JavaFrameAnchor} management around the call can + * be omitted. + */ + LEAF, + + /** + * A call to a leaf function that might use floating point registers and may have its caller + * stack inspected. That is, {@code JavaFrameAnchor} management code around the call is + * required. + */ + STACK_INSPECTABLE_LEAF, + + /** + * A function that may lock, GC or raise an exception and thus requires debug info to be + * associated with a call site to the function. The execution stack may be inspected while + * in the called function. That is, {@code JavaFrameAnchor} management code around the call + * is required. + */ + SAFEPOINT, + } + + /** + * Sentinel marker for a computed jump address. + */ + long JUMP_ADDRESS = 0xDEADDEADBEEFBEEFL; + + boolean isReexecutable(); + + LocationIdentity[] getKilledLocations(); + + void setCompiledStub(Stub stub); + + /** + * Determines if this is a call to a compiled {@linkplain Stub stub}. + */ + boolean isCompiledStub(); + + void finalizeAddress(Backend backend); + + long getAddress(); + + /** + * Determines if the runtime function or stub might use floating point registers. If the answer + * is no, then no FPU state management prologue or epilogue needs to be emitted around the call. + */ + boolean mayContainFP(); + + /** + * Determines if a {@code JavaFrameAnchor} needs to be set up and torn down around this call. + */ + boolean needsJavaFrameAnchor(); + + /** + * Gets the VM symbol associated with the target {@linkplain #getAddress() address} of the call. + */ + String getSymbol(); + + /** + * Identifies foreign calls which are guaranteed to include a safepoint check. + */ + boolean isGuaranteedSafepoint(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java 2016-12-07 13:50:05.922047576 -0800 @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2012, 2016, 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; + +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; + +import java.util.Set; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.target.Backend; +import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.CallingConvention.Type; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.ValueKindFactory; +import jdk.vm.ci.hotspot.HotSpotCallingConventionType; +import jdk.vm.ci.hotspot.HotSpotForeignCallTarget; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Value; + +/** + * The details required to link a HotSpot runtime or stub call. + */ +public class HotSpotForeignCallLinkageImpl extends HotSpotForeignCallTarget implements HotSpotForeignCallLinkage { + + /** + * The descriptor of the call. + */ + protected final ForeignCallDescriptor descriptor; + + /** + * Non-null (eventually) iff this is a call to a compiled {@linkplain Stub stub}. + */ + private Stub stub; + + /** + * The calling convention for this call. + */ + private final CallingConvention outgoingCallingConvention; + + /** + * The calling convention for incoming arguments to the stub, iff this call uses a compiled + * {@linkplain Stub stub}. + */ + private final CallingConvention incomingCallingConvention; + + private final RegisterEffect effect; + + private final Transition transition; + + /** + * The registers and stack slots defined/killed by the call. + */ + private Value[] temporaries = AllocatableValue.NONE; + + /** + * The memory locations killed by the call. + */ + private final LocationIdentity[] killedLocations; + + private final boolean reexecutable; + + /** + * Creates a {@link HotSpotForeignCallLinkage}. + * + * @param descriptor the descriptor of the call + * @param address the address of the code to call + * @param effect specifies if the call destroys or preserves all registers (apart from + * temporaries which are always destroyed) + * @param outgoingCcType outgoing (caller) calling convention type + * @param incomingCcType incoming (callee) calling convention type (can be null) + * @param transition specifies if this is a {@linkplain #needsDebugInfo() leaf} call + * @param reexecutable specifies if the call can be re-executed without (meaningful) side + * effects. Deoptimization will not return to a point before a call that cannot be + * re-executed. + * @param killedLocations the memory locations killed by the call + */ + public static HotSpotForeignCallLinkage create(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, WordTypes wordTypes, HotSpotForeignCallsProvider foreignCalls, + ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Type outgoingCcType, Type incomingCcType, Transition transition, boolean reexecutable, + LocationIdentity... killedLocations) { + CallingConvention outgoingCc = createCallingConvention(metaAccess, codeCache, wordTypes, foreignCalls, descriptor, outgoingCcType); + CallingConvention incomingCc = incomingCcType == null ? null : createCallingConvention(metaAccess, codeCache, wordTypes, foreignCalls, descriptor, incomingCcType); + HotSpotForeignCallLinkageImpl linkage = new HotSpotForeignCallLinkageImpl(descriptor, address, effect, transition, outgoingCc, incomingCc, reexecutable, killedLocations); + if (outgoingCcType == HotSpotCallingConventionType.NativeCall) { + linkage.temporaries = foreignCalls.getNativeABICallerSaveRegisters(); + } + return linkage; + } + + /** + * Gets a calling convention for a given descriptor and call type. + */ + public static CallingConvention createCallingConvention(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, WordTypes wordTypes, ValueKindFactory valueKindFactory, + ForeignCallDescriptor descriptor, Type ccType) { + assert ccType != null; + Class[] argumentTypes = descriptor.getArgumentTypes(); + JavaType[] parameterTypes = new JavaType[argumentTypes.length]; + for (int i = 0; i < parameterTypes.length; ++i) { + parameterTypes[i] = asJavaType(argumentTypes[i], metaAccess, wordTypes); + } + JavaType returnType = asJavaType(descriptor.getResultType(), metaAccess, wordTypes); + RegisterConfig regConfig = codeCache.getRegisterConfig(); + return regConfig.getCallingConvention(ccType, returnType, parameterTypes, valueKindFactory); + } + + private static JavaType asJavaType(Class type, MetaAccessProvider metaAccess, WordTypes wordTypes) { + ResolvedJavaType javaType = metaAccess.lookupJavaType(type); + if (wordTypes.isWord(javaType)) { + javaType = metaAccess.lookupJavaType(wordTypes.getWordKind().toJavaClass()); + } + return javaType; + } + + public HotSpotForeignCallLinkageImpl(ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Transition transition, CallingConvention outgoingCallingConvention, + CallingConvention incomingCallingConvention, boolean reexecutable, LocationIdentity... killedLocations) { + super(address); + this.descriptor = descriptor; + this.address = address; + this.effect = effect; + this.transition = transition; + assert outgoingCallingConvention != null : "only incomingCallingConvention can be null"; + this.outgoingCallingConvention = outgoingCallingConvention; + this.incomingCallingConvention = incomingCallingConvention != null ? incomingCallingConvention : outgoingCallingConvention; + this.reexecutable = reexecutable; + this.killedLocations = killedLocations; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(stub == null ? descriptor.toString() : stub.toString()); + sb.append("@0x").append(Long.toHexString(address)).append(':').append(outgoingCallingConvention).append(":").append(incomingCallingConvention); + if (temporaries != null && temporaries.length != 0) { + sb.append("; temps="); + String sep = ""; + for (Value op : temporaries) { + sb.append(sep).append(op); + sep = ","; + } + } + return sb.toString(); + } + + @Override + public boolean isReexecutable() { + return reexecutable; + } + + @Override + public boolean isGuaranteedSafepoint() { + return transition == Transition.SAFEPOINT; + } + + @Override + public LocationIdentity[] getKilledLocations() { + return killedLocations; + } + + @Override + public CallingConvention getOutgoingCallingConvention() { + return outgoingCallingConvention; + } + + @Override + public CallingConvention getIncomingCallingConvention() { + return incomingCallingConvention; + } + + @Override + public Value[] getTemporaries() { + if (temporaries.length == 0) { + return temporaries; + } + return temporaries.clone(); + } + + @Override + public long getMaxCallTargetOffset() { + return runtime().getHostJVMCIBackend().getCodeCache().getMaxCallTargetOffset(address); + } + + @Override + public ForeignCallDescriptor getDescriptor() { + return descriptor; + } + + @Override + public void setCompiledStub(Stub stub) { + assert address == 0L : "cannot set stub for linkage that already has an address: " + this; + this.stub = stub; + } + + /** + * Determines if this is a call to a compiled {@linkplain Stub stub}. + */ + @Override + public boolean isCompiledStub() { + return address == 0L || stub != null; + } + + @Override + public void finalizeAddress(Backend backend) { + if (address == 0) { + assert stub != null : "linkage without an address must be a stub - forgot to register a Stub associated with " + descriptor + "?"; + InstalledCode code = stub.getCode(backend); + + Set destroyedRegisters = stub.getDestroyedCallerRegisters(); + if (!destroyedRegisters.isEmpty()) { + AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()]; + int i = 0; + for (Register reg : destroyedRegisters) { + temporaryLocations[i++] = reg.asValue(); + } + temporaries = temporaryLocations; + } + address = code.getStart(); + } + } + + @Override + public long getAddress() { + assert address != 0L : "address not yet finalized: " + this; + return address; + } + + @Override + public boolean destroysRegisters() { + return effect == DESTROYS_REGISTERS; + } + + @Override + public boolean needsDebugInfo() { + return transition == Transition.SAFEPOINT; + } + + @Override + public boolean mayContainFP() { + return transition != Transition.LEAF_NOFP; + } + + @Override + public boolean needsJavaFrameAnchor() { + if (transition == Transition.SAFEPOINT || transition == Transition.STACK_INSPECTABLE_LEAF) { + if (stub != null) { + // The stub will do the JavaFrameAnchor management + // around the runtime call(s) it makes + return false; + } else { + return true; + } + } + return false; + } + + @Override + public String getSymbol() { + return stub == null ? null : stub.toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java 2016-12-07 13:50:06.187059224 -0800 @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2015, 2016, 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; + +import static org.graalvm.compiler.core.common.GraalOptions.OptAssumptions; +import static org.graalvm.compiler.nodes.StructuredGraph.NO_PROFILING_INFO; +import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Formattable; +import java.util.Formatter; + +import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.GraalCompiler; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.common.util.CompilationAlarm; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugConfigScope; +import org.graalvm.compiler.debug.DebugEnvironment; +import org.graalvm.compiler.debug.GraalDebugConfig; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.debug.TopLevelDebugConfig; +import org.graalvm.compiler.debug.internal.DebugScope; +import org.graalvm.compiler.debug.internal.method.MethodMetricsRootScopeInfo; +import org.graalvm.compiler.hotspot.CompilationCounters.Options; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.phases.OnStackReplacementPhase; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; +import org.graalvm.compiler.nodes.spi.Replacements; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.Suites; + +import jdk.vm.ci.code.CompilationRequest; +import jdk.vm.ci.code.CompilationRequestResult; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotCompilationRequest; +import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.meta.DefaultProfilingInfo; +import jdk.vm.ci.meta.JavaMethod; +import jdk.vm.ci.meta.ProfilingInfo; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.SpeculationLog; +import jdk.vm.ci.meta.TriState; +import jdk.vm.ci.runtime.JVMCICompiler; + +public class HotSpotGraalCompiler implements GraalJVMCICompiler { + + private final HotSpotJVMCIRuntimeProvider jvmciRuntime; + private final HotSpotGraalRuntimeProvider graalRuntime; + private final CompilationCounters compilationCounters; + private final BootstrapWatchDog bootstrapWatchDog; + + HotSpotGraalCompiler(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider graalRuntime) { + this.jvmciRuntime = jvmciRuntime; + this.graalRuntime = graalRuntime; + // It is sufficient to have one compilation counter object per Graal compiler object. + this.compilationCounters = Options.CompilationCountLimit.getValue() > 0 ? new CompilationCounters() : null; + this.bootstrapWatchDog = graalRuntime.isBootstrapping() && !GraalDebugConfig.Options.BootstrapInitializeOnly.getValue() ? BootstrapWatchDog.maybeCreate(graalRuntime) : null; + } + + @Override + public HotSpotGraalRuntimeProvider getGraalRuntime() { + return graalRuntime; + } + + @Override + @SuppressWarnings("try") + public CompilationRequestResult compileMethod(CompilationRequest request) { + if (graalRuntime.isBootstrapping() && GraalDebugConfig.Options.BootstrapInitializeOnly.getValue()) { + return HotSpotCompilationRequestResult.failure(String.format("Skip compilation because %s is enabled", GraalDebugConfig.Options.BootstrapInitializeOnly.getName()), true); + } + if (bootstrapWatchDog != null && graalRuntime.isBootstrapping()) { + if (bootstrapWatchDog.hitCriticalCompilationRateOrTimeout()) { + // Drain the compilation queue to expedite completion of the bootstrap + return HotSpotCompilationRequestResult.failure("hit critical bootstrap compilation rate or timeout", true); + } + } + ResolvedJavaMethod method = request.getMethod(); + HotSpotCompilationRequest hsRequest = (HotSpotCompilationRequest) request; + try (CompilationWatchDog w1 = CompilationWatchDog.watch(method, hsRequest.getId()); + BootstrapWatchDog.Watch w2 = bootstrapWatchDog == null ? null : bootstrapWatchDog.watch(request); + CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod();) { + if (compilationCounters != null) { + compilationCounters.countCompilation(method); + } + // Ensure a debug configuration for this thread is initialized + if (Debug.isEnabled() && DebugScope.getConfig() == null) { + DebugEnvironment.initialize(TTY.out, graalRuntime.getHostProviders().getSnippetReflection()); + } + CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, true); + CompilationRequestResult r = null; + try (DebugConfigScope dcs = Debug.setConfig(new TopLevelDebugConfig()); + Debug.Scope s = Debug.methodMetricsScope("HotSpotGraalCompiler", MethodMetricsRootScopeInfo.create(method), true, method)) { + r = task.runCompilation(); + } + assert r != null; + return r; + } + } + + public void compileTheWorld() throws Throwable { + HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmciRuntime.getHostJVMCIBackend().getCodeCache(); + int iterations = CompileTheWorldOptions.CompileTheWorldIterations.getValue(); + for (int i = 0; i < iterations; i++) { + codeCache.resetCompilationStatistics(); + TTY.println("CompileTheWorld : iteration " + i); + CompileTheWorld ctw = new CompileTheWorld(jvmciRuntime, this); + ctw.compile(); + } + System.exit(0); + } + + public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId) { + HotSpotBackend backend = graalRuntime.getHostBackend(); + HotSpotProviders providers = backend.getProviders(); + final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI; + StructuredGraph graph = method.isNative() || isOSR ? null : getIntrinsicGraph(method, providers, compilationId); + + if (graph == null) { + SpeculationLog speculationLog = method.getSpeculationLog(); + if (speculationLog != null) { + speculationLog.collectFailedSpeculations(); + } + graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue()), speculationLog, useProfilingInfo, compilationId); + } + + Suites suites = getSuites(providers); + LIRSuites lirSuites = getLIRSuites(providers); + ProfilingInfo profilingInfo = useProfilingInfo ? method.getProfilingInfo(!isOSR, isOSR) : DefaultProfilingInfo.get(TriState.FALSE); + OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo); + if (isOSR) { + // In OSR compiles, we cannot rely on never executed code profiles, because + // all code after the OSR loop is never executed. + optimisticOpts.remove(Optimization.RemoveNeverExecutedCode); + } + CompilationResult result = new CompilationResult(); + result.setEntryBCI(entryBCI); + boolean shouldDebugNonSafepoints = providers.getCodeCache().shouldDebugNonSafepoints(); + PhaseSuite graphBuilderSuite = configGraphBuilderSuite(providers.getSuites().getDefaultGraphBuilderSuite(), shouldDebugNonSafepoints, isOSR); + GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, CompilationResultBuilderFactory.Default); + + if (!isOSR && useProfilingInfo) { + ProfilingInfo profile = profilingInfo; + profile.setCompilerIRSize(StructuredGraph.class, graph.getNodeCount()); + } + + return result; + } + + /** + * Gets a graph produced from the intrinsic for a given method that can be compiled and + * installed for the method. + * + * @param method + * @param compilationId + * @return an intrinsic graph that can be compiled and installed for {@code method} or null + */ + @SuppressWarnings("try") + public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, HotSpotProviders providers, CompilationIdentifier compilationId) { + Replacements replacements = providers.getReplacements(); + ResolvedJavaMethod substMethod = replacements.getSubstitutionMethod(method); + if (substMethod != null) { + assert !substMethod.equals(method); + StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES, NO_PROFILING_INFO, compilationId); + try (Debug.Scope scope = Debug.scope("GetIntrinsicGraph", graph)) { + Plugins plugins = new Plugins(providers.getGraphBuilderPlugins()); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); + IntrinsicContext initialReplacementContext = new IntrinsicContext(method, substMethod, replacements.getReplacementBytecodeProvider(), ROOT_COMPILATION); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config, + OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); + assert !graph.isFrozen(); + return graph; + } catch (Throwable e) { + Debug.handle(e); + } + } + return null; + } + + protected OptimisticOptimizations getOptimisticOpts(ProfilingInfo profilingInfo) { + return new OptimisticOptimizations(profilingInfo); + } + + protected Suites getSuites(HotSpotProviders providers) { + return providers.getSuites().getDefaultSuites(); + } + + protected LIRSuites getLIRSuites(HotSpotProviders providers) { + return providers.getSuites().getDefaultLIRSuites(); + } + + /** + * Reconfigures a given graph builder suite (GBS) if one of the given GBS parameter values is + * not the default. + * + * @param suite the graph builder suite + * @param shouldDebugNonSafepoints specifies if extra debug info should be generated (default is + * false) + * @param isOSR specifies if extra OSR-specific post-processing is required (default is false) + * @return a new suite derived from {@code suite} if any of the GBS parameters did not have a + * default value otherwise {@code suite} + */ + protected PhaseSuite configGraphBuilderSuite(PhaseSuite suite, boolean shouldDebugNonSafepoints, boolean isOSR) { + if (shouldDebugNonSafepoints || isOSR) { + PhaseSuite newGbs = suite.copy(); + + if (shouldDebugNonSafepoints) { + GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous(); + GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig(); + graphBuilderConfig = graphBuilderConfig.withNodeSourcePosition(true); + GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig); + newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase); + } + if (isOSR) { + newGbs.appendPhase(new OnStackReplacementPhase()); + } + return newGbs; + } + return suite; + } + + /** + * Converts {@code method} to a String with {@link JavaMethod#format(String)} and the format + * string {@code "%H.%n(%p)"}. + */ + static String str(JavaMethod method) { + return method.format("%H.%n(%p)"); + } + + /** + * Wraps {@code obj} in a {@link Formatter} that standardizes formatting for certain objects. + */ + static Formattable fmt(Object obj) { + return new Formattable() { + @Override + public void formatTo(Formatter buf, int flags, int width, int precision) { + if (obj instanceof Throwable) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ((Throwable) obj).printStackTrace(new PrintStream(baos)); + buf.format("%s", baos.toString()); + } else if (obj instanceof StackTraceElement[]) { + for (StackTraceElement e : (StackTraceElement[]) obj) { + buf.format("\t%s%n", e); + } + } else if (obj instanceof JavaMethod) { + buf.format("%s", str((JavaMethod) obj)); + } else { + buf.format("%s", obj); + } + } + }; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java 2016-12-07 13:50:06.453070917 -0800 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2015, 2016, 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; + +import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier; +import static org.graalvm.compiler.options.OptionValue.PROFILE_OPTIONVALUE_PROPERTY_NAME; +import static jdk.vm.ci.common.InitTimer.timer; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.ServiceLoader; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.MethodFilter; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionDescriptors; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionsParser; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; + +import jdk.vm.ci.common.InitTimer; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotSignature; +import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory; +import jdk.vm.ci.runtime.JVMCIRuntime; + +public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFactory { + + /** + * The name of the system property specifying a file containing extra Graal option settings. + */ + private static final String GRAAL_OPTIONS_FILE_PROPERTY_NAME = "graal.options.file"; + + /** + * The name of the system property specifying the Graal version. + */ + private static final String GRAAL_VERSION_PROPERTY_NAME = "graal.version"; + + /** + * The prefix for system properties that correspond to {@link Option} annotated fields. A field + * named {@code MyOption} will have its value set from a system property with the name + * {@code GRAAL_OPTION_PROPERTY_PREFIX + "MyOption"}. + */ + public static final String GRAAL_OPTION_PROPERTY_PREFIX = "graal."; + + private static MethodFilter[] graalCompileOnlyFilter; + + /** + * Gets the system property assignment that would set the current value for a given option. + */ + public static String asSystemPropertySetting(OptionValue value) { + return GRAAL_OPTION_PROPERTY_PREFIX + value.getName() + "=" + value.getValue(); + } + + private final HotSpotGraalJVMCIServiceLocator locator; + + HotSpotGraalCompilerFactory(HotSpotGraalJVMCIServiceLocator locator) { + this.locator = locator; + } + + @Override + public String getCompilerName() { + return "graal"; + } + + @Override + public void onSelection() { + initializeOptions(); + JVMCIVersionCheck.check(false); + } + + @Override + public void printProperties(PrintStream out) { + ServiceLoader loader = ServiceLoader.load(OptionDescriptors.class, OptionDescriptors.class.getClassLoader()); + out.println("[Graal properties]"); + OptionsParser.printFlags(loader, out, allOptionsSettings.keySet(), GRAAL_OPTION_PROPERTY_PREFIX); + } + + static class Options { + + // @formatter:off + @Option(help = "In tiered mode compile Graal and JVMCI using optimized first tier code.", type = OptionType.Expert) + public static final OptionValue CompileGraalWithC1Only = new OptionValue<>(true); + + @Option(help = "Hook into VM-level mechanism for denoting compilations to be performed in first tier.", type = OptionType.Expert) + public static final OptionValue UseTrivialPrefixes = new OptionValue<>(false); + + @Option(help = "A method filter selecting what should be compiled by Graal. All other requests will be reduced to CompilationLevel.Simple.", type = OptionType.Expert) + public static final OptionValue GraalCompileOnly = new OptionValue<>(null); + // @formatter:on + + } + + private static Map allOptionsSettings; + + /** + * Initializes options if they haven't already been initialized. + * + * Initialization means first parsing the options in the file denoted by the + * {@code VM.getSavedProperty(String) saved} system property named + * {@value HotSpotGraalCompilerFactory#GRAAL_OPTIONS_FILE_PROPERTY_NAME} if the file exists + * followed by parsing the options encoded in saved system properties whose names start with + * {@value #GRAAL_OPTION_PROPERTY_PREFIX}. Key/value pairs are parsed from the aforementioned + * file with {@link Properties#load(java.io.Reader)}. + */ + @SuppressWarnings("try") + private static synchronized void initializeOptions() { + if (allOptionsSettings == null) { + try (InitTimer t = timer("InitializeOptions")) { + ServiceLoader loader = ServiceLoader.load(OptionDescriptors.class, OptionDescriptors.class.getClassLoader()); + Properties savedProps = getSavedProperties(Java8OrEarlier); + String optionsFile = savedProps.getProperty(GRAAL_OPTIONS_FILE_PROPERTY_NAME); + + if (optionsFile != null) { + File graalOptions = new File(optionsFile); + if (graalOptions.exists()) { + try (FileReader fr = new FileReader(graalOptions)) { + Properties props = new Properties(); + props.load(fr); + Map optionSettings = new HashMap<>(); + for (Map.Entry e : props.entrySet()) { + optionSettings.put((String) e.getKey(), (String) e.getValue()); + } + try { + OptionsParser.parseOptions(optionSettings, null, loader); + if (allOptionsSettings == null) { + allOptionsSettings = new HashMap<>(optionSettings); + } else { + allOptionsSettings.putAll(optionSettings); + } + } catch (Throwable e) { + throw new InternalError("Error parsing an option from " + graalOptions, e); + } + } catch (IOException e) { + throw new InternalError("Error reading " + graalOptions, e); + } + } + } + + Map optionSettings = new HashMap<>(); + for (Map.Entry e : savedProps.entrySet()) { + String name = (String) e.getKey(); + if (name.startsWith(GRAAL_OPTION_PROPERTY_PREFIX)) { + if (name.equals("graal.PrintFlags") || name.equals("graal.ShowFlags")) { + System.err.println("The " + name + " option has been removed and will be ignored. Use -XX:+JVMCIPrintProperties instead."); + } else if (name.equals(GRAAL_OPTIONS_FILE_PROPERTY_NAME) || name.equals(GRAAL_VERSION_PROPERTY_NAME) || name.equals(PROFILE_OPTIONVALUE_PROPERTY_NAME)) { + // Ignore well known properties that do not denote an option + } else { + String value = (String) e.getValue(); + optionSettings.put(name.substring(GRAAL_OPTION_PROPERTY_PREFIX.length()), value); + } + } + } + + OptionsParser.parseOptions(optionSettings, null, loader); + + if (allOptionsSettings == null) { + allOptionsSettings = optionSettings; + } else { + allOptionsSettings.putAll(optionSettings); + } + + if (Options.GraalCompileOnly.getValue() != null) { + graalCompileOnlyFilter = MethodFilter.parse(Options.GraalCompileOnly.getValue()); + if (graalCompileOnlyFilter.length == 0) { + graalCompileOnlyFilter = null; + } + } + if (graalCompileOnlyFilter != null || !Options.UseTrivialPrefixes.getValue()) { + /* + * Exercise this code path early to encourage loading now. This doesn't solve + * problem of deadlock during class loading but seems to eliminate it in + * practice. + */ + adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.FullOptimization); + adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.Simple); + } + } + } + } + + private static Properties getSavedProperties(boolean jdk8OrEarlier) { + try { + String vmClassName = jdk8OrEarlier ? "sun.misc.VM" : "jdk.internal.misc.VM"; + Class vmClass = Class.forName(vmClassName); + Field savedPropsField = vmClass.getDeclaredField("savedProps"); + savedPropsField.setAccessible(true); + return (Properties) savedPropsField.get(null); + } catch (Exception e) { + throw new GraalError(e); + } + } + + @Override + public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) { + HotSpotGraalCompiler compiler = createCompiler(runtime, CompilerConfigurationFactory.selectFactory(null)); + // Only the HotSpotGraalRuntime associated with the compiler created via + // jdk.vm.ci.runtime.JVMCIRuntime.getCompiler() is registered for receiving + // VM events. + locator.onCompilerCreation(compiler); + return compiler; + } + + /** + * Creates a new {@link HotSpotGraalRuntime} object and a new {@link HotSpotGraalCompiler} and + * returns the latter. + * + * @param runtime the JVMCI runtime on which the {@link HotSpotGraalRuntime} is built + * @param compilerConfigurationFactory factory for the {@link CompilerConfiguration} + */ + @SuppressWarnings("try") + public static HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime, CompilerConfigurationFactory compilerConfigurationFactory) { + HotSpotJVMCIRuntime jvmciRuntime = (HotSpotJVMCIRuntime) runtime; + try (InitTimer t = timer("HotSpotGraalRuntime.")) { + HotSpotGraalRuntime graalRuntime = new HotSpotGraalRuntime(jvmciRuntime, compilerConfigurationFactory); + return new HotSpotGraalCompiler(jvmciRuntime, graalRuntime); + } + } + + @Override + public String[] getTrivialPrefixes() { + if (Options.UseTrivialPrefixes.getValue()) { + if (Options.CompileGraalWithC1Only.getValue()) { + return new String[]{"jdk/vm/ci", "org/graalvm/compiler", "com/oracle/graal"}; + } + } + return null; + } + + @Override + public CompilationLevelAdjustment getCompilationLevelAdjustment() { + if (graalCompileOnlyFilter != null) { + return CompilationLevelAdjustment.ByFullSignature; + } + if (!Options.UseTrivialPrefixes.getValue()) { + if (Options.CompileGraalWithC1Only.getValue()) { + // We only decide using the class declaring the method + // so no need to have the method name and signature + // symbols converted to a String. + return CompilationLevelAdjustment.ByHolder; + } + } + return CompilationLevelAdjustment.None; + } + + @Override + public CompilationLevel adjustCompilationLevel(Class declaringClass, String name, String signature, boolean isOsr, CompilationLevel level) { + return adjustCompilationLevelInternal(declaringClass, name, signature, level); + } + + /* + * This method is static so it can be exercised during initialization. + */ + private static CompilationLevel adjustCompilationLevelInternal(Class declaringClass, String name, String signature, CompilationLevel level) { + if (graalCompileOnlyFilter != null) { + if (level == CompilationLevel.FullOptimization) { + String declaringClassName = declaringClass.getName(); + HotSpotSignature sig = null; + for (MethodFilter filter : graalCompileOnlyFilter) { + if (filter.hasSignature() && sig == null) { + sig = new HotSpotSignature(HotSpotJVMCIRuntime.runtime(), signature); + } + if (filter.matches(declaringClassName, name, sig)) { + return level; + } + } + return CompilationLevel.Simple; + } + } + if (level.ordinal() > CompilationLevel.Simple.ordinal()) { + String declaringClassName = declaringClass.getName(); + if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm.compiler") || declaringClassName.startsWith("com.oracle.graal")) { + return CompilationLevel.Simple; + } + } + return level; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java 2016-12-07 13:50:06.718082565 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, 2016, 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; + +import static org.graalvm.compiler.core.common.util.ModuleAPI.addExports; +import static org.graalvm.compiler.core.common.util.ModuleAPI.getModule; +import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION; + +import org.graalvm.compiler.serviceprovider.ServiceProvider; + +import jdk.vm.ci.hotspot.HotSpotVMEventListener; +import jdk.vm.ci.runtime.JVMCICompilerFactory; +import jdk.vm.ci.services.JVMCIServiceLocator; + +@ServiceProvider(JVMCIServiceLocator.class) +public final class HotSpotGraalJVMCIServiceLocator extends JVMCIServiceLocator { + + private boolean exportsAdded; + + /** + * Dynamically exports various internal JDK packages to the Graal module. This requires only + * {@code --add-exports=java.base/jdk.internal.module=org.graalvm.compiler.graal_core} on the VM + * command line instead of a {@code --add-exports} instance for each JDK internal package used + * by Graal. + */ + private void addExports() { + if (JAVA_SPECIFICATION_VERSION >= 9 && !exportsAdded) { + Object javaBaseModule = getModule.invoke(String.class); + Object graalModule = getModule.invoke(getClass()); + addExports.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule); + addExports.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule); + addExports.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule); + exportsAdded = true; + } + } + + private HotSpotGraalRuntime graalRuntime; + + @Override + public T getProvider(Class service) { + if (service == JVMCICompilerFactory.class) { + addExports(); + return service.cast(new HotSpotGraalCompilerFactory(this)); + } else if (service == HotSpotVMEventListener.class) { + if (graalRuntime != null) { + addExports(); + return service.cast(new HotSpotGraalVMEventListener(graalRuntime)); + } + } + return null; + } + + public void onCompilerCreation(HotSpotGraalCompiler compiler) { + assert this.graalRuntime == null : "only expect a single JVMCICompiler to be created"; + this.graalRuntime = (HotSpotGraalRuntime) compiler.getGraalRuntime(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java 2016-12-07 13:50:06.984094257 -0800 @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2011, 2016, 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; + +import static org.graalvm.compiler.debug.GraalDebugConfig.areScopedGlobalMetricsEnabled; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueSummary; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Log; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.MethodFilter; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Verify; +import static jdk.vm.ci.common.InitTimer.timer; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.graalvm.compiler.api.collections.CollectionsProvider; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.api.runtime.GraalRuntime; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.target.Backend; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugEnvironment; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.debug.internal.DebugValuesPrinter; +import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter; +import org.graalvm.compiler.graph.DefaultNodeCollectionsProvider; +import org.graalvm.compiler.graph.NodeCollectionsProvider; +import org.graalvm.compiler.hotspot.CompilerConfigurationFactory.BackendMap; +import org.graalvm.compiler.hotspot.debug.BenchmarkCounters; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.nodes.spi.StampProvider; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.replacements.SnippetCounter; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.stack.StackIntrospection; +import jdk.vm.ci.common.InitTimer; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotVMConfigStore; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.runtime.JVMCIBackend; + +//JaCoCo Exclude + +/** + * Singleton class holding the instance of the {@link GraalRuntime}. + */ +public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { + + private static boolean checkArrayIndexScaleInvariants() { + assert getArrayIndexScale(JavaKind.Byte) == 1; + assert getArrayIndexScale(JavaKind.Boolean) == 1; + assert getArrayIndexScale(JavaKind.Char) == 2; + assert getArrayIndexScale(JavaKind.Short) == 2; + assert getArrayIndexScale(JavaKind.Int) == 4; + assert getArrayIndexScale(JavaKind.Long) == 8; + assert getArrayIndexScale(JavaKind.Float) == 4; + assert getArrayIndexScale(JavaKind.Double) == 8; + return true; + } + + private final HotSpotBackend hostBackend; + private DebugValuesPrinter debugValuesPrinter; + + private final Map, HotSpotBackend> backends = new HashMap<>(); + + private final GraalHotSpotVMConfig config; + + /** + * @param compilerConfigurationFactory factory for the compiler configuration + * {@link CompilerConfigurationFactory#selectFactory(String)} + */ + @SuppressWarnings("try") + HotSpotGraalRuntime(HotSpotJVMCIRuntime jvmciRuntime, CompilerConfigurationFactory compilerConfigurationFactory) { + + HotSpotVMConfigStore store = jvmciRuntime.getConfigStore(); + config = new GraalHotSpotVMConfig(store); + CompileTheWorldOptions.overrideWithNativeOptions(config); + + // Only set HotSpotPrintInlining if it still has its default value (false). + if (GraalOptions.HotSpotPrintInlining.getValue() == false) { + GraalOptions.HotSpotPrintInlining.setValue(config.printInlining); + } + + CompilerConfiguration compilerConfiguration = compilerConfigurationFactory.createCompilerConfiguration(); + BackendMap backendMap = compilerConfigurationFactory.createBackendMap(); + + JVMCIBackend hostJvmciBackend = jvmciRuntime.getHostJVMCIBackend(); + Architecture hostArchitecture = hostJvmciBackend.getTarget().arch; + try (InitTimer t = timer("create backend:", hostArchitecture)) { + HotSpotBackendFactory factory = backendMap.getBackendFactory(hostArchitecture); + if (factory == null) { + throw new GraalError("No backend available for host architecture \"%s\"", hostArchitecture); + } + hostBackend = registerBackend(factory.createBackend(this, compilerConfiguration, jvmciRuntime, null)); + } + + for (JVMCIBackend jvmciBackend : jvmciRuntime.getJVMCIBackends().values()) { + if (jvmciBackend == hostJvmciBackend) { + continue; + } + + Architecture gpuArchitecture = jvmciBackend.getTarget().arch; + HotSpotBackendFactory factory = backendMap.getBackendFactory(gpuArchitecture); + if (factory == null) { + throw new GraalError("No backend available for specified GPU architecture \"%s\"", gpuArchitecture); + } + try (InitTimer t = timer("create backend:", gpuArchitecture)) { + registerBackend(factory.createBackend(this, compilerConfiguration, null, hostBackend)); + } + } + + if (Log.getValue() == null && !areScopedGlobalMetricsEnabled() && Dump.getValue() == null && Verify.getValue() == null) { + if (MethodFilter.getValue() != null && !Debug.isEnabled()) { + TTY.println("WARNING: Ignoring MethodFilter option since Log, Meter, Time, TrackMemUse, Dump and Verify options are all null"); + } + } + + if (Debug.isEnabled()) { + DebugEnvironment.initialize(TTY.out, hostBackend.getProviders().getSnippetReflection()); + + String summary = DebugValueSummary.getValue(); + if (summary != null) { + switch (summary) { + case "Name": + case "Partial": + case "Complete": + case "Thread": + break; + default: + throw new GraalError("Unsupported value for DebugSummaryValue: %s", summary); + } + } + } + + if (Debug.areUnconditionalCountersEnabled() || Debug.areUnconditionalTimersEnabled() || Debug.areUnconditionalMethodMetricsEnabled() || + (Debug.isEnabled() && areScopedGlobalMetricsEnabled()) || (Debug.isEnabled() && Debug.isMethodFilteringEnabled())) { + // This must be created here to avoid loading the DebugValuesPrinter class + // during shutdown() which in turn can cause a deadlock + int mmPrinterType = 0; + mmPrinterType |= MethodMetricsPrinter.Options.MethodMeterPrintAscii.getValue() ? 1 : 0; + mmPrinterType |= MethodMetricsPrinter.Options.MethodMeterFile.getValue() != null ? 2 : 0; + switch (mmPrinterType) { + case 0: + debugValuesPrinter = new DebugValuesPrinter(); + break; + case 1: + debugValuesPrinter = new DebugValuesPrinter(new MethodMetricsPrinter.MethodMetricsASCIIPrinter(TTY.out)); + break; + case 2: + debugValuesPrinter = new DebugValuesPrinter(new MethodMetricsPrinter.MethodMetricsCSVFilePrinter()); + break; + case 3: + debugValuesPrinter = new DebugValuesPrinter( + new MethodMetricsPrinter.MethodMetricsCompositePrinter(new MethodMetricsPrinter.MethodMetricsCSVFilePrinter(), + new MethodMetricsPrinter.MethodMetricsASCIIPrinter(TTY.out))); + break; + default: + break; + } + } + + // Complete initialization of backends + try (InitTimer st = timer(hostBackend.getTarget().arch.getName(), ".completeInitialization")) { + hostBackend.completeInitialization(jvmciRuntime); + } + for (HotSpotBackend backend : backends.values()) { + if (backend != hostBackend) { + try (InitTimer st = timer(backend.getTarget().arch.getName(), ".completeInitialization")) { + backend.completeInitialization(jvmciRuntime); + } + } + } + + BenchmarkCounters.initialize(jvmciRuntime); + + assert checkArrayIndexScaleInvariants(); + + runtimeStartTime = System.nanoTime(); + bootstrapJVMCI = config.getFlag("BootstrapJVMCI", Boolean.class); + } + + private HotSpotBackend registerBackend(HotSpotBackend backend) { + Class arch = backend.getTarget().arch.getClass(); + HotSpotBackend oldValue = backends.put(arch, backend); + assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); + return backend; + } + + @Override + public HotSpotProviders getHostProviders() { + return getHostBackend().getProviders(); + } + + @Override + public GraalHotSpotVMConfig getVMConfig() { + return config; + } + + @Override + public String getName() { + return getClass().getSimpleName(); + } + + private final NodeCollectionsProvider nodeCollectionsProvider = new DefaultNodeCollectionsProvider(); + + @SuppressWarnings("unchecked") + @Override + public T getCapability(Class clazz) { + if (clazz == RuntimeProvider.class) { + return (T) this; + } else if (clazz == CollectionsProvider.class || clazz == NodeCollectionsProvider.class) { + return (T) nodeCollectionsProvider; + } else if (clazz == StackIntrospection.class) { + return (T) this; + } else if (clazz == SnippetReflectionProvider.class) { + return (T) getHostProviders().getSnippetReflection(); + } else if (clazz == StampProvider.class) { + return (T) getHostProviders().getStampProvider(); + } + return null; + } + + @Override + public HotSpotBackend getHostBackend() { + return hostBackend; + } + + @Override + public Backend getBackend(Class arch) { + assert arch != Architecture.class; + return backends.get(arch); + } + + public Map, HotSpotBackend> getBackends() { + return Collections.unmodifiableMap(backends); + } + + private long runtimeStartTime; + + /** + * Take action related to entering a new execution phase. + * + * @param phase the execution phase being entered + */ + static void phaseTransition(String phase) { + CompilationStatistics.clear(phase); + } + + void shutdown() { + if (debugValuesPrinter != null) { + debugValuesPrinter.printDebugValues(); + } + phaseTransition("final"); + + SnippetCounter.printGroups(TTY.out().out()); + BenchmarkCounters.shutdown(runtime(), runtimeStartTime); + } + + void clearMeters() { + if (debugValuesPrinter != null) { + debugValuesPrinter.clearDebugValues(); + } + } + + private final boolean bootstrapJVMCI; + private boolean bootstrapFinished; + + public void notifyBootstrapFinished() { + bootstrapFinished = true; + } + + @Override + public boolean isBootstrapping() { + return bootstrapJVMCI && !bootstrapFinished; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java 2016-12-07 13:50:07.249105906 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011, 2015, 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; + +import org.graalvm.compiler.api.runtime.GraalRuntime; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.code.TargetDescription; + +//JaCoCo Exclude + +/** + * Configuration information for the HotSpot Graal runtime. + */ +public interface HotSpotGraalRuntimeProvider extends GraalRuntime, RuntimeProvider { + + default TargetDescription getTarget() { + return getHostBackend().getTarget(); + } + + HotSpotProviders getHostProviders(); + + @Override + default String getName() { + return getClass().getSimpleName(); + } + + @Override + HotSpotBackend getHostBackend(); + + GraalHotSpotVMConfig getVMConfig(); + + /** + * Determines if the VM is currently bootstrapping the JVMCI compiler. + */ + boolean isBootstrapping(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalVMEventListener.java 2016-12-07 13:50:07.514117554 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015, 2016, 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; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.GraalDebugConfig; + +import jdk.vm.ci.code.CompiledCode; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotVMEventListener; + +public class HotSpotGraalVMEventListener implements HotSpotVMEventListener { + + private final HotSpotGraalRuntime runtime; + + HotSpotGraalVMEventListener(HotSpotGraalRuntime runtime) { + this.runtime = runtime; + } + + @Override + public void notifyShutdown() { + runtime.shutdown(); + } + + @Override + public void notifyInstall(HotSpotCodeCacheProvider codeCache, InstalledCode installedCode, CompiledCode compiledCode) { + if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) { + CompilationResult compResult = Debug.contextLookup(CompilationResult.class); + assert compResult != null : "can't dump installed code properly without CompilationResult"; + Debug.dump(Debug.BASIC_LOG_LEVEL, installedCode, "After code installation"); + } + if (Debug.isLogEnabled()) { + Debug.log("%s", codeCache.disassemble(installedCode)); + } + } + + @Override + public void notifyBootstrapFinished() { + runtime.notifyBootstrapFinished(); + if (GraalDebugConfig.Options.ClearMetricsAfterBootstrap.getValue()) { + runtime.clearMeters(); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java 2016-12-07 13:50:07.778129159 -0800 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2013, 2015, 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; + +import static jdk.vm.ci.code.CodeUtil.getCallingConvention; +import static jdk.vm.ci.common.InitTimer.timer; + +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.stubs.DeoptimizationStub; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.hotspot.stubs.UncommonTrapStub; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.framemap.ReferenceMapBuilder; +import org.graalvm.compiler.nodes.StructuredGraph; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.common.InitTimer; +import jdk.vm.ci.hotspot.HotSpotCallingConventionType; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.runtime.JVMCICompiler; + +/** + * Common functionality of HotSpot host backends. + */ +public abstract class HotSpotHostBackend extends HotSpotBackend { + + /** + * Descriptor for {@code SharedRuntime::deopt_blob()->unpack()} or + * {@link DeoptimizationStub#deoptimizationHandler} depending on + * {@link HotSpotBackend.Options#PreferGraalStubs}. + */ + public static final ForeignCallDescriptor DEOPTIMIZATION_HANDLER = new ForeignCallDescriptor("deoptHandler", void.class); + + /** + * Descriptor for {@code SharedRuntime::deopt_blob()->uncommon_trap()} or + * {@link UncommonTrapStub#uncommonTrapHandler} depending on + * {@link HotSpotBackend.Options#PreferGraalStubs}. + */ + public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class); + + protected final GraalHotSpotVMConfig config; + + public HotSpotHostBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { + super(runtime, providers); + this.config = config; + } + + @Override + @SuppressWarnings("try") + public void completeInitialization(HotSpotJVMCIRuntime jvmciRuntime) { + final HotSpotProviders providers = getProviders(); + HotSpotHostForeignCallsProvider foreignCalls = (HotSpotHostForeignCallsProvider) providers.getForeignCalls(); + final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer(); + + try (InitTimer st = timer("foreignCalls.initialize")) { + foreignCalls.initialize(providers); + } + try (InitTimer st = timer("lowerer.initialize")) { + lowerer.initialize(providers, config); + } + } + + protected CallingConvention makeCallingConvention(StructuredGraph graph, Stub stub) { + if (stub != null) { + return stub.getLinkage().getIncomingCallingConvention(); + } + + CallingConvention cc = getCallingConvention(getCodeCache(), HotSpotCallingConventionType.JavaCallee, graph.method(), this); + if (graph.getEntryBCI() != JVMCICompiler.INVOCATION_ENTRY_BCI) { + // for OSR, only a pointer is passed to the method. + JavaType[] parameterTypes = new JavaType[]{getMetaAccess().lookupJavaType(long.class)}; + CallingConvention tmp = getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCallee, getMetaAccess().lookupJavaType(void.class), parameterTypes, this); + cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0)); + } + return cc; + } + + public void emitStackOverflowCheck(CompilationResultBuilder crb) { + if (config.useStackBanging) { + // Each code entry causes one stack bang n pages down the stack where n + // is configurable by StackShadowPages. The setting depends on the maximum + // depth of VM call stack or native before going back into java code, + // since only java code can raise a stack overflow exception using the + // stack banging mechanism. The VM and native code does not detect stack + // overflow. + // The code in JavaCalls::call() checks that there is at least n pages + // available, so all entry code needs to do is bang once for the end of + // this shadow zone. + // The entry code may need to bang additional pages if the framesize + // is greater than a page. + + int pageSize = config.vmPageSize; + int bangEnd = config.stackShadowPages * pageSize; + + // This is how far the previous frame's stack banging extended. + int bangEndSafe = bangEnd; + + int frameSize = Math.max(crb.frameMap.frameSize(), crb.compilationResult.getMaxInterpreterFrameSize()); + if (frameSize > pageSize) { + bangEnd += frameSize; + } + + int bangOffset = bangEndSafe; + if (bangOffset <= bangEnd) { + crb.blockComment("[stack overflow check]"); + } + while (bangOffset <= bangEnd) { + // Need at least one stack bang at end of shadow zone. + bangStackWithOffset(crb, bangOffset); + bangOffset += pageSize; + } + } + } + + protected abstract void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset); + + @Override + public ReferenceMapBuilder newReferenceMapBuilder(int totalFrameSize) { + return new HotSpotReferenceMapBuilder(totalFrameSize, config.maxOopMapStackOffset); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotInstructionProfiling.java 2016-12-07 13:50:08.046140939 -0800 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2015, 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; + +import java.util.List; + +import org.graalvm.compiler.asm.Assembler; +import org.graalvm.compiler.asm.Assembler.InstructionCounter; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.lir.ConstantValue; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRInsertionBuffer; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.StandardOp.BlockEndOp; +import org.graalvm.compiler.lir.StandardOp.LabelOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; + +public class HotSpotInstructionProfiling extends PostAllocationOptimizationPhase { + public static final String COUNTER_GROUP = "INSTRUCTION_COUNTER"; + private final String[] instructionsToProfile; + + public HotSpotInstructionProfiling(String instructionsToProfile) { + this.instructionsToProfile = instructionsToProfile.split(","); + } + + @Override + protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) { + new Analyzer(target, lirGenRes.getCompilationUnitName(), lirGenRes.getLIR(), context.diagnosticLirGenTool).run(); + } + + private class Analyzer { + private final TargetDescription target; + private final LIR lir; + private final DiagnosticLIRGeneratorTool diagnosticLirGenTool; + private final LIRInsertionBuffer buffer; + private final String compilationUnitName; + + Analyzer(TargetDescription target, String compilationUnitName, LIR lir, DiagnosticLIRGeneratorTool diagnosticLirGenTool) { + this.target = target; + this.lir = lir; + this.compilationUnitName = compilationUnitName; + this.diagnosticLirGenTool = diagnosticLirGenTool; + this.buffer = new LIRInsertionBuffer(); + } + + public void run() { + for (AbstractBlockBase block : lir.getControlFlowGraph().getBlocks()) { + doBlock(block); + } + } + + public void doBlock(AbstractBlockBase block) { + List instructions = lir.getLIRforBlock(block); + assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions; + assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1); + assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2); + assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0); + assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1); + String[] names = new String[instructionsToProfile.length]; + String[] groups = new String[instructionsToProfile.length]; + Value[] increments = new Value[instructionsToProfile.length]; + for (int i = 0; i < instructionsToProfile.length; i++) { + names[i] = compilationUnitName; + groups[i] = COUNTER_GROUP + " " + instructionsToProfile[i]; + // Default is zero; this value is patched to the real instruction count after + // assembly in method HotSpotInstructionProfiling.countInstructions + increments[i] = new ConstantValue(LIRKind.fromJavaKind(target.arch, JavaKind.Int), JavaConstant.INT_0); + } + HotSpotCounterOp op = (HotSpotCounterOp) diagnosticLirGenTool.createMultiBenchmarkCounter(names, groups, increments); + LIRInstruction inst = new InstructionCounterOp(op, instructionsToProfile); + assert inst != null; + buffer.init(instructions); + buffer.append(1, inst); + buffer.finish(); + } + } + + /** + * After assembly the {@link HotSpotBackend#profileInstructions(LIR, CompilationResultBuilder)} + * calls this method for patching the instruction counts into the counter increment code. + */ + public static void countInstructions(LIR lir, Assembler asm) { + InstructionCounterOp lastOp = null; + InstructionCounter counter = asm.getInstructionCounter(); + for (AbstractBlockBase block : lir.codeEmittingOrder()) { + if (block == null) { + continue; + } + for (LIRInstruction inst : lir.getLIRforBlock(block)) { + if (inst instanceof InstructionCounterOp) { + InstructionCounterOp currentOp = (InstructionCounterOp) inst; + + if (lastOp != null) { + int beginPc = lastOp.countOffsetEnd; + int endPc = currentOp.countOffsetBegin; + int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc); + lastOp.delegate.patchCounterIncrement(asm, instructionCounts); + } + lastOp = ((InstructionCounterOp) inst); + } + } + } + if (lastOp != null) { + assert lastOp.countOffsetBegin < asm.position(); + int beginPc = lastOp.countOffsetBegin; + int endPc = asm.position(); + int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc); + lastOp.delegate.patchCounterIncrement(asm, instructionCounts); + } + } + + public static class InstructionCounterOp extends LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(InstructionCounterOp.class); + private final HotSpotCounterOp delegate; + private final String[] instructionsToProfile; + private int countOffsetBegin; + private int countOffsetEnd; + + public InstructionCounterOp(HotSpotCounterOp delegate, String[] instructionsToProfile) { + super(TYPE); + this.delegate = delegate; + this.instructionsToProfile = instructionsToProfile; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + countOffsetBegin = crb.asm.position(); + this.delegate.emitCode(crb); + countOffsetEnd = crb.asm.position(); + } + + public String[] getInstructionsToProfile() { + return instructionsToProfile; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java 2016-12-07 13:50:08.310152543 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014, 2016, 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; + +import java.util.Map; + +import org.graalvm.compiler.core.common.CollectionsFactory; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.StackSlot; + +public class HotSpotLIRGenerationResult extends LIRGenerationResult { + + /** + * The slot reserved for storing the original return address when a frame is marked for + * deoptimization. The return address slot in the callee is overwritten with the address of a + * deoptimization stub. + */ + private StackSlot deoptimizationRescueSlot; + protected final Object stub; + + private int maxInterpreterFrameSize; + + /** + * Map from debug infos that need to be updated with callee save information to the operations + * that provide the information. + */ + private Map calleeSaveInfo = CollectionsFactory.newMap(); + + public HotSpotLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, CallingConvention callingConvention, Object stub) { + super(compilationId, lir, frameMapBuilder, callingConvention); + this.stub = stub; + } + + public Map getCalleeSaveInfo() { + return calleeSaveInfo; + } + + public Stub getStub() { + return (Stub) stub; + } + + public StackSlot getDeoptimizationRescueSlot() { + return deoptimizationRescueSlot; + } + + public final void setDeoptimizationRescueSlot(StackSlot stackSlot) { + this.deoptimizationRescueSlot = stackSlot; + } + + public void setMaxInterpreterFrameSize(int maxInterpreterFrameSize) { + this.maxInterpreterFrameSize = maxInterpreterFrameSize; + } + + public int getMaxInterpreterFrameSize() { + return maxInterpreterFrameSize; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java 2016-12-07 13:50:08.577164279 -0800 @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2012, 2016, 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; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.DeoptimizationFetchUnrollInfoCallNode; +import org.graalvm.compiler.hotspot.nodes.EnterUnpackFramesStackFrameNode; +import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; +import org.graalvm.compiler.hotspot.nodes.LeaveCurrentStackFrameNode; +import org.graalvm.compiler.hotspot.nodes.LeaveDeoptimizedStackFrameNode; +import org.graalvm.compiler.hotspot.nodes.LeaveUnpackFramesStackFrameNode; +import org.graalvm.compiler.hotspot.nodes.PushInterpreterFrameNode; +import org.graalvm.compiler.hotspot.nodes.SaveAllRegistersNode; +import org.graalvm.compiler.hotspot.nodes.UncommonTrapCallNode; +import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; +import org.graalvm.compiler.hotspot.nodes.profiling.RandomSeedNode; +import org.graalvm.compiler.hotspot.replacements.EncodedSymbolConstant; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.gen.LIRGenerator; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition + * to abstract methods from {@link LIRGenerator} and {@link LIRGeneratorTool}. + */ +public interface HotSpotLIRGenerator extends LIRGeneratorTool { + + /** + * Emits an operation to make a tail call. + * + * @param args the arguments of the call + * @param address the target address of the call + */ + void emitTailcall(Value[] args, Value address); + + void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason); + + /** + * Emits code for a {@link SaveAllRegistersNode}. + * + * @return a {@link SaveRegistersOp} operation + */ + SaveRegistersOp emitSaveAllRegisters(); + + /** + * Emits code for a {@link LeaveCurrentStackFrameNode}. + * + * @param saveRegisterOp saved registers + */ + default void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link LeaveDeoptimizedStackFrameNode}. + * + * @param frameSize + * @param initialInfo + */ + default void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link EnterUnpackFramesStackFrameNode}. + * + * @param framePc + * @param senderSp + * @param senderFp + * @param saveRegisterOp + */ + default void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link LeaveUnpackFramesStackFrameNode}. + * + * @param saveRegisterOp + */ + default void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link PushInterpreterFrameNode}. + * + * @param frameSize + * @param framePc + * @param senderSp + * @param initialInfo + */ + default void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link LoadConstantIndirectlyNode}. + * + * @param constant + * @return value of loaded address in register + */ + default Value emitLoadObjectAddress(Constant constant) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link LoadConstantIndirectlyNode}. + * + * @param constant + * @return Value of loaded address in register + */ + @SuppressWarnings("unused") + default Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link GraalHotSpotVMConfigNode}. + * + * @param markId type of address to load + * @return value of loaded global in register + */ + default Value emitLoadConfigValue(int markId) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link ResolveConstantNode} to resolve a {@link HotSpotObjectConstant}. + * + * @param constantDescription a description of the string that need to be materialized (and + * interned) as java.lang.String, generated with {@link EncodedSymbolConstant} + * @return Returns the address of the requested constant. + */ + @SuppressWarnings("unused") + default Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link ResolveConstantNode} to resolve a {@link HotSpotMetaspaceConstant}. + * + * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant} + * generated by {@link EncodedSymbolConstant} + * @return Returns the address of the requested constant. + */ + @SuppressWarnings("unused") + default Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link ResolveMethodAndLoadCountersNode} to resolve a + * {@link HotSpotMetaspaceConstant} that represents a {@link ResolvedJavaMethod} and return the + * corresponding MethodCounters object. + * + * @param klassHint a klass in which the method is declared + * @param methodDescription is symbolic description of the constant generated by + * {@link EncodedSymbolConstant} + * @return Returns the address of the requested constant. + */ + @SuppressWarnings("unused") + default Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link ResolveConstantNode} to resolve a klass + * {@link HotSpotMetaspaceConstant} and run static initializer. + * + * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant} + * generated by {@link EncodedSymbolConstant} + * @return Returns the address of the requested constant. + */ + @SuppressWarnings("unused") + default Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link RandomSeedNode}. + * + * @return value of the counter + */ + default Value emitRandomSeed() { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link UncommonTrapCallNode}. + * + * @param trapRequest + * @param mode + * @param saveRegisterOp + * @return a {@code Deoptimization::UnrollBlock} pointer + */ + default Value emitUncommonTrapCall(Value trapRequest, Value mode, SaveRegistersOp saveRegisterOp) { + throw GraalError.unimplemented(); + } + + /** + * Emits code for a {@link DeoptimizationFetchUnrollInfoCallNode}. + * + * @param mode + * @param saveRegisterOp + * @return a {@code Deoptimization::UnrollBlock} pointer + */ + default Value emitDeoptimizationFetchUnrollInfoCall(Value mode, SaveRegistersOp saveRegisterOp) { + throw GraalError.unimplemented(); + } + + /** + * Gets a stack slot for a lock at a given lock nesting depth. + */ + VirtualStackSlot getLockSlot(int lockDepth); + + @Override + HotSpotProviders getProviders(); + + Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull); + + Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLockStack.java 2016-12-07 13:50:08.844176016 -0800 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2013, 2015, 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; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; + +import java.util.Arrays; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; + +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Manages allocation and re-use of lock slots in a scoped manner. The slots are used in HotSpot's + * lightweight locking mechanism to store the mark word of an object being locked. + */ +public class HotSpotLockStack extends LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(HotSpotLockStack.class); + private static final AllocatableValue[] EMPTY = new AllocatableValue[0]; + + @Def({STACK}) private AllocatableValue[] locks; + private final FrameMapBuilder frameMapBuilder; + private final LIRKind slotKind; + + public HotSpotLockStack(FrameMapBuilder frameMapBuilder, LIRKind slotKind) { + super(TYPE); + this.frameMapBuilder = frameMapBuilder; + this.slotKind = slotKind; + this.locks = EMPTY; + } + + /** + * Gets a stack slot for a lock at a given lock nesting depth, allocating it first if necessary. + */ + public VirtualStackSlot makeLockSlot(int lockDepth) { + if (locks == EMPTY) { + locks = new AllocatableValue[lockDepth + 1]; + } else if (locks.length < lockDepth + 1) { + locks = Arrays.copyOf(locks, lockDepth + 1); + } + if (locks[lockDepth] == null) { + locks[lockDepth] = frameMapBuilder.allocateSpillSlot(slotKind); + } + return (VirtualStackSlot) locks[lockDepth]; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + // do nothing + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotNodeLIRBuilder.java 2016-12-07 13:50:09.108187620 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 2015, 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; + +import org.graalvm.compiler.core.match.MatchableNode; +import org.graalvm.compiler.hotspot.nodes.CompressionNode; +import org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode; +import org.graalvm.compiler.lir.gen.LIRGenerator; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +/** + * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition + * to abstract methods from {@link LIRGenerator} and {@link NodeLIRBuilderTool}. + */ +@MatchableNode(nodeClass = CompressionNode.class, inputs = {"value"}) +public interface HotSpotNodeLIRBuilder { + + void emitPatchReturnAddress(ValueNode address); + + default void emitJumpToExceptionHandler(ValueNode address) { + emitPatchReturnAddress(address); + } + + void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc); + + void visitDirectCompareAndSwap(DirectCompareAndSwapNode x); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReferenceMapBuilder.java 2016-12-07 13:50:09.372199225 -0800 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2009, 2015, 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; + +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.asStackSlot; +import static jdk.vm.ci.code.ValueUtil.isRegister; + +import java.util.ArrayList; + +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.framemap.ReferenceMapBuilder; + +import jdk.vm.ci.code.Location; +import jdk.vm.ci.code.ReferenceMap; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.hotspot.HotSpotReferenceMap; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +public final class HotSpotReferenceMapBuilder extends ReferenceMapBuilder { + + private int maxRegisterSize; + + private final ArrayList objectValues; + private int objectCount; + + private final int totalFrameSize; + private final int maxOopMapStackOffset; + + public HotSpotReferenceMapBuilder(int totalFrameSize, int maxOopMapStackOffset) { + this.objectValues = new ArrayList<>(); + this.objectCount = 0; + this.maxOopMapStackOffset = maxOopMapStackOffset; + this.totalFrameSize = totalFrameSize; + } + + @Override + public void addLiveValue(Value v) { + if (isJavaConstant(v)) { + return; + } + LIRKind lirKind = (LIRKind) v.getValueKind(); + if (!lirKind.isValue()) { + objectValues.add(v); + if (lirKind.isUnknownReference()) { + objectCount++; + } else { + objectCount += lirKind.getReferenceCount(); + } + } + if (isRegister(v)) { + int size = lirKind.getPlatformKind().getSizeInBytes(); + if (size > maxRegisterSize) { + maxRegisterSize = size; + } + } + } + + private static final Location[] NO_LOCATIONS = {}; + private static final int[] NO_SIZES = {}; + + @Override + public ReferenceMap finish(LIRFrameState state) { + Location[] objects; + Location[] derivedBase; + int[] sizeInBytes; + if (objectCount == 0) { + objects = NO_LOCATIONS; + derivedBase = NO_LOCATIONS; + sizeInBytes = NO_SIZES; + } else { + objects = new Location[objectCount]; + derivedBase = new Location[objectCount]; + sizeInBytes = new int[objectCount]; + } + int idx = 0; + for (Value obj : objectValues) { + LIRKind kind = (LIRKind) obj.getValueKind(); + int bytes = bytesPerElement(kind); + if (kind.isUnknownReference()) { + throw GraalError.shouldNotReachHere("unknown reference alive across safepoint"); + } else { + Location base = null; + if (kind.isDerivedReference()) { + Variable baseVariable = (Variable) kind.getDerivedReferenceBase(); + Value baseValue = state.getLiveBasePointers().get(baseVariable.index); + assert baseValue.getPlatformKind().getVectorLength() == 1 && ((LIRKind) baseValue.getValueKind()).isReference(0) && !((LIRKind) baseValue.getValueKind()).isDerivedReference(); + base = toLocation(baseValue, 0); + } + + for (int i = 0; i < kind.getPlatformKind().getVectorLength(); i++) { + if (kind.isReference(i)) { + objects[idx] = toLocation(obj, i * bytes); + derivedBase[idx] = base; + sizeInBytes[idx] = bytes; + idx++; + } + } + } + } + + return new HotSpotReferenceMap(objects, derivedBase, sizeInBytes, maxRegisterSize); + } + + private static int bytesPerElement(LIRKind kind) { + PlatformKind platformKind = kind.getPlatformKind(); + return platformKind.getSizeInBytes() / platformKind.getVectorLength(); + } + + private Location toLocation(Value v, int offset) { + if (isRegister(v)) { + return Location.subregister(asRegister(v), offset); + } else { + StackSlot s = asStackSlot(v); + int totalOffset = s.getOffset(totalFrameSize) + offset; + if (totalOffset > maxOopMapStackOffset) { + throw new PermanentBailoutException("stack offset %d for oopmap is greater than encoding limit %d", totalOffset, maxOopMapStackOffset); + } + return Location.stack(totalOffset); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java 2016-12-07 13:50:09.637210873 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.hotspot.word.HotSpotOperation; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.replacements.ReplacementsImpl; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Filters certain method substitutions based on whether there is underlying hardware support for + * them. + */ +public class HotSpotReplacementsImpl extends ReplacementsImpl { + + public HotSpotReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider, TargetDescription target) { + super(providers, snippetReflection, bytecodeProvider, target); + } + + @Override + protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) { + return method.getAnnotation(HotSpotOperation.class) != null || super.hasGenericInvocationPluginAnnotation(method); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java 2016-12-07 13:50:09.902222521 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 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; + +import java.io.PrintStream; + +import org.graalvm.compiler.debug.TTYStreamProvider; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.serviceprovider.ServiceProvider; + +@ServiceProvider(TTYStreamProvider.class) +public class HotSpotTTYStreamProvider implements TTYStreamProvider { + + public static class Options { + + // @formatter:off + @Option(help = "File to which logging is sent. A %p in the name will be replaced with a string identifying " + + "the process, usually the process id and %t will be replaced by System.currentTimeMillis().", type = OptionType.Expert) + public static final PrintStreamOption LogFile = new PrintStreamOption(); + // @formatter:on + } + + @Override + public PrintStream getStream() { + return Options.LogFile.getStream(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java 2016-12-07 13:50:10.166234126 -0800 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016, 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; + +import java.util.Formatter; + +/** + * Mechanism for checking that the current Java runtime environment supports the minimum JVMCI API + * required by Graal. The {@code JVMCI_VERSION_CHECK} environment variable can be used to ignore a + * failed check ({@code JVMCI_VERSION_CHECK=ignore}) or print a warning ( + * {@code JVMCI_VERSION_CHECK=warn}) and continue. Otherwise, a failed check results in an + * {@link InternalError} being raised or, if called from {@link #main(String[])}, the VM exiting + * with a result code of {@code -1} + * + * This class only depends on the JDK so that it can be used without building Graal. + */ +class JVMCIVersionCheck { + + private static final int JVMCI8_MIN_MAJOR_VERSION = 0; + private static final int JVMCI8_MIN_MINOR_VERSION = 23; + + // Will be updated once an ea build with the required JVMCI API is available. + private static final int JVMCI9_MIN_EA_BUILD = 143; + + private static void failVersionCheck(boolean exit, String reason, Object... args) { + Formatter errorMessage = new Formatter().format(reason, args); + String javaHome = System.getProperty("java.home"); + String vmName = System.getProperty("java.vm.name"); + errorMessage.format("Set the JVMCI_VERSION_CHECK environment variable to \"ignore\" to suppress "); + errorMessage.format("this error or to \"warn\" to emit a warning and continue execution.%n"); + errorMessage.format("Currently used Java home directory is %s.%n", javaHome); + errorMessage.format("Currently used VM configuration is: %s%n", vmName); + if (System.getProperty("java.specification.version").compareTo("1.9") < 0) { + errorMessage.format("Download the latest JVMCI JDK 8 from http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html"); + } else { + errorMessage.format("Download the latest JDK 9 EA from https://jdk9.java.net/download/"); + } + String value = System.getenv("JVMCI_VERSION_CHECK"); + if ("warn".equals(value)) { + System.err.println(errorMessage.toString()); + } else if ("ignore".equals(value)) { + return; + } else if (exit) { + System.err.println(errorMessage.toString()); + System.exit(-1); + } else { + throw new InternalError(errorMessage.toString()); + } + } + + static void check(boolean exitOnFailure) { + // Don't use regular expressions to minimize Graal startup time + String vmVersion = System.getProperty("java.vm.version"); + if (System.getProperty("java.specification.version").compareTo("1.9") < 0) { + int start = vmVersion.indexOf("-jvmci-"); + if (start >= 0) { + start += "-jvmci-".length(); + int end = vmVersion.indexOf('.', start); + if (end > 0) { + int major = Integer.parseInt(vmVersion.substring(start, end)); + start = end + 1; + end = start; + while (end < vmVersion.length() && Character.isDigit(vmVersion.charAt(end))) { + end++; + } + int minor = Integer.parseInt(vmVersion.substring(start, end)); + if (major >= JVMCI8_MIN_MAJOR_VERSION && minor >= JVMCI8_MIN_MINOR_VERSION) { + return; + } + failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal: %d.%d < %d.%d.%n", + major, minor, JVMCI8_MIN_MAJOR_VERSION, JVMCI8_MIN_MINOR_VERSION); + return; + } + } + failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" + + "Cannot read JVMCI version from java.vm.version property: %s.%n", vmVersion); + } else { + if (vmVersion.contains("SNAPSHOT")) { + // The snapshot of http://hg.openjdk.java.net/jdk9/hs tip is expected to work + return; + } + if (vmVersion.contains("internal")) { + // Allow local builds + return; + } + // http://openjdk.java.net/jeps/223 + // Only support EA builds until GA is available + if (vmVersion.startsWith("9-ea+")) { + int start = "9-ea+".length(); + int end = start; + end = start; + while (end < vmVersion.length() && Character.isDigit(vmVersion.charAt(end))) { + end++; + } + int build = Integer.parseInt(vmVersion.substring(start, end)); + if (build >= JVMCI9_MIN_EA_BUILD) { + return; + } + failVersionCheck(exitOnFailure, "The VM is an insufficiently recent EA JDK9 build for Graal: %d < %d.%n", build, JVMCI9_MIN_EA_BUILD); + return; + } + failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" + + "Cannot read JDK9 EA build number from java.vm.version property: %s.%n", vmVersion); + } + } + + /** + * Command line interface for performing the check. + */ + public static void main(String[] args) { + check(true); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOption.java 2016-12-07 13:50:10.432245818 -0800 @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2014, 2015, 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; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; + +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.UniquePathUtilities; + +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; + +/** + * An option that encapsulates and configures a print stream. + */ +public class PrintStreamOption extends OptionValue { + + public PrintStreamOption() { + super(null); + } + + /** + * The print stream to which output will be written. + * + * Declared {@code volatile} to enable safe use of double-checked locking in + * {@link #getStream()} and {@link #setValue(Object)}. + */ + private volatile PrintStream ps; + + /** + * Replaces any instance of %p with an identifying name such as a process ID extracted from + * {@link RuntimeMXBean#getName()} and any instance of %t with the value of + * {@link System#currentTimeMillis()}. + * + * @return the name of the file to log to + */ + private String getFilename() { + String name = getValue(); + if (name.contains("%t")) { + name = name.replaceAll("%t", String.valueOf(UniquePathUtilities.getGlobalTimeStamp())); + } + if (name.contains("%p")) { + String runtimeName = ManagementFactory.getRuntimeMXBean().getName(); + try { + int index = runtimeName.indexOf('@'); + if (index != -1) { + long pid = Long.parseLong(runtimeName.substring(0, index)); + runtimeName = Long.toString(pid); + } + name = name.replaceAll("%p", runtimeName); + } catch (NumberFormatException e) { + + } + } + return name; + } + + /** + * An output stream that redirects to {@link HotSpotJVMCIRuntimeProvider#getLogStream()}. The + * {@link HotSpotJVMCIRuntimeProvider#getLogStream()} value is only accessed the first time an + * IO operation is performed on the stream. This is required to break a deadlock in early JVMCI + * initialization. + */ + static class DelayedOutputStream extends OutputStream { + private volatile OutputStream lazy; + + private OutputStream lazy() { + if (lazy == null) { + synchronized (this) { + if (lazy == null) { + lazy = HotSpotJVMCIRuntime.runtime().getLogStream(); + } + } + } + return lazy; + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + lazy().write(b, off, len); + } + + @Override + public void write(int b) throws IOException { + lazy().write(b); + } + + @Override + public void flush() throws IOException { + lazy().flush(); + } + + @Override + public void close() throws IOException { + lazy().close(); + } + } + + /** + * Gets the print stream configured by this option. If no file is configured, the print stream + * will output to HotSpot's {@link HotSpotJVMCIRuntimeProvider#getLogStream() log} stream. + */ + public PrintStream getStream() { + if (ps == null) { + if (getValue() != null) { + synchronized (this) { + if (ps == null) { + try { + final boolean enableAutoflush = true; + ps = new PrintStream(new FileOutputStream(getFilename()), enableAutoflush); + /* + * Add the JVM and Java arguments to the log file to help identity it. + */ + String inputArguments = String.join(" ", ManagementFactory.getRuntimeMXBean().getInputArguments()); + ps.println("VM Arguments: " + inputArguments); + String cmd = System.getProperty("sun.java.command"); + if (cmd != null) { + ps.println("sun.java.command=" + cmd); + } + } catch (FileNotFoundException e) { + throw new RuntimeException("couldn't open file: " + getValue(), e); + } + } + } + } else { + ps = new PrintStream(new DelayedOutputStream()); + } + } + return ps; + } + + @Override + public void setValue(Object v) { + if (ps != null) { + synchronized (this) { + if (ps != null) { + ps.close(); + ps = null; + } + } + } + super.setValue(v); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java 2016-12-07 13:50:10.696257422 -0800 @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2013, 2014, 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.debug; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.nio.file.Path; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +import org.graalvm.compiler.core.common.SuppressFBWarnings; +import org.graalvm.compiler.debug.CSVUtil; +import org.graalvm.compiler.debug.GraalDebugConfig; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions; +import org.graalvm.compiler.nodes.debug.DynamicCounterNode; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.StableOptionValue; +import org.graalvm.compiler.options.UniquePathUtilities; + +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; + +//JaCoCo Exclude + +/** + * This class contains infrastructure to maintain counters based on {@link DynamicCounterNode}s. The + * infrastructure is enabled by specifying either the GenericDynamicCounters or + * BenchmarkDynamicCounters option. + *

    + * + * The counters are kept in a special area allocated for each native JavaThread object, and the + * number of counters is configured using {@code -XX:JVMCICounterSize=value}. + * {@code -XX:+/-JVMCICountersExcludeCompiler} configures whether to exclude compiler threads + * (defaults to true). + * + * The subsystems that use the logging need to have their own options to turn on the counters, and + * insert DynamicCounterNodes when they're enabled. + * + * Counters will be displayed as a rate (per second) if their group name starts with "~", otherwise + * they will be displayed as a total number. + * + *

    Example

    In order to create statistics about allocations within the DaCapo pmd benchmark + * the following steps are necessary: + *
      + *
    • Set {@code -XX:JVMCICounterSize=value}. The actual required value depends on the granularity + * of the profiling, 10000 should be enough for most cases.
    • + *
    • Also: {@code -XX:+/-JVMCICountersExcludeCompiler} specifies whether the numbers generated by + * compiler threads should be excluded (default: true).
    • + *
    • Start the DaCapo pmd benchmark with + * {@code "-Dgraal.BenchmarkDynamicCounters=err, starting ====, PASSED in "} and + * {@code -Dgraal.ProfileAllocations=true}.
    • + *
    • The numbers will only include allocation from compiled code!
    • + *
    • The counters can be further configured by modifying the + * {@link HotspotSnippetsOptions#ProfileAllocationsContext} flag..
    • + *
    + */ +public class BenchmarkCounters { + + static class Options { + + //@formatter:off + @Option(help = "Turn on the benchmark counters, and displays the results on VM shutdown", type = OptionType.Debug) + public static final OptionValue GenericDynamicCounters = new OptionValue<>(false); + @Option(help = "Turn on the benchmark counters, and displays the results every n milliseconds", type = OptionType.Debug) + public static final OptionValue TimedDynamicCounters = new OptionValue<>(-1); + + @Option(help = "Turn on the benchmark counters, and listen for specific patterns on System.out/System.err:%n" + + "Format: (err|out),start pattern,end pattern (~ matches multiple digits)%n" + + "Examples:%n" + + " dacapo = 'err, starting =====, PASSED in'%n" + + " specjvm2008 = 'out,Iteration ~ (~s) begins:,Iteration ~ (~s) ends:'", type = OptionType.Debug) + public static final OptionValue BenchmarkDynamicCounters = new OptionValue<>(null); + @Option(help = "Use grouping separators for number printing", type = OptionType.Debug) + public static final OptionValue DynamicCountersPrintGroupSeparator = new OptionValue<>(true); + @Option(help = "Print in human readable format", type = OptionType.Debug) + public static final OptionValue DynamicCountersHumanReadable = new OptionValue<>(true); + @Option(help = "Benchmark counters log file (default is stdout)", type = OptionType.Debug) + public static final OptionValue BenchmarkCountersFile = new OptionValue<>(null); + @Option(help = "Dump dynamic counters", type = OptionType.Debug) + public static final StableOptionValue BenchmarkCountersDumpDynamic = new StableOptionValue<>(true); + @Option(help = "Dump static counters", type = OptionType.Debug) + public static final StableOptionValue BenchmarkCountersDumpStatic = new StableOptionValue<>(false); + //@formatter:on + } + + public static boolean enabled = false; + + private static class Counter { + public final int index; + public final String group; + public final AtomicLong staticCounters; + + Counter(int index, String group, AtomicLong staticCounters) { + this.index = index; + this.group = group; + this.staticCounters = staticCounters; + } + } + + public static final ConcurrentHashMap counterMap = new ConcurrentHashMap<>(); + public static long[] delta; + + public static int getIndexConstantIncrement(String name, String group, GraalHotSpotVMConfig config, long increment) { + Counter counter = getCounter(name, group, config); + counter.staticCounters.addAndGet(increment); + return counter.index; + } + + public static int getIndex(String name, String group, GraalHotSpotVMConfig config) { + Counter counter = getCounter(name, group, config); + return counter.index; + } + + @SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block") + private static Counter getCounter(String name, String group, GraalHotSpotVMConfig config) throws GraalError { + if (!enabled) { + throw new GraalError("cannot access count index when counters are not enabled: " + group + ", " + name); + } + String nameGroup = name + "#" + group; + Counter counter = counterMap.get(nameGroup); + if (counter == null) { + synchronized (BenchmarkCounters.class) { + counter = counterMap.get(nameGroup); + if (counter == null) { + counter = new Counter(counterMap.size(), group, new AtomicLong()); + counterMap.put(nameGroup, counter); + } + } + } + assert counter.group.equals(group) : "mismatching groups: " + counter.group + " vs. " + group; + int countersSize = config.jvmciCountersSize; + if (counter.index >= countersSize) { + throw new GraalError("too many counters, reduce number of counters or increase -XX:JVMCICounterSize=... (current value: " + countersSize + ")"); + } + return counter; + } + + private static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) { + if (!counterMap.isEmpty()) { + if (Options.DynamicCountersHumanReadable.getValue()) { + out.println("====== dynamic counters (" + counterMap.size() + " in total) ======"); + } + TreeSet set = new TreeSet<>(); + counterMap.forEach((nameGroup, counter) -> set.add(counter.group)); + for (String group : set) { + if (group != null) { + if (Options.BenchmarkCountersDumpStatic.getValue()) { + dumpCounters(out, seconds, counters, true, group, maxRows); + } + if (Options.BenchmarkCountersDumpDynamic.getValue()) { + dumpCounters(out, seconds, counters, false, group, maxRows); + } + } + } + if (Options.DynamicCountersHumanReadable.getValue()) { + out.println("============================"); + } + + clear(counters); + } + } + + private static synchronized void clear(long[] counters) { + delta = counters; + } + + private static synchronized void dumpCounters(PrintStream out, double seconds, long[] counters, boolean staticCounter, String group, int maxRows) { + + // collect the numbers + long[] array; + if (staticCounter) { + array = new long[counterMap.size()]; + for (Counter counter : counterMap.values()) { + array[counter.index] = counter.staticCounters.get(); + } + } else { + array = counters.clone(); + for (int i = 0; i < array.length; i++) { + array[i] -= delta[i]; + } + } + Set> counterEntrySet = counterMap.entrySet(); + if (Options.DynamicCountersHumanReadable.getValue()) { + dumpHumanReadable(out, seconds, staticCounter, group, maxRows, array, counterEntrySet); + } else { + dumpComputerReadable(out, staticCounter, group, array, counterEntrySet); + } + } + + private static String getName(String nameGroup, String group) { + return nameGroup.substring(0, nameGroup.length() - group.length() - 1); + } + + private static void dumpHumanReadable(PrintStream out, double seconds, boolean staticCounter, String group, int maxRows, long[] array, Set> counterEntrySet) { + // sort the counters by putting them into a sorted map + TreeMap sorted = new TreeMap<>(); + long sum = 0; + for (Map.Entry entry : counterEntrySet) { + Counter counter = entry.getValue(); + int index = counter.index; + if (counter.group.equals(group)) { + sum += array[index]; + sorted.put(array[index] * array.length + index, getName(entry.getKey(), group)); + } + } + + if (sum > 0) { + long cutoff = sorted.size() < 10 ? 1 : Math.max(1, sum / 100); + int cnt = sorted.size(); + + // remove everything below cutoff and keep at most maxRows + Iterator> iter = sorted.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + long counter = entry.getKey() / array.length; + if (counter < cutoff || cnt > maxRows) { + iter.remove(); + } + cnt--; + } + + String numFmt = Options.DynamicCountersPrintGroupSeparator.getValue() ? "%,19d" : "%19d"; + if (staticCounter) { + out.println("=========== " + group + " (static counters):"); + for (Map.Entry entry : sorted.entrySet()) { + long counter = entry.getKey() / array.length; + out.format(Locale.US, numFmt + " %3d%% %s\n", counter, percentage(counter, sum), entry.getValue()); + } + out.format(Locale.US, numFmt + " total\n", sum); + } else { + if (group.startsWith("~")) { + out.println("=========== " + group + " (dynamic counters), time = " + seconds + " s:"); + for (Map.Entry entry : sorted.entrySet()) { + long counter = entry.getKey() / array.length; + out.format(Locale.US, numFmt + "/s %3d%% %s\n", (long) (counter / seconds), percentage(counter, sum), entry.getValue()); + } + out.format(Locale.US, numFmt + "/s total\n", (long) (sum / seconds)); + } else { + out.println("=========== " + group + " (dynamic counters):"); + for (Map.Entry entry : sorted.entrySet()) { + long counter = entry.getKey() / array.length; + out.format(Locale.US, numFmt + " %3d%% %s\n", counter, percentage(counter, sum), entry.getValue()); + } + out.format(Locale.US, numFmt + " total\n", sum); + } + } + } + } + + private static final String CSV_FMT = CSVUtil.buildFormatString("%s", "%s", "%s", "%d"); + + private static void dumpComputerReadable(PrintStream out, boolean staticCounter, String group, long[] array, Set> counterEntrySet) { + String category = staticCounter ? "static counters" : "dynamic counters"; + for (Map.Entry entry : counterEntrySet) { + Counter counter = entry.getValue(); + if (counter.group.equals(group)) { + String name = getName(entry.getKey(), group); + int index = counter.index; + long value = array[index]; + CSVUtil.Escape.println(out, CSV_FMT, category, group, name, value); + } + } + } + + private static long percentage(long counter, long sum) { + return (counter * 200 + 1) / sum / 2; + } + + private abstract static class CallbackOutputStream extends OutputStream { + + protected final PrintStream delegate; + private final byte[][] patterns; + private final int[] positions; + + CallbackOutputStream(PrintStream delegate, String... patterns) { + this.delegate = delegate; + this.positions = new int[patterns.length]; + this.patterns = new byte[patterns.length][]; + for (int i = 0; i < patterns.length; i++) { + this.patterns[i] = patterns[i].getBytes(); + } + } + + protected abstract void patternFound(int index); + + @Override + public void write(int b) throws IOException { + try { + delegate.write(b); + for (int i = 0; i < patterns.length; i++) { + int j = positions[i]; + byte[] cs = patterns[i]; + byte patternChar = cs[j]; + if (patternChar == '~' && Character.isDigit(b)) { + // nothing to do... + } else { + if (patternChar == '~') { + patternChar = cs[++positions[i]]; + } + if (b == patternChar) { + positions[i]++; + } else { + positions[i] = 0; + } + } + if (positions[i] == patterns[i].length) { + positions[i] = 0; + patternFound(i); + } + } + } catch (RuntimeException e) { + e.printStackTrace(delegate); + throw e; + } + } + } + + public static void initialize(final HotSpotJVMCIRuntime jvmciRuntime) { + final class BenchmarkCountersOutputStream extends CallbackOutputStream { + + private long startTime; + private boolean running; + private boolean waitingForEnd; + + private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) { + super(delegate, new String[]{"\n", end, start}); + } + + @Override + protected void patternFound(int index) { + switch (index) { + case 2: + startTime = System.nanoTime(); + BenchmarkCounters.clear(jvmciRuntime.collectCounters()); + running = true; + break; + case 1: + if (running) { + waitingForEnd = true; + } + break; + case 0: + if (waitingForEnd) { + waitingForEnd = false; + running = false; + BenchmarkCounters.dump(getPrintStream(), (System.nanoTime() - startTime) / 1000000000d, jvmciRuntime.collectCounters(), 100); + } + break; + } + } + } + + if (Options.BenchmarkDynamicCounters.getValue() != null) { + String[] arguments = Options.BenchmarkDynamicCounters.getValue().split(","); + if (arguments.length == 0 || (arguments.length % 3) != 0) { + throw new GraalError("invalid arguments to BenchmarkDynamicCounters: (err|out),start,end,(err|out),start,end,... (~ matches multiple digits)"); + } + for (int i = 0; i < arguments.length; i += 3) { + if (arguments[i].equals("err")) { + System.setErr(new PrintStream(new BenchmarkCountersOutputStream(System.err, arguments[i + 1], arguments[i + 2]))); + } else if (arguments[i].equals("out")) { + System.setOut(new PrintStream(new BenchmarkCountersOutputStream(System.out, arguments[i + 1], arguments[i + 2]))); + } else { + throw new GraalError("invalid arguments to BenchmarkDynamicCounters: err|out"); + } + } + enabled = true; + } + if (Options.GenericDynamicCounters.getValue()) { + enabled = true; + } + if (Options.TimedDynamicCounters.getValue() > 0) { + Thread thread = new Thread() { + long lastTime = System.nanoTime(); + PrintStream out = getPrintStream(); + + @Override + public void run() { + while (true) { + try { + Thread.sleep(Options.TimedDynamicCounters.getValue()); + } catch (InterruptedException e) { + } + long time = System.nanoTime(); + dump(out, (time - lastTime) / 1000000000d, jvmciRuntime.collectCounters(), 10); + lastTime = time; + } + } + }; + thread.setDaemon(true); + thread.setPriority(Thread.MAX_PRIORITY); + thread.start(); + enabled = true; + } + if (enabled) { + clear(jvmciRuntime.collectCounters()); + } + } + + public static void shutdown(HotSpotJVMCIRuntime jvmciRuntime, long compilerStartTime) { + if (Options.GenericDynamicCounters.getValue()) { + dump(getPrintStream(), (System.nanoTime() - compilerStartTime) / 1000000000d, jvmciRuntime.collectCounters(), 100); + } + } + + private static PrintStream getPrintStream() { + if (Options.BenchmarkCountersFile.getValue() != null) { + try { + Path path = UniquePathUtilities.getPathGlobal(Options.BenchmarkCountersFile, GraalDebugConfig.Options.DumpPath, "csv"); + TTY.println("Writing benchmark counters to '%s'", path); + return new PrintStream(path.toFile()); + } catch (FileNotFoundException e) { + TTY.out().println(e.getMessage()); + TTY.out().println("Fallback to default"); + } + } + return TTY.out; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/lir/HotSpotZapRegistersPhase.java 2016-12-07 13:50:10.963269159 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2016, 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.lir; + +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import java.util.ArrayList; + +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Indent; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInsertionBuffer; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool; +import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool.ZapRegistersAfterInstruction; +import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool.ZapStackArgumentSpaceBeforeInstruction; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Inserts a {@link DiagnosticLIRGeneratorTool#createZapRegisters ZapRegistersOp} after + * {@link ZapRegistersAfterInstruction} for stubs and + * {@link DiagnosticLIRGeneratorTool#zapArgumentSpace ZapArgumentSpaceOp} after + * {@link ZapStackArgumentSpaceBeforeInstruction} for all compiles. + */ +public final class HotSpotZapRegistersPhase extends PostAllocationOptimizationPhase { + + @Override + protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) { + Stub stub = ((HotSpotLIRGenerationResult) lirGenRes).getStub(); + boolean zapRegisters = stub != null && !stub.preservesRegisters(); + boolean zapStack = false; + for (AllocatableValue arg : lirGenRes.getCallingConvention().getArguments()) { + if (isStackSlot(arg)) { + zapStack = true; + break; + } + } + if (zapRegisters || zapStack) { + LIR lir = lirGenRes.getLIR(); + processLIR(context.diagnosticLirGenTool, (HotSpotLIRGenerationResult) lirGenRes, lir, zapRegisters, zapStack); + } + } + + private static void processLIR(DiagnosticLIRGeneratorTool diagnosticLirGenTool, HotSpotLIRGenerationResult res, LIR lir, boolean zapRegisters, boolean zapStack) { + LIRInsertionBuffer buffer = new LIRInsertionBuffer(); + for (AbstractBlockBase block : lir.codeEmittingOrder()) { + if (block != null) { + processBlock(diagnosticLirGenTool, res, lir, buffer, block, zapRegisters, zapStack); + } + } + } + + @SuppressWarnings("try") + private static void processBlock(DiagnosticLIRGeneratorTool diagnosticLirGenTool, HotSpotLIRGenerationResult res, LIR lir, LIRInsertionBuffer buffer, AbstractBlockBase block, + boolean zapRegisters, boolean zapStack) { + try (Indent indent = Debug.logAndIndent("Process block %s", block)) { + ArrayList instructions = lir.getLIRforBlock(block); + buffer.init(instructions); + for (int index = 0; index < instructions.size(); index++) { + LIRInstruction inst = instructions.get(index); + if (zapStack && inst instanceof ZapStackArgumentSpaceBeforeInstruction) { + LIRInstruction zap = diagnosticLirGenTool.zapArgumentSpace(); + if (zap != null) { + buffer.append(index, zap); + } + } + if (zapRegisters && inst instanceof ZapRegistersAfterInstruction) { + LIRFrameState state = getLIRState(inst); + if (state != null) { + SaveRegistersOp zap = diagnosticLirGenTool.createZapRegisters(); + SaveRegistersOp old = res.getCalleeSaveInfo().put(state, zap); + assert old == null : "Already another SaveRegisterOp registered! " + old; + buffer.append(index + 1, (LIRInstruction) zap); + Debug.log("Insert ZapRegister after %s", inst); + } + } + } + buffer.finish(); + } + } + + /** + * Returns the {@link LIRFrameState} of an instruction. + */ + private static LIRFrameState getLIRState(LIRInstruction inst) { + final LIRFrameState[] lirState = {null}; + inst.forEachState(state -> { + assert lirState[0] == null : "Multiple states: " + inst; + lirState[0] = state; + }); + assert lirState[0] != null : "No state: " + inst; + return lirState[0]; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java 2016-12-07 13:50:11.255281994 -0800 @@ -0,0 +1,742 @@ +/* + * Copyright (c) 2011, 2016, 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.meta; + +import static org.graalvm.compiler.core.common.GraalOptions.AlwaysInlineVTableStubs; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.core.common.GraalOptions.InlineVTableStubs; +import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace; +import static org.graalvm.compiler.core.common.LocationIdentity.any; +import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_KLASS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.COMPRESSED_HUB_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_WRITE_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_LAYOUT_HELPER_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.INIT_LOCATION; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; + +import java.lang.ref.Reference; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.nodes.CompressionNode; +import org.graalvm.compiler.hotspot.nodes.CompressionNode.CompressionOp; +import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; +import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; +import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier; +import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode; +import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode; +import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode; +import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp; +import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp; +import org.graalvm.compiler.hotspot.replacements.AssertionSnippets; +import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode; +import org.graalvm.compiler.hotspot.replacements.HashCodeSnippets; +import org.graalvm.compiler.hotspot.replacements.HubGetClassNode; +import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode; +import org.graalvm.compiler.hotspot.replacements.InstanceOfSnippets; +import org.graalvm.compiler.hotspot.replacements.KlassLayoutHelperNode; +import org.graalvm.compiler.hotspot.replacements.LoadExceptionObjectSnippets; +import org.graalvm.compiler.hotspot.replacements.MonitorSnippets; +import org.graalvm.compiler.hotspot.replacements.NewObjectSnippets; +import org.graalvm.compiler.hotspot.replacements.StringToBytesSnippets; +import org.graalvm.compiler.hotspot.replacements.UnsafeLoadSnippets; +import org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets; +import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets; +import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode; +import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySlowPathNode; +import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySnippets; +import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyUnrollNode; +import org.graalvm.compiler.hotspot.replacements.arraycopy.UnsafeArrayCopySnippets; +import org.graalvm.compiler.hotspot.replacements.profiling.ProfileSnippets; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.AbstractDeoptimizeNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.LoweredCallTargetNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.SafepointNode; +import org.graalvm.compiler.nodes.StartNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.UnwindNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.calc.IntegerDivRemNode; +import org.graalvm.compiler.nodes.calc.IsNullNode; +import org.graalvm.compiler.nodes.calc.RemNode; +import org.graalvm.compiler.nodes.debug.StringToBytesNode; +import org.graalvm.compiler.nodes.debug.VerifyHeapNode; +import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.extended.GetClassNode; +import org.graalvm.compiler.nodes.extended.GuardedUnsafeLoadNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.extended.LoadHubNode; +import org.graalvm.compiler.nodes.extended.LoadMethodNode; +import org.graalvm.compiler.nodes.extended.OSRLocalNode; +import org.graalvm.compiler.nodes.extended.OSRStartNode; +import org.graalvm.compiler.nodes.extended.StoreHubNode; +import org.graalvm.compiler.nodes.extended.UnsafeLoadNode; +import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode; +import org.graalvm.compiler.nodes.java.DynamicNewArrayNode; +import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode; +import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode; +import org.graalvm.compiler.nodes.java.InstanceOfNode; +import org.graalvm.compiler.nodes.java.LoadExceptionObjectNode; +import org.graalvm.compiler.nodes.java.MethodCallTargetNode; +import org.graalvm.compiler.nodes.java.MonitorExitNode; +import org.graalvm.compiler.nodes.java.NewArrayNode; +import org.graalvm.compiler.nodes.java.NewInstanceNode; +import org.graalvm.compiler.nodes.java.NewMultiArrayNode; +import org.graalvm.compiler.nodes.java.RawMonitorEnterNode; +import org.graalvm.compiler.nodes.memory.FloatingReadNode; +import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.WriteNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.spi.LoweringProvider; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.spi.StampProvider; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.replacements.DefaultJavaLoweringProvider; +import org.graalvm.compiler.replacements.nodes.AssertionNode; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotCallingConventionType; +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaField; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * HotSpot implementation of {@link LoweringProvider}. + */ +public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider implements HotSpotLoweringProvider { + + protected final HotSpotGraalRuntimeProvider runtime; + protected final HotSpotRegistersProvider registers; + protected final HotSpotConstantReflectionProvider constantReflection; + + protected InstanceOfSnippets.Templates instanceofSnippets; + protected NewObjectSnippets.Templates newObjectSnippets; + protected MonitorSnippets.Templates monitorSnippets; + protected WriteBarrierSnippets.Templates writeBarrierSnippets; + protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets; + protected UnsafeLoadSnippets.Templates unsafeLoadSnippets; + protected AssertionSnippets.Templates assertionSnippets; + protected ArrayCopySnippets.Templates arraycopySnippets; + protected StringToBytesSnippets.Templates stringToBytesSnippets; + protected HashCodeSnippets.Templates hashCodeSnippets; + protected ResolveConstantSnippets.Templates resolveConstantSnippets; + protected ProfileSnippets.Templates profileSnippets; + + public DefaultHotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, + HotSpotConstantReflectionProvider constantReflection, TargetDescription target) { + super(metaAccess, foreignCalls, target); + this.runtime = runtime; + this.registers = registers; + this.constantReflection = constantReflection; + } + + @Override + public void initialize(HotSpotProviders providers, GraalHotSpotVMConfig config) { + super.initialize(providers, providers.getSnippetReflection()); + + assert target == providers.getCodeCache().getTarget(); + instanceofSnippets = new InstanceOfSnippets.Templates(providers, target); + newObjectSnippets = new NewObjectSnippets.Templates(providers, target, config); + monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking); + writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null); + exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target); + unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target); + assertionSnippets = new AssertionSnippets.Templates(providers, target); + arraycopySnippets = new ArrayCopySnippets.Templates(providers, target); + stringToBytesSnippets = new StringToBytesSnippets.Templates(providers, target); + hashCodeSnippets = new HashCodeSnippets.Templates(providers, target); + if (GeneratePIC.getValue()) { + resolveConstantSnippets = new ResolveConstantSnippets.Templates(providers, target); + profileSnippets = new ProfileSnippets.Templates(providers, target); + } + providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target)); + } + + @Override + public void lower(Node n, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) n.graph(); + if (n instanceof Invoke) { + lowerInvoke((Invoke) n, tool, graph); + } else if (n instanceof LoadMethodNode) { + lowerLoadMethodNode((LoadMethodNode) n); + } else if (n instanceof GetClassNode) { + lowerGetClassNode((GetClassNode) n, tool, graph); + } else if (n instanceof StoreHubNode) { + lowerStoreHubNode((StoreHubNode) n, graph); + } else if (n instanceof OSRStartNode) { + lowerOSRStartNode((OSRStartNode) n); + } else if (n instanceof BytecodeExceptionNode) { + lowerBytecodeExceptionNode((BytecodeExceptionNode) n); + } else if (n instanceof InstanceOfNode) { + InstanceOfNode instanceOfNode = (InstanceOfNode) n; + if (graph.getGuardsStage().areDeoptsFixed()) { + instanceofSnippets.lower(instanceOfNode, tool); + } else { + if (instanceOfNode.allowsNull()) { + ValueNode object = instanceOfNode.getValue(); + LogicNode newTypeCheck = graph.addOrUniqueWithInputs(InstanceOfNode.create(instanceOfNode.type(), object, instanceOfNode.profile(), instanceOfNode.getAnchor())); + LogicNode newNode = LogicNode.or(graph.unique(IsNullNode.create(object)), newTypeCheck, GraalDirectives.UNLIKELY_PROBABILITY); + instanceOfNode.replaceAndDelete(newNode); + } + } + } else if (n instanceof InstanceOfDynamicNode) { + InstanceOfDynamicNode instanceOfDynamicNode = (InstanceOfDynamicNode) n; + if (graph.getGuardsStage().areDeoptsFixed()) { + instanceofSnippets.lower(instanceOfDynamicNode, tool); + } else { + ValueNode mirror = instanceOfDynamicNode.getMirrorOrHub(); + if (mirror.stamp().getStackKind() == JavaKind.Object) { + ClassGetHubNode classGetHub = graph.unique(new ClassGetHubNode(mirror)); + instanceOfDynamicNode.setMirror(classGetHub); + } + + if (instanceOfDynamicNode.allowsNull()) { + ValueNode object = instanceOfDynamicNode.getObject(); + LogicNode newTypeCheck = graph.addOrUniqueWithInputs( + InstanceOfDynamicNode.create(graph.getAssumptions(), tool.getConstantReflection(), instanceOfDynamicNode.getMirrorOrHub(), object, false)); + LogicNode newNode = LogicNode.or(graph.unique(IsNullNode.create(object)), newTypeCheck, GraalDirectives.UNLIKELY_PROBABILITY); + instanceOfDynamicNode.replaceAndDelete(newNode); + } + } + } else if (n instanceof ClassIsAssignableFromNode) { + if (graph.getGuardsStage().areDeoptsFixed()) { + instanceofSnippets.lower((ClassIsAssignableFromNode) n, tool); + } + } else if (n instanceof NewInstanceNode) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { + newObjectSnippets.lower((NewInstanceNode) n, registers, tool); + } + } else if (n instanceof DynamicNewInstanceNode) { + DynamicNewInstanceNode newInstanceNode = (DynamicNewInstanceNode) n; + if (newInstanceNode.getClassClass() == null) { + JavaConstant classClassMirror = constantReflection.forObject(Class.class); + ConstantNode classClass = ConstantNode.forConstant(classClassMirror, tool.getMetaAccess(), graph); + newInstanceNode.setClassClass(classClass); + } + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { + newObjectSnippets.lower(newInstanceNode, registers, tool); + } + } else if (n instanceof NewArrayNode) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { + newObjectSnippets.lower((NewArrayNode) n, registers, tool); + } + } else if (n instanceof DynamicNewArrayNode) { + DynamicNewArrayNode dynamicNewArrayNode = (DynamicNewArrayNode) n; + if (dynamicNewArrayNode.getVoidClass() == null) { + JavaConstant voidClassMirror = constantReflection.forObject(void.class); + ConstantNode voidClass = ConstantNode.forConstant(voidClassMirror, tool.getMetaAccess(), graph); + dynamicNewArrayNode.setVoidClass(voidClass); + } + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { + newObjectSnippets.lower(dynamicNewArrayNode, registers, tool); + } + } else if (n instanceof VerifyHeapNode) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { + newObjectSnippets.lower((VerifyHeapNode) n, registers, tool); + } + } else if (n instanceof RawMonitorEnterNode) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { + monitorSnippets.lower((RawMonitorEnterNode) n, registers, tool); + } + } else if (n instanceof MonitorExitNode) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { + monitorSnippets.lower((MonitorExitNode) n, tool); + } + } else if (n instanceof ArrayCopyNode) { + arraycopySnippets.lower((ArrayCopyNode) n, tool); + } else if (n instanceof ArrayCopySlowPathNode) { + arraycopySnippets.lower((ArrayCopySlowPathNode) n, tool); + } else if (n instanceof ArrayCopyUnrollNode) { + arraycopySnippets.lower((ArrayCopyUnrollNode) n, tool); + } else if (n instanceof G1PreWriteBarrier) { + writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool); + } else if (n instanceof G1PostWriteBarrier) { + writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool); + } else if (n instanceof G1ReferentFieldReadBarrier) { + writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool); + } else if (n instanceof SerialWriteBarrier) { + writeBarrierSnippets.lower((SerialWriteBarrier) n, tool); + } else if (n instanceof SerialArrayRangeWriteBarrier) { + writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool); + } else if (n instanceof G1ArrayRangePreWriteBarrier) { + writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool); + } else if (n instanceof G1ArrayRangePostWriteBarrier) { + writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool); + } else if (n instanceof NewMultiArrayNode) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { + newObjectSnippets.lower((NewMultiArrayNode) n, tool); + } + } else if (n instanceof LoadExceptionObjectNode) { + exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool); + } else if (n instanceof AssertionNode) { + assertionSnippets.lower((AssertionNode) n, tool); + } else if (n instanceof StringToBytesNode) { + if (graph.getGuardsStage().areDeoptsFixed()) { + stringToBytesSnippets.lower((StringToBytesNode) n, tool); + } + } else if (n instanceof IntegerDivRemNode) { + // Nothing to do for division nodes. The HotSpot signal handler catches divisions by + // zero and the MIN_VALUE / -1 cases. + } else if (n instanceof AbstractDeoptimizeNode || n instanceof UnwindNode || n instanceof RemNode || n instanceof SafepointNode) { + /* No lowering, we generate LIR directly for these nodes. */ + } else if (n instanceof ClassGetHubNode) { + lowerClassGetHubNode((ClassGetHubNode) n, tool); + } else if (n instanceof HubGetClassNode) { + lowerHubGetClassNode((HubGetClassNode) n, tool); + } else if (n instanceof KlassLayoutHelperNode) { + lowerKlassLayoutHelperNode((KlassLayoutHelperNode) n, tool); + } else if (n instanceof ComputeObjectAddressNode) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { + lowerComputeObjectAddressNode((ComputeObjectAddressNode) n); + } + } else if (n instanceof IdentityHashCodeNode) { + hashCodeSnippets.lower((IdentityHashCodeNode) n, tool); + } else if (n instanceof ResolveConstantNode) { + resolveConstantSnippets.lower((ResolveConstantNode) n, tool); + } else if (n instanceof ResolveMethodAndLoadCountersNode) { + resolveConstantSnippets.lower((ResolveMethodAndLoadCountersNode) n, tool); + } else if (n instanceof InitializeKlassNode) { + resolveConstantSnippets.lower((InitializeKlassNode) n, tool); + } else if (n instanceof ProfileNode) { + profileSnippets.lower((ProfileNode) n, tool); + } else { + super.lower(n, tool); + } + } + + private static void lowerComputeObjectAddressNode(ComputeObjectAddressNode n) { + /* + * Lower the node into a ComputeObjectAddress node and an Add but ensure that it's below any + * potential safepoints and above it's uses. + */ + for (Node use : n.usages().snapshot()) { + if (use instanceof FixedNode) { + FixedNode fixed = (FixedNode) use; + StructuredGraph graph = n.graph(); + GetObjectAddressNode address = graph.add(new GetObjectAddressNode(n.getObject())); + graph.addBeforeFixed(fixed, address); + AddNode add = graph.addOrUnique(new AddNode(address, n.getOffset())); + use.replaceFirstInput(n, add); + } else { + throw GraalError.shouldNotReachHere("Unexpected floating use of ComputeObjectAddressNode " + n); + } + } + GraphUtil.unlinkFixedNode(n); + n.safeDelete(); + } + + private void lowerKlassLayoutHelperNode(KlassLayoutHelperNode n, LoweringTool tool) { + if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) { + return; + } + StructuredGraph graph = n.graph(); + assert !n.getHub().isConstant(); + AddressNode address = createOffsetAddress(graph, n.getHub(), runtime.getVMConfig().klassLayoutHelperOffset); + n.replaceAtUsagesAndDelete(graph.unique(new FloatingReadNode(address, KLASS_LAYOUT_HELPER_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE))); + } + + private void lowerHubGetClassNode(HubGetClassNode n, LoweringTool tool) { + if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) { + return; + } + + StructuredGraph graph = n.graph(); + assert !n.getHub().isConstant(); + AddressNode address = createOffsetAddress(graph, n.getHub(), runtime.getVMConfig().classMirrorOffset); + FloatingReadNode read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE)); + n.replaceAtUsagesAndDelete(read); + } + + private void lowerClassGetHubNode(ClassGetHubNode n, LoweringTool tool) { + if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) { + return; + } + + StructuredGraph graph = n.graph(); + assert !n.getValue().isConstant(); + AddressNode address = createOffsetAddress(graph, n.getValue(), runtime.getVMConfig().klassOffset); + FloatingReadNode read = graph.unique(new FloatingReadNode(address, CLASS_KLASS_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE)); + n.replaceAtUsagesAndDelete(read); + } + + private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) { + if (invoke.callTarget() instanceof MethodCallTargetNode) { + MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + NodeInputList parameters = callTarget.arguments(); + ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); + if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !StampTool.isPointerNonNull(receiver)) { + GuardingNode receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool); + PiNode nonNullReceiver = graph.unique(new PiNode(receiver, ((ObjectStamp) receiver.stamp()).join(StampFactory.objectNonNull()), (ValueNode) receiverNullCheck)); + parameters.set(0, nonNullReceiver); + receiver = nonNullReceiver; + } + JavaType[] signature = callTarget.targetMethod().getSignature().toParameterTypes(callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass()); + + LoweredCallTargetNode loweredCallTarget = null; + if (InlineVTableStubs.getValue() && callTarget.invokeKind().isIndirect() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) { + HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); + ResolvedJavaType receiverType = invoke.getReceiverType(); + if (hsMethod.isInVirtualMethodTable(receiverType)) { + JavaKind wordKind = runtime.getTarget().wordJavaKind; + ValueNode hub = createReadHub(graph, receiver, tool); + + ReadNode metaspaceMethod = createReadVirtualMethod(graph, hub, hsMethod, receiverType); + // We use LocationNode.ANY_LOCATION for the reads that access the + // compiled code entry as HotSpot does not guarantee they are final + // values. + int methodCompiledEntryOffset = runtime.getVMConfig().methodCompiledEntryOffset; + AddressNode address = createOffsetAddress(graph, metaspaceMethod, methodCompiledEntryOffset); + ReadNode compiledEntry = graph.add(new ReadNode(address, any(), StampFactory.forKind(wordKind), BarrierType.NONE)); + + loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters.toArray(new ValueNode[parameters.size()]), callTarget.returnStamp(), + signature, callTarget.targetMethod(), + HotSpotCallingConventionType.JavaCall, callTarget.invokeKind())); + + graph.addBeforeFixed(invoke.asNode(), metaspaceMethod); + graph.addAfterFixed(metaspaceMethod, compiledEntry); + } + } + + if (loweredCallTarget == null) { + loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters.toArray(new ValueNode[parameters.size()]), callTarget.returnStamp(), + signature, callTarget.targetMethod(), + HotSpotCallingConventionType.JavaCall, + callTarget.invokeKind())); + } + callTarget.replaceAndDelete(loweredCallTarget); + } + } + + @Override + protected Stamp loadStamp(Stamp stamp, JavaKind kind, boolean compressible) { + if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) { + return NarrowOopStamp.compressed((ObjectStamp) stamp, runtime.getVMConfig().getOopEncoding()); + } + return super.loadStamp(stamp, kind, compressible); + } + + @Override + protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, boolean compressible) { + if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) { + return new CompressionNode(CompressionOp.Uncompress, value, runtime.getVMConfig().getOopEncoding()); + } + return super.implicitLoadConvert(kind, value, compressible); + } + + @Override + public ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField f) { + HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) f; + JavaConstant base = constantReflection.asJavaClass(field.getDeclaringClass()); + return ConstantNode.forConstant(base, metaAccess, graph); + } + + @Override + protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean compressible) { + if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) { + return new CompressionNode(CompressionOp.Compress, value, runtime.getVMConfig().getOopEncoding()); + } + return super.implicitStoreConvert(kind, value, compressible); + } + + @Override + protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor) { + /* + * Anchor the read of the element klass to the cfg, because it is only valid when arrayClass + * is an object class, which might not be the case in other parts of the compiled method. + */ + AddressNode address = createOffsetAddress(graph, arrayHub, runtime.getVMConfig().arrayClassElementOffset); + return graph.unique(new FloatingReadNode(address, OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION, null, KlassPointerStamp.klassNonNull(), AbstractBeginNode.prevBegin(anchor))); + } + + @Override + protected void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) { + StructuredGraph graph = load.graph(); + if (!(load instanceof GuardedUnsafeLoadNode) && !graph.getGuardsStage().allowsFloatingGuards() && addReadBarrier(load)) { + unsafeLoadSnippets.lower(load, tool); + } else { + super.lowerUnsafeLoadNode(load, tool); + } + } + + private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) { + StructuredGraph graph = loadMethodNode.graph(); + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) loadMethodNode.getMethod(); + ReadNode metaspaceMethod = createReadVirtualMethod(graph, loadMethodNode.getHub(), method, loadMethodNode.getReceiverType()); + graph.replaceFixed(loadMethodNode, metaspaceMethod); + } + + private static void lowerGetClassNode(GetClassNode getClass, LoweringTool tool, StructuredGraph graph) { + StampProvider stampProvider = tool.getStampProvider(); + LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, getClass.getObject())); + HubGetClassNode hubGetClass = graph.unique(new HubGetClassNode(tool.getMetaAccess(), hub)); + getClass.replaceAtUsagesAndDelete(hubGetClass); + hub.lower(tool); + hubGetClass.lower(tool); + } + + private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) { + WriteNode hub = createWriteHub(graph, storeHub.getObject(), storeHub.getValue()); + graph.replaceFixed(storeHub, hub); + } + + @Override + public BarrierType fieldInitializationBarrier(JavaKind entryKind) { + return (entryKind == JavaKind.Object && !runtime.getVMConfig().useDeferredInitBarriers) ? BarrierType.IMPRECISE : BarrierType.NONE; + } + + @Override + public BarrierType arrayInitializationBarrier(JavaKind entryKind) { + return (entryKind == JavaKind.Object && !runtime.getVMConfig().useDeferredInitBarriers) ? BarrierType.PRECISE : BarrierType.NONE; + } + + private void lowerOSRStartNode(OSRStartNode osrStart) { + StructuredGraph graph = osrStart.graph(); + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + StartNode newStart = graph.add(new StartNode()); + ParameterNode buffer = graph.addWithoutUnique(new ParameterNode(0, StampPair.createSingle(StampFactory.forKind(runtime.getTarget().wordJavaKind)))); + ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer)); + migrationEnd.setStateAfter(osrStart.stateAfter()); + + newStart.setNext(migrationEnd); + FixedNode next = osrStart.next(); + osrStart.setNext(null); + migrationEnd.setNext(next); + graph.setStart(newStart); + + // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block) + int localsOffset = (graph.method().getMaxLocals() - 1) * 8; + for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.TYPE)) { + int size = osrLocal.getStackKind().getSlotCount(); + int offset = localsOffset - (osrLocal.index() + size - 1) * 8; + AddressNode address = createOffsetAddress(graph, buffer, offset); + ReadNode load = graph.add(new ReadNode(address, any(), osrLocal.stamp(), BarrierType.NONE)); + osrLocal.replaceAndDelete(load); + graph.addBeforeFixed(migrationEnd, load); + } + osrStart.replaceAtUsagesAndDelete(newStart); + } + } + + static final class Exceptions { + protected static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException; + protected static final NullPointerException cachedNullPointerException; + + static { + cachedArrayIndexOutOfBoundsException = new ArrayIndexOutOfBoundsException(); + cachedArrayIndexOutOfBoundsException.setStackTrace(new StackTraceElement[0]); + cachedNullPointerException = new NullPointerException(); + cachedNullPointerException.setStackTrace(new StackTraceElement[0]); + } + } + + public static final class RuntimeCalls { + public static final ForeignCallDescriptor CREATE_ARRAY_STORE_EXCEPTION = new ForeignCallDescriptor("createArrayStoreException", ArrayStoreException.class, Object.class); + public static final ForeignCallDescriptor CREATE_CLASS_CAST_EXCEPTION = new ForeignCallDescriptor("createClassCastException", ClassCastException.class, Object.class, KlassPointer.class); + public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", NullPointerException.class); + public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class); + } + + private boolean throwCachedException(BytecodeExceptionNode node) { + Throwable exception; + if (node.getExceptionClass() == NullPointerException.class) { + exception = Exceptions.cachedNullPointerException; + } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) { + exception = Exceptions.cachedArrayIndexOutOfBoundsException; + } else { + return false; + } + + StructuredGraph graph = node.graph(); + FloatingNode exceptionNode = ConstantNode.forConstant(constantReflection.forObject(exception), metaAccess, graph); + graph.replaceFixedWithFloating(node, exceptionNode); + return true; + } + + private void lowerBytecodeExceptionNode(BytecodeExceptionNode node) { + if (OmitHotExceptionStacktrace.getValue()) { + if (throwCachedException(node)) { + return; + } + } + + ForeignCallDescriptor descriptor; + if (node.getExceptionClass() == NullPointerException.class) { + descriptor = RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION; + } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) { + descriptor = RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION; + } else if (node.getExceptionClass() == ArrayStoreException.class) { + descriptor = RuntimeCalls.CREATE_ARRAY_STORE_EXCEPTION; + } else if (node.getExceptionClass() == ClassCastException.class) { + descriptor = RuntimeCalls.CREATE_CLASS_CAST_EXCEPTION; + } else { + throw GraalError.shouldNotReachHere(); + } + + StructuredGraph graph = node.graph(); + ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, descriptor, node.stamp(), node.getArguments())); + graph.replaceFixedWithFixed(node, foreignCallNode); + } + + private boolean addReadBarrier(UnsafeLoadNode load) { + if (runtime.getVMConfig().useG1GC && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getStackKind() == JavaKind.Object && + load.accessKind() == JavaKind.Object && !StampTool.isPointerAlwaysNull(load.object())) { + ResolvedJavaType type = StampTool.typeOrNull(load.object()); + if (type != null && !type.isArray()) { + return true; + } + } + return false; + } + + private ReadNode createReadVirtualMethod(StructuredGraph graph, ValueNode hub, HotSpotResolvedJavaMethod method, ResolvedJavaType receiverType) { + return createReadVirtualMethod(graph, hub, method.vtableEntryOffset(receiverType)); + } + + private ReadNode createReadVirtualMethod(StructuredGraph graph, ValueNode hub, int vtableEntryOffset) { + assert vtableEntryOffset > 0; + // We use LocationNode.ANY_LOCATION for the reads that access the vtable + // entry as HotSpot does not guarantee that this is a final value. + Stamp methodStamp = MethodPointerStamp.method(); + AddressNode address = createOffsetAddress(graph, hub, vtableEntryOffset); + ReadNode metaspaceMethod = graph.add(new ReadNode(address, any(), methodStamp, BarrierType.NONE)); + return metaspaceMethod; + } + + @Override + protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, LoweringTool tool) { + if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) { + return graph.unique(new LoadHubNode(tool.getStampProvider(), object)); + } + assert !object.isConstant() || object.isNullConstant(); + + KlassPointerStamp hubStamp = KlassPointerStamp.klassNonNull(); + if (runtime.getVMConfig().useCompressedClassPointers) { + hubStamp = hubStamp.compressed(runtime.getVMConfig().getKlassEncoding()); + } + + AddressNode address = createOffsetAddress(graph, object, runtime.getVMConfig().hubOffset); + LocationIdentity hubLocation = runtime.getVMConfig().useCompressedClassPointers ? COMPRESSED_HUB_LOCATION : HUB_LOCATION; + FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(address, hubLocation, null, hubStamp, null, BarrierType.NONE)); + if (runtime.getVMConfig().useCompressedClassPointers) { + return CompressionNode.uncompress(memoryRead, runtime.getVMConfig().getKlassEncoding()); + } else { + return memoryRead; + } + } + + private WriteNode createWriteHub(StructuredGraph graph, ValueNode object, ValueNode value) { + assert !object.isConstant() || object.asConstant().isDefaultForKind(); + + ValueNode writeValue = value; + if (runtime.getVMConfig().useCompressedClassPointers) { + writeValue = CompressionNode.compress(value, runtime.getVMConfig().getKlassEncoding()); + } + + AddressNode address = createOffsetAddress(graph, object, runtime.getVMConfig().hubOffset); + return graph.add(new WriteNode(address, HUB_WRITE_LOCATION, writeValue, BarrierType.NONE)); + } + + @Override + protected BarrierType fieldLoadBarrierType(ResolvedJavaField f) { + HotSpotResolvedJavaField loadField = (HotSpotResolvedJavaField) f; + BarrierType barrierType = BarrierType.NONE; + if (runtime.getVMConfig().useG1GC && loadField.getJavaKind() == JavaKind.Object && metaAccess.lookupJavaType(Reference.class).equals(loadField.getDeclaringClass()) && + loadField.getName().equals("referent")) { + barrierType = BarrierType.PRECISE; + } + return barrierType; + } + + @Override + public int fieldOffset(ResolvedJavaField f) { + HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) f; + return field.offset(); + } + + @Override + public int arrayScalingFactor(JavaKind kind) { + if (runtime.getVMConfig().useCompressedOops && kind == JavaKind.Object) { + return super.arrayScalingFactor(JavaKind.Int); + } else { + return super.arrayScalingFactor(kind); + } + } + + @Override + public int arrayBaseOffset(JavaKind kind) { + return getArrayBaseOffset(kind); + } + + @Override + public int arrayLengthOffset() { + return runtime.getVMConfig().arrayOopDescLengthOffset(); + } + + @Override + public LocationIdentity initLocationIdentity() { + return INIT_LOCATION; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotAOTProfilingPlugin.java 2016-12-07 13:50:11.521293686 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016, 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.meta; + +import org.graalvm.compiler.hotspot.FingerprintUtil; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class HotSpotAOTProfilingPlugin extends HotSpotProfilingPlugin { + public static class Options { + @Option(help = "Do profiling and callbacks to tiered runtime", type = OptionType.User)// + public static final OptionValue TieredAOT = new OptionValue<>(false); + @Option(help = "Invocation notification frequency", type = OptionType.Expert)// + public static final OptionValue TierAInvokeNotifyFreqLog = new OptionValue<>(13); + @Option(help = "Inlinee invocation notification frequency (-1 means count, but do not notify)", type = OptionType.Expert)// + public static final OptionValue TierAInvokeInlineeNotifyFreqLog = new OptionValue<>(-1); + @Option(help = "Invocation profile probability", type = OptionType.Expert)// + public static final OptionValue TierAInvokeProfileProbabilityLog = new OptionValue<>(8); + @Option(help = "Backedge notification frequency", type = OptionType.Expert)// + public static final OptionValue TierABackedgeNotifyFreqLog = new OptionValue<>(16); + @Option(help = "Backedge profile probability", type = OptionType.Expert)// + public static final OptionValue TierABackedgeProfileProbabilityLog = new OptionValue<>(12); + } + + @Override + public boolean shouldProfile(GraphBuilderContext builder, ResolvedJavaMethod method) { + return super.shouldProfile(builder, method) && FingerprintUtil.getFingerprint(((HotSpotResolvedObjectType) method.getDeclaringClass())) != 0; + } + + @Override + public int invokeNotifyFreqLog() { + return Options.TierAInvokeNotifyFreqLog.getValue(); + } + + @Override + public int invokeInlineeNotifyFreqLog() { + return Options.TierAInvokeInlineeNotifyFreqLog.getValue(); + } + + @Override + public int invokeProfilePobabilityLog() { + return Options.TierAInvokeProfileProbabilityLog.getValue(); + } + + @Override + public int backedgeNotifyFreqLog() { + return Options.TierABackedgeNotifyFreqLog.getValue(); + } + + @Override + public int backedgeProfilePobabilityLog() { + return Options.TierABackedgeProfileProbabilityLog.getValue(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotClassInitializationPlugin.java 2016-12-07 13:50:11.785305290 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 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.meta; + +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; + +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +public final class HotSpotClassInitializationPlugin implements ClassInitializationPlugin { + @Override + public boolean shouldApply(GraphBuilderContext builder, ResolvedJavaType type) { + if (!builder.parsingIntrinsic()) { + ResolvedJavaMethod method = builder.getGraph().method(); + ResolvedJavaType methodHolder = method.getDeclaringClass(); + // We can elide initialization nodes if type >=: methodHolder. + // The type is already initialized by either "new" or "invokestatic". + + // Emit initialization node if type is an interface since: + // JLS 12.4: Before a class is initialized, its direct superclass must be initialized, + // but interfaces implemented by the class are not initialized. + // and a class or interface type T will be initialized immediately + // before the first occurrence of accesses listed in JLS 12.4.1. + + return !type.isAssignableFrom(methodHolder) || type.isInterface(); + } + return false; + } + + @Override + public ValueNode apply(GraphBuilderContext builder, ResolvedJavaType type, FrameState frameState) { + assert shouldApply(builder, type); + Stamp hubStamp = builder.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull()); + ConstantNode hub = builder.append(ConstantNode.forConstant(hubStamp, ((HotSpotResolvedObjectType) type).klass(), builder.getMetaAccess(), builder.getGraph())); + InitializeKlassNode initialize = builder.append(new InitializeKlassNode(hub)); + initialize.setStateBefore(frameState); + return initialize; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotConstantFieldProvider.java 2016-12-07 13:50:12.050316939 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016, 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.meta; + +import org.graalvm.compiler.core.common.spi.JavaConstantFieldProvider; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; + +import jdk.vm.ci.hotspot.HotSpotResolvedJavaField; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Implements the default constant folding semantics for Java fields in the HotSpot VM. + */ +public class HotSpotConstantFieldProvider extends JavaConstantFieldProvider { + + private final GraalHotSpotVMConfig config; + + public HotSpotConstantFieldProvider(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) { + super(metaAccess); + this.config = config; + } + + @Override + protected boolean isStableField(ResolvedJavaField field, ConstantFieldTool tool) { + if (!config.foldStableValues) { + return false; + } + if (field.isStatic() && !isStaticFieldConstant(field)) { + return false; + } + + if (((HotSpotResolvedJavaField) field).isStable()) { + return true; + } + return super.isStableField(field, tool); + } + + @Override + protected boolean isFinalField(ResolvedJavaField field, ConstantFieldTool tool) { + if (field.isStatic() && !isStaticFieldConstant(field)) { + return false; + } + + return super.isFinalField(field, tool); + } + + private static final String SystemClassName = "Ljava/lang/System;"; + + protected boolean isStaticFieldConstant(ResolvedJavaField field) { + ResolvedJavaType declaringClass = field.getDeclaringClass(); + return declaringClass.isInitialized() && !declaringClass.getName().equals(SystemClassName); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotConstantLoadAction.java 2016-12-07 13:50:12.316328631 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011, 2015, 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.meta; + +public enum HotSpotConstantLoadAction { + RESOLVE(0), + INITIALIZE(1), + MAKE_NOT_ENTRANT(2), + LOAD_COUNTERS(3); + + private int value; + + HotSpotConstantLoadAction(int value) { + this.value = value; + } + + public int value() { + return value; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotDisassemblerProvider.java 2016-12-07 13:50:12.580340235 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013, 2016, 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.meta; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.code.DisassemblerProvider; +import org.graalvm.compiler.serviceprovider.ServiceProvider; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; + +/** + * HotSpot implementation of {@link DisassemblerProvider}. + */ +@ServiceProvider(DisassemblerProvider.class) +public class HotSpotDisassemblerProvider implements DisassemblerProvider { + + @Override + public String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) { + return null; + } + + @Override + public String disassembleInstalledCode(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode code) { + return ((HotSpotCodeCacheProvider) codeCache).disassemble(code); + } + + @Override + public String getName() { + return "hsdis"; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProvider.java 2016-12-07 13:50:12.844351840 -0800 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.meta; + +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; + +import jdk.vm.ci.meta.Value; + +/** + * HotSpot extension of {@link ForeignCallsProvider}. + */ +public interface HotSpotForeignCallsProvider extends ForeignCallsProvider { + + /** + * Gets the registers that must be saved across a foreign call into the runtime. + */ + Value[] getNativeABICallerSaveRegisters(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java 2016-12-07 13:50:13.108363444 -0800 @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2013, 2016, 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.meta; + +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT; +import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCall; +import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCallee; + +import java.util.HashMap; +import java.util.Map; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.stubs.ForeignCallStub; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; + +/** + * HotSpot implementation of {@link HotSpotForeignCallsProvider}. + */ +public abstract class HotSpotForeignCallsProviderImpl implements HotSpotForeignCallsProvider { + + public static final ForeignCallDescriptor OSR_MIGRATION_END = new ForeignCallDescriptor("OSR_migration_end", void.class, long.class); + public static final ForeignCallDescriptor IDENTITY_HASHCODE = new ForeignCallDescriptor("identity_hashcode", int.class, Object.class); + public static final ForeignCallDescriptor VERIFY_OOP = new ForeignCallDescriptor("verify_oop", Object.class, Object.class); + public static final ForeignCallDescriptor LOAD_AND_CLEAR_EXCEPTION = new ForeignCallDescriptor("load_and_clear_exception", Object.class, Word.class); + + public static final ForeignCallDescriptor TEST_DEOPTIMIZE_CALL_INT = new ForeignCallDescriptor("test_deoptimize_call_int", int.class, int.class); + + protected final HotSpotJVMCIRuntimeProvider jvmciRuntime; + protected final HotSpotGraalRuntimeProvider runtime; + + protected final Map foreignCalls = new HashMap<>(); + protected final MetaAccessProvider metaAccess; + protected final CodeCacheProvider codeCache; + protected final WordTypes wordTypes; + + public HotSpotForeignCallsProviderImpl(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache, + WordTypes wordTypes) { + this.jvmciRuntime = jvmciRuntime; + this.runtime = runtime; + this.metaAccess = metaAccess; + this.codeCache = codeCache; + this.wordTypes = wordTypes; + } + + /** + * Registers the linkage for a foreign call. + */ + public HotSpotForeignCallLinkage register(HotSpotForeignCallLinkage linkage) { + assert !foreignCalls.containsKey(linkage.getDescriptor()) : "already registered linkage for " + linkage.getDescriptor(); + foreignCalls.put(linkage.getDescriptor(), linkage); + return linkage; + } + + /** + * Return true if the descriptor has already been registered. + */ + public boolean isRegistered(ForeignCallDescriptor descriptor) { + return foreignCalls.containsKey(descriptor); + } + + /** + * Creates and registers the details for linking a foreign call to a {@link Stub}. + * + * @param descriptor the signature of the call to the stub + * @param reexecutable specifies if the stub call can be re-executed without (meaningful) side + * effects. Deoptimization will not return to a point before a stub call that cannot + * be re-executed. + * @param transition specifies if this is a {@linkplain Transition#LEAF leaf} call + * @param killedLocations the memory locations killed by the stub call + */ + public HotSpotForeignCallLinkage registerStubCall(ForeignCallDescriptor descriptor, boolean reexecutable, Transition transition, LocationIdentity... killedLocations) { + return register(HotSpotForeignCallLinkageImpl.create(metaAccess, codeCache, wordTypes, this, descriptor, 0L, PRESERVES_REGISTERS, JavaCall, JavaCallee, transition, reexecutable, + killedLocations)); + } + + /** + * Creates and registers the linkage for a foreign call. + * + * @param descriptor the signature of the foreign call + * @param address the address of the code to call + * @param outgoingCcType outgoing (caller) calling convention type + * @param effect specifies if the call destroys or preserves all registers (apart from + * temporaries which are always destroyed) + * @param transition specifies if this is a {@linkplain Transition#LEAF leaf} call + * @param reexecutable specifies if the foreign call can be re-executed without (meaningful) + * side effects. Deoptimization will not return to a point before a foreign call that + * cannot be re-executed. + * @param killedLocations the memory locations killed by the foreign call + */ + public HotSpotForeignCallLinkage registerForeignCall(ForeignCallDescriptor descriptor, long address, CallingConvention.Type outgoingCcType, RegisterEffect effect, Transition transition, + boolean reexecutable, LocationIdentity... killedLocations) { + Class resultType = descriptor.getResultType(); + assert address != 0; + assert transition != SAFEPOINT || resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "non-leaf foreign calls must return objects in thread local storage: " + descriptor; + return register(HotSpotForeignCallLinkageImpl.create(metaAccess, codeCache, wordTypes, this, descriptor, address, effect, outgoingCcType, null, transition, reexecutable, killedLocations)); + } + + /** + * Creates a {@linkplain ForeignCallStub stub} for a foreign call. + * + * @param descriptor the signature of the call to the stub + * @param address the address of the foreign code to call + * @param prependThread true if the JavaThread value for the current thread is to be prepended + * to the arguments for the call to {@code address} + * @param transition specifies if this is a {@linkplain Transition#LEAF leaf} call + * @param reexecutable specifies if the foreign call can be re-executed without (meaningful) + * side effects. Deoptimization will not return to a point before a foreign call that + * cannot be re-executed. + * @param killedLocations the memory locations killed by the foreign call + */ + public void linkForeignCall(HotSpotProviders providers, ForeignCallDescriptor descriptor, long address, boolean prependThread, Transition transition, boolean reexecutable, + LocationIdentity... killedLocations) { + ForeignCallStub stub = new ForeignCallStub(jvmciRuntime, providers, address, descriptor, prependThread, transition, reexecutable, killedLocations); + HotSpotForeignCallLinkage linkage = stub.getLinkage(); + HotSpotForeignCallLinkage targetLinkage = stub.getTargetLinkage(); + linkage.setCompiledStub(stub); + register(linkage); + register(targetLinkage); + } + + public static final boolean PREPEND_THREAD = true; + public static final boolean DONT_PREPEND_THREAD = !PREPEND_THREAD; + + public static final boolean REEXECUTABLE = true; + public static final boolean NOT_REEXECUTABLE = !REEXECUTABLE; + + public static final LocationIdentity[] NO_LOCATIONS = {}; + + @Override + public HotSpotForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) { + assert foreignCalls != null : descriptor; + HotSpotForeignCallLinkage callTarget = foreignCalls.get(descriptor); + callTarget.finalizeAddress(runtime.getHostBackend()); + return callTarget; + } + + @Override + public boolean isReexecutable(ForeignCallDescriptor descriptor) { + assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; + return foreignCalls.get(descriptor).isReexecutable(); + } + + @Override + public boolean canDeoptimize(ForeignCallDescriptor descriptor) { + assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; + return foreignCalls.get(descriptor).needsDebugInfo(); + } + + @Override + public boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor) { + assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; + return foreignCalls.get(descriptor).isGuaranteedSafepoint(); + } + + @Override + public LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor) { + assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; + return foreignCalls.get(descriptor).getKilledLocations(); + } + + @Override + public LIRKind getValueKind(JavaKind javaKind) { + return LIRKind.fromJavaKind(codeCache.getTarget().arch, javaKind); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraalConstantFieldProvider.java 2016-12-07 13:50:13.373375092 -0800 @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2016, 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.meta; + +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; +import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.ImmutableCodeLazy.isCalledForSnippets; +import static org.graalvm.compiler.hotspot.stubs.SnippetStub.SnippetGraphUnderConstruction; + +import java.util.ArrayList; +import java.util.List; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.options.StableOptionValue; +import org.graalvm.compiler.replacements.ReplacementsImpl; +import org.graalvm.compiler.replacements.SnippetCounter; +import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.runtime.JVMCI; + +/** + * Extends {@link HotSpotConstantFieldProvider} to override the implementation of + * {@link #readConstantField} with Graal specific semantics. + */ +public class HotSpotGraalConstantFieldProvider extends HotSpotConstantFieldProvider { + + public HotSpotGraalConstantFieldProvider(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) { + super(config, metaAccess); + this.metaAccess = metaAccess; + } + + @Override + public T readConstantField(ResolvedJavaField field, ConstantFieldTool tool) { + assert !ImmutableCode.getValue() || isCalledForSnippets(metaAccess) || SnippetGraphUnderConstruction.get() != null || + FieldReadEnabledInImmutableCode.get() == Boolean.TRUE : tool.getReceiver(); + if (!field.isStatic() && field.getName().equals("value")) { + if (getStableOptionValueType().isInstance(tool.getReceiver())) { + JavaConstant ret = tool.readValue(); + return tool.foldConstant(ret); + } + } + + return super.readConstantField(field, tool); + } + + /** + * In AOT mode, some fields should never be embedded even for snippets/replacements. + */ + @Override + protected boolean isStaticFieldConstant(ResolvedJavaField field) { + return super.isStaticFieldConstant(field) && (!ImmutableCode.getValue() || ImmutableCodeLazy.isEmbeddable(field)); + } + + @Override + protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool tool) { + if (super.isFinalFieldValueConstant(field, value, tool)) { + return true; + } + + if (!field.isStatic()) { + JavaConstant receiver = tool.getReceiver(); + if (getSnippetCounterType().isInstance(receiver) || getNodeClassType().isInstance(receiver)) { + return true; + } + } + + return false; + } + + @Override + protected boolean isStableFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool tool) { + if (super.isStableFieldValueConstant(field, value, tool)) { + return true; + } + + if (!field.isStatic()) { + JavaConstant receiver = tool.getReceiver(); + if (getHotSpotVMConfigType().isInstance(receiver)) { + return true; + } + } + + return false; + } + + private final MetaAccessProvider metaAccess; + + private ResolvedJavaType cachedStableOptionValueType; + private ResolvedJavaType cachedHotSpotVMConfigType; + private ResolvedJavaType cachedSnippetCounterType; + private ResolvedJavaType cachedNodeClassType; + + private ResolvedJavaType getStableOptionValueType() { + if (cachedStableOptionValueType == null) { + cachedStableOptionValueType = metaAccess.lookupJavaType(StableOptionValue.class); + } + return cachedStableOptionValueType; + } + + private ResolvedJavaType getHotSpotVMConfigType() { + if (cachedHotSpotVMConfigType == null) { + cachedHotSpotVMConfigType = metaAccess.lookupJavaType(GraalHotSpotVMConfig.class); + } + return cachedHotSpotVMConfigType; + } + + private ResolvedJavaType getSnippetCounterType() { + if (cachedSnippetCounterType == null) { + cachedSnippetCounterType = metaAccess.lookupJavaType(SnippetCounter.class); + } + return cachedSnippetCounterType; + } + + private ResolvedJavaType getNodeClassType() { + if (cachedNodeClassType == null) { + cachedNodeClassType = metaAccess.lookupJavaType(NodeClass.class); + } + return cachedNodeClassType; + } + + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean enabled = false; + assert enabled = true; + return enabled; + } + + public static final ThreadLocal FieldReadEnabledInImmutableCode = assertionsEnabled() ? new ThreadLocal<>() : null; + + /** + * Compares two {@link StackTraceElement}s for equality, ignoring differences in + * {@linkplain StackTraceElement#getLineNumber() line number}. + */ + private static boolean equalsIgnoringLine(StackTraceElement left, StackTraceElement right) { + return left.getClassName().equals(right.getClassName()) && left.getMethodName().equals(right.getMethodName()) && left.getFileName().equals(right.getFileName()); + } + + /** + * Separate out the static initialization of {@linkplain #isEmbeddable(ResolvedJavaField) + * embeddable fields} to eliminate cycles between clinit and other locks that could lead to + * deadlock. Static code that doesn't call back into type or field machinery is probably ok but + * anything else should be made lazy. + */ + static class ImmutableCodeLazy { + + /** + * If the compiler is configured for AOT mode, {@link #readConstantField} should be only + * called for snippets or replacements. + */ + static boolean isCalledForSnippets(MetaAccessProvider metaAccess) { + assert ImmutableCode.getValue(); + ResolvedJavaMethod makeGraphMethod = null; + ResolvedJavaMethod initMethod = null; + try { + Class rjm = ResolvedJavaMethod.class; + makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm)); + initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); + } catch (NoSuchMethodException | SecurityException e) { + throw new GraalError(e); + } + StackTraceElement makeGraphSTE = makeGraphMethod.asStackTraceElement(0); + StackTraceElement initSTE = initMethod.asStackTraceElement(0); + + StackTraceElement[] stackTrace = new Exception().getStackTrace(); + for (StackTraceElement element : stackTrace) { + // Ignoring line numbers should not weaken this check too much while at + // the same time making it more robust against source code changes + if (equalsIgnoringLine(makeGraphSTE, element) || equalsIgnoringLine(initSTE, element)) { + return true; + } + } + return false; + } + + /** + * Determine if it's ok to embed the value of {@code field}. + */ + static boolean isEmbeddable(ResolvedJavaField field) { + assert ImmutableCode.getValue(); + return !embeddableFields.contains(field); + } + + private static final List embeddableFields = new ArrayList<>(); + static { + try { + MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + embeddableFields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("TRUE"))); + embeddableFields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("FALSE"))); + + Class characterCacheClass = Character.class.getDeclaredClasses()[0]; + assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); + embeddableFields.add(metaAccess.lookupJavaField(characterCacheClass.getDeclaredField("cache"))); + + Class byteCacheClass = Byte.class.getDeclaredClasses()[0]; + assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); + embeddableFields.add(metaAccess.lookupJavaField(byteCacheClass.getDeclaredField("cache"))); + + Class shortCacheClass = Short.class.getDeclaredClasses()[0]; + assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); + embeddableFields.add(metaAccess.lookupJavaField(shortCacheClass.getDeclaredField("cache"))); + + Class integerCacheClass = Integer.class.getDeclaredClasses()[0]; + assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); + embeddableFields.add(metaAccess.lookupJavaField(integerCacheClass.getDeclaredField("cache"))); + + Class longCacheClass = Long.class.getDeclaredClasses()[0]; + assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); + embeddableFields.add(metaAccess.lookupJavaField(longCacheClass.getDeclaredField("cache"))); + + embeddableFields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("UNASSIGNED_STACK"))); + embeddableFields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL"))); + } catch (SecurityException | NoSuchFieldException e) { + throw new GraalError(e); + } + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java 2016-12-07 13:50:13.637386697 -0800 @@ -0,0 +1,571 @@ +/* + * Copyright (c) 2015, 2016, 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.meta; + +import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION; +import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing; + +import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile; +import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved; + +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MutableCallSite; +import java.lang.invoke.VolatileCallSite; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.math.BigInteger; +import java.util.zip.CRC32; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.FingerprintUtil; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode; +import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions; +import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions; +import org.graalvm.compiler.hotspot.replacements.CRC32Substitutions; +import org.graalvm.compiler.hotspot.replacements.CallSiteTargetNode; +import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions; +import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode; +import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode; +import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions; +import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode; +import org.graalvm.compiler.hotspot.replacements.ObjectSubstitutions; +import org.graalvm.compiler.hotspot.replacements.ReflectionGetCallerClassNode; +import org.graalvm.compiler.hotspot.replacements.ReflectionSubstitutions; +import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions; +import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions; +import org.graalvm.compiler.hotspot.replacements.SHASubstitutions; +import org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions; +import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode; +import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.DynamicPiNode; +import org.graalvm.compiler.nodes.FixedGuardNode; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.LeftShiftNode; +import org.graalvm.compiler.nodes.graphbuilderconf.ForeignCallPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; +import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory; +import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; +import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode; +import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.spi.StampProvider; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.options.StableOptionValue; +import org.graalvm.compiler.replacements.InlineDuringParsingPlugin; +import org.graalvm.compiler.replacements.InlineGraalDirectivesPlugin; +import org.graalvm.compiler.replacements.MethodHandlePlugin; +import org.graalvm.compiler.replacements.NodeIntrinsificationProvider; +import org.graalvm.compiler.replacements.ReplacementsImpl; +import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins; +import org.graalvm.compiler.replacements.WordOperationPlugin; +import org.graalvm.compiler.serviceprovider.GraalServices; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Defines the {@link Plugins} used when running on HotSpot. + */ +public class HotSpotGraphBuilderPlugins { + + /** + * Creates a {@link Plugins} object that should be used when running on HotSpot. + * + * @param constantReflection + * @param snippetReflection + * @param foreignCalls + * @param stampProvider + */ + public static Plugins create(GraalHotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, + SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements) { + InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess); + + Plugins plugins = new Plugins(invocationPlugins); + NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes); + HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes); + HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin); + + plugins.appendTypePlugin(nodePlugin); + plugins.appendNodePlugin(nodePlugin); + if (GeneratePIC.getValue()) { + // AOT needs to filter out bad invokes + plugins.prependNodePlugin(new NodePlugin() { + @Override + public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + if (b.parsingIntrinsic()) { + return false; + } + // check if the holder has a valid fingerprint + if (FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) method.getDeclaringClass()) == 0) { + // Deopt otherwise + b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + return true; + } + // the last argument that may come from appendix, check if it is a supported + // constant type + if (args.length > 0) { + JavaConstant constant = args[args.length - 1].asJavaConstant(); + if (constant != null && constant instanceof HotSpotObjectConstant) { + HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) ((HotSpotObjectConstant) constant).getType(); + Class clazz = type.mirror(); + if (clazz.equals(String.class)) { + return false; + } + if (Class.class.isAssignableFrom(clazz) && FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) type) != 0) { + return false; + } + b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + return true; + } + } + return false; + } + }); + } + plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true)); + plugins.appendInlineInvokePlugin(replacements); + if (InlineDuringParsing.getValue()) { + plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin()); + } + plugins.appendInlineInvokePlugin(new InlineGraalDirectivesPlugin()); + + if (GeneratePIC.getValue()) { + plugins.setClassInitializationPlugin(new HotSpotClassInitializationPlugin()); + if (TieredAOT.getValue()) { + plugins.setProfilingPlugin(new HotSpotAOTProfilingPlugin()); + } + } + + invocationPlugins.defer(new Runnable() { + + @Override + public void run() { + BytecodeProvider replacementBytecodeProvider = replacements.getReplacementBytecodeProvider(); + registerObjectPlugins(invocationPlugins, replacementBytecodeProvider); + registerClassPlugins(plugins, config, replacementBytecodeProvider); + registerSystemPlugins(invocationPlugins, foreignCalls); + registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider); + registerCallSitePlugins(invocationPlugins); + registerReflectionPlugins(invocationPlugins, replacementBytecodeProvider); + registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacementBytecodeProvider); + registerStableOptionPlugins(invocationPlugins, snippetReflection); + registerAESPlugins(invocationPlugins, config, replacementBytecodeProvider); + registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider); + registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider); + registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider); + StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true); + + for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) { + factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider); + } + } + }); + return plugins; + } + + private static void registerObjectPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) { + Registration r = new Registration(plugins, Object.class, bytecodeProvider); + if (!GeneratePIC.getValue()) { + // FIXME: clone() requires speculation and requires a fix in here (to check that + // b.getAssumptions() != null), and in ReplacementImpl.getSubstitution() where there is + // an instantiation of IntrinsicGraphBuilder using a constructor that sets + // AllowAssumptions to YES automatically. The former has to inherit the assumptions + // settings from the root compile instead. So, for now, I'm disabling it for + // GeneratePIC. + r.register1("clone", Receiver.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + ValueNode object = receiver.get(); + b.addPush(JavaKind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), object)); + return true; + } + + @Override + public boolean inlineOnly() { + return true; + } + }); + } + r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class); + } + + private static void registerClassPlugins(Plugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) { + Registration r = new Registration(plugins.getInvocationPlugins(), Class.class, bytecodeProvider); + + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getModifiers", Receiver.class); + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isInterface", Receiver.class); + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isArray", Receiver.class); + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isPrimitive", Receiver.class); + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getSuperclass", Receiver.class); + + if (config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop", Integer.MAX_VALUE) != Integer.MAX_VALUE) { + r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getComponentType", Receiver.class); + } + + r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { + ValueNode javaClass = receiver.get(); + LogicNode condition = b.recursiveAppend(InstanceOfDynamicNode.create(b.getAssumptions(), b.getConstantReflection(), javaClass, object, true)); + if (condition.isTautology()) { + b.addPush(JavaKind.Object, object); + } else { + FixedGuardNode fixedGuard = b.add(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false)); + b.addPush(JavaKind.Object, new DynamicPiNode(object, fixedGuard, javaClass)); + } + return true; + } + + @Override + public boolean inlineOnly() { + return true; + } + }); + } + + private static void registerCallSitePlugins(InvocationPlugins plugins) { + InvocationPlugin plugin = new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + ValueNode callSite = receiver.get(); + ValueNode folded = CallSiteTargetNode.tryFold(GraphUtil.originalValue(callSite), b.getMetaAccess(), b.getAssumptions()); + if (folded != null) { + b.addPush(JavaKind.Object, folded); + } else { + b.addPush(JavaKind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), callSite)); + } + return true; + } + + @Override + public boolean inlineOnly() { + return true; + } + }; + plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class); + plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class); + plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class); + } + + private static void registerReflectionPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) { + Registration r = new Registration(plugins, reflectionClass, bytecodeProvider); + r.register0("getCallerClass", new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + b.addPush(JavaKind.Object, new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()))); + return true; + } + + @Override + public boolean inlineOnly() { + return true; + } + }); + r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class); + } + + private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants"); + private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length"); + + /** + * Emits a node to get the metaspace {@code ConstantPool} pointer given the value of the + * {@code constantPoolOop} field in a ConstantPool value. + * + * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value + * @return a node representing the metaspace {@code ConstantPool} pointer associated with + * {@code constantPoolOop} + */ + private static ValueNode getMetaspaceConstantPool(GraphBuilderContext b, ValueNode constantPoolOop, WordTypes wordTypes, GraalHotSpotVMConfig config) { + // ConstantPool.constantPoolOop is in fact the holder class. + ClassGetHubNode klass = b.add(new ClassGetHubNode(constantPoolOop)); + + boolean notCompressible = false; + AddressNode constantsAddress = b.add(new OffsetAddressNode(klass, b.add(ConstantNode.forLong(config.instanceKlassConstantsOffset)))); + return WordOperationPlugin.readOp(b, wordTypes.getWordKind(), constantsAddress, INSTANCE_KLASS_CONSTANTS, BarrierType.NONE, notCompressible); + } + + /** + * Emits a node representing an element in a metaspace {@code ConstantPool}. + * + * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value + */ + private static boolean readMetaspaceConstantPoolElement(GraphBuilderContext b, ValueNode constantPoolOop, ValueNode index, JavaKind elementKind, WordTypes wordTypes, GraalHotSpotVMConfig config) { + ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config); + int shift = CodeUtil.log2(wordTypes.getWordKind().getByteCount()); + ValueNode scaledIndex = b.add(new LeftShiftNode(index, b.add(ConstantNode.forInt(shift)))); + ValueNode offset = b.add(new AddNode(scaledIndex, b.add(ConstantNode.forInt(config.constantPoolSize)))); + AddressNode elementAddress = b.add(new OffsetAddressNode(constants, offset)); + boolean notCompressible = false; + ValueNode elementValue = WordOperationPlugin.readOp(b, elementKind, elementAddress, NamedLocationIdentity.getArrayLocation(elementKind), BarrierType.NONE, notCompressible); + b.addPush(elementKind, elementValue); + return true; + } + + private static void registerConstantPoolPlugins(InvocationPlugins plugins, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) { + Registration r = new Registration(plugins, constantPoolClass, bytecodeProvider); + + r.register2("getSize0", Receiver.class, Object.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop) { + boolean notCompressible = false; + ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config); + AddressNode lengthAddress = b.add(new OffsetAddressNode(constants, b.add(ConstantNode.forLong(config.constantPoolLengthOffset)))); + ValueNode length = WordOperationPlugin.readOp(b, JavaKind.Int, lengthAddress, CONSTANT_POOL_LENGTH, BarrierType.NONE, notCompressible); + b.addPush(JavaKind.Int, length); + return true; + } + }); + + r.register3("getIntAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) { + return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Int, wordTypes, config); + } + }); + r.register3("getLongAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) { + return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Long, wordTypes, config); + } + }); + r.register3("getFloatAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) { + return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Float, wordTypes, config); + } + }); + r.register3("getDoubleAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) { + return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Double, wordTypes, config); + } + }); + } + + private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) { + Registration r = new Registration(plugins, System.class); + r.register0("currentTimeMillis", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_MILLIS)); + r.register0("nanoTime", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_NANOS)); + r.register1("identityHashCode", Object.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { + b.addPush(JavaKind.Int, new IdentityHashCodeNode(object)); + return true; + } + + @Override + public boolean inlineOnly() { + return true; + } + }); + r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) { + b.add(new ArrayCopyNode(b.bci(), src, srcPos, dst, dstPos, length)); + return true; + } + + @Override + public boolean inlineOnly() { + return true; + } + }); + } + + private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) { + Registration r = new Registration(plugins, Thread.class, bytecodeProvider); + r.register0("currentThread", new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind())); + boolean compressible = false; + ValueNode offset = b.add(ConstantNode.forLong(config.threadObjectOffset)); + AddressNode address = b.add(new OffsetAddressNode(thread, offset)); + ValueNode javaThread = WordOperationPlugin.readOp(b, JavaKind.Object, address, JAVA_THREAD_THREAD_OBJECT_LOCATION, BarrierType.NONE, compressible); + boolean exactType = false; + boolean nonNull = true; + b.addPush(JavaKind.Object, new PiNode(javaThread, metaAccess.lookupJavaType(Thread.class), exactType, nonNull)); + return true; + } + }); + + r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class); + } + + private static void registerStableOptionPlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection) { + Registration r = new Registration(plugins, StableOptionValue.class); + r.register1("getValue", Receiver.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + if (receiver.isConstant()) { + StableOptionValue option = snippetReflection.asObject(StableOptionValue.class, (JavaConstant) receiver.get().asConstant()); + b.addPush(JavaKind.Object, ConstantNode.forConstant(snippetReflection.forObject(option.getValue()), b.getMetaAccess())); + return true; + } + return false; + } + }); + } + + public static final String cbcEncryptName; + public static final String cbcDecryptName; + public static final String aesEncryptName; + public static final String aesDecryptName; + + public static final String reflectionClass; + public static final String constantPoolClass; + + static { + if (Java8OrEarlier) { + cbcEncryptName = "encrypt"; + cbcDecryptName = "decrypt"; + aesEncryptName = "encryptBlock"; + aesDecryptName = "decryptBlock"; + reflectionClass = "sun.reflect.Reflection"; + constantPoolClass = "sun.reflect.ConstantPool"; + } else { + cbcEncryptName = "implEncrypt"; + cbcDecryptName = "implDecrypt"; + aesEncryptName = "implEncryptBlock"; + aesDecryptName = "implDecryptBlock"; + reflectionClass = "jdk.internal.reflect.Reflection"; + constantPoolClass = "jdk.internal.reflect.ConstantPool"; + } + } + + private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) { + if (config.useAESIntrinsics) { + assert config.aescryptEncryptBlockStub != 0L; + assert config.aescryptDecryptBlockStub != 0L; + assert config.cipherBlockChainingEncryptAESCryptStub != 0L; + assert config.cipherBlockChainingDecryptAESCryptStub != 0L; + String arch = config.osArch; + String decryptSuffix = arch.equals("sparc") ? "WithOriginalKey" : ""; + Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", bytecodeProvider); + r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class); + r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, int.class, byte[].class, + int.class); + r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", bytecodeProvider); + r.registerMethodSubstitution(AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class); + r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, aesDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class); + } + } + + private static void registerBigIntegerPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) { + Registration r = new Registration(plugins, BigInteger.class, bytecodeProvider); + if (config.useMultiplyToLenIntrinsic()) { + assert config.multiplyToLen != 0L; + if (Java8OrEarlier) { + try { + Method m = BigInteger.class.getDeclaredMethod("multiplyToLen", int[].class, int.class, int[].class, int.class, int[].class); + if (Modifier.isStatic(m.getModifiers())) { + r.registerMethodSubstitution(BigIntegerSubstitutions.class, "multiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class, + int[].class); + } else { + r.registerMethodSubstitution(BigIntegerSubstitutions.class, "multiplyToLen", Receiver.class, int[].class, int.class, int[].class, int.class, + int[].class); + } + } catch (NoSuchMethodException | SecurityException e) { + throw new GraalError(e); + } + } else { + r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMultiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class, + int[].class); + } + } + if (config.useMulAddIntrinsic()) { + r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMulAdd", int[].class, int[].class, int.class, int.class, int.class); + } + if (config.useMontgomeryMultiplyIntrinsic()) { + r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMontgomeryMultiply", int[].class, int[].class, int[].class, int.class, long.class, int[].class); + } + if (config.useMontgomerySquareIntrinsic()) { + r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMontgomerySquare", int[].class, int[].class, int.class, long.class, int[].class); + } + if (config.useSquareToLenIntrinsic()) { + r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implSquareToLen", int[].class, int.class, int[].class, int.class); + } + } + + private static void registerSHAPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) { + if (config.useSHA1Intrinsics()) { + assert config.sha1ImplCompress != 0L; + Registration r = new Registration(plugins, "sun.security.provider.SHA", bytecodeProvider); + r.registerMethodSubstitution(SHASubstitutions.class, SHASubstitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class); + } + if (config.useSHA256Intrinsics()) { + assert config.sha256ImplCompress != 0L; + Registration r = new Registration(plugins, "sun.security.provider.SHA2", bytecodeProvider); + r.registerMethodSubstitution(SHA2Substitutions.class, SHA2Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class); + } + if (config.useSHA512Intrinsics()) { + assert config.sha512ImplCompress != 0L; + Registration r = new Registration(plugins, "sun.security.provider.SHA5", bytecodeProvider); + r.registerMethodSubstitution(SHA5Substitutions.class, SHA5Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class); + } + } + + private static void registerCRC32Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) { + if (config.useCRC32Intrinsics) { + Registration r = new Registration(plugins, CRC32.class, bytecodeProvider); + r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class); + if (Java8OrEarlier) { + r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class); + r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class); + } else { + r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes0", int.class, byte[].class, int.class, int.class); + r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer0", int.class, long.class, int.class, int.class); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java 2016-12-07 13:50:13.903398389 -0800 @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2013, 2016, 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.meta; + +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_DREM; +import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_FREM; +import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL; +import static org.graalvm.compiler.hotspot.HotSpotBackend.BACKEDGE_EVENT; +import static org.graalvm.compiler.hotspot.HotSpotBackend.INVOCATION_EVENT; +import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL; +import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS; +import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL; +import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT; +import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK; +import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK_WITH_ORIGINAL_KEY; +import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_KEY; +import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT; +import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT_BLOCK; +import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER; +import static org.graalvm.compiler.hotspot.HotSpotBackend.FETCH_UNROLL_INFO; +import static org.graalvm.compiler.hotspot.HotSpotBackend.IC_MISS_HANDLER; +import static org.graalvm.compiler.hotspot.HotSpotBackend.MONTGOMERY_MULTIPLY; +import static org.graalvm.compiler.hotspot.HotSpotBackend.MONTGOMERY_SQUARE; +import static org.graalvm.compiler.hotspot.HotSpotBackend.MULTIPLY_TO_LEN; +import static org.graalvm.compiler.hotspot.HotSpotBackend.MUL_ADD; +import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY; +import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE; +import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY; +import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA2_IMPL_COMPRESS; +import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA5_IMPL_COMPRESS; +import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA_IMPL_COMPRESS; +import static org.graalvm.compiler.hotspot.HotSpotBackend.SQUARE_TO_LEN; +import static org.graalvm.compiler.hotspot.HotSpotBackend.UNCOMMON_TRAP; +import static org.graalvm.compiler.hotspot.HotSpotBackend.UNPACK_FRAMES; +import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER; +import static org.graalvm.compiler.hotspot.HotSpotBackend.VM_ERROR; +import static org.graalvm.compiler.hotspot.HotSpotBackend.WRONG_METHOD_HANDLER; +import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NOFP; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.STACK_INSPECTABLE_LEAF; +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPTIMIZATION_HANDLER; +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; +import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_ARRAY_STORE_EXCEPTION; +import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_CLASS_CAST_EXCEPTION; +import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION; +import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION; +import static org.graalvm.compiler.hotspot.replacements.AssertionSnippets.ASSERTION_VM_MESSAGE_C; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_END_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_TOP_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.MonitorSnippets.MONITORENTER; +import static org.graalvm.compiler.hotspot.replacements.MonitorSnippets.MONITOREXIT; +import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.DYNAMIC_NEW_ARRAY; +import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.DYNAMIC_NEW_INSTANCE; +import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.INIT_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions.THREAD_IS_INTERRUPTED; +import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.G1WBPOSTCALL; +import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.G1WBPRECALL; +import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.VALIDATE_OBJECT; +import static org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub.EXCEPTION_HANDLER_FOR_PC; +import static org.graalvm.compiler.hotspot.stubs.NewArrayStub.NEW_ARRAY_C; +import static org.graalvm.compiler.hotspot.stubs.NewInstanceStub.NEW_INSTANCE_C; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.VM_MESSAGE_C; +import static org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub.EXCEPTION_HANDLER_FOR_RETURN_ADDRESS; +import static org.graalvm.compiler.nodes.NamedLocationIdentity.any; +import static org.graalvm.compiler.nodes.java.ForeignCallDescriptors.REGISTER_FINALIZER; +import static org.graalvm.compiler.replacements.Log.LOG_OBJECT; +import static org.graalvm.compiler.replacements.Log.LOG_PRIMITIVE; +import static org.graalvm.compiler.replacements.Log.LOG_PRINTF; +import static org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation.POW; +import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.COS; +import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.EXP; +import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG; +import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10; +import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN; +import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN; +import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.CompilerRuntimeHotSpotVMConfig; +import org.graalvm.compiler.hotspot.stubs.ArrayStoreExceptionStub; +import org.graalvm.compiler.hotspot.stubs.ClassCastExceptionStub; +import org.graalvm.compiler.hotspot.stubs.CreateExceptionStub; +import org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub; +import org.graalvm.compiler.hotspot.stubs.NewArrayStub; +import org.graalvm.compiler.hotspot.stubs.NewInstanceStub; +import org.graalvm.compiler.hotspot.stubs.NullPointerExceptionStub; +import org.graalvm.compiler.hotspot.stubs.OutOfBoundsExceptionStub; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub; +import org.graalvm.compiler.hotspot.stubs.VerifyOopStub; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; + +/** + * HotSpot implementation of {@link ForeignCallsProvider}. + */ +public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCallsProviderImpl { + + public static final ForeignCallDescriptor JAVA_TIME_MILLIS = new ForeignCallDescriptor("javaTimeMillis", long.class); + public static final ForeignCallDescriptor JAVA_TIME_NANOS = new ForeignCallDescriptor("javaTimeNanos", long.class); + + public HotSpotHostForeignCallsProvider(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache, + WordTypes wordTypes) { + super(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes); + } + + protected static void link(Stub stub) { + stub.getLinkage().setCompiledStub(stub); + } + + public static ForeignCallDescriptor lookupCheckcastArraycopyDescriptor(boolean uninit) { + return checkcastArraycopyDescriptors[uninit ? 1 : 0]; + } + + public static ForeignCallDescriptor lookupArraycopyDescriptor(JavaKind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny) { + if (uninit) { + assert kind == JavaKind.Object; + assert !killAny : "unsupported"; + return uninitObjectArraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0]; + } + if (killAny) { + assert kind == JavaKind.Object; + return objectArraycopyDescriptorsKillAny[aligned ? 1 : 0][disjoint ? 1 : 0]; + } + return arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].get(kind); + } + + @SuppressWarnings({"unchecked"}) private static final EnumMap[][] arraycopyDescriptors = (EnumMap[][]) new EnumMap[2][2]; + + private static final ForeignCallDescriptor[][] uninitObjectArraycopyDescriptors = new ForeignCallDescriptor[2][2]; + private static final ForeignCallDescriptor[] checkcastArraycopyDescriptors = new ForeignCallDescriptor[2]; + private static ForeignCallDescriptor[][] objectArraycopyDescriptorsKillAny = new ForeignCallDescriptor[2][2]; + + static { + // Populate the EnumMap instances + for (int i = 0; i < arraycopyDescriptors.length; i++) { + for (int j = 0; j < arraycopyDescriptors[i].length; j++) { + arraycopyDescriptors[i][j] = new EnumMap<>(JavaKind.class); + } + } + } + + private void registerArraycopyDescriptor(Map descMap, JavaKind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny, long routine) { + ForeignCallDescriptor desc = descMap.get(routine); + if (desc == null) { + desc = buildDescriptor(kind, aligned, disjoint, uninit, killAny, routine); + descMap.put(routine, desc); + } + if (uninit) { + assert kind == JavaKind.Object; + uninitObjectArraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0] = desc; + } else { + arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].put(kind, desc); + } + } + + private ForeignCallDescriptor buildDescriptor(JavaKind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny, long routine) { + assert !killAny || kind == JavaKind.Object; + String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + (uninit ? "Uninit" : "") + "Arraycopy" + (killAny ? "KillAny" : ""); + ForeignCallDescriptor desc = new ForeignCallDescriptor(name, void.class, Word.class, Word.class, Word.class); + LocationIdentity killed = killAny ? LocationIdentity.any() : NamedLocationIdentity.getArrayLocation(kind); + registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed); + return desc; + } + + private void registerCheckcastArraycopyDescriptor(boolean uninit, long routine) { + String name = "Object" + (uninit ? "Uninit" : "") + "Checkcast"; + // Input: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as ssize_t, can be zero + // c_rarg3 - size_t ckoff (super_check_offset) + // c_rarg4 - oop ckval (super_klass) + // return: 0 = success, n = number of copied elements xor'd with -1. + ForeignCallDescriptor desc = new ForeignCallDescriptor(name, int.class, Word.class, Word.class, Word.class, Word.class, Word.class); + LocationIdentity killed = NamedLocationIdentity.getArrayLocation(JavaKind.Object); + registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed); + checkcastArraycopyDescriptors[uninit ? 1 : 0] = desc; + } + + private void registerArrayCopy(JavaKind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) { + registerArrayCopy(kind, routine, alignedRoutine, disjointRoutine, alignedDisjointRoutine, false); + } + + private void registerArrayCopy(JavaKind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine, boolean uninit) { + /* + * Sometimes the same function is used for multiple cases so share them when that's the case + * but only within the same Kind. For instance short and char are the same copy routines but + * they kill different memory so they still have to be distinct. + */ + Map descMap = new HashMap<>(); + registerArraycopyDescriptor(descMap, kind, false, false, uninit, false, routine); + registerArraycopyDescriptor(descMap, kind, true, false, uninit, false, alignedRoutine); + registerArraycopyDescriptor(descMap, kind, false, true, uninit, false, disjointRoutine); + registerArraycopyDescriptor(descMap, kind, true, true, uninit, false, alignedDisjointRoutine); + + if (kind == JavaKind.Object && !uninit) { + objectArraycopyDescriptorsKillAny[0][0] = buildDescriptor(kind, false, false, uninit, true, routine); + objectArraycopyDescriptorsKillAny[1][0] = buildDescriptor(kind, true, false, uninit, true, alignedRoutine); + objectArraycopyDescriptorsKillAny[0][1] = buildDescriptor(kind, false, true, uninit, true, disjointRoutine); + objectArraycopyDescriptorsKillAny[1][1] = buildDescriptor(kind, true, true, uninit, true, alignedDisjointRoutine); + } + } + + public void initialize(HotSpotProviders providers) { + GraalHotSpotVMConfig c = runtime.getVMConfig(); + if (!PreferGraalStubs.getValue()) { + registerForeignCall(DEOPTIMIZATION_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(UNCOMMON_TRAP_HANDLER, c.uncommonTrapStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); + } + registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); + + registerForeignCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(JAVA_TIME_NANOS, c.javaTimeNanosAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(SIN.foreignCallDescriptor, c.arithmeticSinAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(COS.foreignCallDescriptor, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(TAN.foreignCallDescriptor, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(EXP.foreignCallDescriptor, c.arithmeticExpAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(LOG.foreignCallDescriptor, c.arithmeticLogAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(LOG10.foreignCallDescriptor, c.arithmeticLog10Address, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(POW.foreignCallDescriptor, c.arithmeticPowAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(ARITHMETIC_FREM, c.fremAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(ARITHMETIC_DREM, c.dremAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); + + registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any()); + + registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any()); + registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any()); + registerForeignCall(FETCH_UNROLL_INFO, c.deoptimizationFetchUnrollInfo, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any()); + registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any()); + registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any()); + registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, NOT_REEXECUTABLE, any()); + + /* + * We cannot use LEAF_SP here because on some architectures we have to align the stack + * manually before calling into the VM. See {@link + * AMD64HotSpotEnterUnpackFramesStackFrameOp#emitCode}. + */ + registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, any()); + + CreateExceptionStub.registerForeignCalls(c, this); + + /* + * This message call is registered twice, where the second one must only be used for calls + * that do not return, i.e., that exit the VM. + */ + registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS); + registerForeignCall(ASSERTION_VM_MESSAGE_C, c.vmMessageAddress, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); + + link(new NewInstanceStub(providers, registerStubCall(NEW_INSTANCE, REEXECUTABLE, SAFEPOINT, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION))); + link(new NewArrayStub(providers, registerStubCall(NEW_ARRAY, REEXECUTABLE, SAFEPOINT, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION))); + link(new ExceptionHandlerStub(providers, foreignCalls.get(EXCEPTION_HANDLER))); + link(new UnwindExceptionToCallerStub(providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, SAFEPOINT, any()))); + link(new VerifyOopStub(providers, registerStubCall(VERIFY_OOP, REEXECUTABLE, LEAF_NOFP, NO_LOCATIONS))); + link(new ArrayStoreExceptionStub(providers, registerStubCall(CREATE_ARRAY_STORE_EXCEPTION, REEXECUTABLE, SAFEPOINT, any()))); + link(new ClassCastExceptionStub(providers, registerStubCall(CREATE_CLASS_CAST_EXCEPTION, REEXECUTABLE, SAFEPOINT, any()))); + link(new NullPointerExceptionStub(providers, registerStubCall(CREATE_NULL_POINTER_EXCEPTION, REEXECUTABLE, SAFEPOINT, any()))); + link(new OutOfBoundsExceptionStub(providers, registerStubCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, REEXECUTABLE, SAFEPOINT, any()))); + + linkForeignCall(providers, IDENTITY_HASHCODE, c.identityHashCodeAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, MARK_WORD_LOCATION); + linkForeignCall(providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any()); + linkForeignCall(providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any()); + linkForeignCall(providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, STACK_INSPECTABLE_LEAF, NOT_REEXECUTABLE, any()); + linkForeignCall(providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + linkForeignCall(providers, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, INIT_LOCATION); + linkForeignCall(providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, INIT_LOCATION); + linkForeignCall(providers, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(providers, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(providers, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(providers, VM_ERROR, c.vmErrorAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(providers, OSR_MIGRATION_END, c.osrMigrationEndAddress, DONT_PREPEND_THREAD, LEAF_NOFP, NOT_REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(providers, G1WBPRECALL, c.writeBarrierPreAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(providers, G1WBPOSTCALL, c.writeBarrierPostAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(providers, VALIDATE_OBJECT, c.validateObject, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); + + if (GeneratePIC.getValue()) { + registerForeignCall(WRONG_METHOD_HANDLER, c.handleWrongMethodStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); + CompilerRuntimeHotSpotVMConfig cr = new CompilerRuntimeHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore()); + linkForeignCall(providers, RESOLVE_STRING_BY_SYMBOL, cr.resolveStringBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + linkForeignCall(providers, RESOLVE_KLASS_BY_SYMBOL, cr.resolveKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any()); + linkForeignCall(providers, RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, cr.resolveMethodBySymbolAndLoadCounters, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(providers, INITIALIZE_KLASS_BY_SYMBOL, cr.initializeKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any()); + linkForeignCall(providers, INVOCATION_EVENT, cr.invocationEvent, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(providers, BACKEDGE_EVENT, cr.backedgeEvent, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS); + } + + // Cannot be a leaf as VM acquires Thread_lock which requires thread_in_vm state + linkForeignCall(providers, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any()); + + linkForeignCall(providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any()); + + registerArrayCopy(JavaKind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy); + registerArrayCopy(JavaKind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy); + registerArrayCopy(JavaKind.Char, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy); + registerArrayCopy(JavaKind.Short, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy); + registerArrayCopy(JavaKind.Int, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy); + registerArrayCopy(JavaKind.Float, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy); + registerArrayCopy(JavaKind.Long, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy); + registerArrayCopy(JavaKind.Double, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy); + registerArrayCopy(JavaKind.Object, c.oopArraycopy, c.oopAlignedArraycopy, c.oopDisjointArraycopy, c.oopAlignedDisjointArraycopy); + registerArrayCopy(JavaKind.Object, c.oopArraycopyUninit, c.oopAlignedArraycopyUninit, c.oopDisjointArraycopyUninit, c.oopAlignedDisjointArraycopyUninit, true); + + registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit); + registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy); + + if (c.useMultiplyToLenIntrinsic()) { + registerForeignCall(MULTIPLY_TO_LEN, c.multiplyToLen, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int)); + } + if (c.useSHA1Intrinsics()) { + registerForeignCall(SHA_IMPL_COMPRESS, c.sha1ImplCompress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any()); + } + if (c.useSHA256Intrinsics()) { + registerForeignCall(SHA2_IMPL_COMPRESS, c.sha256ImplCompress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any()); + } + if (c.useSHA512Intrinsics()) { + registerForeignCall(SHA5_IMPL_COMPRESS, c.sha512ImplCompress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any()); + } + if (c.useMulAddIntrinsic()) { + registerForeignCall(MUL_ADD, c.mulAdd, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int)); + } + if (c.useMontgomeryMultiplyIntrinsic()) { + registerForeignCall(MONTGOMERY_MULTIPLY, c.montgomeryMultiply, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int)); + } + if (c.useMontgomerySquareIntrinsic()) { + registerForeignCall(MONTGOMERY_SQUARE, c.montgomerySquare, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int)); + } + if (c.useSquareToLenIntrinsic()) { + registerForeignCall(SQUARE_TO_LEN, c.squareToLen, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int)); + } + + if (c.useAESIntrinsics) { + /* + * When the java.ext.dirs property is modified then the crypto classes might not be + * found. If that's the case we ignore the ClassNotFoundException and continue since we + * cannot replace a non-existing method anyway. + */ + try { + // These stubs do callee saving + registerForeignCall(ENCRYPT_BLOCK, c.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); + registerForeignCall(DECRYPT_BLOCK, c.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); + registerForeignCall(DECRYPT_BLOCK_WITH_ORIGINAL_KEY, c.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, + NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); + } catch (GraalError e) { + if (!(e.getCause() instanceof ClassNotFoundException)) { + throw e; + } + } + try { + // These stubs do callee saving + registerForeignCall(ENCRYPT, c.cipherBlockChainingEncryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, + NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); + registerForeignCall(DECRYPT, c.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, + NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); + registerForeignCall(DECRYPT_WITH_ORIGINAL_KEY, c.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, + NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); + } catch (GraalError e) { + if (!(e.getCause() instanceof ClassNotFoundException)) { + throw e; + } + } + } + } + + public HotSpotForeignCallLinkage getForeignCall(ForeignCallDescriptor descriptor) { + assert foreignCalls != null : descriptor; + return foreignCalls.get(descriptor); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java 2016-12-07 13:50:14.167409993 -0800 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2015, 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.meta; + +import java.lang.reflect.Type; + +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.phases.AheadOfTimeVerificationPhase; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.replacements.nodes.MacroNode; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Extension of {@link InvocationPlugins} that disables plugins based on runtime configuration. + */ +final class HotSpotInvocationPlugins extends InvocationPlugins { + final GraalHotSpotVMConfig config; + + HotSpotInvocationPlugins(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) { + super(metaAccess); + this.config = config; + } + + @Override + public void register(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) { + if (!config.usePopCountInstruction) { + if (name.equals("bitCount")) { + assert declaringClass.equals(Integer.class) || declaringClass.equals(Long.class); + return; + } + } + super.register(plugin, declaringClass, name, argumentTypes); + } + + @Override + public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable newNodes) { + for (Node node : newNodes) { + if (node instanceof MacroNode) { + // MacroNode based plugins can only be used for inlining since they + // require a valid bci should they need to replace themselves with + // an InvokeNode during lowering. + assert plugin.inlineOnly() : String.format("plugin that creates a %s (%s) must return true for inlineOnly(): %s", MacroNode.class.getSimpleName(), node, plugin); + } + } + if (GraalOptions.ImmutableCode.getValue()) { + for (Node node : newNodes) { + if (node.hasUsages() && node instanceof ConstantNode) { + ConstantNode c = (ConstantNode) node; + if (c.getStackKind() == JavaKind.Object && AheadOfTimeVerificationPhase.isIllegalObjectConstant(c)) { + if (isClass(c)) { + // This will be handled later by LoadJavaMirrorWithKlassPhase + } else { + // Tolerate uses in unused FrameStates + if (node.usages().filter((n) -> !(n instanceof FrameState) || n.hasUsages()).isNotEmpty()) { + throw new AssertionError("illegal constant node in AOT: " + node); + } + } + } + } + } + } + super.checkNewNodes(b, plugin, newNodes); + } + + private static boolean isClass(ConstantNode node) { + ResolvedJavaType type = StampTool.typeOrNull(node); + return type != null && "Ljava/lang/Class;".equals(type.getName()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotLoweringProvider.java 2016-12-07 13:50:14.432421642 -0800 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011, 2015, 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.meta; + +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.nodes.spi.LoweringProvider; + +/** + * HotSpot implementation of {@link LoweringProvider}. + */ +public interface HotSpotLoweringProvider extends LoweringProvider { + + void initialize(HotSpotProviders providers, GraalHotSpotVMConfig config); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java 2016-12-07 13:50:14.696433246 -0800 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2015, 2016, 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.meta; + +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; +import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.FieldReadEnabledInImmutableCode; + +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool; +import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.TypePlugin; +import org.graalvm.compiler.nodes.util.ConstantFoldUtil; +import org.graalvm.compiler.replacements.WordOperationPlugin; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.JavaTypeProfile; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * This plugin handles the HotSpot-specific customizations of bytecode parsing: + *

    + * {@link Word}-type rewriting for {@link GraphBuilderContext#parsingIntrinsic intrinsic} functions + * (snippets and method substitutions), by forwarding to the {@link WordOperationPlugin}. Note that + * we forward the {@link NodePlugin} and {@link TypePlugin} methods, but not the + * {@link InlineInvokePlugin} methods implemented by {@link WordOperationPlugin}. The latter is not + * necessary because HotSpot only uses the {@link Word} type in methods that are force-inlined, + * i.e., there are never non-inlined invokes that involve the {@link Word} type. + *

    + * Constant folding of field loads. + */ +public final class HotSpotNodePlugin implements NodePlugin, TypePlugin { + protected final WordOperationPlugin wordOperationPlugin; + + public HotSpotNodePlugin(WordOperationPlugin wordOperationPlugin) { + this.wordOperationPlugin = wordOperationPlugin; + } + + @Override + public boolean canChangeStackKind(GraphBuilderContext b) { + if (b.parsingIntrinsic()) { + return wordOperationPlugin.canChangeStackKind(b); + } + return false; + } + + @Override + public StampPair interceptType(GraphBuilderTool b, JavaType declaredType, boolean nonNull) { + if (b.parsingIntrinsic()) { + return wordOperationPlugin.interceptType(b, declaredType, nonNull); + } + return null; + } + + @Override + public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleInvoke(b, method, args)) { + return true; + } + return false; + } + + @Override + public boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) { + if (!ImmutableCode.getValue() || b.parsingIntrinsic()) { + if (object.isConstant()) { + JavaConstant asJavaConstant = object.asJavaConstant(); + if (tryReadField(b, field, asJavaConstant)) { + return true; + } + } + } + if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadField(b, object, field)) { + return true; + } + return false; + } + + @Override + public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field) { + if (!ImmutableCode.getValue() || b.parsingIntrinsic()) { + if (tryReadField(b, field, null)) { + return true; + } + } + if (GeneratePIC.getValue()) { + if (field.isSynthetic() && field.getName().startsWith("$assertionsDisabled")) { + return tryReadField(b, field, null); + } + } + if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) { + return true; + } + return false; + } + + private static boolean tryReadField(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object) { + // FieldReadEnabledInImmutableCode is non null only if assertions are enabled + if (FieldReadEnabledInImmutableCode != null && ImmutableCode.getValue()) { + FieldReadEnabledInImmutableCode.set(Boolean.TRUE); + try { + return tryConstantFold(b, field, object); + } finally { + FieldReadEnabledInImmutableCode.set(null); + } + } else { + return tryConstantFold(b, field, object); + } + } + + private static boolean tryConstantFold(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object) { + ConstantNode result = ConstantFoldUtil.tryConstantFold(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), field, object); + if (result != null) { + result = b.getGraph().unique(result); + b.push(field.getJavaKind(), result); + return true; + } + return false; + } + + @Override + public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreField(b, object, field, value)) { + return true; + } + return false; + } + + @Override + public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreStaticField(b, field, value)) { + return true; + } + return false; + } + + @Override + public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadIndexed(b, array, index, elementKind)) { + return true; + } + return false; + } + + @Override + public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreIndexed(b, array, index, elementKind, value)) { + return true; + } + return false; + } + + @Override + public boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleCheckCast(b, object, type, profile)) { + return true; + } + return false; + } + + @Override + public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { + if (b.parsingIntrinsic() && wordOperationPlugin.handleInstanceOf(b, object, type, profile)) { + return true; + } + return false; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProfilingPlugin.java 2016-12-07 13:50:14.960444850 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015, 2016, 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.meta; + +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileBranchNode; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.ConditionalNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.ProfilingPlugin; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public abstract class HotSpotProfilingPlugin implements ProfilingPlugin { + public static class Options { + @Option(help = "Emit profiling of invokes", type = OptionType.Expert)// + public static final OptionValue ProfileInvokes = new OptionValue<>(true); + @Option(help = "Emit profiling of backedges", type = OptionType.Expert)// + public static final OptionValue ProfileBackedges = new OptionValue<>(true); + } + + public abstract int invokeNotifyFreqLog(); + + public abstract int invokeInlineeNotifyFreqLog(); + + public abstract int invokeProfilePobabilityLog(); + + public abstract int backedgeNotifyFreqLog(); + + public abstract int backedgeProfilePobabilityLog(); + + @Override + public boolean shouldProfile(GraphBuilderContext builder, ResolvedJavaMethod method) { + return !builder.parsingIntrinsic(); + } + + @Override + public void profileInvoke(GraphBuilderContext builder, ResolvedJavaMethod method, FrameState frameState) { + assert shouldProfile(builder, method); + if (Options.ProfileInvokes.getValue() && !method.isClassInitializer()) { + ProfileNode p = builder.append(new ProfileInvokeNode(method, invokeNotifyFreqLog(), invokeProfilePobabilityLog())); + p.setStateBefore(frameState); + } + } + + @Override + public void profileGoto(GraphBuilderContext builder, ResolvedJavaMethod method, int bci, int targetBci, FrameState frameState) { + assert shouldProfile(builder, method); + if (Options.ProfileBackedges.getValue() && targetBci <= bci) { + ProfileNode p = builder.append(new ProfileBranchNode(method, backedgeNotifyFreqLog(), backedgeProfilePobabilityLog(), bci, targetBci)); + p.setStateBefore(frameState); + } + } + + @Override + public void profileIf(GraphBuilderContext builder, ResolvedJavaMethod method, int bci, LogicNode condition, int trueBranchBci, int falseBranchBci, FrameState frameState) { + assert shouldProfile(builder, method); + if (Options.ProfileBackedges.getValue() && (falseBranchBci <= bci || trueBranchBci <= bci)) { + boolean negate = false; + int targetBci = trueBranchBci; + if (falseBranchBci <= bci) { + assert trueBranchBci > bci; + negate = true; + targetBci = falseBranchBci; + } else { + assert trueBranchBci <= bci && falseBranchBci > bci; + } + ValueNode trueValue = builder.append(ConstantNode.forBoolean(!negate)); + ValueNode falseValue = builder.append(ConstantNode.forBoolean(negate)); + ConditionalNode branchCondition = builder.append(new ConditionalNode(condition, trueValue, falseValue)); + ProfileNode p = builder.append(new ProfileBranchNode(method, backedgeNotifyFreqLog(), backedgeProfilePobabilityLog(), branchCondition, bci, targetBci)); + p.setStateBefore(frameState); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProviders.java 2016-12-07 13:50:15.224456455 -0800 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013, 2016, 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.meta; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; +import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.spi.LoweringProvider; +import org.graalvm.compiler.nodes.spi.NodeCostProvider; +import org.graalvm.compiler.nodes.spi.Replacements; +import org.graalvm.compiler.phases.tiers.SuitesProvider; +import org.graalvm.compiler.phases.util.Providers; + +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; + +/** + * Extends {@link Providers} to include a number of extra capabilities used by the HotSpot parts of + * the compiler. + */ +public class HotSpotProviders extends Providers { + + private final SuitesProvider suites; + private final HotSpotRegistersProvider registers; + private final SnippetReflectionProvider snippetReflection; + private final HotSpotWordTypes wordTypes; + private final Plugins graphBuilderPlugins; + + public HotSpotProviders(MetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantField, + HotSpotForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, NodeCostProvider nodeCostProvider, SuitesProvider suites, + HotSpotRegistersProvider registers, + SnippetReflectionProvider snippetReflection, HotSpotWordTypes wordTypes, Plugins graphBuilderPlugins) { + super(metaAccess, codeCache, constantReflection, constantField, foreignCalls, lowerer, replacements, new HotSpotStampProvider(), nodeCostProvider); + this.suites = suites; + this.registers = registers; + this.snippetReflection = snippetReflection; + this.wordTypes = wordTypes; + this.graphBuilderPlugins = graphBuilderPlugins; + } + + @Override + public HotSpotCodeCacheProvider getCodeCache() { + return (HotSpotCodeCacheProvider) super.getCodeCache(); + } + + @Override + public HotSpotForeignCallsProvider getForeignCalls() { + return (HotSpotForeignCallsProvider) super.getForeignCalls(); + } + + public SuitesProvider getSuites() { + return suites; + } + + public HotSpotRegistersProvider getRegisters() { + return registers; + } + + public SnippetReflectionProvider getSnippetReflection() { + return snippetReflection; + } + + public Plugins getGraphBuilderPlugins() { + return graphBuilderPlugins; + } + + public HotSpotWordTypes getWordTypes() { + return wordTypes; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotRegisters.java 2016-12-07 13:50:15.488468059 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, 2012, 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.meta; + +import jdk.vm.ci.code.Register; + +public class HotSpotRegisters implements HotSpotRegistersProvider { + + private final Register threadRegister; + private final Register heapBaseRegister; + private final Register stackPointerRegister; + + public HotSpotRegisters(Register threadRegister, Register heapBaseRegister, Register stackPointerRegister) { + this.threadRegister = threadRegister; + this.heapBaseRegister = heapBaseRegister; + this.stackPointerRegister = stackPointerRegister; + } + + @Override + public Register getThreadRegister() { + assert !threadRegister.equals(Register.None) : "thread register is not defined"; + return threadRegister; + } + + @Override + public Register getHeapBaseRegister() { + assert !heapBaseRegister.equals(Register.None) : "heap base register is not defined"; + return heapBaseRegister; + } + + @Override + public Register getStackPointerRegister() { + assert !stackPointerRegister.equals(Register.None) : "stack pointer register is not defined"; + return stackPointerRegister; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotRegistersProvider.java 2016-12-07 13:50:15.754479751 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011, 2012, 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.meta; + +import jdk.vm.ci.code.Register; + +/** + * Special registers reserved by HotSpot for frequently used values. + */ +public interface HotSpotRegistersProvider { + + /** + * Gets the register holding the current thread. + */ + Register getThreadRegister(); + + /** + * Gets the register holding the heap base address for compressed pointers. + */ + Register getHeapBaseRegister(); + + /** + * Gets the stack pointer register. + */ + Register getStackPointerRegister(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java 2016-12-07 13:50:16.019491400 -0800 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014, 2015, 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.meta; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaType; + +public class HotSpotSnippetReflectionProvider implements SnippetReflectionProvider { + + private final HotSpotGraalRuntimeProvider runtime; + private final HotSpotConstantReflectionProvider constantReflection; + private final WordTypes wordTypes; + + public HotSpotSnippetReflectionProvider(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) { + this.runtime = runtime; + this.constantReflection = constantReflection; + this.wordTypes = wordTypes; + } + + @Override + public JavaConstant forObject(Object object) { + return constantReflection.forObject(object); + } + + @Override + public Object asObject(ResolvedJavaType type, JavaConstant constant) { + if (constant.isNull()) { + return null; + } + HotSpotObjectConstant hsConstant = (HotSpotObjectConstant) constant; + return hsConstant.asObject(type); + } + + @Override + public T asObject(Class type, JavaConstant constant) { + if (constant.isNull()) { + return null; + } + HotSpotObjectConstant hsConstant = (HotSpotObjectConstant) constant; + return hsConstant.asObject(type); + } + + @Override + public JavaConstant forBoxed(JavaKind kind, Object value) { + if (kind == JavaKind.Object) { + return forObject(value); + } else { + return JavaConstant.forBoxedPrimitive(value); + } + } + + // Lazily initialized + private Class wordTypesType; + private Class runtimeType; + private Class configType; + + @Override + public T getInjectedNodeIntrinsicParameter(Class type) { + // Need to test all fields since there no guarantee under the JMM + // about the order in which these fields are written. + GraalHotSpotVMConfig config = runtime.getVMConfig(); + if (configType == null || wordTypesType == null || configType == null) { + wordTypesType = wordTypes.getClass(); + runtimeType = runtime.getClass(); + configType = config.getClass(); + } + + if (type.isAssignableFrom(wordTypesType)) { + return type.cast(wordTypes); + } + if (type.isAssignableFrom(runtimeType)) { + return type.cast(runtime); + } + if (type.isAssignableFrom(configType)) { + return type.cast(config); + } + return null; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotStampProvider.java 2016-12-07 13:50:16.283503004 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014, 2014, 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.meta; + +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp; +import org.graalvm.compiler.nodes.spi.StampProvider; + +public class HotSpotStampProvider implements StampProvider { + + @Override + public Stamp createHubStamp(ObjectStamp object) { + return KlassPointerStamp.klassNonNull(); + } + + @Override + public Stamp createMethodStamp() { + return MethodPointerStamp.methodNonNull(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java 2016-12-07 13:50:16.548514652 -0800 @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2015, 2016, 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.meta; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; +import static org.graalvm.compiler.core.common.GraalOptions.VerifyPhases; + +import java.util.ListIterator; + +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.HotSpotInstructionProfiling; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.phases.AheadOfTimeVerificationPhase; +import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase; +import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase; +import org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase; +import org.graalvm.compiler.hotspot.phases.aot.AOTInliningPolicy; +import org.graalvm.compiler.hotspot.phases.aot.EliminateRedundantInitializationPhase; +import org.graalvm.compiler.hotspot.phases.aot.ReplaceConstantNodesPhase; +import org.graalvm.compiler.hotspot.phases.profiling.FinalizeProfileNodesPhase; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.java.SuitesProviderBase; +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.nodes.EncodedGraph; +import org.graalvm.compiler.nodes.GraphEncoder; +import org.graalvm.compiler.nodes.SimplifyingGraphDecoder; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.AddressLoweringPhase; +import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.ExpandLogicPhase; +import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.Suites; +import org.graalvm.compiler.phases.tiers.SuitesCreator; + +/** + * HotSpot implementation of {@link SuitesCreator}. + */ +public class HotSpotSuitesProvider extends SuitesProviderBase { + + protected final GraalHotSpotVMConfig config; + protected final HotSpotGraalRuntimeProvider runtime; + + private final AddressLowering addressLowering; + private final SuitesCreator defaultSuitesCreator; + + public HotSpotSuitesProvider(SuitesCreator defaultSuitesCreator, GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, AddressLowering addressLowering) { + this.defaultSuitesCreator = defaultSuitesCreator; + this.config = config; + this.runtime = runtime; + this.addressLowering = addressLowering; + this.defaultGraphBuilderSuite = createGraphBuilderSuite(); + } + + @Override + public Suites createSuites() { + Suites ret = defaultSuitesCreator.createSuites(); + + if (ImmutableCode.getValue()) { + // lowering introduces class constants, therefore it must be after lowering + ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase(config.classMirrorOffset, config.useCompressedOops ? config.getOopEncoding() : null)); + if (VerifyPhases.getValue()) { + ret.getHighTier().appendPhase(new AheadOfTimeVerificationPhase()); + } + if (GeneratePIC.getValue()) { + // EliminateRedundantInitializationPhase must happen before the first lowering. + ListIterator> highTierLowering = ret.getHighTier().findPhase(LoweringPhase.class); + highTierLowering.previous(); + highTierLowering.add(new EliminateRedundantInitializationPhase()); + if (HotSpotAOTProfilingPlugin.Options.TieredAOT.getValue()) { + highTierLowering.add(new FinalizeProfileNodesPhase(HotSpotAOTProfilingPlugin.Options.TierAInvokeInlineeNotifyFreqLog.getValue())); + } + ret.getMidTier().findPhase(LoopSafepointInsertionPhase.class).add(new ReplaceConstantNodesPhase()); + + // Replace inlining policy + ListIterator> iter = ret.getHighTier().findPhase(InliningPhase.class); + InliningPhase inlining = (InliningPhase) iter.previous(); + CanonicalizerPhase canonicalizer = inlining.getCanonicalizer(); + iter.set(new InliningPhase(new AOTInliningPolicy(null), canonicalizer)); + } + } + + ret.getMidTier().appendPhase(new WriteBarrierAdditionPhase(config)); + if (VerifyPhases.getValue()) { + ret.getMidTier().appendPhase(new WriteBarrierVerificationPhase(config)); + } + + ret.getLowTier().findPhase(ExpandLogicPhase.class).add(new AddressLoweringPhase(addressLowering)); + + return ret; + } + + protected PhaseSuite createGraphBuilderSuite() { + PhaseSuite suite = defaultSuitesCreator.getDefaultGraphBuilderSuite().copy(); + assert appendGraphEncoderTest(suite); + return suite; + } + + /** + * When assertions are enabled, we encode and decode every parsed graph, to ensure that the + * encoding and decoding process work correctly. The decoding performs canonicalization during + * decoding, so the decoded graph can be different than the encoded graph - we cannot check them + * for equality here. However, the encoder {@link GraphEncoder#verifyEncoding verifies the + * encoding itself}, i.e., performs a decoding without canoncialization and checks the graphs + * for equality. + */ + private boolean appendGraphEncoderTest(PhaseSuite suite) { + suite.appendPhase(new BasePhase() { + @Override + protected void run(StructuredGraph graph, HighTierContext context) { + EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, runtime.getTarget().arch); + + SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), + context.getStampProvider(), !ImmutableCode.getValue(), runtime.getTarget().arch); + StructuredGraph targetGraph = new StructuredGraph(graph.method(), AllowAssumptions.YES, INVALID_COMPILATION_ID); + graphDecoder.decode(targetGraph, encodedGraph); + } + + @Override + protected CharSequence getName() { + return "VerifyEncodingDecoding"; + } + }); + return true; + } + + /** + * Modifies a given {@link GraphBuilderConfiguration} to record per node source information. + * + * @param gbs the current graph builder suite to modify + */ + public static PhaseSuite withNodeSourcePosition(PhaseSuite gbs) { + PhaseSuite newGbs = gbs.copy(); + GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous(); + GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig(); + GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig.withNodeSourcePosition(true)); + newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase); + return newGbs; + } + + @Override + public LIRSuites createLIRSuites() { + LIRSuites suites = defaultSuitesCreator.createLIRSuites(); + String profileInstructions = HotSpotBackend.Options.ASMInstructionProfiling.getValue(); + if (profileInstructions != null) { + suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions)); + } + return suites; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java 2016-12-07 13:50:16.813526301 -0800 @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2015, 2016, 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.meta; + +import static org.graalvm.compiler.core.common.LocationIdentity.any; +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_EQ; +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE; +import static org.graalvm.compiler.nodes.ConstantNode.forBoolean; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.bytecode.BridgeMethodUtils; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.nodes.LoadIndexedPointerNode; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.nodes.type.MetaspacePointerStamp; +import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp; +import org.graalvm.compiler.hotspot.word.HotSpotOperation; +import org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode; +import org.graalvm.compiler.hotspot.word.PointerCastNode; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.ConditionalNode; +import org.graalvm.compiler.nodes.calc.IsNullNode; +import org.graalvm.compiler.nodes.calc.PointerEqualsNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.java.LoadIndexedNode; +import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.replacements.WordOperationPlugin; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Extends {@link WordOperationPlugin} to handle {@linkplain HotSpotOperation HotSpot word + * operations}. + */ +class HotSpotWordOperationPlugin extends WordOperationPlugin { + HotSpotWordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) { + super(snippetReflection, wordTypes); + } + + @Override + protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) { + ResolvedJavaType arrayType = StampTool.typeOrNull(array); + Stamp componentStamp = wordTypes.getWordStamp(arrayType.getComponentType()); + if (componentStamp instanceof MetaspacePointerStamp) { + return new LoadIndexedPointerNode(componentStamp, array, index); + } else { + return super.createLoadIndexedNode(array, index); + } + } + + @Override + public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + if (!wordTypes.isWordOperation(method)) { + return false; + } + + HotSpotOperation operation = BridgeMethodUtils.getAnnotation(HotSpotOperation.class, method); + if (operation == null) { + processWordOperation(b, args, wordTypes.getWordOperation(method, b.getMethod().getDeclaringClass())); + return true; + } + processHotSpotWordOperation(b, method, args, operation); + return true; + } + + protected void processHotSpotWordOperation(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, HotSpotOperation operation) { + JavaKind returnKind = method.getSignature().getReturnKind(); + switch (operation.opcode()) { + case POINTER_EQ: + case POINTER_NE: + assert args.length == 2; + HotspotOpcode opcode = operation.opcode(); + ValueNode left = args[0]; + ValueNode right = args[1]; + assert left.stamp() instanceof MetaspacePointerStamp : left + " " + left.stamp(); + assert right.stamp() instanceof MetaspacePointerStamp : right + " " + right.stamp(); + assert opcode == POINTER_EQ || opcode == POINTER_NE; + + PointerEqualsNode comparison = b.add(new PointerEqualsNode(left, right)); + ValueNode eqValue = b.add(forBoolean(opcode == POINTER_EQ)); + ValueNode neValue = b.add(forBoolean(opcode == POINTER_NE)); + b.addPush(returnKind, new ConditionalNode(comparison, eqValue, neValue)); + break; + + case IS_NULL: + assert args.length == 1; + ValueNode pointer = args[0]; + assert pointer.stamp() instanceof MetaspacePointerStamp; + + LogicNode isNull = b.add(IsNullNode.create(pointer)); + b.addPush(returnKind, new ConditionalNode(isNull, b.add(forBoolean(true)), b.add(forBoolean(false)))); + break; + + case FROM_POINTER: + assert args.length == 1; + b.addPush(returnKind, new PointerCastNode(StampFactory.forKind(wordKind), args[0])); + break; + + case TO_KLASS_POINTER: + assert args.length == 1; + b.addPush(returnKind, new PointerCastNode(KlassPointerStamp.klass(), args[0])); + break; + + case TO_METHOD_POINTER: + assert args.length == 1; + b.addPush(returnKind, new PointerCastNode(MethodPointerStamp.method(), args[0])); + break; + + case READ_KLASS_POINTER: + assert args.length == 2 || args.length == 3; + Stamp readStamp = KlassPointerStamp.klass(); + AddressNode address = makeAddress(b, args[0], args[1]); + LocationIdentity location; + if (args.length == 2) { + location = any(); + } else { + assert args[2].isConstant(); + location = snippetReflection.asObject(LocationIdentity.class, args[2].asJavaConstant()); + } + ReadNode read = b.add(new ReadNode(address, location, readStamp, BarrierType.NONE)); + /* + * The read must not float outside its block otherwise it may float above an + * explicit zero check on its base address. + */ + read.setGuard(AbstractBeginNode.prevBegin(read)); + b.push(returnKind, read); + break; + + default: + throw GraalError.shouldNotReachHere("unknown operation: " + operation.opcode()); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/AcquiredCASLockNode.java 2016-12-07 13:50:17.078537949 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +/** + * Marks the control flow path where an object acquired a lightweight lock based on an atomic + * compare-and-swap (CAS) of the mark word in the object's header. + */ +@NodeInfo(cycles = CYCLES_0, size = SIZE_0) +public final class AcquiredCASLockNode extends FixedWithNextNode implements LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(AcquiredCASLockNode.class); + + @Input ValueNode object; + + public AcquiredCASLockNode(ValueNode object) { + super(TYPE, StampFactory.forVoid()); + this.object = object; + } + + public ValueNode object() { + return object; + } + + @Override + public void generate(NodeLIRBuilderTool generator) { + // This is just a marker node so it generates nothing + } + + @NodeIntrinsic + public static native void mark(Object object); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/AllocaNode.java 2016-12-07 13:50:17.343549597 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import java.util.BitSet; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; + +/** + * Reserves a block of memory in the stack frame of a method. The block is reserved in the frame for + * the entire execution of the associated method. + */ +@NodeInfo(cycles = CYCLES_2, size = SIZE_1) +public final class AllocaNode extends FixedWithNextNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(AllocaNode.class); + /** + * The number of slots in block. + */ + protected final int slots; + + /** + * The indexes of the object pointer slots in the block. Each such object pointer slot must be + * initialized before any safepoint in the method otherwise the garbage collector will see + * garbage values when processing these slots. + */ + protected final BitSet objects; + + public AllocaNode(@InjectedNodeParameter WordTypes wordTypes, int slots) { + this(slots, wordTypes.getWordKind(), new BitSet()); + } + + public AllocaNode(int slots, JavaKind wordKind, BitSet objects) { + super(TYPE, StampFactory.forKind(wordKind)); + this.slots = slots; + this.objects = objects; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + VirtualStackSlot array = gen.getLIRGeneratorTool().getResult().getFrameMapBuilder().allocateStackSlots(slots, objects, null); + Value result = gen.getLIRGeneratorTool().emitAddress(array); + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native Word alloca(@ConstantNodeParameter int slots); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ArrayRangeWriteBarrier.java 2016-12-07 13:50:17.607561201 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.Lowerable; + +@NodeInfo +public abstract class ArrayRangeWriteBarrier extends WriteBarrier implements Lowerable { + + public static final NodeClass TYPE = NodeClass.create(ArrayRangeWriteBarrier.class); + @Input ValueNode object; + @Input ValueNode startIndex; + @Input ValueNode length; + + protected ArrayRangeWriteBarrier(NodeClass c, ValueNode object, ValueNode startIndex, ValueNode length) { + super(c); + this.object = object; + this.startIndex = startIndex; + this.length = length; + } + + public ValueNode getObject() { + return object; + } + + public ValueNode getStartIndex() { + return startIndex; + } + + public ValueNode getLength() { + return length; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java 2016-12-07 13:50:17.873572894 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012, 2016, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.InputType.Memory; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.extended.MonitorEnter; +import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.meta.Value; + +/** + * Intrinsic for opening a scope binding a stack-based lock with an object. A lock scope must be + * closed with an {@link EndLockScopeNode}. The frame state after this node denotes that the object + * is locked (ensuring the GC sees and updates the object) so it must come after any null pointer + * check on the object. + */ +@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_2, size = SIZE_1) +public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorEnter, MemoryCheckpoint.Single { + + public static final NodeClass TYPE = NodeClass.create(BeginLockScopeNode.class); + protected int lockDepth; + + public BeginLockScopeNode(@InjectedNodeParameter WordTypes wordTypes, int lockDepth) { + super(TYPE, StampFactory.forKind(wordTypes.getWordKind())); + this.lockDepth = lockDepth; + } + + @Override + public boolean hasSideEffect() { + return false; + } + + @Override + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert lockDepth != -1; + HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool(); + VirtualStackSlot slot = hsGen.getLockSlot(lockDepth); + Value result = gen.getLIRGeneratorTool().emitAddress(slot); + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native Word beginLockScope(@ConstantNodeParameter int lockDepth); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CompressionNode.java 2016-12-07 13:50:18.138584542 -0800 @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2014, 2016, 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.nodes; + +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; + +import org.graalvm.compiler.core.common.type.AbstractObjectStamp; +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.CompressEncoding; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.ConvertNode; +import org.graalvm.compiler.nodes.calc.UnaryNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.type.StampTool; + +import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.Value; + +/** + * Compress or uncompress an oop or metaspace pointer. + */ +@NodeInfo(nameTemplate = "{p#op/s}", cycles = CYCLES_2, size = SIZE_2) +public final class CompressionNode extends UnaryNode implements ConvertNode, LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(CompressionNode.class); + + public enum CompressionOp { + Compress, + Uncompress + } + + protected final CompressionOp op; + protected final CompressEncoding encoding; + + public CompressionNode(CompressionOp op, ValueNode input, CompressEncoding encoding) { + super(TYPE, mkStamp(op, input.stamp(), encoding), input); + this.op = op; + this.encoding = encoding; + } + + @Override + public Stamp foldStamp(Stamp newStamp) { + assert newStamp.isCompatible(getValue().stamp()); + return mkStamp(op, newStamp, encoding); + } + + public static CompressionNode compress(ValueNode input, CompressEncoding encoding) { + return input.graph().unique(new CompressionNode(CompressionOp.Compress, input, encoding)); + } + + public static CompressionNode compressNoUnique(ValueNode input, CompressEncoding encoding) { + return new CompressionNode(CompressionOp.Compress, input, encoding); + } + + public static CompressionNode uncompress(ValueNode input, CompressEncoding encoding) { + return input.graph().unique(new CompressionNode(CompressionOp.Uncompress, input, encoding)); + } + + private static Constant compress(Constant c) { + if (JavaConstant.NULL_POINTER.equals(c)) { + return HotSpotCompressedNullConstant.COMPRESSED_NULL; + } else if (c instanceof HotSpotConstant) { + return ((HotSpotConstant) c).compress(); + } else { + throw GraalError.shouldNotReachHere("invalid constant input for compress op: " + c); + } + } + + private static Constant uncompress(Constant c) { + if (c instanceof HotSpotConstant) { + return ((HotSpotConstant) c).uncompress(); + } else { + throw GraalError.shouldNotReachHere("invalid constant input for uncompress op: " + c); + } + } + + @Override + public Constant convert(Constant c, ConstantReflectionProvider constantReflection) { + switch (op) { + case Compress: + return compress(c); + case Uncompress: + return uncompress(c); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) { + switch (op) { + case Compress: + return uncompress(c); + case Uncompress: + return compress(c); + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Override + public boolean isLossless() { + return true; + } + + private static Stamp mkStamp(CompressionOp op, Stamp input, CompressEncoding encoding) { + switch (op) { + case Compress: + if (input instanceof ObjectStamp) { + // compressed oop + return NarrowOopStamp.compressed((ObjectStamp) input, encoding); + } else if (input instanceof KlassPointerStamp) { + // compressed klass pointer + return ((KlassPointerStamp) input).compressed(encoding); + } + break; + case Uncompress: + if (input instanceof NarrowOopStamp) { + // oop + assert encoding.equals(((NarrowOopStamp) input).getEncoding()); + return ((NarrowOopStamp) input).uncompressed(); + } else if (input instanceof KlassPointerStamp) { + // metaspace pointer + assert encoding.equals(((KlassPointerStamp) input).getEncoding()); + return ((KlassPointerStamp) input).uncompressed(); + } + break; + } + throw GraalError.shouldNotReachHere(String.format("Unexpected input stamp %s", input)); + } + + public CompressionOp getOp() { + return op; + } + + public CompressEncoding getEncoding() { + return encoding; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { + if (forValue.isConstant()) { + if (GeneratePIC.getValue()) { + // We always want uncompressed constants + return this; + } + int stableDimension = ((ConstantNode) forValue).getStableDimension(); + boolean isDefaultStable = ((ConstantNode) forValue).isDefaultStable(); + return ConstantNode.forConstant(stamp(), convert(forValue.asConstant(), tool.getConstantReflection()), stableDimension, isDefaultStable, tool.getMetaAccess()); + } else if (forValue instanceof CompressionNode) { + CompressionNode other = (CompressionNode) forValue; + if (op != other.op && encoding.equals(other.encoding)) { + return other.getValue(); + } + } + return this; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool(); + boolean nonNull; + if (getValue().stamp() instanceof AbstractObjectStamp) { + nonNull = StampTool.isPointerNonNull(getValue().stamp()); + } else { + // metaspace pointers are never null + nonNull = true; + } + + Value result; + switch (op) { + case Compress: + result = hsGen.emitCompress(gen.operand(getValue()), encoding, nonNull); + break; + case Uncompress: + result = hsGen.emitUncompress(gen.operand(getValue()), encoding, nonNull); + break; + default: + throw GraalError.shouldNotReachHere(); + } + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native Object compression(@ConstantNodeParameter CompressionOp op, Object object, @ConstantNodeParameter CompressEncoding encoding); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ComputeObjectAddressNode.java 2016-12-07 13:50:18.402596146 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.debug.ControlFlowAnchored; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +import jdk.vm.ci.meta.JavaKind; + +/** + * A high-level intrinsic for getting an address inside of an object. During lowering it will be + * moved next to any uses to avoid creating a derived pointer that is live across a safepoint. + */ +@NodeInfo(cycles = CYCLES_3, size = SIZE_2) +public final class ComputeObjectAddressNode extends FixedWithNextNode implements Lowerable, ControlFlowAnchored { + public static final NodeClass TYPE = NodeClass.create(ComputeObjectAddressNode.class); + + @Input ValueNode object; + @Input ValueNode offset; + + public ComputeObjectAddressNode(ValueNode obj, ValueNode offset) { + super(TYPE, StampFactory.forKind(JavaKind.Long)); + this.object = obj; + this.offset = offset; + } + + @NodeIntrinsic + public static native long get(Object array, long offset); + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + public ValueNode getObject() { + return object; + } + + public ValueNode getOffset() { + return offset; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CurrentJavaThreadNode.java 2016-12-07 13:50:18.666607750 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; + +/** + * Gets the address of the C++ JavaThread object for the current thread. + */ +@NodeInfo(cycles = CYCLES_1, size = SIZE_1) +public final class CurrentJavaThreadNode extends FloatingNode implements LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(CurrentJavaThreadNode.class); + + public CurrentJavaThreadNode(@InjectedNodeParameter WordTypes wordTypes) { + this(wordTypes.getWordKind()); + } + + public CurrentJavaThreadNode(JavaKind wordKind) { + super(TYPE, StampFactory.forKind(wordKind)); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + Register rawThread = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).getProviders().getRegisters().getThreadRegister(); + PlatformKind wordKind = gen.getLIRGeneratorTool().target().arch.getWordKind(); + gen.setResult(this, rawThread.asValue(LIRKind.value(wordKind))); + } + + @NodeIntrinsic + public static native Word get(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CurrentLockNode.java 2016-12-07 13:50:18.931619399 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.meta.Value; + +/** + * Intrinsic for getting the lock in the current {@linkplain BeginLockScopeNode lock scope}. + */ +@NodeInfo(cycles = CYCLES_2, size = SIZE_1) +public final class CurrentLockNode extends FixedWithNextNode implements LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(CurrentLockNode.class); + + protected int lockDepth; + + public CurrentLockNode(@InjectedNodeParameter WordTypes wordTypes, int lockDepth) { + super(TYPE, StampFactory.forKind(wordTypes.getWordKind())); + this.lockDepth = lockDepth; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert lockDepth != -1; + HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool(); + VirtualStackSlot slot = hsGen.getLockSlot(lockDepth); + // The register allocator cannot handle stack -> register moves so we use an LEA here + Value result = gen.getLIRGeneratorTool().emitAddress(slot); + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native Word currentLock(@ConstantNodeParameter int lockDepth); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java 2016-12-07 13:50:19.195631003 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014, 2016, 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.nodes; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.FETCH_UNROLL_INFO; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; + +/** + * A call to the runtime code {@code Deoptimization::fetch_unroll_info}. + */ +@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) +public final class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single { + + public static final NodeClass TYPE = NodeClass.create(DeoptimizationFetchUnrollInfoCallNode.class); + @Input SaveAllRegistersNode registerSaver; + @Input ValueNode mode; + protected final ForeignCallsProvider foreignCalls; + + public DeoptimizationFetchUnrollInfoCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver, ValueNode mode) { + super(TYPE, StampFactory.forKind(JavaKind.fromJavaClass(FETCH_UNROLL_INFO.getResultType()))); + this.registerSaver = (SaveAllRegistersNode) registerSaver; + this.mode = mode; + this.foreignCalls = foreignCalls; + } + + @Override + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); + } + + public SaveRegistersOp getSaveRegistersOp() { + return registerSaver.getSaveRegistersOp(); + } + + /** + * Returns the node representing the exec_mode/unpack_kind used during this fetch_unroll_info + * call. + */ + public ValueNode getMode() { + return mode; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitDeoptimizationFetchUnrollInfoCall(gen.operand(getMode()), getSaveRegistersOp()); + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native Word fetchUnrollInfo(long registerSaver, int mode); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizeCallerNode.java 2016-12-07 13:50:19.459642607 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, 2011, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ControlSinkNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; + +/** + * Removes the current frame and tail calls the uncommon trap routine. + */ +@NodeInfo(shortName = "DeoptCaller", nameTemplate = "DeoptCaller {p#reason/s}", cycles = CYCLES_1, size = SIZE_3) +public final class DeoptimizeCallerNode extends ControlSinkNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(DeoptimizeCallerNode.class); + protected final DeoptimizationAction action; + protected final DeoptimizationReason reason; + + public DeoptimizeCallerNode(DeoptimizationAction action, DeoptimizationReason reason) { + super(TYPE, StampFactory.forVoid()); + this.action = action; + this.reason = reason; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitDeoptimizeCaller(action, reason); + } + + @NodeIntrinsic + public static native void deopt(@ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter DeoptimizationReason reason); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizingStubCall.java 2016-12-07 13:50:19.725654300 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; + +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; + +@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) +public abstract class DeoptimizingStubCall extends DeoptimizingFixedWithNextNode { + + public static final NodeClass TYPE = NodeClass.create(DeoptimizingStubCall.class); + + public DeoptimizingStubCall(NodeClass c, Stamp stamp) { + super(c, stamp); + } + + @Override + public boolean canDeoptimize() { + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DimensionsNode.java 2016-12-07 13:50:19.992666036 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012, 2015, 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.nodes; + +import static org.graalvm.compiler.asm.NumUtil.roundUp; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import java.util.BitSet; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.meta.Value; + +/** + * Intrinsic for allocating an on-stack array of integers to hold the dimensions of a multianewarray + * instruction. + */ +@NodeInfo(cycles = CYCLES_2, size = SIZE_1) +public final class DimensionsNode extends FixedWithNextNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(DimensionsNode.class); + protected final int rank; + + public DimensionsNode(@InjectedNodeParameter WordTypes wordTypes, int rank) { + super(TYPE, StampFactory.forKind(wordTypes.getWordKind())); + this.rank = rank; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + LIRGeneratorTool lirGen = gen.getLIRGeneratorTool(); + int size = rank * 4; + int wordSize = lirGen.target().wordSize; + int slots = roundUp(size, wordSize) / wordSize; + VirtualStackSlot array = lirGen.getResult().getFrameMapBuilder().allocateStackSlots(slots, new BitSet(0), null); + Value result = lirGen.emitAddress(array); + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native Word allocaDimsArray(@ConstantNodeParameter int rank); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DirectCompareAndSwapNode.java 2016-12-07 13:50:20.258677728 -0800 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2012, 2016, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.InputType.Association; +import static org.graalvm.compiler.nodeinfo.InputType.Memory; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.StateSplit; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.java.CompareAndSwapNode; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode.Address; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; + +/** + * A special purpose store node that differs from {@link CompareAndSwapNode} in that it is not a + * {@link StateSplit} and it {@linkplain #compareAndSwap(Address, Word, Word, LocationIdentity)} + * returns either the expected value or the compared against value instead of a boolean. + */ +@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_30, size = SIZE_8) +public final class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single { + + public static final NodeClass TYPE = NodeClass.create(DirectCompareAndSwapNode.class); + @Input(Association) AddressNode address; + @Input ValueNode expectedValue; + @Input ValueNode newValue; + + protected final LocationIdentity locationIdentity; + + public DirectCompareAndSwapNode(ValueNode address, ValueNode expected, ValueNode newValue, LocationIdentity locationIdentity) { + super(TYPE, expected.stamp()); + this.address = (AddressNode) address; + this.expectedValue = expected; + this.newValue = newValue; + this.locationIdentity = locationIdentity; + } + + public AddressNode getAddress() { + return address; + } + + public ValueNode expectedValue() { + return expectedValue; + } + + public ValueNode newValue() { + return newValue; + } + + @Override + public LocationIdentity getLocationIdentity() { + return locationIdentity; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + ((HotSpotNodeLIRBuilder) gen).visitDirectCompareAndSwap(this); + } + + /** + * Compares an expected value with the actual value in a location denoted by an address. Iff + * they are same, {@code newValue} is placed into the location and the {@code expectedValue} is + * returned. Otherwise, the actual value is returned. All of the above is performed in one + * atomic hardware transaction. + * + * @param address the address to be atomically tested and updated + * @param expectedValue if this value is currently in the field, perform the swap + * @param newValue the new value to put into the field + * @return either {@code expectedValue} or the actual value + */ + @NodeIntrinsic + public static native Word compareAndSwap(Address address, Word expectedValue, Word newValue, @ConstantNodeParameter LocationIdentity locationIdentity); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java 2016-12-07 13:50:20.523689376 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012, 2016, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.InputType.Memory; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.extended.MonitorExit; +import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +/** + * Intrinsic for closing a {@linkplain BeginLockScopeNode scope} binding a stack-based lock with an + * object. + */ +@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_0, size = SIZE_0) +public final class EndLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorExit, MemoryCheckpoint.Single { + public static final NodeClass TYPE = NodeClass.create(EndLockScopeNode.class); + + public EndLockScopeNode() { + super(TYPE, StampFactory.forVoid()); + } + + @Override + public boolean hasSideEffect() { + return false; + } + + @Override + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + } + + @NodeIntrinsic + public static native void endLockScope(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EnterUnpackFramesStackFrameNode.java 2016-12-07 13:50:20.787700981 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2013, 2014, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_10; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.Value; + +/** + * Emits code to enter a low-level stack frame specifically to call out to the C++ method + * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}. + */ +@NodeInfo(cycles = CYCLES_20, size = SIZE_10) +public final class EnterUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(EnterUnpackFramesStackFrameNode.class); + + @Input ValueNode framePc; + @Input ValueNode senderSp; + @Input ValueNode senderFp; + @Input SaveAllRegistersNode registerSaver; + + public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp, ValueNode registerSaver) { + super(TYPE, StampFactory.forVoid()); + this.framePc = framePc; + this.senderSp = senderSp; + this.senderFp = senderFp; + this.registerSaver = (SaveAllRegistersNode) registerSaver; + } + + private SaveRegistersOp getSaveRegistersOp() { + return registerSaver.getSaveRegistersOp(); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + Value operandValue = gen.operand(framePc); + Value senderSpValue = gen.operand(senderSp); + Value senderFpValue = gen.operand(senderFp); + ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitEnterUnpackFramesStackFrame(operandValue, senderSpValue, senderFpValue, getSaveRegistersOp()); + } + + @NodeIntrinsic + public static native void enterUnpackFramesStackFrame(Word framePc, Word senderSp, Word senderFp, long registerSaver); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/FastAcquireBiasedLockNode.java 2016-12-07 13:50:21.051712585 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +/** + * Marks the control flow path where an object acquired a biased lock because the lock was already + * biased to the object on the current thread. + */ +@NodeInfo(cycles = CYCLES_0, size = SIZE_0) +public final class FastAcquireBiasedLockNode extends FixedWithNextNode implements LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(FastAcquireBiasedLockNode.class); + + @Input ValueNode object; + + public FastAcquireBiasedLockNode(ValueNode object) { + super(TYPE, StampFactory.forVoid()); + this.object = object; + } + + public ValueNode object() { + return object; + } + + @Override + public void generate(NodeLIRBuilderTool generator) { + // This is just a marker node so it generates nothing + } + + @NodeIntrinsic + public static native void mark(Object object); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePostWriteBarrier.java 2016-12-07 13:50:21.315724189 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; + +@NodeInfo(cycles = CYCLES_100, size = SIZE_100) +public class G1ArrayRangePostWriteBarrier extends ArrayRangeWriteBarrier { + public static final NodeClass TYPE = NodeClass.create(G1ArrayRangePostWriteBarrier.class); + + public G1ArrayRangePostWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) { + super(TYPE, object, startIndex, length); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePreWriteBarrier.java 2016-12-07 13:50:21.583735969 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; + +@NodeInfo(cycles = CYCLES_100, size = SIZE_100) +public final class G1ArrayRangePreWriteBarrier extends ArrayRangeWriteBarrier { + public static final NodeClass TYPE = NodeClass.create(G1ArrayRangePreWriteBarrier.class); + + public G1ArrayRangePreWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) { + super(TYPE, object, startIndex, length); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PostWriteBarrier.java 2016-12-07 13:50:21.848747617 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; + +@NodeInfo(cycles = CYCLES_50, size = SIZE_50) +public class G1PostWriteBarrier extends ObjectWriteBarrier { + + public static final NodeClass TYPE = NodeClass.create(G1PostWriteBarrier.class); + protected final boolean alwaysNull; + + public G1PostWriteBarrier(AddressNode address, ValueNode value, boolean precise, boolean alwaysNull) { + this(TYPE, address, value, precise, alwaysNull); + } + + protected G1PostWriteBarrier(NodeClass c, AddressNode address, ValueNode value, boolean precise, boolean alwaysNull) { + super(c, address, value, precise); + this.alwaysNull = alwaysNull; + } + + public boolean alwaysNull() { + return alwaysNull; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PreWriteBarrier.java 2016-12-07 13:50:22.112759222 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.DeoptimizingNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; + +@NodeInfo(cycles = CYCLES_50, size = SIZE_50) +public final class G1PreWriteBarrier extends ObjectWriteBarrier implements DeoptimizingNode.DeoptBefore { + + public static final NodeClass TYPE = NodeClass.create(G1PreWriteBarrier.class); + + @OptionalInput(InputType.State) FrameState stateBefore; + protected final boolean nullCheck; + protected final boolean doLoad; + + public G1PreWriteBarrier(AddressNode address, ValueNode expectedObject, boolean doLoad, boolean nullCheck) { + super(TYPE, address, expectedObject, true); + this.doLoad = doLoad; + this.nullCheck = nullCheck; + } + + public ValueNode getExpectedObject() { + return getValue(); + } + + public boolean doLoad() { + return doLoad; + } + + public boolean getNullCheck() { + return nullCheck; + } + + @Override + public boolean canDeoptimize() { + return nullCheck; + } + + @Override + public FrameState stateBefore() { + return stateBefore; + } + + @Override + public void setStateBefore(FrameState state) { + updateUsages(stateBefore, state); + stateBefore = state; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ReferentFieldReadBarrier.java 2016-12-07 13:50:22.376770826 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; + +/** + * The {@code G1ReferentFieldReadBarrier} is added when a read access is performed to the referent + * field of a {@link java.lang.ref.Reference} object (through a {@code LoadFieldNode} or an + * {@code UnsafeLoadNode}). The return value of the read is passed to the snippet implementing the + * read barrier and consequently is added to the SATB queue if the concurrent marker is enabled. + */ +@NodeInfo(cycles = CYCLES_50, size = SIZE_50) +public final class G1ReferentFieldReadBarrier extends ObjectWriteBarrier { + public static final NodeClass TYPE = NodeClass.create(G1ReferentFieldReadBarrier.class); + + protected final boolean doLoad; + + public G1ReferentFieldReadBarrier(AddressNode address, ValueNode expectedObject, boolean doLoad) { + super(TYPE, address, expectedObject, true); + this.doLoad = doLoad; + } + + public ValueNode getExpectedObject() { + return getValue(); + } + + public boolean doLoad() { + return doLoad; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GetObjectAddressNode.java 2016-12-07 13:50:22.641782474 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaKind; + +/** + * Intrinsification for getting the address of an object. The code path(s) between a call to + * {@link #get(Object)} and all uses of the returned value must not contain safepoints. This can + * only be guaranteed if used in a snippet that is instantiated after frame state assignment. + * {@link ComputeObjectAddressNode} should generally be used in preference to this node. + */ +@NodeInfo(cycles = CYCLES_2, size = SIZE_1) +public final class GetObjectAddressNode extends FixedWithNextNode implements LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(GetObjectAddressNode.class); + + @Input ValueNode object; + + public GetObjectAddressNode(ValueNode obj) { + super(TYPE, StampFactory.forKind(JavaKind.Long)); + this.object = obj; + } + + @NodeIntrinsic + public static native long get(Object array); + + @Override + public void generate(NodeLIRBuilderTool gen) { + AllocatableValue obj = gen.getLIRGeneratorTool().newVariable(LIRKind.unknownReference(gen.getLIRGeneratorTool().target().arch.getWordKind())); + gen.getLIRGeneratorTool().emitMove(obj, gen.operand(object)); + gen.setResult(this, obj); + } + + @Override + public boolean verify() { + assert graph().getGuardsStage().areFrameStatesAtDeopts() || graph().method().getAnnotation(Snippet.class) != null : "GetObjectAddressNode can't be used directly until frame states are fixed"; + return super.verify(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java 2016-12-07 13:50:22.906794123 -0800 @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2015, 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.nodes; + +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; + +/** + * Represents {@link GraalHotSpotVMConfig} values that may change after compilation. + */ +@NodeInfo(cycles = CYCLES_1, size = SIZE_1) +public class GraalHotSpotVMConfigNode extends FloatingNode implements LIRLowerable, Canonicalizable { + public static final NodeClass TYPE = NodeClass.create(GraalHotSpotVMConfigNode.class); + + private final GraalHotSpotVMConfig config; + protected final int markId; + + public GraalHotSpotVMConfigNode(@InjectedNodeParameter GraalHotSpotVMConfig config, int markId, JavaKind kind) { + super(TYPE, StampFactory.forKind(kind)); + this.config = config; + this.markId = markId; + } + + /** + * Constructor selected by {@link #loadConfigValue(int, JavaKind)}. + * + * @param config + * @param markId + */ + public GraalHotSpotVMConfigNode(@InjectedNodeParameter GraalHotSpotVMConfig config, int markId) { + super(TYPE, StampFactory.forKind(JavaKind.Boolean)); + this.config = config; + this.markId = 0; + } + + @Override + public void generate(NodeLIRBuilderTool generator) { + Value res = ((HotSpotLIRGenerator) generator.getLIRGeneratorTool()).emitLoadConfigValue(markId); + generator.setResult(this, res); + } + + @NodeIntrinsic + private static native boolean isConfigValueConstant(@ConstantNodeParameter int markId); + + @NodeIntrinsic + private static native long loadConfigValue(@ConstantNodeParameter int markId, @ConstantNodeParameter JavaKind kind); + + public static long cardTableAddress() { + return loadConfigValue(cardTableAddressMark(INJECTED_VMCONFIG), JavaKind.Long); + } + + public static boolean isCardTableAddressConstant() { + return isConfigValueConstant(cardTableAddressMark(INJECTED_VMCONFIG)); + } + + public static long heapTopAddress() { + return loadConfigValue(heapTopAddressMark(INJECTED_VMCONFIG), JavaKind.Long); + } + + public static long heapEndAddress() { + return loadConfigValue(heapEndAddressMark(INJECTED_VMCONFIG), JavaKind.Long); + } + + public static long crcTableAddress() { + return loadConfigValue(crcTableAddressMark(INJECTED_VMCONFIG), JavaKind.Long); + } + + public static int logOfHeapRegionGrainBytes() { + return (int) loadConfigValue(logOfHeapRegionGrainBytesMark(INJECTED_VMCONFIG), JavaKind.Byte); + } + + public static boolean inlineContiguousAllocationSupported() { + return loadConfigValue(inlineContiguousAllocationSupportedMark(INJECTED_VMCONFIG), JavaKind.Byte) > 0; + } + + @Fold + public static int cardTableAddressMark(@InjectedParameter GraalHotSpotVMConfig config) { + return config.MARKID_CARD_TABLE_ADDRESS; + } + + @Fold + public static int heapTopAddressMark(@InjectedParameter GraalHotSpotVMConfig config) { + return config.MARKID_HEAP_TOP_ADDRESS; + } + + @Fold + public static int heapEndAddressMark(@InjectedParameter GraalHotSpotVMConfig config) { + return config.MARKID_HEAP_END_ADDRESS; + } + + @Fold + public static int crcTableAddressMark(@InjectedParameter GraalHotSpotVMConfig config) { + return config.MARKID_CRC_TABLE_ADDRESS; + } + + @Fold + public static int logOfHeapRegionGrainBytesMark(@InjectedParameter GraalHotSpotVMConfig config) { + return config.MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES; + } + + @Fold + public static int inlineContiguousAllocationSupportedMark(@InjectedParameter GraalHotSpotVMConfig config) { + return config.MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (markId == 0) { + return ConstantNode.forBoolean(!GeneratePIC.getValue()); + } + if (!GeneratePIC.getValue()) { + if (markId == cardTableAddressMark(config)) { + return ConstantNode.forLong(config.cardtableStartAddress); + } else if (markId == heapTopAddressMark(config)) { + return ConstantNode.forLong(config.heapTopAddress); + } else if (markId == heapEndAddressMark(config)) { + return ConstantNode.forLong(config.heapEndAddress); + } else if (markId == crcTableAddressMark(config)) { + return ConstantNode.forLong(config.crcTableAddress); + } else if (markId == logOfHeapRegionGrainBytesMark(config)) { + return ConstantNode.forInt(config.logOfHRGrainBytes); + } else if (markId == inlineContiguousAllocationSupportedMark(config)) { + return ConstantNode.forBoolean(config.inlineContiguousAllocationSupported); + } else { + assert false; + } + } + return this; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotDirectCallTargetNode.java 2016-12-07 13:50:23.170805727 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2012, 2015, 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.nodes; + +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.DirectCallTargetNode; +import org.graalvm.compiler.nodes.ValueNode; + +import jdk.vm.ci.code.CallingConvention.Type; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@NodeInfo +public final class HotSpotDirectCallTargetNode extends DirectCallTargetNode { + public static final NodeClass TYPE = NodeClass.create(HotSpotDirectCallTargetNode.class); + + public HotSpotDirectCallTargetNode(ValueNode[] arguments, StampPair returnStamp, JavaType[] signature, ResolvedJavaMethod target, Type callType, InvokeKind invokeKind) { + super(TYPE, arguments, returnStamp, signature, target, callType, invokeKind); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotIndirectCallTargetNode.java 2016-12-07 13:50:23.435817375 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2012, 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.nodes; + +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.IndirectCallTargetNode; +import org.graalvm.compiler.nodes.ValueNode; + +import jdk.vm.ci.code.CallingConvention.Type; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@NodeInfo +public final class HotSpotIndirectCallTargetNode extends IndirectCallTargetNode { + public static final NodeClass TYPE = NodeClass.create(HotSpotIndirectCallTargetNode.class); + + @Input ValueNode metaspaceMethod; + + public HotSpotIndirectCallTargetNode(ValueNode metaspaceMethod, ValueNode computedAddress, ValueNode[] arguments, StampPair returnStamp, JavaType[] signature, + ResolvedJavaMethod target, + Type callType, InvokeKind invokeKind) { + super(TYPE, computedAddress, arguments, returnStamp, signature, target, callType, invokeKind); + this.metaspaceMethod = metaspaceMethod; + } + + public ValueNode metaspaceMethod() { + return metaspaceMethod; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotNodeCostProvider.java 2016-12-07 13:50:23.700829023 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode; +import org.graalvm.compiler.nodeinfo.NodeCycles; +import org.graalvm.compiler.nodeinfo.NodeSize; +import org.graalvm.compiler.nodes.spi.DefaultNodeCostProvider; +import org.graalvm.compiler.nodes.type.StampTool; + +import jdk.vm.ci.meta.ResolvedJavaType; + +public abstract class HotSpotNodeCostProvider extends DefaultNodeCostProvider { + + @Override + public NodeSize size(Node n) { + if (n instanceof ObjectCloneNode) { + ResolvedJavaType type = StampTool.typeOrNull(((ObjectCloneNode) n).getObject()); + if (type != null) { + if (type.isArray()) { + return SIZE_30; + } else { + return SIZE_20; + } + } + } + return super.size(n); + } + + @Override + public NodeCycles cycles(Node n) { + if (n instanceof ObjectCloneNode) { + ResolvedJavaType type = StampTool.typeOrNull(((ObjectCloneNode) n).getObject()); + if (type != null) { + if (type.isArray()) { + return CYCLES_30; + } else { + return CYCLES_20; + } + } + } + return super.cycles(n); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java 2016-12-07 13:50:23.966840716 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ControlSinkNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; + +/** + * Sets up the {@linkplain HotSpotBackend#EXCEPTION_HANDLER_IN_CALLER arguments} expected by an + * exception handler in the caller's frame, removes the current frame and jumps to said handler. + */ +@NodeInfo(cycles = CYCLES_15, size = SIZE_8) +public final class JumpToExceptionHandlerInCallerNode extends ControlSinkNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(JumpToExceptionHandlerInCallerNode.class); + @Input ValueNode handlerInCallerPc; + @Input ValueNode exception; + @Input ValueNode exceptionPc; + + public JumpToExceptionHandlerInCallerNode(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + super(TYPE, StampFactory.forVoid()); + this.handlerInCallerPc = handlerInCallerPc; + this.exception = exception; + this.exceptionPc = exceptionPc; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + ((HotSpotNodeLIRBuilder) gen).emitJumpToExceptionHandlerInCaller(handlerInCallerPc, exception, exceptionPc); + } + + @NodeIntrinsic + public static native void jumpToExceptionHandlerInCaller(Word handlerInCallerPc, Object exception, Word exceptionPc); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerNode.java 2016-12-07 13:50:24.230852320 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder; +import org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; + +/** + * Jumps to the exception handler specified by {@link #address}. This node is specific for the + * {@link ExceptionHandlerStub} and should not be used elswhere. + */ +@NodeInfo(cycles = CYCLES_2, size = SIZE_1) +public final class JumpToExceptionHandlerNode extends FixedWithNextNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(JumpToExceptionHandlerNode.class); + @Input ValueNode address; + + public JumpToExceptionHandlerNode(ValueNode address) { + super(TYPE, StampFactory.forVoid()); + this.address = address; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + ((HotSpotNodeLIRBuilder) gen).emitJumpToExceptionHandler(address); + } + + @NodeIntrinsic + public static native void jumpToExceptionHandler(Word address); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveCurrentStackFrameNode.java 2016-12-07 13:50:24.495863968 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +/** + * Emits code to leave (pop) the current low-level stack frame. This operation also removes the + * return address if its location is on the stack. + */ +@NodeInfo(cycles = CYCLES_10, size = SIZE_6) +public final class LeaveCurrentStackFrameNode extends FixedWithNextNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(LeaveCurrentStackFrameNode.class); + @Input SaveAllRegistersNode registerSaver; + + public LeaveCurrentStackFrameNode(ValueNode registerSaver) { + super(TYPE, StampFactory.forVoid()); + this.registerSaver = (SaveAllRegistersNode) registerSaver; + } + + private SaveRegistersOp getSaveRegistersOp() { + return registerSaver.getSaveRegistersOp(); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveCurrentStackFrame(getSaveRegistersOp()); + } + + @NodeIntrinsic + public static native void leaveCurrentStackFrame(long registerSaver); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveDeoptimizedStackFrameNode.java 2016-12-07 13:50:24.760875616 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.stubs.DeoptimizationStub; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.Value; + +/** + * Emits code to leave (pop) the current low-level stack frame which is being deoptimized. This node + * is only used in {@link DeoptimizationStub}. + */ +@NodeInfo(cycles = CYCLES_3, size = SIZE_2) +public final class LeaveDeoptimizedStackFrameNode extends FixedWithNextNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(LeaveDeoptimizedStackFrameNode.class); + @Input ValueNode frameSize; + @Input ValueNode initialInfo; + + public LeaveDeoptimizedStackFrameNode(ValueNode frameSize, ValueNode initialInfo) { + super(TYPE, StampFactory.forVoid()); + this.frameSize = frameSize; + this.initialInfo = initialInfo; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + Value frameSizeValue = gen.operand(frameSize); + Value initialInfoValue = gen.operand(initialInfo); + ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveDeoptimizedStackFrame(frameSizeValue, initialInfoValue); + } + + @NodeIntrinsic + public static native void leaveDeoptimizedStackFrame(int frameSize, Word initialInfo); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java 2016-12-07 13:50:25.029887440 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +/** + * Emits code to leave a low-level stack frame specifically to call out to the C++ method + * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}. + */ +@NodeInfo(cycles = CYCLES_10, size = SIZE_6) +public final class LeaveUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(LeaveUnpackFramesStackFrameNode.class); + @Input SaveAllRegistersNode registerSaver; + + public LeaveUnpackFramesStackFrameNode(ValueNode registerSaver) { + super(TYPE, StampFactory.forVoid()); + this.registerSaver = (SaveAllRegistersNode) registerSaver; + } + + private SaveRegistersOp getSaveRegistersOp() { + return registerSaver.getSaveRegistersOp(); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveUnpackFramesStackFrame(getSaveRegistersOp()); + } + + @NodeIntrinsic + public static native void leaveUnpackFramesStackFrame(long registerSaver); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LoadIndexedPointerNode.java 2016-12-07 13:50:25.293899045 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014, 2015, 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.nodes; + +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.java.LoadIndexedNode; + +import jdk.vm.ci.meta.JavaKind; + +@NodeInfo +public final class LoadIndexedPointerNode extends LoadIndexedNode { + + public static final NodeClass TYPE = NodeClass.create(LoadIndexedPointerNode.class); + + public LoadIndexedPointerNode(Stamp stamp, ValueNode array, ValueNode index) { + super(TYPE, stamp, array, index, JavaKind.Illegal); + } + + @Override + public boolean inferStamp() { + return false; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/MonitorCounterNode.java 2016-12-07 13:50:25.558910693 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import java.util.BitSet; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.nodeinfo.NodeCycles; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.meta.Value; + +/** + * Node that is used to maintain a stack based counter of how many locks are currently held. + */ +@NodeInfo(cycles = NodeCycles.CYCLES_2, size = SIZE_1) +public final class MonitorCounterNode extends FloatingNode implements LIRLowerable, Node.ValueNumberable { + public static final NodeClass TYPE = NodeClass.create(MonitorCounterNode.class); + + public MonitorCounterNode(@InjectedNodeParameter WordTypes wordTypes) { + super(TYPE, StampFactory.forKind(wordTypes.getWordKind())); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance"; + VirtualStackSlot counter = gen.getLIRGeneratorTool().getResult().getFrameMapBuilder().allocateStackSlots(1, new BitSet(0), null); + Value result = gen.getLIRGeneratorTool().emitAddress(counter); + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native Word counter(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ObjectWriteBarrier.java 2016-12-07 13:50:25.822922297 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; + +@NodeInfo +public abstract class ObjectWriteBarrier extends WriteBarrier { + + public static final NodeClass TYPE = NodeClass.create(ObjectWriteBarrier.class); + @Input(InputType.Association) protected AddressNode address; + @OptionalInput protected ValueNode value; + protected final boolean precise; + + protected ObjectWriteBarrier(NodeClass c, AddressNode address, ValueNode value, boolean precise) { + super(c); + this.address = address; + this.value = value; + this.precise = precise; + } + + public ValueNode getValue() { + return value; + } + + public AddressNode getAddress() { + return address; + } + + public boolean usePrecise() { + return precise; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/PatchReturnAddressNode.java 2016-12-07 13:50:26.087933945 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; + +/** + * Modifies the return address of the current frame. + */ +@NodeInfo(cycles = CYCLES_2, size = SIZE_1) +public final class PatchReturnAddressNode extends FixedWithNextNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(PatchReturnAddressNode.class); + @Input ValueNode address; + + public PatchReturnAddressNode(ValueNode address) { + super(TYPE, StampFactory.forVoid()); + this.address = address; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + ((HotSpotNodeLIRBuilder) gen).emitPatchReturnAddress(address); + } + + @NodeIntrinsic + public static native void patchReturnAddress(Word address); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/PushInterpreterFrameNode.java 2016-12-07 13:50:26.352945594 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.Value; + +/** + * A call to the runtime code implementing the uncommon trap logic. + */ +@NodeInfo(cycles = CYCLES_8, size = SIZE_6) +public final class PushInterpreterFrameNode extends FixedWithNextNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(PushInterpreterFrameNode.class); + @Input ValueNode framePc; + @Input ValueNode frameSize; + @Input ValueNode senderSp; + @Input ValueNode initialInfo; + + public PushInterpreterFrameNode(ValueNode frameSize, ValueNode framePc, ValueNode senderSp, ValueNode initialInfo) { + super(TYPE, StampFactory.forVoid()); + this.frameSize = frameSize; + this.framePc = framePc; + this.senderSp = senderSp; + this.initialInfo = initialInfo; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + Value frameSizeValue = gen.operand(frameSize); + Value framePcValue = gen.operand(framePc); + Value senderSpValue = gen.operand(senderSp); + Value initialInfoValue = gen.operand(initialInfo); + ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitPushInterpreterFrame(frameSizeValue, framePcValue, senderSpValue, initialInfoValue); + } + + @NodeIntrinsic + public static native void pushInterpreterFrame(Word frameSize, Word framePc, Word senderSp, Word initialInfo); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SaveAllRegistersNode.java 2016-12-07 13:50:26.619957330 -0800 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2013, 2016, 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.nodes; + +import jdk.vm.ci.meta.JavaKind; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +/** + * Saves all allocatable registers. + */ +@NodeInfo(allowedUsageTypes = {InputType.Memory}) +public final class SaveAllRegistersNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single { + + public static final NodeClass TYPE = NodeClass.create(SaveAllRegistersNode.class); + protected SaveRegistersOp saveRegistersOp; + + public SaveAllRegistersNode() { + super(TYPE, StampFactory.forKind(JavaKind.Long)); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + saveRegistersOp = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitSaveAllRegisters(); + } + + /** + * @return the map from registers to the stack locations in they are saved + */ + public SaveRegistersOp getSaveRegistersOp() { + assert saveRegistersOp != null : "saved registers op has not yet been created"; + return saveRegistersOp; + } + + /** + * @return a token that couples this node to an {@link UncommonTrapCallNode} so that the latter + * has access to the {@linkplain SaveRegistersOp#getMap register save map} + */ + @NodeIntrinsic + public static native long saveAllRegisters(); + + @Override + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialArrayRangeWriteBarrier.java 2016-12-07 13:50:26.886969066 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; + +@NodeInfo(cycles = CYCLES_15, size = SIZE_20) +public final class SerialArrayRangeWriteBarrier extends ArrayRangeWriteBarrier { + + public static final NodeClass TYPE = NodeClass.create(SerialArrayRangeWriteBarrier.class); + + public SerialArrayRangeWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) { + super(TYPE, object, startIndex, length); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialWriteBarrier.java 2016-12-07 13:50:27.152980758 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.memory.address.AddressNode; + +@NodeInfo(cycles = CYCLES_8, size = SIZE_3) +public class SerialWriteBarrier extends ObjectWriteBarrier { + + public static final NodeClass TYPE = NodeClass.create(SerialWriteBarrier.class); + + public SerialWriteBarrier(AddressNode address, boolean precise) { + this(TYPE, address, precise); + } + + protected SerialWriteBarrier(NodeClass c, AddressNode address, boolean precise) { + super(c, address, null, precise); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SnippetAnchorNode.java 2016-12-07 13:50:27.416992362 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.InputType.Anchor; +import static org.graalvm.compiler.nodeinfo.InputType.Guard; +import static org.graalvm.compiler.nodeinfo.InputType.Value; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Simplifiable; +import org.graalvm.compiler.graph.spi.SimplifierTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; + +@NodeInfo(allowedUsageTypes = {Value, Anchor, Guard}, cycles = CYCLES_0, size = SIZE_0) +public final class SnippetAnchorNode extends FixedWithNextNode implements Simplifiable, GuardingNode { + public static final NodeClass TYPE = NodeClass.create(SnippetAnchorNode.class); + + public SnippetAnchorNode() { + super(TYPE, StampFactory.object()); + } + + @Override + public void simplify(SimplifierTool tool) { + AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(this); + replaceAtUsages(Anchor, prevBegin); + replaceAtUsages(Guard, prevBegin); + if (tool.allUsagesAvailable() && hasNoUsages()) { + graph().removeFixed(this); + } + } + + @NodeIntrinsic + public static native GuardingNode anchor(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SnippetLocationProxyNode.java 2016-12-07 13:50:27.683004054 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; + +@NodeInfo(allowedUsageTypes = {InputType.Association, InputType.Value}, cycles = CYCLES_0, size = SIZE_0) +public final class SnippetLocationProxyNode extends FloatingNode implements Canonicalizable, Node.ValueNumberable { + + public static final NodeClass TYPE = NodeClass.create(SnippetLocationProxyNode.class); + @Input(InputType.Unchecked) ValueNode location; + + public SnippetLocationProxyNode(ValueNode location) { + super(TYPE, StampFactory.object()); + this.location = location; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + return location.isAllowedUsageType(InputType.Association) ? location : this; + } + + @NodeIntrinsic + public static native GuardingNode location(Object location); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java 2016-12-07 13:50:27.947015659 -0800 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011, 2016, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.InputType.Memory; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; + +import java.util.Arrays; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodeinfo.Verbosity; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; + +/** + * Node for a {@linkplain ForeignCallDescriptor foreign} call from within a stub. + */ +@NodeInfo(nameTemplate = "StubForeignCall#{p#descriptor/s}", allowedUsageTypes = Memory, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) +public final class StubForeignCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi { + + public static final NodeClass TYPE = NodeClass.create(StubForeignCallNode.class); + @Input NodeInputList arguments; + protected final ForeignCallsProvider foreignCalls; + + protected final ForeignCallDescriptor descriptor; + + public StubForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) { + super(TYPE, StampFactory.forKind(JavaKind.fromJavaClass(descriptor.getResultType()))); + this.arguments = new NodeInputList<>(this, arguments); + this.descriptor = descriptor; + this.foreignCalls = foreignCalls; + } + + public ForeignCallDescriptor getDescriptor() { + return descriptor; + } + + @Override + public LocationIdentity[] getLocationIdentities() { + LocationIdentity[] killedLocations = foreignCalls.getKilledLocations(descriptor); + killedLocations = Arrays.copyOf(killedLocations, killedLocations.length + 1); + killedLocations[killedLocations.length - 1] = HotSpotReplacementsUtil.PENDING_EXCEPTION_LOCATION; + return killedLocations; + } + + protected Value[] operands(NodeLIRBuilderTool gen) { + Value[] operands = new Value[arguments.size()]; + for (int i = 0; i < operands.length; i++) { + operands[i] = gen.operand(arguments.get(i)); + } + return operands; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert graph().start() instanceof StubStartNode; + ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(descriptor); + Value[] operands = operands(gen); + Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, null, operands); + if (result != null) { + gen.setResult(this, result); + } + } + + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name) { + return super.toString(verbosity) + "#" + descriptor; + } + return super.toString(verbosity); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubStartNode.java 2016-12-07 13:50:28.213027351 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.StartNode; + +/** + * Start node for a {@link Stub}'s graph. + */ +@NodeInfo(cycles = CYCLES_0, size = SIZE_0) +public final class StubStartNode extends StartNode { + + public static final NodeClass TYPE = NodeClass.create(StubStartNode.class); + protected final Stub stub; + + public StubStartNode(Stub stub) { + super(TYPE); + this.stub = stub; + } + + public Stub getStub() { + return stub; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/UncommonTrapCallNode.java 2016-12-07 13:50:28.478038999 -0800 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2013, 2016, 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.nodes; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.UNCOMMON_TRAP; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; + +/** + * A call to the runtime code implementing the uncommon trap logic. + */ +@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) +public final class UncommonTrapCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single { + + public static final NodeClass TYPE = NodeClass.create(UncommonTrapCallNode.class); + @Input ValueNode trapRequest; + @Input ValueNode mode; + @Input SaveAllRegistersNode registerSaver; + protected final ForeignCallsProvider foreignCalls; + + public UncommonTrapCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver, ValueNode trapRequest, ValueNode mode) { + super(TYPE, StampFactory.forKind(JavaKind.fromJavaClass(UNCOMMON_TRAP.getResultType()))); + this.trapRequest = trapRequest; + this.mode = mode; + this.registerSaver = (SaveAllRegistersNode) registerSaver; + this.foreignCalls = foreignCalls; + } + + @Override + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); + } + + public SaveRegistersOp getSaveRegistersOp() { + return registerSaver.getSaveRegistersOp(); + } + + /** + * Returns the node representing the exec_mode/unpack_kind used during this fetch_unroll_info + * call. + */ + public ValueNode getMode() { + return mode; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + Value trapRequestValue = gen.operand(trapRequest); + Value modeValue = gen.operand(getMode()); + Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitUncommonTrapCall(trapRequestValue, modeValue, getSaveRegistersOp()); + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native Word uncommonTrap(long registerSaver, int trapRequest, int mode); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/VMErrorNode.java 2016-12-07 13:50:28.744050691 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012, 2016, 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.nodes; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.VM_ERROR; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; + +import org.graalvm.compiler.bytecode.Bytecode; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.replacements.Log; +import org.graalvm.compiler.replacements.nodes.CStringConstant; + +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * Causes the VM to exit with a description of the current Java location and an optional + * {@linkplain Log#printf(String, long) formatted} error message specified. + */ +@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) +public final class VMErrorNode extends DeoptimizingStubCall implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(VMErrorNode.class); + protected final String format; + @Input ValueNode value; + + public VMErrorNode(String format, ValueNode value) { + super(TYPE, StampFactory.forVoid()); + this.format = format; + this.value = value; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + String whereString; + if (stateBefore() != null) { + String nl = CodeUtil.NEW_LINE; + StringBuilder sb = new StringBuilder("in compiled code associated with frame state:"); + FrameState fs = stateBefore(); + while (fs != null) { + Bytecode.appendLocation(sb.append(nl).append("\t"), fs.getCode(), fs.bci); + fs = fs.outerFrameState(); + } + whereString = sb.toString(); + } else { + ResolvedJavaMethod method = graph().method(); + whereString = "in compiled code for " + (method == null ? graph().toString() : method.format("%H.%n(%p)")); + } + + LIRKind wordKind = gen.getLIRGeneratorTool().getLIRKind(StampFactory.pointer()); + Value whereArg = gen.getLIRGeneratorTool().emitConstant(wordKind, new CStringConstant(whereString)); + Value formatArg = gen.getLIRGeneratorTool().emitConstant(wordKind, new CStringConstant(format)); + + ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(VM_ERROR); + gen.getLIRGeneratorTool().emitForeignCall(linkage, null, whereArg, formatArg, gen.operand(value)); + } + + @NodeIntrinsic + public static native void vmError(@ConstantNodeParameter String format, long value); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/WriteBarrier.java 2016-12-07 13:50:29.008062296 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013, 2015, 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.nodes; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +@NodeInfo +public abstract class WriteBarrier extends FixedWithNextNode implements Lowerable { + + public static final NodeClass TYPE = NodeClass.create(WriteBarrier.class); + + protected WriteBarrier(NodeClass c) { + super(c, StampFactory.forVoid()); + } + + @Override + public void lower(LoweringTool tool) { + assert graph().getGuardsStage().areFrameStatesAtDeopts(); + tool.getLowerer().lower(this, tool); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java 2016-12-07 13:50:29.272073900 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 2016, 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.nodes.aot; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.replacements.EncodedSymbolConstant; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.Constant; + +@NodeInfo +public final class EncodedSymbolNode extends FloatingNode implements Canonicalizable { + + public static final NodeClass TYPE = NodeClass.create(EncodedSymbolNode.class); + + @OptionalInput protected ValueNode value; + + public EncodedSymbolNode(ValueNode value) { + super(TYPE, null); + assert value != null; + this.value = value; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (value != null) { + Constant constant = GraphUtil.foldIfConstantAndRemove(this, value); + if (constant != null) { + return new ConstantNode(new EncodedSymbolConstant(constant), StampFactory.pointer()); + } + } + return this; + } + + @NodeIntrinsic(setStampFromReturnType = true) + public static native Word encode(Object constant); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java 2016-12-07 13:50:29.537085548 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016, 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.nodes.aot; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +@NodeInfo(cycles = CYCLES_3, size = SIZE_20) +public class InitializeKlassNode extends DeoptimizingFixedWithNextNode implements Lowerable { + public static final NodeClass TYPE = NodeClass.create(InitializeKlassNode.class); + + @Input ValueNode value; + + public InitializeKlassNode(ValueNode value) { + super(TYPE, value.stamp()); + this.value = value; + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + public ValueNode value() { + return value; + } + + @Override + public boolean canDeoptimize() { + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java 2016-12-07 13:50:29.803097240 -0800 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016, 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.nodes.aot; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.DeoptimizingNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.util.GraphUtil; + +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; + +/** + * A call to the VM via a regular stub. + */ +@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_20) +public class InitializeKlassStubCall extends AbstractMemoryCheckpoint implements LIRLowerable, Canonicalizable, DeoptimizingNode.DeoptBefore, MemoryCheckpoint.Single { + public static final NodeClass TYPE = NodeClass.create(InitializeKlassStubCall.class); + + @OptionalInput protected ValueNode value; + @Input protected ValueNode string; + @OptionalInput(InputType.State) protected FrameState stateBefore; + protected Constant constant; + + protected InitializeKlassStubCall(ValueNode value, ValueNode string) { + super(TYPE, value.stamp()); + this.value = value; + this.string = string; + } + + @NodeIntrinsic + public static native KlassPointer initializeKlass(KlassPointer value, Object string); + + @Override + public Node canonical(CanonicalizerTool tool) { + if (value != null) { + constant = GraphUtil.foldIfConstantAndRemove(this, value); + } + return this; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert constant != null : "Expected the value to fold: " + value; + Value stringValue = gen.operand(string); + LIRFrameState fs = gen.state(this); + assert fs != null : "Frame state should be set"; + assert constant instanceof HotSpotMetaspaceConstant; + Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitKlassInitializationAndRetrieval(constant, stringValue, fs); + gen.setResult(this, result); + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); + } + + @Override + public FrameState stateBefore() { + return stateBefore; + } + + @Override + public void setStateBefore(FrameState f) { + updateUsages(stateBefore, f); + stateBefore = f; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyFixedNode.java 2016-12-07 13:50:30.069108932 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016, 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.nodes.aot; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3; + +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.hotspot.word.MethodPointer; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.util.GraphUtil; + +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; + +@NodeInfo(cycles = CYCLES_3, size = SIZE_3) +public class LoadConstantIndirectlyFixedNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(LoadConstantIndirectlyFixedNode.class); + + @OptionalInput protected ValueNode value; + protected Constant constant; + protected HotSpotConstantLoadAction action; + + public LoadConstantIndirectlyFixedNode(ValueNode value) { + super(TYPE, value.stamp().unrestricted()); + this.value = value; + this.constant = null; + this.action = HotSpotConstantLoadAction.RESOLVE; + } + + public LoadConstantIndirectlyFixedNode(ValueNode value, HotSpotConstantLoadAction action) { + super(TYPE, value.stamp().unrestricted()); + this.value = value; + this.constant = null; + this.action = action; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (value != null) { + constant = GraphUtil.foldIfConstantAndRemove(this, value); + } + return this; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert constant != null : "Expected the value to fold: " + value; + Value result; + if (constant instanceof HotSpotObjectConstant) { + result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadObjectAddress(constant); + } else if (constant instanceof HotSpotMetaspaceConstant) { + result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, action); + } else { + throw new PermanentBailoutException("Unsupported constant type: " + constant); + } + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native KlassPointer loadKlass(KlassPointer klassPointer, @ConstantNodeParameter HotSpotConstantLoadAction action); + + @NodeIntrinsic + public static native KlassPointer loadKlass(KlassPointer klassPointer); + + @NodeIntrinsic + public static native MethodPointer loadMethod(MethodPointer klassPointer); + + @NodeIntrinsic + public static native Object loadObject(Object object); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java 2016-12-07 13:50:30.333120536 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016, 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.nodes.aot; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3; + +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.util.GraphUtil; + +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; + +@NodeInfo(cycles = CYCLES_3, size = SIZE_3) +public class LoadConstantIndirectlyNode extends FloatingNode implements Canonicalizable, LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(LoadConstantIndirectlyNode.class); + + @OptionalInput protected ValueNode value; + protected Constant constant; + protected HotSpotConstantLoadAction action; + + public LoadConstantIndirectlyNode(ValueNode value) { + super(TYPE, value.stamp().unrestricted()); + this.value = value; + this.constant = null; + this.action = HotSpotConstantLoadAction.RESOLVE; + } + + public LoadConstantIndirectlyNode(ValueNode value, HotSpotConstantLoadAction action) { + super(TYPE, value.stamp().unrestricted()); + this.value = value; + this.constant = null; + this.action = action; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (value != null) { + constant = GraphUtil.foldIfConstantAndRemove(this, value); + } + return this; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert constant != null : "Expected the value to fold: " + value; + Value result; + if (constant instanceof HotSpotObjectConstant) { + result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadObjectAddress(constant); + } else if (constant instanceof HotSpotMetaspaceConstant) { + result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, action); + } else { + throw new PermanentBailoutException("Unsupported constant type: " + constant); + } + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native KlassPointer loadKlass(KlassPointer klassPointer, @ConstantNodeParameter HotSpotConstantLoadAction action); + + @NodeIntrinsic + public static native KlassPointer loadKlass(KlassPointer klassPointer); + + @NodeIntrinsic + public static native Object loadObject(Object object); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersIndirectlyNode.java 2016-12-07 13:50:30.598132184 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016, 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.nodes.aot; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3; + +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; +import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp; +import org.graalvm.compiler.hotspot.word.MethodCountersPointer; +import org.graalvm.compiler.hotspot.word.MethodPointer; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.util.GraphUtil; + +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; + +@NodeInfo(cycles = CYCLES_3, size = SIZE_3) +public class LoadMethodCountersIndirectlyNode extends FloatingNode implements Canonicalizable, LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(LoadMethodCountersIndirectlyNode.class); + + @OptionalInput protected ValueNode value; + protected Constant constant; + + public LoadMethodCountersIndirectlyNode(ValueNode value) { + super(TYPE, MethodCountersPointerStamp.methodCounters()); + this.value = value; + this.constant = null; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (value != null) { + constant = GraphUtil.foldIfConstantAndRemove(this, value); + } + return this; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert constant != null : "Expected the value to fold: " + value; + Value result; + if (constant instanceof HotSpotMetaspaceConstant) { + result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, HotSpotConstantLoadAction.LOAD_COUNTERS); + } else { + throw new PermanentBailoutException("Unsupported constant type: " + constant); + } + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native MethodCountersPointer loadMethodCounters(MethodPointer methodPointer); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersNode.java 2016-12-07 13:50:30.864143877 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016, 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.nodes.aot; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +@NodeInfo(cycles = CYCLES_3, size = SIZE_3) +public class LoadMethodCountersNode extends FloatingNode implements LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(LoadMethodCountersNode.class); + + ResolvedJavaMethod method; + + public LoadMethodCountersNode(ResolvedJavaMethod method) { + super(TYPE, MethodCountersPointerStamp.methodCountersNonNull()); + this.method = method; + } + + public ResolvedJavaMethod getMethod() { + return method; + } + + public static NodeIterable getLoadMethodCountersNodes(StructuredGraph graph) { + return graph.getNodes().filter(LoadMethodCountersNode.class); + } + + @Override + public void generate(NodeLIRBuilderTool generator) { + // TODO: With AOT we don't need this, as this node will be replaced. + // Implement later when profiling is needed in the JIT mode. + throw GraalError.unimplemented(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantNode.java 2016-12-07 13:50:31.129155525 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016, 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.nodes.aot; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +@NodeInfo(cycles = CYCLES_3, size = SIZE_20) +public class ResolveConstantNode extends FloatingNode implements Lowerable { + public static final NodeClass TYPE = NodeClass.create(ResolveConstantNode.class); + + @Input ValueNode value; + protected HotSpotConstantLoadAction action; + + public ResolveConstantNode(ValueNode value, HotSpotConstantLoadAction action) { + super(TYPE, value.stamp()); + this.value = value; + this.action = action; + } + + public ResolveConstantNode(ValueNode value) { + super(TYPE, value.stamp()); + this.value = value; + this.action = HotSpotConstantLoadAction.RESOLVE; + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + public ValueNode value() { + return value; + } + + public HotSpotConstantLoadAction action() { + return action; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java 2016-12-07 13:50:31.395167217 -0800 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, 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.nodes.aot; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20; + +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; +import org.graalvm.compiler.hotspot.nodes.DeoptimizingStubCall; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.util.GraphUtil; + +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; + +/** + * A call to the VM via a regular stub. + */ +@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_20) +public class ResolveConstantStubCall extends DeoptimizingStubCall implements Canonicalizable, LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(ResolveConstantStubCall.class); + + @OptionalInput protected ValueNode value; + @Input protected ValueNode string; + protected Constant constant; + protected HotSpotConstantLoadAction action; + + public ResolveConstantStubCall(ValueNode value, ValueNode string) { + super(TYPE, value.stamp()); + this.value = value; + this.string = string; + this.action = HotSpotConstantLoadAction.RESOLVE; + } + + public ResolveConstantStubCall(ValueNode value, ValueNode string, HotSpotConstantLoadAction action) { + super(TYPE, value.stamp()); + this.value = value; + this.string = string; + this.action = action; + } + + @NodeIntrinsic + public static native Object resolveObject(Object value, Object symbol); + + @NodeIntrinsic + public static native KlassPointer resolveKlass(KlassPointer value, Object symbol); + + @NodeIntrinsic + public static native KlassPointer resolveKlass(KlassPointer value, Object symbol, @ConstantNodeParameter HotSpotConstantLoadAction action); + + @Override + public Node canonical(CanonicalizerTool tool) { + if (value != null) { + constant = GraphUtil.foldIfConstantAndRemove(this, value); + } + return this; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert constant != null : "Expected the value to fold: " + value; + Value stringValue = gen.operand(string); + Value result; + LIRFrameState fs = gen.state(this); + assert fs != null : "The stateAfter is null"; + if (constant instanceof HotSpotObjectConstant) { + result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitObjectConstantRetrieval(constant, stringValue, fs); + } else if (constant instanceof HotSpotMetaspaceConstant) { + if (action == HotSpotConstantLoadAction.RESOLVE) { + result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitMetaspaceConstantRetrieval(constant, stringValue, fs); + } else { + assert action == HotSpotConstantLoadAction.INITIALIZE; + result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitKlassInitializationAndRetrieval(constant, stringValue, fs); + } + } else { + throw new PermanentBailoutException("Unsupported constant type: " + constant); + } + gen.setResult(this, result); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersNode.java 2016-12-07 13:50:31.661178909 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016, 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.nodes.aot; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +@NodeInfo(cycles = CYCLES_3, size = SIZE_20) +public class ResolveMethodAndLoadCountersNode extends FloatingNode implements Lowerable { + public static final NodeClass TYPE = NodeClass.create(ResolveMethodAndLoadCountersNode.class); + + ResolvedJavaMethod method; + @Input ValueNode hub; + + public ResolveMethodAndLoadCountersNode(ResolvedJavaMethod method, ValueNode hub) { + super(TYPE, MethodCountersPointerStamp.methodCountersNonNull()); + this.method = method; + this.hub = hub; + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + public ResolvedJavaMethod getMethod() { + return method; + } + + public ValueNode getHub() { + return hub; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersStubCall.java 2016-12-07 13:50:31.926190557 -0800 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016, 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.nodes.aot; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.hotspot.nodes.DeoptimizingStubCall; +import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.hotspot.word.MethodCountersPointer; +import org.graalvm.compiler.hotspot.word.MethodPointer; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.util.GraphUtil; + +/** + * A call to the VM via a regular stub. + */ +@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_20) +public class ResolveMethodAndLoadCountersStubCall extends DeoptimizingStubCall implements Canonicalizable, LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(ResolveMethodAndLoadCountersStubCall.class); + + @OptionalInput protected ValueNode method; + @Input protected ValueNode klassHint; + @Input protected ValueNode methodDescription; + protected Constant methodConstant; + + public ResolveMethodAndLoadCountersStubCall(ValueNode method, ValueNode klassHint, ValueNode methodDescription) { + super(TYPE, MethodCountersPointerStamp.methodCountersNonNull()); + this.klassHint = klassHint; + this.method = method; + this.methodDescription = methodDescription; + } + + @NodeIntrinsic + public static native MethodCountersPointer resolveMethodAndLoadCounters(MethodPointer method, KlassPointer klassHint, Object methodDescription); + + @Override + public Node canonical(CanonicalizerTool tool) { + if (method != null) { + methodConstant = GraphUtil.foldIfConstantAndRemove(this, method); + } + return this; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert methodConstant != null : "Expected method to fold: " + method; + + Value methodDescriptionValue = gen.operand(methodDescription); + Value klassHintValue = gen.operand(klassHint); + LIRFrameState fs = gen.state(this); + assert fs != null : "The stateAfter is null"; + + Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitResolveMethodAndLoadCounters(methodConstant, klassHintValue, methodDescriptionValue, fs); + + gen.setResult(this, result); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileBranchNode.java 2016-12-07 13:50:32.191202205 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016, 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.nodes.profiling; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.ConditionalNode; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@NodeInfo +public class ProfileBranchNode extends ProfileWithNotificationNode { + public static final NodeClass TYPE = NodeClass.create(ProfileBranchNode.class); + + @OptionalInput ValueNode branchCondition; + protected int bci; + protected int targetBci; + + public ProfileBranchNode(ResolvedJavaMethod method, int freqLog, int probabilityLog, ConditionalNode branchCondition, int bci, int targetBci) { + super(TYPE, method, freqLog, probabilityLog); + assert targetBci <= bci; + this.branchCondition = branchCondition; + this.bci = bci; + this.targetBci = targetBci; + } + + public ProfileBranchNode(ResolvedJavaMethod method, int freqLog, int probabilityLog, int bci, int targetBci) { + super(TYPE, method, freqLog, probabilityLog); + assert targetBci <= bci; + this.branchCondition = null; + this.bci = bci; + this.targetBci = targetBci; + } + + public int bci() { + return bci; + } + + public int targetBci() { + return targetBci; + } + + public ValueNode branchCondition() { + return branchCondition; + } + + public boolean hasCondition() { + return branchCondition != null; + } + + /** + * Gathers all the {@link ProfileBranchNode}s that are inputs to the + * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph. + */ + public static NodeIterable getProfileBranchNodes(StructuredGraph graph) { + return graph.getNodes().filter(ProfileBranchNode.class); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileInvokeNode.java 2016-12-07 13:50:32.457213898 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016, 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.nodes.profiling; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.StructuredGraph; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@NodeInfo +public class ProfileInvokeNode extends ProfileWithNotificationNode { + public static final NodeClass TYPE = NodeClass.create(ProfileInvokeNode.class); + + public ProfileInvokeNode(ResolvedJavaMethod method, int freqLog, int probabilityLog) { + super(TYPE, method, freqLog, probabilityLog); + } + + /** + * Gathers all the {@link ProfileInvokeNode}s that are inputs to the + * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph. + */ + public static NodeIterable getProfileInvokeNodes(StructuredGraph graph) { + return graph.getNodes().filter(ProfileInvokeNode.class); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileNode.java 2016-12-07 13:50:32.722225546 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016, 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.nodes.profiling; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +@NodeInfo +public class ProfileNode extends DeoptimizingFixedWithNextNode implements Lowerable { + public static class Options { + @Option(help = "Control probabilistic profiling on AMD64", type = OptionType.Expert)// + public static final OptionValue ProbabilisticProfiling = new OptionValue<>(true); + } + + public static final NodeClass TYPE = NodeClass.create(ProfileNode.class); + + protected ResolvedJavaMethod method; + + // Only used if ProbabilisticProfiling == true and may be ignored by lowerer. + @OptionalInput protected ValueNode random; + + // logarithm base 2 of the profile probability + protected int probabilityLog; + + protected ProfileNode(NodeClass c, ResolvedJavaMethod method, int probabilityLog) { + super(c, StampFactory.forVoid()); + this.method = method; + this.probabilityLog = probabilityLog; + } + + public ProfileNode(ResolvedJavaMethod method, int probabilityLog) { + super(TYPE, StampFactory.forVoid()); + this.method = method; + this.probabilityLog = probabilityLog; + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + public ResolvedJavaMethod getProfiledMethod() { + return method; + } + + public ValueNode getRandom() { + return random; + } + + public void setRandom(ValueNode r) { + updateUsages(random, r); + this.random = r; + } + + /** + * Get the logarithm base 2 of the profile probability. + */ + public int getProbabilityLog() { + return probabilityLog; + } + + /** + * Gathers all the {@link ProfileNode}s that are inputs to the + * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph. + */ + public static NodeIterable getProfileNodes(StructuredGraph graph) { + return graph.getNodes().filter(ProfileNode.class); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileWithNotificationNode.java 2016-12-07 13:50:32.987237194 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016, 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.nodes.profiling; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; + +@NodeInfo(cycles = CYCLES_10, size = SIZE_50) +public class ProfileWithNotificationNode extends ProfileNode { + public static final NodeClass TYPE = NodeClass.create(ProfileWithNotificationNode.class); + + protected int freqLog; + + protected ProfileWithNotificationNode(NodeClass c, ResolvedJavaMethod method, int freqLog, int probabilityLog) { + super(c, method, probabilityLog); + this.freqLog = freqLog; + } + + public ProfileWithNotificationNode(ResolvedJavaMethod method, int freqLog, int probabilityLog) { + super(TYPE, method, probabilityLog); + this.freqLog = freqLog; + } + + /** + * Get the logarithm base 2 of the notification frequency. + */ + public int getNotificationFreqLog() { + return freqLog; + } + + /** + * Set the logarithm base 2 of the notification frequency. + */ + public void setNotificationFreqLog(int freqLog) { + assert freqLog < 32; + this.freqLog = freqLog; + } + + public void setNotificationOff() { + setNotificationFreqLog(-1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/RandomSeedNode.java 2016-12-07 13:50:33.252248842 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016, 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.nodes.profiling; + +import jdk.vm.ci.meta.Value; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +@NodeInfo(cycles = CYCLES_1, size = SIZE_1) +public class RandomSeedNode extends FloatingNode implements LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(RandomSeedNode.class); + + public RandomSeedNode() { + super(TYPE, StampFactory.intValue()); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitRandomSeed(); + gen.setResult(this, result); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotLIRKindTool.java 2016-12-07 13:50:33.518260534 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 2015, 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.nodes.type; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; + +/** + * Extension of {@link LIRKindTool} that includes support for compressed pointer kinds. + */ +public interface HotSpotLIRKindTool extends LIRKindTool { + + /** + * Get the platform specific kind used to represent compressed oops. + */ + LIRKind getNarrowOopKind(); + + /** + * Gets the platform specific kind used to represent compressed metaspace pointers. + */ + LIRKind getNarrowPointerKind(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/KlassPointerStamp.java 2016-12-07 13:50:33.783272182 -0800 @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2014, 2015, 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.nodes.type; + +import java.util.Objects; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.core.common.type.AbstractPointerStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.hotspot.CompressEncoding; + +import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; +import jdk.vm.ci.hotspot.HotSpotMemoryAccessProvider; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.MetaAccessProvider; + +public final class KlassPointerStamp extends MetaspacePointerStamp { + + private static final KlassPointerStamp KLASS = new KlassPointerStamp(false, false); + + private static final KlassPointerStamp KLASS_NON_NULL = new KlassPointerStamp(true, false); + + private static final KlassPointerStamp KLASS_ALWAYS_NULL = new KlassPointerStamp(false, true); + + private final CompressEncoding encoding; + + public static KlassPointerStamp klass() { + return KLASS; + } + + public static KlassPointerStamp klassNonNull() { + return KLASS_NON_NULL; + } + + public static KlassPointerStamp klassAlwaysNull() { + return KLASS_ALWAYS_NULL; + } + + private KlassPointerStamp(boolean nonNull, boolean alwaysNull) { + this(nonNull, alwaysNull, null); + } + + private KlassPointerStamp(boolean nonNull, boolean alwaysNull, CompressEncoding encoding) { + super(nonNull, alwaysNull); + this.encoding = encoding; + } + + @Override + protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) { + return new KlassPointerStamp(newNonNull, newAlwaysNull, encoding); + } + + @Override + public boolean isCompatible(Stamp otherStamp) { + if (this == otherStamp) { + return true; + } + if (otherStamp instanceof KlassPointerStamp) { + KlassPointerStamp other = (KlassPointerStamp) otherStamp; + return Objects.equals(this.encoding, other.encoding); + } + return false; + } + + @Override + public boolean isCompatible(Constant constant) { + if (constant instanceof HotSpotMetaspaceConstant) { + return ((HotSpotMetaspaceConstant) constant).asResolvedJavaType() != null; + } else { + return super.isCompatible(constant); + } + } + + @Override + public Stamp constant(Constant c, MetaAccessProvider meta) { + if (isCompressed()) { + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { + return new KlassPointerStamp(false, true, encoding); + } + } else { + if (JavaConstant.NULL_POINTER.equals(c)) { + return KLASS_ALWAYS_NULL; + } + } + + assert c instanceof HotSpotMetaspaceConstant; + assert ((HotSpotMetaspaceConstant) c).isCompressed() == isCompressed(); + if (nonNull()) { + return this; + } + if (isCompressed()) { + return new KlassPointerStamp(true, false, encoding); + } else { + return KLASS_NON_NULL; + } + } + + @Override + public Constant asConstant() { + if (alwaysNull() && isCompressed()) { + return HotSpotCompressedNullConstant.COMPRESSED_NULL; + } else { + return super.asConstant(); + } + } + + @Override + public LIRKind getLIRKind(LIRKindTool tool) { + if (isCompressed()) { + return ((HotSpotLIRKindTool) tool).getNarrowPointerKind(); + } else { + return super.getLIRKind(tool); + } + } + + public boolean isCompressed() { + return encoding != null; + } + + public CompressEncoding getEncoding() { + return encoding; + } + + public KlassPointerStamp compressed(CompressEncoding newEncoding) { + assert !isCompressed(); + return new KlassPointerStamp(nonNull(), alwaysNull(), newEncoding); + } + + public KlassPointerStamp uncompressed() { + assert isCompressed(); + return new KlassPointerStamp(nonNull(), alwaysNull()); + } + + @Override + public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) { + HotSpotMemoryAccessProvider hsProvider = (HotSpotMemoryAccessProvider) provider; + if (isCompressed()) { + return hsProvider.readNarrowKlassPointerConstant(base, displacement); + } else { + return hsProvider.readKlassPointerConstant(base, displacement); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((encoding == null) ? 0 : encoding.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (!(obj instanceof KlassPointerStamp)) { + return false; + } + KlassPointerStamp other = (KlassPointerStamp) obj; + return Objects.equals(this.encoding, other.encoding); + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder("Klass*"); + appendString(ret); + if (isCompressed()) { + ret.append("(compressed ").append(encoding).append(")"); + } + return ret.toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MetaspacePointerStamp.java 2016-12-07 13:50:34.048283831 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014, 2015, 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.nodes.type; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.core.common.type.AbstractPointerStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +public abstract class MetaspacePointerStamp extends AbstractPointerStamp { + + protected MetaspacePointerStamp(boolean nonNull, boolean alwaysNull) { + super(nonNull, alwaysNull); + } + + @Override + public LIRKind getLIRKind(LIRKindTool tool) { + return tool.getWordKind(); + } + + @Override + public Stamp empty() { + // there is no empty pointer stamp + return this; + } + + @Override + public boolean isCompatible(Constant constant) { + return constant.isDefaultForKind(); + } + + @Override + public boolean hasValues() { + return true; + } + + @Override + public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { + throw GraalError.shouldNotReachHere("metaspace pointer has no Java type"); + } + + protected void appendString(StringBuilder str) { + str.append(nonNull() ? "!" : "").append(alwaysNull() ? " NULL" : ""); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MethodCountersPointerStamp.java 2016-12-07 13:50:34.314295523 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014, 2015, 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.nodes.type; + +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.MetaAccessProvider; + +import org.graalvm.compiler.core.common.type.AbstractPointerStamp; +import org.graalvm.compiler.core.common.type.Stamp; + +public final class MethodCountersPointerStamp extends MetaspacePointerStamp { + + private static final MethodCountersPointerStamp METHOD_COUNTERS = new MethodCountersPointerStamp(false, false); + + private static final MethodCountersPointerStamp METHOD_COUNTERS_NON_NULL = new MethodCountersPointerStamp(true, false); + + private static final MethodCountersPointerStamp METHOD_COUNTERS_ALWAYS_NULL = new MethodCountersPointerStamp(false, true); + + public static MethodCountersPointerStamp methodCounters() { + return METHOD_COUNTERS; + } + + public static MethodCountersPointerStamp methodCountersNonNull() { + return METHOD_COUNTERS_NON_NULL; + } + + private MethodCountersPointerStamp(boolean nonNull, boolean alwaysNull) { + super(nonNull, alwaysNull); + } + + @Override + protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) { + if (newNonNull) { + assert !newAlwaysNull; + return METHOD_COUNTERS_NON_NULL; + } else if (newAlwaysNull) { + return METHOD_COUNTERS_ALWAYS_NULL; + } else { + return METHOD_COUNTERS; + } + } + + @Override + public boolean isCompatible(Stamp otherStamp) { + if (this == otherStamp) { + return true; + } + return otherStamp instanceof MethodCountersPointerStamp; + } + + @Override + public Stamp constant(Constant c, MetaAccessProvider meta) { + if (JavaConstant.NULL_POINTER.equals(c)) { + return METHOD_COUNTERS_ALWAYS_NULL; + } else { + assert c instanceof HotSpotMetaspaceConstant; + return METHOD_COUNTERS_NON_NULL; + } + } + + @Override + public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) { + return null; + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder("MethodCounters*"); + appendString(ret); + return ret.toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MethodPointerStamp.java 2016-12-07 13:50:34.580307215 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, 2015, 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.nodes.type; + +import org.graalvm.compiler.core.common.type.AbstractPointerStamp; +import org.graalvm.compiler.core.common.type.Stamp; + +import jdk.vm.ci.hotspot.HotSpotMemoryAccessProvider; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.MetaAccessProvider; + +public final class MethodPointerStamp extends MetaspacePointerStamp { + + private static final MethodPointerStamp METHOD = new MethodPointerStamp(false, false); + + private static final MethodPointerStamp METHOD_NON_NULL = new MethodPointerStamp(true, false); + + private static final MethodPointerStamp METHOD_ALWAYS_NULL = new MethodPointerStamp(false, true); + + public static MethodPointerStamp method() { + return METHOD; + } + + public static MethodPointerStamp methodNonNull() { + return METHOD_NON_NULL; + } + + private MethodPointerStamp(boolean nonNull, boolean alwaysNull) { + super(nonNull, alwaysNull); + } + + @Override + protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) { + if (newNonNull) { + assert !newAlwaysNull; + return METHOD_NON_NULL; + } else if (newAlwaysNull) { + return METHOD_ALWAYS_NULL; + } else { + return METHOD; + } + } + + @Override + public boolean isCompatible(Stamp otherStamp) { + if (this == otherStamp) { + return true; + } + return otherStamp instanceof MethodPointerStamp; + } + + @Override + public boolean isCompatible(Constant constant) { + if (constant instanceof HotSpotMetaspaceConstant) { + return ((HotSpotMetaspaceConstant) constant).asResolvedJavaMethod() != null; + } else { + return super.isCompatible(constant); + } + } + + @Override + public Stamp constant(Constant c, MetaAccessProvider meta) { + if (JavaConstant.NULL_POINTER.equals(c)) { + return METHOD_ALWAYS_NULL; + } else { + assert c instanceof HotSpotMetaspaceConstant; + return METHOD_NON_NULL; + } + } + + @Override + public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) { + HotSpotMemoryAccessProvider hsProvider = (HotSpotMemoryAccessProvider) provider; + return hsProvider.readMethodPointerConstant(base, displacement); + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder("Method*"); + appendString(ret); + return ret.toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/NarrowOopStamp.java 2016-12-07 13:50:34.846318907 -0800 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2014, 2016, 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.nodes.type; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.core.common.type.AbstractObjectStamp; +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.hotspot.CompressEncoding; + +import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; +import jdk.vm.ci.hotspot.HotSpotMemoryAccessProvider; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +public class NarrowOopStamp extends AbstractObjectStamp { + + private final CompressEncoding encoding; + + public NarrowOopStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull, CompressEncoding encoding) { + super(type, exactType, nonNull, alwaysNull); + this.encoding = encoding; + } + + @Override + protected AbstractObjectStamp copyWith(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) { + return new NarrowOopStamp(type, exactType, nonNull, alwaysNull, encoding); + } + + public static Stamp compressed(AbstractObjectStamp stamp, CompressEncoding encoding) { + return new NarrowOopStamp(stamp.type(), stamp.isExactType(), stamp.nonNull(), stamp.alwaysNull(), encoding); + } + + public Stamp uncompressed() { + return new ObjectStamp(type(), isExactType(), nonNull(), alwaysNull()); + } + + public CompressEncoding getEncoding() { + return encoding; + } + + @Override + public LIRKind getLIRKind(LIRKindTool tool) { + return ((HotSpotLIRKindTool) tool).getNarrowOopKind(); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append('n'); + appendString(str); + return str.toString(); + } + + @Override + public boolean isCompatible(Stamp other) { + if (this == other) { + return true; + } + if (other instanceof NarrowOopStamp) { + NarrowOopStamp narrow = (NarrowOopStamp) other; + return encoding.equals(narrow.encoding); + } + return false; + } + + @Override + public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) { + HotSpotMemoryAccessProvider hsProvider = (HotSpotMemoryAccessProvider) provider; + return hsProvider.readNarrowOopConstant(base, displacement); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + encoding.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + NarrowOopStamp other = (NarrowOopStamp) obj; + if (!encoding.equals(other.encoding)) { + return false; + } + return super.equals(other); + } + + @Override + public JavaConstant asConstant() { + if (alwaysNull()) { + return HotSpotCompressedNullConstant.COMPRESSED_NULL; + } else { + return null; + } + } + + @Override + public boolean isCompatible(Constant other) { + if (other instanceof HotSpotObjectConstant) { + return ((HotSpotObjectConstant) other).isCompressed(); + } + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/package-info.java 2016-12-07 13:50:35.112330599 -0800 @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011, 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; --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java 2016-12-07 13:50:35.378342291 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013, 2015, 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.phases; + +import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; + +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.phases.VerifyPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.JavaKind; + +/** + * Checks for {@link #isIllegalObjectConstant(ConstantNode) illegal} object constants in a graph + * processed for AOT compilation. + * + * @see LoadJavaMirrorWithKlassPhase + */ +public class AheadOfTimeVerificationPhase extends VerifyPhase { + + @Override + protected boolean verify(StructuredGraph graph, PhaseContext context) { + for (ConstantNode node : getConstantNodes(graph)) { + if (isIllegalObjectConstant(node)) { + throw new VerificationError("illegal object constant: " + node); + } + } + return true; + } + + public static boolean isIllegalObjectConstant(ConstantNode node) { + return isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node); + } + + private static boolean isObject(ConstantNode node) { + return node.getStackKind() == JavaKind.Object; + } + + private static boolean isNullReference(ConstantNode node) { + return isObject(node) && node.isNullConstant(); + } + + private static boolean isDirectMethodHandle(ConstantNode node) { + if (!isObject(node)) { + return false; + } + return "Ljava/lang/invoke/DirectMethodHandle;".equals(StampTool.typeOrNull(node).getName()); + } + + private static boolean isBoundMethodHandle(ConstantNode node) { + if (!isObject(node)) { + return false; + } + return StampTool.typeOrNull(node).getName().startsWith("Ljava/lang/invoke/BoundMethodHandle"); + } + + private static boolean isInternedString(ConstantNode node) { + if (!isObject(node)) { + return false; + } + + HotSpotObjectConstant c = (HotSpotObjectConstant) node.asConstant(); + return c.isInternedString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java 2016-12-07 13:50:35.645354027 -0800 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2013, 2015, 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.phases; + +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_LOCATION; +import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; +import static org.graalvm.compiler.nodes.NamedLocationIdentity.FINAL_LOCATION; + +import org.graalvm.compiler.core.common.type.AbstractObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.TypeReference; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.CompressEncoding; +import org.graalvm.compiler.hotspot.nodes.CompressionNode; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.FloatingReadNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaField; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.hotspot.HotSpotResolvedPrimitiveType; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * For AOT compilation we aren't allowed to use a {@link Class} reference ({@code javaMirror}) + * directly. Instead the {@link Class} reference should be obtained from the {@code Klass} object. + * The reason for this is, that in Class Data Sharing (CDS) a {@code Klass} object is mapped to a + * fixed address in memory, but the {@code javaMirror} is not (which lives in the Java heap). + * + * Lowering can introduce new {@link ConstantNode}s containing a {@link Class} reference, thus this + * phase must be applied after {@link LoweringPhase}. + * + * @see AheadOfTimeVerificationPhase + */ +public class LoadJavaMirrorWithKlassPhase extends BasePhase { + + private final int classMirrorOffset; + private final CompressEncoding oopEncoding; + + public LoadJavaMirrorWithKlassPhase(int classMirrorOffset, CompressEncoding oopEncoding) { + this.classMirrorOffset = classMirrorOffset; + this.oopEncoding = oopEncoding; + } + + private ValueNode getClassConstantReplacement(StructuredGraph graph, PhaseContext context, JavaConstant constant) { + if (constant instanceof HotSpotObjectConstant) { + ConstantReflectionProvider constantReflection = context.getConstantReflection(); + ResolvedJavaType type = constantReflection.asJavaType(constant); + if (type != null) { + MetaAccessProvider metaAccess = context.getMetaAccess(); + Stamp stamp = StampFactory.objectNonNull(TypeReference.createExactTrusted(metaAccess.lookupJavaType(Class.class))); + + if (type instanceof HotSpotResolvedObjectType) { + ConstantNode klass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) type).klass(), metaAccess, graph); + AddressNode address = graph.unique(new OffsetAddressNode(klass, ConstantNode.forLong(classMirrorOffset, graph))); + ValueNode read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_LOCATION, null, stamp)); + + if (((HotSpotObjectConstant) constant).isCompressed()) { + return CompressionNode.compress(read, oopEncoding); + } else { + return read; + } + } else { + /* + * Primitive classes are more difficult since they don't have a corresponding + * Klass* so get them from Class.TYPE for the java box type. + */ + HotSpotResolvedPrimitiveType primitive = (HotSpotResolvedPrimitiveType) type; + ResolvedJavaType boxingClass = metaAccess.lookupJavaType(primitive.getJavaKind().toBoxedJavaClass()); + ConstantNode clazz = ConstantNode.forConstant(context.getConstantReflection().asJavaClass(boxingClass), metaAccess, graph); + HotSpotResolvedJavaField[] a = (HotSpotResolvedJavaField[]) boxingClass.getStaticFields(); + HotSpotResolvedJavaField typeField = null; + for (HotSpotResolvedJavaField f : a) { + if (f.getName().equals("TYPE")) { + typeField = f; + break; + } + } + if (typeField == null) { + throw new GraalError("Can't find TYPE field in class"); + } + + if (oopEncoding != null) { + stamp = NarrowOopStamp.compressed((AbstractObjectStamp) stamp, oopEncoding); + } + AddressNode address = graph.unique(new OffsetAddressNode(clazz, ConstantNode.forLong(typeField.offset(), graph))); + ValueNode read = graph.unique(new FloatingReadNode(address, FINAL_LOCATION, null, stamp)); + + if (oopEncoding == null || ((HotSpotObjectConstant) constant).isCompressed()) { + return read; + } else { + return CompressionNode.uncompress(read, oopEncoding); + } + } + } + } + return null; + } + + @Override + protected void run(StructuredGraph graph, PhaseContext context) { + for (ConstantNode node : getConstantNodes(graph)) { + JavaConstant constant = node.asJavaConstant(); + ValueNode freadNode = getClassConstantReplacement(graph, context, constant); + if (freadNode != null) { + node.replace(graph, freadNode); + } + } + } + + @Override + public float codeSizeIncrease() { + return 2.5f; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java 2016-12-07 13:50:35.909365631 -0800 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2011, 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.phases; + +import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required; + +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.core.common.cfg.Loop; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.loop.LoopsData; +import org.graalvm.compiler.loop.phases.LoopTransformations; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.Verbosity; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.EntryMarkerNode; +import org.graalvm.compiler.nodes.EntryProxyNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.StartNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.extended.OSRLocalNode; +import org.graalvm.compiler.nodes.extended.OSRStartNode; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.phases.Phase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; + +import jdk.vm.ci.runtime.JVMCICompiler; + +public class OnStackReplacementPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + if (graph.getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI) { + // This happens during inlining in a OSR method, because the same phase plan will be + // used. + assert graph.getNodes(EntryMarkerNode.TYPE).isEmpty(); + return; + } + Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement initial"); + EntryMarkerNode osr; + int maxIterations = -1; + int iterations = 0; + do { + osr = getEntryMarker(graph); + LoopsData loops = new LoopsData(graph); + // Find the loop that contains the EntryMarker + Loop l = loops.getCFG().getNodeToBlock().get(osr).getLoop(); + if (l == null) { + break; + } + iterations++; + if (maxIterations == -1) { + maxIterations = l.getDepth(); + } else if (iterations > maxIterations) { + throw GraalError.shouldNotReachHere(); + } + // Peel the outermost loop first + while (l.getParent() != null) { + l = l.getParent(); + } + + LoopTransformations.peel(loops.loop(l)); + osr.replaceAtUsages(InputType.Guard, AbstractBeginNode.prevBegin((FixedNode) osr.predecessor())); + for (Node usage : osr.usages().snapshot()) { + EntryProxyNode proxy = (EntryProxyNode) usage; + proxy.replaceAndDelete(proxy.value()); + } + GraphUtil.removeFixedWithUnusedInputs(osr); + Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement loop peeling result"); + } while (true); + + FrameState osrState = osr.stateAfter(); + osr.setStateAfter(null); + OSRStartNode osrStart = graph.add(new OSRStartNode()); + StartNode start = graph.start(); + FixedNode next = osr.next(); + osr.setNext(null); + osrStart.setNext(next); + graph.setStart(osrStart); + osrStart.setStateAfter(osrState); + + for (int i = 0; i < osrState.localsSize(); i++) { + ValueNode value = osrState.localAt(i); + if (value instanceof EntryProxyNode) { + EntryProxyNode proxy = (EntryProxyNode) value; + /* + * we need to drop the stamp since the types we see during OSR may be too precise + * (if a branch was not parsed for example). + */ + proxy.replaceAndDelete(graph.addOrUnique(new OSRLocalNode(i, proxy.stamp().unrestricted()))); + } else { + assert value == null || value instanceof OSRLocalNode; + } + } + osr.replaceAtUsages(InputType.Guard, osrStart); + assert osr.usages().isEmpty(); + + GraphUtil.killCFG(start); + + Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement result"); + new DeadCodeEliminationPhase(Required).apply(graph); + } + + private static EntryMarkerNode getEntryMarker(StructuredGraph graph) { + NodeIterable osrNodes = graph.getNodes(EntryMarkerNode.TYPE); + EntryMarkerNode osr = osrNodes.first(); + if (osr == null) { + throw new PermanentBailoutException("No OnStackReplacementNode generated"); + } + if (osrNodes.count() > 1) { + throw new GraalError("Multiple OnStackReplacementNodes generated"); + } + if (osr.stateAfter().locksSize() != 0) { + throw new PermanentBailoutException("OSR with locks not supported"); + } + if (osr.stateAfter().stackSize() != 0) { + throw new PermanentBailoutException("OSR with stack entries not supported: %s", osr.stateAfter().toString(Verbosity.Debugger)); + } + return osr; + } + + @Override + public float codeSizeIncrease() { + return 5.0f; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java 2016-12-07 13:50:36.174377280 -0800 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2013, 2015, 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.phases; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier; +import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode; +import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode; +import org.graalvm.compiler.nodes.java.LoweredCompareAndSwapNode; +import org.graalvm.compiler.nodes.memory.FixedAccessNode; +import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.WriteNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.phases.Phase; + +public class WriteBarrierAdditionPhase extends Phase { + + private GraalHotSpotVMConfig config; + + public WriteBarrierAdditionPhase(GraalHotSpotVMConfig config) { + this.config = config; + } + + @Override + protected void run(StructuredGraph graph) { + for (Node n : graph.getNodes()) { + if (n instanceof ReadNode) { + addReadNodeBarriers((ReadNode) n, graph); + } else if (n instanceof WriteNode) { + addWriteNodeBarriers((WriteNode) n, graph); + } else if (n instanceof LoweredAtomicReadAndWriteNode) { + LoweredAtomicReadAndWriteNode loweredAtomicReadAndWriteNode = (LoweredAtomicReadAndWriteNode) n; + addAtomicReadWriteNodeBarriers(loweredAtomicReadAndWriteNode, graph); + } else if (n instanceof LoweredCompareAndSwapNode) { + addCASBarriers((LoweredCompareAndSwapNode) n, graph); + } else if (n instanceof ArrayRangeWriteNode) { + ArrayRangeWriteNode node = (ArrayRangeWriteNode) n; + if (node.isObjectArray()) { + addArrayRangeBarriers(node, graph); + } + } + } + } + + private void addReadNodeBarriers(ReadNode node, StructuredGraph graph) { + if (node.getBarrierType() == BarrierType.PRECISE) { + assert config.useG1GC; + G1ReferentFieldReadBarrier barrier = graph.add(new G1ReferentFieldReadBarrier(node.getAddress(), node, false)); + graph.addAfterFixed(node, barrier); + } else { + assert node.getBarrierType() == BarrierType.NONE : "Non precise read barrier has been attached to read node."; + } + } + + protected static void addG1PreWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean doLoad, boolean nullCheck, StructuredGraph graph) { + G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(address, value, doLoad, nullCheck)); + preBarrier.setStateBefore(node.stateBefore()); + node.setNullCheck(false); + node.setStateBefore(null); + graph.addBeforeFixed(node, preBarrier); + } + + protected void addG1PostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) { + final boolean alwaysNull = StampTool.isPointerAlwaysNull(value); + graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(address, value, precise, alwaysNull))); + } + + protected void addSerialPostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) { + final boolean alwaysNull = StampTool.isPointerAlwaysNull(value); + if (alwaysNull) { + // Serial barrier isn't needed for null value + return; + } + graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(address, precise))); + } + + private void addWriteNodeBarriers(WriteNode node, StructuredGraph graph) { + BarrierType barrierType = node.getBarrierType(); + switch (barrierType) { + case NONE: + // nothing to do + break; + case IMPRECISE: + case PRECISE: + boolean precise = barrierType == BarrierType.PRECISE; + if (config.useG1GC) { + if (!node.isInitialization()) { + addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph); + } + addG1PostWriteBarrier(node, node.getAddress(), node.value(), precise, graph); + } else { + addSerialPostWriteBarrier(node, node.getAddress(), node.value(), precise, graph); + } + break; + default: + throw new GraalError("unexpected barrier type: " + barrierType); + } + } + + private void addAtomicReadWriteNodeBarriers(LoweredAtomicReadAndWriteNode node, StructuredGraph graph) { + BarrierType barrierType = node.getBarrierType(); + switch (barrierType) { + case NONE: + // nothing to do + break; + case IMPRECISE: + case PRECISE: + boolean precise = barrierType == BarrierType.PRECISE; + if (config.useG1GC) { + addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph); + addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); + } else { + addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); + } + break; + default: + throw new GraalError("unexpected barrier type: " + barrierType); + } + } + + private void addCASBarriers(LoweredCompareAndSwapNode node, StructuredGraph graph) { + BarrierType barrierType = node.getBarrierType(); + switch (barrierType) { + case NONE: + // nothing to do + break; + case IMPRECISE: + case PRECISE: + boolean precise = barrierType == BarrierType.PRECISE; + if (config.useG1GC) { + addG1PreWriteBarrier(node, node.getAddress(), node.getExpectedValue(), false, false, graph); + addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); + } else { + addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); + } + break; + default: + throw new GraalError("unexpected barrier type: " + barrierType); + } + } + + private void addArrayRangeBarriers(ArrayRangeWriteNode node, StructuredGraph graph) { + if (config.useG1GC) { + if (!node.isInitialization()) { + G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); + graph.addBeforeFixed(node, g1ArrayRangePreWriteBarrier); + } + G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); + graph.addAfterFixed(node, g1ArrayRangePostWriteBarrier); + } else { + SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); + graph.addAfterFixed(node, serialArrayRangeWriteBarrier); + } + } + + @Override + public boolean checkContract() { + return false; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java 2016-12-07 13:50:36.448389323 -0800 @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2013, 2015, 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.phases; + +import java.util.Iterator; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeFlood; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.nodes.ArrayRangeWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.ObjectWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier; +import org.graalvm.compiler.nodes.DeoptimizingNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode; +import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode; +import org.graalvm.compiler.nodes.java.LoweredCompareAndSwapNode; +import org.graalvm.compiler.nodes.memory.FixedAccessNode; +import org.graalvm.compiler.nodes.memory.HeapAccess; +import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.WriteNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.phases.Phase; + +/** + * Verification phase that checks if, for every write, at least one write barrier is present at all + * paths leading to the previous safepoint. For every write, necessitating a write barrier, a + * bottom-up traversal of the graph is performed up to the previous safepoints via all possible + * paths. If, for a certain path, no write barrier satisfying the processed write is found, an + * assertion is generated. + */ +public class WriteBarrierVerificationPhase extends Phase { + + private final GraalHotSpotVMConfig config; + + public WriteBarrierVerificationPhase(GraalHotSpotVMConfig config) { + this.config = config; + } + + @Override + protected void run(StructuredGraph graph) { + processWrites(graph); + } + + private void processWrites(StructuredGraph graph) { + for (Node node : graph.getNodes()) { + if (isObjectWrite(node) || isObjectArrayRangeWrite(node)) { + validateWrite(node); + } + } + } + + private void validateWrite(Node write) { + /* + * The currently validated write is checked in order to discover if it has an appropriate + * attached write barrier. + */ + if (hasAttachedBarrier((FixedWithNextNode) write)) { + return; + } + NodeFlood frontier = write.graph().createNodeFlood(); + expandFrontier(frontier, write); + Iterator iterator = frontier.iterator(); + while (iterator.hasNext()) { + Node currentNode = iterator.next(); + if (isSafepoint(currentNode)) { + throw new AssertionError("Write barrier must be present " + write); + } + if (useG1GC()) { + if (!(currentNode instanceof G1PostWriteBarrier) || (!validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode))) { + expandFrontier(frontier, currentNode); + } + } else { + if (!(currentNode instanceof SerialWriteBarrier) || (!validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode)) || + ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode))) { + expandFrontier(frontier, currentNode); + } + } + } + } + + private boolean useG1GC() { + return config.useG1GC; + } + + private boolean hasAttachedBarrier(FixedWithNextNode node) { + final Node next = node.next(); + final Node previous = node.predecessor(); + final boolean validatePreBarrier = useG1GC() && (isObjectWrite(node) || !((ArrayRangeWriteNode) node).isInitialization()); + if (isObjectWrite(node)) { + return (isObjectBarrier(node, next) || StampTool.isPointerAlwaysNull(getValueWritten(node))) && (!validatePreBarrier || isObjectBarrier(node, previous)); + } else if (isObjectArrayRangeWrite(node)) { + return (isArrayBarrier(node, next) || StampTool.isPointerAlwaysNull(getValueWritten(node))) && (!validatePreBarrier || isArrayBarrier(node, previous)); + } else { + return true; + } + } + + private static boolean isObjectBarrier(FixedWithNextNode node, final Node next) { + return next instanceof ObjectWriteBarrier && validateBarrier((FixedAccessNode) node, (ObjectWriteBarrier) next); + } + + private static boolean isArrayBarrier(FixedWithNextNode node, final Node next) { + return (next instanceof ArrayRangeWriteBarrier) && ((ArrayRangeWriteNode) node).getArray() == ((ArrayRangeWriteBarrier) next).getObject(); + } + + private static boolean isObjectWrite(Node node) { + // Read nodes with barrier attached (G1 Ref field) are not validated yet. + return node instanceof FixedAccessNode && ((HeapAccess) node).getBarrierType() != BarrierType.NONE && !(node instanceof ReadNode); + } + + private static boolean isObjectArrayRangeWrite(Node node) { + return node instanceof ArrayRangeWriteNode && ((ArrayRangeWriteNode) node).isObjectArray(); + } + + private static void expandFrontier(NodeFlood frontier, Node node) { + for (Node previousNode : node.cfgPredecessors()) { + if (previousNode != null) { + frontier.add(previousNode); + } + } + } + + private static boolean isSafepoint(Node node) { + /* + * LoopBegin nodes are also treated as safepoints since a bottom-up analysis is performed + * and loop safepoints are placed before LoopEnd nodes. Possible elimination of write + * barriers inside loops, derived from writes outside loops, can not be permitted. + */ + return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode); + } + + private static ValueNode getValueWritten(FixedWithNextNode write) { + if (write instanceof WriteNode) { + return ((WriteNode) write).value(); + } else if (write instanceof LoweredCompareAndSwapNode) { + return ((LoweredCompareAndSwapNode) write).getNewValue(); + } else if (write instanceof LoweredAtomicReadAndWriteNode) { + return ((LoweredAtomicReadAndWriteNode) write).getNewValue(); + } else { + throw GraalError.shouldNotReachHere(String.format("unexpected write node %s", write)); + } + } + + private static boolean validateBarrier(FixedAccessNode write, ObjectWriteBarrier barrier) { + assert write instanceof WriteNode || write instanceof LoweredCompareAndSwapNode || write instanceof LoweredAtomicReadAndWriteNode : "Node must be of type requiring a write barrier " + write; + if (!barrier.usePrecise()) { + if (barrier.getAddress() instanceof OffsetAddressNode && write.getAddress() instanceof OffsetAddressNode) { + return ((OffsetAddressNode) barrier.getAddress()).getBase() == ((OffsetAddressNode) write.getAddress()).getBase(); + } + } + return barrier.getAddress() == write.getAddress(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java 2016-12-07 13:50:36.716401103 -0800 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2016, 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.phases.aot; + +import static org.graalvm.compiler.core.common.GraalOptions.InlineEverything; +import static org.graalvm.compiler.core.common.GraalOptions.TrivialInliningSize; + +import java.util.Map; + +import org.graalvm.compiler.hotspot.FingerprintUtil; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.spi.Replacements; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.phases.common.inlining.InliningUtil; +import org.graalvm.compiler.phases.common.inlining.info.InlineInfo; +import org.graalvm.compiler.phases.common.inlining.policy.GreedyInliningPolicy; +import org.graalvm.compiler.phases.common.inlining.walker.MethodInvocation; + +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; + +public class AOTInliningPolicy extends GreedyInliningPolicy { + public static class Options { + // @formatter:off + @Option(help = "", type = OptionType.Expert) + public static final OptionValue AOTInliningDepthToSizeRate = new OptionValue<>(2.5); + @Option(help = "", type = OptionType.Expert) + public static final OptionValue AOTInliningSizeMaximum = new OptionValue<>(300); + @Option(help = "", type = OptionType.Expert) + public static final OptionValue AOTInliningSizeMinimum = new OptionValue<>(50); + // @formatter:on + } + + public AOTInliningPolicy(Map hints) { + super(hints); + } + + protected double maxInliningSize(int inliningDepth) { + return Math.max(Options.AOTInliningSizeMaximum.getValue() / (inliningDepth * Options.AOTInliningDepthToSizeRate.getValue()), Options.AOTInliningSizeMinimum.getValue()); + } + + @Override + public boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { + final InlineInfo info = invocation.callee(); + + for (int i = 0; i < info.numberOfMethods(); ++i) { + HotSpotResolvedObjectType t = (HotSpotResolvedObjectType) info.methodAt(i).getDeclaringClass(); + if (FingerprintUtil.getFingerprint(t) == 0) { + return false; + } + } + + final double probability = invocation.probability(); + final double relevance = invocation.relevance(); + + if (InlineEverything.getValue()) { + InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything"); + return true; + } + + if (isIntrinsic(replacements, info)) { + InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); + return true; + } + + if (info.shouldInline()) { + InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining"); + return true; + } + + double inliningBonus = getInliningBonus(info); + int nodes = info.determineNodeCount(); + + if (nodes < TrivialInliningSize.getValue() * inliningBonus) { + InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); + return true; + } + + double maximumNodes = computeMaximumSize(relevance, (int) (maxInliningSize(inliningDepth) * inliningBonus)); + if (nodes <= maximumNodes) { + InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, + nodes, maximumNodes); + return true; + } + + InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); + return false; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java 2016-12-07 13:50:36.981412751 -0800 @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2016, 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.phases.aot; + +import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map.Entry; + +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.JavaConstant; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class EliminateRedundantInitializationPhase extends BasePhase { + /** + * Find blocks with class initializing nodes for the class identified the by the constant node. + * Return the map of a block to a list of initializing nodes in that block. + * + * @param cfg an instance of the {@link ControlFlowGraph}. + * @param constant common input to the instances of {@link InitializeKlassNode}. + * @return map of blocks to lists of initializing nodes. + */ + private static HashMap> findBlocksWithInitializers(ControlFlowGraph cfg, ConstantNode constant) { + // node is ConstantNode representing a metaspace constant (a klass reference). + // InitializeKlassNodes for the same class would share the same ConstantNode input. + NodeIterable initializers = constant.usages().filter(InitializeKlassNode.class); + // Map the found nodes to blocks + HashMap> blockToInits = new HashMap<>(); + for (Node i : initializers) { + Block b = cfg.blockFor(i); + ArrayList initsInBlock = blockToInits.get(b); + if (initsInBlock == null) { + initsInBlock = new ArrayList<>(); + } + initsInBlock.add(i); + blockToInits.put(b, initsInBlock); + } + return blockToInits; + } + + /** + * Process the block-to-initializers map and produce a list of blocks that contain more than one + * instance of {@link InitializeKlassNode}. + * + * @param blockToInits a map of blocks to lists of {@link InitializeKlassNode} instances. + * @return list of blocks that contain multiple instances of {@link InitializeKlassNode}. + */ + private static ArrayList findBlocksWithMultipleInitializers(HashMap> blockToInits) { + ArrayList result = new ArrayList<>(); + // Select the blocks from the blocksToInits map that have more than one InitializeKlassNode + for (Entry> e : blockToInits.entrySet()) { + if (e.getValue().size() > 1) { + result.add(e.getKey()); + } + } + return result; + } + + /** + * Iterate through blocks with multiple instances of {@link InitializeKlassNode} and identify + * redundant instances. Remove redundant instances from the block-to-list-of-initializer map. + * + * @param blockToInits a map of blocks to lists of {@link InitializeKlassNode} instances. + * @param blocksWithMultipleInits a list of blocks that contain multiple instances of + * {@link InitializeKlassNode}. + * @param constant common input to the instances of {@link InitializeKlassNode}. + * @return list of {@link InitializeKlassNode} instances that can be removed. + */ + private static ArrayList findRedundantLocalInitializers(HashMap> blockToInits, ArrayList blocksWithMultipleInits, ConstantNode constant) { + ArrayList result = new ArrayList<>(); + for (Block b : blocksWithMultipleInits) { + // First initializer for our constant in the block + InitializeKlassNode first = null; + for (Node n : b.getNodes()) { + if (n instanceof InitializeKlassNode) { + InitializeKlassNode i = (InitializeKlassNode) n; + if (i.value() == constant) { + if (first == null) { + // First instance of {@link InitializeKlassNode} stays. + first = i; + } else { + // All the following instances of {@link InitializeKlassNode} can be + // removed. + result.add(i); + } + } + } + } + assert first != null; + + // Replace the entry in the initsInBlock map to contain just a single initializer + ArrayList initsInBlock = new ArrayList<>(); + initsInBlock.add(first); + blockToInits.put(b, initsInBlock); + } + return result; + } + + /** + * Find cases when one {@link InitializeKlassNode} instance dominates another. The dominated + * instance can be removed. + * + * @param blockToInits a map of blocks to lists of {@link InitializeKlassNode} instances. + * @return list of {@link InitializeKlassNode} instances that can be removed. + */ + private static ArrayList findRedundantGlobalInitializers(HashMap> blockToInits) { + ArrayList result = new ArrayList<>(); + for (Entry> e : blockToInits.entrySet()) { + Block currentBlock = e.getKey(); + ArrayList nodesInCurrent = e.getValue(); + if (nodesInCurrent != null) { // if the list is null, the initializer has already been + // eliminated. + for (Block d : currentBlock.getDominated()) { + ArrayList nodesInDominated = blockToInits.get(d); + if (nodesInDominated != null) { // if the list is null, the initializer has + // already been eliminated. + assert nodesInDominated.size() == 1; + Node n = nodesInDominated.iterator().next(); + result.add(n); + blockToInits.put(d, null); + } + } + } + } + return result; + } + + /** + * Compute the list of redundant {@link InitializeKlassNode} instances that have the common + * {@link ConstantNode}. + * + * @param cfg an instance of the {@link ControlFlowGraph}. + * @param constant common input to the instances of {@link InitializeKlassNode}. + * @return list of {@link InitializeKlassNode} instances that can be removed. + */ + private static ArrayList processConstantNode(ControlFlowGraph cfg, ConstantNode constant) { + HashMap> blockToInits = findBlocksWithInitializers(cfg, constant); + ArrayList blocksWithMultipleInits = findBlocksWithMultipleInitializers(blockToInits); + ArrayList redundantInits = findRedundantLocalInitializers(blockToInits, blocksWithMultipleInits, constant); + // At this point each block has at most one initializer for this constant + if (blockToInits.size() > 1) { + redundantInits.addAll(findRedundantGlobalInitializers(blockToInits)); + } + return redundantInits; + } + + /** + * Find each {@link Invoke} that has a corresponding {@link InitializeKlassNode}. These + * {@link InitializeKlassNode} are redundant and are removed. + * + */ + private static void removeInitsAtStaticCalls(StructuredGraph graph) { + for (Invoke invoke : graph.getInvokes()) { + if (invoke.classInit() != null) { + Node classInit = invoke.classInit(); + classInit.replaceAtUsages(null); + graph.removeFixed((FixedWithNextNode) classInit); + } + } + } + + /** + * Find {@link InitializeKlassNode} instances that can be removed because there is an existing + * dominating initialization. + * + * @param graph the program graph. + */ + private static void removeRedundantInits(StructuredGraph graph) { + // Create cfg, we need blocks and dominators. + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, true, false); + ArrayList redundantInits = new ArrayList<>(); + for (ConstantNode node : getConstantNodes(graph)) { + JavaConstant constant = node.asJavaConstant(); + if (constant instanceof HotSpotMetaspaceConstant) { + redundantInits.addAll(processConstantNode(cfg, node)); + } + } + // Remove redundant instances of {@link InitializeKlassNode} from the graph. + for (Node n : redundantInits) { + graph.removeFixed((FixedWithNextNode) n); + } + } + + @Override + protected void run(StructuredGraph graph, PhaseContext context) { + removeInitsAtStaticCalls(graph); + removeRedundantInits(graph); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java 2016-12-07 13:50:37.246424400 -0800 @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2016, 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.phases.aot; + +import static org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode.getLoadMethodCountersNodes; +import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; + +import java.util.HashSet; + +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.FingerprintUtil; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; +import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; +import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode; +import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; +import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class ReplaceConstantNodesPhase extends BasePhase { + + private static final HashSet> builtIns = new HashSet<>(); + + static { + builtIns.add(Boolean.class); + + Class characterCacheClass = Character.class.getDeclaredClasses()[0]; + assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); + builtIns.add(characterCacheClass); + + Class byteCacheClass = Byte.class.getDeclaredClasses()[0]; + assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); + builtIns.add(byteCacheClass); + + Class shortCacheClass = Short.class.getDeclaredClasses()[0]; + assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); + builtIns.add(shortCacheClass); + + Class integerCacheClass = Integer.class.getDeclaredClasses()[0]; + assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); + builtIns.add(integerCacheClass); + + Class longCacheClass = Long.class.getDeclaredClasses()[0]; + assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); + builtIns.add(longCacheClass); + } + + private static boolean isReplacementNode(Node n) { + // @formatter:off + return n instanceof LoadConstantIndirectlyNode || + n instanceof LoadConstantIndirectlyFixedNode || + n instanceof ResolveConstantNode || + n instanceof InitializeKlassNode; + // @formatter:on + } + + private static boolean checkForBadFingerprint(HotSpotResolvedJavaType type) { + if (type.isArray()) { + if (type.getElementalType().isPrimitive()) { + return false; + } + return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) (type.getElementalType())) == 0; + } + return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) type) == 0; + } + + private static void handleHotSpotMetaspaceConstant(StructuredGraph graph, ConstantNode node) { + HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant(); + HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType(); + + if (type != null) { + if (checkForBadFingerprint(type)) { + throw new GraalError("Type with bad fingerprint: " + type); + } + + assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants"; + ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass(); + ValueNode replacement; + + if (type.isArray() && type.getComponentType().isPrimitive()) { + // Special case for primitive arrays. The AOT runtime pre-resolves them, so we may + // omit the resolution call. + replacement = new LoadConstantIndirectlyNode(node); + } else if (type.equals(topMethodHolder) || (type.isAssignableFrom(topMethodHolder) && !type.isInterface())) { + // If it's a supertype of or the same class that declares the top method, we are + // guaranteed to have it resolved already. If it's an interface, we just test for + // equality. + replacement = new LoadConstantIndirectlyNode(node); + } else if (builtIns.contains(type.mirror())) { + // Special case of klass constants that come from {@link BoxingSnippets}. + replacement = new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE); + } else { + replacement = new ResolveConstantNode(node); + } + + node.replaceAtUsages(graph.addOrUnique(replacement), n -> !isReplacementNode(n)); + } else { + throw new GraalError("Unsupported metaspace constant type: " + type); + } + } + + private static void handleHotSpotObjectConstant(StructuredGraph graph, ConstantNode node) { + HotSpotObjectConstant constant = (HotSpotObjectConstant) node.asJavaConstant(); + HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) constant.getType(); + if (type.mirror().equals(String.class)) { + assert !constant.isCompressed() : "No support for replacing compressed oop constants"; + ValueNode replacement = graph.unique(new ResolveConstantNode(node)); + node.replaceAtUsages(replacement, n -> !(n instanceof ResolveConstantNode)); + } else { + throw new GraalError("Unsupported object constant type: " + type); + } + } + + private static void handleLoadMethodCounters(StructuredGraph graph, LoadMethodCountersNode node, PhaseContext context) { + ResolvedJavaType type = node.getMethod().getDeclaringClass(); + Stamp hubStamp = context.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull()); + ConstantReflectionProvider constantReflection = context.getConstantReflection(); + ConstantNode klassHint = ConstantNode.forConstant(hubStamp, constantReflection.asObjectHub(type), context.getMetaAccess(), graph); + ValueNode replacement = graph.unique(new ResolveMethodAndLoadCountersNode(node.getMethod(), klassHint)); + node.replaceAtUsages(replacement, n -> !(n instanceof ResolveMethodAndLoadCountersNode)); + } + + @Override + protected void run(StructuredGraph graph, PhaseContext context) { + // Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass + // constants. + for (LoadMethodCountersNode node : getLoadMethodCountersNodes(graph)) { + handleLoadMethodCounters(graph, node, context); + } + + // Replace object and klass constants (including the ones added in the previous pass) with + // resolution nodes. + for (ConstantNode node : getConstantNodes(graph)) { + Constant constant = node.asConstant(); + if (constant instanceof HotSpotMetaspaceConstant) { + handleHotSpotMetaspaceConstant(graph, node); + } else if (constant instanceof HotSpotObjectConstant) { + handleHotSpotObjectConstant(graph, node); + } + } + } + + @Override + public boolean checkContract() { + return false; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/profiling/FinalizeProfileNodesPhase.java 2016-12-07 13:50:37.511436048 -0800 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2016, 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.phases.profiling; + +import static org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode.getProfileInvokeNodes; +import static org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode.getProfileNodes; + +import java.util.HashMap; +import java.util.Map; + +import org.graalvm.compiler.core.common.cfg.Loop; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; +import org.graalvm.compiler.hotspot.nodes.profiling.RandomSeedNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.ValuePhiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.MulNode; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class FinalizeProfileNodesPhase extends BasePhase { + private int inlineeInvokeNotificationFreqLog; + + public static class Options { + @Option(help = "Profile simple methods", type = OptionType.Expert)// + public static final OptionValue ProfileSimpleMethods = new OptionValue<>(true); + @Option(help = "Maximum number of nodes in a graph for a simple method", type = OptionType.Expert)// + public static final OptionValue SimpleMethodGraphSize = new OptionValue<>(256); + @Option(help = "Maximum number of calls in a simple method", type = OptionType.Expert)// + public static final OptionValue SimpleMethodCalls = new OptionValue<>(1); + @Option(help = "Maximum number of indirect calls in a simple moethod", type = OptionType.Expert)// + public static final OptionValue SimpleMethodIndirectCalls = new OptionValue<>(0); + + } + + public FinalizeProfileNodesPhase(int inlineeInvokeNotificationFreqLog) { + this.inlineeInvokeNotificationFreqLog = inlineeInvokeNotificationFreqLog; + } + + private static void removeAllProfilingNodes(StructuredGraph graph) { + getProfileNodes(graph).forEach((n) -> GraphUtil.removeFixedWithUnusedInputs(n)); + } + + private void assignInlineeInvokeFrequencies(StructuredGraph graph) { + for (ProfileInvokeNode node : getProfileInvokeNodes(graph)) { + ResolvedJavaMethod profiledMethod = node.getProfiledMethod(); + if (!profiledMethod.equals(graph.method())) { + // Some inlinee, reassign the inlinee frequency + node.setNotificationFreqLog(inlineeInvokeNotificationFreqLog); + } + } + } + + // Hacky heuristic to determine whether we want any profiling in this method. + // The heuristic is applied after the graph is fully formed and before the first lowering. + private static boolean simpleMethodHeuristic(StructuredGraph graph) { + if (Options.ProfileSimpleMethods.getValue()) { + return false; + } + + // Check if the graph is smallish.. + if (graph.getNodeCount() > Options.SimpleMethodGraphSize.getValue()) { + return false; + } + + // Check if method has loops + if (graph.hasLoops()) { + return false; + } + + // Check if method has calls + if (graph.getNodes().filter(InvokeNode.class).count() > Options.SimpleMethodCalls.getValue()) { + return false; + } + + // Check if method has calls that need profiling + if (graph.getNodes().filter(InvokeNode.class).filter((n) -> ((InvokeNode) n).getInvokeKind().isIndirect()).count() > Options.SimpleMethodIndirectCalls.getDefaultValue()) { + return false; + } + + return true; + } + + private static void assignRandomSources(StructuredGraph graph) { + ValueNode seed = graph.unique(new RandomSeedNode()); + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, false, true, false, false); + Map loopRandomValueCache = new HashMap<>(); + + for (ProfileNode node : getProfileNodes(graph)) { + ValueNode random; + Block block = cfg.blockFor(node); + Loop loop = block.getLoop(); + // Inject LCG + // pseudo-random number generator into the loop + if (loop != null) { + LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode(); + random = loopRandomValueCache.get(loopBegin); + if (random == null) { + PhiNode phi = graph.addWithoutUnique(new ValuePhiNode(seed.stamp(), loopBegin)); + phi.addInput(seed); + // X_{n+1} = a*X_n + c, using glibc-like constants + ValueNode a = ConstantNode.forInt(1103515245, graph); + ValueNode c = ConstantNode.forInt(12345, graph); + ValueNode next = graph.addOrUniqueWithInputs(new AddNode(c, new MulNode(phi, a))); + for (int i = 0; i < loopBegin.getLoopEndCount(); i++) { + phi.addInput(next); + } + random = phi; + loopRandomValueCache.put(loopBegin, random); + } + } else { + // Graal doesn't compile methods with irreducible loops. So all profile nodes that + // are not in a loop are guaranteed to be executed at most once. We feed the seed + // value to such nodes directly. + random = seed; + } + node.setRandom(random); + } + } + + @Override + protected void run(StructuredGraph graph, PhaseContext context) { + if (simpleMethodHeuristic(graph)) { + removeAllProfilingNodes(graph); + return; + } + + assignInlineeInvokeFrequencies(graph); + if (ProfileNode.Options.ProbabilisticProfiling.getValue()) { + assignRandomSources(graph); + } + } + + @Override + public boolean checkContract() { + return false; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java 2016-12-07 13:50:37.777447740 -0800 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2012, 2016, 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.replacements; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK; +import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK_WITH_ORIGINAL_KEY; +import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT_BLOCK; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; + +import java.lang.reflect.Field; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; +import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.extended.UnsafeLoadNode; +import org.graalvm.compiler.word.Pointer; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaKind; + +// JaCoCo Exclude + +/** + * Substitutions for {@code com.sun.crypto.provider.AESCrypt} methods. + */ +@ClassSubstitution(className = "com.sun.crypto.provider.AESCrypt", optional = true) +public class AESCryptSubstitutions { + + static final long kOffset; + static final long lastKeyOffset; + static final Class AESCryptClass; + static final int AES_BLOCK_SIZE; + + static { + try { + // Need to use the system class loader as com.sun.crypto.provider.AESCrypt + // is normally loaded by the extension class loader which is not delegated + // to by the JVMCI class loader. + ClassLoader cl = ClassLoader.getSystemClassLoader(); + AESCryptClass = Class.forName("com.sun.crypto.provider.AESCrypt", true, cl); + kOffset = UnsafeAccess.UNSAFE.objectFieldOffset(AESCryptClass.getDeclaredField("K")); + lastKeyOffset = UnsafeAccess.UNSAFE.objectFieldOffset(AESCryptClass.getDeclaredField("lastKey")); + Field aesBlockSizeField = Class.forName("com.sun.crypto.provider.AESConstants", true, cl).getDeclaredField("AES_BLOCK_SIZE"); + aesBlockSizeField.setAccessible(true); + AES_BLOCK_SIZE = aesBlockSizeField.getInt(null); + } catch (Exception ex) { + throw new GraalError(ex); + } + } + + @MethodSubstitution(isStatic = false) + static void encryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { + crypt(rcvr, in, inOffset, out, outOffset, true, false); + } + + @MethodSubstitution(isStatic = false) + static void implEncryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { + crypt(rcvr, in, inOffset, out, outOffset, true, false); + } + + @MethodSubstitution(isStatic = false) + static void decryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { + crypt(rcvr, in, inOffset, out, outOffset, false, false); + } + + @MethodSubstitution(isStatic = false) + static void implDecryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { + crypt(rcvr, in, inOffset, out, outOffset, false, false); + } + + /** + * Variation for platforms (e.g. SPARC) that need do key expansion in stubs due to compatibility + * issues between Java key expansion and hardware crypto instructions. + */ + @MethodSubstitution(value = "decryptBlock", isStatic = false) + static void decryptBlockWithOriginalKey(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { + crypt(rcvr, in, inOffset, out, outOffset, false, true); + } + + /** + * @see #decryptBlockWithOriginalKey(Object, byte[], int, byte[], int) + */ + @MethodSubstitution(value = "implDecryptBlock", isStatic = false) + static void implDecryptBlockWithOriginalKey(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { + crypt(rcvr, in, inOffset, out, outOffset, false, true); + } + + private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt, boolean withOriginalKey) { + checkArgs(in, inOffset, out, outOffset); + Object realReceiver = PiNode.piCastNonNull(rcvr, AESCryptClass); + Object kObject = UnsafeLoadNode.load(realReceiver, kOffset, JavaKind.Object, LocationIdentity.any()); + Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Int)); + Word inAddr = Word.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset)); + Word outAddr = Word.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset)); + if (encrypt) { + encryptBlockStub(ENCRYPT_BLOCK, inAddr, outAddr, kAddr); + } else { + if (withOriginalKey) { + Object lastKeyObject = UnsafeLoadNode.load(realReceiver, lastKeyOffset, JavaKind.Object, LocationIdentity.any()); + Pointer lastKeyAddr = Word.objectToTrackedPointer(lastKeyObject).add(getArrayBaseOffset(JavaKind.Byte)); + decryptBlockWithOriginalKeyStub(DECRYPT_BLOCK_WITH_ORIGINAL_KEY, inAddr, outAddr, kAddr, lastKeyAddr); + } else { + decryptBlockStub(DECRYPT_BLOCK, inAddr, outAddr, kAddr); + } + } + } + + /** + * Perform null and array bounds checks for arguments to a cipher operation. + */ + static void checkArgs(byte[] in, int inOffset, byte[] out, int outOffset) { + if (probability(VERY_SLOW_PATH_PROBABILITY, inOffset < 0 || in.length - AES_BLOCK_SIZE < inOffset || outOffset < 0 || out.length - AES_BLOCK_SIZE < outOffset)) { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + } + + @NodeIntrinsic(ForeignCallNode.class) + public static native void encryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key); + + @NodeIntrinsic(ForeignCallNode.class) + public static native void decryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key); + + @NodeIntrinsic(ForeignCallNode.class) + public static native void decryptBlockWithOriginalKeyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer originalKey); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AssertionSnippets.java 2016-12-07 13:50:38.041459344 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014, 2016, 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.replacements; + +import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; +import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.StubStartNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.replacements.nodes.AssertionNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.TargetDescription; + +public class AssertionSnippets implements Snippets { + + /** + * This call can only be used with true for the "vmError" parameter, so that it can be + * configured to be a leaf method. + */ + public static final ForeignCallDescriptor ASSERTION_VM_MESSAGE_C = new ForeignCallDescriptor("assertionVmMessageC", void.class, boolean.class, Word.class, long.class, long.class, long.class); + + @Snippet + public static void assertion(boolean value, @ConstantParameter String message) { + if (!value) { + vmMessageC(ASSERTION_VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L); + } + } + + @Snippet + public static void stubAssertion(boolean value, @ConstantParameter String message) { + if (!value) { + vmMessageC(ASSERTION_VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L); + } + } + + @NodeIntrinsic(ForeignCallNode.class) + static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo assertion = snippet(AssertionSnippets.class, "assertion"); + private final SnippetInfo stubAssertion = snippet(AssertionSnippets.class, "stubAssertion"); + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + } + + public void lower(AssertionNode assertionNode, LoweringTool tool) { + StructuredGraph graph = assertionNode.graph(); + Arguments args = new Arguments(graph.start() instanceof StubStartNode ? stubAssertion : assertion, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("value", assertionNode.value()); + args.addConst("message", "failed runtime assertion in snippet/stub: " + assertionNode.message() + " (" + graph.method() + ")"); + + template(args).instantiate(providers.getMetaAccess(), assertionNode, DEFAULT_REPLACER, args); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/BigIntegerSubstitutions.java 2016-12-07 13:50:38.306470992 -0800 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, 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.replacements; + +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayStart; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.hotspot.HotSpotBackend; + +@ClassSubstitution(className = "java.math.BigInteger", optional = true) +public class BigIntegerSubstitutions { + + @MethodSubstitution(isStatic = false) + static int[] multiplyToLen(@SuppressWarnings("unused") Object receiver, int[] x, int xlen, int[] y, int ylen, int[] zIn) { + return multiplyToLenStatic(x, xlen, y, ylen, zIn); + } + + @MethodSubstitution(isStatic = true) + static int[] multiplyToLenStatic(int[] x, int xlen, int[] y, int ylen, int[] zIn) { + int[] zResult = zIn; + int zLen; + if (zResult == null || zResult.length < (xlen + ylen)) { + zLen = xlen + ylen; + zResult = new int[xlen + ylen]; + } else { + zLen = zIn.length; + } + HotSpotBackend.multiplyToLenStub(arrayStart(x), xlen, arrayStart(y), ylen, arrayStart(zResult), zLen); + return zResult; + } + + @MethodSubstitution(isStatic = true) + static int mulAdd(int[] out, int[] in, int offset, int len, int k) { + int[] outNonNull = GraalDirectives.guardingNonNull(out); + int newOffset = outNonNull.length - offset; + return HotSpotBackend.mulAddStub(arrayStart(outNonNull), arrayStart(in), newOffset, len, k); + } + + @MethodSubstitution(isStatic = true) + static int implMulAdd(int[] out, int[] in, int offset, int len, int k) { + int[] outNonNull = GraalDirectives.guardingNonNull(out); + int newOffset = outNonNull.length - offset; + return HotSpotBackend.mulAddStub(arrayStart(outNonNull), arrayStart(in), newOffset, len, k); + } + + @MethodSubstitution(isStatic = true) + static int[] implMontgomeryMultiply(int[] a, int[] b, int[] n, int len, long inv, int[] product) { + HotSpotBackend.implMontgomeryMultiply(arrayStart(a), arrayStart(b), arrayStart(n), len, inv, arrayStart(product)); + return product; + + } + + @MethodSubstitution(isStatic = true) + static int[] implMontgomerySquare(int[] a, int[] n, int len, long inv, int[] product) { + HotSpotBackend.implMontgomerySquare(arrayStart(a), arrayStart(n), len, inv, arrayStart(product)); + return product; + } + + @MethodSubstitution(isStatic = true) + static int[] implSquareToLen(int[] x, int len, int[] z, int zLen) { + HotSpotBackend.implSquareToLen(arrayStart(x), len, arrayStart(z), zLen); + return z; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32Substitutions.java 2016-12-07 13:50:38.572482684 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2012, 2015, 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.replacements; + +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset; + +import java.util.zip.CRC32; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; +import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.JavaKind; + +// JaCoCo Exclude + +/** + * Substitutions for {@link CRC32}. + */ +@ClassSubstitution(CRC32.class) +public class CRC32Substitutions { + + /** + * Gets the address of {@code StubRoutines::x86::_crc_table} in {@code stubRoutines_x86.hpp}. + */ + @Fold + static long crcTableAddress(@InjectedParameter GraalHotSpotVMConfig config) { + return config.crcTableAddress; + } + + @MethodSubstitution + static int update(int crc, int b) { + final long crcTableRawAddress = GraalHotSpotVMConfigNode.crcTableAddress(); + + int c = ~crc; + int index = (b ^ c) & 0xFF; + int offset = index << 2; + int result = Word.unsigned(crcTableRawAddress).readInt(offset); + result = result ^ (c >>> 8); + return ~result; + } + + @MethodSubstitution + static int updateBytes(int crc, byte[] buf, int off, int len) { + Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, arrayBaseOffset(JavaKind.Byte) + off)); + return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len); + } + + /** + * @since 9 + */ + @MethodSubstitution(optional = true) + static int updateBytes0(int crc, byte[] buf, int off, int len) { + Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, arrayBaseOffset(JavaKind.Byte) + off)); + return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len); + } + + @MethodSubstitution + static int updateByteBuffer(int crc, long addr, int off, int len) { + Word bufAddr = Word.unsigned(addr).add(off); + return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len); + } + + /** + * @since 9 + */ + @MethodSubstitution(optional = true) + static int updateByteBuffer0(int crc, long addr, int off, int len) { + Word bufAddr = Word.unsigned(addr).add(off); + return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len); + } + + public static final ForeignCallDescriptor UPDATE_BYTES_CRC32 = new ForeignCallDescriptor("updateBytesCRC32", int.class, int.class, Word.class, int.class); + + @NodeIntrinsic(ForeignCallNode.class) + public static native int updateBytesCRC32(@ConstantNodeParameter ForeignCallDescriptor descriptor, int crc, Word buf, int length); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CallSiteTargetNode.java 2016-12-07 13:50:38.837494333 -0800 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013, 2014, 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.replacements; + +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.nodes.MacroStateSplitNode; + +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@NodeInfo +public final class CallSiteTargetNode extends MacroStateSplitNode implements Canonicalizable, Lowerable { + + public static final NodeClass TYPE = NodeClass.create(CallSiteTargetNode.class); + + public CallSiteTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode receiver) { + super(TYPE, invokeKind, targetMethod, bci, returnStamp, receiver); + } + + private ValueNode getCallSite() { + return arguments.get(0); + } + + public static ConstantNode tryFold(ValueNode callSite, MetaAccessProvider metaAccess, Assumptions assumptions) { + if (callSite != null && callSite.isConstant() && !callSite.isNullConstant()) { + HotSpotObjectConstant c = (HotSpotObjectConstant) callSite.asConstant(); + JavaConstant target = c.getCallSiteTarget(assumptions); + if (target != null) { + return ConstantNode.forConstant(target, metaAccess); + } + } + return null; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + ConstantNode target = tryFold(getCallSite(), tool.getMetaAccess(), graph().getAssumptions()); + if (target != null) { + return target; + } + + return this; + } + + @Override + public void lower(LoweringTool tool) { + ConstantNode target = tryFold(getCallSite(), tool.getMetaAccess(), graph().getAssumptions()); + + if (target != null) { + graph().replaceFixedWithFloating(this, target); + } else { + InvokeNode invoke = createInvoke(); + graph().replaceFixedWithFixed(this, invoke); + invoke.lower(tool); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java 2016-12-07 13:50:39.102505981 -0800 @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2012, 2016, 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.replacements; + +import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT; +import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_KEY; +import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT; +import static org.graalvm.compiler.hotspot.replacements.UnsafeAccess.UNSAFE; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.extended.UnsafeLoadNode; +import org.graalvm.compiler.word.Pointer; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.JavaKind; + +// JaCoCo Exclude + +/** + * Substitutions for {@code com.sun.crypto.provider.CipherBlockChaining} methods. + */ +@ClassSubstitution(className = "com.sun.crypto.provider.CipherBlockChaining", optional = true) +public class CipherBlockChainingSubstitutions { + + private static final long embeddedCipherOffset; + private static final long rOffset; + private static final Class cipherBlockChainingClass; + private static final Class feedbackCipherClass; + static { + try { + // Need to use the system class loader as com.sun.crypto.provider.FeedbackCipher + // is normally loaded by the extension class loader which is not delegated + // to by the JVMCI class loader. + ClassLoader cl = ClassLoader.getSystemClassLoader(); + + feedbackCipherClass = Class.forName("com.sun.crypto.provider.FeedbackCipher", true, cl); + embeddedCipherOffset = UNSAFE.objectFieldOffset(feedbackCipherClass.getDeclaredField("embeddedCipher")); + + cipherBlockChainingClass = Class.forName("com.sun.crypto.provider.CipherBlockChaining", true, cl); + rOffset = UNSAFE.objectFieldOffset(cipherBlockChainingClass.getDeclaredField("r")); + } catch (Exception ex) { + throw new GraalError(ex); + } + } + + @Fold + static Class getAESCryptClass() { + return AESCryptSubstitutions.AESCryptClass; + } + + @MethodSubstitution(isStatic = false) + static int encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); + if (getAESCryptClass().isInstance(embeddedCipher)) { + Object aesCipher = getAESCryptClass().cast(embeddedCipher); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false); + return inLength; + } else { + return encrypt(realReceiver, in, inOffset, inLength, out, outOffset); + } + } + + @MethodSubstitution(isStatic = false, value = "implEncrypt") + static int implEncrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); + if (getAESCryptClass().isInstance(embeddedCipher)) { + Object aesCipher = getAESCryptClass().cast(embeddedCipher); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false); + return inLength; + } else { + return implEncrypt(realReceiver, in, inOffset, inLength, out, outOffset); + } + } + + @MethodSubstitution(isStatic = false) + static int decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); + if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { + Object aesCipher = getAESCryptClass().cast(embeddedCipher); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false); + return inLength; + } else { + return decrypt(realReceiver, in, inOffset, inLength, out, outOffset); + } + } + + @MethodSubstitution(isStatic = false) + static int implDecrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); + if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { + Object aesCipher = getAESCryptClass().cast(embeddedCipher); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false); + return inLength; + } else { + return implDecrypt(realReceiver, in, inOffset, inLength, out, outOffset); + } + } + + /** + * Variation for platforms (e.g. SPARC) that need do key expansion in stubs due to compatibility + * issues between Java key expansion and hardware crypto instructions. + */ + @MethodSubstitution(isStatic = false, value = "decrypt") + static int decryptWithOriginalKey(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); + if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { + Object aesCipher = getAESCryptClass().cast(embeddedCipher); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, true); + return inLength; + } else { + return decryptWithOriginalKey(realReceiver, in, inOffset, inLength, out, outOffset); + } + } + + /** + * @see #decryptWithOriginalKey(Object, byte[], int, int, byte[], int) + */ + @MethodSubstitution(isStatic = false, value = "implDecrypt") + static int implDecryptWithOriginalKey(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); + if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { + Object aesCipher = getAESCryptClass().cast(embeddedCipher); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, true); + return inLength; + } else { + return implDecryptWithOriginalKey(realReceiver, in, inOffset, inLength, out, outOffset); + } + } + + private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt, boolean withOriginalKey) { + AESCryptSubstitutions.checkArgs(in, inOffset, out, outOffset); + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object aesCipher = getAESCryptClass().cast(embeddedCipher); + Object kObject = UnsafeLoadNode.load(aesCipher, AESCryptSubstitutions.kOffset, JavaKind.Object, LocationIdentity.any()); + Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, JavaKind.Object, LocationIdentity.any()); + Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Int)); + Pointer rAddr = Word.objectToTrackedPointer(rObject).add(getArrayBaseOffset(JavaKind.Byte)); + Word inAddr = Word.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset)); + Word outAddr = Word.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset)); + if (encrypt) { + encryptAESCryptStub(ENCRYPT, inAddr, outAddr, kAddr, rAddr, inLength); + } else { + if (withOriginalKey) { + Object lastKeyObject = UnsafeLoadNode.load(aesCipher, AESCryptSubstitutions.lastKeyOffset, JavaKind.Object, LocationIdentity.any()); + Pointer lastKeyAddr = Word.objectToTrackedPointer(lastKeyObject).add(getArrayBaseOffset(JavaKind.Byte)); + decryptAESCryptWithOriginalKeyStub(DECRYPT_WITH_ORIGINAL_KEY, inAddr, outAddr, kAddr, rAddr, inLength, lastKeyAddr); + } else { + decryptAESCryptStub(DECRYPT, inAddr, outAddr, kAddr, rAddr, inLength); + } + } + } + + @NodeIntrinsic(ForeignCallNode.class) + public static native void encryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength); + + @NodeIntrinsic(ForeignCallNode.class) + public static native void decryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength); + + @NodeIntrinsic(ForeignCallNode.class) + public static native void decryptAESCryptWithOriginalKeyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength, Pointer originalKey); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java 2016-12-07 13:50:39.367517629 -0800 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2014, 2016, 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.replacements; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FloatingGuardedNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.ConvertNode; +import org.graalvm.compiler.nodes.extended.GetClassNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.extended.LoadHubNode; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Read {@code Class::_klass} to get the hub for a {@link java.lang.Class}. This node mostly exists + * to replace {@code _klass._java_mirror._klass} with {@code _klass}. The constant folding could be + * handled by + * {@link ReadNode#canonicalizeRead(ValueNode, AddressNode, LocationIdentity, CanonicalizerTool)}. + */ +@NodeInfo(cycles = CYCLES_4, size = SIZE_1) +public final class ClassGetHubNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, ConvertNode { + public static final NodeClass TYPE = NodeClass.create(ClassGetHubNode.class); + @Input protected ValueNode clazz; + + public ClassGetHubNode(ValueNode clazz) { + this(clazz, null); + } + + public ClassGetHubNode(ValueNode clazz, ValueNode guard) { + super(TYPE, KlassPointerStamp.klass(), (GuardingNode) guard); + this.clazz = clazz; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (tool.allUsagesAvailable() && hasNoUsages()) { + return null; + } else { + if (clazz.isConstant()) { + MetaAccessProvider metaAccess = tool.getMetaAccess(); + if (metaAccess != null) { + ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(clazz.asJavaConstant()); + if (exactType.isPrimitive()) { + return ConstantNode.forConstant(stamp(), JavaConstant.NULL_POINTER, metaAccess); + } else { + return ConstantNode.forConstant(stamp(), tool.getConstantReflection().asObjectHub(exactType), metaAccess); + } + } + } + if (clazz instanceof GetClassNode) { + GetClassNode getClass = (GetClassNode) clazz; + return new LoadHubNode(KlassPointerStamp.klassNonNull(), getClass.getObject()); + } + if (clazz instanceof HubGetClassNode) { + // replace _klass._java_mirror._klass -> _klass + return ((HubGetClassNode) clazz).getHub(); + } + return this; + } + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + @NodeIntrinsic + public static native KlassPointer readClass(Class clazz); + + @NodeIntrinsic + public static native KlassPointer readClass(Class clazz, GuardingNode guard); + + @Override + public ValueNode getValue() { + return clazz; + } + + @Override + public Constant convert(Constant c, ConstantReflectionProvider constantReflection) { + ResolvedJavaType exactType = constantReflection.asJavaType(c); + if (exactType.isPrimitive()) { + return JavaConstant.NULL_POINTER; + } else { + return constantReflection.asObjectHub(exactType); + } + } + + @Override + public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) { + assert !c.equals(JavaConstant.NULL_POINTER); + ResolvedJavaType objectType = constantReflection.asJavaType(c); + return constantReflection.asJavaClass(objectType); + } + + @Override + public boolean isLossless() { + return false; + } + + @Override + public boolean preservesOrder(Condition op, Constant value, ConstantReflectionProvider constantReflection) { + assert op == Condition.EQ || op == Condition.NE; + ResolvedJavaType exactType = constantReflection.asJavaType(value); + return !exactType.isPrimitive(); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/EncodedSymbolConstant.java 2016-12-07 13:50:39.631529233 -0800 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016, 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.replacements; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.nio.ByteBuffer; + +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.core.common.type.DataPointerConstant; + +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.Constant; + +/** + * Represents an encoded representation of a constant. + */ +public final class EncodedSymbolConstant extends DataPointerConstant { + private final Constant constant; + private byte[] bytes; + + public EncodedSymbolConstant(Constant constant) { + super(1); + this.constant = constant; + } + + @Override + public int getSerializedSize() { + return getEncodedConstant().length; + } + + @Override + public void serialize(ByteBuffer buffer) { + buffer.put(getEncodedConstant()); + } + + /** + * Converts a string to a byte array with modified UTF-8 encoding. The first two bytes of the + * byte array store the length of the string in bytes. + * + * @param s a java.lang.String in UTF-16 + */ + private static byte[] toUTF8String(String s) { + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream()) { + DataOutputStream stream = new DataOutputStream(bytes); + stream.writeUTF(s); + return bytes.toByteArray(); + } catch (Exception e) { + throw new PermanentBailoutException(e, "String conversion failed: %s", s); + } + } + + private static byte[] encodeConstant(Constant constant) { + assert constant != null; + if (constant instanceof HotSpotObjectConstant) { + return toUTF8String(((HotSpotObjectConstant) constant).asObject(String.class)); + } else if (constant instanceof HotSpotMetaspaceConstant) { + HotSpotMetaspaceConstant metaspaceConstant = ((HotSpotMetaspaceConstant) constant); + HotSpotResolvedObjectType klass = metaspaceConstant.asResolvedJavaType(); + if (klass != null) { + return toUTF8String(klass.getName()); + } + HotSpotResolvedJavaMethod method = metaspaceConstant.asResolvedJavaMethod(); + if (method != null) { + byte[] methodName = toUTF8String(method.getName()); + byte[] signature = toUTF8String(method.getSignature().toMethodDescriptor()); + byte[] result = new byte[methodName.length + signature.length]; + int resultPos = 0; + System.arraycopy(methodName, 0, result, resultPos, methodName.length); + resultPos += methodName.length; + System.arraycopy(signature, 0, result, resultPos, signature.length); + resultPos += signature.length; + assert resultPos == result.length; + return result; + } + + } + throw new PermanentBailoutException("Encoding of constant %s failed", constant); + } + + public byte[] getEncodedConstant() { + if (bytes == null) { + bytes = encodeConstant(constant); + } + return bytes; + } + + @Override + public String toValueString() { + return "encoded symbol\"" + constant.toValueString() + "\""; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java 2016-12-07 13:50:39.901541101 -0800 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, 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.replacements; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.IDENTITY_HASHCODE; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockMaskInPlace; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.identityHashCode; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.identityHashCodeShift; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadWordFromObject; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.markOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.uninitializedIdentityHashCodeValue; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.unlockedMask; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.TargetDescription; + +public class HashCodeSnippets implements Snippets { + + @Snippet + public static int identityHashCodeSnippet(final Object thisObj) { + if (probability(NOT_FREQUENT_PROBABILITY, thisObj == null)) { + return 0; + } + return computeHashCode(thisObj); + } + + static int computeHashCode(final Object x) { + Word mark = loadWordFromObject(x, markOffset(INJECTED_VMCONFIG)); + + // this code is independent from biased locking (although it does not look that way) + final Word biasedLock = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)); + if (probability(FAST_PATH_PROBABILITY, biasedLock.equal(Word.unsigned(unlockedMask(INJECTED_VMCONFIG))))) { + int hash = (int) mark.unsignedShiftRight(identityHashCodeShift(INJECTED_VMCONFIG)).rawValue(); + if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue(INJECTED_VMCONFIG))) { + return hash; + } + } + return identityHashCode(IDENTITY_HASHCODE, x); + } + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo identityHashCodeSnippet = snippet(HashCodeSnippets.class, "identityHashCodeSnippet", HotSpotReplacementsUtil.MARK_WORD_LOCATION); + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + } + + public void lower(IdentityHashCodeNode node, LoweringTool tool) { + StructuredGraph graph = node.graph(); + Arguments args = new Arguments(identityHashCodeSnippet, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("thisObj", node.object); + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args); + } + + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotClassSubstitutions.java 2016-12-07 13:50:40.166552749 -0800 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2012, 2014, 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.replacements; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.ARRAY_KLASS_COMPONENT_MIRROR; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_ACCESS_FLAGS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_MODIFIER_FLAGS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_SUPER_KLASS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayKlassComponentMirrorOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassAccessFlagsOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassIsArray; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassModifierFlagsOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassSuperKlassOffset; + +import java.lang.reflect.Modifier; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodes.PiNode; + +// JaCoCo Exclude + +/** + * Substitutions for {@link java.lang.Class} methods. + */ +@ClassSubstitution(Class.class) +public class HotSpotClassSubstitutions { + + @MethodSubstitution(isStatic = false) + public static int getModifiers(final Class thisObj) { + KlassPointer klass = ClassGetHubNode.readClass(thisObj); + if (klass.isNull()) { + // Class for primitive type + return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; + } else { + return klass.readInt(klassModifierFlagsOffset(INJECTED_VMCONFIG), KLASS_MODIFIER_FLAGS_LOCATION); + } + } + + @MethodSubstitution(isStatic = false) + public static boolean isInterface(final Class thisObj) { + KlassPointer klass = ClassGetHubNode.readClass(thisObj); + if (klass.isNull()) { + // Class for primitive type + return false; + } else { + int accessFlags = klass.readInt(klassAccessFlagsOffset(INJECTED_VMCONFIG), KLASS_ACCESS_FLAGS_LOCATION); + return (accessFlags & Modifier.INTERFACE) != 0; + } + } + + @MethodSubstitution(isStatic = false) + public static boolean isArray(final Class thisObj) { + KlassPointer klass = ClassGetHubNode.readClass(thisObj); + if (klass.isNull()) { + // Class for primitive type + return false; + } else { + return klassIsArray(klass); + } + } + + @MethodSubstitution(isStatic = false) + public static boolean isPrimitive(final Class thisObj) { + KlassPointer klass = ClassGetHubNode.readClass(thisObj); + return klass.isNull(); + } + + @MethodSubstitution(isStatic = false) + public static Class getSuperclass(final Class thisObj) { + KlassPointer klass = ClassGetHubNode.readClass(thisObj); + if (!klass.isNull()) { + int accessFlags = klass.readInt(klassAccessFlagsOffset(INJECTED_VMCONFIG), KLASS_ACCESS_FLAGS_LOCATION); + if ((accessFlags & Modifier.INTERFACE) == 0) { + if (klassIsArray(klass)) { + return Object.class; + } else { + KlassPointer superKlass = klass.readKlassPointer(klassSuperKlassOffset(INJECTED_VMCONFIG), KLASS_SUPER_KLASS_LOCATION); + if (superKlass.isNull()) { + return null; + } else { + return readJavaMirror(superKlass); + } + } + } + } else { + // Class for primitive type + } + return null; + } + + public static Class readJavaMirror(KlassPointer klass) { + return PiNode.asNonNullClass(HubGetClassNode.readClass(klass)); + } + + @MethodSubstitution(isStatic = false) + public static Class getComponentType(final Class thisObj) { + KlassPointer klass = ClassGetHubNode.readClass(thisObj); + if (!klass.isNull()) { + if (klassIsArray(klass)) { + return PiNode.asNonNullClass(klass.readObject(arrayKlassComponentMirrorOffset(INJECTED_VMCONFIG), ARRAY_KLASS_COMPONENT_MIRROR)); + } + } else { + // Class for primitive type + } + return null; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java 2016-12-07 13:50:40.431564397 -0800 @@ -0,0 +1,954 @@ +/* + * Copyright (c) 2012, 2016, 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.replacements; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.VERIFY_OOP; +import static org.graalvm.compiler.hotspot.replacements.UnsafeAccess.UNSAFE; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.SuppressFBWarnings; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.TypeReference; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.nodes.CompressionNode; +import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; +import org.graalvm.compiler.hotspot.nodes.SnippetAnchorNode; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodes.CanonicalizableLocation; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.extended.LoadHubNode; +import org.graalvm.compiler.nodes.extended.StoreHubNode; +import org.graalvm.compiler.nodes.extended.UnsafeLoadNode; +import org.graalvm.compiler.nodes.memory.Access; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.replacements.ReplacementsUtil; +import org.graalvm.compiler.replacements.nodes.ReadRegisterNode; +import org.graalvm.compiler.replacements.nodes.WriteRegisterNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.Assumptions.AssumptionResult; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaType; + +//JaCoCo Exclude + +/** + * A collection of methods used in HotSpot snippets, substitutions and stubs. + */ +public class HotSpotReplacementsUtil { + + abstract static class HotSpotOptimizingLocationIdentity extends NamedLocationIdentity implements CanonicalizableLocation { + + HotSpotOptimizingLocationIdentity(String name) { + super(name, true); + } + + @Override + public abstract ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool); + + protected ValueNode findReadHub(ValueNode object) { + ValueNode base = object; + if (base instanceof CompressionNode) { + base = ((CompressionNode) base).getValue(); + } + if (base instanceof Access) { + Access access = (Access) base; + if (access.getLocationIdentity().equals(HUB_LOCATION) || access.getLocationIdentity().equals(COMPRESSED_HUB_LOCATION)) { + AddressNode address = access.getAddress(); + if (address instanceof OffsetAddressNode) { + OffsetAddressNode offset = (OffsetAddressNode) address; + return offset.getBase(); + } + } + } else if (base instanceof LoadHubNode) { + LoadHubNode loadhub = (LoadHubNode) base; + return loadhub.getValue(); + } + return null; + } + + /** + * Fold reads that convert from Class -> Hub -> Class or vice versa. + * + * @param read + * @param object + * @param otherLocation + * @return an earlier read or the original {@code read} + */ + protected static ValueNode foldIndirection(ValueNode read, ValueNode object, LocationIdentity otherLocation) { + if (object instanceof Access) { + Access access = (Access) object; + if (access.getLocationIdentity().equals(otherLocation)) { + AddressNode address = access.getAddress(); + if (address instanceof OffsetAddressNode) { + OffsetAddressNode offset = (OffsetAddressNode) address; + assert offset.getBase().stamp().isCompatible(read.stamp()); + return offset.getBase(); + } + } + } + return read; + } + } + + public static HotSpotJVMCIRuntimeProvider runtime() { + return HotSpotJVMCIRuntime.runtime(); + } + + @Fold + public static GraalHotSpotVMConfig config(@InjectedParameter GraalHotSpotVMConfig config) { + assert config != null; + return config; + } + + @Fold + public static boolean useTLAB(@InjectedParameter GraalHotSpotVMConfig config) { + return config.useTLAB; + } + + @Fold + public static boolean verifyOops(@InjectedParameter GraalHotSpotVMConfig config) { + return config.verifyOops; + } + + public static final LocationIdentity EXCEPTION_OOP_LOCATION = NamedLocationIdentity.mutable("ExceptionOop"); + + /** + * @see GraalHotSpotVMConfig#threadExceptionOopOffset + */ + @Fold + public static int threadExceptionOopOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.threadExceptionOopOffset; + } + + public static final LocationIdentity EXCEPTION_PC_LOCATION = NamedLocationIdentity.mutable("ExceptionPc"); + + @Fold + public static int threadExceptionPcOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.threadExceptionPcOffset; + } + + public static final LocationIdentity TLAB_TOP_LOCATION = NamedLocationIdentity.mutable("TlabTop"); + + @Fold + public static int threadTlabTopOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.threadTlabTopOffset(); + } + + public static final LocationIdentity TLAB_END_LOCATION = NamedLocationIdentity.mutable("TlabEnd"); + + @Fold + static int threadTlabEndOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.threadTlabEndOffset(); + } + + public static final LocationIdentity TLAB_START_LOCATION = NamedLocationIdentity.mutable("TlabStart"); + + @Fold + static int threadTlabStartOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.threadTlabStartOffset(); + } + + public static final LocationIdentity PENDING_EXCEPTION_LOCATION = NamedLocationIdentity.mutable("PendingException"); + + /** + * @see GraalHotSpotVMConfig#pendingExceptionOffset + */ + @Fold + static int threadPendingExceptionOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.pendingExceptionOffset; + } + + public static final LocationIdentity PENDING_DEOPTIMIZATION_LOCATION = NamedLocationIdentity.mutable("PendingDeoptimization"); + + /** + * @see GraalHotSpotVMConfig#pendingDeoptimizationOffset + */ + @Fold + static int threadPendingDeoptimizationOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.pendingDeoptimizationOffset; + } + + public static final LocationIdentity OBJECT_RESULT_LOCATION = NamedLocationIdentity.mutable("ObjectResult"); + + @Fold + static int objectResultOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.threadObjectResultOffset; + } + + /** + * @see GraalHotSpotVMConfig#threadExceptionOopOffset + */ + public static Object readExceptionOop(Word thread) { + return thread.readObject(threadExceptionOopOffset(INJECTED_VMCONFIG), EXCEPTION_OOP_LOCATION); + } + + public static Word readExceptionPc(Word thread) { + return thread.readWord(threadExceptionPcOffset(INJECTED_VMCONFIG), EXCEPTION_PC_LOCATION); + } + + /** + * @see GraalHotSpotVMConfig#threadExceptionOopOffset + */ + public static void writeExceptionOop(Word thread, Object value) { + thread.writeObject(threadExceptionOopOffset(INJECTED_VMCONFIG), value, EXCEPTION_OOP_LOCATION); + } + + public static void writeExceptionPc(Word thread, Word value) { + thread.writeWord(threadExceptionPcOffset(INJECTED_VMCONFIG), value, EXCEPTION_PC_LOCATION); + } + + public static Word readTlabTop(Word thread) { + return thread.readWord(threadTlabTopOffset(INJECTED_VMCONFIG), TLAB_TOP_LOCATION); + } + + public static Word readTlabEnd(Word thread) { + return thread.readWord(threadTlabEndOffset(INJECTED_VMCONFIG), TLAB_END_LOCATION); + } + + public static Word readTlabStart(Word thread) { + return thread.readWord(threadTlabStartOffset(INJECTED_VMCONFIG), TLAB_START_LOCATION); + } + + public static void writeTlabTop(Word thread, Word top) { + thread.writeWord(threadTlabTopOffset(INJECTED_VMCONFIG), top, TLAB_TOP_LOCATION); + } + + @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected") + public static void initializeTlab(Word thread, Word start, Word end) { + thread.writeWord(threadTlabStartOffset(INJECTED_VMCONFIG), start, TLAB_START_LOCATION); + thread.writeWord(threadTlabTopOffset(INJECTED_VMCONFIG), start, TLAB_TOP_LOCATION); + thread.writeWord(threadTlabEndOffset(INJECTED_VMCONFIG), end, TLAB_END_LOCATION); + } + + /** + * Clears the pending exception for the given thread. + * + * @return the pending exception, or null if there was none + */ + @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected") + public static Object clearPendingException(Word thread) { + Object result = thread.readObject(threadPendingExceptionOffset(INJECTED_VMCONFIG), PENDING_EXCEPTION_LOCATION); + thread.writeObject(threadPendingExceptionOffset(INJECTED_VMCONFIG), null, PENDING_EXCEPTION_LOCATION); + return result; + } + + /** + * Reads the pending deoptimization value for the given thread. + * + * @return {@code true} if there was a pending deoptimization + */ + public static int readPendingDeoptimization(Word thread) { + return thread.readInt(threadPendingDeoptimizationOffset(INJECTED_VMCONFIG), PENDING_DEOPTIMIZATION_LOCATION); + } + + /** + * Writes the pending deoptimization value for the given thread. + */ + public static void writePendingDeoptimization(Word thread, int value) { + thread.writeInt(threadPendingDeoptimizationOffset(INJECTED_VMCONFIG), value, PENDING_DEOPTIMIZATION_LOCATION); + } + + /** + * Gets and clears the object result from a runtime call stored in a thread local. + * + * @return the object that was in the thread local + */ + public static Object getAndClearObjectResult(Word thread) { + Object result = thread.readObject(objectResultOffset(INJECTED_VMCONFIG), OBJECT_RESULT_LOCATION); + thread.writeObject(objectResultOffset(INJECTED_VMCONFIG), null, OBJECT_RESULT_LOCATION); + return result; + } + + public static final LocationIdentity JAVA_THREAD_THREAD_OBJECT_LOCATION = NamedLocationIdentity.mutable("JavaThread::_threadObj"); + + @Fold + public static int threadObjectOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.threadObjectOffset; + } + + public static final LocationIdentity JAVA_THREAD_OSTHREAD_LOCATION = NamedLocationIdentity.mutable("JavaThread::_osthread"); + + @Fold + public static int osThreadOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.osThreadOffset; + } + + @Fold + public static int osThreadInterruptedOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.osThreadInterruptedOffset; + } + + @Fold + public static JavaKind getWordKind() { + return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind; + } + + @Fold + public static int wordSize() { + return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordSize; + } + + @Fold + public static int pageSize() { + return UNSAFE.pageSize(); + } + + @Fold + public static int heapWordSize(@InjectedParameter GraalHotSpotVMConfig config) { + return config.heapWordSize; + } + + public static final LocationIdentity PROTOTYPE_MARK_WORD_LOCATION = NamedLocationIdentity.mutable("PrototypeMarkWord"); + + @Fold + public static int prototypeMarkWordOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.prototypeMarkWordOffset; + } + + @Fold + public static long arrayPrototypeMarkWord(@InjectedParameter GraalHotSpotVMConfig config) { + return config.arrayPrototypeMarkWord(); + } + + public static final LocationIdentity KLASS_ACCESS_FLAGS_LOCATION = NamedLocationIdentity.immutable("Klass::_access_flags"); + + @Fold + public static int klassAccessFlagsOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.klassAccessFlagsOffset; + } + + @Fold + public static int jvmAccWrittenFlags(@InjectedParameter GraalHotSpotVMConfig config) { + return config.jvmAccWrittenFlags; + } + + public static final LocationIdentity KLASS_LAYOUT_HELPER_LOCATION = new HotSpotOptimizingLocationIdentity("Klass::_layout_helper") { + @Override + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + ValueNode javaObject = findReadHub(object); + if (javaObject != null) { + if (javaObject.stamp() instanceof ObjectStamp) { + ObjectStamp stamp = (ObjectStamp) javaObject.stamp(); + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) stamp.javaType(tool.getMetaAccess()); + if (type.isArray() && !type.getComponentType().isPrimitive()) { + int layout = type.layoutHelper(); + return ConstantNode.forInt(layout); + } + } + } + return read; + } + }; + + @Fold + public static int klassLayoutHelperOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.klassLayoutHelperOffset; + } + + public static int readLayoutHelper(KlassPointer hub) { + // return hub.readInt(klassLayoutHelperOffset(), KLASS_LAYOUT_HELPER_LOCATION); + GuardingNode anchorNode = SnippetAnchorNode.anchor(); + return loadKlassLayoutHelperIntrinsic(hub, anchorNode); + } + + @NodeIntrinsic(value = KlassLayoutHelperNode.class) + public static native int loadKlassLayoutHelperIntrinsic(KlassPointer object, GuardingNode anchor); + + @NodeIntrinsic(value = KlassLayoutHelperNode.class) + public static native int loadKlassLayoutHelperIntrinsic(KlassPointer object); + + /** + * Checks if class {@code klass} is an array. + * + * See: Klass::layout_helper_is_array + * + * @param klass the class to be checked + * @return true if klass is an array, false otherwise + */ + public static boolean klassIsArray(KlassPointer klass) { + /* + * The less-than check only works if both values are ints. We use local variables to make + * sure these are still ints and haven't changed. + */ + final int layoutHelper = readLayoutHelper(klass); + final int layoutHelperNeutralValue = config(INJECTED_VMCONFIG).klassLayoutHelperNeutralValue; + return (layoutHelper < layoutHelperNeutralValue); + } + + public static final LocationIdentity ARRAY_KLASS_COMPONENT_MIRROR = NamedLocationIdentity.immutable("ArrayKlass::_component_mirror"); + + @Fold + public static int arrayKlassComponentMirrorOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop"); + } + + public static final LocationIdentity KLASS_SUPER_KLASS_LOCATION = NamedLocationIdentity.immutable("Klass::_super"); + + @Fold + public static int klassSuperKlassOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.klassSuperKlassOffset; + } + + public static final LocationIdentity MARK_WORD_LOCATION = NamedLocationIdentity.mutable("MarkWord"); + + @Fold + public static int markOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.markOffset; + } + + public static final LocationIdentity HUB_WRITE_LOCATION = NamedLocationIdentity.mutable("Hub:write"); + + public static final LocationIdentity HUB_LOCATION = new HotSpotOptimizingLocationIdentity("Hub") { + @Override + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + TypeReference constantType = StampTool.typeReferenceOrNull(object); + if (constantType != null && constantType.isExact()) { + return ConstantNode.forConstant(read.stamp(), tool.getConstantReflection().asObjectHub(constantType.getType()), tool.getMetaAccess()); + } + return read; + } + }; + + public static final LocationIdentity COMPRESSED_HUB_LOCATION = new HotSpotOptimizingLocationIdentity("CompressedHub") { + @Override + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + TypeReference constantType = StampTool.typeReferenceOrNull(object); + if (constantType != null && constantType.isExact()) { + return ConstantNode.forConstant(read.stamp(), ((HotSpotMetaspaceConstant) tool.getConstantReflection().asObjectHub(constantType.getType())).compress(), tool.getMetaAccess()); + } + return read; + } + }; + + @Fold + static int hubOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.hubOffset; + } + + public static void initializeObjectHeader(Word memory, Word markWord, KlassPointer hub) { + memory.writeWord(markOffset(INJECTED_VMCONFIG), markWord, MARK_WORD_LOCATION); + StoreHubNode.write(memory, hub); + } + + @Fold + public static int unlockedMask(@InjectedParameter GraalHotSpotVMConfig config) { + return config.unlockedMask; + } + + /** + * Mask for a biasable, locked or unlocked mark word. + * + *

    +     * +----------------------------------+-+-+
    +     * |                                 1|1|1|
    +     * +----------------------------------+-+-+
    +     * 
    + * + */ + @Fold + public static int biasedLockMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) { + return config.biasedLockMaskInPlace; + } + + @Fold + public static int epochMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) { + return config.epochMaskInPlace; + } + + /** + * Pattern for a biasable, unlocked mark word. + * + *
    +     * +----------------------------------+-+-+
    +     * |                                 1|0|1|
    +     * +----------------------------------+-+-+
    +     * 
    + * + */ + @Fold + public static int biasedLockPattern(@InjectedParameter GraalHotSpotVMConfig config) { + return config.biasedLockPattern; + } + + @Fold + public static int ageMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) { + return config.ageMaskInPlace; + } + + @Fold + public static int metaspaceArrayLengthOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.metaspaceArrayLengthOffset; + } + + @Fold + public static int metaspaceArrayBaseOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.metaspaceArrayBaseOffset; + } + + @Fold + public static int arrayLengthOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.arrayOopDescLengthOffset(); + } + + @Fold + public static int arrayBaseOffset(JavaKind elementKind) { + return getArrayBaseOffset(elementKind); + } + + @Fold + public static int arrayIndexScale(JavaKind elementKind) { + return getArrayIndexScale(elementKind); + } + + public static Word arrayStart(int[] a) { + return Word.unsigned(ComputeObjectAddressNode.get(a, getArrayBaseOffset(JavaKind.Int))); + } + + @Fold + public static int instanceHeaderSize(@InjectedParameter GraalHotSpotVMConfig config) { + return config.useCompressedClassPointers ? (2 * wordSize()) - 4 : 2 * wordSize(); + } + + @Fold + public static byte dirtyCardValue(@InjectedParameter GraalHotSpotVMConfig config) { + return config.dirtyCardValue; + } + + @Fold + public static byte g1YoungCardValue(@InjectedParameter GraalHotSpotVMConfig config) { + return config.g1YoungCardValue; + } + + @Fold + public static int cardTableShift(@InjectedParameter GraalHotSpotVMConfig config) { + return config.cardtableShift; + } + + @Fold + public static long cardTableStart(@InjectedParameter GraalHotSpotVMConfig config) { + return config.cardtableStartAddress; + } + + @Fold + public static int g1CardQueueIndexOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.g1CardQueueIndexOffset(); + } + + @Fold + public static int g1CardQueueBufferOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.g1CardQueueBufferOffset(); + } + + @Fold + public static int logOfHeapRegionGrainBytes(@InjectedParameter GraalHotSpotVMConfig config) { + return config.logOfHRGrainBytes; + } + + @Fold + public static int g1SATBQueueMarkingOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.g1SATBQueueMarkingOffset(); + } + + @Fold + public static int g1SATBQueueIndexOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.g1SATBQueueIndexOffset(); + } + + @Fold + public static int g1SATBQueueBufferOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.g1SATBQueueBufferOffset(); + } + + public static final LocationIdentity KLASS_SUPER_CHECK_OFFSET_LOCATION = NamedLocationIdentity.immutable("Klass::_super_check_offset"); + + @Fold + public static int superCheckOffsetOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.superCheckOffsetOffset; + } + + public static final LocationIdentity SECONDARY_SUPER_CACHE_LOCATION = NamedLocationIdentity.mutable("SecondarySuperCache"); + + @Fold + public static int secondarySuperCacheOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.secondarySuperCacheOffset; + } + + public static final LocationIdentity SECONDARY_SUPERS_LOCATION = NamedLocationIdentity.immutable("SecondarySupers"); + + @Fold + public static int secondarySupersOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.secondarySupersOffset; + } + + public static final LocationIdentity DISPLACED_MARK_WORD_LOCATION = NamedLocationIdentity.mutable("DisplacedMarkWord"); + + @Fold + public static int lockDisplacedMarkOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.basicLockDisplacedHeaderOffset; + } + + @Fold + public static boolean useBiasedLocking(@InjectedParameter GraalHotSpotVMConfig config) { + return config.useBiasedLocking; + } + + @Fold + public static boolean useDeferredInitBarriers(@InjectedParameter GraalHotSpotVMConfig config) { + return config.useDeferredInitBarriers; + } + + @Fold + public static boolean useG1GC(@InjectedParameter GraalHotSpotVMConfig config) { + return config.useG1GC; + } + + @Fold + public static boolean useCompressedOops(@InjectedParameter GraalHotSpotVMConfig config) { + return config.useCompressedOops; + } + + @Fold + static int uninitializedIdentityHashCodeValue(@InjectedParameter GraalHotSpotVMConfig config) { + return config.uninitializedIdentityHashCodeValue; + } + + @Fold + static int identityHashCodeShift(@InjectedParameter GraalHotSpotVMConfig config) { + return config.identityHashCodeShift; + } + + /** + * Loads the hub of an object (without null checking it first). + */ + public static KlassPointer loadHub(Object object) { + return loadHubIntrinsic(object); + } + + public static Object verifyOop(Object object) { + if (verifyOops(INJECTED_VMCONFIG)) { + verifyOopStub(VERIFY_OOP, object); + } + return object; + } + + @NodeIntrinsic(ForeignCallNode.class) + private static native Object verifyOopStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object); + + public static Word loadWordFromObject(Object object, int offset) { + ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject"); + return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.any()); + } + + public static Word loadWordFromObject(Object object, int offset, LocationIdentity identity) { + ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject"); + return loadWordFromObjectIntrinsic(object, offset, getWordKind(), identity); + } + + public static KlassPointer loadKlassFromObject(Object object, int offset, LocationIdentity identity) { + ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject"); + return loadKlassFromObjectIntrinsic(object, offset, getWordKind(), identity); + } + + /** + * Reads the value of a given register. + * + * @param register a register which must not be available to the register allocator + * @return the value of {@code register} as a word + */ + public static Word registerAsWord(@ConstantNodeParameter Register register) { + return registerAsWord(register, true, false); + } + + @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true) + public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming); + + @NodeIntrinsic(value = WriteRegisterNode.class, setStampFromReturnType = true) + public static native void writeRegisterAsWord(@ConstantNodeParameter Register register, Word value); + + @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) + private static native Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter JavaKind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity); + + @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) + private static native KlassPointer loadKlassFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter JavaKind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity); + + @NodeIntrinsic(value = LoadHubNode.class) + public static native KlassPointer loadHubIntrinsic(Object object); + + @Fold + public static int log2WordSize() { + return CodeUtil.log2(wordSize()); + } + + public static final LocationIdentity CLASS_STATE_LOCATION = NamedLocationIdentity.mutable("ClassState"); + + @Fold + public static int instanceKlassInitStateOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.instanceKlassInitStateOffset; + } + + @Fold + public static int instanceKlassStateFullyInitialized(@InjectedParameter GraalHotSpotVMConfig config) { + return config.instanceKlassStateFullyInitialized; + } + + /** + * + * @param hub the hub of an InstanceKlass + * @return true is the InstanceKlass represented by hub is fully initialized + */ + public static boolean isInstanceKlassFullyInitialized(KlassPointer hub) { + return readInstanceKlassState(hub) == instanceKlassStateFullyInitialized(INJECTED_VMCONFIG); + } + + private static byte readInstanceKlassState(KlassPointer hub) { + return hub.readByte(instanceKlassInitStateOffset(INJECTED_VMCONFIG), CLASS_STATE_LOCATION); + } + + public static final LocationIdentity KLASS_MODIFIER_FLAGS_LOCATION = NamedLocationIdentity.immutable("Klass::_modifier_flags"); + + @Fold + public static int klassModifierFlagsOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.klassModifierFlagsOffset; + } + + public static final LocationIdentity CLASS_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("Class._klass") { + @Override + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + return foldIndirection(read, object, CLASS_MIRROR_LOCATION); + } + }; + + @Fold + public static int klassOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.klassOffset; + } + + public static final LocationIdentity CLASS_ARRAY_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("Class._array_klass") { + @Override + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + return foldIndirection(read, object, ARRAY_KLASS_COMPONENT_MIRROR); + } + }; + + @Fold + public static int arrayKlassOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.arrayKlassOffset; + } + + public static final LocationIdentity CLASS_MIRROR_LOCATION = NamedLocationIdentity.immutable("Klass::_java_mirror"); + + public static final LocationIdentity HEAP_TOP_LOCATION = NamedLocationIdentity.mutable("HeapTop"); + + @Fold + public static long heapTopAddress(@InjectedParameter GraalHotSpotVMConfig config) { + return config.heapTopAddress; + } + + public static final LocationIdentity HEAP_END_LOCATION = NamedLocationIdentity.mutable("HeapEnd"); + + @Fold + public static long heapEndAddress(@InjectedParameter GraalHotSpotVMConfig config) { + return config.heapEndAddress; + } + + @Fold + public static long tlabIntArrayMarkWord(@InjectedParameter GraalHotSpotVMConfig config) { + return config.tlabIntArrayMarkWord(); + } + + @Fold + public static boolean inlineContiguousAllocationSupported(@InjectedParameter GraalHotSpotVMConfig config) { + return config.inlineContiguousAllocationSupported; + } + + @Fold + public static int tlabAlignmentReserveInHeapWords(@InjectedParameter GraalHotSpotVMConfig config) { + return config.tlabAlignmentReserve; + } + + public static final LocationIdentity TLAB_SIZE_LOCATION = NamedLocationIdentity.mutable("TlabSize"); + + @Fold + public static int threadTlabSizeOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.threadTlabSizeOffset(); + } + + public static final LocationIdentity TLAB_THREAD_ALLOCATED_BYTES_LOCATION = NamedLocationIdentity.mutable("TlabThreadAllocatedBytes"); + + @Fold + public static int threadAllocatedBytesOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.threadAllocatedBytesOffset; + } + + public static final LocationIdentity TLAB_REFILL_WASTE_LIMIT_LOCATION = NamedLocationIdentity.mutable("RefillWasteLimit"); + + @Fold + public static int tlabRefillWasteLimitOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.tlabRefillWasteLimitOffset(); + } + + public static final LocationIdentity TLAB_NOF_REFILLS_LOCATION = NamedLocationIdentity.mutable("TlabNOfRefills"); + + @Fold + public static int tlabNumberOfRefillsOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.tlabNumberOfRefillsOffset(); + } + + public static final LocationIdentity TLAB_FAST_REFILL_WASTE_LOCATION = NamedLocationIdentity.mutable("TlabFastRefillWaste"); + + @Fold + public static int tlabFastRefillWasteOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.tlabFastRefillWasteOffset(); + } + + public static final LocationIdentity TLAB_SLOW_ALLOCATIONS_LOCATION = NamedLocationIdentity.mutable("TlabSlowAllocations"); + + @Fold + public static int tlabSlowAllocationsOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.tlabSlowAllocationsOffset(); + } + + @Fold + public static int tlabRefillWasteIncrement(@InjectedParameter GraalHotSpotVMConfig config) { + return config.tlabRefillWasteIncrement; + } + + @Fold + public static boolean tlabStats(@InjectedParameter GraalHotSpotVMConfig config) { + return config.tlabStats; + } + + @Fold + public static int layoutHelperHeaderSizeShift(@InjectedParameter GraalHotSpotVMConfig config) { + return config.layoutHelperHeaderSizeShift; + } + + @Fold + public static int layoutHelperHeaderSizeMask(@InjectedParameter GraalHotSpotVMConfig config) { + return config.layoutHelperHeaderSizeMask; + } + + @Fold + public static int layoutHelperLog2ElementSizeShift(@InjectedParameter GraalHotSpotVMConfig config) { + return config.layoutHelperLog2ElementSizeShift; + } + + @Fold + public static int layoutHelperLog2ElementSizeMask(@InjectedParameter GraalHotSpotVMConfig config) { + return config.layoutHelperLog2ElementSizeMask; + } + + @Fold + public static int layoutHelperElementTypeShift(@InjectedParameter GraalHotSpotVMConfig config) { + return config.layoutHelperElementTypeShift; + } + + @Fold + public static int layoutHelperElementTypeMask(@InjectedParameter GraalHotSpotVMConfig config) { + return config.layoutHelperElementTypeMask; + } + + @Fold + public static int layoutHelperElementTypePrimitiveInPlace(@InjectedParameter GraalHotSpotVMConfig config) { + return config.layoutHelperElementTypePrimitiveInPlace(); + } + + @NodeIntrinsic(ForeignCallNode.class) + public static native int identityHashCode(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object); + + @Fold + public static int verifiedEntryPointOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.nmethodEntryOffset; + } + + @Fold + public static long gcTotalCollectionsAddress(@InjectedParameter GraalHotSpotVMConfig config) { + return config.gcTotalCollectionsAddress(); + } + + @Fold + public static long referentOffset() { + try { + return UNSAFE.objectFieldOffset(java.lang.ref.Reference.class.getDeclaredField("referent")); + } catch (Exception e) { + throw new GraalError(e); + } + } + + public static final LocationIdentity OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("ObjArrayKlass::_element_klass") { + @Override + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + ValueNode javaObject = findReadHub(object); + if (javaObject != null) { + ResolvedJavaType type = StampTool.typeOrNull(javaObject); + if (type != null && type.isArray()) { + ResolvedJavaType element = type.getComponentType(); + if (element != null && !element.isPrimitive() && !element.getElementalType().isInterface()) { + Assumptions assumptions = object.graph().getAssumptions(); + AssumptionResult leafType = element.findLeafConcreteSubtype(); + if (leafType != null && leafType.canRecordTo(assumptions)) { + leafType.recordTo(assumptions); + return ConstantNode.forConstant(read.stamp(), tool.getConstantReflection().asObjectHub(leafType.getResult()), tool.getMetaAccess()); + } + } + } + } + return read; + } + }; + + @Fold + public static int arrayClassElementOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.arrayClassElementOffset; + } + + public static final LocationIdentity PRIMARY_SUPERS_LOCATION = NamedLocationIdentity.immutable("PrimarySupers"); + + public static final LocationIdentity METASPACE_ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("MetaspaceArrayLength"); + + public static final LocationIdentity SECONDARY_SUPERS_ELEMENT_LOCATION = NamedLocationIdentity.immutable("SecondarySupersElement"); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotspotSnippetsOptions.java 2016-12-07 13:50:40.697576089 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015, 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.replacements; + +import org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.ProfileContext; +import org.graalvm.compiler.options.EnumOptionValue; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +/** + * Options related to HotSpot snippets in this package. + * + * Note: This must be a top level class to work around for + * Eclipse bug 477597. + */ +public class HotspotSnippetsOptions { + + // @formatter:off + @Option(help = "If the probability that a type check will hit one the profiled types (up to " + + "TypeCheckMaxHints) is below this value, the type check will be compiled without profiling info", type = OptionType.Expert) + public static final OptionValue TypeCheckMinProfileHitProbability = new OptionValue<>(0.5); + + @Option(help = "The maximum number of profiled types that will be used when compiling a profiled type check. " + + "Note that TypeCheckMinProfileHitProbability also influences whether profiling info is used in compiled type checks.", type = OptionType.Expert) + public static final OptionValue TypeCheckMaxHints = new OptionValue<>(2); + + @Option(help = "Use a VM runtime call to load and clear the exception object from the thread at the start of a compiled exception handler.", type = OptionType.Debug) + public static final OptionValue LoadExceptionObjectInVM = new OptionValue<>(false); + + @Option(help = "Enable profiling of allocation sites.", type = OptionType.Debug) + public static final OptionValue ProfileAllocations = new OptionValue<>(false); + + @Option(help = "Control the naming of the counters when using ProfileAllocations.", type = OptionType.Debug) + public static final EnumOptionValue ProfileAllocationsContext = new EnumOptionValue<>(ProfileContext.AllocatingMethod); + + @Option(help = "Enable profiling of monitor operations.", type = OptionType.Debug) + public static final OptionValue ProfileMonitors = new OptionValue<>(false); + + @Option(help = "Trace monitor operations on objects whose type contains this substring.", type = OptionType.Debug) + public static final OptionValue TraceMonitorsTypeFilter = new OptionValue<>(null); + + @Option(help = "Trace monitor operations in methods whose fully qualified name contains this substring.", type = OptionType.Debug) + public static final OptionValue TraceMonitorsMethodFilter = new OptionValue<>(null); + + @Option(help = "Emit extra code to dynamically check monitor operations are balanced.", type = OptionType.Debug) + public static final OptionValue VerifyBalancedMonitors = new OptionValue<>(false); + //@formatter:on +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java 2016-12-07 13:50:40.962587737 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014, 2015, 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.replacements; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.TypeReference; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FloatingGuardedNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.ConvertNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Read {@code Klass::_java_mirror} and incorporate non-null type information into stamp. This is + * also used by {@link ClassGetHubNode} to eliminate chains of {@code klass._java_mirror._klass}. + */ +@NodeInfo(cycles = CYCLES_4, size = SIZE_1) +public final class HubGetClassNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, ConvertNode { + public static final NodeClass TYPE = NodeClass.create(HubGetClassNode.class); + @Input protected ValueNode hub; + + public HubGetClassNode(@InjectedNodeParameter MetaAccessProvider metaAccess, ValueNode hub) { + super(TYPE, StampFactory.objectNonNull(TypeReference.createWithoutAssumptions(metaAccess.lookupJavaType(Class.class))), null); + this.hub = hub; + } + + public ValueNode getHub() { + return hub; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (tool.allUsagesAvailable() && hasNoUsages()) { + return null; + } else { + MetaAccessProvider metaAccess = tool.getMetaAccess(); + if (metaAccess != null && hub.isConstant()) { + ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(hub.asConstant()); + if (exactType != null) { + return ConstantNode.forConstant(tool.getConstantReflection().asJavaClass(exactType), metaAccess); + } + } + return this; + } + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + @NodeIntrinsic + public static native Class readClass(KlassPointer hub); + + @Override + public ValueNode getValue() { + return hub; + } + + @Override + public Constant convert(Constant c, ConstantReflectionProvider constantReflection) { + if (JavaConstant.NULL_POINTER.equals(c)) { + return c; + } + return constantReflection.asJavaClass(constantReflection.asJavaType(c)); + } + + @Override + public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) { + if (JavaConstant.NULL_POINTER.equals(c)) { + return c; + } + ResolvedJavaType type = constantReflection.asJavaType(c); + if (type.isPrimitive()) { + return JavaConstant.NULL_POINTER; + } else { + return constantReflection.asObjectHub(type); + } + } + + @Override + public boolean isLossless() { + /* + * Any concrete Klass* has a corresponding java.lang.Class + */ + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java 2016-12-07 13:50:41.227599385 -0800 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, 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.replacements; + +import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.type.AbstractObjectStamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.JavaConstant; + +@NodeInfo(cycles = CYCLES_0, size = SIZE_0) +public class IdentityHashCodeNode extends FixedWithNextNode implements Canonicalizable, Lowerable, MemoryCheckpoint.Single { + + public static final NodeClass TYPE = NodeClass.create(IdentityHashCodeNode.class); + + @Input ValueNode object; + + public IdentityHashCodeNode(ValueNode object) { + super(TYPE, StampFactory.forInteger(32)); + this.object = object; + + } + + @Override + public LocationIdentity getLocationIdentity() { + return HotSpotReplacementsUtil.MARK_WORD_LOCATION; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (object.isConstant()) { + assert object.stamp() instanceof AbstractObjectStamp; + JavaConstant c = (JavaConstant) object.asConstant(); + if (ImmutableCode.getValue()) { + return this; + } + JavaConstant identityHashCode = null; + if (c.isNull()) { + identityHashCode = JavaConstant.forInt(0); + } else { + identityHashCode = JavaConstant.forInt(((HotSpotObjectConstant) c).getIdentityHashCode()); + } + + return new ConstantNode(identityHashCode, StampFactory.forConstant(identityHashCode)); + } + return this; + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + @NodeIntrinsic + public static native int identityHashCode(Object object); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/InstanceOfSnippets.java 2016-12-07 13:50:41.494611121 -0800 @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2012, 2015, 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.replacements; + +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PRIMARY_SUPERS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.SECONDARY_SUPER_CACHE_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHubIntrinsic; +import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TypeCheckMaxHints; +import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TypeCheckMinProfileHitProbability; +import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.checkSecondarySubType; +import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.checkUnknownSubType; +import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.createHints; +import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.displayHit; +import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.displayMiss; +import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.exactHit; +import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.exactMiss; +import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.hintsHit; +import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.hintsMiss; +import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.isNull; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_LIKELY_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; +import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile; +import static jdk.vm.ci.meta.DeoptimizationReason.OptimizedTypeCheckViolated; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.SnippetAnchorNode; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.Hints; +import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.TypeCheckHints; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.extended.BranchProbabilityNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode; +import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode; +import org.graalvm.compiler.nodes.java.InstanceOfNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.InstanceOfSnippetsTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaTypeProfile; +import jdk.vm.ci.meta.TriState; + +/** + * Snippets used for implementing the type test of an instanceof instruction. Since instanceof is a + * floating node, it is lowered separately for each of its usages. + * + * The type tests implemented are described in the paper + * Fast subtype checking in the HotSpot JVM + * by Cliff Click and John Rose. + */ +public class InstanceOfSnippets implements Snippets { + + /** + * A test against a set of hints derived from a profile with 100% precise coverage of seen + * types. This snippet deoptimizes on hint miss paths. + */ + @Snippet + public static Object instanceofWithProfile(Object object, @VarargsParameter KlassPointer[] hints, @VarargsParameter boolean[] hintIsPositive, Object trueValue, Object falseValue, + @ConstantParameter boolean nullSeen) { + if (probability(NOT_FREQUENT_PROBABILITY, object == null)) { + isNull.inc(); + if (!nullSeen) { + // See comment below for other deoptimization path; the + // same reasoning applies here. + DeoptimizeNode.deopt(InvalidateReprofile, OptimizedTypeCheckViolated); + } + return falseValue; + } + GuardingNode anchorNode = SnippetAnchorNode.anchor(); + KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode)); + // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < hints.length; i++) { + KlassPointer hintHub = hints[i]; + boolean positive = hintIsPositive[i]; + if (probability(LIKELY_PROBABILITY, hintHub.equal(objectHub))) { + hintsHit.inc(); + return positive ? trueValue : falseValue; + } + hintsMiss.inc(); + } + // This maybe just be a rare event but it might also indicate a phase change + // in the application. Ideally we want to use DeoptimizationAction.None for + // the former but the cost is too high if indeed it is the latter. As such, + // we defensively opt for InvalidateReprofile. + DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, OptimizedTypeCheckViolated); + return falseValue; + } + + /** + * A test against a final type. + */ + @Snippet + public static Object instanceofExact(Object object, KlassPointer exactHub, Object trueValue, Object falseValue) { + if (probability(NOT_FREQUENT_PROBABILITY, object == null)) { + isNull.inc(); + return falseValue; + } + GuardingNode anchorNode = SnippetAnchorNode.anchor(); + KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode)); + if (probability(LIKELY_PROBABILITY, objectHub.notEqual(exactHub))) { + exactMiss.inc(); + return falseValue; + } + exactHit.inc(); + return trueValue; + } + + @Snippet + public static Object instanceofExactPIC(Object object, KlassPointer exactHub, Object trueValue, Object falseValue) { + KlassPointer exactHubPIC = ResolveConstantSnippets.resolveKlassConstant(exactHub); + return instanceofExact(object, exactHubPIC, trueValue, falseValue); + } + + /** + * A test against a primary type. + */ + @Snippet + public static Object instanceofPrimary(KlassPointer hub, Object object, @ConstantParameter int superCheckOffset, Object trueValue, Object falseValue) { + if (probability(NOT_FREQUENT_PROBABILITY, object == null)) { + isNull.inc(); + return falseValue; + } + GuardingNode anchorNode = SnippetAnchorNode.anchor(); + KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode)); + if (probability(NOT_LIKELY_PROBABILITY, objectHub.readKlassPointer(superCheckOffset, PRIMARY_SUPERS_LOCATION).notEqual(hub))) { + displayMiss.inc(); + return falseValue; + } + displayHit.inc(); + return trueValue; + } + + @Snippet + public static Object instanceofPrimaryPIC(KlassPointer hub, Object object, @ConstantParameter int superCheckOffset, Object trueValue, Object falseValue) { + KlassPointer resolvedHub = ResolveConstantSnippets.resolveKlassConstant(hub); + return instanceofPrimary(resolvedHub, object, superCheckOffset, trueValue, falseValue); + } + + /** + * A test against a restricted secondary type type. + */ + @Snippet + public static Object instanceofSecondary(KlassPointer hub, Object object, @VarargsParameter KlassPointer[] hints, @VarargsParameter boolean[] hintIsPositive, Object trueValue, Object falseValue) { + if (probability(NOT_FREQUENT_PROBABILITY, object == null)) { + isNull.inc(); + return falseValue; + } + GuardingNode anchorNode = SnippetAnchorNode.anchor(); + KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode)); + // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < hints.length; i++) { + KlassPointer hintHub = hints[i]; + boolean positive = hintIsPositive[i]; + if (probability(NOT_FREQUENT_PROBABILITY, hintHub.equal(objectHub))) { + hintsHit.inc(); + return positive ? trueValue : falseValue; + } + } + hintsMiss.inc(); + if (!checkSecondarySubType(hub, objectHub)) { + return falseValue; + } + return trueValue; + } + + @Snippet + public static Object instanceofSecondaryPIC(KlassPointer hub, Object object, @VarargsParameter KlassPointer[] hints, @VarargsParameter boolean[] hintIsPositive, Object trueValue, + Object falseValue) { + KlassPointer resolvedHub = ResolveConstantSnippets.resolveKlassConstant(hub); + return instanceofSecondary(resolvedHub, object, hints, hintIsPositive, trueValue, falseValue); + } + + /** + * Type test used when the type being tested against is not known at compile time. + */ + @Snippet + public static Object instanceofDynamic(KlassPointer hub, Object object, Object trueValue, Object falseValue, @ConstantParameter boolean allowNull) { + if (probability(NOT_FREQUENT_PROBABILITY, object == null)) { + isNull.inc(); + if (allowNull) { + return trueValue; + } else { + return falseValue; + } + } + GuardingNode anchorNode = SnippetAnchorNode.anchor(); + KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode)); + // The hub of a primitive type can be null => always return false in this case. + if (hub.isNull() || !checkUnknownSubType(hub, objectHub)) { + return falseValue; + } + return trueValue; + } + + @Snippet + public static Object isAssignableFrom(Class thisClass, Class otherClass, Object trueValue, Object falseValue) { + if (BranchProbabilityNode.probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, otherClass == null)) { + DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); + return false; + } + GuardingNode anchorNode = SnippetAnchorNode.anchor(); + KlassPointer thisHub = ClassGetHubNode.readClass(thisClass, anchorNode); + KlassPointer otherHub = ClassGetHubNode.readClass(otherClass, anchorNode); + if (thisHub.isNull() || otherHub.isNull()) { + // primitive types, only true if equal. + return thisClass == otherClass ? trueValue : falseValue; + } + if (!TypeCheckSnippetUtils.checkUnknownSubType(thisHub, otherHub)) { + return falseValue; + } + return trueValue; + } + + public static class Templates extends InstanceOfSnippetsTemplates { + + private final SnippetInfo instanceofWithProfile = snippet(InstanceOfSnippets.class, "instanceofWithProfile"); + private final SnippetInfo instanceofExact = snippet(InstanceOfSnippets.class, "instanceofExact"); + private final SnippetInfo instanceofExactPIC = snippet(InstanceOfSnippets.class, "instanceofExactPIC"); + private final SnippetInfo instanceofPrimary = snippet(InstanceOfSnippets.class, "instanceofPrimary"); + private final SnippetInfo instanceofPrimaryPIC = snippet(InstanceOfSnippets.class, "instanceofPrimaryPIC"); + private final SnippetInfo instanceofSecondary = snippet(InstanceOfSnippets.class, "instanceofSecondary", SECONDARY_SUPER_CACHE_LOCATION); + private final SnippetInfo instanceofSecondaryPIC = snippet(InstanceOfSnippets.class, "instanceofSecondaryPIC", SECONDARY_SUPER_CACHE_LOCATION); + private final SnippetInfo instanceofDynamic = snippet(InstanceOfSnippets.class, "instanceofDynamic", SECONDARY_SUPER_CACHE_LOCATION); + private final SnippetInfo isAssignableFrom = snippet(InstanceOfSnippets.class, "isAssignableFrom", SECONDARY_SUPER_CACHE_LOCATION); + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + } + + @Override + protected Arguments makeArguments(InstanceOfUsageReplacer replacer, LoweringTool tool) { + if (replacer.instanceOf instanceof InstanceOfNode) { + InstanceOfNode instanceOf = (InstanceOfNode) replacer.instanceOf; + ValueNode object = instanceOf.getValue(); + Assumptions assumptions = instanceOf.graph().getAssumptions(); + + JavaTypeProfile profile = instanceOf.profile(); + if (GeneratePIC.getValue()) { + // FIXME: We can't embed constants in hints. We can't really load them from GOT + // either. Hard problem. + profile = null; + } + TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), profile, assumptions, TypeCheckMinProfileHitProbability.getValue(), TypeCheckMaxHints.getValue()); + final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type().getType(); + ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), instanceOf.graph()); + + Arguments args; + + StructuredGraph graph = instanceOf.graph(); + if (hintInfo.hintHitProbability >= 1.0 && hintInfo.exact == null) { + Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph); + args = new Arguments(instanceofWithProfile, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("object", object); + args.addVarargs("hints", KlassPointer.class, KlassPointerStamp.klassNonNull(), hints.hubs); + args.addVarargs("hintIsPositive", boolean.class, StampFactory.forKind(JavaKind.Boolean), hints.isPositive); + } else if (hintInfo.exact != null) { + SnippetInfo snippet = GeneratePIC.getValue() ? instanceofExactPIC : instanceofExact; + args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("object", object); + args.add("exactHub", ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) hintInfo.exact).klass(), providers.getMetaAccess(), graph)); + } else if (type.isPrimaryType()) { + SnippetInfo snippet = GeneratePIC.getValue() ? instanceofPrimaryPIC : instanceofPrimary; + args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("hub", hub); + args.add("object", object); + args.addConst("superCheckOffset", type.superCheckOffset()); + } else { + Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph); + SnippetInfo snippet = GeneratePIC.getValue() ? instanceofSecondaryPIC : instanceofSecondary; + args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("hub", hub); + args.add("object", object); + args.addVarargs("hints", KlassPointer.class, KlassPointerStamp.klassNonNull(), hints.hubs); + args.addVarargs("hintIsPositive", boolean.class, StampFactory.forKind(JavaKind.Boolean), hints.isPositive); + } + args.add("trueValue", replacer.trueValue); + args.add("falseValue", replacer.falseValue); + if (hintInfo.hintHitProbability >= 1.0 && hintInfo.exact == null) { + args.addConst("nullSeen", hintInfo.profile.getNullSeen() != TriState.FALSE); + } + return args; + } else if (replacer.instanceOf instanceof InstanceOfDynamicNode) { + InstanceOfDynamicNode instanceOf = (InstanceOfDynamicNode) replacer.instanceOf; + ValueNode object = instanceOf.getObject(); + + Arguments args = new Arguments(instanceofDynamic, instanceOf.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("hub", instanceOf.getMirrorOrHub()); + args.add("object", object); + args.add("trueValue", replacer.trueValue); + args.add("falseValue", replacer.falseValue); + args.addConst("allowNull", instanceOf.allowsNull()); + return args; + } else if (replacer.instanceOf instanceof ClassIsAssignableFromNode) { + ClassIsAssignableFromNode isAssignable = (ClassIsAssignableFromNode) replacer.instanceOf; + Arguments args = new Arguments(isAssignableFrom, isAssignable.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("thisClass", isAssignable.getThisClass()); + args.add("otherClass", isAssignable.getOtherClass()); + args.add("trueValue", replacer.trueValue); + args.add("falseValue", replacer.falseValue); + return args; + } else { + throw GraalError.shouldNotReachHere(); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java 2016-12-07 13:50:41.762622901 -0800 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2014, 2015, 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.replacements; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FloatingGuardedNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.extended.LoadHubNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Read {@code Klass::_layout_helper} and incorporate any useful stamp information based on any type + * information in {@code klass}. + */ +@NodeInfo(cycles = CYCLES_4, size = SIZE_1) +public final class KlassLayoutHelperNode extends FloatingGuardedNode implements Canonicalizable, Lowerable { + + public static final NodeClass TYPE = NodeClass.create(KlassLayoutHelperNode.class); + @Input protected ValueNode klass; + protected final GraalHotSpotVMConfig config; + + public KlassLayoutHelperNode(@InjectedNodeParameter GraalHotSpotVMConfig config, ValueNode klass) { + this(config, klass, null); + } + + public KlassLayoutHelperNode(@InjectedNodeParameter GraalHotSpotVMConfig config, ValueNode klass, ValueNode guard) { + super(TYPE, StampFactory.forKind(JavaKind.Int), (GuardingNode) guard); + this.klass = klass; + this.config = config; + } + + @Override + public boolean inferStamp() { + if (klass instanceof LoadHubNode) { + LoadHubNode hub = (LoadHubNode) klass; + Stamp hubStamp = hub.getValue().stamp(); + if (hubStamp instanceof ObjectStamp) { + ObjectStamp objectStamp = (ObjectStamp) hubStamp; + ResolvedJavaType type = objectStamp.type(); + if (type != null && !type.isJavaLangObject()) { + if (!type.isArray() && !type.isInterface()) { + /* + * Definitely some form of instance type. + */ + return updateStamp(StampFactory.forInteger(JavaKind.Int, config.klassLayoutHelperNeutralValue, Integer.MAX_VALUE)); + } + if (type.isArray()) { + return updateStamp(StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE, config.klassLayoutHelperNeutralValue - 1)); + } + } + } + } + return false; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (tool.allUsagesAvailable() && hasNoUsages()) { + return null; + } else { + if (klass.isConstant()) { + if (!klass.asConstant().isDefaultForKind()) { + Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), klass.asConstant(), config.klassLayoutHelperOffset); + return ConstantNode.forConstant(stamp(), constant, tool.getMetaAccess()); + } + } + if (klass instanceof LoadHubNode) { + LoadHubNode hub = (LoadHubNode) klass; + Stamp hubStamp = hub.getValue().stamp(); + if (hubStamp instanceof ObjectStamp) { + ObjectStamp ostamp = (ObjectStamp) hubStamp; + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) ostamp.type(); + if (type != null && type.isArray() && !type.getComponentType().isPrimitive()) { + // The layout for all object arrays is the same. + Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), type.klass(), config.klassLayoutHelperOffset); + return ConstantNode.forConstant(stamp(), constant, tool.getMetaAccess()); + } + } + } + return this; + } + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + public ValueNode getHub() { + return klass; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java 2016-12-07 13:50:42.027634549 -0800 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2012, 2015, 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.replacements; + +import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.LOAD_AND_CLEAR_EXCEPTION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.EXCEPTION_OOP_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.EXCEPTION_PC_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readExceptionOop; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeExceptionOop; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeExceptionPc; +import static org.graalvm.compiler.nodes.PiNode.piCast; +import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.java.LoadExceptionObjectNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.replacements.nodes.ReadRegisterNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; + +/** + * Snippet for loading the exception object at the start of an exception dispatcher. + *

    + * The frame state upon entry to an exception handler is such that it is a + * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly the + * exception object (per the JVM spec) to rethrow. This means that the code generated for this node + * must not cause a deoptimization as the runtime/interpreter would not have a valid location to + * find the exception object to be rethrown. + */ +public class LoadExceptionObjectSnippets implements Snippets { + + /** + * Alternative way to implement exception object loading. + */ + private static final boolean USE_C_RUNTIME = HotspotSnippetsOptions.LoadExceptionObjectInVM.getValue(); + + @Snippet + public static Object loadException(@ConstantParameter Register threadRegister) { + Word thread = registerAsWord(threadRegister); + Object exception = readExceptionOop(thread); + writeExceptionOop(thread, null); + writeExceptionPc(thread, Word.zero()); + return piCast(exception, StampFactory.forNodeIntrinsic()); + } + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo loadException = snippet(LoadExceptionObjectSnippets.class, "loadException", EXCEPTION_OOP_LOCATION, EXCEPTION_PC_LOCATION); + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + } + + public void lower(LoadExceptionObjectNode loadExceptionObject, HotSpotRegistersProvider registers, LoweringTool tool) { + if (USE_C_RUNTIME) { + StructuredGraph graph = loadExceptionObject.graph(); + ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), true, false)); + graph.addBeforeFixed(loadExceptionObject, thread); + ForeignCallNode loadExceptionC = graph.add(new ForeignCallNode(providers.getForeignCalls(), LOAD_AND_CLEAR_EXCEPTION, thread)); + loadExceptionC.setStateAfter(loadExceptionObject.stateAfter()); + graph.replaceFixedWithFixed(loadExceptionObject, loadExceptionC); + } else { + Arguments args = new Arguments(loadException, loadExceptionObject.graph().getGuardsStage(), tool.getLoweringStage()); + args.addConst("threadRegister", registers.getThreadRegister()); + template(args).instantiate(providers.getMetaAccess(), loadExceptionObject, DEFAULT_REPLACER, args); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java 2016-12-07 13:50:42.291646154 -0800 @@ -0,0 +1,697 @@ +/* + * Copyright (c) 2012, 2016, 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.replacements; + +import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters; +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.nodes.BeginLockScopeNode.beginLockScope; +import static org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode.compareAndSwap; +import static org.graalvm.compiler.hotspot.nodes.EndLockScopeNode.endLockScope; +import static org.graalvm.compiler.hotspot.nodes.VMErrorNode.vmError; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.DISPLACED_MARK_WORD_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.ageMaskInPlace; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockMaskInPlace; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockPattern; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.epochMaskInPlace; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadWordFromObject; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.lockDisplacedMarkOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.markOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.pageSize; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.prototypeMarkWordOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.unlockedMask; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useBiasedLocking; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOop; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize; +import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.ProfileMonitors; +import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TraceMonitorsMethodFilter; +import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TraceMonitorsTypeFilter; +import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.VerifyBalancedMonitors; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_FAST_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; +import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; + +import java.util.List; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.bytecode.Bytecode; +import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.hotspot.nodes.AcquiredCASLockNode; +import org.graalvm.compiler.hotspot.nodes.CurrentLockNode; +import org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode; +import org.graalvm.compiler.hotspot.nodes.FastAcquireBiasedLockNode; +import org.graalvm.compiler.hotspot.nodes.MonitorCounterNode; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodes.BreakpointNode; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.debug.DynamicCounterNode; +import org.graalvm.compiler.nodes.extended.BranchProbabilityNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.java.MethodCallTargetNode; +import org.graalvm.compiler.nodes.java.MonitorExitNode; +import org.graalvm.compiler.nodes.java.RawMonitorEnterNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.phases.common.inlining.InliningUtil; +import org.graalvm.compiler.replacements.Log; +import org.graalvm.compiler.replacements.SnippetCounter; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.WordBase; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Snippets used for implementing the monitorenter and monitorexit instructions. + * + * The locking algorithm used is described in the paper + * Eliminating synchronization-related + * atomic operations with biased locking and bulk rebiasing by Kenneth Russell and David + * Detlefs. + * + * Comment below is reproduced from {@code markOop.hpp} for convenience: + * + *

    + *  Bit-format of an object header (most significant first, big endian layout below):
    + *  32 bits:
    + *  --------
    + *             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
    + *             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
    + *             size:32 ------------------------------------------>| (CMS free block)
    + *             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
    + *
    + *  64 bits:
    + *  --------
    + *  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
    + *  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
    + *  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
    + *  size:64 ----------------------------------------------------->| (CMS free block)
    + *
    + *  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
    + *  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
    + *  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
    + *  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
    + *
    + *  - hash contains the identity hash value: largest value is
    + *    31 bits, see os::random().  Also, 64-bit vm's require
    + *    a hash value no bigger than 32 bits because they will not
    + *    properly generate a mask larger than that: see library_call.cpp
    + *    and c1_CodePatterns_sparc.cpp.
    + *
    + *  - the biased lock pattern is used to bias a lock toward a given
    + *    thread. When this pattern is set in the low three bits, the lock
    + *    is either biased toward a given thread or "anonymously" biased,
    + *    indicating that it is possible for it to be biased. When the
    + *    lock is biased toward a given thread, locking and unlocking can
    + *    be performed by that thread without using atomic operations.
    + *    When a lock's bias is revoked, it reverts back to the normal
    + *    locking scheme described below.
    + *
    + *    Note that we are overloading the meaning of the "unlocked" state
    + *    of the header. Because we steal a bit from the age we can
    + *    guarantee that the bias pattern will never be seen for a truly
    + *    unlocked object.
    + *
    + *    Note also that the biased state contains the age bits normally
    + *    contained in the object header. Large increases in scavenge
    + *    times were seen when these bits were absent and an arbitrary age
    + *    assigned to all biased objects, because they tended to consume a
    + *    significant fraction of the eden semispaces and were not
    + *    promoted promptly, causing an increase in the amount of copying
    + *    performed. The runtime system aligns all JavaThread* pointers to
    + *    a very large value (currently 128 bytes (32bVM) or 256 bytes (64bVM))
    + *    to make room for the age bits & the epoch bits (used in support of
    + *    biased locking), and for the CMS "freeness" bit in the 64bVM (+COOPs).
    + *
    + *    [JavaThread* | epoch | age | 1 | 01]       lock is biased toward given thread
    + *    [0           | epoch | age | 1 | 01]       lock is anonymously biased
    + *
    + *  - the two lock bits are used to describe three states: locked/unlocked and monitor.
    + *
    + *    [ptr             | 00]  locked             ptr points to real header on stack
    + *    [header      | 0 | 01]  unlocked           regular object header
    + *    [ptr             | 10]  monitor            inflated lock (header is wapped out)
    + *    [ptr             | 11]  marked             used by markSweep to mark an object
    + *                                               not valid at any other time
    + *
    + *    We assume that stack/thread pointers have the lowest two bits cleared.
    + * 
    + * + * Note that {@code Thread::allocate} enforces {@code JavaThread} objects to be aligned + * appropriately to comply with the layouts above. + */ +public class MonitorSnippets implements Snippets { + + private static final boolean PROFILE_CONTEXT = false; + + @Fold + static boolean doProfile() { + return ProfileMonitors.getValue(); + } + + @Snippet + public static void monitorenter(Object object, KlassPointer hub, @ConstantParameter int lockDepth, @ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister, + @ConstantParameter boolean trace) { + verifyOop(object); + + // Load the mark word - this includes a null-check on object + final Word mark = loadWordFromObject(object, markOffset(INJECTED_VMCONFIG)); + + final Word lock = beginLockScope(lockDepth); + + trace(trace, " object: 0x%016lx\n", Word.objectToTrackedPointer(object)); + trace(trace, " lock: 0x%016lx\n", lock); + trace(trace, " mark: 0x%016lx\n", mark); + + incCounter(); + + if (useBiasedLocking(INJECTED_VMCONFIG)) { + // See whether the lock is currently biased toward our thread and + // whether the epoch is still valid. + // Note that the runtime guarantees sufficient alignment of JavaThread + // pointers to allow age to be placed into low bits. + final Word biasableLockBits = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)); + + // Check whether the bias pattern is present in the object's mark word + // and the bias owner and the epoch are both still current. + final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION); + final Word thread = registerAsWord(threadRegister); + final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace(INJECTED_VMCONFIG)); + trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord); + trace(trace, " thread: 0x%016lx\n", thread); + trace(trace, " tmp: 0x%016lx\n", tmp); + if (probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, tmp.equal(0))) { + // Object is already biased to current thread -> done + traceObject(trace, "+lock{bias:existing}", object, true); + lockBiasExisting.inc(); + FastAcquireBiasedLockNode.mark(object); + return; + } + + // Now check to see whether biasing is enabled for this object + if (probability(BranchProbabilityNode.FAST_PATH_PROBABILITY, biasableLockBits.notEqual(Word.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) { + // Biasing not enabled -> fall through to lightweight locking + unbiasable.inc(); + } else { + // At this point we know that the mark word has the bias pattern and + // that we are not the bias owner in the current epoch. We need to + // figure out more details about the state of the mark word in order to + // know what operations can be legally performed on the object's + // mark word. + + // If the low three bits in the xor result aren't clear, that means + // the prototype header is no longer biasable and we have to revoke + // the bias on this object. + if (probability(FREQUENT_PROBABILITY, tmp.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(0))) { + // Biasing is still enabled for object's type. See whether the + // epoch of the current bias is still valid, meaning that the epoch + // bits of the mark word are equal to the epoch bits of the + // prototype mark word. (Note that the prototype mark word's epoch bits + // only change at a safepoint.) If not, attempt to rebias the object + // toward the current thread. Note that we must be absolutely sure + // that the current epoch is invalid in order to do this because + // otherwise the manipulations it performs on the mark word are + // illegal. + if (probability(FREQUENT_PROBABILITY, tmp.and(epochMaskInPlace(INJECTED_VMCONFIG)).equal(0))) { + // The epoch of the current bias is still valid but we know nothing + // about the owner; it might be set or it might be clear. Try to + // acquire the bias of the object using an atomic operation. If this + // fails we will go in to the runtime to revoke the object's bias. + // Note that we first construct the presumed unbiased header so we + // don't accidentally blow away another thread's valid bias. + Word unbiasedMark = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG) | ageMaskInPlace(INJECTED_VMCONFIG) | epochMaskInPlace(INJECTED_VMCONFIG)); + Word biasedMark = unbiasedMark.or(thread); + trace(trace, " unbiasedMark: 0x%016lx\n", unbiasedMark); + trace(trace, " biasedMark: 0x%016lx\n", biasedMark); + if (probability(VERY_FAST_PATH_PROBABILITY, + compareAndSwap(OffsetAddressNode.address(object, markOffset(INJECTED_VMCONFIG)), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark))) { + // Object is now biased to current thread -> done + traceObject(trace, "+lock{bias:acquired}", object, true); + lockBiasAcquired.inc(); + return; + } + // If the biasing toward our thread failed, this means that another thread + // owns the bias and we need to revoke that bias. The revocation will occur + // in the interpreter runtime. + traceObject(trace, "+lock{stub:revoke}", object, true); + lockStubRevoke.inc(); + } else { + // At this point we know the epoch has expired, meaning that the + // current bias owner, if any, is actually invalid. Under these + // circumstances _only_, are we allowed to use the current mark word + // value as the comparison value when doing the CAS to acquire the + // bias in the current epoch. In other words, we allow transfer of + // the bias from one thread to another directly in this situation. + Word biasedMark = prototypeMarkWord.or(thread); + trace(trace, " biasedMark: 0x%016lx\n", biasedMark); + if (probability(VERY_FAST_PATH_PROBABILITY, + compareAndSwap(OffsetAddressNode.address(object, markOffset(INJECTED_VMCONFIG)), mark, biasedMark, MARK_WORD_LOCATION).equal(mark))) { + // Object is now biased to current thread -> done + traceObject(trace, "+lock{bias:transfer}", object, true); + lockBiasTransfer.inc(); + return; + } + // If the biasing toward our thread failed, then another thread + // succeeded in biasing it toward itself and we need to revoke that + // bias. The revocation will occur in the runtime in the slow case. + traceObject(trace, "+lock{stub:epoch-expired}", object, true); + lockStubEpochExpired.inc(); + } + monitorenterStubC(MONITORENTER, object, lock); + return; + } else { + // The prototype mark word doesn't have the bias bit set any + // more, indicating that objects of this data type are not supposed + // to be biased any more. We are going to try to reset the mark of + // this object to the prototype value and fall through to the + // CAS-based locking scheme. Note that if our CAS fails, it means + // that another thread raced us for the privilege of revoking the + // bias of this particular object, so it's okay to continue in the + // normal locking code. + Word result = compareAndSwap(OffsetAddressNode.address(object, markOffset(INJECTED_VMCONFIG)), mark, prototypeMarkWord, MARK_WORD_LOCATION); + + // Fall through to the normal CAS-based lock, because no matter what + // the result of the above CAS, some thread must have succeeded in + // removing the bias bit from the object's header. + + if (ENABLE_BREAKPOINT) { + bkpt(object, mark, tmp, result); + } + revokeBias.inc(); + } + } + } + + // Create the unlocked mark word pattern + Word unlockedMark = mark.or(unlockedMask(INJECTED_VMCONFIG)); + trace(trace, " unlockedMark: 0x%016lx\n", unlockedMark); + + // Copy this unlocked mark word into the lock slot on the stack + lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), unlockedMark, DISPLACED_MARK_WORD_LOCATION); + + // Test if the object's mark word is unlocked, and if so, store the + // (address of) the lock slot into the object's mark word. + Word currentMark = compareAndSwap(OffsetAddressNode.address(object, markOffset(INJECTED_VMCONFIG)), unlockedMark, lock, MARK_WORD_LOCATION); + if (probability(BranchProbabilityNode.SLOW_PATH_PROBABILITY, currentMark.notEqual(unlockedMark))) { + trace(trace, " currentMark: 0x%016lx\n", currentMark); + // The mark word in the object header was not the same. + // Either the object is locked by another thread or is already locked + // by the current thread. The latter is true if the mark word + // is a stack pointer into the current thread's stack, i.e.: + // + // 1) (currentMark & aligned_mask) == 0 + // 2) rsp <= currentMark + // 3) currentMark <= rsp + page_size + // + // These 3 tests can be done by evaluating the following expression: + // + // (currentMark - rsp) & (aligned_mask - page_size) + // + // assuming both the stack pointer and page_size have their least + // significant 2 bits cleared and page_size is a power of 2 + final Word alignedMask = Word.unsigned(wordSize() - 1); + final Word stackPointer = registerAsWord(stackPointerRegister).add(config(INJECTED_VMCONFIG).stackBias); + if (probability(VERY_SLOW_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0))) { + // Most likely not a recursive lock, go into a slow runtime call + traceObject(trace, "+lock{stub:failed-cas}", object, true); + lockStubFailedCas.inc(); + monitorenterStubC(MONITORENTER, object, lock); + return; + } else { + // Recursively locked => write 0 to the lock slot + lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), Word.zero(), DISPLACED_MARK_WORD_LOCATION); + traceObject(trace, "+lock{cas:recursive}", object, true); + lockCasRecursive.inc(); + } + } else { + traceObject(trace, "+lock{cas}", object, true); + lockCas.inc(); + AcquiredCASLockNode.mark(object); + } + } + + /** + * Calls straight out to the monitorenter stub. + */ + @Snippet + public static void monitorenterStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) { + verifyOop(object); + incCounter(); + if (object == null) { + DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); + } + // BeginLockScope nodes do not read from object so a use of object + // cannot float about the null check above + final Word lock = beginLockScope(lockDepth); + traceObject(trace, "+lock{stub}", object, true); + monitorenterStubC(MONITORENTER, object, lock); + } + + @Snippet + public static void monitorexit(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) { + trace(trace, " object: 0x%016lx\n", Word.objectToTrackedPointer(object)); + if (useBiasedLocking(INJECTED_VMCONFIG)) { + // Check for biased locking unlock case, which is a no-op + // Note: we do not have to check the thread ID for two reasons. + // First, the interpreter checks for IllegalMonitorStateException at + // a higher level. Second, if the bias was revoked while we held the + // lock, the object could not be rebiased toward another thread, so + // the bias bit would be clear. + final Word mark = loadWordFromObject(object, markOffset(INJECTED_VMCONFIG)); + trace(trace, " mark: 0x%016lx\n", mark); + if (probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(Word.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) { + endLockScope(); + decCounter(); + traceObject(trace, "-lock{bias}", object, false); + unlockBias.inc(); + return; + } + } + + final Word lock = CurrentLockNode.currentLock(lockDepth); + + // Load displaced mark + final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), DISPLACED_MARK_WORD_LOCATION); + trace(trace, " displacedMark: 0x%016lx\n", displacedMark); + + if (probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, displacedMark.equal(0))) { + // Recursive locking => done + traceObject(trace, "-lock{recursive}", object, false); + unlockCasRecursive.inc(); + } else { + verifyOop(object); + // Test if object's mark word is pointing to the displaced mark word, and if so, restore + // the displaced mark in the object - if the object's mark word is not pointing to + // the displaced mark word, do unlocking via runtime call. + if (probability(VERY_SLOW_PATH_PROBABILITY, + DirectCompareAndSwapNode.compareAndSwap(OffsetAddressNode.address(object, markOffset(INJECTED_VMCONFIG)), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock))) { + // The object's mark word was not pointing to the displaced header, + // we do unlocking via runtime call. + traceObject(trace, "-lock{stub}", object, false); + unlockStub.inc(); + monitorexitStubC(MONITOREXIT, object, lock); + } else { + traceObject(trace, "-lock{cas}", object, false); + unlockCas.inc(); + } + } + endLockScope(); + decCounter(); + } + + /** + * Calls straight out to the monitorexit stub. + */ + @Snippet + public static void monitorexitStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) { + verifyOop(object); + traceObject(trace, "-lock{stub}", object, false); + final Word lock = CurrentLockNode.currentLock(lockDepth); + monitorexitStubC(MONITOREXIT, object, lock); + endLockScope(); + decCounter(); + } + + public static void traceObject(boolean enabled, String action, Object object, boolean enter) { + if (doProfile()) { + DynamicCounterNode.counter(action, enter ? "number of monitor enters" : "number of monitor exits", 1, PROFILE_CONTEXT); + } + if (enabled) { + Log.print(action); + Log.print(' '); + Log.printlnObject(object); + } + } + + public static void trace(boolean enabled, String format, WordBase value) { + if (enabled) { + Log.printf(format, value.rawValue()); + } + } + + /** + * Leaving the breakpoint code in to provide an example of how to use the {@link BreakpointNode} + * intrinsic. + */ + private static final boolean ENABLE_BREAKPOINT = false; + + private static final LocationIdentity MONITOR_COUNTER_LOCATION = NamedLocationIdentity.mutable("MonitorCounter"); + + @NodeIntrinsic(BreakpointNode.class) + static native void bkpt(Object object, Word mark, Word tmp, Word value); + + private static final boolean VERIFY_BALANCED_MONITORS = VerifyBalancedMonitors.getValue(); + + public static void incCounter() { + if (VERIFY_BALANCED_MONITORS) { + final Word counter = MonitorCounterNode.counter(); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); + counter.writeInt(0, count + 1, MONITOR_COUNTER_LOCATION); + } + } + + public static void decCounter() { + if (VERIFY_BALANCED_MONITORS) { + final Word counter = MonitorCounterNode.counter(); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); + counter.writeInt(0, count - 1, MONITOR_COUNTER_LOCATION); + } + } + + @Snippet + private static void initCounter() { + final Word counter = MonitorCounterNode.counter(); + counter.writeInt(0, 0, MONITOR_COUNTER_LOCATION); + } + + @Snippet + private static void checkCounter(@ConstantParameter String errMsg) { + final Word counter = MonitorCounterNode.counter(); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); + if (count != 0) { + vmError(errMsg, count); + } + } + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo monitorenter = snippet(MonitorSnippets.class, "monitorenter"); + private final SnippetInfo monitorexit = snippet(MonitorSnippets.class, "monitorexit"); + private final SnippetInfo monitorenterStub = snippet(MonitorSnippets.class, "monitorenterStub"); + private final SnippetInfo monitorexitStub = snippet(MonitorSnippets.class, "monitorexitStub"); + private final SnippetInfo initCounter = snippet(MonitorSnippets.class, "initCounter"); + private final SnippetInfo checkCounter = snippet(MonitorSnippets.class, "checkCounter"); + + private final boolean useFastLocking; + + public Templates(HotSpotProviders providers, TargetDescription target, boolean useFastLocking) { + super(providers, providers.getSnippetReflection(), target); + this.useFastLocking = useFastLocking; + } + + public void lower(RawMonitorEnterNode monitorenterNode, HotSpotRegistersProvider registers, LoweringTool tool) { + StructuredGraph graph = monitorenterNode.graph(); + checkBalancedMonitors(graph, tool); + + assert ((ObjectStamp) monitorenterNode.object().stamp()).nonNull(); + + Arguments args; + if (useFastLocking) { + args = new Arguments(monitorenter, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("object", monitorenterNode.object()); + args.add("hub", monitorenterNode.getHub()); + args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth()); + args.addConst("threadRegister", registers.getThreadRegister()); + args.addConst("stackPointerRegister", registers.getStackPointerRegister()); + args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(graph.method())); + } else { + args = new Arguments(monitorenterStub, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("object", monitorenterNode.object()); + args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth()); + args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(graph.method())); + } + + template(args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args); + } + + public void lower(MonitorExitNode monitorexitNode, LoweringTool tool) { + StructuredGraph graph = monitorexitNode.graph(); + + Arguments args; + if (useFastLocking) { + args = new Arguments(monitorexit, graph.getGuardsStage(), tool.getLoweringStage()); + } else { + args = new Arguments(monitorexitStub, graph.getGuardsStage(), tool.getLoweringStage()); + } + args.add("object", monitorexitNode.object()); + args.addConst("lockDepth", monitorexitNode.getMonitorId().getLockDepth()); + args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(graph.method())); + + template(args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args); + } + + public static boolean isTracingEnabledForType(ValueNode object) { + ResolvedJavaType type = StampTool.typeOrNull(object.stamp()); + String filter = TraceMonitorsTypeFilter.getValue(); + if (filter == null) { + return false; + } else { + if (filter.length() == 0) { + return true; + } + if (type == null) { + return false; + } + return (type.getName().contains(filter)); + } + } + + public static boolean isTracingEnabledForMethod(ResolvedJavaMethod method) { + String filter = TraceMonitorsMethodFilter.getValue(); + if (filter == null) { + return false; + } else { + if (filter.length() == 0) { + return true; + } + if (method == null) { + return false; + } + return (method.format("%H.%n").contains(filter)); + } + } + + /** + * If balanced monitor checking is enabled then nodes are inserted at the start and all + * return points of the graph to initialize and check the monitor counter respectively. + */ + private void checkBalancedMonitors(StructuredGraph graph, LoweringTool tool) { + if (VERIFY_BALANCED_MONITORS) { + NodeIterable nodes = graph.getNodes().filter(MonitorCounterNode.class); + if (nodes.isEmpty()) { + // Only insert the nodes if this is the first monitorenter being lowered. + JavaType returnType = initCounter.getMethod().getSignature().getReturnType(initCounter.getMethod().getDeclaringClass()); + StampPair returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false); + MethodCallTargetNode callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, initCounter.getMethod(), new ValueNode[0], returnStamp, null)); + InvokeNode invoke = graph.add(new InvokeNode(callTarget, 0)); + invoke.setStateAfter(graph.start().stateAfter()); + graph.addAfterFixed(graph.start(), invoke); + + StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod(), null); + InliningUtil.inline(invoke, inlineeGraph, false, null, null); + + List rets = graph.getNodes(ReturnNode.TYPE).snapshot(); + for (ReturnNode ret : rets) { + returnType = checkCounter.getMethod().getSignature().getReturnType(checkCounter.getMethod().getDeclaringClass()); + String msg = "unbalanced monitors in " + graph.method().format("%H.%n(%p)") + ", count = %d"; + ConstantNode errMsg = ConstantNode.forConstant(tool.getConstantReflection().forString(msg), providers.getMetaAccess(), graph); + returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false); + callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter.getMethod(), new ValueNode[]{errMsg}, returnStamp, null)); + invoke = graph.add(new InvokeNode(callTarget, 0)); + Bytecode code = new ResolvedJavaMethodBytecode(graph.method()); + FrameState stateAfter = new FrameState(null, code, BytecodeFrame.AFTER_BCI, new ValueNode[0], new ValueNode[0], 0, new ValueNode[0], null, false, false); + invoke.setStateAfter(graph.add(stateAfter)); + graph.addBeforeFixed(ret, invoke); + + Arguments args = new Arguments(checkCounter, graph.getGuardsStage(), tool.getLoweringStage()); + args.addConst("errMsg", msg); + inlineeGraph = template(args).copySpecializedGraph(); + InliningUtil.inline(invoke, inlineeGraph, false, null, null); + } + } + } + } + } + + public static final ForeignCallDescriptor MONITORENTER = new ForeignCallDescriptor("monitorenter", void.class, Object.class, Word.class); + public static final ForeignCallDescriptor MONITOREXIT = new ForeignCallDescriptor("monitorexit", void.class, Object.class, Word.class); + + @NodeIntrinsic(ForeignCallNode.class) + private static native void monitorenterStubC(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock); + + @NodeIntrinsic(ForeignCallNode.class) + public static native void monitorexitStubC(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock); + + /** + * Counters for the various paths for acquiring a lock. The counters whose names start with + * {@code "lock"} are mutually exclusive. The other counters are for paths that may be shared. + */ + public static final SnippetCounter.Group lockCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("MonitorEnters") : null; + public static final SnippetCounter lockBiasExisting = new SnippetCounter(lockCounters, "lock{bias:existing}", "bias-locked previously biased object"); + public static final SnippetCounter lockBiasAcquired = new SnippetCounter(lockCounters, "lock{bias:acquired}", "bias-locked newly biased object"); + public static final SnippetCounter lockBiasTransfer = new SnippetCounter(lockCounters, "lock{bias:transfer}", "bias-locked, biased transferred"); + public static final SnippetCounter lockCas = new SnippetCounter(lockCounters, "lock{cas}", "cas-locked an object"); + public static final SnippetCounter lockCasRecursive = new SnippetCounter(lockCounters, "lock{cas:recursive}", "cas-locked, recursive"); + public static final SnippetCounter lockStubEpochExpired = new SnippetCounter(lockCounters, "lock{stub:epoch-expired}", "stub-locked, epoch expired"); + public static final SnippetCounter lockStubRevoke = new SnippetCounter(lockCounters, "lock{stub:revoke}", "stub-locked, biased revoked"); + public static final SnippetCounter lockStubFailedCas = new SnippetCounter(lockCounters, "lock{stub:failed-cas}", "stub-locked, failed cas"); + + public static final SnippetCounter unbiasable = new SnippetCounter(lockCounters, "unbiasable", "object with unbiasable type"); + public static final SnippetCounter revokeBias = new SnippetCounter(lockCounters, "revokeBias", "object had bias revoked"); + + /** + * Counters for the various paths for releasing a lock. The counters whose names start with + * {@code "unlock"} are mutually exclusive. The other counters are for paths that may be shared. + */ + public static final SnippetCounter.Group unlockCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("MonitorExits") : null; + public static final SnippetCounter unlockBias = new SnippetCounter(unlockCounters, "unlock{bias}", "bias-unlocked an object"); + public static final SnippetCounter unlockCas = new SnippetCounter(unlockCounters, "unlock{cas}", "cas-unlocked an object"); + public static final SnippetCounter unlockCasRecursive = new SnippetCounter(unlockCounters, "unlock{cas:recursive}", "cas-unlocked an object, recursive"); + public static final SnippetCounter unlockStub = new SnippetCounter(unlockCounters, "unlock{stub}", "stub-unlocked an object"); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java 2016-12-07 13:50:42.558657890 -0800 @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2012, 2016, 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.replacements; + +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters; +import static org.graalvm.compiler.core.common.calc.UnsignedMath.belowThan; +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_ARRAY_KLASS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_WRITE_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_END_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_TOP_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayKlassOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayLengthOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.initializeObjectHeader; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.instanceHeaderSize; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.isInstanceKlassFullyInitialized; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeMask; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeShift; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeMask; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeShift; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadKlassFromObject; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.prototypeMarkWordOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readLayoutHelper; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabEnd; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabTop; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useBiasedLocking; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useTLAB; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOop; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeTlabTop; +import static org.graalvm.compiler.nodes.PiArrayNode.piArrayCast; +import static org.graalvm.compiler.nodes.PiNode.piCast; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; +import static org.graalvm.compiler.replacements.ReplacementsUtil.REPLACEMENTS_ASSERTIONS_ENABLED; +import static org.graalvm.compiler.replacements.ReplacementsUtil.staticAssert; +import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; +import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring; +import static org.graalvm.compiler.replacements.nodes.ExplodeLoopNode.explodeLoop; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; +import static jdk.vm.ci.hotspot.HotSpotMetaAccessProvider.computeArrayAllocationSize; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.hotspot.nodes.DimensionsNode; +import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode; +import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.PrefetchAllocateNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.debug.DynamicCounterNode; +import org.graalvm.compiler.nodes.debug.VerifyHeapNode; +import org.graalvm.compiler.nodes.extended.BranchProbabilityNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.extended.MembarNode; +import org.graalvm.compiler.nodes.java.DynamicNewArrayNode; +import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode; +import org.graalvm.compiler.nodes.java.NewArrayNode; +import org.graalvm.compiler.nodes.java.NewInstanceNode; +import org.graalvm.compiler.nodes.java.NewMultiArrayNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.replacements.ReplacementsUtil; +import org.graalvm.compiler.replacements.SnippetCounter; +import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.code.MemoryBarriers; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Snippets used for implementing NEW, ANEWARRAY and NEWARRAY. + */ +public class NewObjectSnippets implements Snippets { + + public static final LocationIdentity INIT_LOCATION = NamedLocationIdentity.mutable("Initialization"); + + enum ProfileContext { + AllocatingMethod, + InstanceOrArray, + AllocatedType, + AllocatedTypesInMethod, + Total + } + + @Fold + static String createName(String path, String typeContext) { + switch (HotspotSnippetsOptions.ProfileAllocationsContext.getValue()) { + case AllocatingMethod: + return ""; + case InstanceOrArray: + return path; + case AllocatedType: + case AllocatedTypesInMethod: + return typeContext; + case Total: + return "bytes"; + default: + throw GraalError.shouldNotReachHere(); + } + } + + @Fold + static boolean doProfile() { + return HotspotSnippetsOptions.ProfileAllocations.getValue(); + } + + @Fold + static boolean withContext() { + ProfileContext context = HotspotSnippetsOptions.ProfileAllocationsContext.getValue(); + return context == ProfileContext.AllocatingMethod || context == ProfileContext.AllocatedTypesInMethod; + } + + protected static void profileAllocation(String path, long size, String typeContext) { + if (doProfile()) { + String name = createName(path, typeContext); + + boolean context = withContext(); + DynamicCounterNode.counter(name, "number of bytes allocated", size, context); + DynamicCounterNode.counter(name, "number of allocations", 1, context); + } + } + + public static void emitPrefetchAllocate(Word address, boolean isArray) { + GraalHotSpotVMConfig config = config(INJECTED_VMCONFIG); + if (config.allocatePrefetchStyle > 0) { + // Insert a prefetch for each allocation only on the fast-path + // Generate several prefetch instructions. + int lines = isArray ? config.allocatePrefetchLines : config.allocateInstancePrefetchLines; + int stepSize = config.allocatePrefetchStepSize; + int distance = config.allocatePrefetchDistance; + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < lines; i++) { + PrefetchAllocateNode.prefetch(OffsetAddressNode.address(address, distance)); + distance += stepSize; + } + } + } + + @Snippet + public static Object allocateInstance(@ConstantParameter int size, KlassPointer hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, + @ConstantParameter boolean constantSize, @ConstantParameter String typeContext) { + Object result; + Word thread = registerAsWord(threadRegister); + Word top = readTlabTop(thread); + Word end = readTlabEnd(thread); + Word newTop = top.add(size); + if (useTLAB(INJECTED_VMCONFIG) && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { + writeTlabTop(thread, newTop); + emitPrefetchAllocate(newTop, false); + result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, true); + } else { + new_stub.inc(); + result = newInstance(HotSpotBackend.NEW_INSTANCE, hub); + } + profileAllocation("instance", size, typeContext); + return piCast(verifyOop(result), StampFactory.forNodeIntrinsic()); + } + + @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true) + public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub); + + @Snippet + public static Object allocateInstancePIC(@ConstantParameter int size, KlassPointer hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, + @ConstantParameter Register threadRegister, + @ConstantParameter boolean constantSize, @ConstantParameter String typeContext) { + // Klass must be initialized by the time the first instance is allocated, therefore we can + // just load it from the corresponding cell and avoid the resolution check. We have to use a + // fixed load though, to prevent it from floating above the initialization. + KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub); + return allocateInstance(size, picHub, prototypeMarkWord, fillContents, threadRegister, constantSize, typeContext); + } + + @Snippet + public static Object allocateInstanceDynamic(Class type, Class classClass, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) { + if (probability(SLOW_PATH_PROBABILITY, type == null || DynamicNewInstanceNode.throwsInstantiationException(type, classClass))) { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + + KlassPointer hub = ClassGetHubNode.readClass(type); + if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) { + if (probability(FAST_PATH_PROBABILITY, isInstanceKlassFullyInitialized(hub))) { + int layoutHelper = readLayoutHelper(hub); + /* + * src/share/vm/oops/klass.hpp: For instances, layout helper is a positive number, + * the instance size. This size is already passed through align_object_size and + * scaled to bytes. The low order bit is set if instances of this class cannot be + * allocated using the fastpath. + */ + if (probability(FAST_PATH_PROBABILITY, (layoutHelper & 1) == 0)) { + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION); + /* + * FIXME(je,ds): we should actually pass typeContext instead of "" but late + * binding of parameters is not yet supported by the GraphBuilderPlugin system. + */ + return allocateInstance(layoutHelper, hub, prototypeMarkWord, fillContents, threadRegister, false, ""); + } + } + } + return dynamicNewInstanceStub(type); + } + + /** + * Maximum array length for which fast path allocation is used. + */ + public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF; + + @Snippet + public static Object allocatePrimitiveArrayPIC(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize, + @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext) { + KlassPointer picHub = LoadConstantIndirectlyNode.loadKlass(hub); + return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false); + } + + @Snippet + public static Object allocateArrayPIC(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize, + @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext) { + KlassPointer picHub = ResolveConstantSnippets.resolveKlassConstant(hub); + return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false); + } + + @Snippet + public static Object allocateArray(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize, + @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext) { + Object result = allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false); + return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic()); + } + + private static Object allocateArrayImpl(KlassPointer hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, + @ConstantParameter Register threadRegister, + @ConstantParameter boolean maybeUnroll, String typeContext, boolean skipNegativeCheck) { + Object result; + int alignment = wordSize(); + int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); + Word thread = registerAsWord(threadRegister); + Word top = readTlabTop(thread); + Word end = readTlabEnd(thread); + Word newTop = top.add(allocationSize); + if (probability(FREQUENT_PROBABILITY, skipNegativeCheck || belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB(INJECTED_VMCONFIG) && + probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { + writeTlabTop(thread, newTop); + emitPrefetchAllocate(newTop, true); + newarray_loopInit.inc(); + result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, true); + } else { + result = newArray(HotSpotBackend.NEW_ARRAY, hub, length, fillContents); + } + profileAllocation("array", allocationSize, typeContext); + return result; + } + + @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true) + public static native Object newArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length, boolean fillContents); + + public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class); + public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class); + + @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true) + public static native Object dynamicNewArrayStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class elementType, int length); + + public static Object dynamicNewInstanceStub(Class elementType) { + return dynamicNewInstanceStubCall(DYNAMIC_NEW_INSTANCE, elementType); + } + + @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true) + public static native Object dynamicNewInstanceStubCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class elementType); + + @Snippet + public static Object allocateArrayDynamic(Class elementType, Class voidClass, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, + @ConstantParameter JavaKind knownElementKind, @ConstantParameter int knownLayoutHelper, Word prototypeMarkWord) { + Object result = allocateArrayDynamicImpl(elementType, voidClass, length, fillContents, threadRegister, knownElementKind, knownLayoutHelper, prototypeMarkWord); + return result; + } + + private static Object allocateArrayDynamicImpl(Class elementType, Class voidClass, int length, boolean fillContents, Register threadRegister, JavaKind knownElementKind, + int knownLayoutHelper, Word prototypeMarkWord) { + /* + * We only need the dynamic check for void when we have no static information from + * knownElementKind. + */ + staticAssert(knownElementKind != JavaKind.Void, "unsupported knownElementKind"); + if (knownElementKind == JavaKind.Illegal && probability(SLOW_PATH_PROBABILITY, elementType == null || DynamicNewArrayNode.throwsIllegalArgumentException(elementType, voidClass))) { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + + KlassPointer klass = loadKlassFromObject(elementType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION); + if (probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, klass.isNull() || length < 0)) { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + int layoutHelper = knownElementKind != JavaKind.Illegal ? knownLayoutHelper : readLayoutHelper(klass); + //@formatter:off + // from src/share/vm/oops/klass.hpp: + // + // For arrays, layout helper is a negative number, containing four + // distinct bytes, as follows: + // MSB:[tag, hsz, ebt, log2(esz)]:LSB + // where: + // tag is 0x80 if the elements are oops, 0xC0 if non-oops + // hsz is array header size in bytes (i.e., offset of first element) + // ebt is the BasicType of the elements + // esz is the element size in bytes + //@formatter:on + + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG); + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG); + + Object result = allocateArrayImpl(klass, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type", true); + return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic()); + } + + /** + * Calls the runtime stub for implementing MULTIANEWARRAY. + */ + @Snippet + public static Object newmultiarray(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) { + Word dims = DimensionsNode.allocaDimsArray(rank); + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < rank; i++) { + dims.writeInt(i * 4, dimensions[i], INIT_LOCATION); + } + return newArrayCall(HotSpotBackend.NEW_MULTI_ARRAY, hub, rank, dims); + } + + @Snippet + public static Object newmultiarrayPIC(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) { + KlassPointer hubPIC = ResolveConstantSnippets.resolveKlassConstant(hub); + return newmultiarray(hubPIC, rank, dimensions); + } + + @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true) + public static native Object newArrayCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int rank, Word dims); + + /** + * Maximum number of long stores to emit when zeroing an object with a constant size. Larger + * objects have their bodies initialized in a loop. + */ + private static final int MAX_UNROLLED_OBJECT_ZEROING_STORES = 8; + + /** + * Zero uninitialized memory in a newly allocated object, unrolling as necessary and ensuring + * that stores are aligned. + * + * @param size number of bytes to zero + * @param memory beginning of object which is being zeroed + * @param constantSize is {@code size} known to be constant in the snippet + * @param startOffset offset to begin zeroing. May not be word aligned. + * @param manualUnroll maximally unroll zeroing + */ + private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) { + fillMemory(0, size, memory, constantSize, startOffset, manualUnroll, useSnippetCounters); + } + + private static void fillMemory(long value, int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) { + ReplacementsUtil.runtimeAssert((size & 0x7) == 0, "unaligned object size"); + int offset = startOffset; + if ((offset & 0x7) != 0) { + memory.writeInt(offset, (int) value, INIT_LOCATION); + offset += 4; + } + ReplacementsUtil.runtimeAssert((offset & 0x7) == 0, "unaligned offset"); + if (manualUnroll && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) { + ReplacementsUtil.staticAssert(!constantSize, "size shouldn't be constant at instantiation time"); + // This case handles arrays of constant length. Instead of having a snippet variant for + // each length, generate a chain of stores of maximum length. Once it's inlined the + // break statement will trim excess stores. + if (useSnippetCounters) { + new_seqInit.inc(); + } + explodeLoop(); + for (int i = 0; i < MAX_UNROLLED_OBJECT_ZEROING_STORES; i++, offset += 8) { + if (offset == size) { + break; + } + memory.initializeLong(offset, value, INIT_LOCATION); + } + } else { + // Use Word instead of int to avoid extension to long in generated code + Word off = Word.signed(offset); + if (constantSize && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) { + if (useSnippetCounters) { + new_seqInit.inc(); + } + explodeLoop(); + } else { + if (useSnippetCounters) { + new_loopInit.inc(); + } + } + for (; off.rawValue() < size; off = off.add(8)) { + memory.initializeLong(off, value, INIT_LOCATION); + } + } + } + + /** + * Fill uninitialized memory with garbage value in a newly allocated object, unrolling as + * necessary and ensuring that stores are aligned. + * + * @param size number of bytes to zero + * @param memory beginning of object which is being zeroed + * @param constantSize is {@code size} known to be constant in the snippet + * @param startOffset offset to begin zeroing. May not be word aligned. + * @param manualUnroll maximally unroll zeroing + */ + private static void fillWithGarbage(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) { + fillMemory(0xfefefefefefefefeL, size, memory, constantSize, startOffset, manualUnroll, useSnippetCounters); + } + + /** + * Formats some allocated memory with an object header and zeroes out the rest. Disables asserts + * since they can't be compiled in stubs. + */ + public static Object formatObjectForStub(KlassPointer hub, int size, Word memory, Word compileTimePrototypeMarkWord) { + return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, false); + } + + /** + * Formats some allocated memory with an object header and zeroes out the rest. + */ + protected static Object formatObject(KlassPointer hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, boolean useSnippetCounters) { + Word prototypeMarkWord = useBiasedLocking(INJECTED_VMCONFIG) ? hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord; + initializeObjectHeader(memory, prototypeMarkWord, hub); + if (fillContents) { + zeroMemory(size, memory, constantSize, instanceHeaderSize(INJECTED_VMCONFIG), false, useSnippetCounters); + } else if (REPLACEMENTS_ASSERTIONS_ENABLED) { + fillWithGarbage(size, memory, constantSize, instanceHeaderSize(INJECTED_VMCONFIG), false, useSnippetCounters); + } + MembarNode.memoryBarrier(MemoryBarriers.STORE_STORE, INIT_LOCATION); + return memory.toObject(); + } + + @Snippet + protected static void verifyHeap(@ConstantParameter Register threadRegister) { + Word thread = registerAsWord(threadRegister); + Word topValue = readTlabTop(thread); + if (!topValue.equal(Word.zero())) { + Word topValueContents = topValue.readWord(0, MARK_WORD_LOCATION); + if (topValueContents.equal(Word.zero())) { + AssertionSnippets.vmMessageC(AssertionSnippets.ASSERTION_VM_MESSAGE_C, true, cstring("overzeroing of TLAB detected"), 0L, 0L, 0L); + } + } + } + + /** + * Formats some allocated memory with an object header and zeroes out the rest. + */ + public static Object formatArray(KlassPointer hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll, + boolean useSnippetCounters) { + memory.writeInt(arrayLengthOffset(INJECTED_VMCONFIG), length, INIT_LOCATION); + /* + * store hub last as the concurrent garbage collectors assume length is valid if hub field + * is not null + */ + initializeObjectHeader(memory, prototypeMarkWord, hub); + if (fillContents) { + zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, useSnippetCounters); + } else if (REPLACEMENTS_ASSERTIONS_ENABLED) { + fillWithGarbage(allocationSize, memory, false, headerSize, maybeUnroll, useSnippetCounters); + } + MembarNode.memoryBarrier(MemoryBarriers.STORE_STORE, INIT_LOCATION); + return memory.toObject(); + } + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo allocateInstance = snippet(NewObjectSnippets.class, "allocateInstance", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + private final SnippetInfo allocateInstancePIC = snippet(NewObjectSnippets.class, "allocateInstancePIC", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, + TLAB_END_LOCATION); + private final SnippetInfo allocateArray = snippet(NewObjectSnippets.class, "allocateArray", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + private final SnippetInfo allocateArrayPIC = snippet(NewObjectSnippets.class, "allocateArrayPIC", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + private final SnippetInfo allocatePrimitiveArrayPIC = snippet(NewObjectSnippets.class, "allocatePrimitiveArrayPIC", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, + TLAB_END_LOCATION); + private final SnippetInfo allocateArrayDynamic = snippet(NewObjectSnippets.class, "allocateArrayDynamic", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, + TLAB_END_LOCATION); + private final SnippetInfo allocateInstanceDynamic = snippet(NewObjectSnippets.class, "allocateInstanceDynamic", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, + TLAB_END_LOCATION); + private final SnippetInfo newmultiarray = snippet(NewObjectSnippets.class, "newmultiarray", INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + private final SnippetInfo newmultiarrayPIC = snippet(NewObjectSnippets.class, "newmultiarrayPIC", INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + private final SnippetInfo verifyHeap = snippet(NewObjectSnippets.class, "verifyHeap"); + private final GraalHotSpotVMConfig config; + + public Templates(HotSpotProviders providers, TargetDescription target, GraalHotSpotVMConfig config) { + super(providers, providers.getSnippetReflection(), target); + this.config = config; + } + + /** + * Lowers a {@link NewInstanceNode}. + */ + public void lower(NewInstanceNode newInstanceNode, HotSpotRegistersProvider registers, LoweringTool tool) { + StructuredGraph graph = newInstanceNode.graph(); + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass(); + assert !type.isArray(); + ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), graph); + int size = instanceSize(type); + + SnippetInfo snippet = GeneratePIC.getValue() ? allocateInstancePIC : allocateInstance; + Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + args.addConst("size", size); + args.add("hub", hub); + args.add("prototypeMarkWord", type.prototypeMarkWord()); + args.addConst("fillContents", newInstanceNode.fillContents()); + args.addConst("threadRegister", registers.getThreadRegister()); + args.addConst("constantSize", true); + args.addConst("typeContext", HotspotSnippetsOptions.ProfileAllocations.getValue() ? type.toJavaName(false) : ""); + + SnippetTemplate template = template(args); + Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args); + template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args); + } + + /** + * Lowers a {@link NewArrayNode}. + */ + public void lower(NewArrayNode newArrayNode, HotSpotRegistersProvider registers, LoweringTool tool) { + StructuredGraph graph = newArrayNode.graph(); + ResolvedJavaType elementType = newArrayNode.elementType(); + HotSpotResolvedObjectType arrayType = (HotSpotResolvedObjectType) elementType.getArrayClass(); + JavaKind elementKind = elementType.getJavaKind(); + ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), arrayType.klass(), providers.getMetaAccess(), graph); + final int headerSize = getArrayBaseOffset(elementKind); + int log2ElementSize = CodeUtil.log2(HotSpotJVMCIRuntimeProvider.getArrayIndexScale(elementKind)); + + SnippetInfo snippet; + if (GeneratePIC.getValue()) { + if (elementType.isPrimitive()) { + snippet = allocatePrimitiveArrayPIC; + } else { + snippet = allocateArrayPIC; + } + } else { + snippet = allocateArray; + } + + Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("hub", hub); + ValueNode length = newArrayNode.length(); + args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); + assert arrayType.prototypeMarkWord() == lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord() : "all array types are assumed to have the same prototypeMarkWord"; + args.add("prototypeMarkWord", arrayType.prototypeMarkWord()); + args.addConst("headerSize", headerSize); + args.addConst("log2ElementSize", log2ElementSize); + args.addConst("fillContents", newArrayNode.fillContents()); + args.addConst("threadRegister", registers.getThreadRegister()); + args.addConst("maybeUnroll", length.isConstant()); + args.addConst("typeContext", HotspotSnippetsOptions.ProfileAllocations.getValue() ? arrayType.toJavaName(false) : ""); + SnippetTemplate template = template(args); + Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args); + template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args); + } + + public void lower(DynamicNewInstanceNode newInstanceNode, HotSpotRegistersProvider registers, LoweringTool tool) { + Arguments args = new Arguments(allocateInstanceDynamic, newInstanceNode.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("type", newInstanceNode.getInstanceType()); + ValueNode classClass = newInstanceNode.getClassClass(); + assert classClass != null; + args.add("classClass", classClass); + args.addConst("fillContents", newInstanceNode.fillContents()); + args.addConst("threadRegister", registers.getThreadRegister()); + + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args); + } + + public void lower(DynamicNewArrayNode newArrayNode, HotSpotRegistersProvider registers, LoweringTool tool) { + StructuredGraph graph = newArrayNode.graph(); + Arguments args = new Arguments(allocateArrayDynamic, newArrayNode.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("elementType", newArrayNode.getElementType()); + ValueNode voidClass = newArrayNode.getVoidClass(); + assert voidClass != null; + args.add("voidClass", voidClass); + ValueNode length = newArrayNode.length(); + args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); + args.addConst("fillContents", newArrayNode.fillContents()); + args.addConst("threadRegister", registers.getThreadRegister()); + /* + * We use Kind.Illegal as a marker value instead of null because constant snippet + * parameters cannot be null. + */ + args.addConst("knownElementKind", newArrayNode.getKnownElementKind() == null ? JavaKind.Illegal : newArrayNode.getKnownElementKind()); + if (newArrayNode.getKnownElementKind() != null) { + args.addConst("knownLayoutHelper", lookupArrayClass(tool, newArrayNode.getKnownElementKind()).layoutHelper()); + } else { + args.addConst("knownLayoutHelper", 0); + } + args.add("prototypeMarkWord", lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord()); + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args); + } + + private static HotSpotResolvedObjectType lookupArrayClass(LoweringTool tool, JavaKind kind) { + return (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(kind == JavaKind.Object ? Object.class : kind.toJavaClass()).getArrayClass(); + } + + public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) { + StructuredGraph graph = newmultiarrayNode.graph(); + int rank = newmultiarrayNode.dimensionCount(); + ValueNode[] dims = new ValueNode[rank]; + for (int i = 0; i < newmultiarrayNode.dimensionCount(); i++) { + dims[i] = newmultiarrayNode.dimension(i); + } + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newmultiarrayNode.type(); + ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), graph); + + SnippetInfo snippet = GeneratePIC.getValue() ? newmultiarrayPIC : newmultiarray; + Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("hub", hub); + args.addConst("rank", rank); + args.addVarargs("dimensions", int.class, StampFactory.forKind(JavaKind.Int), dims); + template(args).instantiate(providers.getMetaAccess(), newmultiarrayNode, DEFAULT_REPLACER, args); + } + + private static int instanceSize(HotSpotResolvedObjectType type) { + int size = type.instanceSize(); + assert size >= 0; + return size; + } + + public void lower(VerifyHeapNode verifyHeapNode, HotSpotRegistersProvider registers, LoweringTool tool) { + if (config.cAssertions) { + Arguments args = new Arguments(verifyHeap, verifyHeapNode.graph().getGuardsStage(), tool.getLoweringStage()); + args.addConst("threadRegister", registers.getThreadRegister()); + + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), verifyHeapNode, DEFAULT_REPLACER, args); + } else { + GraphUtil.removeFixedWithUnusedInputs(verifyHeapNode); + } + } + } + + private static final SnippetCounter.Group countersNew = SnippetCounters.getValue() ? new SnippetCounter.Group("NewInstance") : null; + private static final SnippetCounter new_seqInit = new SnippetCounter(countersNew, "tlabSeqInit", "TLAB alloc with unrolled zeroing"); + private static final SnippetCounter new_loopInit = new SnippetCounter(countersNew, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); + private static final SnippetCounter new_stub = new SnippetCounter(countersNew, "stub", "alloc and zeroing via stub"); + + private static final SnippetCounter.Group countersNewArray = SnippetCounters.getValue() ? new SnippetCounter.Group("NewArray") : null; + private static final SnippetCounter newarray_loopInit = new SnippetCounter(countersNewArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); + private static final SnippetCounter newarray_stub = new SnippetCounter(countersNewArray, "stub", "alloc and zeroing via stub"); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java 2016-12-07 13:50:42.824669582 -0800 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2013, 2015, 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.replacements; + +import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; + +import java.lang.reflect.Method; + +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.java.LoadFieldNode; +import org.graalvm.compiler.nodes.java.NewInstanceNode; +import org.graalvm.compiler.nodes.java.StoreFieldNode; +import org.graalvm.compiler.nodes.spi.ArrayLengthProvider; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.spi.Replacements; +import org.graalvm.compiler.nodes.spi.VirtualizableAllocation; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.replacements.nodes.BasicObjectCloneNode; + +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +@NodeInfo +public final class ObjectCloneNode extends BasicObjectCloneNode implements VirtualizableAllocation, ArrayLengthProvider { + + public static final NodeClass TYPE = NodeClass.create(ObjectCloneNode.class); + + public ObjectCloneNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode receiver) { + super(TYPE, invokeKind, targetMethod, bci, returnStamp, receiver); + } + + @Override + @SuppressWarnings("try") + protected StructuredGraph getLoweredSnippetGraph(LoweringTool tool) { + ResolvedJavaType type = StampTool.typeOrNull(getObject()); + if (type != null) { + if (type.isArray()) { + Method method = ObjectCloneSnippets.arrayCloneMethods.get(type.getComponentType().getJavaKind()); + if (method != null) { + final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(method); + final Replacements replacements = tool.getReplacements(); + StructuredGraph snippetGraph = null; + try (Scope s = Debug.scope("ArrayCloneSnippet", snippetMethod)) { + snippetGraph = replacements.getSnippet(snippetMethod, null); + } catch (Throwable e) { + throw Debug.handle(e); + } + + assert snippetGraph != null : "ObjectCloneSnippets should be installed"; + return lowerReplacement((StructuredGraph) snippetGraph.copy(), tool); + } + assert false : "unhandled array type " + type.getComponentType().getJavaKind(); + } else { + Assumptions assumptions = graph().getAssumptions(); + type = getConcreteType(getObject().stamp()); + if (type != null) { + StructuredGraph newGraph = new StructuredGraph(AllowAssumptions.from(assumptions != null), INVALID_COMPILATION_ID); + ParameterNode param = newGraph.addWithoutUnique(new ParameterNode(0, StampPair.createSingle(getObject().stamp()))); + NewInstanceNode newInstance = newGraph.add(new NewInstanceNode(type, true)); + newGraph.addAfterFixed(newGraph.start(), newInstance); + ReturnNode returnNode = newGraph.add(new ReturnNode(newInstance)); + newGraph.addAfterFixed(newInstance, returnNode); + + for (ResolvedJavaField field : type.getInstanceFields(true)) { + LoadFieldNode load = newGraph.add(LoadFieldNode.create(newGraph.getAssumptions(), param, field)); + newGraph.addBeforeFixed(returnNode, load); + newGraph.addBeforeFixed(returnNode, newGraph.add(new StoreFieldNode(newInstance, field, load))); + } + return lowerReplacement(newGraph, tool); + } + } + } + return null; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneSnippets.java 2016-12-07 13:50:43.091681318 -0800 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2011, 2015, 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.replacements; + +import java.lang.reflect.Method; +import java.util.EnumMap; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyCallNode; +import org.graalvm.compiler.nodes.java.DynamicNewArrayNode; +import org.graalvm.compiler.nodes.java.NewArrayNode; +import org.graalvm.compiler.replacements.Snippets; + +import jdk.vm.ci.meta.JavaKind; + +public class ObjectCloneSnippets implements Snippets { + + public static final EnumMap arrayCloneMethods = new EnumMap<>(JavaKind.class); + + static { + arrayCloneMethods.put(JavaKind.Boolean, getCloneMethod("booleanArrayClone", boolean[].class)); + arrayCloneMethods.put(JavaKind.Byte, getCloneMethod("byteArrayClone", byte[].class)); + arrayCloneMethods.put(JavaKind.Char, getCloneMethod("charArrayClone", char[].class)); + arrayCloneMethods.put(JavaKind.Short, getCloneMethod("shortArrayClone", short[].class)); + arrayCloneMethods.put(JavaKind.Int, getCloneMethod("intArrayClone", int[].class)); + arrayCloneMethods.put(JavaKind.Float, getCloneMethod("floatArrayClone", float[].class)); + arrayCloneMethods.put(JavaKind.Long, getCloneMethod("longArrayClone", long[].class)); + arrayCloneMethods.put(JavaKind.Double, getCloneMethod("doubleArrayClone", double[].class)); + arrayCloneMethods.put(JavaKind.Object, getCloneMethod("objectArrayClone", Object[].class)); + } + + private static Method getCloneMethod(String name, Class param) { + try { + return ObjectCloneSnippets.class.getDeclaredMethod(name, param); + } catch (SecurityException | NoSuchMethodException e) { + throw new GraalError(e); + } + } + + @Snippet + public static boolean[] booleanArrayClone(boolean[] src) { + boolean[] result = (boolean[]) NewArrayNode.newUninitializedArray(Boolean.TYPE, src.length); + ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Boolean); + return result; + } + + @Snippet + public static byte[] byteArrayClone(byte[] src) { + byte[] result = (byte[]) NewArrayNode.newUninitializedArray(Byte.TYPE, src.length); + ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Byte); + return result; + } + + @Snippet + public static short[] shortArrayClone(short[] src) { + short[] result = (short[]) NewArrayNode.newUninitializedArray(Short.TYPE, src.length); + ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Short); + return result; + } + + @Snippet + public static char[] charArrayClone(char[] src) { + char[] result = (char[]) NewArrayNode.newUninitializedArray(Character.TYPE, src.length); + ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Char); + return result; + } + + @Snippet + public static int[] intArrayClone(int[] src) { + int[] result = (int[]) NewArrayNode.newUninitializedArray(Integer.TYPE, src.length); + ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Int); + return result; + } + + @Snippet + public static float[] floatArrayClone(float[] src) { + float[] result = (float[]) NewArrayNode.newUninitializedArray(Float.TYPE, src.length); + ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Float); + return result; + } + + @Snippet + public static long[] longArrayClone(long[] src) { + long[] result = (long[]) NewArrayNode.newUninitializedArray(Long.TYPE, src.length); + ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Long); + return result; + } + + @Snippet + public static double[] doubleArrayClone(double[] src) { + double[] result = (double[]) NewArrayNode.newUninitializedArray(Double.TYPE, src.length); + ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Double); + return result; + } + + @Snippet + public static Object[] objectArrayClone(Object[] src) { + /* Since this snippet is lowered early the array must be initialized */ + Object[] result = (Object[]) DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(src.getClass().getComponentType()), src.length, JavaKind.Object); + ArrayCopyCallNode.disjointUninitializedArraycopy(src, 0, result, 0, src.length, JavaKind.Object); + return result; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java 2016-12-07 13:50:43.356692966 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, 2016, 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.replacements; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; + +// JaCoCo Exclude + +/** + * Substitutions for {@link java.lang.Object} methods. + */ +@ClassSubstitution(Object.class) +public class ObjectSubstitutions { + + @MethodSubstitution(isStatic = false) + public static int hashCode(final Object thisObj) { + return IdentityHashCodeNode.identityHashCode(thisObj); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java 2016-12-07 13:50:43.623704702 -0800 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013, 2015, 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.replacements; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20; + +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.nodes.MacroStateSplitNode; + +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "This node can be lowered to a call", size = SIZE_20) +public final class ReflectionGetCallerClassNode extends MacroStateSplitNode implements Canonicalizable, Lowerable { + + public static final NodeClass TYPE = NodeClass.create(ReflectionGetCallerClassNode.class); + + public ReflectionGetCallerClassNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) { + super(TYPE, invokeKind, targetMethod, bci, returnStamp, arguments); + } + + @Override + public Node canonical(CanonicalizerTool tool) { + ConstantNode callerClassNode = getCallerClassNode(tool.getMetaAccess(), tool.getConstantReflection()); + if (callerClassNode != null) { + return callerClassNode; + } + return this; + } + + @Override + public void lower(LoweringTool tool) { + ConstantNode callerClassNode = getCallerClassNode(tool.getMetaAccess(), tool.getConstantReflection()); + + if (callerClassNode != null) { + graph().replaceFixedWithFloating(this, graph().addOrUniqueWithInputs(callerClassNode)); + } else { + InvokeNode invoke = createInvoke(); + graph().replaceFixedWithFixed(this, invoke); + invoke.lower(tool); + } + } + + /** + * If inlining is deep enough this method returns a {@link ConstantNode} of the caller class by + * walking the the stack. + * + * @param metaAccess + * @return ConstantNode of the caller class, or null + */ + private ConstantNode getCallerClassNode(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) { + // Walk back up the frame states to find the caller at the required depth. + FrameState state = stateAfter(); + + // Cf. JVM_GetCallerClass + // NOTE: Start the loop at depth 1 because the current frame state does + // not include the Reflection.getCallerClass() frame. + for (int n = 1; state != null; state = state.outerFrameState(), n++) { + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) state.getMethod(); + switch (n) { + case 0: + throw GraalError.shouldNotReachHere("current frame state does not include the Reflection.getCallerClass frame"); + case 1: + // Frame 0 and 1 must be caller sensitive (see JVM_GetCallerClass). + if (!method.isCallerSensitive()) { + return null; // bail-out; let JVM_GetCallerClass do the work + } + break; + default: + if (!method.ignoredBySecurityStackWalk()) { + // We have reached the desired frame; return the holder class. + HotSpotResolvedObjectType callerClass = method.getDeclaringClass(); + return ConstantNode.forConstant(constantReflection.asJavaClass(callerClass), metaAccess); + } + break; + } + } + return null; // bail-out; let JVM_GetCallerClass do the work + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionSubstitutions.java 2016-12-07 13:50:43.890716438 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.replacements; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_ACCESS_FLAGS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.jvmAccWrittenFlags; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassAccessFlagsOffset; + +import java.lang.reflect.Modifier; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.hotspot.word.KlassPointer; + +/** + * Substitutions for {@link sun.reflect.Reflection} methods. + */ +@ClassSubstitution(className = {"jdk.internal.reflect.Reflection", "sun.reflect.Reflection"}, optional = true) +public class ReflectionSubstitutions { + + @MethodSubstitution + public static int getClassAccessFlags(Class aClass) { + KlassPointer klass = ClassGetHubNode.readClass(GraalDirectives.guardingNonNull(aClass)); + if (klass.isNull()) { + // Class for primitive type + return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; + } else { + return klass.readInt(klassAccessFlagsOffset(INJECTED_VMCONFIG), KLASS_ACCESS_FLAGS_LOCATION) & jvmAccWrittenFlags(INJECTED_VMCONFIG); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java 2016-12-07 13:50:44.155728086 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016, 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.replacements; + +import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.extended.UnsafeLoadNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.JavaKind; + +@ClassSubstitution(className = "sun.security.provider.SHA2", optional = true) +public class SHA2Substitutions { + + static final long stateOffset; + + static final Class shaClass; + + public static final String implCompressName = Java8OrEarlier ? "implCompress" : "implCompress0"; + + static { + try { + // Need to use the system class loader as com.sun.crypto.provider.AESCrypt + // is normally loaded by the extension class loader which is not delegated + // to by the JVMCI class loader. + ClassLoader cl = ClassLoader.getSystemClassLoader(); + shaClass = Class.forName("sun.security.provider.SHA2", true, cl); + stateOffset = UnsafeAccess.UNSAFE.objectFieldOffset(shaClass.getDeclaredField("state")); + } catch (Exception ex) { + throw new GraalError(ex); + } + } + + @MethodSubstitution(isStatic = false) + static void implCompress0(Object receiver, byte[] buf, int ofs) { + Object realReceiver = PiNode.piCastNonNull(receiver, shaClass); + Object state = UnsafeLoadNode.load(realReceiver, stateOffset, JavaKind.Object, LocationIdentity.any()); + Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs)); + Word stateAddr = Word.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int))); + HotSpotBackend.sha2ImplCompressStub(bufAddr, stateAddr); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java 2016-12-07 13:50:44.420739734 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016, 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.replacements; + +import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.extended.UnsafeLoadNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.JavaKind; + +@ClassSubstitution(className = "sun.security.provider.SHA5", optional = true) +public class SHA5Substitutions { + + static final long stateOffset; + + static final Class shaClass; + + public static final String implCompressName = Java8OrEarlier ? "implCompress" : "implCompress0"; + + static { + try { + // Need to use the system class loader as com.sun.crypto.provider.AESCrypt + // is normally loaded by the extension class loader which is not delegated + // to by the JVMCI class loader. + ClassLoader cl = ClassLoader.getSystemClassLoader(); + shaClass = Class.forName("sun.security.provider.SHA5", true, cl); + stateOffset = UnsafeAccess.UNSAFE.objectFieldOffset(shaClass.getDeclaredField("state")); + } catch (Exception ex) { + throw new GraalError(ex); + } + } + + @MethodSubstitution(isStatic = false) + static void implCompress0(Object receiver, byte[] buf, int ofs) { + Object realReceiver = PiNode.piCastNonNull(receiver, shaClass); + Object state = UnsafeLoadNode.load(realReceiver, stateOffset, JavaKind.Object, LocationIdentity.any()); + Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs)); + Word stateAddr = Word.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int))); + HotSpotBackend.sha5ImplCompressStub(bufAddr, stateAddr); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java 2016-12-07 13:50:44.685751382 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016, 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.replacements; + +import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.extended.UnsafeLoadNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.JavaKind; + +@ClassSubstitution(className = "sun.security.provider.SHA", optional = true) +public class SHASubstitutions { + + static final long stateOffset; + + static final Class shaClass; + + public static final String implCompressName = Java8OrEarlier ? "implCompress" : "implCompress0"; + + static { + try { + // Need to use the system class loader as com.sun.crypto.provider.AESCrypt + // is normally loaded by the extension class loader which is not delegated + // to by the JVMCI class loader. + ClassLoader cl = ClassLoader.getSystemClassLoader(); + shaClass = Class.forName("sun.security.provider.SHA", true, cl); + stateOffset = UnsafeAccess.UNSAFE.objectFieldOffset(shaClass.getDeclaredField("state")); + } catch (Exception ex) { + throw new GraalError(ex); + } + } + + @MethodSubstitution(isStatic = false) + static void implCompress0(Object receiver, byte[] buf, int ofs) { + Object realReceiver = PiNode.piCastNonNull(receiver, shaClass); + Object state = UnsafeLoadNode.load(realReceiver, stateOffset, JavaKind.Object, LocationIdentity.any()); + Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs)); + Word stateAddr = Word.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int))); + HotSpotBackend.shaImplCompressStub(bufAddr, stateAddr); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java 2016-12-07 13:50:44.950763030 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012, 2016, 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.replacements; + +import static org.graalvm.compiler.hotspot.replacements.UnsafeAccess.UNSAFE; +import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.debug.StringToBytesNode; +import org.graalvm.compiler.nodes.java.NewArrayNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.replacements.nodes.CStringConstant; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.JavaKind; + +/** + * The {@code StringToBytesSnippets} contains a snippet for lowering {@link StringToBytesNode}. + */ +public class StringToBytesSnippets implements Snippets { + + public static final LocationIdentity CSTRING_LOCATION = NamedLocationIdentity.immutable("CString location"); + + @Fold + static long arrayBaseOffset() { + return UNSAFE.arrayBaseOffset(char[].class); + } + + @Snippet + public static byte[] transform(@ConstantParameter String compilationTimeString) { + int i = compilationTimeString.length(); + byte[] array = (byte[]) NewArrayNode.newUninitializedArray(byte.class, i); + Word cArray = CStringConstant.cstring(compilationTimeString); + while (i-- > 0) { + // array[i] = cArray.readByte(i); + UNSAFE.putByte(array, arrayBaseOffset() + i, cArray.readByte(i, CSTRING_LOCATION)); + } + return array; + } + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo create; + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + create = snippet(StringToBytesSnippets.class, "transform", NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); + } + + public void lower(StringToBytesNode stringToBytesNode, LoweringTool tool) { + Arguments args = new Arguments(create, stringToBytesNode.graph().getGuardsStage(), tool.getLoweringStage()); + args.addConst("compilationTimeString", stringToBytesNode.getValue()); + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), stringToBytesNode, DEFAULT_REPLACER, args); + } + + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java 2016-12-07 13:50:45.216774722 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012, 2016, 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.replacements; + +import static org.graalvm.compiler.core.common.LocationIdentity.any; +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_OSTHREAD_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.osThreadInterruptedOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.osThreadOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.threadObjectOffset; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.word.Word; + +/** + * Substitutions for {@link java.lang.Thread} methods. + */ +@ClassSubstitution(Thread.class) +public class ThreadSubstitutions { + + @MethodSubstitution(isStatic = false) + public static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) { + Word javaThread = CurrentJavaThreadNode.get(); + Object thread = javaThread.readObject(threadObjectOffset(INJECTED_VMCONFIG), JAVA_THREAD_THREAD_OBJECT_LOCATION); + if (thisObject == thread) { + Word osThread = javaThread.readWord(osThreadOffset(INJECTED_VMCONFIG), JAVA_THREAD_OSTHREAD_LOCATION); + boolean interrupted = osThread.readInt(osThreadInterruptedOffset(INJECTED_VMCONFIG), any()) != 0; + if (!interrupted || !clearInterrupted) { + return interrupted; + } + } + + return threadIsInterruptedStub(THREAD_IS_INTERRUPTED, thisObject, clearInterrupted); + } + + public static final ForeignCallDescriptor THREAD_IS_INTERRUPTED = new ForeignCallDescriptor("thread_is_interrupted", boolean.class, Thread.class, boolean.class); + + @NodeIntrinsic(ForeignCallNode.class) + private static native boolean threadIsInterruptedStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Thread thread, boolean clearIsInterrupted); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/TypeCheckSnippetUtils.java 2016-12-07 13:50:45.485786546 -0800 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2013, 2014, 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.replacements; + +import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters; +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_SUPER_CHECK_OFFSET_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.METASPACE_ARRAY_LENGTH_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PRIMARY_SUPERS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.SECONDARY_SUPERS_ELEMENT_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.SECONDARY_SUPERS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.SECONDARY_SUPER_CACHE_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.metaspaceArrayBaseOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.metaspaceArrayLengthOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.secondarySuperCacheOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.secondarySupersOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.superCheckOffsetOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_LIKELY_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; + +import java.util.Arrays; + +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.TypeCheckHints; +import org.graalvm.compiler.replacements.SnippetCounter; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.MetaAccessProvider; + +//JaCoCo Exclude + +/** + * Utilities and common code paths used by the type check snippets. + */ +public class TypeCheckSnippetUtils { + + static boolean checkSecondarySubType(KlassPointer t, KlassPointer s) { + // if (S.cache == T) return true + if (s.readKlassPointer(secondarySuperCacheOffset(INJECTED_VMCONFIG), SECONDARY_SUPER_CACHE_LOCATION).equal(t)) { + cacheHit.inc(); + return true; + } + + return checkSelfAndSupers(t, s); + } + + static boolean checkUnknownSubType(KlassPointer t, KlassPointer s) { + // int off = T.offset + int superCheckOffset = t.readInt(superCheckOffsetOffset(INJECTED_VMCONFIG), KLASS_SUPER_CHECK_OFFSET_LOCATION); + boolean primary = superCheckOffset != secondarySuperCacheOffset(INJECTED_VMCONFIG); + + // if (T = S[off]) return true + if (s.readKlassPointer(superCheckOffset, PRIMARY_SUPERS_LOCATION).equal(t)) { + if (primary) { + cacheHit.inc(); + } else { + displayHit.inc(); + } + return true; + } + + // if (off != &cache) return false + if (primary) { + displayMiss.inc(); + return false; + } + + return checkSelfAndSupers(t, s); + } + + private static boolean checkSelfAndSupers(KlassPointer t, KlassPointer s) { + // if (T == S) return true + if (s.equal(t)) { + T_equals_S.inc(); + return true; + } + + // if (S.scan_s_s_array(T)) { S.cache = T; return true; } + Word secondarySupers = s.readWord(secondarySupersOffset(INJECTED_VMCONFIG), SECONDARY_SUPERS_LOCATION); + int length = secondarySupers.readInt(metaspaceArrayLengthOffset(INJECTED_VMCONFIG), METASPACE_ARRAY_LENGTH_LOCATION); + for (int i = 0; i < length; i++) { + if (probability(NOT_LIKELY_PROBABILITY, t.equal(loadSecondarySupersElement(secondarySupers, i)))) { + s.writeKlassPointer(secondarySuperCacheOffset(INJECTED_VMCONFIG), t, SECONDARY_SUPER_CACHE_LOCATION); + secondariesHit.inc(); + return true; + } + } + secondariesMiss.inc(); + return false; + } + + /** + * A set of type check hints ordered by decreasing probabilities. + */ + public static class Hints { + + /** + * The hubs of the hint types. + */ + public final ConstantNode[] hubs; + + /** + * A predicate over {@link #hubs} specifying whether the corresponding hint type is a + * sub-type of the checked type. + */ + public final boolean[] isPositive; + + Hints(ConstantNode[] hints, boolean[] hintIsPositive) { + this.hubs = hints; + this.isPositive = hintIsPositive; + } + } + + static Hints createHints(TypeCheckHints hints, MetaAccessProvider metaAccess, boolean positiveOnly, StructuredGraph graph) { + ConstantNode[] hubs = new ConstantNode[hints.hints.length]; + boolean[] isPositive = new boolean[hints.hints.length]; + int index = 0; + for (int i = 0; i < hubs.length; i++) { + if (!positiveOnly || hints.hints[i].positive) { + hubs[index] = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) hints.hints[i].type).klass(), metaAccess, graph); + isPositive[index] = hints.hints[i].positive; + index++; + } + } + if (positiveOnly && index != hubs.length) { + assert index < hubs.length; + hubs = Arrays.copyOf(hubs, index); + isPositive = Arrays.copyOf(isPositive, index); + } + return new Hints(hubs, isPositive); + } + + static KlassPointer loadSecondarySupersElement(Word metaspaceArray, int index) { + return KlassPointer.fromWord(metaspaceArray.readWord(metaspaceArrayBaseOffset(INJECTED_VMCONFIG) + index * wordSize(), SECONDARY_SUPERS_ELEMENT_LOCATION)); + } + + private static final SnippetCounter.Group counters = SnippetCounters.getValue() ? new SnippetCounter.Group("TypeCheck") : null; + static final SnippetCounter hintsHit = new SnippetCounter(counters, "hintsHit", "hit a hint type"); + static final SnippetCounter hintsMiss = new SnippetCounter(counters, "hintsMiss", "missed a hint type"); + static final SnippetCounter exactHit = new SnippetCounter(counters, "exactHit", "exact type test succeeded"); + static final SnippetCounter exactMiss = new SnippetCounter(counters, "exactMiss", "exact type test failed"); + static final SnippetCounter isNull = new SnippetCounter(counters, "isNull", "object tested was null"); + static final SnippetCounter cacheHit = new SnippetCounter(counters, "cacheHit", "secondary type cache hit"); + static final SnippetCounter secondariesHit = new SnippetCounter(counters, "secondariesHit", "secondaries scan succeeded"); + static final SnippetCounter secondariesMiss = new SnippetCounter(counters, "secondariesMiss", "secondaries scan failed"); + static final SnippetCounter displayHit = new SnippetCounter(counters, "displayHit", "primary type test succeeded"); + static final SnippetCounter displayMiss = new SnippetCounter(counters, "displayMiss", "primary type test failed"); + static final SnippetCounter T_equals_S = new SnippetCounter(counters, "T_equals_S", "object type was equal to secondary type"); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeAccess.java 2016-12-07 13:50:45.750798194 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2012, 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.replacements; + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + +/** + * Package private access to the {@link Unsafe} capability. + */ +class UnsafeAccess { + + static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + // Fast path when we are trusted. + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + // Slow path when we are not trusted. + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java 2016-12-07 13:50:46.014809798 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, 2015, 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.replacements; + +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.referentOffset; +import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode; +import org.graalvm.compiler.nodes.extended.UnsafeLoadNode; +import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.TargetDescription; + +public class UnsafeLoadSnippets implements Snippets { + + @Snippet + public static Object lowerUnsafeLoad(Object object, long offset) { + Object fixedObject = FixedValueAnchorNode.getObject(object); + if (object instanceof java.lang.ref.Reference && referentOffset() == offset) { + return Word.objectToTrackedPointer(fixedObject).readObject((int) offset, BarrierType.PRECISE); + } else { + return Word.objectToTrackedPointer(fixedObject).readObject((int) offset, BarrierType.NONE); + } + } + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo unsafeLoad = snippet(UnsafeLoadSnippets.class, "lowerUnsafeLoad"); + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + } + + public void lower(UnsafeLoadNode load, LoweringTool tool) { + Arguments args = new Arguments(unsafeLoad, load.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("object", load.object()); + args.add("offset", load.offset()); + template(args).instantiate(providers.getMetaAccess(), load, DEFAULT_REPLACER, args); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java 2016-12-07 13:50:46.280821490 -0800 @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2012, 2016, 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.replacements; + +import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters; +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.cardTableShift; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.dirtyCardValue; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1CardQueueBufferOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1CardQueueIndexOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueBufferOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueIndexOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueMarkingOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1YoungCardValue; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOop; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOops; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; +import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; +import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.CompressEncoding; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.hotspot.nodes.CompressionNode; +import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier; +import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode; +import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; +import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier; +import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.extended.MembarNode; +import org.graalvm.compiler.nodes.extended.NullCheckNode; +import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode.Address; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.Log; +import org.graalvm.compiler.replacements.SnippetCounter; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.replacements.nodes.DirectObjectStoreNode; +import org.graalvm.compiler.replacements.nodes.DirectStoreNode; +import org.graalvm.compiler.word.Pointer; +import org.graalvm.compiler.word.Unsigned; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.JavaKind; + +public class WriteBarrierSnippets implements Snippets { + + private static final SnippetCounter.Group countersWriteBarriers = SnippetCounters.getValue() ? new SnippetCounter.Group("WriteBarriers") : null; + private static final SnippetCounter serialWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialWriteBarrier", "Number of Serial Write Barriers"); + private static final SnippetCounter g1AttemptedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPreWriteBarrier", "Number of attempted G1 Pre Write Barriers"); + private static final SnippetCounter g1EffectivePreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectivePreWriteBarrier", "Number of effective G1 Pre Write Barriers"); + private static final SnippetCounter g1ExecutedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPreWriteBarrier", "Number of executed G1 Pre Write Barriers"); + private static final SnippetCounter g1AttemptedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPostWriteBarrier", "Number of attempted G1 Post Write Barriers"); + private static final SnippetCounter g1EffectiveAfterXORPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterXORPostWriteBarrier", + "Number of effective G1 Post Write Barriers (after passing the XOR test)"); + private static final SnippetCounter g1EffectiveAfterNullPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterNullPostWriteBarrier", + "Number of effective G1 Post Write Barriers (after passing the NULL test)"); + private static final SnippetCounter g1ExecutedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPostWriteBarrier", "Number of executed G1 Post Write Barriers"); + + public static final LocationIdentity GC_CARD_LOCATION = NamedLocationIdentity.mutable("GC-Card"); + public static final LocationIdentity GC_LOG_LOCATION = NamedLocationIdentity.mutable("GC-Log"); + public static final LocationIdentity GC_INDEX_LOCATION = NamedLocationIdentity.mutable("GC-Index"); + + private static void serialWriteBarrier(Pointer ptr) { + serialWriteBarrierCounter.inc(); + final long startAddress = GraalHotSpotVMConfigNode.cardTableAddress(); + Word base = (Word) ptr.unsignedShiftRight(cardTableShift(INJECTED_VMCONFIG)); + if (((int) startAddress) == startAddress && GraalHotSpotVMConfigNode.isCardTableAddressConstant()) { + base.writeByte((int) startAddress, (byte) 0, GC_CARD_LOCATION); + } else { + base.writeByte(Word.unsigned(startAddress), (byte) 0, GC_CARD_LOCATION); + } + } + + @Snippet + public static void serialImpreciseWriteBarrier(Object object) { + serialWriteBarrier(Word.objectToTrackedPointer(object)); + } + + @Snippet + public static void serialPreciseWriteBarrier(Address address) { + serialWriteBarrier(Word.fromAddress(address)); + } + + @Snippet + public static void serialArrayRangeWriteBarrier(Object object, int startIndex, int length) { + if (length == 0) { + return; + } + Object dest = FixedValueAnchorNode.getObject(object); + int cardShift = cardTableShift(INJECTED_VMCONFIG); + final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress(); + final int scale = arrayIndexScale(JavaKind.Object); + int header = arrayBaseOffset(JavaKind.Object); + long dstAddr = GetObjectAddressNode.get(dest); + long start = (dstAddr + header + (long) startIndex * scale) >>> cardShift; + long end = (dstAddr + header + ((long) startIndex + length - 1) * scale) >>> cardShift; + long count = end - start + 1; + while (count-- > 0) { + DirectStoreNode.storeBoolean((start + cardStart) + count, false, JavaKind.Boolean); + } + } + + @Snippet + public static void g1PreWriteBarrier(Address address, Object object, Object expectedObject, @ConstantParameter boolean doLoad, @ConstantParameter boolean nullCheck, + @ConstantParameter Register threadRegister, @ConstantParameter boolean trace) { + if (nullCheck) { + NullCheckNode.nullCheck(address); + } + Word thread = registerAsWord(threadRegister); + verifyOop(object); + Object fixedExpectedObject = FixedValueAnchorNode.getObject(expectedObject); + Pointer field = Word.fromAddress(address); + Pointer previousOop = Word.objectToTrackedPointer(fixedExpectedObject); + byte markingValue = thread.readByte(g1SATBQueueMarkingOffset(INJECTED_VMCONFIG)); + int gcCycle = 0; + if (trace) { + gcCycle = (int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG)).readLong(0); + log(trace, "[%d] G1-Pre Thread %p Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue()); + log(trace, "[%d] G1-Pre Thread %p Expected Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(fixedExpectedObject).rawValue()); + log(trace, "[%d] G1-Pre Thread %p Field %p\n", gcCycle, thread.rawValue(), field.rawValue()); + log(trace, "[%d] G1-Pre Thread %p Marking %d\n", gcCycle, thread.rawValue(), markingValue); + log(trace, "[%d] G1-Pre Thread %p DoLoad %d\n", gcCycle, thread.rawValue(), doLoad ? 1L : 0L); + } + g1AttemptedPreWriteBarrierCounter.inc(); + // If the concurrent marker is enabled, the barrier is issued. + if (probability(NOT_FREQUENT_PROBABILITY, markingValue != (byte) 0)) { + // If the previous value has to be loaded (before the write), the load is issued. + // The load is always issued except the cases of CAS and referent field. + if (probability(LIKELY_PROBABILITY, doLoad)) { + previousOop = Word.objectToTrackedPointer(field.readObject(0, BarrierType.NONE)); + if (trace) { + log(trace, "[%d] G1-Pre Thread %p Previous Object %p\n ", gcCycle, thread.rawValue(), previousOop.rawValue()); + verifyOop(previousOop.toObject()); + } + } + g1EffectivePreWriteBarrierCounter.inc(); + // If the previous value is null the barrier should not be issued. + if (probability(FREQUENT_PROBABILITY, previousOop.notEqual(0))) { + g1ExecutedPreWriteBarrierCounter.inc(); + // If the thread-local SATB buffer is full issue a native call which will + // initialize a new one and add the entry. + Word indexAddress = thread.add(g1SATBQueueIndexOffset(INJECTED_VMCONFIG)); + Word indexValue = indexAddress.readWord(0); + if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) { + Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset(INJECTED_VMCONFIG)); + Word nextIndex = indexValue.subtract(wordSize()); + Word logAddress = bufferAddress.add(nextIndex); + // Log the object to be marked as well as update the SATB's buffer next index. + logAddress.writeWord(0, previousOop, GC_LOG_LOCATION); + indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION); + } else { + g1PreBarrierStub(G1WBPRECALL, previousOop.toObject()); + } + } + } + } + + @Snippet + public static void g1PostWriteBarrier(Address address, Object object, Object value, @ConstantParameter boolean usePrecise, @ConstantParameter Register threadRegister, + @ConstantParameter boolean trace) { + Word thread = registerAsWord(threadRegister); + Object fixedValue = FixedValueAnchorNode.getObject(value); + verifyOop(object); + verifyOop(fixedValue); + validateObject(object, fixedValue); + Pointer oop; + if (usePrecise) { + oop = Word.fromAddress(address); + } else { + oop = Word.objectToTrackedPointer(object); + } + int gcCycle = 0; + if (trace) { + gcCycle = (int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG)).readLong(0); + log(trace, "[%d] G1-Post Thread: %p Object: %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue()); + log(trace, "[%d] G1-Post Thread: %p Field: %p\n", gcCycle, thread.rawValue(), oop.rawValue()); + } + Pointer writtenValue = Word.objectToTrackedPointer(fixedValue); + // The result of the xor reveals whether the installed pointer crosses heap regions. + // In case it does the write barrier has to be issued. + final int logOfHeapRegionGrainBytes = GraalHotSpotVMConfigNode.logOfHeapRegionGrainBytes(); + Unsigned xorResult = (oop.xor(writtenValue)).unsignedShiftRight(logOfHeapRegionGrainBytes); + + // Calculate the address of the card to be enqueued to the + // thread local card queue. + Unsigned cardBase = oop.unsignedShiftRight(cardTableShift(INJECTED_VMCONFIG)); + final long startAddress = GraalHotSpotVMConfigNode.cardTableAddress(); + int displacement = 0; + if (((int) startAddress) == startAddress && GraalHotSpotVMConfigNode.isCardTableAddressConstant()) { + displacement = (int) startAddress; + } else { + cardBase = cardBase.add(Word.unsigned(startAddress)); + } + Word cardAddress = (Word) cardBase.add(displacement); + + g1AttemptedPostWriteBarrierCounter.inc(); + if (probability(FREQUENT_PROBABILITY, xorResult.notEqual(0))) { + g1EffectiveAfterXORPostWriteBarrierCounter.inc(); + + // If the written value is not null continue with the barrier addition. + if (probability(FREQUENT_PROBABILITY, writtenValue.notEqual(0))) { + byte cardByte = cardAddress.readByte(0, GC_CARD_LOCATION); + g1EffectiveAfterNullPostWriteBarrierCounter.inc(); + + // If the card is already dirty, (hence already enqueued) skip the insertion. + if (probability(NOT_FREQUENT_PROBABILITY, cardByte != g1YoungCardValue(INJECTED_VMCONFIG))) { + MembarNode.memoryBarrier(STORE_LOAD, GC_CARD_LOCATION); + byte cardByteReload = cardAddress.readByte(0, GC_CARD_LOCATION); + if (probability(NOT_FREQUENT_PROBABILITY, cardByteReload != dirtyCardValue(INJECTED_VMCONFIG))) { + log(trace, "[%d] G1-Post Thread: %p Card: %p \n", gcCycle, thread.rawValue(), Word.unsigned(cardByte).rawValue()); + cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION); + g1ExecutedPostWriteBarrierCounter.inc(); + + // If the thread local card queue is full, issue a native call which will + // initialize a new one and add the card entry. + Word indexAddress = thread.add(g1CardQueueIndexOffset(INJECTED_VMCONFIG)); + Word indexValue = thread.readWord(g1CardQueueIndexOffset(INJECTED_VMCONFIG)); + if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) { + Word bufferAddress = thread.readWord(g1CardQueueBufferOffset(INJECTED_VMCONFIG)); + Word nextIndex = indexValue.subtract(wordSize()); + Word logAddress = bufferAddress.add(nextIndex); + // Log the object to be scanned as well as update + // the card queue's next index. + logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION); + indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION); + } else { + g1PostBarrierStub(G1WBPOSTCALL, cardAddress); + } + } + } + } + } + } + + @Snippet + public static void g1ArrayRangePreWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) { + Word thread = registerAsWord(threadRegister); + byte markingValue = thread.readByte(g1SATBQueueMarkingOffset(INJECTED_VMCONFIG)); + // If the concurrent marker is not enabled or the vector length is zero, return. + if (markingValue == (byte) 0 || length == 0) { + return; + } + Object dest = FixedValueAnchorNode.getObject(object); + Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset(INJECTED_VMCONFIG)); + Word indexAddress = thread.add(g1SATBQueueIndexOffset(INJECTED_VMCONFIG)); + long dstAddr = GetObjectAddressNode.get(dest); + long indexValue = indexAddress.readWord(0).rawValue(); + final int scale = arrayIndexScale(JavaKind.Object); + int header = arrayBaseOffset(JavaKind.Object); + + for (int i = startIndex; i < length; i++) { + long address = dstAddr + header + (i * scale); + Pointer oop = Word.objectToTrackedPointer(Word.unsigned(address).readObject(0, BarrierType.NONE)); + verifyOop(oop.toObject()); + if (oop.notEqual(0)) { + if (indexValue != 0) { + indexValue = indexValue - wordSize(); + Word logAddress = bufferAddress.add(Word.unsigned(indexValue)); + // Log the object to be marked as well as update the SATB's buffer next index. + logAddress.writeWord(0, oop, GC_LOG_LOCATION); + indexAddress.writeWord(0, Word.unsigned(indexValue), GC_INDEX_LOCATION); + } else { + g1PreBarrierStub(G1WBPRECALL, oop.toObject()); + } + } + } + } + + @Snippet + public static void g1ArrayRangePostWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) { + if (length == 0) { + return; + } + Object dest = FixedValueAnchorNode.getObject(object); + Word thread = registerAsWord(threadRegister); + Word bufferAddress = thread.readWord(g1CardQueueBufferOffset(INJECTED_VMCONFIG)); + Word indexAddress = thread.add(g1CardQueueIndexOffset(INJECTED_VMCONFIG)); + long indexValue = thread.readWord(g1CardQueueIndexOffset(INJECTED_VMCONFIG)).rawValue(); + + int cardShift = cardTableShift(INJECTED_VMCONFIG); + final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress(); + final int scale = arrayIndexScale(JavaKind.Object); + int header = arrayBaseOffset(JavaKind.Object); + long dstAddr = GetObjectAddressNode.get(dest); + long start = (dstAddr + header + (long) startIndex * scale) >>> cardShift; + long end = (dstAddr + header + ((long) startIndex + length - 1) * scale) >>> cardShift; + long count = end - start + 1; + + while (count-- > 0) { + Word cardAddress = Word.unsigned((start + cardStart) + count); + byte cardByte = cardAddress.readByte(0, GC_CARD_LOCATION); + // If the card is already dirty, (hence already enqueued) skip the insertion. + if (probability(NOT_FREQUENT_PROBABILITY, cardByte != g1YoungCardValue(INJECTED_VMCONFIG))) { + MembarNode.memoryBarrier(STORE_LOAD, GC_CARD_LOCATION); + byte cardByteReload = cardAddress.readByte(0, GC_CARD_LOCATION); + if (probability(NOT_FREQUENT_PROBABILITY, cardByteReload != dirtyCardValue(INJECTED_VMCONFIG))) { + cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION); + // If the thread local card queue is full, issue a native call which will + // initialize a new one and add the card entry. + if (indexValue != 0) { + indexValue = indexValue - wordSize(); + Word logAddress = bufferAddress.add(Word.unsigned(indexValue)); + // Log the object to be scanned as well as update + // the card queue's next index. + logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION); + indexAddress.writeWord(0, Word.unsigned(indexValue), GC_INDEX_LOCATION); + } else { + g1PostBarrierStub(G1WBPOSTCALL, cardAddress); + } + } + } + } + } + + public static final ForeignCallDescriptor G1WBPRECALL = new ForeignCallDescriptor("write_barrier_pre", void.class, Object.class); + + @NodeIntrinsic(ForeignCallNode.class) + private static native void g1PreBarrierStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object); + + public static final ForeignCallDescriptor G1WBPOSTCALL = new ForeignCallDescriptor("write_barrier_post", void.class, Word.class); + + @NodeIntrinsic(ForeignCallNode.class) + public static native void g1PostBarrierStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word card); + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo serialImpreciseWriteBarrier = snippet(WriteBarrierSnippets.class, "serialImpreciseWriteBarrier", GC_CARD_LOCATION); + private final SnippetInfo serialPreciseWriteBarrier = snippet(WriteBarrierSnippets.class, "serialPreciseWriteBarrier", GC_CARD_LOCATION); + private final SnippetInfo serialArrayRangeWriteBarrier = snippet(WriteBarrierSnippets.class, "serialArrayRangeWriteBarrier"); + private final SnippetInfo g1PreWriteBarrier = snippet(WriteBarrierSnippets.class, "g1PreWriteBarrier", GC_INDEX_LOCATION, GC_LOG_LOCATION); + private final SnippetInfo g1ReferentReadBarrier = snippet(WriteBarrierSnippets.class, "g1PreWriteBarrier", GC_INDEX_LOCATION, GC_LOG_LOCATION); + private final SnippetInfo g1PostWriteBarrier = snippet(WriteBarrierSnippets.class, "g1PostWriteBarrier", GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION); + private final SnippetInfo g1ArrayRangePreWriteBarrier = snippet(WriteBarrierSnippets.class, "g1ArrayRangePreWriteBarrier", GC_INDEX_LOCATION, GC_LOG_LOCATION); + private final SnippetInfo g1ArrayRangePostWriteBarrier = snippet(WriteBarrierSnippets.class, "g1ArrayRangePostWriteBarrier", GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION); + + private final CompressEncoding oopEncoding; + + public Templates(HotSpotProviders providers, TargetDescription target, CompressEncoding oopEncoding) { + super(providers, providers.getSnippetReflection(), target); + this.oopEncoding = oopEncoding; + } + + public void lower(SerialWriteBarrier writeBarrier, LoweringTool tool) { + Arguments args; + if (writeBarrier.usePrecise()) { + args = new Arguments(serialPreciseWriteBarrier, writeBarrier.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("address", writeBarrier.getAddress()); + } else { + args = new Arguments(serialImpreciseWriteBarrier, writeBarrier.graph().getGuardsStage(), tool.getLoweringStage()); + OffsetAddressNode address = (OffsetAddressNode) writeBarrier.getAddress(); + args.add("object", address.getBase()); + } + template(args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args); + } + + public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, LoweringTool tool) { + Arguments args = new Arguments(serialArrayRangeWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("object", arrayRangeWriteBarrier.getObject()); + args.add("startIndex", arrayRangeWriteBarrier.getStartIndex()); + args.add("length", arrayRangeWriteBarrier.getLength()); + template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); + } + + public void lower(G1PreWriteBarrier writeBarrierPre, HotSpotRegistersProvider registers, LoweringTool tool) { + Arguments args = new Arguments(g1PreWriteBarrier, writeBarrierPre.graph().getGuardsStage(), tool.getLoweringStage()); + AddressNode address = writeBarrierPre.getAddress(); + args.add("address", address); + if (address instanceof OffsetAddressNode) { + args.add("object", ((OffsetAddressNode) address).getBase()); + } else { + args.add("object", null); + } + + ValueNode expected = writeBarrierPre.getExpectedObject(); + if (expected != null && expected.stamp() instanceof NarrowOopStamp) { + assert oopEncoding != null; + expected = CompressionNode.uncompress(expected, oopEncoding); + } + args.add("expectedObject", expected); + + args.addConst("doLoad", writeBarrierPre.doLoad()); + args.addConst("nullCheck", writeBarrierPre.getNullCheck()); + args.addConst("threadRegister", registers.getThreadRegister()); + args.addConst("trace", traceBarrier()); + template(args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args); + } + + public void lower(G1ReferentFieldReadBarrier readBarrier, HotSpotRegistersProvider registers, LoweringTool tool) { + Arguments args = new Arguments(g1ReferentReadBarrier, readBarrier.graph().getGuardsStage(), tool.getLoweringStage()); + AddressNode address = readBarrier.getAddress(); + args.add("address", address); + if (address instanceof OffsetAddressNode) { + args.add("object", ((OffsetAddressNode) address).getBase()); + } else { + args.add("object", null); + } + + ValueNode expected = readBarrier.getExpectedObject(); + if (expected != null && expected.stamp() instanceof NarrowOopStamp) { + assert oopEncoding != null; + expected = CompressionNode.uncompress(expected, oopEncoding); + } + + args.add("expectedObject", expected); + args.addConst("doLoad", readBarrier.doLoad()); + args.addConst("nullCheck", false); + args.addConst("threadRegister", registers.getThreadRegister()); + args.addConst("trace", traceBarrier()); + template(args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args); + } + + public void lower(G1PostWriteBarrier writeBarrierPost, HotSpotRegistersProvider registers, LoweringTool tool) { + StructuredGraph graph = writeBarrierPost.graph(); + if (writeBarrierPost.alwaysNull()) { + graph.removeFixed(writeBarrierPost); + return; + } + Arguments args = new Arguments(g1PostWriteBarrier, graph.getGuardsStage(), tool.getLoweringStage()); + AddressNode address = writeBarrierPost.getAddress(); + args.add("address", address); + if (address instanceof OffsetAddressNode) { + args.add("object", ((OffsetAddressNode) address).getBase()); + } else { + assert writeBarrierPost.usePrecise() : "found imprecise barrier that's not an object access " + writeBarrierPost; + args.add("object", null); + } + + ValueNode value = writeBarrierPost.getValue(); + if (value.stamp() instanceof NarrowOopStamp) { + assert oopEncoding != null; + value = CompressionNode.uncompress(value, oopEncoding); + } + args.add("value", value); + + args.addConst("usePrecise", writeBarrierPost.usePrecise()); + args.addConst("threadRegister", registers.getThreadRegister()); + args.addConst("trace", traceBarrier()); + template(args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args); + } + + public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) { + Arguments args = new Arguments(g1ArrayRangePreWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("object", arrayRangeWriteBarrier.getObject()); + args.add("startIndex", arrayRangeWriteBarrier.getStartIndex()); + args.add("length", arrayRangeWriteBarrier.getLength()); + args.addConst("threadRegister", registers.getThreadRegister()); + template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); + } + + public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) { + Arguments args = new Arguments(g1ArrayRangePostWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("object", arrayRangeWriteBarrier.getObject()); + args.add("startIndex", arrayRangeWriteBarrier.getStartIndex()); + args.add("length", arrayRangeWriteBarrier.getLength()); + args.addConst("threadRegister", registers.getThreadRegister()); + template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); + } + } + + /** + * Log method of debugging purposes. + */ + public static void log(boolean enabled, String format, long value) { + if (enabled) { + Log.printf(format, value); + } + } + + public static void log(boolean enabled, String format, long value1, long value2) { + if (enabled) { + Log.printf(format, value1, value2); + } + } + + public static void log(boolean enabled, String format, long value1, long value2, long value3) { + if (enabled) { + Log.printf(format, value1, value2, value3); + } + } + + public static boolean traceBarrier() { + return GraalOptions.GCDebugStartCycle.getValue() > 0 && + ((int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG)).readLong(0) > GraalOptions.GCDebugStartCycle.getValue()); + } + + /** + * Validation helper method which performs sanity checks on write operations. The addresses of + * both the object and the value being written are checked in order to determine if they reside + * in a valid heap region. If an object is stale, an invalid access is performed in order to + * prematurely crash the VM and debug the stack trace of the faulty method. + */ + public static void validateObject(Object parent, Object child) { + if (verifyOops(INJECTED_VMCONFIG) && child != null && !validateOop(VALIDATE_OBJECT, parent, child)) { + log(true, "Verification ERROR, Parent: %p Child: %p\n", Word.objectToTrackedPointer(parent).rawValue(), Word.objectToTrackedPointer(child).rawValue()); + DirectObjectStoreNode.storeObject(null, 0, 0, null, LocationIdentity.any(), JavaKind.Object); + } + } + + public static final ForeignCallDescriptor VALIDATE_OBJECT = new ForeignCallDescriptor("validate_object", boolean.class, Word.class, Word.class); + + @NodeIntrinsic(ForeignCallNode.class) + private static native boolean validateOop(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object parent, Object object); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java 2016-12-07 13:50:46.547833226 -0800 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2016, 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.replacements.aot; + +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; +import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.aot.EncodedSymbolNode; +import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; +import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassStubCall; +import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; +import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersIndirectlyNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall; +import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.hotspot.word.MethodCountersPointer; +import org.graalvm.compiler.hotspot.word.MethodPointer; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.meta.Constant; + +public class ResolveConstantSnippets implements Snippets { + + @Snippet + public static Object resolveObjectConstant(Object constant) { + Object result = LoadConstantIndirectlyNode.loadObject(constant); + if (probability(VERY_SLOW_PATH_PROBABILITY, result == null)) { + result = ResolveConstantStubCall.resolveObject(constant, EncodedSymbolNode.encode(constant)); + } + return result; + } + + @Snippet + public static KlassPointer resolveKlassConstant(KlassPointer constant) { + KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant); + if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) { + result = ResolveConstantStubCall.resolveKlass(constant, EncodedSymbolNode.encode(constant)); + } + return result; + } + + @Snippet + public static MethodCountersPointer resolveMethodAndLoadCounters(MethodPointer method, KlassPointer klassHint) { + MethodCountersPointer result = LoadMethodCountersIndirectlyNode.loadMethodCounters(method); + if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) { + result = ResolveMethodAndLoadCountersStubCall.resolveMethodAndLoadCounters(method, klassHint, EncodedSymbolNode.encode(method)); + } + return result; + } + + @Snippet + public static KlassPointer initializeKlass(KlassPointer constant) { + KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant, HotSpotConstantLoadAction.INITIALIZE); + if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) { + result = InitializeKlassStubCall.initializeKlass(constant, EncodedSymbolNode.encode(constant)); + } + return result; + } + + @Snippet + public static KlassPointer pureInitializeKlass(KlassPointer constant) { + KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant, HotSpotConstantLoadAction.INITIALIZE); + if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) { + result = ResolveConstantStubCall.resolveKlass(constant, EncodedSymbolNode.encode(constant), HotSpotConstantLoadAction.INITIALIZE); + } + return result; + } + + public static class Templates extends AbstractTemplates { + private final SnippetInfo resolveObjectConstant = snippet(ResolveConstantSnippets.class, "resolveObjectConstant"); + private final SnippetInfo resolveKlassConstant = snippet(ResolveConstantSnippets.class, "resolveKlassConstant"); + private final SnippetInfo resolveMethodAndLoadCounters = snippet(ResolveConstantSnippets.class, "resolveMethodAndLoadCounters"); + private final SnippetInfo initializeKlass = snippet(ResolveConstantSnippets.class, "initializeKlass"); + private final SnippetInfo pureInitializeKlass = snippet(ResolveConstantSnippets.class, "pureInitializeKlass"); + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + } + + public void lower(ResolveConstantNode resolveConstantNode, LoweringTool tool) { + StructuredGraph graph = resolveConstantNode.graph(); + + ValueNode value = resolveConstantNode.value(); + assert value.isConstant() : "Expected a constant: " + value; + Constant constant = value.asConstant(); + SnippetInfo snippet = null; + + if (constant instanceof HotSpotMetaspaceConstant) { + HotSpotMetaspaceConstant hotspotMetaspaceConstant = (HotSpotMetaspaceConstant) constant; + if (hotspotMetaspaceConstant.asResolvedJavaType() != null) { + if (resolveConstantNode.action() == HotSpotConstantLoadAction.RESOLVE) { + snippet = resolveKlassConstant; + } else { + assert resolveConstantNode.action() == HotSpotConstantLoadAction.INITIALIZE; + snippet = pureInitializeKlass; + } + } + } else if (constant instanceof HotSpotObjectConstant) { + snippet = resolveObjectConstant; + HotSpotObjectConstant hotspotObjectConstant = (HotSpotObjectConstant) constant; + assert hotspotObjectConstant.isInternedString(); + } + if (snippet == null) { + throw new GraalError("Unsupported constant type: " + constant); + } + + Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("constant", value); + + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, tool, args); + + assert resolveConstantNode.hasNoUsages(); + if (!resolveConstantNode.isDeleted()) { + GraphUtil.killWithUnusedFloatingInputs(resolveConstantNode); + } + } + + public void lower(InitializeKlassNode initializeKlassNode, LoweringTool tool) { + StructuredGraph graph = initializeKlassNode.graph(); + + ValueNode value = initializeKlassNode.value(); + assert value.isConstant() : "Expected a constant: " + value; + Constant constant = value.asConstant(); + + if (constant instanceof HotSpotMetaspaceConstant) { + Arguments args = new Arguments(initializeKlass, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("constant", value); + + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), initializeKlassNode, DEFAULT_REPLACER, args); + assert initializeKlassNode.hasNoUsages(); + if (!initializeKlassNode.isDeleted()) { + GraphUtil.killWithUnusedFloatingInputs(initializeKlassNode); + } + + } else { + throw new GraalError("Unsupported constant type: " + constant); + } + } + + public void lower(ResolveMethodAndLoadCountersNode resolveMethodAndLoadCountersNode, LoweringTool tool) { + StructuredGraph graph = resolveMethodAndLoadCountersNode.graph(); + ConstantNode method = ConstantNode.forConstant(MethodPointerStamp.methodNonNull(), resolveMethodAndLoadCountersNode.getMethod().getEncoding(), tool.getMetaAccess(), graph); + Arguments args = new Arguments(resolveMethodAndLoadCounters, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("method", method); + args.add("klassHint", resolveMethodAndLoadCountersNode.getHub()); + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), resolveMethodAndLoadCountersNode, DEFAULT_REPLACER, tool, args); + + assert resolveMethodAndLoadCountersNode.hasNoUsages(); + if (!resolveMethodAndLoadCountersNode.isDeleted()) { + GraphUtil.killWithUnusedFloatingInputs(resolveMethodAndLoadCountersNode); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyCallNode.java 2016-12-07 13:50:46.814844962 -0800 @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2014, 2016, 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. + */ +//JaCoCo Exclude +package org.graalvm.compiler.hotspot.replacements.arraycopy; + +import static org.graalvm.compiler.nodeinfo.InputType.Memory; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; +import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.IntegerConvertNode; +import org.graalvm.compiler.nodes.calc.LeftShiftNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryAccess; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PrimitiveConstant; + +@NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) +public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, MemoryAccess, Canonicalizable { + + public static final NodeClass TYPE = NodeClass.create(ArrayCopyCallNode.class); + @Input protected ValueNode src; + @Input protected ValueNode srcPos; + @Input protected ValueNode dest; + @Input protected ValueNode destPos; + @Input protected ValueNode length; + + @OptionalInput(Memory) MemoryNode lastLocationAccess; + + protected final JavaKind elementKind; + protected final LocationIdentity locationIdentity; + + /** + * Aligned means that the offset of the copy is heap word aligned. + */ + protected boolean aligned; + protected boolean disjoint; + protected boolean uninitialized; + + protected final HotSpotGraalRuntimeProvider runtime; + + public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, + boolean aligned, boolean disjoint, boolean uninitialized) { + this(runtime, src, srcPos, dest, destPos, length, elementKind, null, aligned, disjoint, uninitialized); + } + + public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, + boolean disjoint) { + this(runtime, src, srcPos, dest, destPos, length, elementKind, null, false, disjoint, false); + } + + protected ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, + LocationIdentity locationIdentity, boolean aligned, boolean disjoint, boolean uninitialized) { + super(TYPE, StampFactory.forVoid()); + assert elementKind != null; + this.src = src; + this.srcPos = srcPos; + this.dest = dest; + this.destPos = destPos; + this.length = length; + this.elementKind = elementKind; + this.locationIdentity = (locationIdentity != null ? locationIdentity : NamedLocationIdentity.getArrayLocation(elementKind)); + this.aligned = aligned; + this.disjoint = disjoint; + this.uninitialized = uninitialized; + this.runtime = runtime; + } + + public ValueNode getSource() { + return src; + } + + public ValueNode getSourcePosition() { + return srcPos; + } + + public ValueNode getDestination() { + return dest; + } + + public ValueNode getDestinationPosition() { + return destPos; + } + + public ValueNode getLength() { + return length; + } + + public JavaKind getElementKind() { + return elementKind; + } + + private ValueNode computeBase(ValueNode base, ValueNode pos) { + FixedWithNextNode basePtr = graph().add(new GetObjectAddressNode(base)); + graph().addBeforeFixed(this, basePtr); + Stamp wordStamp = StampFactory.forKind(runtime.getTarget().wordJavaKind); + ValueNode wordPos = IntegerConvertNode.convert(pos, wordStamp, graph()); + int shift = CodeUtil.log2(getArrayIndexScale(elementKind)); + ValueNode scaledIndex = graph().unique(new LeftShiftNode(wordPos, ConstantNode.forInt(shift, graph()))); + ValueNode offset = graph().unique(new AddNode(scaledIndex, ConstantNode.forIntegerStamp(wordStamp, getArrayBaseOffset(elementKind), graph()))); + return graph().unique(new OffsetAddressNode(basePtr, offset)); + } + + @Override + public void lower(LoweringTool tool) { + if (graph().getGuardsStage().areFrameStatesAtDeopts()) { + updateAlignedDisjoint(); + ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint(), isUninitialized(), + locationIdentity.equals(LocationIdentity.any())); + StructuredGraph graph = graph(); + ValueNode srcAddr = computeBase(getSource(), getSourcePosition()); + ValueNode destAddr = computeBase(getDestination(), getDestinationPosition()); + ValueNode len = getLength(); + if (len.stamp().getStackKind() != JavaKind.Long) { + len = IntegerConvertNode.convert(len, StampFactory.forKind(JavaKind.Long), graph()); + } + ForeignCallNode call = graph.add(new ForeignCallNode(runtime.getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len)); + call.setStateAfter(stateAfter()); + graph.replaceFixedWithFixed(this, call); + } + } + + @Override + public MemoryNode getLastLocationAccess() { + return lastLocationAccess; + } + + @Override + public void setLastLocationAccess(MemoryNode lla) { + updateUsagesInterface(lastLocationAccess, lla); + lastLocationAccess = lla; + } + + @Override + public LocationIdentity getLocationIdentity() { + return locationIdentity; + } + + @NodeIntrinsic + private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind, @ConstantNodeParameter boolean aligned, + @ConstantNodeParameter boolean disjoint, @ConstantNodeParameter boolean uninitialized); + + @NodeIntrinsic + private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind, + @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter boolean aligned, @ConstantNodeParameter boolean disjoint, + @ConstantNodeParameter boolean uninitialized); + + public static void arraycopyObjectKillsAny(Object src, int srcPos, Object dest, int destPos, int length) { + arraycopy(src, srcPos, dest, destPos, length, JavaKind.Object, LocationIdentity.any(), false, false, false); + } + + public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) { + arraycopy(src, srcPos, dest, destPos, length, elementKind, false, false, false); + } + + public static void disjointArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) { + arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, false); + } + + public static void disjointUninitializedArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) { + arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, true); + } + + public boolean isAligned() { + return aligned; + } + + public boolean isDisjoint() { + return disjoint; + } + + public boolean isUninitialized() { + return uninitialized; + } + + boolean isHeapWordAligned(JavaConstant value, JavaKind kind) { + return (getArrayBaseOffset(kind) + (long) value.asInt() * getArrayIndexScale(kind)) % runtime.getVMConfig().heapWordSize == 0; + } + + public void updateAlignedDisjoint() { + JavaKind componentKind = elementKind; + if (srcPos == destPos) { + // Can treat as disjoint + disjoint = true; + } + PrimitiveConstant constantSrc = (PrimitiveConstant) srcPos.stamp().asConstant(); + PrimitiveConstant constantDst = (PrimitiveConstant) destPos.stamp().asConstant(); + if (constantSrc != null && constantDst != null) { + if (!aligned) { + aligned = isHeapWordAligned(constantSrc, componentKind) && isHeapWordAligned(constantDst, componentKind); + } + if (constantSrc.asInt() >= constantDst.asInt()) { + // low to high copy so treat as disjoint + disjoint = true; + } + } + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (getLength().isConstant() && getLength().asConstant().isDefaultForKind()) { + if (lastLocationAccess != null) { + replaceAtUsages(InputType.Memory, lastLocationAccess.asNode()); + } + return null; + } + return this; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java 2016-12-07 13:50:47.079856610 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013, 2016, 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.replacements.arraycopy; + +import jdk.vm.ci.meta.JavaKind; + +import static org.graalvm.compiler.core.common.LocationIdentity.any; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.spi.Virtualizable; +import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode; + +@NodeInfo +public final class ArrayCopyNode extends BasicArrayCopyNode implements Virtualizable, Lowerable { + + public static final NodeClass TYPE = NodeClass.create(ArrayCopyNode.class); + + private JavaKind elementKind; + + public ArrayCopyNode(int bci, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) { + super(TYPE, src, srcPos, dst, dstPos, length, null, bci); + elementKind = ArrayCopySnippets.Templates.selectComponentKind(this); + } + + @Override + public LocationIdentity getLocationIdentity() { + if (elementKind == null) { + elementKind = ArrayCopySnippets.Templates.selectComponentKind(this); + } + if (elementKind != null) { + return NamedLocationIdentity.getArrayLocation(elementKind); + } + return any(); + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java 2016-12-07 13:50:47.343868214 -0800 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015, 2016, 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.replacements.arraycopy; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.meta.JavaKind; + +import static org.graalvm.compiler.core.common.LocationIdentity.any; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode; + +@NodeInfo(allowedUsageTypes = InputType.Memory) +public final class ArrayCopySlowPathNode extends BasicArrayCopyNode { + + public static final NodeClass TYPE = NodeClass.create(ArrayCopySlowPathNode.class); + + private final SnippetTemplate.SnippetInfo snippet; + + /** + * Extra context for the slow path snippet. + */ + private final Object argument; + + /** + * AOT compilation requires klass constants to be exposed after the first lowering to be handled + * automatically. Lowering for {@link ArrayCopySlowPathNode}, with snippet == + * {@link ArrayCopySnippets#arraycopyPredictedObjectWork}, requires a klass of Object[]. For + * other snippets {@link #predictedKlass} is a null constant. + */ + @Input protected ValueNode predictedKlass; + + public ArrayCopySlowPathNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode predictedKlass, JavaKind elementKind, + SnippetTemplate.SnippetInfo snippet, Object argument) { + super(TYPE, src, srcPos, dest, destPos, length, elementKind, BytecodeFrame.INVALID_FRAMESTATE_BCI); + assert StampTool.isPointerNonNull(src) && StampTool.isPointerNonNull(dest) : "must have been null checked"; + this.snippet = snippet; + this.argument = argument; + this.predictedKlass = predictedKlass; + } + + @NodeIntrinsic + public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, KlassPointer predictedKlass, + @ConstantNodeParameter JavaKind elementKind, @ConstantNodeParameter SnippetTemplate.SnippetInfo snippet, @ConstantNodeParameter Object argument); + + public SnippetTemplate.SnippetInfo getSnippet() { + return snippet; + } + + public Object getArgument() { + return argument; + } + + @Override + public LocationIdentity getLocationIdentity() { + if (elementKind != null) { + return NamedLocationIdentity.getArrayLocation(elementKind); + } + return any(); + } + + public void setBci(int bci) { + this.bci = bci; + } + + public ValueNode getPredictedKlass() { + return predictedKlass; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java 2016-12-07 13:50:47.608879863 -0800 @@ -0,0 +1,628 @@ +/* + * Copyright (c) 2011, 2016, 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.replacements.arraycopy; + +import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters; +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_SUPER_CHECK_OFFSET_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayClassElementOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperElementTypePrimitiveInPlace; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHub; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readLayoutHelper; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.superCheckOffsetOffset; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; + +import java.lang.reflect.Method; +import java.util.EnumMap; +import java.util.Map; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodes.CallTargetNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.extended.UnsafeLoadNode; +import org.graalvm.compiler.nodes.java.ArrayLengthNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.replacements.SnippetCounter; +import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode; +import org.graalvm.compiler.replacements.nodes.DirectObjectStoreNode; +import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +public class ArrayCopySnippets implements Snippets { + + private static int checkArrayType(KlassPointer hub) { + int layoutHelper = readLayoutHelper(hub); + if (probability(SLOW_PATH_PROBABILITY, layoutHelper >= 0)) { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + return layoutHelper; + } + + private static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length) { + if (probability(SLOW_PATH_PROBABILITY, srcPos < 0)) { + checkAIOOBECounter.inc(); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + if (probability(SLOW_PATH_PROBABILITY, destPos < 0)) { + checkAIOOBECounter.inc(); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + if (probability(SLOW_PATH_PROBABILITY, length < 0)) { + checkAIOOBECounter.inc(); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + if (probability(SLOW_PATH_PROBABILITY, srcPos > ArrayLengthNode.arrayLength(src) - length)) { + checkAIOOBECounter.inc(); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + if (probability(SLOW_PATH_PROBABILITY, destPos > ArrayLengthNode.arrayLength(dest) - length)) { + checkAIOOBECounter.inc(); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + checkSuccessCounter.inc(); + } + + @Snippet + public static void arraycopyZeroLengthIntrinsic(Object src, int srcPos, Object dest, int destPos, int length) { + Object nonNullSrc = GraalDirectives.guardingNonNull(src); + Object nonNullDest = GraalDirectives.guardingNonNull(dest); + KlassPointer srcHub = loadHub(nonNullSrc); + KlassPointer destHub = loadHub(nonNullDest); + checkArrayType(srcHub); + checkArrayType(destHub); + checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); + zeroLengthStaticCounter.inc(); + } + + @Snippet + public static void arraycopyExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, @ConstantParameter SnippetCounter counter, + @ConstantParameter SnippetCounter copiedCounter) { + Object nonNullSrc = GraalDirectives.guardingNonNull(src); + Object nonNullDest = GraalDirectives.guardingNonNull(dest); + checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); + counter.inc(); + copiedCounter.add(length); + ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind); + if (length == 0) { + zeroLengthDynamicCounter.inc(); + } else { + nonZeroLengthDynamicCounter.inc(); + nonZeroLengthDynamicCopiedCounter.add(length); + } + } + + /** + * This intrinsic is useful for the case where we know something statically about one of the + * inputs but not the other. + */ + @Snippet + public static void arraycopyPredictedExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, + @ConstantParameter SnippetCounter counter, @ConstantParameter SnippetCounter copiedCounter) { + Object nonNullSrc = GraalDirectives.guardingNonNull(src); + Object nonNullDest = GraalDirectives.guardingNonNull(dest); + KlassPointer srcHub = loadHub(nonNullSrc); + KlassPointer destHub = loadHub(nonNullDest); + if (probability(SLOW_PATH_PROBABILITY, srcHub != destHub)) { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); + counter.inc(); + copiedCounter.add(length); + ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind); + if (length == 0) { + zeroLengthDynamicCounter.inc(); + } else { + nonZeroLengthDynamicCounter.inc(); + nonZeroLengthDynamicCopiedCounter.add(length); + } + } + + @Snippet + public static void arraycopyPredictedObjectWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, KlassPointer objectArrayKlass, + @ConstantParameter SnippetCounter counter, @ConstantParameter SnippetCounter copiedCounter) { + if (length > 0) { + KlassPointer srcHub = loadHub(PiNode.asNonNullObject(nonNullSrc)); + KlassPointer destHub = loadHub(PiNode.asNonNullObject(nonNullDest)); + if (probability(FAST_PATH_PROBABILITY, srcHub == destHub || destHub == objectArrayKlass)) { + counter.inc(); + copiedCounter.add(length); + predictedObjectArrayCopyFastPathCounter.inc(); + predictedObjectArrayCopyFastPathCopiedCounter.add(length); + ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length); + } else { + predictedObjectArrayCopySlowPathCounter.inc(); + predictedObjectArrayCopySlowPathCopiedCounter.add(length); + System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length); + } + } + } + + /** + * This is the basic template for the full arraycopy checks, including a check that the + * underlying type is really an array type. + */ + @Snippet + public static void arraycopySlowPathIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, KlassPointer predictedKlass, @ConstantParameter JavaKind elementKind, + @ConstantParameter SnippetInfo slowPath, @ConstantParameter Object slowPathArgument) { + Object nonNullSrc = GraalDirectives.guardingNonNull(src); + Object nonNullDest = GraalDirectives.guardingNonNull(dest); + KlassPointer srcHub = loadHub(nonNullSrc); + KlassPointer destHub = loadHub(nonNullDest); + checkArrayType(srcHub); + checkArrayType(destHub); + checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); + if (length == 0) { + zeroLengthDynamicCounter.inc(); + } else { + nonZeroLengthDynamicCounter.inc(); + nonZeroLengthDynamicCopiedCounter.add(length); + } + ArrayCopySlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, predictedKlass, elementKind, slowPath, slowPathArgument); + } + + /** + * Snippet for unrolled arraycopy. + */ + @Snippet + public static void arraycopyUnrolledIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter int unrolledLength, @ConstantParameter JavaKind elementKind) { + Object nonNullSrc = GraalDirectives.guardingNonNull(src); + Object nonNullDest = GraalDirectives.guardingNonNull(dest); + checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); + if (length == 0) { + zeroLengthDynamicCounter.inc(); + } else { + nonZeroLengthDynamicCounter.inc(); + nonZeroLengthDynamicCopiedCounter.add(length); + } + ArrayCopyUnrollNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, unrolledLength, elementKind); + } + + @Snippet + public static void checkcastArraycopyWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length) { + if (length > 0) { + KlassPointer destKlass = loadHub(nonNullDest); + KlassPointer srcKlass = loadHub(nonNullSrc); + if (probability(SLOW_PATH_PROBABILITY, srcKlass == destKlass)) { + // no storecheck required. + objectCheckcastSameTypeCounter.inc(); + objectCheckcastSameTypeCopiedCounter.add(length); + ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length); + } else { + KlassPointer destElemKlass = destKlass.readKlassPointer(arrayClassElementOffset(INJECTED_VMCONFIG), OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION); + Word superCheckOffset = Word.signed(destElemKlass.readInt(superCheckOffsetOffset(INJECTED_VMCONFIG), KLASS_SUPER_CHECK_OFFSET_LOCATION)); + objectCheckcastCounter.inc(); + objectCheckcastCopiedCounter.add(length); + int copiedElements = CheckcastArrayCopyCallNode.checkcastArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, superCheckOffset, destElemKlass, false); + if (copiedElements != 0) { + /* + * the checkcast stub doesn't throw the ArrayStoreException, but returns the + * number of copied elements (xor'd with -1). + */ + copiedElements ^= -1; + System.arraycopy(nonNullSrc, srcPos + copiedElements, nonNullDest, destPos + copiedElements, length - copiedElements); + } + } + } + } + + @Snippet + public static void arraycopyGeneric(Object src, int srcPos, Object dest, int destPos, int length) { + Object nonNullSrc = GraalDirectives.guardingNonNull(src); + Object nonNullDest = GraalDirectives.guardingNonNull(dest); + KlassPointer srcHub = loadHub(nonNullSrc); + KlassPointer destHub = loadHub(nonNullDest); + if (probability(FAST_PATH_PROBABILITY, srcHub.equal(destHub)) && probability(FAST_PATH_PROBABILITY, nonNullSrc != nonNullDest)) { + int layoutHelper = checkArrayType(srcHub); + final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace(INJECTED_VMCONFIG)) == 0); + checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); + if (probability(FAST_PATH_PROBABILITY, isObjectArray)) { + genericObjectExactCallCounter.inc(); + genericObjectExactCallCopiedCounter.add(length); + ArrayCopyCallNode.disjointArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, JavaKind.Object); + } else { + genericPrimitiveCallCounter.inc(); + genericPrimitiveCallCopiedCounter.add(length); + UnsafeArrayCopyNode.arraycopyPrimitive(nonNullSrc, srcPos, nonNullDest, destPos, length, layoutHelper); + } + } else { + SystemArraycopyCounter.inc(); + SystemArraycopyCopiedCounter.add(length); + System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length); + } + } + + @Fold + static LocationIdentity getArrayLocation(JavaKind kind) { + return NamedLocationIdentity.getArrayLocation(kind); + } + + @Snippet + public static void arraycopyUnrolledWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, @ConstantParameter int length, @ConstantParameter JavaKind elementKind) { + final int scale = arrayIndexScale(elementKind); + int arrayBaseOffset = arrayBaseOffset(elementKind); + LocationIdentity arrayLocation = getArrayLocation(elementKind); + if (nonNullSrc == nonNullDest && srcPos < destPos) { // bad aliased case + long start = (long) (length - 1) * scale; + long i = start; + ExplodeLoopNode.explodeLoop(); + for (int iteration = 0; iteration < length; iteration++) { + if (i >= 0) { + Object a = UnsafeLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation); + DirectObjectStoreNode.storeObject(nonNullDest, arrayBaseOffset, i + (long) destPos * scale, a, arrayLocation, elementKind); + i -= scale; + } + } + } else { + long end = (long) length * scale; + long i = 0; + ExplodeLoopNode.explodeLoop(); + for (int iteration = 0; iteration < length; iteration++) { + if (i < end) { + Object a = UnsafeLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation); + DirectObjectStoreNode.storeObject(nonNullDest, arrayBaseOffset, i + (long) destPos * scale, a, arrayLocation, elementKind); + i += scale; + } + } + } + } + + private static final SnippetCounter.Group checkCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy checkInputs") : null; + private static final SnippetCounter checkSuccessCounter = new SnippetCounter(checkCounters, "checkSuccess", "checkSuccess"); + private static final SnippetCounter checkAIOOBECounter = new SnippetCounter(checkCounters, "checkAIOOBE", "checkAIOOBE"); + + private static final SnippetCounter.Group counters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy") : null; + + private static final SnippetCounter objectCheckcastCounter = new SnippetCounter(counters, "Object[]{non-exact}", "arraycopy for non-exact Object[] arrays"); + private static final SnippetCounter objectCheckcastSameTypeCounter = new SnippetCounter(counters, "Object[]{same-type}", "arraycopy call for src.klass == dest.klass Object[] arrays"); + private static final SnippetCounter predictedObjectArrayCopySlowPathCounter = new SnippetCounter(counters, "Object[]{slow-path}", "used System.arraycopy slow path for predicted Object[] arrays"); + private static final SnippetCounter predictedObjectArrayCopyFastPathCounter = new SnippetCounter(counters, "Object[]{fast-path}", "used oop_arraycopy for predicted Object[] arrays"); + + private static final EnumMap arraycopyCallCounters = new EnumMap<>(JavaKind.class); + private static final EnumMap arraycopyCounters = new EnumMap<>(JavaKind.class); + + private static final EnumMap arraycopyCallCopiedCounters = new EnumMap<>(JavaKind.class); + private static final EnumMap arraycopyCopiedCounters = new EnumMap<>(JavaKind.class); + + static void createArraycopyCounter(JavaKind kind) { + arraycopyCallCounters.put(kind, new SnippetCounter(counters, kind + "[]{stub}", "arraycopy call for " + kind + "[] arrays")); + arraycopyCounters.put(kind, new SnippetCounter(counters, kind + "[]{inline}", "inline arraycopy for " + kind + "[] arrays")); + + arraycopyCallCopiedCounters.put(kind, new SnippetCounter(copiedCounters, kind + "[]{stub}", "arraycopy call for " + kind + "[] arrays")); + arraycopyCopiedCounters.put(kind, new SnippetCounter(copiedCounters, kind + "[]{inline}", "inline arraycopy for " + kind + "[] arrays")); + } + + static { + createArraycopyCounter(JavaKind.Byte); + createArraycopyCounter(JavaKind.Boolean); + createArraycopyCounter(JavaKind.Char); + createArraycopyCounter(JavaKind.Short); + createArraycopyCounter(JavaKind.Int); + createArraycopyCounter(JavaKind.Long); + createArraycopyCounter(JavaKind.Float); + createArraycopyCounter(JavaKind.Double); + createArraycopyCounter(JavaKind.Object); + } + + private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays"); + private static final SnippetCounter genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays"); + private static final SnippetCounter SystemArraycopyCounter = new SnippetCounter(counters, "genericObject", "call to System.arraycopy"); + + private static final SnippetCounter.Group lengthCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy 0-length checks") : null; + + private static final SnippetCounter zeroLengthStaticCounter = new SnippetCounter(lengthCounters, "0-lengthcopy static", "arraycopy where the length is statically 0"); + private static final SnippetCounter zeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "0-lengthcopy dynamically", "arraycopy where the length is dynamically 0"); + private static final SnippetCounter nonZeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "non-0-lengthcopy dynamically", "arraycopy where the length is dynamically not zero"); + + private static final SnippetCounter.Group copiedCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy copied elements") : null; + + private static final SnippetCounter nonZeroLengthDynamicCopiedCounter = new SnippetCounter(copiedCounters, "non-0-lengthcopy dynamically", "arraycopy where the length is dynamically not zero"); + private static final SnippetCounter genericPrimitiveCallCopiedCounter = new SnippetCounter(copiedCounters, "genericPrimitive", "generic arraycopy snippet for primitive arrays"); + private static final SnippetCounter genericObjectExactCallCopiedCounter = new SnippetCounter(copiedCounters, "genericObjectExact", "generic arraycopy snippet for special object arrays"); + private static final SnippetCounter SystemArraycopyCopiedCounter = new SnippetCounter(copiedCounters, "genericObject", "call to System.arraycopy"); + + private static final SnippetCounter objectCheckcastCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{non-exact}", "arraycopy for non-exact Object[] arrays"); + private static final SnippetCounter objectCheckcastSameTypeCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{same-type}", "arraycopy call for src.klass == dest.klass Object[] arrays"); + private static final SnippetCounter predictedObjectArrayCopySlowPathCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{slow-path}", + "used System.arraycopy slow path for predicted Object[] arrays"); + private static final SnippetCounter predictedObjectArrayCopyFastPathCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{fast-path}", "used oop_arraycopy for predicted Object[] arrays"); + + public static class Templates extends SnippetTemplate.AbstractTemplates { + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + } + + private ResolvedJavaMethod originalArraycopy() throws GraalError { + if (originalArraycopy == null) { + Method method; + try { + method = System.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class); + } catch (NoSuchMethodException | SecurityException e) { + throw new GraalError(e); + } + originalArraycopy = providers.getMetaAccess().lookupJavaMethod(method); + } + return originalArraycopy; + } + + private ResolvedJavaMethod originalArraycopy; + + private final SnippetInfo checkcastArraycopyWorkSnippet = snippet("checkcastArraycopyWork"); + private final SnippetInfo arraycopyGenericSnippet = snippet("arraycopyGeneric"); + + private final SnippetInfo arraycopySlowPathIntrinsicSnippet = snippet("arraycopySlowPathIntrinsic"); + private final SnippetInfo arraycopyUnrolledIntrinsicSnippet = snippet("arraycopyUnrolledIntrinsic"); + private final SnippetInfo arraycopyExactIntrinsicSnippet = snippet("arraycopyExactIntrinsic"); + private final SnippetInfo arraycopyZeroLengthIntrinsicSnippet = snippet("arraycopyZeroLengthIntrinsic"); + private final SnippetInfo arraycopyPredictedExactIntrinsicSnippet = snippet("arraycopyPredictedExactIntrinsic"); + private final SnippetInfo arraycopyPredictedObjectWorkSnippet = snippet("arraycopyPredictedObjectWork"); + + private final SnippetInfo arraycopyUnrolledWorkSnippet = snippet("arraycopyUnrolledWork"); + + protected SnippetInfo snippet(String methodName) { + SnippetInfo info = snippet(ArrayCopySnippets.class, methodName, LocationIdentity.any()); + info.setOriginalMethod(originalArraycopy()); + return info; + } + + public static JavaKind selectComponentKind(BasicArrayCopyNode arraycopy) { + return selectComponentKind(arraycopy, true); + } + + public static JavaKind selectComponentKind(BasicArrayCopyNode arraycopy, boolean exact) { + ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp()); + ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp()); + + if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { + if (!exact) { + JavaKind component = getComponentKind(srcType); + if (component != null) { + return component; + } + return getComponentKind(destType); + } + return null; + } + if (exact) { + if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) { + return null; + } + if (!arraycopy.isExact()) { + return null; + } + } + return srcType.getComponentType().getJavaKind(); + } + + private static JavaKind getComponentKind(ResolvedJavaType type) { + if (type != null && type.isArray()) { + return type.getComponentType().getJavaKind(); + } + return null; + } + + private static boolean shouldUnroll(ValueNode length) { + return length.isConstant() && length.asJavaConstant().asInt() <= 8 && length.asJavaConstant().asInt() != 0; + } + + public void lower(ArrayCopyNode arraycopy, LoweringTool tool) { + JavaKind componentKind = selectComponentKind(arraycopy); + SnippetInfo snippetInfo = null; + SnippetInfo slowPathSnippetInfo = null; + Object slowPathArgument = null; + + if (arraycopy.getLength().isConstant() && arraycopy.getLength().asJavaConstant().asLong() == 0) { + snippetInfo = arraycopyZeroLengthIntrinsicSnippet; + } else if (arraycopy.isExact()) { + snippetInfo = arraycopyExactIntrinsicSnippet; + if (shouldUnroll(arraycopy.getLength())) { + snippetInfo = arraycopyUnrolledIntrinsicSnippet; + } + } else { + if (componentKind == JavaKind.Object) { + ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp()); + ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp()); + ResolvedJavaType srcComponentType = srcType == null ? null : srcType.getComponentType(); + ResolvedJavaType destComponentType = destType == null ? null : destType.getComponentType(); + if (srcComponentType != null && destComponentType != null && !srcComponentType.isPrimitive() && !destComponentType.isPrimitive()) { + snippetInfo = arraycopySlowPathIntrinsicSnippet; + slowPathSnippetInfo = checkcastArraycopyWorkSnippet; + slowPathArgument = LocationIdentity.any(); + /* + * Because this snippet has to use Sysytem.arraycopy as a slow path, we must + * pretend to kill any() so clear the componentKind. + */ + componentKind = null; + } + } + if (componentKind == null && snippetInfo == null) { + JavaKind predictedKind = selectComponentKind(arraycopy, false); + if (predictedKind != null) { + /* + * At least one array is of a known type requiring no store checks, so + * assume the other is of the same type. Generally this is working around + * deficiencies in our propagation of type information. + */ + componentKind = predictedKind; + if (predictedKind == JavaKind.Object) { + snippetInfo = arraycopySlowPathIntrinsicSnippet; + slowPathSnippetInfo = arraycopyPredictedObjectWorkSnippet; + slowPathArgument = predictedKind; + componentKind = null; + } else { + snippetInfo = arraycopyPredictedExactIntrinsicSnippet; + } + } + } + if (snippetInfo == null) { + snippetInfo = arraycopyGenericSnippet; + } + } + Arguments args = new Arguments(snippetInfo, arraycopy.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("src", arraycopy.getSource()); + args.add("srcPos", arraycopy.getSourcePosition()); + args.add("dest", arraycopy.getDestination()); + args.add("destPos", arraycopy.getDestinationPosition()); + args.add("length", arraycopy.getLength()); + if (snippetInfo == arraycopyUnrolledIntrinsicSnippet) { + args.addConst("unrolledLength", arraycopy.getLength().asJavaConstant().asInt()); + args.addConst("elementKind", componentKind != null ? componentKind : JavaKind.Illegal); + } else if (snippetInfo == arraycopySlowPathIntrinsicSnippet) { + ValueNode predictedKlass = null; + if (slowPathArgument == arraycopyPredictedObjectWorkSnippet) { + HotSpotResolvedObjectType arrayClass = (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(Object[].class); + predictedKlass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), arrayClass.klass(), tool.getMetaAccess(), arraycopy.graph()); + } else { + predictedKlass = ConstantNode.forConstant(KlassPointerStamp.klassAlwaysNull(), JavaConstant.NULL_POINTER, tool.getMetaAccess(), arraycopy.graph()); + } + args.add("predictedKlass", predictedKlass); + args.addConst("elementKind", componentKind != null ? componentKind : JavaKind.Illegal); + args.addConst("slowPath", slowPathSnippetInfo); + assert slowPathArgument != null; + args.addConst("slowPathArgument", slowPathArgument); + } else if (snippetInfo == arraycopyExactIntrinsicSnippet || snippetInfo == arraycopyPredictedExactIntrinsicSnippet) { + assert componentKind != null; + args.addConst("elementKind", componentKind); + args.addConst("counter", arraycopyCallCounters.get(componentKind)); + args.addConst("copiedCounter", arraycopyCallCopiedCounters.get(componentKind)); + } + instantiate(args, arraycopy); + } + + public void lower(ArrayCopySlowPathNode arraycopy, LoweringTool tool) { + StructuredGraph graph = arraycopy.graph(); + if (!graph.getGuardsStage().areFrameStatesAtDeopts()) { + // Can't be lowered yet + return; + } + SnippetInfo snippetInfo = arraycopy.getSnippet(); + Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("nonNullSrc", arraycopy.getSource()); + args.add("srcPos", arraycopy.getSourcePosition()); + args.add("nonNullDest", arraycopy.getDestination()); + args.add("destPos", arraycopy.getDestinationPosition()); + if (snippetInfo == arraycopyUnrolledWorkSnippet) { + args.addConst("length", ((Integer) arraycopy.getArgument()).intValue()); + args.addConst("elementKind", arraycopy.getElementKind()); + } else { + args.add("length", arraycopy.getLength()); + } + if (snippetInfo == arraycopyPredictedObjectWorkSnippet) { + args.add("objectArrayKlass", arraycopy.getPredictedKlass()); + args.addConst("counter", arraycopyCallCounters.get(JavaKind.Object)); + args.addConst("copiedCounter", arraycopyCallCopiedCounters.get(JavaKind.Object)); + } + instantiate(args, arraycopy); + } + + public void lower(ArrayCopyUnrollNode arraycopy, LoweringTool tool) { + StructuredGraph graph = arraycopy.graph(); + if (!graph.getGuardsStage().areFrameStatesAtDeopts()) { + // Can't be lowered yet + return; + } + SnippetInfo snippetInfo = arraycopyUnrolledWorkSnippet; + Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("nonNullSrc", arraycopy.getSource()); + args.add("srcPos", arraycopy.getSourcePosition()); + args.add("nonNullDest", arraycopy.getDestination()); + args.add("destPos", arraycopy.getDestinationPosition()); + args.addConst("length", arraycopy.getUnrollLength()); + args.addConst("elementKind", arraycopy.getElementKind()); + template(args).instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args); + } + + /** + * Instantiate the snippet template and fix up the FrameState of any Invokes of + * System.arraycopy and propagate the captured bci in the ArrayCopySlowPathNode. + * + * @param args + * @param arraycopy + */ + private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) { + StructuredGraph graph = arraycopy.graph(); + SnippetTemplate template = template(args); + Map replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args); + for (Node originalNode : replacements.keySet()) { + if (originalNode instanceof Invoke) { + Invoke invoke = (Invoke) replacements.get(originalNode); + assert invoke.asNode().graph() == graph; + CallTargetNode call = invoke.callTarget(); + + if (!call.targetMethod().equals(originalArraycopy)) { + throw new GraalError("unexpected invoke %s in snippet", call.targetMethod()); + } + // Here we need to fix the bci of the invoke + InvokeNode newInvoke = graph.add(new InvokeNode(invoke.callTarget(), arraycopy.getBci())); + if (arraycopy.stateDuring() != null) { + newInvoke.setStateDuring(arraycopy.stateDuring()); + } else { + assert arraycopy.stateAfter() != null; + newInvoke.setStateAfter(arraycopy.stateAfter()); + } + graph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke); + } else if (originalNode instanceof ArrayCopySlowPathNode) { + ArrayCopySlowPathNode slowPath = (ArrayCopySlowPathNode) replacements.get(originalNode); + assert arraycopy.stateAfter() != null; + slowPath.setStateAfter(arraycopy.stateAfter()); + slowPath.setBci(arraycopy.getBci()); + } + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyUnrollNode.java 2016-12-07 13:50:47.874891555 -0800 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2015, 2016, 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.replacements.arraycopy; + +import jdk.vm.ci.meta.JavaKind; + +import static org.graalvm.compiler.core.common.LocationIdentity.any; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode; +import org.graalvm.compiler.nodes.memory.MemoryAccess; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +@NodeInfo(allowedUsageTypes = InputType.Memory) +public class ArrayCopyUnrollNode extends ArrayRangeWriteNode implements MemoryCheckpoint.Single, Lowerable, MemoryAccess { + + public static final NodeClass TYPE = NodeClass.create(ArrayCopyUnrollNode.class); + + @Input protected ValueNode src; + @Input protected ValueNode srcPos; + @Input protected ValueNode dest; + @Input protected ValueNode destPos; + @Input protected ValueNode length; + + private JavaKind elementKind; + + private int unrolledLength; + + @OptionalInput(InputType.Memory) private MemoryNode lastLocationAccess; + + public ArrayCopyUnrollNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, int unrolledLength, JavaKind elementKind) { + super(TYPE, StampFactory.forKind(JavaKind.Void)); + this.src = src; + this.srcPos = srcPos; + this.dest = dest; + this.destPos = destPos; + this.length = length; + this.unrolledLength = unrolledLength; + assert elementKind != null && elementKind != JavaKind.Illegal; + this.elementKind = elementKind; + } + + public ValueNode getSource() { + return src; + } + + public ValueNode getSourcePosition() { + return srcPos; + } + + public ValueNode getDestination() { + return dest; + } + + public ValueNode getDestinationPosition() { + return destPos; + } + + @Override + public ValueNode getLength() { + return length; + } + + @Override + public ValueNode getArray() { + return dest; + } + + @Override + public ValueNode getIndex() { + return destPos; + } + + @Override + public boolean isObjectArray() { + return elementKind == JavaKind.Object; + } + + @Override + public boolean isInitialization() { + return false; + } + + @NodeIntrinsic + public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantNodeParameter int unrolledLength, + @ConstantNodeParameter JavaKind elementKind); + + public int getUnrollLength() { + return unrolledLength; + } + + public JavaKind getElementKind() { + return elementKind; + } + + @Override + public LocationIdentity getLocationIdentity() { + if (elementKind != null) { + return NamedLocationIdentity.getArrayLocation(elementKind); + } + return any(); + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + @Override + public MemoryNode getLastLocationAccess() { + return lastLocationAccess; + } + + @Override + public void setLastLocationAccess(MemoryNode lla) { + updateUsagesInterface(lastLocationAccess, lla); + lastLocationAccess = lla; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java 2016-12-07 13:50:48.139903203 -0800 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2014, 2016, 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. + */ +//JaCoCo Exclude +package org.graalvm.compiler.hotspot.replacements.arraycopy; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; +import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.IntegerConvertNode; +import org.graalvm.compiler.nodes.calc.LeftShiftNode; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.meta.JavaKind; + +@NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Value}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) +public final class CheckcastArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single { + + public static final NodeClass TYPE = NodeClass.create(CheckcastArrayCopyCallNode.class); + @Input ValueNode src; + @Input ValueNode srcPos; + @Input ValueNode dest; + @Input ValueNode destPos; + @Input ValueNode length; + @Input ValueNode destElemKlass; + @Input ValueNode superCheckOffset; + + protected final boolean uninit; + + protected final HotSpotGraalRuntimeProvider runtime; + + protected CheckcastArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, + ValueNode superCheckOffset, ValueNode destElemKlass, boolean uninit) { + super(TYPE, StampFactory.forKind(JavaKind.Int)); + this.src = src; + this.srcPos = srcPos; + this.dest = dest; + this.destPos = destPos; + this.length = length; + this.superCheckOffset = superCheckOffset; + this.destElemKlass = destElemKlass; + this.uninit = uninit; + this.runtime = runtime; + } + + public ValueNode getSource() { + return src; + } + + public ValueNode getSourcePosition() { + return srcPos; + } + + public ValueNode getDestination() { + return dest; + } + + public ValueNode getDestinationPosition() { + return destPos; + } + + public ValueNode getLength() { + return length; + } + + public boolean isUninit() { + return uninit; + } + + private ValueNode computeBase(ValueNode base, ValueNode pos) { + FixedWithNextNode basePtr = graph().add(new GetObjectAddressNode(base)); + graph().addBeforeFixed(this, basePtr); + + int shift = CodeUtil.log2(getArrayIndexScale(JavaKind.Object)); + ValueNode scaledIndex = graph().unique(new LeftShiftNode(pos, ConstantNode.forInt(shift, graph()))); + ValueNode offset = graph().unique(new AddNode(scaledIndex, ConstantNode.forInt(getArrayBaseOffset(JavaKind.Object), graph()))); + return graph().unique(new OffsetAddressNode(basePtr, offset)); + } + + @Override + public void lower(LoweringTool tool) { + if (graph().getGuardsStage().areFrameStatesAtDeopts()) { + ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupCheckcastArraycopyDescriptor(isUninit()); + StructuredGraph graph = graph(); + ValueNode srcAddr = computeBase(getSource(), getSourcePosition()); + ValueNode destAddr = computeBase(getDestination(), getDestinationPosition()); + ValueNode len = getLength(); + if (len.stamp().getStackKind() != runtime.getTarget().wordJavaKind) { + len = IntegerConvertNode.convert(len, StampFactory.forKind(runtime.getTarget().wordJavaKind), graph()); + } + ForeignCallNode call = graph.add(new ForeignCallNode(runtime.getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len, superCheckOffset, destElemKlass)); + call.setStateAfter(stateAfter()); + graph.replaceFixedWithFixed(this, call); + } + } + + @Override + public LocationIdentity getLocationIdentity() { + /* + * Because of restrictions that the memory graph of snippets matches the original node, + * pretend that we kill any. + */ + return LocationIdentity.any(); + } + + @NodeIntrinsic + public static native int checkcastArraycopy(Object src, int srcPos, Object dest, int destPos, int length, Word superCheckOffset, Object destElemKlass, @ConstantNodeParameter boolean uninit); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java 2016-12-07 13:50:48.404914851 -0800 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2013, 2016, 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.replacements.arraycopy; + +import static org.graalvm.compiler.core.common.LocationIdentity.any; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_200; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_200; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode; +import org.graalvm.compiler.nodes.memory.MemoryAccess; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; + +import jdk.vm.ci.meta.JavaKind; + +@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_200, size = SIZE_200) +public final class UnsafeArrayCopyNode extends ArrayRangeWriteNode implements Lowerable, MemoryCheckpoint.Single, MemoryAccess { + + public static final NodeClass TYPE = NodeClass.create(UnsafeArrayCopyNode.class); + @Input ValueNode src; + @Input ValueNode srcPos; + @Input ValueNode dest; + @Input ValueNode destPos; + @Input ValueNode length; + @OptionalInput ValueNode layoutHelper; + + @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess; + + protected JavaKind elementKind; + + public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper, JavaKind elementKind) { + super(TYPE, StampFactory.forVoid()); + assert layoutHelper == null || elementKind == null; + this.src = src; + this.srcPos = srcPos; + this.dest = dest; + this.destPos = destPos; + this.length = length; + this.layoutHelper = layoutHelper; + this.elementKind = elementKind; + } + + public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind) { + this(src, srcPos, dest, destPos, length, null, elementKind); + } + + public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper) { + this(src, srcPos, dest, destPos, length, layoutHelper, null); + } + + @Override + public ValueNode getArray() { + return dest; + } + + @Override + public ValueNode getIndex() { + return destPos; + } + + @Override + public ValueNode getLength() { + return length; + } + + @Override + public boolean isObjectArray() { + return elementKind == JavaKind.Object; + } + + @Override + public boolean isInitialization() { + return false; + } + + public JavaKind getElementKind() { + return elementKind; + } + + @Override + public void lower(LoweringTool tool) { + if (graph().getGuardsStage().areFrameStatesAtDeopts()) { + UnsafeArrayCopySnippets.Templates templates = tool.getReplacements().getSnippetTemplateCache(UnsafeArrayCopySnippets.Templates.class); + templates.lower(this, tool); + } + } + + public void addSnippetArguments(Arguments args) { + args.add("src", src); + args.add("srcPos", srcPos); + args.add("dest", dest); + args.add("destPos", destPos); + args.add("length", length); + if (layoutHelper != null) { + args.add("layoutHelper", layoutHelper); + } + } + + @Override + public LocationIdentity getLocationIdentity() { + if (elementKind != null) { + return NamedLocationIdentity.getArrayLocation(elementKind); + } + return any(); + } + + @Override + public MemoryNode getLastLocationAccess() { + return lastLocationAccess; + } + + @Override + public void setLastLocationAccess(MemoryNode lla) { + updateUsagesInterface(lastLocationAccess, lla); + lastLocationAccess = lla; + } + + @NodeIntrinsic + public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind); + + @NodeIntrinsic + public static native void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java 2016-12-07 13:50:48.670926543 -0800 @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2013, 2016, 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.replacements.arraycopy; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeMask; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeShift; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeMask; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeShift; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.runtime; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize; +import static org.graalvm.compiler.nodes.NamedLocationIdentity.any; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; +import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.extended.UnsafeCopyNode; +import org.graalvm.compiler.nodes.extended.UnsafeLoadNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.replacements.nodes.DirectObjectStoreNode; +import org.graalvm.compiler.word.ObjectAccess; +import org.graalvm.compiler.word.Unsigned; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.JavaKind; + +/** + * As opposed to {@link ArrayCopySnippets}, these Snippets do not perform store checks. + */ +public class UnsafeArrayCopySnippets implements Snippets { + + private static final boolean supportsUnalignedMemoryAccess = runtime().getHostJVMCIBackend().getTarget().arch.supportsUnalignedMemoryAccess(); + + private static final JavaKind VECTOR_KIND = JavaKind.Long; + private static final long VECTOR_SIZE = getArrayIndexScale(VECTOR_KIND); + + private static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, JavaKind baseKind, LocationIdentity locationIdentity) { + int arrayBaseOffset = arrayBaseOffset(baseKind); + int elementSize = arrayIndexScale(baseKind); + long byteLength = (long) length * elementSize; + long srcOffset = (long) srcPos * elementSize; + long destOffset = (long) destPos * elementSize; + + long preLoopBytes; + long mainLoopBytes; + long postLoopBytes; + + // We can easily vectorize the loop if both offsets have the same alignment. + if (byteLength >= VECTOR_SIZE && (srcOffset % VECTOR_SIZE) == (destOffset % VECTOR_SIZE)) { + preLoopBytes = NumUtil.roundUp(arrayBaseOffset + srcOffset, VECTOR_SIZE) - (arrayBaseOffset + srcOffset); + postLoopBytes = (byteLength - preLoopBytes) % VECTOR_SIZE; + mainLoopBytes = byteLength - preLoopBytes - postLoopBytes; + } else { + // Does the architecture support unaligned memory accesses? + if (supportsUnalignedMemoryAccess) { + preLoopBytes = byteLength % VECTOR_SIZE; + mainLoopBytes = byteLength - preLoopBytes; + postLoopBytes = 0; + } else { + // No. Let's do element-wise copying. + preLoopBytes = byteLength; + mainLoopBytes = 0; + postLoopBytes = 0; + } + } + + if (probability(NOT_FREQUENT_PROBABILITY, src == dest) && probability(NOT_FREQUENT_PROBABILITY, srcPos < destPos)) { + // bad aliased case + srcOffset += byteLength; + destOffset += byteLength; + + // Post-loop + for (long i = 0; i < postLoopBytes; i += elementSize) { + srcOffset -= elementSize; + destOffset -= elementSize; + UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity); + } + // Main-loop + for (long i = 0; i < mainLoopBytes; i += VECTOR_SIZE) { + srcOffset -= VECTOR_SIZE; + destOffset -= VECTOR_SIZE; + UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, VECTOR_KIND, locationIdentity); + } + // Pre-loop + for (long i = 0; i < preLoopBytes; i += elementSize) { + srcOffset -= elementSize; + destOffset -= elementSize; + UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity); + } + } else { + // Pre-loop + for (long i = 0; i < preLoopBytes; i += elementSize) { + UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity); + srcOffset += elementSize; + destOffset += elementSize; + } + // Main-loop + for (long i = 0; i < mainLoopBytes; i += VECTOR_SIZE) { + UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, VECTOR_KIND, locationIdentity); + srcOffset += VECTOR_SIZE; + destOffset += VECTOR_SIZE; + } + // Post-loop + for (long i = 0; i < postLoopBytes; i += elementSize) { + UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity); + srcOffset += elementSize; + destOffset += elementSize; + } + } + } + + @Fold + static LocationIdentity getArrayLocation(JavaKind kind) { + return NamedLocationIdentity.getArrayLocation(kind); + } + + @Snippet + public static void arraycopyByte(byte[] src, int srcPos, byte[] dest, int destPos, int length) { + JavaKind kind = JavaKind.Byte; + vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind)); + } + + @Snippet + public static void arraycopyBoolean(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { + JavaKind kind = JavaKind.Boolean; + vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind)); + } + + @Snippet + public static void arraycopyChar(char[] src, int srcPos, char[] dest, int destPos, int length) { + JavaKind kind = JavaKind.Char; + vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind)); + } + + @Snippet + public static void arraycopyShort(short[] src, int srcPos, short[] dest, int destPos, int length) { + JavaKind kind = JavaKind.Short; + vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind)); + } + + @Snippet + public static void arraycopyInt(int[] src, int srcPos, int[] dest, int destPos, int length) { + JavaKind kind = JavaKind.Int; + vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind)); + } + + @Snippet + public static void arraycopyFloat(float[] src, int srcPos, float[] dest, int destPos, int length) { + JavaKind kind = JavaKind.Float; + vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind)); + } + + @Snippet + public static void arraycopyLong(long[] src, int srcPos, long[] dest, int destPos, int length) { + JavaKind kind = JavaKind.Long; + vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind)); + } + + @Snippet + public static void arraycopyDouble(double[] src, int srcPos, double[] dest, int destPos, int length) { + JavaKind kind = JavaKind.Double; + /* + * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values to be + * copied atomically, but not long values. For example, on Intel 32-bit this code is not + * atomic as long as the vector kind remains Kind.Long. + */ + vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind)); + } + + /** + * For this kind, Object, we want to avoid write barriers between writes, but instead have them + * at the end of the snippet. This is done by using {@link DirectObjectStoreNode}, and rely on + * {@link WriteBarrierAdditionPhase} to put write barriers after the {@link UnsafeArrayCopyNode} + * with kind Object. + */ + @Snippet + public static void arraycopyObject(Object[] src, int srcPos, Object[] dest, int destPos, int length) { + JavaKind kind = JavaKind.Object; + final int scale = arrayIndexScale(kind); + int arrayBaseOffset = arrayBaseOffset(kind); + LocationIdentity arrayLocation = getArrayLocation(kind); + if (src == dest && srcPos < destPos) { // bad aliased case + long start = (long) (length - 1) * scale; + for (long i = start; i >= 0; i -= scale) { + Object a = UnsafeLoadNode.load(src, arrayBaseOffset + i + (long) srcPos * scale, kind, arrayLocation); + DirectObjectStoreNode.storeObject(dest, arrayBaseOffset, i + (long) destPos * scale, a, getArrayLocation(kind), kind); + } + } else { + long end = (long) length * scale; + for (long i = 0; i < end; i += scale) { + Object a = UnsafeLoadNode.load(src, arrayBaseOffset + i + (long) srcPos * scale, kind, arrayLocation); + DirectObjectStoreNode.storeObject(dest, arrayBaseOffset, i + (long) destPos * scale, a, getArrayLocation(kind), kind); + } + } + } + + @Snippet + public static void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) { + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG); + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG); + + Unsigned vectorSize = Word.unsigned(VECTOR_SIZE); + Unsigned srcOffset = Word.unsigned(srcPos).shiftLeft(log2ElementSize).add(headerSize); + Unsigned destOffset = Word.unsigned(destPos).shiftLeft(log2ElementSize).add(headerSize); + Unsigned destStart = destOffset; + Unsigned destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize)); + + Unsigned destVectorEnd = null; + Unsigned nonVectorBytes = null; + Unsigned sizeInBytes = Word.unsigned(length).shiftLeft(log2ElementSize); + if (supportsUnalignedMemoryAccess) { + nonVectorBytes = sizeInBytes.unsignedRemainder(vectorSize); + destVectorEnd = destEnd; + } else { + boolean inPhase = srcOffset.and((int) VECTOR_SIZE - 1).equal(destOffset.and((int) VECTOR_SIZE - 1)); + boolean hasAtLeastOneVector = sizeInBytes.aboveOrEqual(vectorSize); + // We must have at least one full vector, otherwise we must copy each byte separately + if (hasAtLeastOneVector && inPhase) { // If in phase, we can vectorize + nonVectorBytes = vectorSize.subtract(destStart.unsignedRemainder(vectorSize)); + } else { // fallback is byte-wise + nonVectorBytes = sizeInBytes; + } + destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(vectorSize)); + } + + Unsigned destNonVectorEnd = destStart.add(nonVectorBytes); + while (destOffset.belowThan(destNonVectorEnd)) { + ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any()); + destOffset = destOffset.add(1); + srcOffset = srcOffset.add(1); + } + // Unsigned destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(8)); + while (destOffset.belowThan(destVectorEnd)) { + ObjectAccess.writeWord(dest, destOffset, ObjectAccess.readWord(src, srcOffset, any()), any()); + destOffset = destOffset.add(wordSize()); + srcOffset = srcOffset.add(wordSize()); + } + // Do the last bytes each when it is required to have absolute alignment. + while (!supportsUnalignedMemoryAccess && destOffset.belowThan(destEnd)) { + ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any()); + destOffset = destOffset.add(1); + srcOffset = srcOffset.add(1); + } + } + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo[] arraycopySnippets; + private final SnippetInfo genericPrimitiveSnippet; + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + + arraycopySnippets = new SnippetInfo[JavaKind.values().length]; + arraycopySnippets[JavaKind.Boolean.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyBoolean"); + arraycopySnippets[JavaKind.Byte.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyByte"); + arraycopySnippets[JavaKind.Short.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyShort"); + arraycopySnippets[JavaKind.Char.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyChar"); + arraycopySnippets[JavaKind.Int.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyInt"); + arraycopySnippets[JavaKind.Long.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyLong"); + arraycopySnippets[JavaKind.Float.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyFloat"); + arraycopySnippets[JavaKind.Double.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyDouble"); + arraycopySnippets[JavaKind.Object.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyObject"); + + genericPrimitiveSnippet = snippet(UnsafeArrayCopySnippets.class, "arraycopyPrimitive"); + } + + public void lower(UnsafeArrayCopyNode node, LoweringTool tool) { + JavaKind elementKind = node.getElementKind(); + SnippetInfo snippet; + if (elementKind == null) { + // primitive array of unknown kind + snippet = genericPrimitiveSnippet; + } else { + snippet = arraycopySnippets[elementKind.ordinal()]; + assert snippet != null : "arraycopy snippet for " + elementKind.name() + " not found"; + } + + Arguments args = new Arguments(snippet, node.graph().getGuardsStage(), tool.getLoweringStage()); + node.addSnippetArguments(args); + + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), node, DEFAULT_REPLACER, args); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java 2016-12-07 13:50:48.935938191 -0800 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016, 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.replacements.profiling; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; +import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileBranchNode; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; +import org.graalvm.compiler.hotspot.word.MethodCountersPointer; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; + +import jdk.vm.ci.code.TargetDescription; + +public class ProbabilisticProfileSnippets implements Snippets { + @Snippet + public static boolean shouldProfile(@ConstantParameter int probLog, int random) { + int probabilityMask = (1 << probLog) - 1; + return (random & probabilityMask) == 0; + } + + @Snippet + public static int notificationMask(int freqLog, int probLog) { + int probabilityMask = (1 << probLog) - 1; + int frequencyMask = (1 << freqLog) - 1; + return frequencyMask & ~probabilityMask; + } + + @NodeIntrinsic(ForeignCallNode.class) + public static native void methodInvocationEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters); + + @Snippet + public static void profileMethodEntryWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog) { + if (probability(1.0 / (1 << probLog), shouldProfile(probLog, random))) { + int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + (config(INJECTED_VMCONFIG).invocationCounterIncrement << probLog); + counters.writeInt(config(INJECTED_VMCONFIG).invocationCounterOffset, counterValue); + if (freqLog >= 0) { + int mask = notificationMask(freqLog, probLog); + if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) { + methodInvocationEvent(HotSpotBackend.INVOCATION_EVENT, counters); + } + } + } + } + + @NodeIntrinsic(ForeignCallNode.class) + public static native void methodBackedgeEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters, int bci, int targetBci); + + @Snippet + public static void profileBackedgeWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog, int bci, int targetBci) { + if (probability(1.0 / (1 << probLog), shouldProfile(probLog, random))) { + int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + (config(INJECTED_VMCONFIG).invocationCounterIncrement << probLog); + counters.writeInt(config(INJECTED_VMCONFIG).backedgeCounterOffset, counterValue); + int mask = notificationMask(freqLog, probLog); + if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) { + methodBackedgeEvent(HotSpotBackend.BACKEDGE_EVENT, counters, bci, targetBci); + } + } + } + + @Snippet + public static void profileConditionalBackedgeWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog, boolean branchCondition, + int bci, int targetBci) { + if (branchCondition) { + profileBackedgeWithProbability(counters, random, freqLog, probLog, bci, targetBci); + } + } + + public static class Templates extends AbstractTemplates { + private final SnippetInfo profileMethodEntryWithProbability = snippet(ProbabilisticProfileSnippets.class, "profileMethodEntryWithProbability"); + private final SnippetInfo profileBackedgeWithProbability = snippet(ProbabilisticProfileSnippets.class, "profileBackedgeWithProbability"); + private final SnippetInfo profileConditionalBackedgeWithProbability = snippet(ProbabilisticProfileSnippets.class, "profileConditionalBackedgeWithProbability"); + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + } + + public void lower(ProfileNode profileNode, LoweringTool tool) { + assert profileNode.getRandom() != null; + + StructuredGraph graph = profileNode.graph(); + LoadMethodCountersNode counters = graph.unique(new LoadMethodCountersNode(profileNode.getProfiledMethod())); + + if (profileNode instanceof ProfileBranchNode) { + // Backedge event + ProfileBranchNode profileBranchNode = (ProfileBranchNode) profileNode; + SnippetInfo snippet = profileBranchNode.hasCondition() ? profileConditionalBackedgeWithProbability : profileBackedgeWithProbability; + Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + ConstantNode bci = ConstantNode.forInt(profileBranchNode.bci(), graph); + ConstantNode targetBci = ConstantNode.forInt(profileBranchNode.targetBci(), graph); + args.add("counters", counters); + args.add("random", profileBranchNode.getRandom()); + args.addConst("freqLog", profileBranchNode.getNotificationFreqLog()); + args.addConst("probLog", profileBranchNode.getProbabilityLog()); + if (profileBranchNode.hasCondition()) { + args.add("branchCondition", profileBranchNode.branchCondition()); + } + args.add("bci", bci); + args.add("targetBci", targetBci); + + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); + } else if (profileNode instanceof ProfileInvokeNode) { + ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode; + // Method invocation event + Arguments args = new Arguments(profileMethodEntryWithProbability, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("counters", counters); + args.add("random", profileInvokeNode.getRandom()); + args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog()); + args.addConst("probLog", profileInvokeNode.getProbabilityLog()); + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); + } else { + throw new GraalError("Unsupported profile node type: " + profileNode); + } + + assert profileNode.hasNoUsages(); + if (!profileNode.isDeleted()) { + GraphUtil.killWithUnusedFloatingInputs(profileNode); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java 2016-12-07 13:50:49.199949795 -0800 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016, 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.replacements.profiling; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; +import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileBranchNode; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; +import org.graalvm.compiler.hotspot.word.MethodCountersPointer; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; +import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; +import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; +import org.graalvm.compiler.replacements.Snippets; + +import jdk.vm.ci.code.TargetDescription; + +public class ProfileSnippets implements Snippets { + @NodeIntrinsic(ForeignCallNode.class) + public static native void methodInvocationEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters); + + @Snippet + public static void profileMethodEntry(MethodCountersPointer counters, @ConstantParameter int freqLog) { + int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement; + counters.writeInt(config(INJECTED_VMCONFIG).invocationCounterOffset, counterValue); + if (freqLog >= 0) { + final int frequencyMask = (1 << freqLog) - 1; + if (probability(SLOW_PATH_PROBABILITY, (counterValue & (frequencyMask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) { + methodInvocationEvent(HotSpotBackend.INVOCATION_EVENT, counters); + } + } + } + + @NodeIntrinsic(ForeignCallNode.class) + public static native void methodBackedgeEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters, int bci, int targetBci); + + @Snippet + public static void profileBackedge(MethodCountersPointer counters, @ConstantParameter int freqLog, int bci, int targetBci) { + int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement; + counters.writeInt(config(INJECTED_VMCONFIG).backedgeCounterOffset, counterValue); + final int frequencyMask = (1 << freqLog) - 1; + if (probability(SLOW_PATH_PROBABILITY, (counterValue & (frequencyMask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) { + methodBackedgeEvent(HotSpotBackend.BACKEDGE_EVENT, counters, bci, targetBci); + } + } + + @Snippet + public static void profileConditionalBackedge(MethodCountersPointer counters, @ConstantParameter int freqLog, boolean branchCondition, int bci, int targetBci) { + if (branchCondition) { + profileBackedge(counters, freqLog, bci, targetBci); + } + } + + public static class Templates extends AbstractTemplates { + private final SnippetInfo profileMethodEntry = snippet(ProfileSnippets.class, "profileMethodEntry"); + private final SnippetInfo profileBackedge = snippet(ProfileSnippets.class, "profileBackedge"); + private final SnippetInfo profileConditionalBackedge = snippet(ProfileSnippets.class, "profileConditionalBackedge"); + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + } + + public void lower(ProfileNode profileNode, LoweringTool tool) { + StructuredGraph graph = profileNode.graph(); + LoadMethodCountersNode counters = graph.unique(new LoadMethodCountersNode(profileNode.getProfiledMethod())); + + if (profileNode instanceof ProfileBranchNode) { + // Backedge event + ProfileBranchNode profileBranchNode = (ProfileBranchNode) profileNode; + SnippetInfo snippet = profileBranchNode.hasCondition() ? profileConditionalBackedge : profileBackedge; + Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + ConstantNode bci = ConstantNode.forInt(profileBranchNode.bci(), graph); + ConstantNode targetBci = ConstantNode.forInt(profileBranchNode.targetBci(), graph); + args.add("counters", counters); + args.addConst("freqLog", profileBranchNode.getNotificationFreqLog()); + if (profileBranchNode.hasCondition()) { + args.add("branchCondition", profileBranchNode.branchCondition()); + } + args.add("bci", bci); + args.add("targetBci", targetBci); + + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); + } else if (profileNode instanceof ProfileInvokeNode) { + ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode; + // Method invocation event + Arguments args = new Arguments(profileMethodEntry, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("counters", counters); + args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog()); + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); + } else { + throw new GraalError("Unsupported profile node type: " + profileNode); + } + + assert profileNode.hasNoUsages(); + if (!profileNode.isDeleted()) { + GraphUtil.killWithUnusedFloatingInputs(profileNode); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ArrayStoreExceptionStub.java 2016-12-07 13:50:49.466961531 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016, 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.stubs; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil; +import org.graalvm.compiler.hotspot.word.KlassPointer; + +import jdk.vm.ci.code.Register; + +/** + */ +public class ArrayStoreExceptionStub extends CreateExceptionStub { + + public ArrayStoreExceptionStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super("createArrayStoreException", providers, linkage); + } + + @Override + protected Object getConstantParameterValue(int index, String name) { + GraalError.guarantee(index == 1, "unknown parameter %s at index %d", name, index); + return providers.getRegisters().getThreadRegister(); + } + + @Snippet + private static Object createArrayStoreException(Object object, @ConstantParameter Register threadRegister) { + KlassPointer klass = HotSpotReplacementsUtil.loadHub(object); + return createException(threadRegister, ArrayStoreException.class, klass); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ClassCastExceptionStub.java 2016-12-07 13:50:49.731973179 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016, 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.stubs; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil; +import org.graalvm.compiler.hotspot.word.KlassPointer; + +import jdk.vm.ci.code.Register; + +/** + */ +public class ClassCastExceptionStub extends CreateExceptionStub { + + public ClassCastExceptionStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super("createClassCastException", providers, linkage); + } + + @Override + protected Object getConstantParameterValue(int index, String name) { + GraalError.guarantee(index == 2, "unknown parameter %s at index %d", name, index); + return providers.getRegisters().getThreadRegister(); + } + + @Snippet + private static Object createClassCastException(Object object, KlassPointer targetKlass, @ConstantParameter Register threadRegister) { + KlassPointer objKlass = HotSpotReplacementsUtil.loadHub(object); + return createException(threadRegister, ClassCastException.class, objKlass, targetKlass); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java 2016-12-07 13:50:49.995984783 -0800 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016, 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.stubs; + +import static org.graalvm.compiler.core.common.LocationIdentity.any; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT; +import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.REEXECUTABLE; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.clearPendingException; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; +import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.replacements.nodes.CStringConstant; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.Register; + +/** + * Base class for stubs that create a runtime exception. + */ +public class CreateExceptionStub extends SnippetStub { + + protected CreateExceptionStub(String snippetMethodName, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super(snippetMethodName, providers, linkage); + } + + @Fold + static String getInternalClassName(Class cls) { + return cls.getName().replace('.', '/'); + } + + private static Word classAsCString(Class cls) { + return CStringConstant.cstring(getInternalClassName(cls)); + } + + protected static Object createException(Register threadRegister, Class exception) { + Word message = null; + return createException(threadRegister, exception, message); + } + + protected static Object createException(Register threadRegister, Class exception, Word message) { + Word thread = registerAsWord(threadRegister); + throwAndPostJvmtiException(THROW_AND_POST_JVMTI_EXCEPTION, thread, classAsCString(exception), message); + return clearPendingException(thread); + } + + protected static Object createException(Register threadRegister, Class exception, KlassPointer klass) { + Word thread = registerAsWord(threadRegister); + throwKlassExternalNameException(THROW_KLASS_EXTERNAL_NAME_EXCEPTION, thread, classAsCString(exception), klass); + return clearPendingException(thread); + } + + protected static Object createException(Register threadRegister, Class exception, KlassPointer objKlass, KlassPointer targetKlass) { + Word thread = registerAsWord(threadRegister); + throwClassCastException(THROW_CLASS_CAST_EXCEPTION, thread, classAsCString(exception), objKlass, targetKlass); + return clearPendingException(thread); + } + + private static final ForeignCallDescriptor THROW_AND_POST_JVMTI_EXCEPTION = new ForeignCallDescriptor("throw_and_post_jvmti_exception", void.class, Word.class, Word.class, Word.class); + private static final ForeignCallDescriptor THROW_KLASS_EXTERNAL_NAME_EXCEPTION = new ForeignCallDescriptor("throw_klass_external_name_exception", void.class, Word.class, Word.class, + KlassPointer.class); + private static final ForeignCallDescriptor THROW_CLASS_CAST_EXCEPTION = new ForeignCallDescriptor("throw_class_cast_exception", void.class, Word.class, Word.class, KlassPointer.class, + KlassPointer.class); + + @NodeIntrinsic(StubForeignCallNode.class) + private static native void throwAndPostJvmtiException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, Word message); + + @NodeIntrinsic(StubForeignCallNode.class) + private static native void throwKlassExternalNameException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, KlassPointer klass); + + @NodeIntrinsic(StubForeignCallNode.class) + private static native void throwClassCastException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, KlassPointer objKlass, KlassPointer targetKlass); + + public static void registerForeignCalls(GraalHotSpotVMConfig c, HotSpotForeignCallsProviderImpl foreignCalls) { + foreignCalls.registerForeignCall(THROW_AND_POST_JVMTI_EXCEPTION, c.throwAndPostJvmtiExceptionAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any()); + foreignCalls.registerForeignCall(THROW_KLASS_EXTERNAL_NAME_EXCEPTION, c.throwKlassExternalNameExceptionAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any()); + foreignCalls.registerForeignCall(THROW_CLASS_CAST_EXCEPTION, c.throwClassCastExceptionAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any()); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/DeoptimizationStub.java 2016-12-07 13:50:50.260996431 -0800 @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2013, 2015, 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.stubs; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.HotSpotBackend.UNPACK_FRAMES; +import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs; +import static org.graalvm.compiler.hotspot.nodes.DeoptimizationFetchUnrollInfoCallNode.fetchUnrollInfo; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.pageSize; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeRegisterAsWord; +import static org.graalvm.compiler.hotspot.stubs.UncommonTrapStub.STACK_BANG_LOCATION; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.EnterUnpackFramesStackFrameNode; +import org.graalvm.compiler.hotspot.nodes.LeaveCurrentStackFrameNode; +import org.graalvm.compiler.hotspot.nodes.LeaveDeoptimizedStackFrameNode; +import org.graalvm.compiler.hotspot.nodes.LeaveUnpackFramesStackFrameNode; +import org.graalvm.compiler.hotspot.nodes.PushInterpreterFrameNode; +import org.graalvm.compiler.hotspot.nodes.SaveAllRegistersNode; +import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; + +/** + * Deoptimization stub. + * + * This is the entry point for code which is returning to a de-optimized frame. + * + * The steps taken by this frame are as follows: + * + *
  • push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all + * potentially live registers (at a pollpoint many registers can be live). + * + *
  • call the C routine: Deoptimization::fetch_unroll_info (this function returns information + * about the number and size of interpreter frames which are equivalent to the frame which is being + * deoptimized) + * + *
  • deallocate the unpack frame, restoring only results values. Other volatile registers will now + * be captured in the vframeArray as needed. + * + *
  • deallocate the deoptimization frame + * + *
  • in a loop using the information returned in the previous step push new interpreter frames + * (take care to propagate the return values through each new frame pushed) + * + *
  • create a dummy "unpack_frame" and save the return values (O0, O1, F0) + * + *
  • call the C routine: Deoptimization::unpack_frames (this function lays out values on the + * interpreter frame which was just created) + * + *
  • deallocate the dummy unpack_frame + * + *
  • ensure that all the return values are correctly set and then do a return to the interpreter + * entry point + * + *

    + * ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet + * because we change the current stack layout and so the code is very sensitive to register + * allocation. + */ +public class DeoptimizationStub extends SnippetStub { + + private final TargetDescription target; + + public DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) { + super(DeoptimizationStub.class, "deoptimizationHandler", providers, linkage); + this.target = target; + assert PreferGraalStubs.getValue(); + } + + @Override + public boolean preservesRegisters() { + return false; + } + + @Override + protected Object getConstantParameterValue(int index, String name) { + switch (index) { + case 0: + return providers.getRegisters().getThreadRegister(); + case 1: + return providers.getRegisters().getStackPointerRegister(); + default: + throw GraalError.shouldNotReachHere("unknown parameter " + name + " at index " + index); + } + } + + /** + * Deoptimization handler for normal deoptimization + * {@link GraalHotSpotVMConfig#deoptimizationUnpackDeopt}. + */ + @Snippet + private static void deoptimizationHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) { + final Word thread = registerAsWord(threadRegister); + final long registerSaver = SaveAllRegistersNode.saveAllRegisters(); + + final Word unrollBlock = fetchUnrollInfo(registerSaver, deoptimizationUnpackDeopt(INJECTED_VMCONFIG)); + + deoptimizationCommon(stackPointerRegister, thread, registerSaver, unrollBlock); + } + + static void deoptimizationCommon(Register stackPointerRegister, final Word thread, final long registerSaver, final Word unrollBlock) { + // Pop all the frames we must move/replace. + // + // Frame picture (youngest to oldest) + // 1: self-frame + // 2: deoptimizing frame + // 3: caller of deoptimizing frame (could be compiled/interpreted). + + // Pop self-frame. + LeaveCurrentStackFrameNode.leaveCurrentStackFrame(registerSaver); + + // Load the initial info we should save (e.g. frame pointer). + final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset(INJECTED_VMCONFIG)); + + // Pop deoptimized frame. + final int sizeOfDeoptimizedFrame = unrollBlock.readInt(deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset(INJECTED_VMCONFIG)); + LeaveDeoptimizedStackFrameNode.leaveDeoptimizedStackFrame(sizeOfDeoptimizedFrame, initialInfo); + + /* + * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for + * total size of the interpreter frames plus shadow page size. Bang one page at a time + * because large sizes can bang beyond yellow and red zones. + * + * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository. + */ + final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset(INJECTED_VMCONFIG)); + final int bangPages = NumUtil.roundUp(totalFrameSizes, pageSize()) / pageSize() + stackShadowPages(INJECTED_VMCONFIG); + Word stackPointer = readRegister(stackPointerRegister); + + for (int i = 1; i < bangPages; i++) { + stackPointer.writeInt((-i * pageSize()) + stackBias(INJECTED_VMCONFIG), 0, STACK_BANG_LOCATION); + } + + // Load number of interpreter frames. + final int numberOfFrames = unrollBlock.readInt(deoptimizationUnrollBlockNumberOfFramesOffset(INJECTED_VMCONFIG)); + + // Load address of array of frame sizes. + final Word frameSizes = unrollBlock.readWord(deoptimizationUnrollBlockFrameSizesOffset(INJECTED_VMCONFIG)); + + // Load address of array of frame PCs. + final Word framePcs = unrollBlock.readWord(deoptimizationUnrollBlockFramePcsOffset(INJECTED_VMCONFIG)); + + /* + * Get the current stack pointer (sender's original SP) before adjustment so that we can + * save it in the skeletal interpreter frame. + */ + Word senderSp = readRegister(stackPointerRegister); + + // Adjust old interpreter frame to make space for new frame's extra Java locals. + final int callerAdjustment = unrollBlock.readInt(deoptimizationUnrollBlockCallerAdjustmentOffset(INJECTED_VMCONFIG)); + writeRegister(stackPointerRegister, readRegister(stackPointerRegister).subtract(callerAdjustment)); + + for (int i = 0; i < numberOfFrames; i++) { + final Word frameSize = frameSizes.readWord(i * wordSize()); + final Word framePc = framePcs.readWord(i * wordSize()); + + // Push an interpreter frame onto the stack. + PushInterpreterFrameNode.pushInterpreterFrame(frameSize, framePc, senderSp, initialInfo); + + // Get the current stack pointer (sender SP) and pass it to next frame. + senderSp = readRegister(stackPointerRegister); + } + + // Get final return address. + final Word framePc = framePcs.readWord(numberOfFrames * wordSize()); + + /* + * Enter a frame to call out to unpack frames. Since we changed the stack pointer to an + * unknown alignment we need to align it here before calling C++ code. + */ + final Word senderFp = initialInfo; + EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp, registerSaver); + + final int mode = unrollBlock.readInt(deoptimizationUnrollBlockUnpackKindOffset(INJECTED_VMCONFIG)); + unpackFrames(UNPACK_FRAMES, thread, mode); + + LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame(registerSaver); + } + + /** + * Reads the value of the passed register as a Word. + */ + private static Word readRegister(Register register) { + return registerAsWord(register, false, false); + } + + /** + * Writes the value of the passed register. + * + * @param value value the register should be set to + */ + private static void writeRegister(Register register, Word value) { + writeRegisterAsWord(register, value); + } + + @Fold + static int stackShadowPages(@InjectedParameter GraalHotSpotVMConfig config) { + return config.useStackBanging ? config.stackShadowPages : 0; + } + + /** + * Returns the stack bias for the host architecture. + * + * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository. + * + * @return stack bias + */ + @Deprecated + @Fold + static int stackBias(@InjectedParameter GraalHotSpotVMConfig config) { + return config.stackBias; + } + + @Fold + static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset; + } + + @Fold + static int deoptimizationUnrollBlockCallerAdjustmentOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockCallerAdjustmentOffset; + } + + @Fold + static int deoptimizationUnrollBlockNumberOfFramesOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockNumberOfFramesOffset; + } + + @Fold + static int deoptimizationUnrollBlockTotalFrameSizesOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockTotalFrameSizesOffset; + } + + @Fold + static int deoptimizationUnrollBlockUnpackKindOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockUnpackKindOffset; + } + + @Fold + static int deoptimizationUnrollBlockFrameSizesOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockFrameSizesOffset; + } + + @Fold + static int deoptimizationUnrollBlockFramePcsOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockFramePcsOffset; + } + + @Fold + static int deoptimizationUnrollBlockInitialInfoOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockInitialInfoOffset; + } + + @Fold + static int deoptimizationUnpackDeopt(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnpackDeopt; + } + + @Fold + static int deoptimizationUnpackUncommonTrap(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnpackUncommonTrap; + } + + @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true) + public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java 2016-12-07 13:50:50.527008123 -0800 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2012, 2015, 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.stubs; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.nodes.JumpToExceptionHandlerNode.jumpToExceptionHandler; +import static org.graalvm.compiler.hotspot.nodes.PatchReturnAddressNode.patchReturnAddress; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readExceptionOop; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readExceptionPc; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeExceptionOop; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeExceptionPc; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.cAssertionsEnabled; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.decipher; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.fatal; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.Register; + +/** + * Stub called by the {@linkplain GraalHotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception + * handler entry point} in a compiled method. This entry point is used when returning to a method to + * handle an exception thrown by a callee. It is not used for routing implicit exceptions. + * Therefore, it does not need to save any registers as HotSpot uses a caller save convention. + *

    + * The descriptor for a call to this stub is {@link HotSpotBackend#EXCEPTION_HANDLER}. + */ +public class ExceptionHandlerStub extends SnippetStub { + + public ExceptionHandlerStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super("exceptionHandler", providers, linkage); + } + + /** + * This stub is called when returning to a method to handle an exception thrown by a callee. It + * is not used for routing implicit exceptions. Therefore, it does not need to save any + * registers as HotSpot uses a caller save convention. + */ + @Override + public boolean preservesRegisters() { + return false; + } + + @Override + protected Object getConstantParameterValue(int index, String name) { + assert index == 2; + return providers.getRegisters().getThreadRegister(); + } + + @Snippet + private static void exceptionHandler(Object exception, Word exceptionPc, @ConstantParameter Register threadRegister) { + Word thread = registerAsWord(threadRegister); + checkNoExceptionInThread(thread, assertionsEnabled(INJECTED_VMCONFIG)); + checkExceptionNotNull(assertionsEnabled(INJECTED_VMCONFIG), exception); + writeExceptionOop(thread, exception); + writeExceptionPc(thread, exceptionPc); + if (logging()) { + printf("handling exception %p (", Word.objectToTrackedPointer(exception).rawValue()); + decipher(Word.objectToTrackedPointer(exception).rawValue()); + printf(") at %p (", exceptionPc.rawValue()); + decipher(exceptionPc.rawValue()); + printf(")\n"); + } + + // patch throwing pc into return address so that deoptimization finds the right debug info + patchReturnAddress(exceptionPc); + + Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread); + + if (logging()) { + printf("handler for exception %p at %p is at %p (", Word.objectToTrackedPointer(exception).rawValue(), exceptionPc.rawValue(), handlerPc.rawValue()); + decipher(handlerPc.rawValue()); + printf(")\n"); + } + + // patch the return address so that this stub returns to the exception handler + jumpToExceptionHandler(handlerPc); + } + + static void checkNoExceptionInThread(Word thread, boolean enabled) { + if (enabled) { + Object currentException = readExceptionOop(thread); + if (currentException != null) { + fatal("exception object in thread must be null, not %p", Word.objectToTrackedPointer(currentException).rawValue()); + } + if (cAssertionsEnabled(INJECTED_VMCONFIG)) { + // This thread-local is only cleared in DEBUG builds of the VM + // (see OptoRuntime::generate_exception_blob) + Word currentExceptionPc = readExceptionPc(thread); + if (currentExceptionPc.notEqual(Word.zero())) { + fatal("exception PC in thread must be zero, not %p", currentExceptionPc.rawValue()); + } + } + } + } + + static void checkExceptionNotNull(boolean enabled, Object exception) { + if (enabled && exception == null) { + fatal("exception must not be null"); + } + } + + @Fold + static boolean logging() { + return StubOptions.TraceExceptionHandlerStub.getValue(); + } + + /** + * Determines if either Java assertions are enabled for {@link ExceptionHandlerStub} or if this + * is a HotSpot build where the ASSERT mechanism is enabled. + *

    + * This first check relies on the per-class assertion status which is why this method must be in + * this class. + */ + @Fold + @SuppressWarnings("all") + static boolean assertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) { + boolean enabled = false; + assert enabled = true; + return enabled || cAssertionsEnabled(config); + } + + public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = newDescriptor(ExceptionHandlerStub.class, "exceptionHandlerForPc", Word.class, Word.class); + + @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true) + public static native Word exceptionHandlerForPc(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForPc, Word thread); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java 2016-12-07 13:50:50.792019771 -0800 @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2012, 2016, 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.stubs; + +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS; +import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCall; +import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCallee; +import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall; + +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.JavaMethodContext; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; +import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.replacements.GraphKit; +import org.graalvm.compiler.replacements.nodes.ReadRegisterNode; +import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.hotspot.HotSpotSignature; +import jdk.vm.ci.meta.JavaMethod; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Signature; + +/** + * A {@linkplain #getGraph generated} stub for a {@link Transition non-leaf} foreign call from + * compiled code. A stub is required for such calls as the caller may be scheduled for + * deoptimization while the call is in progress. And since these are foreign/runtime calls on slow + * paths, we don't want to force the register allocator to spill around the call. As such, this stub + * saves and restores all allocatable registers. It also + * {@linkplain StubUtil#handlePendingException(Word, boolean) handles} any exceptions raised during + * the foreign call. + */ +public class ForeignCallStub extends Stub { + + private final HotSpotJVMCIRuntimeProvider jvmciRuntime; + + /** + * The target of the call. + */ + private final HotSpotForeignCallLinkage target; + + /** + * Specifies if the JavaThread value for the current thread is to be prepended to the arguments + * for the call to {@link #target}. + */ + protected final boolean prependThread; + + /** + * Creates a stub for a call to code at a given address. + * + * @param address the address of the code to call + * @param descriptor the signature of the call to this stub + * @param prependThread true if the JavaThread value for the current thread is to be prepended + * to the arguments for the call to {@code address} + * @param reexecutable specifies if the stub call can be re-executed without (meaningful) side + * effects. Deoptimization will not return to a point before a stub call that cannot + * be re-executed. + * @param killedLocations the memory locations killed by the stub call + */ + public ForeignCallStub(HotSpotJVMCIRuntimeProvider runtime, HotSpotProviders providers, long address, ForeignCallDescriptor descriptor, boolean prependThread, Transition transition, + boolean reexecutable, LocationIdentity... killedLocations) { + super(providers, HotSpotForeignCallLinkageImpl.create(providers.getMetaAccess(), providers.getCodeCache(), providers.getWordTypes(), providers.getForeignCalls(), descriptor, 0L, + PRESERVES_REGISTERS, JavaCall, JavaCallee, transition, reexecutable, killedLocations)); + this.jvmciRuntime = runtime; + this.prependThread = prependThread; + Class[] targetParameterTypes = createTargetParameters(descriptor); + ForeignCallDescriptor targetSig = new ForeignCallDescriptor(descriptor.getName() + ":C", descriptor.getResultType(), targetParameterTypes); + target = HotSpotForeignCallLinkageImpl.create(providers.getMetaAccess(), providers.getCodeCache(), providers.getWordTypes(), providers.getForeignCalls(), targetSig, address, + DESTROYS_REGISTERS, NativeCall, NativeCall, transition, reexecutable, killedLocations); + } + + /** + * Gets the linkage information for the call from this stub. + */ + public HotSpotForeignCallLinkage getTargetLinkage() { + return target; + } + + private Class[] createTargetParameters(ForeignCallDescriptor descriptor) { + Class[] parameters = descriptor.getArgumentTypes(); + if (prependThread) { + Class[] newParameters = new Class[parameters.length + 1]; + System.arraycopy(parameters, 0, newParameters, 1, parameters.length); + newParameters[0] = Word.class; + return newParameters; + } + return parameters; + } + + @Override + protected ResolvedJavaMethod getInstalledCodeOwner() { + return null; + } + + private class DebugScopeContext implements JavaMethod, JavaMethodContext { + @Override + public JavaMethod asJavaMethod() { + return this; + } + + @Override + public Signature getSignature() { + ForeignCallDescriptor d = linkage.getDescriptor(); + MetaAccessProvider metaAccess = providers.getMetaAccess(); + Class[] arguments = d.getArgumentTypes(); + ResolvedJavaType[] parameters = new ResolvedJavaType[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + parameters[i] = metaAccess.lookupJavaType(arguments[i]); + } + return new HotSpotSignature(jvmciRuntime, metaAccess.lookupJavaType(d.getResultType()), parameters); + } + + @Override + public String getName() { + return linkage.getDescriptor().getName(); + } + + @Override + public JavaType getDeclaringClass() { + return providers.getMetaAccess().lookupJavaType(ForeignCallStub.class); + } + + @Override + public String toString() { + return format("ForeignCallStub<%n(%p)>"); + } + } + + @Override + protected Object debugScopeContext() { + return new DebugScopeContext() { + + }; + } + + /** + * Creates a graph for this stub. + *

    + * If the stub returns an object, the graph created corresponds to this pseudo code: + * + *

    +     *     Object foreignFunctionStub(args...) {
    +     *         foreignFunction(currentThread,  args);
    +     *         if (clearPendingException(thread())) {
    +     *             getAndClearObjectResult(thread());
    +     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
    +     *         }
    +     *         return verifyObject(getAndClearObjectResult(thread()));
    +     *     }
    +     * 
    + * + * If the stub returns a primitive or word, the graph created corresponds to this pseudo code + * (using {@code int} as the primitive return type): + * + *
    +     *     int foreignFunctionStub(args...) {
    +     *         int result = foreignFunction(currentThread,  args);
    +     *         if (clearPendingException(thread())) {
    +     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
    +     *         }
    +     *         return result;
    +     *     }
    +     * 
    + * + * If the stub is void, the graph created corresponds to this pseudo code: + * + *
    +     *     void foreignFunctionStub(args...) {
    +     *         foreignFunction(currentThread,  args);
    +     *         if (clearPendingException(thread())) {
    +     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
    +     *         }
    +     *     }
    +     * 
    + * + * In each example above, the {@code currentThread} argument is the C++ JavaThread value (i.e., + * %r15 on AMD64) and is only prepended if {@link #prependThread} is true. + */ + @Override + protected StructuredGraph getGraph(CompilationIdentifier compilationId) { + WordTypes wordTypes = providers.getWordTypes(); + Class[] args = linkage.getDescriptor().getArgumentTypes(); + boolean isObjectResult = !LIRKind.isValue(linkage.getOutgoingCallingConvention().getReturn()); + + StructuredGraph graph = new StructuredGraph(toString(), null, AllowAssumptions.NO, compilationId); + graph.disableUnsafeAccessTracking(); + + GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins()); + ParameterNode[] params = createParameters(kit, args); + + ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false)); + ValueNode result = createTargetCall(kit, params, thread); + kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph)); + if (isObjectResult) { + InvokeNode object = kit.createInvoke(HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread); + result = kit.createInvoke(StubUtil.class, "verifyObject", object); + } + kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result)); + + if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { + Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Initial stub graph"); + } + + kit.inlineInvokes(); + + if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { + Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Stub graph before compilation"); + } + + return graph; + } + + private ParameterNode[] createParameters(GraphKit kit, Class[] args) { + ParameterNode[] params = new ParameterNode[args.length]; + ResolvedJavaType accessingClass = providers.getMetaAccess().lookupJavaType(getClass()); + for (int i = 0; i < args.length; i++) { + ResolvedJavaType type = providers.getMetaAccess().lookupJavaType(args[i]).resolve(accessingClass); + StampPair stamp = StampFactory.forDeclaredType(kit.getGraph().getAssumptions(), type, false); + ParameterNode param = kit.unique(new ParameterNode(i, stamp)); + params[i] = param; + } + return params; + } + + private StubForeignCallNode createTargetCall(GraphKit kit, ParameterNode[] params, ReadRegisterNode thread) { + if (prependThread) { + ValueNode[] targetArguments = new ValueNode[1 + params.length]; + targetArguments[0] = thread; + System.arraycopy(params, 0, targetArguments, 1, params.length); + return kit.append(new StubForeignCallNode(providers.getForeignCalls(), target.getDescriptor(), targetArguments)); + } else { + return kit.append(new StubForeignCallNode(providers.getForeignCalls(), target.getDescriptor(), params)); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java 2016-12-07 13:50:51.058031463 -0800 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2012, 2015, 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.stubs; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayPrototypeMarkWord; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.getAndClearObjectResult; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperElementTypeMask; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperElementTypeShift; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeMask; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeShift; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeMask; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeShift; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadKlassLayoutHelperIntrinsic; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize; +import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH; +import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.formatArray; +import static org.graalvm.compiler.hotspot.stubs.NewInstanceStub.refillAllocate; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.handlePendingException; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.verifyObject; +import static jdk.vm.ci.hotspot.HotSpotMetaAccessProvider.computeArrayAllocationSize; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; +import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.replacements.NewObjectSnippets; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; + +/** + * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is + * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails. + * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++ + * runtime to complete the allocation. + */ +public class NewArrayStub extends SnippetStub { + + public NewArrayStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super("newArray", providers, linkage); + } + + @Override + protected Object[] makeConstArgs() { + HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) providers.getMetaAccess().lookupJavaType(int[].class); + int count = method.getSignature().getParameterCount(false); + Object[] args = new Object[count]; + assert checkConstArg(3, "intArrayHub"); + assert checkConstArg(4, "threadRegister"); + args[3] = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), intArrayType.klass(), null); + args[4] = providers.getRegisters().getThreadRegister(); + return args; + } + + @Fold + static boolean logging() { + return StubOptions.TraceNewArrayStub.getValue(); + } + + /** + * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to + * -XX:-UseTLAB). + * + * @param hub the hub of the object to be allocated + * @param length the length of the array + * @param fillContents Should the array be filled with zeroes? + * @param intArrayHub the hub for {@code int[].class} + */ + @Snippet + private static Object newArray(KlassPointer hub, int length, boolean fillContents, @ConstantParameter KlassPointer intArrayHub, @ConstantParameter Register threadRegister) { + int layoutHelper = loadKlassLayoutHelperIntrinsic(hub); + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG); + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG); + int elementKind = (layoutHelper >> layoutHelperElementTypeShift(INJECTED_VMCONFIG)) & layoutHelperElementTypeMask(INJECTED_VMCONFIG); + int sizeInBytes = computeArrayAllocationSize(length, wordSize(), headerSize, log2ElementSize); + if (logging()) { + printf("newArray: element kind %d\n", elementKind); + printf("newArray: array length %d\n", length); + printf("newArray: array size %d\n", sizeInBytes); + printf("newArray: hub=%p\n", hub.asWord().rawValue()); + } + + // check that array length is small enough for fast path. + Word thread = registerAsWord(threadRegister); + boolean inlineContiguousAllocationSupported = GraalHotSpotVMConfigNode.inlineContiguousAllocationSupported(); + if (inlineContiguousAllocationSupported && length >= 0 && length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) { + Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging()); + if (memory.notEqual(0)) { + if (logging()) { + printf("newArray: allocated new array at %p\n", memory.rawValue()); + } + return verifyObject( + formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord(INJECTED_VMCONFIG)), fillContents, false, false)); + } + } + if (logging()) { + printf("newArray: calling new_array_c\n"); + } + + newArrayC(NEW_ARRAY_C, thread, hub, length); + handlePendingException(thread, true); + return verifyObject(getAndClearObjectResult(thread)); + } + + public static final ForeignCallDescriptor NEW_ARRAY_C = newDescriptor(NewArrayStub.class, "newArrayC", void.class, Word.class, KlassPointer.class, int.class); + + @NodeIntrinsic(StubForeignCallNode.class) + public static native void newArrayC(@ConstantNodeParameter ForeignCallDescriptor newArrayC, Word thread, KlassPointer hub, int length); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java 2016-12-07 13:50:51.323043111 -0800 @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2012, 2015, 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.stubs; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode.compareAndSwap; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HEAP_END_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HEAP_TOP_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_FAST_REFILL_WASTE_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_NOF_REFILLS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_REFILL_WASTE_LIMIT_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_SIZE_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_SLOW_ALLOCATIONS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_THREAD_ALLOCATED_BYTES_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.getAndClearObjectResult; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.initializeTlab; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.isInstanceKlassFullyInitialized; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadKlassLayoutHelperIntrinsic; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.log2WordSize; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.prototypeMarkWordOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabEnd; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabStart; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabTop; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.threadAllocatedBytesOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.threadTlabSizeOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabAlignmentReserveInHeapWords; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabFastRefillWasteOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabIntArrayMarkWord; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabNumberOfRefillsOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabRefillWasteIncrement; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabRefillWasteLimitOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabSlowAllocationsOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabStats; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useG1GC; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useTLAB; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeTlabTop; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.handlePendingException; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.verifyObject; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY; +import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; +import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.replacements.NewObjectSnippets; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.memory.address.RawAddressNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.JavaKind; + +/** + * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is + * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails. + * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++ + * runtime for to complete the allocation. + */ +public class NewInstanceStub extends SnippetStub { + + public NewInstanceStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super("newInstance", providers, linkage); + } + + @Override + protected Object[] makeConstArgs() { + HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) providers.getMetaAccess().lookupJavaType(int[].class); + int count = method.getSignature().getParameterCount(false); + Object[] args = new Object[count]; + assert checkConstArg(1, "intArrayHub"); + assert checkConstArg(2, "threadRegister"); + args[1] = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), intArrayType.klass(), null); + args[2] = providers.getRegisters().getThreadRegister(); + return args; + } + + private static Word allocate(Word thread, int size) { + Word top = readTlabTop(thread); + Word end = readTlabEnd(thread); + Word newTop = top.add(size); + /* + * this check might lead to problems if the TLAB is within 16GB of the address space end + * (checked in c++ code) + */ + if (probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { + writeTlabTop(thread, newTop); + return top; + } + return Word.zero(); + } + + @Fold + static boolean logging() { + return StubOptions.TraceNewInstanceStub.getValue(); + } + + /** + * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to + * -XX:-UseTLAB). + * + * @param hub the hub of the object to be allocated + * @param intArrayHub the hub for {@code int[].class} + */ + @Snippet + private static Object newInstance(KlassPointer hub, @ConstantParameter KlassPointer intArrayHub, @ConstantParameter Register threadRegister) { + /* + * The type is known to be an instance so Klass::_layout_helper is the instance size as a + * raw number + */ + int sizeInBytes = loadKlassLayoutHelperIntrinsic(hub); + Word thread = registerAsWord(threadRegister); + boolean inlineContiguousAllocationSupported = GraalHotSpotVMConfigNode.inlineContiguousAllocationSupported(); + if (!forceSlowPath() && inlineContiguousAllocationSupported) { + if (isInstanceKlassFullyInitialized(hub)) { + Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging()); + if (memory.notEqual(0)) { + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION); + NewObjectSnippets.formatObjectForStub(hub, sizeInBytes, memory, prototypeMarkWord); + return verifyObject(memory.toObject()); + } + } + } + + if (logging()) { + printf("newInstance: calling new_instance_c\n"); + } + + newInstanceC(NEW_INSTANCE_C, thread, hub); + handlePendingException(thread, true); + return verifyObject(getAndClearObjectResult(thread)); + } + + /** + * Attempts to refill the current thread's TLAB and retries the allocation. + * + * @param intArrayHub the hub for {@code int[].class} + * @param sizeInBytes the size of the allocation + * @param log specifies if logging is enabled + * + * @return the newly allocated, uninitialized chunk of memory, or {@link Word#zero()} if the + * operation was unsuccessful + */ + static Word refillAllocate(Word thread, KlassPointer intArrayHub, int sizeInBytes, boolean log) { + // If G1 is enabled, the "eden" allocation space is not the same always + // and therefore we have to go to slowpath to allocate a new TLAB. + if (useG1GC(INJECTED_VMCONFIG)) { + return Word.zero(); + } + if (!useTLAB(INJECTED_VMCONFIG)) { + return edenAllocate(Word.unsigned(sizeInBytes), log); + } + Word intArrayMarkWord = Word.unsigned(tlabIntArrayMarkWord(INJECTED_VMCONFIG)); + int alignmentReserveInBytes = tlabAlignmentReserveInHeapWords(INJECTED_VMCONFIG) * wordSize(); + + Word top = readTlabTop(thread); + Word end = readTlabEnd(thread); + + // calculate amount of free space + long tlabFreeSpaceInBytes = end.subtract(top).rawValue(); + + if (log) { + printf("refillTLAB: thread=%p\n", thread.rawValue()); + printf("refillTLAB: top=%p\n", top.rawValue()); + printf("refillTLAB: end=%p\n", end.rawValue()); + printf("refillTLAB: tlabFreeSpaceInBytes=%ld\n", tlabFreeSpaceInBytes); + } + + long tlabFreeSpaceInWords = tlabFreeSpaceInBytes >>> log2WordSize(); + + // Retain TLAB and allocate object in shared space if + // the amount free in the TLAB is too large to discard. + Word refillWasteLimit = thread.readWord(tlabRefillWasteLimitOffset(INJECTED_VMCONFIG), TLAB_REFILL_WASTE_LIMIT_LOCATION); + if (tlabFreeSpaceInWords <= refillWasteLimit.rawValue()) { + if (tlabStats(INJECTED_VMCONFIG)) { + // increment number of refills + thread.writeInt(tlabNumberOfRefillsOffset(INJECTED_VMCONFIG), thread.readInt(tlabNumberOfRefillsOffset(INJECTED_VMCONFIG), TLAB_NOF_REFILLS_LOCATION) + 1, TLAB_NOF_REFILLS_LOCATION); + if (log) { + printf("thread: %p -- number_of_refills %d\n", thread.rawValue(), thread.readInt(tlabNumberOfRefillsOffset(INJECTED_VMCONFIG), TLAB_NOF_REFILLS_LOCATION)); + } + // accumulate wastage + int wastage = thread.readInt(tlabFastRefillWasteOffset(INJECTED_VMCONFIG), TLAB_FAST_REFILL_WASTE_LOCATION) + (int) tlabFreeSpaceInWords; + if (log) { + printf("thread: %p -- accumulated wastage %d\n", thread.rawValue(), wastage); + } + thread.writeInt(tlabFastRefillWasteOffset(INJECTED_VMCONFIG), wastage, TLAB_FAST_REFILL_WASTE_LOCATION); + } + + // if TLAB is currently allocated (top or end != null) then + // fill [top, end + alignment_reserve) with array object + if (top.notEqual(0)) { + int headerSize = arrayBaseOffset(JavaKind.Int); + // just like the HotSpot assembler stubs, assumes that tlabFreeSpaceInInts fits in + // an int + int tlabFreeSpaceInInts = (int) tlabFreeSpaceInBytes >>> 2; + int length = ((alignmentReserveInBytes - headerSize) >>> 2) + tlabFreeSpaceInInts; + NewObjectSnippets.formatArray(intArrayHub, 0, length, headerSize, top, intArrayMarkWord, false, false, false); + + long allocated = thread.readLong(threadAllocatedBytesOffset(INJECTED_VMCONFIG), TLAB_THREAD_ALLOCATED_BYTES_LOCATION); + allocated = allocated + top.subtract(readTlabStart(thread)).rawValue(); + thread.writeLong(threadAllocatedBytesOffset(INJECTED_VMCONFIG), allocated, TLAB_THREAD_ALLOCATED_BYTES_LOCATION); + } + + // refill the TLAB with an eden allocation + Word tlabRefillSizeInWords = thread.readWord(threadTlabSizeOffset(INJECTED_VMCONFIG), TLAB_SIZE_LOCATION); + Word tlabRefillSizeInBytes = tlabRefillSizeInWords.multiply(wordSize()); + // allocate new TLAB, address returned in top + top = edenAllocate(tlabRefillSizeInBytes, log); + if (top.notEqual(0)) { + end = top.add(tlabRefillSizeInBytes.subtract(alignmentReserveInBytes)); + initializeTlab(thread, top, end); + + return NewInstanceStub.allocate(thread, sizeInBytes); + } else { + return Word.zero(); + } + } else { + // Retain TLAB + Word newRefillWasteLimit = refillWasteLimit.add(tlabRefillWasteIncrement(INJECTED_VMCONFIG)); + thread.writeWord(tlabRefillWasteLimitOffset(INJECTED_VMCONFIG), newRefillWasteLimit, TLAB_REFILL_WASTE_LIMIT_LOCATION); + if (log) { + printf("refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit.rawValue()); + } + + if (tlabStats(INJECTED_VMCONFIG)) { + thread.writeInt(tlabSlowAllocationsOffset(INJECTED_VMCONFIG), thread.readInt(tlabSlowAllocationsOffset(INJECTED_VMCONFIG), TLAB_SLOW_ALLOCATIONS_LOCATION) + 1, + TLAB_SLOW_ALLOCATIONS_LOCATION); + } + + return edenAllocate(Word.unsigned(sizeInBytes), log); + } + } + + /** + * Attempts to allocate a chunk of memory from Eden space. + * + * @param sizeInBytes the size of the chunk to allocate + * @param log specifies if logging is enabled + * @return the allocated chunk or {@link Word#zero()} if allocation fails + */ + public static Word edenAllocate(Word sizeInBytes, boolean log) { + final long heapTopRawAddress = GraalHotSpotVMConfigNode.heapTopAddress(); + final long heapEndRawAddress = GraalHotSpotVMConfigNode.heapEndAddress(); + + Word heapTopAddress = Word.unsigned(heapTopRawAddress); + Word heapEndAddress = Word.unsigned(heapEndRawAddress); + + while (true) { + Word heapTop = heapTopAddress.readWord(0, HEAP_TOP_LOCATION); + Word newHeapTop = heapTop.add(sizeInBytes); + if (newHeapTop.belowOrEqual(heapTop)) { + return Word.zero(); + } + + Word heapEnd = heapEndAddress.readWord(0, HEAP_END_LOCATION); + if (newHeapTop.aboveThan(heapEnd)) { + return Word.zero(); + } + + if (compareAndSwap(RawAddressNode.address(heapTopAddress), heapTop, newHeapTop, HEAP_TOP_LOCATION).equal(heapTop)) { + return heapTop; + } + } + } + + @Fold + static boolean forceSlowPath() { + return StubOptions.ForceUseOfNewInstanceStub.getValue(); + } + + public static final ForeignCallDescriptor NEW_INSTANCE_C = newDescriptor(NewInstanceStub.class, "newInstanceC", void.class, Word.class, KlassPointer.class); + + @NodeIntrinsic(StubForeignCallNode.class) + public static native void newInstanceC(@ConstantNodeParameter ForeignCallDescriptor newInstanceC, Word thread, KlassPointer hub); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NullPointerExceptionStub.java 2016-12-07 13:50:51.590054847 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016, 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.stubs; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; + +import jdk.vm.ci.code.Register; + +/** + * Stub to allocate a {@link NullPointerException} thrown by a bytecode. + */ +public class NullPointerExceptionStub extends CreateExceptionStub { + + public NullPointerExceptionStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super("createNullPointerException", providers, linkage); + } + + @Override + protected Object getConstantParameterValue(int index, String name) { + GraalError.guarantee(index == 0, "unknown parameter %s at index %d", name, index); + return providers.getRegisters().getThreadRegister(); + } + + @Snippet + private static Object createNullPointerException(@ConstantParameter Register threadRegister) { + return createException(threadRegister, NullPointerException.class); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java 2016-12-07 13:50:51.855066495 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, 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.stubs; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.AllocaNode; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.Register; + +/** + * Stub to allocate an {@link ArrayIndexOutOfBoundsException} thrown by a bytecode. + */ +public class OutOfBoundsExceptionStub extends CreateExceptionStub { + + public OutOfBoundsExceptionStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super("createOutOfBoundsException", providers, linkage); + } + + private static final int MAX_INT_STRING_SIZE = Integer.toString(Integer.MIN_VALUE).length(); + + @Override + protected Object getConstantParameterValue(int index, String name) { + switch (index) { + case 1: + return providers.getRegisters().getThreadRegister(); + case 2: + int wordSize = providers.getWordTypes().getWordKind().getByteCount(); + // (MAX_INT_STRING_SIZE + 1) / wordSize, rounded up + return MAX_INT_STRING_SIZE / wordSize + 1; + default: + throw GraalError.shouldNotReachHere("unknown parameter " + name + " at index " + index); + } + } + + @Snippet + private static Object createOutOfBoundsException(int idx, @ConstantParameter Register threadRegister, @ConstantParameter int bufferSizeInWords) { + Word buffer = AllocaNode.alloca(bufferSizeInWords); + + long number = idx; + if (number < 0) { + number = -number; + } + + Word ptr = buffer.add(MAX_INT_STRING_SIZE); + ptr.writeByte(0, (byte) 0); + do { + long digit = number % 10; + number /= 10; + + ptr = ptr.subtract(1); + ptr.writeByte(0, (byte) ('0' + digit)); + } while (number > 0); + + if (idx < 0) { + ptr = ptr.subtract(1); + ptr.writeByte(0, (byte) '-'); + } + + return createException(threadRegister, ArrayIndexOutOfBoundsException.class, ptr); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java 2016-12-07 13:50:52.121078187 -0800 @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2012, 2016, 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.stubs; + +import static org.graalvm.compiler.nodes.StructuredGraph.NO_PROFILING_INFO; +import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING; + +import java.lang.reflect.Method; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; +import org.graalvm.compiler.replacements.ConstantBindingParameterPlugin; +import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.Snippets; + +import jdk.vm.ci.meta.Local; +import jdk.vm.ci.meta.LocalVariableTable; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Base class for a stub defined by a snippet. + */ +public abstract class SnippetStub extends Stub implements Snippets { + + protected final ResolvedJavaMethod method; + + /** + * Creates a new snippet stub. + * + * @param snippetMethodName name of the single {@link Snippet} annotated method in the class of + * this object + * @param linkage linkage details for a call to the stub + */ + public SnippetStub(String snippetMethodName, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + this(null, snippetMethodName, providers, linkage); + } + + /** + * Creates a new snippet stub. + * + * @param snippetDeclaringClass this class in which the {@link Snippet} annotated method is + * declared. If {@code null}, this the class of this object is used. + * @param snippetMethodName name of the single {@link Snippet} annotated method in + * {@code snippetDeclaringClass} + * @param linkage linkage details for a call to the stub + */ + public SnippetStub(Class snippetDeclaringClass, String snippetMethodName, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super(providers, linkage); + Method javaMethod = SnippetTemplate.AbstractTemplates.findMethod(snippetDeclaringClass == null ? getClass() : snippetDeclaringClass, snippetMethodName, null); + this.method = providers.getMetaAccess().lookupJavaMethod(javaMethod); + } + + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean enabled = false; + assert enabled = true; + return enabled; + } + + public static final ThreadLocal SnippetGraphUnderConstruction = assertionsEnabled() ? new ThreadLocal<>() : null; + + @Override + @SuppressWarnings("try") + protected StructuredGraph getGraph(CompilationIdentifier compilationId) { + Plugins defaultPlugins = providers.getGraphBuilderPlugins(); + MetaAccessProvider metaAccess = providers.getMetaAccess(); + SnippetReflectionProvider snippetReflection = providers.getSnippetReflection(); + + Plugins plugins = new Plugins(defaultPlugins); + plugins.prependParameterPlugin(new ConstantBindingParameterPlugin(makeConstArgs(), metaAccess, snippetReflection)); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); + + // Stubs cannot have optimistic assumptions since they have + // to be valid for the entire run of the VM. + final StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, NO_PROFILING_INFO, compilationId); + try (Scope outer = Debug.scope("SnippetStub", graph)) { + graph.disableUnsafeAccessTracking(); + + if (SnippetGraphUnderConstruction != null) { + assert SnippetGraphUnderConstruction.get() == null : SnippetGraphUnderConstruction.get().toString() + " " + graph; + SnippetGraphUnderConstruction.set(graph); + } + + try { + IntrinsicContext initialIntrinsicContext = new IntrinsicContext(method, method, providers.getReplacements().getReplacementBytecodeProvider(), INLINE_AFTER_PARSING); + GraphBuilderPhase.Instance instance = new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), + providers.getConstantReflection(), providers.getConstantFieldProvider(), + config, OptimisticOptimizations.NONE, + initialIntrinsicContext); + instance.apply(graph); + + } finally { + if (SnippetGraphUnderConstruction != null) { + SnippetGraphUnderConstruction.set(null); + } + } + + graph.setGuardsStage(GuardsStage.FLOATING_GUARDS); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + PhaseContext context = new PhaseContext(providers); + canonicalizer.apply(graph, context); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + } catch (Throwable e) { + throw Debug.handle(e); + } + + return graph; + } + + protected boolean checkConstArg(int index, String expectedName) { + assert method.getParameterAnnotation(ConstantParameter.class, index) != null : String.format("parameter %d of %s is expected to be constant", index, method.format("%H.%n(%p)")); + LocalVariableTable lvt = method.getLocalVariableTable(); + if (lvt != null) { + Local local = lvt.getLocal(index, 0); + assert local != null; + String actualName = local.getName(); + assert actualName.equals(expectedName) : String.format("parameter %d of %s is expected to be named %s, not %s", index, method.format("%H.%n(%p)"), expectedName, actualName); + } + return true; + } + + protected Object[] makeConstArgs() { + int count = method.getSignature().getParameterCount(false); + Object[] args = new Object[count]; + for (int i = 0; i < args.length; i++) { + if (method.getParameterAnnotation(ConstantParameter.class, i) != null) { + args[i] = getConstantParameterValue(i, null); + } + } + return args; + } + + protected Object getConstantParameterValue(int index, String name) { + throw new GraalError("%s must override getConstantParameterValue() to provide a value for parameter %d%s", getClass().getName(), index, name == null ? "" : " (" + name + ")"); + } + + @Override + protected Object debugScopeContext() { + return getInstalledCodeOwner(); + } + + @Override + public ResolvedJavaMethod getInstalledCodeOwner() { + return method; + } + + @Override + public String toString() { + return "Stub<" + getInstalledCodeOwner().format("%h.%n") + ">"; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java 2016-12-07 13:50:52.386089835 -0800 @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2012, 2016, 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.stubs; + +import static org.graalvm.compiler.core.GraalCompiler.emitBackEnd; +import static org.graalvm.compiler.core.GraalCompiler.emitFrontEnd; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.target.Backend; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.internal.DebugScope; +import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.StubStartNode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.lir.phases.LIRPhase; +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext; +import org.graalvm.compiler.lir.profiling.MoveProfilingPhase; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.Suites; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.code.site.ConstantReference; +import jdk.vm.ci.code.site.DataPatch; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.hotspot.HotSpotCompiledCode; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.DefaultProfilingInfo; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.TriState; + +//JaCoCo Exclude + +/** + * Base class for implementing some low level code providing the out-of-line slow path for a snippet + * and/or a callee saved call to a HotSpot C/C++ runtime function or even a another compiled Java + * method. + */ +public abstract class Stub { + + private static final List stubs = new ArrayList<>(); + + /** + * The linkage information for a call to this stub from compiled code. + */ + protected final HotSpotForeignCallLinkage linkage; + + /** + * The code installed for the stub. + */ + protected InstalledCode code; + + /** + * Compilation result from which {@link #code} was created. + */ + protected CompilationResult compResult; + + /** + * The registers destroyed by this stub (from the caller's perspective). + */ + private Set destroyedCallerRegisters; + + private HotSpotCompiledCode compiledCode; + + public void initDestroyedCallerRegisters(Set registers) { + assert registers != null; + assert destroyedCallerRegisters == null || registers.equals(destroyedCallerRegisters) : "cannot redefine"; + destroyedCallerRegisters = registers; + } + + /** + * Gets the registers destroyed by this stub from a caller's perspective. These are the + * temporaries of this stub and must thus be caller saved by a callers of this stub. + */ + public Set getDestroyedCallerRegisters() { + assert destroyedCallerRegisters != null : "not yet initialized"; + return destroyedCallerRegisters; + } + + /** + * Determines if this stub preserves all registers apart from those it + * {@linkplain #getDestroyedCallerRegisters() destroys}. + */ + public boolean preservesRegisters() { + return true; + } + + protected final HotSpotProviders providers; + + /** + * Creates a new stub. + * + * @param linkage linkage details for a call to the stub + */ + public Stub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + this.linkage = linkage; + this.providers = providers; + stubs.add(this); + } + + /** + * Gets an immutable view of all stubs that have been created. + */ + public static Collection getStubs() { + return Collections.unmodifiableList(stubs); + } + + /** + * Gets the linkage for a call to this stub from compiled code. + */ + public HotSpotForeignCallLinkage getLinkage() { + return linkage; + } + + public RegisterConfig getRegisterConfig() { + return null; + } + + /** + * Gets the graph that from which the code for this stub will be compiled. + * + * @param compilationId unique compilation id for the stub + */ + protected abstract StructuredGraph getGraph(CompilationIdentifier compilationId); + + @Override + public String toString() { + return "Stub<" + linkage.getDescriptor() + ">"; + } + + /** + * Gets the method the stub's code will be associated with once installed. This may be null. + */ + protected abstract ResolvedJavaMethod getInstalledCodeOwner(); + + /** + * Gets a context object for the debug scope created when producing the code for this stub. + */ + protected abstract Object debugScopeContext(); + + /** + * Gets the code for this stub, compiling it first if necessary. + */ + @SuppressWarnings("try") + public synchronized InstalledCode getCode(final Backend backend) { + if (code == null) { + try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) { + final StructuredGraph graph = getGraph(getStubCompilationId()); + + // Stubs cannot be recompiled so they cannot be compiled with assumptions + assert graph.getAssumptions() == null; + + if (!(graph.start() instanceof StubStartNode)) { + StubStartNode newStart = graph.add(new StubStartNode(Stub.this)); + newStart.setStateAfter(graph.start().stateAfter()); + graph.replaceFixed(graph.start(), newStart); + } + + CodeCacheProvider codeCache = providers.getCodeCache(); + + compResult = new CompilationResult(toString(), GeneratePIC.getValue()); + try (Scope s0 = Debug.scope("StubCompilation", graph, providers.getCodeCache())) { + Suites suites = createSuites(); + emitFrontEnd(providers, backend, graph, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, DefaultProfilingInfo.get(TriState.UNKNOWN), suites); + LIRSuites lirSuites = createLIRSuites(); + emitBackEnd(graph, Stub.this, getInstalledCodeOwner(), backend, compResult, CompilationResultBuilderFactory.Default, getRegisterConfig(), lirSuites); + assert checkStubInvariants(); + } catch (Throwable e) { + throw Debug.handle(e); + } + + assert destroyedCallerRegisters != null; + try (Scope s = Debug.scope("CodeInstall", compResult)) { + // Add a GeneratePIC check here later, we don't want to install + // code if we don't have a corresponding VM global symbol. + compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(null, null, compResult); + code = codeCache.installCode(null, compiledCode, null, null, false); + } catch (Throwable e) { + throw Debug.handle(e); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + assert code != null : "error installing stub " + this; + } + + return code; + } + + public CompilationIdentifier getStubCompilationId() { + return new StubCompilationIdentifier(this); + } + + /** + * Checks the conditions a compilation must satisfy to be installed as a RuntimeStub. + */ + private boolean checkStubInvariants() { + assert compResult.getExceptionHandlers().isEmpty() : this; + + // Stubs cannot be recompiled so they cannot be compiled with + // assumptions and there is no point in recording evol_method dependencies + assert compResult.getAssumptions() == null : "stubs should not use assumptions: " + this; + + for (DataPatch data : compResult.getDataPatches()) { + if (data.reference instanceof ConstantReference) { + ConstantReference ref = (ConstantReference) data.reference; + if (ref.getConstant() instanceof HotSpotMetaspaceConstant) { + HotSpotMetaspaceConstant c = (HotSpotMetaspaceConstant) ref.getConstant(); + if (c.asResolvedJavaType() != null && c.asResolvedJavaType().getName().equals("[I")) { + // special handling for NewArrayStub + // embedding the type '[I' is safe, since it is never unloaded + continue; + } + } + } + + assert !(data.reference instanceof ConstantReference) : this + " cannot have embedded object or metadata constant: " + data.reference; + } + for (Infopoint infopoint : compResult.getInfopoints()) { + assert infopoint instanceof Call : this + " cannot have non-call infopoint: " + infopoint; + Call call = (Call) infopoint; + assert call.target instanceof HotSpotForeignCallLinkage : this + " cannot have non runtime call: " + call.target; + HotSpotForeignCallLinkage callLinkage = (HotSpotForeignCallLinkage) call.target; + assert !callLinkage.isCompiledStub() || callLinkage.getDescriptor().equals(UNCOMMON_TRAP_HANDLER) : this + " cannot call compiled stub " + callLinkage; + } + return true; + } + + protected Suites createSuites() { + Suites defaultSuites = providers.getSuites().getDefaultSuites(); + return new Suites(new PhaseSuite<>(), defaultSuites.getMidTier(), defaultSuites.getLowTier()); + } + + protected LIRSuites createLIRSuites() { + LIRSuites lirSuites = new LIRSuites(providers.getSuites().getDefaultLIRSuites()); + ListIterator> moveProfiling = lirSuites.getPostAllocationOptimizationStage().findPhase(MoveProfilingPhase.class); + if (moveProfiling != null) { + moveProfiling.remove(); + } + return lirSuites; + } + + /** + * Gets the HotSpotCompiledCode that was created during installation. + */ + public synchronized HotSpotCompiledCode getCompiledCode(final Backend backend) { + getCompilationResult(backend); + assert compiledCode != null; + return compiledCode; + } + + /** + * Gets the compilation result for this stub, compiling it first if necessary, and installing it + * in code. + */ + public synchronized CompilationResult getCompilationResult(final Backend backend) { + if (code == null) { + getCode(backend); + } + return compResult; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubCompilationIdentifier.java 2016-12-07 13:50:52.652101527 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016, 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.stubs; + +import java.util.concurrent.atomic.AtomicLong; + +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.debug.GraalError; + +/** + * {@link CompilationIdentifier} for {@linkplain Stub stub compilations}. + */ +public class StubCompilationIdentifier implements CompilationIdentifier { + + private static final AtomicLong uniqueStubIds = new AtomicLong(); + private final long id; + private final Stub stub; + + public StubCompilationIdentifier(Stub stub) { + this.id = uniqueStubIds.getAndIncrement(); + this.stub = stub; + } + + @Override + public final String toString() { + return toString(Verbosity.DETAILED); + } + + @Override + public String toString(Verbosity verbosity) { + switch (verbosity) { + case ID: + return buildID(); + case NAME: + return buildName(); + case DETAILED: + return buildID() + '[' + buildName() + ']'; + } + throw new GraalError("unknown verbosity: " + verbosity); + } + + private String buildName() { + return stub.toString(); + } + + private String buildID() { + return "StubCompilation-" + id; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubOptions.java 2016-12-07 13:50:52.916113131 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013, 2015, 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.stubs; + +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; + +//JaCoCo Exclude + +/** + * Options related to HotSpot Graal-generated stubs. + * + * Note: This must be a top level class to work around for + * Eclipse bug 477597. + */ +public class StubOptions { + // @formatter:off + @Option(help = "Trace execution of stub used to handle an exception thrown by a callee.", type = OptionType.Debug) + static final OptionValue TraceExceptionHandlerStub = new OptionValue<>(false); + + @Option(help = "Trace execution of the stub that routes an exception to a handler in the calling frame.", type = OptionType.Debug) + static final OptionValue TraceUnwindStub = new OptionValue<>(false); + + @Option(help = "Trace execution of slow path stub for array allocation.", type = OptionType.Debug) + static final OptionValue TraceNewArrayStub = new OptionValue<>(false); + + @Option(help = "Trace execution of slow path stub for non-array object allocation.", type = OptionType.Debug) + static final OptionValue TraceNewInstanceStub = new OptionValue<>(false); + + @Option(help = "Force non-array object allocation to always use the slow path.", type = OptionType.Debug) + static final OptionValue ForceUseOfNewInstanceStub = new OptionValue<>(false); + //@formatter:on +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java 2016-12-07 13:50:53.182124823 -0800 @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2013, 2016, 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.stubs; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.clearPendingException; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.getAndClearObjectResult; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHubIntrinsic; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOops; +import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring; +import static org.graalvm.compiler.word.Word.unsigned; +import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.List; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.nodes.DeoptimizeCallerNode; +import org.graalvm.compiler.hotspot.nodes.SnippetAnchorNode; +import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; +import org.graalvm.compiler.hotspot.nodes.VMErrorNode; +import org.graalvm.compiler.hotspot.word.KlassPointer; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.replacements.Log; +import org.graalvm.compiler.word.Pointer; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.meta.DeoptimizationAction; + +//JaCoCo Exclude + +/** + * A collection of methods used in {@link Stub}s. + */ +public class StubUtil { + + public static final ForeignCallDescriptor VM_MESSAGE_C = newDescriptor(StubUtil.class, "vmMessageC", void.class, boolean.class, Word.class, long.class, long.class, long.class); + + public static ForeignCallDescriptor newDescriptor(Class stubClass, String name, Class resultType, Class... argumentTypes) { + ForeignCallDescriptor d = new ForeignCallDescriptor(name, resultType, argumentTypes); + assert descriptorFor(stubClass, name).equals(d) : descriptorFor(stubClass, name) + " != " + d; + return d; + } + + /** + * Looks for a {@link StubForeignCallNode} node intrinsic named {@code name} in + * {@code stubClass} and returns a {@link ForeignCallDescriptor} based on its signature and the + * value of {@code hasSideEffect}. + */ + private static ForeignCallDescriptor descriptorFor(Class stubClass, String name) { + Method found = null; + for (Method method : stubClass.getDeclaredMethods()) { + if (Modifier.isStatic(method.getModifiers()) && method.getAnnotation(NodeIntrinsic.class) != null && method.getName().equals(name)) { + if (method.getAnnotation(NodeIntrinsic.class).value().equals(StubForeignCallNode.class)) { + assert found == null : "found more than one foreign call named " + name + " in " + stubClass; + assert method.getParameterTypes().length != 0 && method.getParameterTypes()[0] == ForeignCallDescriptor.class : "first parameter of foreign call '" + name + "' in " + stubClass + + " must be of type " + ForeignCallDescriptor.class.getSimpleName(); + found = method; + } + } + } + assert found != null : "could not find foreign call named " + name + " in " + stubClass; + List> paramList = Arrays.asList(found.getParameterTypes()); + Class[] cCallTypes = paramList.subList(1, paramList.size()).toArray(new Class[paramList.size() - 1]); + return new ForeignCallDescriptor(name, found.getReturnType(), cCallTypes); + } + + public static void handlePendingException(Word thread, boolean isObjectResult) { + if (clearPendingException(thread) != null) { + if (isObjectResult) { + getAndClearObjectResult(thread); + } + DeoptimizeCallerNode.deopt(DeoptimizationAction.None, RuntimeConstraint); + } + } + + /** + * Determines if this is a HotSpot build where the ASSERT mechanism is enabled. + */ + @Fold + public static boolean cAssertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) { + return config.cAssertions; + } + + @NodeIntrinsic(StubForeignCallNode.class) + private static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); + + /** + * Prints a message to the log stream. + *

    + * Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object + * constant in a RuntimeStub. + * + * @param message a message string + */ + public static void printf(String message) { + vmMessageC(VM_MESSAGE_C, false, cstring(message), 0L, 0L, 0L); + } + + /** + * Prints a message to the log stream. + *

    + * Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object + * constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param value the value associated with the first conversion specifier in {@code format} + */ + public static void printf(String format, long value) { + vmMessageC(VM_MESSAGE_C, false, cstring(format), value, 0L, 0L); + } + + /** + * Prints a message to the log stream. + *

    + * Stubs must use this instead of {@link Log#printf(String, long, long)} to avoid an object + * constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param v1 the value associated with the first conversion specifier in {@code format} + * @param v2 the value associated with the second conversion specifier in {@code format} + */ + public static void printf(String format, long v1, long v2) { + vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, 0L); + } + + /** + * Prints a message to the log stream. + *

    + * Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an + * object constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param v1 the value associated with the first conversion specifier in {@code format} + * @param v2 the value associated with the second conversion specifier in {@code format} + * @param v3 the value associated with the third conversion specifier in {@code format} + */ + public static void printf(String format, long v1, long v2, long v3) { + vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, v3); + } + + /** + * Analyzes a given value and prints information about it to the log stream. + */ + public static void decipher(long value) { + vmMessageC(VM_MESSAGE_C, false, Word.zero(), value, 0L, 0L); + } + + /** + * Exits the VM with a given error message. + *

    + * Stubs must use this instead of {@link VMErrorNode#vmError(String, long)} to avoid an + * object constant in a RuntimeStub. + * + * @param message an error message + */ + public static void fatal(String message) { + vmMessageC(VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L); + } + + /** + * Exits the VM with a given error message. + *

    + * Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an + * object constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param value the value associated with the first conversion specifier in {@code format} + */ + public static void fatal(String format, long value) { + vmMessageC(VM_MESSAGE_C, true, cstring(format), value, 0L, 0L); + } + + /** + * Exits the VM with a given error message. + *

    + * Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an + * object constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param v1 the value associated with the first conversion specifier in {@code format} + * @param v2 the value associated with the second conversion specifier in {@code format} + */ + public static void fatal(String format, long v1, long v2) { + vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, 0L); + } + + /** + * Exits the VM with a given error message. + *

    + * Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an + * object constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param v1 the value associated with the first conversion specifier in {@code format} + * @param v2 the value associated with the second conversion specifier in {@code format} + * @param v3 the value associated with the third conversion specifier in {@code format} + */ + public static void fatal(String format, long v1, long v2, long v3) { + vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, v3); + } + + /** + * Verifies that a given object value is well formed if {@code -XX:+VerifyOops} is enabled. + */ + public static Object verifyObject(Object object) { + if (verifyOops(INJECTED_VMCONFIG)) { + Word verifyOopCounter = Word.unsigned(verifyOopCounterAddress(INJECTED_VMCONFIG)); + verifyOopCounter.writeInt(0, verifyOopCounter.readInt(0) + 1); + + Pointer oop = Word.objectToTrackedPointer(object); + if (object != null) { + GuardingNode anchorNode = SnippetAnchorNode.anchor(); + // make sure object is 'reasonable' + if (!oop.and(unsigned(verifyOopMask(INJECTED_VMCONFIG))).equal(unsigned(verifyOopBits(INJECTED_VMCONFIG)))) { + fatal("oop not in heap: %p", oop.rawValue()); + } + + KlassPointer klass = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode)); + if (klass.isNull()) { + fatal("klass for oop %p is null", oop.rawValue()); + } + } + } + return object; + } + + @Fold + static long verifyOopCounterAddress(@InjectedParameter GraalHotSpotVMConfig config) { + return config.verifyOopCounterAddress; + } + + @Fold + static long verifyOopMask(@InjectedParameter GraalHotSpotVMConfig config) { + return config.verifyOopMask; + } + + @Fold + static long verifyOopBits(@InjectedParameter GraalHotSpotVMConfig config) { + return config.verifyOopBits; + } + + @Fold + static int hubOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.hubOffset; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UncommonTrapStub.java 2016-12-07 13:50:53.452136691 -0800 @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2013, 2016, 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.stubs; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readPendingDeoptimization; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writePendingDeoptimization; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeRegisterAsWord; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.SaveAllRegistersNode; +import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; +import org.graalvm.compiler.hotspot.nodes.UncommonTrapCallNode; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; + +/** + * Uncommon trap stub. + * + * This is the entry point for code which is returning to a de-optimized frame. + * + * The steps taken by this frame are as follows: + * + *

  • push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all + * potentially live registers (at a pollpoint many registers can be live). + * + *
  • call the C routine: Deoptimization::fetch_unroll_info (this function returns information + * about the number and size of interpreter frames which are equivalent to the frame which is being + * deoptimized) + * + *
  • deallocate the unpack frame, restoring only results values. Other volatile registers will now + * be captured in the vframeArray as needed. + * + *
  • deallocate the deoptimization frame + * + *
  • in a loop using the information returned in the previous step push new interpreter frames + * (take care to propagate the return values through each new frame pushed) + * + *
  • create a dummy "unpack_frame" and save the return values (O0, O1, F0) + * + *
  • call the C routine: Deoptimization::unpack_frames (this function lays out values on the + * interpreter frame which was just created) + * + *
  • deallocate the dummy unpack_frame + * + *
  • ensure that all the return values are correctly set and then do a return to the interpreter + * entry point + * + *

    + * ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet + * because we change the current stack layout and so the code is very sensitive to register + * allocation. + */ +public class UncommonTrapStub extends SnippetStub { + + public static final LocationIdentity STACK_BANG_LOCATION = NamedLocationIdentity.mutable("stack bang"); + + private final TargetDescription target; + + public UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) { + super(UncommonTrapStub.class, "uncommonTrapHandler", providers, linkage); + this.target = target; + assert PreferGraalStubs.getValue(); + } + + @Override + public boolean preservesRegisters() { + return false; + } + + @Override + protected Object getConstantParameterValue(int index, String name) { + switch (index) { + case 0: + return providers.getRegisters().getThreadRegister(); + case 1: + return providers.getRegisters().getStackPointerRegister(); + default: + throw GraalError.shouldNotReachHere("unknown parameter " + name + " at index " + index); + } + } + + /** + * Uncommon trap handler. + * + * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This + * routine captures the return values and returns a structure which describes the current frame + * size and the sizes of all replacement frames. The current frame is compiled code and may + * contain many inlined functions, each with their own JVM state. We pop the current frame, then + * push all the new frames. Then we call the C routine unpack_frames() to populate these frames. + * Finally unpack_frames() returns us the new target address. Notice that callee-save registers + * are BLOWN here; they have already been captured in the vframeArray at the time the return PC + * was patched. + */ + @Snippet + private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) { + final Word thread = registerAsWord(threadRegister); + final long registerSaver = SaveAllRegistersNode.saveAllRegisters(); + + final int actionAndReason = readPendingDeoptimization(thread); + writePendingDeoptimization(thread, -1); + + final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason, deoptimizationUnpackUncommonTrap(INJECTED_VMCONFIG)); + + DeoptimizationStub.deoptimizationCommon(stackPointerRegister, thread, registerSaver, unrollBlock); + } + + /** + * Reads the value of the passed register as a Word. + */ + private static Word readRegister(Register register) { + return registerAsWord(register, false, false); + } + + /** + * Writes the value of the passed register. + * + * @param value value the register should be set to + */ + private static void writeRegister(Register register, Word value) { + writeRegisterAsWord(register, value); + } + + @Fold + static int stackShadowPages(@InjectedParameter GraalHotSpotVMConfig config) { + return config.useStackBanging ? config.stackShadowPages : 0; + } + + /** + * Returns the stack bias for the host architecture. + * + * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository. + * + * @return stack bias + */ + @Deprecated + @Fold + static int stackBias(@InjectedParameter GraalHotSpotVMConfig config) { + return config.stackBias; + } + + @Fold + static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset; + } + + @Fold + static int deoptimizationUnrollBlockCallerAdjustmentOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockCallerAdjustmentOffset; + } + + @Fold + static int deoptimizationUnrollBlockNumberOfFramesOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockNumberOfFramesOffset; + } + + @Fold + static int deoptimizationUnrollBlockTotalFrameSizesOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockTotalFrameSizesOffset; + } + + @Fold + static int deoptimizationUnrollBlockFrameSizesOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockFrameSizesOffset; + } + + @Fold + static int deoptimizationUnrollBlockFramePcsOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockFramePcsOffset; + } + + @Fold + static int deoptimizationUnrollBlockInitialInfoOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnrollBlockInitialInfoOffset; + } + + @Fold + static int deoptimizationUnpackDeopt(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnpackDeopt; + } + + @Fold + static int deoptimizationUnpackUncommonTrap(@InjectedParameter GraalHotSpotVMConfig config) { + return config.deoptimizationUnpackUncommonTrap; + } + + @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true) + public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java 2016-12-07 13:50:53.718148383 -0800 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2012, 2015, 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.stubs; + +import static org.graalvm.compiler.hotspot.nodes.JumpToExceptionHandlerInCallerNode.jumpToExceptionHandlerInCaller; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; +import static org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub.checkExceptionNotNull; +import static org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub.checkNoExceptionInThread; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.cAssertionsEnabled; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.decipher; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor; +import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; +import org.graalvm.compiler.nodes.UnwindNode; +import org.graalvm.compiler.word.Pointer; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.Register; + +/** + * Stub called by an {@link UnwindNode}. This stub executes in the frame of the method throwing an + * exception and completes by jumping to the exception handler in the calling frame. + */ +public class UnwindExceptionToCallerStub extends SnippetStub { + + public UnwindExceptionToCallerStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super("unwindExceptionToCaller", providers, linkage); + } + + /** + * The current frame is unwound by this stub. Therefore, it does not need to save any registers + * as HotSpot uses a caller save convention. + */ + @Override + public boolean preservesRegisters() { + return false; + } + + @Override + protected Object getConstantParameterValue(int index, String name) { + assert index == 2; + return providers.getRegisters().getThreadRegister(); + } + + @Snippet + private static void unwindExceptionToCaller(Object exception, Word returnAddress, @ConstantParameter Register threadRegister) { + Pointer exceptionOop = Word.objectToTrackedPointer(exception); + if (logging()) { + printf("unwinding exception %p (", exceptionOop.rawValue()); + decipher(exceptionOop.rawValue()); + printf(") at %p (", returnAddress.rawValue()); + decipher(returnAddress.rawValue()); + printf(")\n"); + } + Word thread = registerAsWord(threadRegister); + checkNoExceptionInThread(thread, assertionsEnabled(null)); + checkExceptionNotNull(assertionsEnabled(null), exception); + + Word handlerInCallerPc = exceptionHandlerForReturnAddress(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, thread, returnAddress); + + if (logging()) { + printf("handler for exception %p at return address %p is at %p (", exceptionOop.rawValue(), returnAddress.rawValue(), handlerInCallerPc.rawValue()); + decipher(handlerInCallerPc.rawValue()); + printf(")\n"); + } + + jumpToExceptionHandlerInCaller(handlerInCallerPc, exception, returnAddress); + } + + @Fold + static boolean logging() { + return StubOptions.TraceUnwindStub.getValue(); + } + + /** + * Determines if either Java assertions are enabled for {@link UnwindExceptionToCallerStub} or + * if this is a HotSpot build where the ASSERT mechanism is enabled. + *

    + * This first check relies on the per-class assertion status which is why this method must be in + * this class. + */ + @Fold + @SuppressWarnings("all") + static boolean assertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) { + boolean enabled = false; + assert enabled = true; + return enabled || cAssertionsEnabled(config); + } + + public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = newDescriptor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", Word.class, Word.class, + Word.class); + + @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true) + public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/VerifyOopStub.java 2016-12-07 13:50:53.983160031 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, 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.stubs; + +import static org.graalvm.compiler.hotspot.stubs.StubUtil.verifyObject; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; + +/** + * Stub called via {@link HotSpotHostForeignCallsProvider#VERIFY_OOP}. + */ +public class VerifyOopStub extends SnippetStub { + + public VerifyOopStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super("verifyOop", providers, linkage); + } + + @Snippet + private static Object verifyOop(Object object) { + return verifyObject(object); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/HotSpotOperation.java 2016-12-07 13:50:54.247171635 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, 2016, 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.word; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface HotSpotOperation { + + enum HotspotOpcode { + FROM_POINTER, + TO_KLASS_POINTER, + TO_METHOD_POINTER, + POINTER_EQ, + POINTER_NE, + IS_NULL, + READ_KLASS_POINTER + } + + HotspotOpcode opcode(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/HotSpotWordTypes.java 2016-12-07 13:50:54.513183327 -0800 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012, 2016, 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.word; + +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp; +import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp; +import org.graalvm.compiler.word.WordTypes; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Extends {@link WordTypes} with information about HotSpot metaspace pointer types. + */ +public class HotSpotWordTypes extends WordTypes { + + /** + * Resolved type for {@link MetaspacePointer}. + */ + private final ResolvedJavaType metaspacePointerType; + + /** + * Resolved type for {@link KlassPointer}. + */ + private final ResolvedJavaType klassPointerType; + + /** + * Resolved type for {@link MethodPointer}. + */ + private final ResolvedJavaType methodPointerType; + + /** + * Resolved type for {@link MethodCountersPointer}. + */ + private final ResolvedJavaType methodCountersPointerType; + + public HotSpotWordTypes(MetaAccessProvider metaAccess, JavaKind wordKind) { + super(metaAccess, wordKind); + this.metaspacePointerType = metaAccess.lookupJavaType(MetaspacePointer.class); + this.klassPointerType = metaAccess.lookupJavaType(KlassPointer.class); + this.methodPointerType = metaAccess.lookupJavaType(MethodPointer.class); + this.methodCountersPointerType = metaAccess.lookupJavaType(MethodCountersPointer.class); + } + + @Override + public boolean isWord(JavaType type) { + if (type instanceof ResolvedJavaType && metaspacePointerType.isAssignableFrom((ResolvedJavaType) type)) { + return true; + } + return super.isWord(type); + } + + @Override + public JavaKind asKind(JavaType type) { + if (klassPointerType.equals(type) || methodPointerType.equals(type)) { + return getWordKind(); + } + return super.asKind(type); + } + + @Override + public Stamp getWordStamp(ResolvedJavaType type) { + if (type.equals(klassPointerType)) { + return KlassPointerStamp.klass(); + } else if (type.equals(methodPointerType)) { + return MethodPointerStamp.method(); + } else if (type.equals(methodCountersPointerType)) { + return MethodCountersPointerStamp.methodCounters(); + } + return super.getWordStamp(type); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/KlassPointer.java 2016-12-07 13:50:54.777194931 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014, 2016, 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.word; + +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_EQ; +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE; +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.READ_KLASS_POINTER; +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.TO_KLASS_POINTER; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.word.Pointer; +import org.graalvm.compiler.word.Word.Opcode; +import org.graalvm.compiler.word.Word.Operation; + +/** + * Marker type for a metaspace pointer to a type. + */ +public abstract class KlassPointer extends MetaspacePointer { + + @HotSpotOperation(opcode = POINTER_EQ) + public abstract boolean equal(KlassPointer other); + + @HotSpotOperation(opcode = POINTER_NE) + public abstract boolean notEqual(KlassPointer other); + + @HotSpotOperation(opcode = TO_KLASS_POINTER) + public static native KlassPointer fromWord(Pointer pointer); + + @HotSpotOperation(opcode = READ_KLASS_POINTER) + public native KlassPointer readKlassPointer(int offset, LocationIdentity locationIdentity); + + @Operation(opcode = Opcode.WRITE_POINTER) + public native void writeKlassPointer(int offset, KlassPointer t, LocationIdentity locationIdentity); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MetaspacePointer.java 2016-12-07 13:50:55.041206535 -0800 @@ -0,0 +1,1002 @@ +/* + * Copyright (c) 2014, 2016, 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.word; + +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.FROM_POINTER; +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.IS_NULL; + +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; +import org.graalvm.compiler.word.Pointer; +import org.graalvm.compiler.word.Signed; +import org.graalvm.compiler.word.Unsigned; +import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.Word.Opcode; +import org.graalvm.compiler.word.Word.Operation; +import org.graalvm.compiler.word.WordBase; + +/** + * Marker type for a metaspace pointer. + */ +public abstract class MetaspacePointer { + + @HotSpotOperation(opcode = IS_NULL) + public abstract boolean isNull(); + + @HotSpotOperation(opcode = FROM_POINTER) + public abstract Pointer asWord(); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract byte readByte(WordBase offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract char readChar(WordBase offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract short readShort(WordBase offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract int readInt(WordBase offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract long readLong(WordBase offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract float readFloat(WordBase offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract double readDouble(WordBase offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract Word readWord(WordBase offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract Object readObject(WordBase offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract byte readByte(int offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract char readChar(int offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract short readShort(int offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract int readInt(int offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract long readLong(int offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract float readFloat(int offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract double readDouble(int offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract Word readWord(int offset, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract Object readObject(int offset, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeChar(WordBase offset, char val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeShort(WordBase offset, short val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeInt(WordBase offset, int val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeLong(WordBase offset, long val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity); + + /** + * Initializes the memory at address {@code (this + offset)}. Both the base address and offset + * are in bytes. The memory must be uninitialized or zero prior to this operation. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.INITIALIZE) + public abstract void initializeLong(WordBase offset, long val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeByte(int offset, byte val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeChar(int offset, char val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeShort(int offset, short val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeInt(int offset, int val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeLong(int offset, long val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeFloat(int offset, float val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeDouble(int offset, double val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeWord(int offset, WordBase val, LocationIdentity locationIdentity); + + /** + * Initializes the memory at address {@code (this + offset)}. Both the base address and offset + * are in bytes. The memory must be uninitialized or zero prior to this operation. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.INITIALIZE) + public abstract void initializeLong(int offset, long val, LocationIdentity locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeObject(int offset, Object val, LocationIdentity locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract byte readByte(WordBase offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract char readChar(WordBase offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract short readShort(WordBase offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract int readInt(WordBase offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract long readLong(WordBase offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract float readFloat(WordBase offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract double readDouble(WordBase offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract Word readWord(WordBase offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract Object readObject(WordBase offset); + + /** + * Reads the memory at address {@code (this + offset)}. This access will decompress the oop if + * the VM uses compressed oops, and it can be parameterized to allow read barriers (G1 referent + * field). + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param barrierType the type of the read barrier to be added + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract Object readObject(WordBase offset, BarrierType barrierType); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract byte readByte(int offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract char readChar(int offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract short readShort(int offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract int readInt(int offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract long readLong(int offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract float readFloat(int offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract double readDouble(int offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract Word readWord(int offset); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract Object readObject(int offset); + + /** + * Reads the memory at address {@code (this + offset)}. This access will decompress the oop if + * the VM uses compressed oops, and it can be parameterized to allow read barriers (G1 referent + * field). + * + * @param offset the signed offset for the memory access + * @param barrierType the type of the read barrier to be added + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER) + public abstract Object readObject(int offset, BarrierType barrierType); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeByte(WordBase offset, byte val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeChar(WordBase offset, char val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeShort(WordBase offset, short val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeInt(WordBase offset, int val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeLong(WordBase offset, long val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeFloat(WordBase offset, float val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeDouble(WordBase offset, double val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeWord(WordBase offset, WordBase val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

    + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeObject(WordBase offset, Object val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeByte(int offset, byte val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeChar(int offset, char val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeShort(int offset, short val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeInt(int offset, int val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeLong(int offset, long val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeFloat(int offset, float val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeDouble(int offset, double val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeWord(int offset, WordBase val); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param val the value to be written to memory + */ + @Operation(opcode = Opcode.WRITE_POINTER) + public abstract void writeObject(int offset, Object val); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodCountersPointer.java 2016-12-07 13:50:55.309218315 -0800 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, 2014, 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.word; + +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_EQ; +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE; + +/** + * Marker type for a metaspace pointer to a method counters. + */ +public abstract class MethodCountersPointer extends MetaspacePointer { + + @HotSpotOperation(opcode = POINTER_EQ) + public abstract boolean equal(MethodCountersPointer other); + + @HotSpotOperation(opcode = POINTER_NE) + public abstract boolean notEqual(MethodCountersPointer other); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodPointer.java 2016-12-07 13:50:55.574229963 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, 2014, 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.word; + +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_EQ; +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE; +import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.TO_METHOD_POINTER; + +import org.graalvm.compiler.word.Pointer; + +/** + * Marker type for a metaspace pointer to a method. + */ +public abstract class MethodPointer extends MetaspacePointer { + + @HotSpotOperation(opcode = POINTER_EQ) + public abstract boolean equal(KlassPointer other); + + @HotSpotOperation(opcode = POINTER_NE) + public abstract boolean notEqual(KlassPointer other); + + @HotSpotOperation(opcode = TO_METHOD_POINTER) + public static native MethodPointer fromWord(Pointer pointer); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/PointerCastNode.java 2016-12-07 13:50:55.839241611 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014, 2014, 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.word; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.Value; + +/** + * Cast between Word and metaspace pointers exposed by the {@link HotspotOpcode#FROM_POINTER} and + * {@link HotspotOpcode#TO_KLASS_POINTER} operations. + */ +@NodeInfo(cycles = CYCLES_0, size = SIZE_0) +public final class PointerCastNode extends FloatingNode implements LIRLowerable, Node.ValueNumberable { + + public static final NodeClass TYPE = NodeClass.create(PointerCastNode.class); + @Input ValueNode input; + + public PointerCastNode(Stamp stamp, ValueNode input) { + super(TYPE, stamp); + this.input = input; + } + + public ValueNode getInput() { + return input; + } + + @Override + public void generate(NodeLIRBuilderTool generator) { + Value value = generator.operand(input); + assert value.getValueKind().equals(generator.getLIRGeneratorTool().getLIRKind(stamp())) : "PointerCastNode shouldn't change the LIRKind"; + + generator.setResult(this, value); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/overview.html 2016-12-07 13:50:56.105253303 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.java project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java 2016-12-07 13:50:56.369264907 -0800 @@ -0,0 +1,1076 @@ +/* + * Copyright (c) 2009, 2015, 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.java; + +import static org.graalvm.compiler.bytecode.Bytecodes.AALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.AASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.ARETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.ARRAYLENGTH; +import static org.graalvm.compiler.bytecode.Bytecodes.ATHROW; +import static org.graalvm.compiler.bytecode.Bytecodes.BALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.BASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.CALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.CASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.DALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.DASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.DRETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.FALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.FASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.FRETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.GETFIELD; +import static org.graalvm.compiler.bytecode.Bytecodes.GOTO; +import static org.graalvm.compiler.bytecode.Bytecodes.GOTO_W; +import static org.graalvm.compiler.bytecode.Bytecodes.IALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.IASTORE; +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.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.IRETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.JSR; +import static org.graalvm.compiler.bytecode.Bytecodes.JSR_W; +import static org.graalvm.compiler.bytecode.Bytecodes.LALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.LASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.LOOKUPSWITCH; +import static org.graalvm.compiler.bytecode.Bytecodes.LRETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.PUTFIELD; +import static org.graalvm.compiler.bytecode.Bytecodes.RET; +import static org.graalvm.compiler.bytecode.Bytecodes.RETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.SALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.SASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH; +import static org.graalvm.compiler.core.common.GraalOptions.SupportJsrBytecodes; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; + +import org.graalvm.compiler.bytecode.Bytecode; +import org.graalvm.compiler.bytecode.BytecodeLookupSwitch; +import org.graalvm.compiler.bytecode.BytecodeStream; +import org.graalvm.compiler.bytecode.BytecodeSwitch; +import org.graalvm.compiler.bytecode.BytecodeTableSwitch; +import org.graalvm.compiler.bytecode.Bytecodes; +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.core.common.CollectionsFactory; +import org.graalvm.compiler.debug.Debug; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.meta.ExceptionHandler; + +/** + * Builds a mapping between bytecodes and basic blocks and builds a conservative control flow graph + * (CFG). It makes one linear passes over the bytecodes to build the CFG where it detects block + * headers and connects them. + *

    + * It also creates exception dispatch blocks for exception handling. These blocks are between a + * bytecode that might throw an exception, and the actual exception handler entries, and are later + * used to create the type checks with the exception handler catch types. If a bytecode is covered + * by an exception handler, this bytecode ends the basic block. This guarantees that a) control flow + * cannot be transferred to an exception dispatch block in the middle of a block, and b) that every + * block has at most one exception dispatch block (which is always the last entry in the successor + * list). + *

    + * If a bytecode is covered by multiple exception handlers, a chain of exception dispatch blocks is + * created so that multiple exception handler types can be checked. The chains are re-used if + * multiple bytecodes are covered by the same exception handlers. + *

    + * Note that exception unwinds, i.e., bytecodes that can throw an exception but the exception is not + * handled in this method, do not end a basic block. Not modeling the exception unwind block reduces + * the complexity of the CFG, and there is no algorithm yet where the exception unwind block would + * matter. + *

    + * The class also handles subroutines (jsr and ret bytecodes): subroutines are inlined by + * duplicating the subroutine blocks. This is limited to simple, structured subroutines with a + * maximum subroutine nesting of 4. Otherwise, a bailout is thrown. + *

    + * Loops in the methods are detected. If a method contains an irreducible loop (a loop with more + * than one entry), a bailout is thrown. This simplifies the compiler later on since only structured + * loops need to be supported. + *

    + * A data flow analysis computes the live local variables from the point of view of the interpreter. + * The result is used later to prune frame states, i.e., remove local variable entries that are + * guaranteed to be never used again (even in the case of deoptimization). + *

    + * The algorithms and analysis in this class are conservative and do not use any assumptions or + * profiling information. + */ +public final class BciBlockMapping { + + public static class BciBlock implements Cloneable { + + protected int id; + public int startBci; + public int endBci; + public boolean isExceptionEntry; + public boolean isLoopHeader; + public int loopId; + public int loopEnd; + protected List successors; + private int predecessorCount; + + private boolean visited; + private boolean active; + public long loops; + public JSRData jsrData; + + public static class JSRData implements Cloneable { + public HashMap jsrAlternatives; + public JsrScope jsrScope = JsrScope.EMPTY_SCOPE; + public BciBlock jsrSuccessor; + public int jsrReturnBci; + public BciBlock retSuccessor; + public boolean endsWithRet = false; + + public JSRData copy() { + try { + return (JSRData) this.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + } + + public BciBlock() { + this.successors = new ArrayList<>(4); + } + + public BciBlock exceptionDispatchBlock() { + if (successors.size() > 0 && successors.get(successors.size() - 1) instanceof ExceptionDispatchBlock) { + return successors.get(successors.size() - 1); + } + return null; + } + + public int getId() { + return id; + } + + public int getPredecessorCount() { + return this.predecessorCount; + } + + public int numNormalSuccessors() { + if (exceptionDispatchBlock() != null) { + return successors.size() - 1; + } + return successors.size(); + } + + public BciBlock copy() { + try { + BciBlock block = (BciBlock) super.clone(); + if (block.jsrData != null) { + block.jsrData = block.jsrData.copy(); + } + block.successors = new ArrayList<>(successors); + return block; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("B").append(getId()); + sb.append('[').append(startBci).append("->").append(endBci); + if (isLoopHeader || isExceptionEntry) { + sb.append(' '); + if (isLoopHeader) { + sb.append('L'); + } + if (isExceptionEntry) { + sb.append('!'); + } + } + sb.append(']'); + return sb.toString(); + } + + public int getLoopDepth() { + return Long.bitCount(loops); + } + + public boolean isLoopHeader() { + return isLoopHeader; + } + + public boolean isExceptionEntry() { + return isExceptionEntry; + } + + public BciBlock getSuccessor(int index) { + return successors.get(index); + } + + /** + * Get the loop id of the inner most loop. + * + * @return the loop id of the most inner loop or -1 if not part of any loop + */ + public int getLoopId() { + long l = loops; + if (l == 0) { + return -1; + } + int pos = 0; + for (int lMask = 1; (l & lMask) == 0; lMask = lMask << 1) { + pos++; + } + return pos; + } + + /** + * Iterate over loop ids. + */ + public Iterable loopIdIterable() { + return new Iterable() { + @Override + public Iterator iterator() { + return idIterator(loops); + } + }; + } + + private static Iterator idIterator(long field) { + return new Iterator() { + + long l = field; + int pos = 0; + int lMask = 1; + + @Override + public Integer next() { + for (; (l & lMask) == 0; lMask = lMask << 1) { + pos++; + } + l &= ~lMask; + return pos; + } + + @Override + public boolean hasNext() { + return l != 0; + } + }; + + } + + public double probability() { + return 1D; + } + + public BciBlock getPostdominator() { + return null; + } + + private JSRData getOrCreateJSRData() { + if (jsrData == null) { + jsrData = new JSRData(); + } + return jsrData; + } + + void setEndsWithRet() { + getOrCreateJSRData().endsWithRet = true; + } + + public JsrScope getJsrScope() { + if (this.jsrData == null) { + return JsrScope.EMPTY_SCOPE; + } else { + return jsrData.jsrScope; + } + } + + public boolean endsWithRet() { + if (this.jsrData == null) { + return false; + } else { + return jsrData.endsWithRet; + } + } + + void setRetSuccessor(BciBlock bciBlock) { + this.getOrCreateJSRData().retSuccessor = bciBlock; + } + + public BciBlock getRetSuccessor() { + if (this.jsrData == null) { + return null; + } else { + return jsrData.retSuccessor; + } + } + + public BciBlock getJsrSuccessor() { + if (this.jsrData == null) { + return null; + } else { + return jsrData.jsrSuccessor; + } + } + + public int getJsrReturnBci() { + if (this.jsrData == null) { + return -1; + } else { + return jsrData.jsrReturnBci; + } + } + + public HashMap getJsrAlternatives() { + if (this.jsrData == null) { + return null; + } else { + return jsrData.jsrAlternatives; + } + } + + public void initJsrAlternatives() { + JSRData data = this.getOrCreateJSRData(); + if (data.jsrAlternatives == null) { + data.jsrAlternatives = new HashMap<>(); + } + } + + void setJsrScope(JsrScope nextScope) { + this.getOrCreateJSRData().jsrScope = nextScope; + } + + void setJsrSuccessor(BciBlock clone) { + this.getOrCreateJSRData().jsrSuccessor = clone; + } + + void setJsrReturnBci(int bci) { + this.getOrCreateJSRData().jsrReturnBci = bci; + } + + public int getSuccessorCount() { + return successors.size(); + } + + public List getSuccessors() { + return successors; + } + + void setId(int i) { + this.id = i; + } + + public void addSuccessor(BciBlock sux) { + successors.add(sux); + sux.predecessorCount++; + } + + public void clearSucccessors() { + for (BciBlock sux : successors) { + sux.predecessorCount--; + } + successors.clear(); + } + } + + public static class ExceptionDispatchBlock extends BciBlock { + + private HashMap exceptionDispatch = new HashMap<>(); + + public ExceptionHandler handler; + public int deoptBci; + } + + /** + * The blocks found in this method, in reverse postorder. + */ + private BciBlock[] blocks; + public final Bytecode code; + public boolean hasJsrBytecodes; + + private final ExceptionHandler[] exceptionHandlers; + private BciBlock startBlock; + private BciBlock[] loopHeaders; + + private static final int LOOP_HEADER_MAX_CAPACITY = Long.SIZE; + private static final int LOOP_HEADER_INITIAL_CAPACITY = 4; + + private int blocksNotYetAssignedId; + public int returnCount; + private int returnBci; + + /** + * Creates a new BlockMap instance from {@code code}. + */ + private BciBlockMapping(Bytecode code) { + this.code = code; + this.exceptionHandlers = code.getExceptionHandlers(); + } + + public BciBlock[] getBlocks() { + return this.blocks; + } + + public int getReturnCount() { + return this.returnCount; + } + + /** + * Builds the block map and conservative CFG and numbers blocks. + */ + public void build(BytecodeStream stream) { + int codeSize = code.getCodeSize(); + BciBlock[] blockMap = new BciBlock[codeSize]; + makeExceptionEntries(blockMap); + iterateOverBytecodes(blockMap, stream); + if (hasJsrBytecodes) { + if (!SupportJsrBytecodes.getValue()) { + throw new JsrNotSupportedBailout("jsr/ret parsing disabled"); + } + createJsrAlternatives(blockMap, blockMap[0]); + } + if (Debug.isLogEnabled()) { + this.log(blockMap, "Before BlockOrder"); + } + computeBlockOrder(blockMap); + fixLoopBits(blockMap); + + assert verify(); + + startBlock = blockMap[0]; + if (Debug.isLogEnabled()) { + this.log(blockMap, "Before LivenessAnalysis"); + } + } + + private boolean verify() { + for (BciBlock block : blocks) { + assert blocks[block.getId()] == block; + + for (int i = 0; i < block.getSuccessorCount(); i++) { + BciBlock sux = block.getSuccessor(i); + if (sux instanceof ExceptionDispatchBlock) { + assert i == block.getSuccessorCount() - 1 : "Only one exception handler allowed, and it must be last in successors list"; + } + } + } + + return true; + } + + private void makeExceptionEntries(BciBlock[] blockMap) { + // start basic blocks at all exception handler blocks and mark them as exception entries + for (ExceptionHandler h : this.exceptionHandlers) { + BciBlock xhandler = makeBlock(blockMap, h.getHandlerBCI()); + xhandler.isExceptionEntry = true; + } + } + + private void iterateOverBytecodes(BciBlock[] blockMap, BytecodeStream stream) { + // iterate over the bytecodes top to bottom. + // mark the entrypoints of basic blocks and build lists of successors for + // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret) + BciBlock current = null; + stream.setBCI(0); + while (stream.currentBC() != Bytecodes.END) { + int bci = stream.currentBCI(); + + if (current == null || blockMap[bci] != null) { + BciBlock b = makeBlock(blockMap, bci); + if (current != null) { + addSuccessor(blockMap, current.endBci, b); + } + current = b; + } + blockMap[bci] = current; + current.endBci = bci; + + switch (stream.currentBC()) { + case IRETURN: // fall through + case LRETURN: // fall through + case FRETURN: // fall through + case DRETURN: // fall through + case ARETURN: // fall through + case RETURN: { + returnCount++; + current = null; + returnBci = bci; + break; + } + case ATHROW: { + current = null; + ExceptionDispatchBlock handler = handleExceptions(blockMap, bci); + if (handler != null) { + addSuccessor(blockMap, bci, handler); + } + break; + } + case IFEQ: // fall through + case IFNE: // fall through + case IFLT: // fall through + case IFGE: // fall through + case IFGT: // fall through + case IFLE: // fall through + case IF_ICMPEQ: // fall through + case IF_ICMPNE: // fall through + case IF_ICMPLT: // fall through + case IF_ICMPGE: // fall through + case IF_ICMPGT: // fall through + case IF_ICMPLE: // fall through + case IF_ACMPEQ: // fall through + case IF_ACMPNE: // fall through + case IFNULL: // fall through + case IFNONNULL: { + current = null; + addSuccessor(blockMap, bci, makeBlock(blockMap, stream.readBranchDest())); + addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI())); + break; + } + case GOTO: + case GOTO_W: { + current = null; + addSuccessor(blockMap, bci, makeBlock(blockMap, stream.readBranchDest())); + break; + } + case TABLESWITCH: { + current = null; + addSwitchSuccessors(blockMap, bci, new BytecodeTableSwitch(stream, bci)); + break; + } + case LOOKUPSWITCH: { + current = null; + addSwitchSuccessors(blockMap, bci, new BytecodeLookupSwitch(stream, bci)); + break; + } + case JSR: + case JSR_W: { + hasJsrBytecodes = true; + int target = stream.readBranchDest(); + if (target == 0) { + throw new JsrNotSupportedBailout("jsr target bci 0 not allowed"); + } + BciBlock b1 = makeBlock(blockMap, target); + current.setJsrSuccessor(b1); + current.setJsrReturnBci(stream.nextBCI()); + current = null; + addSuccessor(blockMap, bci, b1); + break; + } + case RET: { + current.setEndsWithRet(); + current = null; + break; + } + case INVOKEINTERFACE: + case INVOKESPECIAL: + case INVOKESTATIC: + case INVOKEVIRTUAL: + case INVOKEDYNAMIC: { + current = null; + addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI())); + ExceptionDispatchBlock handler = handleExceptions(blockMap, bci); + if (handler != null) { + addSuccessor(blockMap, bci, handler); + } + break; + } + case IASTORE: + case LASTORE: + case FASTORE: + case DASTORE: + case AASTORE: + case BASTORE: + case CASTORE: + case SASTORE: + case IALOAD: + case LALOAD: + case FALOAD: + case DALOAD: + case AALOAD: + case BALOAD: + case CALOAD: + case SALOAD: + case ARRAYLENGTH: + case PUTFIELD: + case GETFIELD: { + ExceptionDispatchBlock handler = handleExceptions(blockMap, bci); + if (handler != null) { + current = null; + addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI())); + addSuccessor(blockMap, bci, handler); + } + } + } + stream.next(); + } + } + + private BciBlock makeBlock(BciBlock[] blockMap, int startBci) { + BciBlock oldBlock = blockMap[startBci]; + if (oldBlock == null) { + BciBlock newBlock = new BciBlock(); + blocksNotYetAssignedId++; + newBlock.startBci = startBci; + blockMap[startBci] = newBlock; + return newBlock; + + } else if (oldBlock.startBci != startBci) { + // Backward branch into the middle of an already processed block. + // Add the correct fall-through successor. + BciBlock newBlock = new BciBlock(); + blocksNotYetAssignedId++; + newBlock.startBci = startBci; + newBlock.endBci = oldBlock.endBci; + for (BciBlock oldSuccessor : oldBlock.getSuccessors()) { + newBlock.addSuccessor(oldSuccessor); + } + + oldBlock.endBci = startBci - 1; + oldBlock.clearSucccessors(); + oldBlock.addSuccessor(newBlock); + + for (int i = startBci; i <= newBlock.endBci; i++) { + blockMap[i] = newBlock; + } + return newBlock; + + } else { + return oldBlock; + } + } + + private void addSwitchSuccessors(BciBlock[] blockMap, int predBci, BytecodeSwitch bswitch) { + // adds distinct targets to the successor list + Collection targets = new TreeSet<>(); + for (int i = 0; i < bswitch.numberOfCases(); i++) { + targets.add(bswitch.targetAt(i)); + } + targets.add(bswitch.defaultTarget()); + for (int targetBci : targets) { + addSuccessor(blockMap, predBci, makeBlock(blockMap, targetBci)); + } + } + + private static void addSuccessor(BciBlock[] blockMap, int predBci, BciBlock sux) { + BciBlock predecessor = blockMap[predBci]; + if (sux.isExceptionEntry) { + throw new PermanentBailoutException("Exception handler can be reached by both normal and exceptional control flow"); + } + predecessor.addSuccessor(sux); + } + + private final ArrayList jsrVisited = new ArrayList<>(); + + private void createJsrAlternatives(BciBlock[] blockMap, BciBlock block) { + jsrVisited.add(block); + JsrScope scope = block.getJsrScope(); + + if (block.endsWithRet()) { + block.setRetSuccessor(blockMap[scope.nextReturnAddress()]); + block.addSuccessor(block.getRetSuccessor()); + assert block.getRetSuccessor() != block.getJsrSuccessor(); + } + Debug.log("JSR alternatives block %s sux %s jsrSux %s retSux %s jsrScope %s", block, block.getSuccessors(), block.getJsrSuccessor(), block.getRetSuccessor(), block.getJsrScope()); + + if (block.getJsrSuccessor() != null || !scope.isEmpty()) { + for (int i = 0; i < block.getSuccessorCount(); i++) { + BciBlock successor = block.getSuccessor(i); + JsrScope nextScope = scope; + if (successor == block.getJsrSuccessor()) { + nextScope = scope.push(block.getJsrReturnBci()); + } + if (successor == block.getRetSuccessor()) { + nextScope = scope.pop(); + } + if (!successor.getJsrScope().isPrefixOf(nextScope)) { + throw new JsrNotSupportedBailout("unstructured control flow (" + successor.getJsrScope() + " " + nextScope + ")"); + } + if (!nextScope.isEmpty()) { + BciBlock clone; + if (successor.getJsrAlternatives() != null && successor.getJsrAlternatives().containsKey(nextScope)) { + clone = successor.getJsrAlternatives().get(nextScope); + } else { + successor.initJsrAlternatives(); + clone = successor.copy(); + blocksNotYetAssignedId++; + clone.setJsrScope(nextScope); + successor.getJsrAlternatives().put(nextScope, clone); + } + block.getSuccessors().set(i, clone); + if (successor == block.getJsrSuccessor()) { + block.setJsrSuccessor(clone); + } + if (successor == block.getRetSuccessor()) { + block.setRetSuccessor(clone); + } + } + } + } + for (BciBlock successor : block.getSuccessors()) { + if (!jsrVisited.contains(successor)) { + createJsrAlternatives(blockMap, successor); + } + } + } + + private HashMap initialExceptionDispatch = CollectionsFactory.newMap(); + + private ExceptionDispatchBlock handleExceptions(BciBlock[] blockMap, int bci) { + ExceptionDispatchBlock lastHandler = null; + + for (int i = exceptionHandlers.length - 1; i >= 0; i--) { + ExceptionHandler h = exceptionHandlers[i]; + if (h.getStartBCI() <= bci && bci < h.getEndBCI()) { + if (h.isCatchAll()) { + // Discard all information about succeeding exception handlers, since they can + // never be reached. + lastHandler = null; + } + + HashMap exceptionDispatch = lastHandler != null ? lastHandler.exceptionDispatch : initialExceptionDispatch; + ExceptionDispatchBlock curHandler = exceptionDispatch.get(h); + if (curHandler == null) { + curHandler = new ExceptionDispatchBlock(); + blocksNotYetAssignedId++; + curHandler.startBci = -1; + curHandler.endBci = -1; + curHandler.deoptBci = bci; + curHandler.handler = h; + curHandler.addSuccessor(blockMap[h.getHandlerBCI()]); + if (lastHandler != null) { + curHandler.addSuccessor(lastHandler); + } + exceptionDispatch.put(h, curHandler); + } + lastHandler = curHandler; + } + } + return lastHandler; + } + + private boolean loopChanges; + + private void fixLoopBits(BciBlock[] blockMap) { + do { + loopChanges = false; + for (BciBlock b : blocks) { + b.visited = false; + } + + long loop = fixLoopBits(blockMap, blockMap[0]); + + if (loop != 0) { + // There is a path from a loop end to the method entry that does not pass the loop + // header. + // Therefore, the loop is non reducible (has more than one entry). + // We don't want to compile such methods because the IR only supports structured + // loops. + throw new PermanentBailoutException("Non-reducible loop: %016x", loop); + } + } while (loopChanges); + } + + private void computeBlockOrder(BciBlock[] blockMap) { + int maxBlocks = blocksNotYetAssignedId; + this.blocks = new BciBlock[blocksNotYetAssignedId]; + long loop = computeBlockOrder(blockMap[0]); + + if (loop != 0) { + // There is a path from a loop end to the method entry that does not pass the loop + // header. Therefore, the loop is non reducible (has more than one entry). + // We don't want to compile such methods because the IR only supports structured loops. + throw new PermanentBailoutException("Non-reducible loop"); + } + + // Purge null entries for unreached blocks and sort blocks such that loop bodies are always + // consecutively in the array. + int blockCount = maxBlocks - blocksNotYetAssignedId + 2; + BciBlock[] newBlocks = new BciBlock[blockCount]; + int next = 0; + for (int i = 0; i < blocks.length; ++i) { + BciBlock b = blocks[i]; + if (b != null) { + b.setId(next); + newBlocks[next++] = b; + if (b.isLoopHeader) { + next = handleLoopHeader(newBlocks, next, i, b); + } + } + } + + // Add return block. + BciBlock returnBlock = new BciBlock(); + returnBlock.startBci = returnBci; + returnBlock.endBci = returnBci; + returnBlock.setId(newBlocks.length - 2); + newBlocks[newBlocks.length - 2] = returnBlock; + + // Add unwind block. + ExceptionDispatchBlock unwindBlock = new ExceptionDispatchBlock(); + unwindBlock.startBci = -1; + unwindBlock.endBci = -1; + unwindBlock.deoptBci = code.getMethod().isSynchronized() ? BytecodeFrame.UNWIND_BCI : BytecodeFrame.AFTER_EXCEPTION_BCI; + unwindBlock.setId(newBlocks.length - 1); + newBlocks[newBlocks.length - 1] = unwindBlock; + + blocks = newBlocks; + } + + private int handleLoopHeader(BciBlock[] newBlocks, int nextStart, int i, BciBlock loopHeader) { + int next = nextStart; + int endOfLoop = nextStart - 1; + for (int j = i + 1; j < blocks.length; ++j) { + BciBlock other = blocks[j]; + if (other != null && (other.loops & (1L << loopHeader.loopId)) != 0) { + other.setId(next); + endOfLoop = next; + newBlocks[next++] = other; + blocks[j] = null; + if (other.isLoopHeader) { + next = handleLoopHeader(newBlocks, next, j, other); + } + } + } + loopHeader.loopEnd = endOfLoop; + return next; + } + + public void log(BciBlock[] blockMap, String name) { + if (Debug.isLogEnabled()) { + String n = System.lineSeparator(); + StringBuilder sb = new StringBuilder(Debug.currentScope()).append("BlockMap ").append(name).append(" :"); + sb.append(n); + Iterable it; + if (blocks == null) { + it = new HashSet<>(Arrays.asList(blockMap)); + } else { + it = Arrays.asList(blocks); + } + for (BciBlock b : it) { + if (b == null) { + continue; + } + sb.append("B").append(b.getId()).append(" (").append(b.startBci).append(" -> ").append(b.endBci).append(")"); + if (b.isLoopHeader) { + sb.append(" LoopHeader"); + } + if (b.isExceptionEntry) { + sb.append(" ExceptionEntry"); + } + sb.append(n).append(" Sux : "); + for (BciBlock s : b.getSuccessors()) { + sb.append("B").append(s.getId()).append(" (").append(s.startBci).append(" -> ").append(s.endBci).append(")"); + if (s.isExceptionEntry) { + sb.append("!"); + } + sb.append(" "); + } + sb.append(n).append(" Loop : "); + for (int pos : b.loopIdIterable()) { + sb.append("B").append(loopHeaders[pos].getId()).append(" "); + } + sb.append(n); + } + Debug.log("%s", sb); + } + } + + /** + * Get the header block for a loop index. + */ + public BciBlock getLoopHeader(int index) { + return loopHeaders[index]; + } + + /** + * The next available loop number. + */ + private int nextLoop; + + /** + * Mark the block as a loop header, using the next available loop number. Also checks for corner + * cases that we don't want to compile. + */ + private void makeLoopHeader(BciBlock block) { + if (!block.isLoopHeader) { + block.isLoopHeader = true; + + if (block.isExceptionEntry) { + // Loops that are implicitly formed by an exception handler lead to all sorts of + // corner cases. + // Don't compile such methods for now, until we see a concrete case that allows + // checking for correctness. + throw new PermanentBailoutException("Loop formed by an exception handler"); + } + if (nextLoop >= LOOP_HEADER_MAX_CAPACITY) { + // This restriction can be removed by using a fall-back to a BitSet in case we have + // more than 64 loops + // Don't compile such methods for now, until we see a concrete case that allows + // checking for correctness. + throw new PermanentBailoutException("Too many loops in method"); + } + + assert block.loops == 0; + block.loops = 1L << nextLoop; + Debug.log("makeLoopHeader(%s) -> %x", block, block.loops); + if (loopHeaders == null) { + loopHeaders = new BciBlock[LOOP_HEADER_INITIAL_CAPACITY]; + } else if (nextLoop >= loopHeaders.length) { + loopHeaders = Arrays.copyOf(loopHeaders, LOOP_HEADER_MAX_CAPACITY); + } + loopHeaders[nextLoop] = block; + block.loopId = nextLoop; + nextLoop++; + } + assert Long.bitCount(block.loops) == 1; + } + + /** + * Depth-first traversal of the control flow graph. The flag {@linkplain BciBlock#visited} is + * used to visit every block only once. The flag {@linkplain BciBlock#active} is used to detect + * cycles (backward edges). + */ + private long computeBlockOrder(BciBlock block) { + if (block.visited) { + if (block.active) { + // Reached block via backward branch. + makeLoopHeader(block); + // Return cached loop information for this block. + return block.loops; + } else if (block.isLoopHeader) { + return block.loops & ~(1L << block.loopId); + } else { + return block.loops; + } + } + + block.visited = true; + block.active = true; + + long loops = 0; + for (BciBlock successor : block.getSuccessors()) { + // Recursively process successors. + loops |= computeBlockOrder(successor); + if (successor.active) { + // Reached block via backward branch. + loops |= (1L << successor.loopId); + } + } + + block.loops = loops; + Debug.log("computeBlockOrder(%s) -> %x", block, block.loops); + + if (block.isLoopHeader) { + loops &= ~(1L << block.loopId); + } + + block.active = false; + blocksNotYetAssignedId--; + blocks[blocksNotYetAssignedId] = block; + + return loops; + } + + private long fixLoopBits(BciBlock[] blockMap, BciBlock block) { + if (block.visited) { + // Return cached loop information for this block. + if (block.isLoopHeader) { + return block.loops & ~(1L << block.loopId); + } else { + return block.loops; + } + } + + block.visited = true; + long loops = block.loops; + for (BciBlock successor : block.getSuccessors()) { + // Recursively process successors. + loops |= fixLoopBits(blockMap, successor); + } + if (block.loops != loops) { + loopChanges = true; + block.loops = loops; + Debug.log("fixLoopBits0(%s) -> %x", block, block.loops); + } + + if (block.isLoopHeader) { + loops &= ~(1L << block.loopId); + } + + return loops; + } + + public static BciBlockMapping create(BytecodeStream stream, Bytecode code) { + BciBlockMapping map = new BciBlockMapping(code); + map.build(stream); + if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { + Debug.dump(Debug.INFO_LOG_LEVEL, map, code.getMethod().format("After block building %f %R %H.%n(%P)")); + } + + return map; + } + + public BciBlock[] getLoopHeaders() { + return loopHeaders; + } + + public BciBlock getStartBlock() { + return startBlock; + } + + public BciBlock getReturnBlock() { + return blocks[blocks.length - 2]; + } + + public ExceptionDispatchBlock getUnwindBlock() { + return (ExceptionDispatchBlock) blocks[blocks.length - 1]; + } + + public int getLoopCount() { + return nextLoop; + } + + public int getBlockCount() { + return blocks.length; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java 2016-12-07 13:50:56.637276687 -0800 @@ -0,0 +1,4118 @@ +/* + * Copyright (c) 2009, 2016, 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.java; + +import static org.graalvm.compiler.bytecode.Bytecodes.AALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.AASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.ACONST_NULL; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.ANEWARRAY; +import static org.graalvm.compiler.bytecode.Bytecodes.ARETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.ARRAYLENGTH; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.ATHROW; +import static org.graalvm.compiler.bytecode.Bytecodes.BALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.BASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.BIPUSH; +import static org.graalvm.compiler.bytecode.Bytecodes.BREAKPOINT; +import static org.graalvm.compiler.bytecode.Bytecodes.CALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.CASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.CHECKCAST; +import static org.graalvm.compiler.bytecode.Bytecodes.D2F; +import static org.graalvm.compiler.bytecode.Bytecodes.D2I; +import static org.graalvm.compiler.bytecode.Bytecodes.D2L; +import static org.graalvm.compiler.bytecode.Bytecodes.DADD; +import static org.graalvm.compiler.bytecode.Bytecodes.DALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.DASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.DCMPG; +import static org.graalvm.compiler.bytecode.Bytecodes.DCMPL; +import static org.graalvm.compiler.bytecode.Bytecodes.DCONST_0; +import static org.graalvm.compiler.bytecode.Bytecodes.DCONST_1; +import static org.graalvm.compiler.bytecode.Bytecodes.DDIV; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.DMUL; +import static org.graalvm.compiler.bytecode.Bytecodes.DNEG; +import static org.graalvm.compiler.bytecode.Bytecodes.DREM; +import static org.graalvm.compiler.bytecode.Bytecodes.DRETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.DSUB; +import static org.graalvm.compiler.bytecode.Bytecodes.DUP; +import static org.graalvm.compiler.bytecode.Bytecodes.DUP2; +import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X1; +import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X2; +import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X1; +import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X2; +import static org.graalvm.compiler.bytecode.Bytecodes.F2D; +import static org.graalvm.compiler.bytecode.Bytecodes.F2I; +import static org.graalvm.compiler.bytecode.Bytecodes.F2L; +import static org.graalvm.compiler.bytecode.Bytecodes.FADD; +import static org.graalvm.compiler.bytecode.Bytecodes.FALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.FASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.FCMPG; +import static org.graalvm.compiler.bytecode.Bytecodes.FCMPL; +import static org.graalvm.compiler.bytecode.Bytecodes.FCONST_0; +import static org.graalvm.compiler.bytecode.Bytecodes.FCONST_1; +import static org.graalvm.compiler.bytecode.Bytecodes.FCONST_2; +import static org.graalvm.compiler.bytecode.Bytecodes.FDIV; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.FMUL; +import static org.graalvm.compiler.bytecode.Bytecodes.FNEG; +import static org.graalvm.compiler.bytecode.Bytecodes.FREM; +import static org.graalvm.compiler.bytecode.Bytecodes.FRETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.FSUB; +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.I2B; +import static org.graalvm.compiler.bytecode.Bytecodes.I2C; +import static org.graalvm.compiler.bytecode.Bytecodes.I2D; +import static org.graalvm.compiler.bytecode.Bytecodes.I2F; +import static org.graalvm.compiler.bytecode.Bytecodes.I2L; +import static org.graalvm.compiler.bytecode.Bytecodes.I2S; +import static org.graalvm.compiler.bytecode.Bytecodes.IADD; +import static org.graalvm.compiler.bytecode.Bytecodes.IALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.IAND; +import static org.graalvm.compiler.bytecode.Bytecodes.IASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_3; +import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_4; +import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_5; +import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_M1; +import static org.graalvm.compiler.bytecode.Bytecodes.IDIV; +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.IINC; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.IMUL; +import static org.graalvm.compiler.bytecode.Bytecodes.INEG; +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.IOR; +import static org.graalvm.compiler.bytecode.Bytecodes.IREM; +import static org.graalvm.compiler.bytecode.Bytecodes.IRETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.ISHL; +import static org.graalvm.compiler.bytecode.Bytecodes.ISHR; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.ISUB; +import static org.graalvm.compiler.bytecode.Bytecodes.IUSHR; +import static org.graalvm.compiler.bytecode.Bytecodes.IXOR; +import static org.graalvm.compiler.bytecode.Bytecodes.JSR; +import static org.graalvm.compiler.bytecode.Bytecodes.JSR_W; +import static org.graalvm.compiler.bytecode.Bytecodes.L2D; +import static org.graalvm.compiler.bytecode.Bytecodes.L2F; +import static org.graalvm.compiler.bytecode.Bytecodes.L2I; +import static org.graalvm.compiler.bytecode.Bytecodes.LADD; +import static org.graalvm.compiler.bytecode.Bytecodes.LALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.LAND; +import static org.graalvm.compiler.bytecode.Bytecodes.LASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.LCMP; +import static org.graalvm.compiler.bytecode.Bytecodes.LCONST_0; +import static org.graalvm.compiler.bytecode.Bytecodes.LCONST_1; +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.LDIV; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.LMUL; +import static org.graalvm.compiler.bytecode.Bytecodes.LNEG; +import static org.graalvm.compiler.bytecode.Bytecodes.LOOKUPSWITCH; +import static org.graalvm.compiler.bytecode.Bytecodes.LOR; +import static org.graalvm.compiler.bytecode.Bytecodes.LREM; +import static org.graalvm.compiler.bytecode.Bytecodes.LRETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.LSHL; +import static org.graalvm.compiler.bytecode.Bytecodes.LSHR; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.LSUB; +import static org.graalvm.compiler.bytecode.Bytecodes.LUSHR; +import static org.graalvm.compiler.bytecode.Bytecodes.LXOR; +import static org.graalvm.compiler.bytecode.Bytecodes.MONITORENTER; +import static org.graalvm.compiler.bytecode.Bytecodes.MONITOREXIT; +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.NOP; +import static org.graalvm.compiler.bytecode.Bytecodes.POP; +import static org.graalvm.compiler.bytecode.Bytecodes.POP2; +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.RETURN; +import static org.graalvm.compiler.bytecode.Bytecodes.SALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.SASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.SIPUSH; +import static org.graalvm.compiler.bytecode.Bytecodes.SWAP; +import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH; +import static org.graalvm.compiler.bytecode.Bytecodes.nameOf; +import static org.graalvm.compiler.core.common.GraalOptions.DeoptALot; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.core.common.GraalOptions.PrintProfilingInformation; +import static org.graalvm.compiler.core.common.GraalOptions.ResolveClassBeforeStaticInvoke; +import static org.graalvm.compiler.core.common.GraalOptions.StressInvokeWithExceptionNode; +import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation; +import static org.graalvm.compiler.core.common.type.StampFactory.objectNonNull; +import static org.graalvm.compiler.debug.GraalError.guarantee; +import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; +import static org.graalvm.compiler.java.BytecodeParserOptions.DumpDuringGraphBuilding; +import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing; +import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins; +import static org.graalvm.compiler.java.BytecodeParserOptions.UseGuardedIntrinsics; +import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_DURING_PARSING; +import static org.graalvm.compiler.nodes.type.StampTool.isPointerNonNull; +import static java.lang.String.format; +import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile; +import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile; +import static jdk.vm.ci.meta.DeoptimizationReason.JavaSubroutineMismatch; +import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException; +import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint; +import static jdk.vm.ci.meta.DeoptimizationReason.TypeCheckedInliningViolated; +import static jdk.vm.ci.meta.DeoptimizationReason.UnreachedCode; +import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved; +import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI; + +import java.lang.ref.Reference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Formatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.graalvm.compiler.bytecode.Bytecode; +import org.graalvm.compiler.bytecode.BytecodeDisassembler; +import org.graalvm.compiler.bytecode.BytecodeLookupSwitch; +import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.bytecode.BytecodeStream; +import org.graalvm.compiler.bytecode.BytecodeSwitch; +import org.graalvm.compiler.bytecode.BytecodeTableSwitch; +import org.graalvm.compiler.bytecode.Bytecodes; +import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; +import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider; +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.common.LocationIdentity; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.FloatConvert; +import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; +import org.graalvm.compiler.core.common.type.AbstractPointerStamp; +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.core.common.type.TypeReference; +import org.graalvm.compiler.core.common.util.Util; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.Indent; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.graph.Graph.Mark; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.java.BciBlockMapping.BciBlock; +import org.graalvm.compiler.java.BciBlockMapping.ExceptionDispatchBlock; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.BeginNode; +import org.graalvm.compiler.nodes.BeginStateSplitNode; +import org.graalvm.compiler.nodes.CallTargetNode; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.ControlSplitNode; +import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.EndNode; +import org.graalvm.compiler.nodes.EntryMarkerNode; +import org.graalvm.compiler.nodes.EntryProxyNode; +import org.graalvm.compiler.nodes.FieldLocationIdentity; +import org.graalvm.compiler.nodes.FixedGuardNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.FullInfopointNode; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.InvokeWithExceptionNode; +import org.graalvm.compiler.nodes.KillingBeginNode; +import org.graalvm.compiler.nodes.LogicConstantNode; +import org.graalvm.compiler.nodes.LogicNegationNode; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.LoopEndNode; +import org.graalvm.compiler.nodes.LoopExitNode; +import org.graalvm.compiler.nodes.MergeNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StartNode; +import org.graalvm.compiler.nodes.StateSplit; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.UnwindNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.AndNode; +import org.graalvm.compiler.nodes.calc.CompareNode; +import org.graalvm.compiler.nodes.calc.ConditionalNode; +import org.graalvm.compiler.nodes.calc.DivNode; +import org.graalvm.compiler.nodes.calc.FloatConvertNode; +import org.graalvm.compiler.nodes.calc.IntegerBelowNode; +import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; +import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; +import org.graalvm.compiler.nodes.calc.IsNullNode; +import org.graalvm.compiler.nodes.calc.LeftShiftNode; +import org.graalvm.compiler.nodes.calc.MulNode; +import org.graalvm.compiler.nodes.calc.NarrowNode; +import org.graalvm.compiler.nodes.calc.NegateNode; +import org.graalvm.compiler.nodes.calc.NormalizeCompareNode; +import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; +import org.graalvm.compiler.nodes.calc.OrNode; +import org.graalvm.compiler.nodes.calc.RemNode; +import org.graalvm.compiler.nodes.calc.RightShiftNode; +import org.graalvm.compiler.nodes.calc.SignExtendNode; +import org.graalvm.compiler.nodes.calc.SignedDivNode; +import org.graalvm.compiler.nodes.calc.SignedRemNode; +import org.graalvm.compiler.nodes.calc.SubNode; +import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode; +import org.graalvm.compiler.nodes.calc.XorNode; +import org.graalvm.compiler.nodes.calc.ZeroExtendNode; +import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationBeginNode; +import org.graalvm.compiler.nodes.extended.AnchoringNode; +import org.graalvm.compiler.nodes.extended.BranchProbabilityNode; +import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode; +import org.graalvm.compiler.nodes.extended.GuardedNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; +import org.graalvm.compiler.nodes.extended.LoadHubNode; +import org.graalvm.compiler.nodes.extended.LoadMethodNode; +import org.graalvm.compiler.nodes.extended.MembarNode; +import org.graalvm.compiler.nodes.extended.ValueAnchorNode; +import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo; +import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver; +import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.ProfilingPlugin; +import org.graalvm.compiler.nodes.java.ArrayLengthNode; +import org.graalvm.compiler.nodes.java.ExceptionObjectNode; +import org.graalvm.compiler.nodes.java.FinalFieldBarrierNode; +import org.graalvm.compiler.nodes.java.InstanceOfNode; +import org.graalvm.compiler.nodes.java.LoadFieldNode; +import org.graalvm.compiler.nodes.java.LoadIndexedNode; +import org.graalvm.compiler.nodes.java.MethodCallTargetNode; +import org.graalvm.compiler.nodes.java.MonitorEnterNode; +import org.graalvm.compiler.nodes.java.MonitorExitNode; +import org.graalvm.compiler.nodes.java.MonitorIdNode; +import org.graalvm.compiler.nodes.java.NewArrayNode; +import org.graalvm.compiler.nodes.java.NewInstanceNode; +import org.graalvm.compiler.nodes.java.NewMultiArrayNode; +import org.graalvm.compiler.nodes.java.RegisterFinalizerNode; +import org.graalvm.compiler.nodes.java.StoreFieldNode; +import org.graalvm.compiler.nodes.java.StoreIndexedNode; +import org.graalvm.compiler.nodes.spi.StampProvider; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.phases.OptimisticOptimizations; + +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.code.site.InfopointReason; +import jdk.vm.ci.meta.ConstantPool; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaField; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaMethod; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.JavaTypeProfile; +import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType; +import jdk.vm.ci.meta.LineNumberTable; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ProfilingInfo; +import jdk.vm.ci.meta.RawConstant; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.TriState; + +/** + * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. + */ +public class BytecodeParser implements GraphBuilderContext { + + /** + * The minimum value to which {@link BytecodeParserOptions#TraceBytecodeParserLevel} must be set + * to trace the bytecode instructions as they are parsed. + */ + public static final int TRACELEVEL_INSTRUCTIONS = 1; + + /** + * The minimum value to which {@link BytecodeParserOptions#TraceBytecodeParserLevel} must be set + * to trace the frame state before each bytecode instruction as it is parsed. + */ + public static final int TRACELEVEL_STATE = 2; + + /** + * Meters the number of actual bytecodes parsed. + */ + public static final DebugCounter BytecodesParsed = Debug.counter("BytecodesParsed"); + + protected static final DebugCounter EXPLICIT_EXCEPTIONS = Debug.counter("ExplicitExceptions"); + + /** + * A scoped object for tasks to be performed after parsing an intrinsic such as processing + * {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frames states. + */ + static class IntrinsicScope implements AutoCloseable { + FrameState stateBefore; + final Mark mark; + final BytecodeParser parser; + + /** + * Creates a scope for root parsing an intrinsic. + * + * @param parser the parsing context of the intrinsic + */ + IntrinsicScope(BytecodeParser parser) { + this.parser = parser; + assert parser.parent == null; + assert parser.bci() == 0; + mark = null; + } + + /** + * Creates a scope for parsing an intrinsic during graph builder inlining. + * + * @param parser the parsing context of the (non-intrinsic) method calling the intrinsic + * @param args the arguments to the call + */ + IntrinsicScope(BytecodeParser parser, JavaKind[] argSlotKinds, ValueNode[] args) { + assert !parser.parsingIntrinsic(); + this.parser = parser; + mark = parser.getGraph().getMark(); + stateBefore = parser.frameState.create(parser.bci(), parser.getNonIntrinsicAncestor(), false, argSlotKinds, args); + } + + @Override + public void close() { + IntrinsicContext intrinsic = parser.intrinsicContext; + if (intrinsic != null && intrinsic.isPostParseInlined()) { + return; + } + + processPlaceholderFrameStates(intrinsic); + } + + /** + * Fixes up the {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frame states + * added to the graph while parsing/inlining the intrinsic for which this object exists. + */ + private void processPlaceholderFrameStates(IntrinsicContext intrinsic) { + FrameState stateAfterReturn = null; + StructuredGraph graph = parser.getGraph(); + for (Node node : graph.getNewNodes(mark)) { + if (node instanceof FrameState) { + FrameState frameState = (FrameState) node; + if (BytecodeFrame.isPlaceholderBci(frameState.bci)) { + if (frameState.bci == BytecodeFrame.AFTER_BCI) { + FrameStateBuilder frameStateBuilder = parser.frameState; + if (frameState.stackSize() != 0) { + assert frameState.usages().count() == 1; + ValueNode returnVal = frameState.stackAt(0); + assert returnVal == frameState.usages().first(); + + if (parser.currentInvokeReturnType == null) { + assert intrinsic.isCompilationRoot(); + FrameState newFrameState = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI)); + frameState.replaceAndDelete(newFrameState); + } else { + /* + * Swap the top-of-stack value with the side-effect return value + * using the frame state. + */ + JavaKind returnKind = parser.currentInvokeReturnType.getJavaKind(); + ValueNode tos = frameStateBuilder.pop(returnKind); + assert tos.getStackKind() == returnVal.getStackKind(); + FrameState newFrameState = frameStateBuilder.create(parser.stream.nextBCI(), parser.getNonIntrinsicAncestor(), false, new JavaKind[]{returnKind}, + new ValueNode[]{returnVal}); + frameState.replaceAndDelete(newFrameState); + frameStateBuilder.push(returnKind, tos); + } + } else { + if (stateAfterReturn == null) { + if (intrinsic != null) { + assert intrinsic.isCompilationRoot(); + stateAfterReturn = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI)); + } else { + stateAfterReturn = frameStateBuilder.create(parser.stream.nextBCI(), null); + } + } + frameState.replaceAndDelete(stateAfterReturn); + } + } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) { + if (stateBefore == null) { + stateBefore = graph.start().stateAfter(); + } + if (stateBefore != frameState) { + frameState.replaceAndDelete(stateBefore); + } + } else { + assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI; + } + } + } + } + } + } + + private static class Target { + FixedNode fixed; + FrameStateBuilder state; + + Target(FixedNode fixed, FrameStateBuilder state) { + this.fixed = fixed; + this.state = state; + } + } + + @SuppressWarnings("serial") + public static class BytecodeParserError extends GraalError { + + public BytecodeParserError(Throwable cause) { + super(cause); + } + + public BytecodeParserError(String msg, Object... args) { + super(msg, args); + } + } + + private final GraphBuilderPhase.Instance graphBuilderInstance; + protected final StructuredGraph graph; + + private BciBlockMapping blockMap; + private LocalLiveness liveness; + protected final int entryBCI; + private final BytecodeParser parent; + + private LineNumberTable lnt; + private int previousLineNumber; + private int currentLineNumber; + + private ValueNode methodSynchronizedObject; + + private ValueNode returnValue; + private FixedWithNextNode beforeReturnNode; + private ValueNode unwindValue; + private FixedWithNextNode beforeUnwindNode; + + protected FixedWithNextNode lastInstr; // the last instruction added + private boolean controlFlowSplit; + private final InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(this); + + private FixedWithNextNode[] firstInstructionArray; + private FrameStateBuilder[] entryStateArray; + + private int lastBCI; // BCI of lastInstr. This field is for resolving instrumentation target. + + private boolean finalBarrierRequired; + private ValueNode originalReceiver; + + protected BytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, + int entryBCI, IntrinsicContext intrinsicContext) { + this.bytecodeProvider = intrinsicContext == null ? new ResolvedJavaMethodBytecodeProvider() : intrinsicContext.getBytecodeProvider(); + this.code = bytecodeProvider.getBytecode(method); + this.method = code.getMethod(); + this.graphBuilderInstance = graphBuilderInstance; + this.graph = graph; + this.graphBuilderConfig = graphBuilderInstance.graphBuilderConfig; + this.optimisticOpts = graphBuilderInstance.optimisticOpts; + this.metaAccess = graphBuilderInstance.metaAccess; + this.stampProvider = graphBuilderInstance.stampProvider; + this.constantReflection = graphBuilderInstance.constantReflection; + this.constantFieldProvider = graphBuilderInstance.constantFieldProvider; + this.stream = new BytecodeStream(code.getCode()); + this.profilingInfo = graph.useProfilingInfo() ? code.getProfilingInfo() : null; + this.constantPool = code.getConstantPool(); + this.intrinsicContext = intrinsicContext; + this.entryBCI = entryBCI; + this.parent = parent; + this.lastBCI = -1; + + assert code.getCode() != null : "method must contain bytecodes: " + method; + + if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) { + lnt = code.getLineNumberTable(); + previousLineNumber = -1; + } + } + + protected GraphBuilderPhase.Instance getGraphBuilderInstance() { + return graphBuilderInstance; + } + + public ValueNode getReturnValue() { + return returnValue; + } + + public FixedWithNextNode getBeforeReturnNode() { + return this.beforeReturnNode; + } + + public ValueNode getUnwindValue() { + return unwindValue; + } + + public FixedWithNextNode getBeforeUnwindNode() { + return this.beforeUnwindNode; + } + + @SuppressWarnings("try") + protected void buildRootMethod() { + FrameStateBuilder startFrameState = new FrameStateBuilder(this, code, graph); + startFrameState.initializeForMethodStart(graph.getAssumptions(), graphBuilderConfig.eagerResolving() || intrinsicContext != null, graphBuilderConfig.getPlugins()); + + try (IntrinsicScope s = intrinsicContext != null ? new IntrinsicScope(this) : null) { + build(graph.start(), startFrameState); + } + + cleanupFinalGraph(); + ComputeLoopFrequenciesClosure.compute(graph); + } + + @SuppressWarnings("try") + protected void build(FixedWithNextNode startInstruction, FrameStateBuilder startFrameState) { + if (PrintProfilingInformation.getValue() && profilingInfo != null) { + TTY.println("Profiling info for " + method.format("%H.%n(%p)")); + TTY.println(Util.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), " ")); + } + + try (Indent indent = Debug.logAndIndent("build graph for %s", method)) { + if (bytecodeProvider.shouldRecordMethodDependencies()) { + assert getParent() != null || method.equals(graph.method()); + // Record method dependency in the graph + graph.recordMethod(method); + } + + // compute the block map, setup exception handlers and get the entrypoint(s) + BciBlockMapping newMapping = BciBlockMapping.create(stream, code); + this.blockMap = newMapping; + this.firstInstructionArray = new FixedWithNextNode[blockMap.getBlockCount()]; + this.entryStateArray = new FrameStateBuilder[blockMap.getBlockCount()]; + if (!method.isStatic()) { + originalReceiver = startFrameState.loadLocal(0, JavaKind.Object); + } + + /* + * Configure the assertion checking behavior of the FrameStateBuilder. This needs to be + * done only when assertions are enabled, so it is wrapped in an assertion itself. + */ + assert computeKindVerification(startFrameState); + + try (Scope s = Debug.scope("LivenessAnalysis")) { + int maxLocals = method.getMaxLocals(); + liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount()); + } catch (Throwable e) { + throw Debug.handle(e); + } + + lastInstr = startInstruction; + this.setCurrentFrameState(startFrameState); + stream.setBCI(0); + + BciBlock startBlock = blockMap.getStartBlock(); + if (this.parent == null) { + StartNode startNode = graph.start(); + if (method.isSynchronized()) { + assert !parsingIntrinsic(); + startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI, startNode)); + } else { + if (!parsingIntrinsic()) { + if (graph.method() != null && graph.method().isJavaLangObjectInit()) { + /* + * Don't clear the receiver when Object. is the compilation root. + * The receiver is needed as input to RegisterFinalizerNode. + */ + } else { + frameState.clearNonLiveLocals(startBlock, liveness, true); + } + assert bci() == 0; + startNode.setStateAfter(createFrameState(bci(), startNode)); + } else { + if (startNode.stateAfter() == null) { + FrameState stateAfterStart = createStateAfterStartOfReplacementGraph(); + startNode.setStateAfter(stateAfterStart); + } + } + } + } + + if (method.isSynchronized()) { + // add a monitor enter to the start block + methodSynchronizedObject = synchronizedObject(frameState, method); + frameState.clearNonLiveLocals(startBlock, liveness, true); + assert bci() == 0; + genMonitorEnter(methodSynchronizedObject, bci()); + } + + ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); + if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + profilingPlugin.profileInvoke(this, method, stateBefore); + } + + finishPrepare(lastInstr); + + genInfoPointNode(InfopointReason.METHOD_START, null); + + currentBlock = blockMap.getStartBlock(); + setEntryState(startBlock, frameState); + if (startBlock.isLoopHeader) { + appendGoto(startBlock); + } else { + setFirstInstruction(startBlock, lastInstr); + } + + BciBlock[] blocks = blockMap.getBlocks(); + for (BciBlock block : blocks) { + processBlock(block); + } + + if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL) && DumpDuringGraphBuilding.getValue() && this.beforeReturnNode != startInstruction) { + Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Bytecodes parsed: %s.%s", method.getDeclaringClass().getUnqualifiedName(), method.getName()); + } + } + } + + private boolean computeKindVerification(FrameStateBuilder startFrameState) { + if (blockMap.hasJsrBytecodes) { + /* + * The JSR return address is an int value, but stored using the astore bytecode. Instead + * of weakening the kind assertion checking for all methods, we disable it completely + * for methods that contain a JSR bytecode. + */ + startFrameState.disableKindVerification(); + } + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.canChangeStackKind(this)) { + /* + * We have a plugin that can change the kind of values, so no kind assertion + * checking is possible. + */ + startFrameState.disableKindVerification(); + } + } + return true; + } + + /** + * Hook for subclasses to modify the graph start instruction or append new instructions to it. + * + * @param startInstr the start instruction of the graph + */ + protected void finishPrepare(FixedWithNextNode startInstr) { + } + + protected void cleanupFinalGraph() { + GraphUtil.normalizeLoops(graph); + + // Remove dead parameters. + for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { + if (param.hasNoUsages()) { + assert param.inputs().isEmpty(); + param.safeDelete(); + } + } + + // Remove redundant begin nodes. + for (BeginNode beginNode : graph.getNodes(BeginNode.TYPE)) { + Node predecessor = beginNode.predecessor(); + if (predecessor instanceof ControlSplitNode) { + // The begin node is necessary. + } else { + if (beginNode.hasUsages()) { + reanchorGuardedNodes(beginNode); + } + GraphUtil.unlinkFixedNode(beginNode); + beginNode.safeDelete(); + } + } + } + + /** + * Removes {@link GuardedNode}s from {@code beginNode}'s usages and re-attaches them to an + * appropriate preceeding {@link GuardingNode}. + */ + protected void reanchorGuardedNodes(BeginNode beginNode) { + // Find the new guarding node + GuardingNode guarding = null; + Node pred = beginNode.predecessor(); + while (pred != null) { + if (pred instanceof BeginNode) { + if (pred.predecessor() instanceof ControlSplitNode) { + guarding = (GuardingNode) pred; + break; + } + } else if (pred.getNodeClass().getAllowedUsageTypes().contains(InputType.Guard)) { + guarding = (GuardingNode) pred; + break; + } + pred = pred.predecessor(); + } + + // Reset the guard for all of beginNode's usages + for (Node usage : beginNode.usages().snapshot()) { + GuardedNode guarded = (GuardedNode) usage; + assert guarded.getGuard() == beginNode; + guarded.setGuard(guarding); + } + assert beginNode.hasNoUsages() : beginNode; + } + + /** + * Creates the frame state after the start node of a graph for an {@link IntrinsicContext + * intrinsic} that is the parse root (either for root compiling or for post-parse inlining). + */ + private FrameState createStateAfterStartOfReplacementGraph() { + assert parent == null; + assert frameState.getMethod().equals(intrinsicContext.getIntrinsicMethod()); + assert bci() == 0; + assert frameState.stackSize() == 0; + FrameState stateAfterStart; + if (intrinsicContext.isPostParseInlined()) { + stateAfterStart = graph.add(new FrameState(BytecodeFrame.BEFORE_BCI)); + } else { + ResolvedJavaMethod original = intrinsicContext.getOriginalMethod(); + ValueNode[] locals; + if (original.getMaxLocals() == frameState.localsSize() || original.isNative()) { + locals = new ValueNode[original.getMaxLocals()]; + for (int i = 0; i < locals.length; i++) { + ValueNode node = frameState.locals[i]; + if (node == FrameState.TWO_SLOT_MARKER) { + node = null; + } + locals[i] = node; + } + } else { + locals = new ValueNode[original.getMaxLocals()]; + int parameterCount = original.getSignature().getParameterCount(!original.isStatic()); + for (int i = 0; i < parameterCount; i++) { + ValueNode param = frameState.locals[i]; + if (param == FrameState.TWO_SLOT_MARKER) { + param = null; + } + locals[i] = param; + assert param == null || param instanceof ParameterNode || param.isConstant(); + } + } + ValueNode[] stack = {}; + int stackSize = 0; + ValueNode[] locks = {}; + List monitorIds = Collections.emptyList(); + stateAfterStart = graph.add(new FrameState(null, new ResolvedJavaMethodBytecode(original), 0, locals, stack, stackSize, locks, monitorIds, false, false)); + } + return stateAfterStart; + } + + /** + * @param type the unresolved type of the constant + */ + protected void handleUnresolvedLoadConstant(JavaType type) { + assert !graphBuilderConfig.eagerResolving(); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + } + + /** + * @param type the unresolved type of the type check + * @param object the object value whose type is being checked against {@code type} + */ + protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) { + assert !graphBuilderConfig.eagerResolving(); + append(new FixedGuardNode(graph.unique(IsNullNode.create(object)), Unresolved, InvalidateRecompile)); + frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER)); + } + + /** + * @param type the unresolved type of the type check + * @param object the object value whose type is being checked against {@code type} + */ + protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) { + assert !graphBuilderConfig.eagerResolving(); + AbstractBeginNode successor = graph.add(new BeginNode()); + DeoptimizeNode deopt = graph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + append(new IfNode(graph.unique(IsNullNode.create(object)), successor, deopt, 1)); + lastInstr = successor; + frameState.push(JavaKind.Int, appendConstant(JavaConstant.INT_0)); + } + + /** + * @param type the type being instantiated + */ + protected void handleUnresolvedNewInstance(JavaType type) { + assert !graphBuilderConfig.eagerResolving(); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + } + + /** + * @param type the type of the array being instantiated + * @param length the length of the array + */ + protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) { + assert !graphBuilderConfig.eagerResolving(); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + } + + /** + * @param type the type being instantiated + * @param dims the dimensions for the multi-array + */ + protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) { + assert !graphBuilderConfig.eagerResolving(); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + } + + /** + * @param field the unresolved field + * @param receiver the object containing the field or {@code null} if {@code field} is static + */ + protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) { + assert !graphBuilderConfig.eagerResolving(); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + } + + /** + * @param field the unresolved field + * @param value the value being stored to the field + * @param receiver the object containing the field or {@code null} if {@code field} is static + */ + protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) { + assert !graphBuilderConfig.eagerResolving(); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + } + + /** + * @param type + */ + protected void handleUnresolvedExceptionType(JavaType type) { + assert !graphBuilderConfig.eagerResolving(); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + } + + /** + * @param javaMethod + * @param invokeKind + */ + protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) { + assert !graphBuilderConfig.eagerResolving(); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + } + + private AbstractBeginNode handleException(ValueNode exceptionObject, int bci) { + assert bci == BytecodeFrame.BEFORE_BCI || bci == bci() : "invalid bci"; + Debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, (profilingInfo == null ? "" : profilingInfo.getExceptionSeen(bci))); + + FrameStateBuilder dispatchState = frameState.copy(); + dispatchState.clearStack(); + + AbstractBeginNode dispatchBegin; + if (exceptionObject == null) { + ExceptionObjectNode newExceptionObject = graph.add(new ExceptionObjectNode(metaAccess)); + dispatchBegin = newExceptionObject; + dispatchState.push(JavaKind.Object, dispatchBegin); + dispatchState.setRethrowException(true); + newExceptionObject.setStateAfter(dispatchState.create(bci, newExceptionObject)); + } else { + dispatchBegin = graph.add(new BeginNode()); + dispatchState.push(JavaKind.Object, exceptionObject); + dispatchState.setRethrowException(true); + } + this.controlFlowSplit = true; + FixedWithNextNode finishedDispatch = finishInstruction(dispatchBegin, dispatchState); + + createHandleExceptionTarget(finishedDispatch, bci, dispatchState); + + return dispatchBegin; + } + + protected void createHandleExceptionTarget(FixedWithNextNode finishedDispatch, int bci, FrameStateBuilder dispatchState) { + BciBlock dispatchBlock = currentBlock.exceptionDispatchBlock(); + /* + * The exception dispatch block is always for the last bytecode of a block, so if we are not + * at the endBci yet, there is no exception handler for this bci and we can unwind + * immediately. + */ + if (bci != currentBlock.endBci || dispatchBlock == null) { + dispatchBlock = blockMap.getUnwindBlock(); + } + + FixedNode target = createTarget(dispatchBlock, dispatchState); + finishedDispatch.setNext(target); + } + + protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, JavaKind kind) { + return LoadIndexedNode.create(graph.getAssumptions(), array, index, kind, metaAccess, constantReflection); + } + + protected void genStoreIndexed(ValueNode array, ValueNode index, JavaKind kind, ValueNode value) { + add(new StoreIndexedNode(array, index, kind, value)); + } + + protected ValueNode genIntegerAdd(ValueNode x, ValueNode y) { + return AddNode.create(x, y); + } + + protected ValueNode genIntegerSub(ValueNode x, ValueNode y) { + return SubNode.create(x, y); + } + + protected ValueNode genIntegerMul(ValueNode x, ValueNode y) { + return MulNode.create(x, y); + } + + protected ValueNode genFloatAdd(ValueNode x, ValueNode y) { + return AddNode.create(x, y); + } + + protected ValueNode genFloatSub(ValueNode x, ValueNode y) { + return SubNode.create(x, y); + } + + protected ValueNode genFloatMul(ValueNode x, ValueNode y) { + return MulNode.create(x, y); + } + + protected ValueNode genFloatDiv(ValueNode x, ValueNode y) { + return DivNode.create(x, y); + } + + protected ValueNode genFloatRem(ValueNode x, ValueNode y) { + return new RemNode(x, y); + } + + protected ValueNode genIntegerDiv(ValueNode x, ValueNode y) { + return new SignedDivNode(x, y); + } + + protected ValueNode genIntegerRem(ValueNode x, ValueNode y) { + return new SignedRemNode(x, y); + } + + protected ValueNode genNegateOp(ValueNode x) { + return (new NegateNode(x)); + } + + protected ValueNode genLeftShift(ValueNode x, ValueNode y) { + return new LeftShiftNode(x, y); + } + + protected ValueNode genRightShift(ValueNode x, ValueNode y) { + return new RightShiftNode(x, y); + } + + protected ValueNode genUnsignedRightShift(ValueNode x, ValueNode y) { + return new UnsignedRightShiftNode(x, y); + } + + protected ValueNode genAnd(ValueNode x, ValueNode y) { + return AndNode.create(x, y); + } + + protected ValueNode genOr(ValueNode x, ValueNode y) { + return OrNode.create(x, y); + } + + protected ValueNode genXor(ValueNode x, ValueNode y) { + return XorNode.create(x, y); + } + + protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) { + return NormalizeCompareNode.create(x, y, isUnorderedLess, constantReflection); + } + + protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) { + return FloatConvertNode.create(op, input); + } + + protected ValueNode genNarrow(ValueNode input, int bitCount) { + return NarrowNode.create(input, bitCount); + } + + protected ValueNode genSignExtend(ValueNode input, int bitCount) { + return SignExtendNode.create(input, bitCount); + } + + protected ValueNode genZeroExtend(ValueNode input, int bitCount) { + return ZeroExtendNode.create(input, bitCount); + } + + protected void genGoto() { + ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); + if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + int targetBci = currentBlock.getSuccessor(0).startBci; + profilingPlugin.profileGoto(this, method, bci(), targetBci, stateBefore); + } + appendGoto(currentBlock.getSuccessor(0)); + assert currentBlock.numNormalSuccessors() == 1; + } + + protected LogicNode genObjectEquals(ValueNode x, ValueNode y) { + return ObjectEqualsNode.create(x, y, constantReflection); + } + + protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) { + return IntegerEqualsNode.create(x, y, constantReflection); + } + + protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) { + return IntegerLessThanNode.create(x, y, constantReflection); + } + + protected ValueNode genUnique(ValueNode x) { + return graph.addOrUniqueWithInputs(x); + } + + protected LogicNode genUnique(LogicNode x) { + return graph.addOrUniqueWithInputs(x); + } + + protected ValueNode genIfNode(LogicNode condition, FixedNode falseSuccessor, FixedNode trueSuccessor, double d) { + return new IfNode(condition, falseSuccessor, trueSuccessor, d); + } + + protected void genThrow() { + genInfoPointNode(InfopointReason.BYTECODE_POSITION, null); + + ValueNode exception = frameState.pop(JavaKind.Object); + FixedGuardNode nullCheck = append(new FixedGuardNode(graph.unique(IsNullNode.create(exception)), NullCheckException, InvalidateReprofile, true)); + PiNode nonNullException = graph.unique(new PiNode(exception, exception.stamp().join(objectNonNull()), nullCheck)); + lastInstr.setNext(handleException(nonNullException, bci())); + } + + protected LogicNode createInstanceOf(TypeReference type, ValueNode object) { + return InstanceOfNode.create(type, object); + } + + protected AnchoringNode createAnchor(JavaTypeProfile profile) { + if (profile == null || profile.getNotRecordedProbability() > 0.0) { + return null; + } else { + return append(new ValueAnchorNode(null)); + } + } + + protected LogicNode createInstanceOf(TypeReference type, ValueNode object, JavaTypeProfile profile) { + return InstanceOfNode.create(type, object, profile, createAnchor(profile)); + } + + protected LogicNode createInstanceOfAllowNull(TypeReference type, ValueNode object, JavaTypeProfile profile) { + return InstanceOfNode.createAllowNull(type, object, profile, createAnchor(profile)); + } + + protected ValueNode genConditional(ValueNode x) { + return new ConditionalNode((LogicNode) x); + } + + protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) { + return new NewInstanceNode(type, fillContents); + } + + protected NewArrayNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents) { + return new NewArrayNode(elementType, length, fillContents); + } + + protected NewMultiArrayNode createNewMultiArray(ResolvedJavaType type, ValueNode[] dimensions) { + return new NewMultiArrayNode(type, dimensions); + } + + protected ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field) { + StampPair stamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, field.getType(), false); + if (stamp == null) { + return LoadFieldNode.create(this.graph.getAssumptions(), receiver, field); + } else { + return LoadFieldNode.createOverrideStamp(stamp, receiver, field); + } + } + + protected ValueNode emitExplicitNullCheck(ValueNode receiver) { + if (StampTool.isPointerNonNull(receiver.stamp())) { + return receiver; + } + BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class)); + AbstractBeginNode falseSucc = graph.add(new BeginNode()); + PiNode nonNullReceiver = graph.unique(new PiNode(receiver, receiver.stamp().join(objectNonNull()), falseSucc)); + append(new IfNode(graph.unique(IsNullNode.create(receiver)), exception, falseSucc, 0.01)); + lastInstr = falseSucc; + + exception.setStateAfter(createFrameState(bci(), exception)); + exception.setNext(handleException(exception, bci())); + return nonNullReceiver; + } + + protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) { + AbstractBeginNode trueSucc = graph.add(new BeginNode()); + BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index)); + append(new IfNode(graph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99)); + lastInstr = trueSucc; + + exception.setStateAfter(createFrameState(bci(), exception)); + exception.setNext(handleException(exception, bci())); + } + + protected ValueNode genArrayLength(ValueNode x) { + return ArrayLengthNode.create(x, constantReflection); + } + + protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) { + StoreFieldNode storeFieldNode = new StoreFieldNode(receiver, field, value); + append(storeFieldNode); + storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI(), storeFieldNode)); + } + + /** + * Ensure that concrete classes are at least linked before generating an invoke. Interfaces may + * never be linked so simply return true for them. + * + * @param target + * @return true if the declared holder is an interface or is linked + */ + private static boolean callTargetIsResolved(JavaMethod target) { + if (target instanceof ResolvedJavaMethod) { + ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; + ResolvedJavaType resolvedType = resolvedTarget.getDeclaringClass(); + return resolvedType.isInterface() || resolvedType.isLinked(); + } + return false; + } + + protected void genInvokeStatic(JavaMethod target) { + if (callTargetIsResolved(target)) { + ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; + ResolvedJavaType holder = resolvedTarget.getDeclaringClass(); + if (!holder.isInitialized() && ResolveClassBeforeStaticInvoke.getValue()) { + handleUnresolvedInvoke(target, InvokeKind.Static); + } else { + ValueNode classInit = null; + ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin(); + if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedTarget.getDeclaringClass())) { + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + classInit = classInitializationPlugin.apply(this, resolvedTarget.getDeclaringClass(), stateBefore); + } + + ValueNode[] args = frameState.popArguments(resolvedTarget.getSignature().getParameterCount(false)); + Invoke invoke = appendInvoke(InvokeKind.Static, resolvedTarget, args); + if (invoke != null) { + invoke.setClassInit(classInit); + } + } + } else { + handleUnresolvedInvoke(target, InvokeKind.Static); + } + } + + protected void genInvokeInterface(JavaMethod target) { + if (callTargetIsResolved(target)) { + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); + appendInvoke(InvokeKind.Interface, (ResolvedJavaMethod) target, args); + } else { + handleUnresolvedInvoke(target, InvokeKind.Interface); + } + } + + protected void genInvokeDynamic(JavaMethod target) { + if (target instanceof ResolvedJavaMethod) { + JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC); + if (appendix != null) { + frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph)); + } + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(false)); + appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); + } else { + handleUnresolvedInvoke(target, InvokeKind.Static); + } + } + + protected void genInvokeVirtual(JavaMethod target) { + if (callTargetIsResolved(target)) { + /* + * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) + * or MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see + * https://wikis.oracle.com/display/HotSpotInternals/Method+handles +and+invokedynamic + */ + boolean hasReceiver = !((ResolvedJavaMethod) target).isStatic(); + JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL); + if (appendix != null) { + frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph)); + } + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver)); + if (hasReceiver) { + appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); + } else { + appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); + } + } else { + handleUnresolvedInvoke(target, InvokeKind.Virtual); + } + + } + + protected void genInvokeSpecial(JavaMethod target) { + if (callTargetIsResolved(target)) { + assert target != null; + assert target.getSignature() != null; + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); + appendInvoke(InvokeKind.Special, (ResolvedJavaMethod) target, args); + } else { + handleUnresolvedInvoke(target, InvokeKind.Special); + } + } + + private InvokeKind currentInvokeKind; + private JavaType currentInvokeReturnType; + protected FrameStateBuilder frameState; + protected BciBlock currentBlock; + protected final BytecodeStream stream; + protected final GraphBuilderConfiguration graphBuilderConfig; + protected final ResolvedJavaMethod method; + protected final Bytecode code; + protected final BytecodeProvider bytecodeProvider; + protected final ProfilingInfo profilingInfo; + protected final OptimisticOptimizations optimisticOpts; + protected final ConstantPool constantPool; + protected final MetaAccessProvider metaAccess; + private final ConstantReflectionProvider constantReflection; + private final ConstantFieldProvider constantFieldProvider; + private final StampProvider stampProvider; + protected final IntrinsicContext intrinsicContext; + + @Override + public InvokeKind getInvokeKind() { + return currentInvokeKind; + } + + @Override + public JavaType getInvokeReturnType() { + return currentInvokeReturnType; + } + + private boolean forceInliningEverything; + + @Override + public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean inlineEverything) { + boolean previous = forceInliningEverything; + forceInliningEverything = previous || inlineEverything; + try { + appendInvoke(invokeKind, targetMethod, args); + } finally { + forceInliningEverything = previous; + } + } + + private Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) { + ResolvedJavaMethod targetMethod = initialTargetMethod; + InvokeKind invokeKind = initialInvokeKind; + if (initialInvokeKind.isIndirect()) { + ResolvedJavaType contextType = this.frameState.getMethod().getDeclaringClass(); + ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(initialInvokeKind, args[0], initialTargetMethod, contextType); + if (specialCallTarget != null) { + invokeKind = InvokeKind.Special; + targetMethod = specialCallTarget; + } + } + + JavaKind resultType = targetMethod.getSignature().getReturnKind(); + if (DeoptALot.getValue()) { + append(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint)); + frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, graph)); + return null; + } + + JavaType returnType = targetMethod.getSignature().getReturnType(method.getDeclaringClass()); + if (graphBuilderConfig.eagerResolving() || parsingIntrinsic()) { + returnType = returnType.resolve(targetMethod.getDeclaringClass()); + } + if (invokeKind.hasReceiver()) { + args[0] = emitExplicitExceptions(args[0], null); + + if (args[0].isNullConstant()) { + append(new DeoptimizeNode(InvalidateRecompile, NullCheckException)); + return null; + } + } + + InlineInfo inlineInfo = null; + try { + currentInvokeReturnType = returnType; + currentInvokeKind = invokeKind; + if (tryNodePluginForInvocation(args, targetMethod)) { + if (TraceParserPlugins.getValue()) { + traceWithContext("used node plugin for %s", targetMethod.format("%h.%n(%p)")); + } + return null; + } + + if (!invokeKind.isIndirect() || (UseGuardedIntrinsics.getValue() && !GeneratePIC.getValue())) { + if (tryInvocationPlugin(invokeKind, args, targetMethod, resultType, returnType)) { + if (TraceParserPlugins.getValue()) { + traceWithContext("used invocation plugin for %s", targetMethod.format("%h.%n(%p)")); + } + return null; + } + } + if (invokeKind.isDirect()) { + + inlineInfo = tryInline(args, targetMethod); + if (inlineInfo == SUCCESSFULLY_INLINED) { + return null; + } + } + } finally { + currentInvokeReturnType = null; + currentInvokeKind = null; + } + + JavaTypeProfile profile = null; + if (invokeKind.isIndirect() && profilingInfo != null && this.optimisticOpts.useTypeCheckHints()) { + profile = profilingInfo.getTypeProfile(bci()); + } + return createNonInlinedInvoke(args, targetMethod, invokeKind, resultType, returnType, inlineInfo, profile); + } + + protected Invoke createNonInlinedInvoke(ValueNode[] args, ResolvedJavaMethod targetMethod, InvokeKind invokeKind, + JavaKind resultType, JavaType returnType, InlineInfo inlineInfo, JavaTypeProfile profile) { + + StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false); + if (returnStamp == null) { + returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false); + } + + MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, args, returnStamp, profile)); + + Invoke invoke; + if (omitInvokeExceptionEdge(callTarget, inlineInfo)) { + invoke = createInvoke(callTarget, resultType); + } else { + invoke = createInvokeWithException(callTarget, resultType); + AbstractBeginNode beginNode = graph.add(new KillingBeginNode(LocationIdentity.any())); + invoke.setNext(beginNode); + lastInstr = beginNode; + } + + for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) { + plugin.notifyNotInlined(this, targetMethod, invoke); + } + + return invoke; + } + + /** + * If the method returns true, the invocation of the given {@link MethodCallTargetNode call + * target} does not need an exception edge. + * + * @param callTarget The call target. + */ + protected boolean omitInvokeExceptionEdge(MethodCallTargetNode callTarget, InlineInfo lastInlineInfo) { + if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION) { + return false; + } else if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_NO_EXCEPTION) { + return true; + } else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.CheckAll) { + return false; + } else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.OmitAll) { + return true; + } else { + assert graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.Profile; + // be conservative if information was not recorded (could result in endless + // recompiles otherwise) + return (!StressInvokeWithExceptionNode.getValue() && optimisticOpts.useExceptionProbability() && profilingInfo != null && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE); + } + } + + /** + * Contains all the assertion checking logic around the application of an + * {@link InvocationPlugin}. This class is only loaded when assertions are enabled. + */ + class InvocationPluginAssertions { + final InvocationPlugin plugin; + final ValueNode[] args; + final ResolvedJavaMethod targetMethod; + final JavaKind resultType; + final int beforeStackSize; + final boolean needsNullCheck; + final int nodeCount; + final Mark mark; + + InvocationPluginAssertions(InvocationPlugin plugin, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) { + guarantee(assertionsEnabled(), "%s should only be loaded and instantiated if assertions are enabled", getClass().getSimpleName()); + this.plugin = plugin; + this.targetMethod = targetMethod; + this.args = args; + this.resultType = resultType; + this.beforeStackSize = frameState.stackSize(); + this.needsNullCheck = !targetMethod.isStatic() && args[0].getStackKind() == JavaKind.Object && !StampTool.isPointerNonNull(args[0].stamp()); + this.nodeCount = graph.getNodeCount(); + this.mark = graph.getMark(); + } + + String error(String format, Object... a) { + return String.format(format, a) + String.format("%n\tplugin at %s", plugin.getApplySourceLocation(metaAccess)); + } + + boolean check(boolean pluginResult) { + if (pluginResult == true) { + int expectedStackSize = beforeStackSize + resultType.getSlotCount(); + assert expectedStackSize == frameState.stackSize() : error("plugin manipulated the stack incorrectly: expected=%d, actual=%d", expectedStackSize, frameState.stackSize()); + NodeIterable newNodes = graph.getNewNodes(mark); + assert !needsNullCheck || isPointerNonNull(args[0].stamp()) : error("plugin needs to null check the receiver of %s: receiver=%s", targetMethod.format("%H.%n(%p)"), args[0]); + for (Node n : newNodes) { + if (n instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) n; + assert stateSplit.stateAfter() != null || !stateSplit.hasSideEffect() : error("%s node added by plugin for %s need to have a non-null frame state: %s", + StateSplit.class.getSimpleName(), targetMethod.format("%H.%n(%p)"), stateSplit); + } + } + try { + graphBuilderConfig.getPlugins().getInvocationPlugins().checkNewNodes(BytecodeParser.this, plugin, newNodes); + } catch (Throwable t) { + throw new AssertionError(error("Error in plugin"), t); + } + } else { + assert nodeCount == graph.getNodeCount() : error("plugin that returns false must not create new nodes"); + assert beforeStackSize == frameState.stackSize() : error("plugin that returns false must not modify the stack"); + } + return true; + } + } + + protected static class IntrinsicGuard { + final FixedWithNextNode lastInstr; + final Mark mark; + final AbstractBeginNode nonIntrinsicBranch; + final ValueNode receiver; + final JavaTypeProfile profile; + + public IntrinsicGuard(FixedWithNextNode lastInstr, ValueNode receiver, Mark mark, AbstractBeginNode nonIntrinsicBranch, JavaTypeProfile profile) { + this.lastInstr = lastInstr; + this.receiver = receiver; + this.mark = mark; + this.nonIntrinsicBranch = nonIntrinsicBranch; + this.profile = profile; + } + } + + /** + * Weaves a test of the receiver type to ensure the dispatch will select {@code targetMethod} + * and not another method that overrides it. This should only be called if there is an intrinsic + * (i.e., an {@link InvocationPlugin}) for {@code targetMethod} and the invocation is indirect. + * + * The control flow woven around the intrinsic is as follows: + * + *

    +     *  if (LoadMethod(LoadHub(receiver)) == targetMethod) {
    +     *       
    +     *  } else {
    +     *       
    +     *  }
    +     * 
    + * + * The {@code else} branch is woven by {@link #afterInvocationPluginExecution}. + * + * @return {@code null} if the intrinsic cannot be used otherwise an object to be used by + * {@link #afterInvocationPluginExecution} to weave code for the non-intrinsic branch + */ + protected IntrinsicGuard guardIntrinsic(ValueNode[] args, ResolvedJavaMethod targetMethod, InvocationPluginReceiver pluginReceiver) { + ValueNode intrinsicReceiver = args[0]; + ResolvedJavaType receiverType = StampTool.typeOrNull(intrinsicReceiver); + if (receiverType == null) { + // The verifier guarantees it to be at least type declaring targetMethod + receiverType = targetMethod.getDeclaringClass(); + } + ResolvedJavaMethod resolvedMethod = receiverType.resolveMethod(targetMethod, method.getDeclaringClass()); + if (resolvedMethod == null || resolvedMethod == targetMethod) { + assert resolvedMethod == null || targetMethod.getDeclaringClass().isAssignableFrom(resolvedMethod.getDeclaringClass()); + Mark mark = graph.getMark(); + FixedWithNextNode currentLastInstr = lastInstr; + ValueNode nonNullReceiver = pluginReceiver.get(); + Stamp methodStamp = stampProvider.createMethodStamp(); + LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, nonNullReceiver)); + LoadMethodNode actual = append(new LoadMethodNode(methodStamp, targetMethod, receiverType, method.getDeclaringClass(), hub)); + ConstantNode expected = graph.unique(ConstantNode.forConstant(methodStamp, targetMethod.getEncoding(), getMetaAccess())); + LogicNode compare = graph.unique(CompareNode.createCompareNode(Condition.EQ, actual, expected, constantReflection)); + + JavaTypeProfile profile = null; + if (profilingInfo != null && this.optimisticOpts.useTypeCheckHints()) { + profile = profilingInfo.getTypeProfile(bci()); + if (profile != null) { + JavaTypeProfile newProfile = adjustProfileForInvocationPlugin(profile, targetMethod); + if (newProfile != profile) { + if (newProfile.getTypes().length == 0) { + // All profiled types select the intrinsic so + // emit a fixed guard instead of a if-then-else. + lastInstr = append(new FixedGuardNode(compare, TypeCheckedInliningViolated, InvalidateReprofile, false)); + return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, null, null); + } + } else { + // No profiled types select the intrinsic so emit a virtual call + return null; + } + profile = newProfile; + } + } + + AbstractBeginNode intrinsicBranch = graph.add(new BeginNode()); + AbstractBeginNode nonIntrinsicBranch = graph.add(new BeginNode()); + append(new IfNode(compare, intrinsicBranch, nonIntrinsicBranch, 0.01)); + lastInstr = intrinsicBranch; + return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, nonIntrinsicBranch, profile); + } else { + // Receiver selects an overriding method so emit a virtual call + return null; + } + } + + /** + * Adjusts the profile for an indirect invocation of a virtual method for which there is an + * intrinsic. The adjustment made by this method is to remove all types from the profile that do + * not override {@code targetMethod}. + * + * @param profile the profile to adjust + * @param targetMethod the virtual method for which there is an intrinsic + * @return the adjusted profile or the original {@code profile} object if no adjustment was made + */ + protected JavaTypeProfile adjustProfileForInvocationPlugin(JavaTypeProfile profile, ResolvedJavaMethod targetMethod) { + if (profile.getTypes().length > 0) { + List retained = new ArrayList<>(); + double notRecordedProbability = profile.getNotRecordedProbability(); + for (ProfiledType ptype : profile.getTypes()) { + if (!ptype.getType().resolveMethod(targetMethod, method.getDeclaringClass()).equals(targetMethod)) { + retained.add(ptype); + } else { + notRecordedProbability += ptype.getProbability(); + } + } + if (!retained.isEmpty()) { + if (retained.size() != profile.getTypes().length) { + return new JavaTypeProfile(profile.getNullSeen(), notRecordedProbability, retained.toArray(new ProfiledType[retained.size()])); + } + } else { + return new JavaTypeProfile(profile.getNullSeen(), notRecordedProbability, new ProfiledType[0]); + } + } + return profile; + } + + /** + * Performs any action required after execution of an invocation plugin. This includes + * {@linkplain InvocationPluginAssertions#check(boolean) checking} invocation plugin invariants + * as well as weaving the {@code else} branch of the code woven by {@link #guardIntrinsic} if + * {@code guard != null}. + */ + protected void afterInvocationPluginExecution(boolean pluginResult, InvocationPluginAssertions assertions, IntrinsicGuard intrinsicGuard, + InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) { + assert assertions.check(pluginResult); + if (intrinsicGuard != null) { + if (pluginResult) { + if (intrinsicGuard.nonIntrinsicBranch != null) { + // Intrinsic emitted: emit a virtual call to the target method and + // merge it with the intrinsic branch + EndNode intrinsicEnd = append(new EndNode()); + + FrameStateBuilder intrinsicState = null; + FrameStateBuilder nonIntrinisicState = null; + if (resultType != JavaKind.Void) { + intrinsicState = frameState.copy(); + frameState.pop(resultType); + nonIntrinisicState = frameState; + } + + lastInstr = intrinsicGuard.nonIntrinsicBranch; + createNonInlinedInvoke(args, targetMethod, invokeKind, resultType, returnType, null, intrinsicGuard.profile); + + EndNode nonIntrinsicEnd = append(new EndNode()); + AbstractMergeNode mergeNode = graph.add(new MergeNode()); + + mergeNode.addForwardEnd(intrinsicEnd); + if (intrinsicState != null) { + intrinsicState.merge(mergeNode, nonIntrinisicState); + frameState = intrinsicState; + } + mergeNode.addForwardEnd(nonIntrinsicEnd); + mergeNode.setStateAfter(frameState.create(stream.nextBCI(), mergeNode)); + + lastInstr = mergeNode; + } + } else { + // Intrinsic was not applied: remove intrinsic guard + // and restore the original receiver node in the arguments array + for (Node node : graph.getNewNodes(intrinsicGuard.mark)) { + GraphUtil.killCFG(node); + } + lastInstr = intrinsicGuard.lastInstr; + args[0] = intrinsicGuard.receiver; + } + } + } + + protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) { + InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod); + if (plugin != null) { + + if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) { + // Self recursive intrinsic means the original + // method should be called. + assert !targetMethod.hasBytecodes() : "TODO: when does this happen?"; + return false; + } + + InvocationPluginReceiver pluginReceiver = invocationPluginReceiver.init(targetMethod, args); + + IntrinsicGuard intrinsicGuard = null; + if (invokeKind.isIndirect()) { + intrinsicGuard = guardIntrinsic(args, targetMethod, pluginReceiver); + if (intrinsicGuard == null) { + return false; + } else if (intrinsicGuard.nonIntrinsicBranch == null) { + assert lastInstr instanceof FixedGuardNode; + } + } + + InvocationPluginAssertions assertions = assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null; + if (plugin.execute(this, targetMethod, pluginReceiver, args)) { + afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); + return true; + } else { + afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); + } + } + return false; + } + + private boolean tryNodePluginForInvocation(ValueNode[] args, ResolvedJavaMethod targetMethod) { + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleInvoke(this, targetMethod, args)) { + return true; + } + } + return false; + } + + private static final InlineInfo SUCCESSFULLY_INLINED = InlineInfo.createStandardInlineInfo(null); + + /** + * Try to inline a method. If the method was inlined, returns {@link #SUCCESSFULLY_INLINED}. + * Otherwise, it returns the {@link InlineInfo} that lead to the decision to not inline it, or + * {@code null} if there is no {@link InlineInfo} for this method. + */ + private InlineInfo tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod) { + boolean canBeInlined = forceInliningEverything || parsingIntrinsic() || targetMethod.canBeInlined(); + if (!canBeInlined) { + return null; + } + + if (forceInliningEverything) { + if (inline(targetMethod, targetMethod, null, args)) { + return SUCCESSFULLY_INLINED; + } else { + return null; + } + } + + for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) { + InlineInfo inlineInfo = plugin.shouldInlineInvoke(this, targetMethod, args); + if (inlineInfo != null) { + if (inlineInfo.getMethodToInline() != null) { + if (inline(targetMethod, inlineInfo.getMethodToInline(), inlineInfo.getIntrinsicBytecodeProvider(), args)) { + return SUCCESSFULLY_INLINED; + } + } + /* Do not inline, and do not ask the remaining plugins. */ + return inlineInfo; + } + } + return null; + } + + @Override + public boolean intrinsify(BytecodeProvider intrinsicBytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] args) { + if (receiver != null) { + receiver.get(); + } + boolean res = inline(targetMethod, substitute, intrinsicBytecodeProvider, args); + assert res : "failed to inline " + substitute; + return res; + } + + private boolean inline(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, BytecodeProvider intrinsicBytecodeProvider, ValueNode[] args) { + if (TraceInlineDuringParsing.getValue() || TraceParserPlugins.getValue()) { + if (targetMethod.equals(inlinedMethod)) { + traceWithContext("inlining call to %s", inlinedMethod.format("%h.%n(%p)")); + } else { + traceWithContext("inlining call to %s as intrinsic for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)")); + } + } + IntrinsicContext intrinsic = this.intrinsicContext; + if (intrinsic != null && intrinsic.isCallToOriginal(targetMethod)) { + if (intrinsic.isCompilationRoot()) { + // A root compiled intrinsic needs to deoptimize + // if the slow path is taken. During frame state + // assignment, the deopt node will get its stateBefore + // from the start node of the intrinsic + append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint)); + printInlining(targetMethod, inlinedMethod, true, "compilation root (bytecode parsing)"); + return true; + } else { + // Otherwise inline the original method. Any frame state created + // during the inlining will exclude frame(s) in the + // intrinsic method (see HIRFrameStateBuilder.create(int bci)). + if (intrinsic.getOriginalMethod().isNative()) { + printInlining(targetMethod, inlinedMethod, false, "native method (bytecode parsing)"); + return false; + } + printInlining(targetMethod, inlinedMethod, true, "inline intrinsic (bytecode parsing)"); + parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null); + return true; + } + } else { + boolean isIntrinsic = intrinsicBytecodeProvider != null; + if (intrinsic == null && isIntrinsic) { + assert !inlinedMethod.equals(targetMethod); + intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, intrinsicBytecodeProvider, INLINE_DURING_PARSING); + } + if (inlinedMethod.hasBytecodes()) { + for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) { + plugin.notifyBeforeInline(inlinedMethod); + } + printInlining(targetMethod, inlinedMethod, true, "inline method (bytecode parsing)"); + parseAndInlineCallee(inlinedMethod, args, intrinsic); + for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) { + plugin.notifyAfterInline(inlinedMethod); + } + } else { + printInlining(targetMethod, inlinedMethod, false, "no bytecodes (abstract or native) (bytecode parsing)"); + return false; + } + } + return true; + } + + private void printInlining(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, boolean success, String msg) { + if (GraalOptions.HotSpotPrintInlining.getValue()) { + if (targetMethod.equals(inlinedMethod)) { + Util.printInlining(inlinedMethod, bci(), getDepth(), success, "%s", msg); + } else { + Util.printInlining(inlinedMethod, bci(), getDepth(), success, "%s intrinsic for %s", msg, targetMethod.format("%h.%n(%p)")); + } + } + } + + /** + * Prints a line to {@link TTY} with a prefix indicating the current parse context. The prefix + * is of the form: + * + *
    +     * {SPACE * n} {name of method being parsed} "(" {file name} ":" {line number} ")"
    +     * 
    + * + * where {@code n} is the current inlining depth. + * + * @param format a format string + * @param args arguments to the format string + */ + + protected void traceWithContext(String format, Object... args) { + StackTraceElement where = code.asStackTraceElement(bci()); + TTY.println(format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(), + format(format, args))); + } + + protected BytecodeParserError asParserError(Throwable e) { + if (e instanceof BytecodeParserError) { + return (BytecodeParserError) e; + } + BytecodeParser bp = this; + BytecodeParserError res = new BytecodeParserError(e); + while (bp != null) { + res.addContext("parsing " + bp.code.asStackTraceElement(bp.bci())); + bp = bp.parent; + } + return res; + } + + @SuppressWarnings("try") + protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) { + try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, targetMethod.getSignature().toParameterKinds(!targetMethod.isStatic()), args) : null) { + + BytecodeParser parser = graphBuilderInstance.createBytecodeParser(graph, this, targetMethod, INVOCATION_ENTRY_BCI, calleeIntrinsicContext); + FrameStateBuilder startFrameState = new FrameStateBuilder(parser, parser.code, graph); + if (!targetMethod.isStatic()) { + args[0] = nullCheckedValue(args[0]); + } + startFrameState.initializeFromArgumentsArray(args); + parser.build(this.lastInstr, startFrameState); + + FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode(); + this.lastInstr = calleeBeforeReturnNode; + JavaKind calleeReturnKind = targetMethod.getSignature().getReturnKind(); + if (calleeBeforeReturnNode != null) { + ValueNode calleeReturnValue = parser.getReturnValue(); + if (calleeReturnValue != null) { + frameState.push(calleeReturnKind.getStackKind(), calleeReturnValue); + } + } + + FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); + if (calleeBeforeUnwindNode != null) { + ValueNode calleeUnwindValue = parser.getUnwindValue(); + assert calleeUnwindValue != null; + calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci())); + } + } + } + + public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, JavaTypeProfile profile) { + return new MethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, profile); + } + + protected InvokeNode createInvoke(CallTargetNode callTarget, JavaKind resultType) { + InvokeNode invoke = append(new InvokeNode(callTarget, bci())); + frameState.pushReturn(resultType, invoke); + invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); + return invoke; + } + + protected InvokeWithExceptionNode createInvokeWithException(CallTargetNode callTarget, JavaKind resultType) { + if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) { + /* + * Clear non-live locals early so that the exception handler entry gets the cleared + * state. + */ + frameState.clearNonLiveLocals(currentBlock, liveness, false); + } + + AbstractBeginNode exceptionEdge = handleException(null, bci()); + InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci())); + frameState.pushReturn(resultType, invoke); + invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); + return invoke; + } + + protected void genReturn(ValueNode returnVal, JavaKind returnKind) { + if (parsingIntrinsic() && returnVal != null) { + if (returnVal instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) returnVal; + FrameState stateAfter = stateSplit.stateAfter(); + if (stateSplit.hasSideEffect()) { + assert stateSplit != null; + if (stateAfter.bci == BytecodeFrame.AFTER_BCI) { + assert stateAfter.usages().count() == 1; + assert stateAfter.usages().first() == stateSplit; + stateAfter.replaceAtUsages(graph.add(new FrameState(BytecodeFrame.AFTER_BCI, returnVal))); + GraphUtil.killWithUnusedFloatingInputs(stateAfter); + } else { + /* + * This must be the return value from within a partial intrinsification. + */ + assert !BytecodeFrame.isPlaceholderBci(stateAfter.bci); + } + } else { + assert stateAfter == null; + } + } + } + if (parent == null) { + frameState.setRethrowException(false); + frameState.clearStack(); + beforeReturn(returnVal, returnKind); + append(new ReturnNode(returnVal)); + } else { + if (blockMap.getReturnCount() == 1 || !controlFlowSplit) { + // There is only a single return. + beforeReturn(returnVal, returnKind); + this.returnValue = returnVal; + this.beforeReturnNode = this.lastInstr; + this.lastInstr = null; + } else { + frameState.setRethrowException(false); + frameState.clearStack(); + if (returnVal != null) { + frameState.push(returnKind, returnVal); + } + assert blockMap.getReturnCount() > 1; + appendGoto(blockMap.getReturnBlock()); + } + } + } + + private void beforeReturn(ValueNode x, JavaKind kind) { + if (graph.method() != null && graph.method().isJavaLangObjectInit()) { + /* + * Get the receiver from the initial state since bytecode rewriting could do arbitrary + * things to the state of the locals. + */ + ValueNode receiver = graph.start().stateAfter().localAt(0); + assert receiver != null && receiver.getStackKind() == JavaKind.Object; + if (RegisterFinalizerNode.mayHaveFinalizer(receiver, graph.getAssumptions())) { + append(new RegisterFinalizerNode(receiver)); + } + } + genInfoPointNode(InfopointReason.METHOD_END, x); + if (finalBarrierRequired) { + assert originalReceiver != null; + append(new FinalFieldBarrierNode(originalReceiver)); + } + synchronizedEpilogue(BytecodeFrame.AFTER_BCI, x, kind); + } + + protected MonitorEnterNode createMonitorEnterNode(ValueNode x, MonitorIdNode monitorId) { + return new MonitorEnterNode(x, monitorId); + } + + protected void genMonitorEnter(ValueNode x, int bci) { + MonitorIdNode monitorId = graph.add(new MonitorIdNode(frameState.lockDepth(true))); + MonitorEnterNode monitorEnter = append(createMonitorEnterNode(x, monitorId)); + frameState.pushLock(x, monitorId); + monitorEnter.setStateAfter(createFrameState(bci, monitorEnter)); + } + + protected void genMonitorExit(ValueNode x, ValueNode escapedReturnValue, int bci) { + if (frameState.lockDepth(false) == 0) { + throw bailout("unbalanced monitors: too many exits"); + } + MonitorIdNode monitorId = frameState.peekMonitorId(); + ValueNode lockedObject = frameState.popLock(); + if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) { + throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject))); + } + MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, escapedReturnValue)); + monitorExit.setStateAfter(createFrameState(bci, monitorExit)); + } + + protected void genJsr(int dest) { + BciBlock successor = currentBlock.getJsrSuccessor(); + assert successor.startBci == dest : successor.startBci + " != " + dest + " @" + bci(); + JsrScope scope = currentBlock.getJsrScope(); + int nextBci = getStream().nextBCI(); + if (!successor.getJsrScope().pop().equals(scope)) { + throw new JsrNotSupportedBailout("unstructured control flow (internal limitation)"); + } + if (successor.getJsrScope().nextReturnAddress() != nextBci) { + throw new JsrNotSupportedBailout("unstructured control flow (internal limitation)"); + } + ConstantNode nextBciNode = getJsrConstant(nextBci); + frameState.push(JavaKind.Object, nextBciNode); + appendGoto(successor); + } + + protected void genRet(int localIndex) { + BciBlock successor = currentBlock.getRetSuccessor(); + ValueNode local = frameState.loadLocal(localIndex, JavaKind.Object); + JsrScope scope = currentBlock.getJsrScope(); + int retAddress = scope.nextReturnAddress(); + ConstantNode returnBciNode = getJsrConstant(retAddress); + LogicNode guard = IntegerEqualsNode.create(local, returnBciNode, constantReflection); + guard = graph.unique(guard); + append(new FixedGuardNode(guard, JavaSubroutineMismatch, InvalidateReprofile)); + if (!successor.getJsrScope().equals(scope.pop())) { + throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)"); + } + appendGoto(successor); + } + + private ConstantNode getJsrConstant(long bci) { + JavaConstant nextBciConstant = new RawConstant(bci); + Stamp nextBciStamp = StampFactory.forConstant(nextBciConstant); + ConstantNode nextBciNode = new ConstantNode(nextBciConstant, nextBciStamp); + return graph.unique(nextBciNode); + } + + protected void genIntegerSwitch(ValueNode value, ArrayList actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors) { + if (value.isConstant()) { + JavaConstant constant = (JavaConstant) value.asConstant(); + int constantValue = constant.asInt(); + for (int i = 0; i < keys.length; ++i) { + if (keys[i] == constantValue) { + appendGoto(actualSuccessors.get(keySuccessors[i])); + return; + } + } + appendGoto(actualSuccessors.get(keySuccessors[keys.length])); + } else { + this.controlFlowSplit = true; + double[] successorProbabilities = successorProbabilites(actualSuccessors.size(), keySuccessors, keyProbabilities); + IntegerSwitchNode switchNode = append(new IntegerSwitchNode(value, actualSuccessors.size(), keys, keyProbabilities, keySuccessors)); + for (int i = 0; i < actualSuccessors.size(); i++) { + switchNode.setBlockSuccessor(i, createBlockTarget(successorProbabilities[i], actualSuccessors.get(i), frameState)); + } + } + } + + /** + * Helper function that sums up the probabilities of all keys that lead to a specific successor. + * + * @return an array of size successorCount with the accumulated probability for each successor. + */ + private static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) { + double[] probability = new double[successorCount]; + for (int i = 0; i < keySuccessors.length; i++) { + probability[keySuccessors[i]] += keyProbabilities[i]; + } + return probability; + } + + protected ConstantNode appendConstant(JavaConstant constant) { + assert constant != null; + return ConstantNode.forConstant(constant, metaAccess, graph); + } + + @Override + public T append(T v) { + if (v.graph() != null) { + return v; + } + T added = graph.addOrUnique(v); + if (added == v) { + updateLastInstruction(v); + } + return added; + } + + @Override + public T recursiveAppend(T v) { + if (v.graph() != null) { + return v; + } + T added = graph.addOrUniqueWithInputs(v); + if (added == v) { + updateLastInstruction(v); + } + return added; + } + + private void updateLastInstruction(T v) { + if (UseGraalInstrumentation.getValue()) { + // resolve instrumentation target + if (v instanceof InstrumentationBeginNode) { + InstrumentationBeginNode begin = (InstrumentationBeginNode) v; + if (!begin.isAnchored() && lastBCI != -1) { + int currentBCI = stream.currentBCI(); + // temporarily set the bytecode stream to lastBCI + stream.setBCI(lastBCI); + // The instrumentation should be associated with the predecessor. In case of the + // predecessor being optimized away, e.g., inlining, we should not set the + // target. + if (stream.nextBCI() == currentBCI) { + begin.setTarget(lastInstr); + } + // restore the current BCI + stream.setBCI(currentBCI); + } + } + } + if (v instanceof FixedNode) { + FixedNode fixedNode = (FixedNode) v; + lastInstr.setNext(fixedNode); + if (fixedNode instanceof FixedWithNextNode) { + FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode; + assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end"; + lastInstr = fixedWithNextNode; + lastBCI = stream.currentBCI(); + } else { + lastInstr = null; + lastBCI = -1; + } + } + } + + private Target checkLoopExit(FixedNode target, BciBlock targetBlock, FrameStateBuilder state) { + if (currentBlock != null) { + long exits = currentBlock.loops & ~targetBlock.loops; + if (exits != 0) { + LoopExitNode firstLoopExit = null; + LoopExitNode lastLoopExit = null; + + int pos = 0; + ArrayList exitLoops = new ArrayList<>(Long.bitCount(exits)); + do { + long lMask = 1L << pos; + if ((exits & lMask) != 0) { + exitLoops.add(blockMap.getLoopHeader(pos)); + exits &= ~lMask; + } + pos++; + } while (exits != 0); + + Collections.sort(exitLoops, new Comparator() { + + @Override + public int compare(BciBlock o1, BciBlock o2) { + return Long.bitCount(o2.loops) - Long.bitCount(o1.loops); + } + }); + + int bci = targetBlock.startBci; + if (targetBlock instanceof ExceptionDispatchBlock) { + bci = ((ExceptionDispatchBlock) targetBlock).deoptBci; + } + FrameStateBuilder newState = state.copy(); + for (BciBlock loop : exitLoops) { + LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(loop); + LoopExitNode loopExit = graph.add(new LoopExitNode(loopBegin)); + if (lastLoopExit != null) { + lastLoopExit.setNext(loopExit); + } + if (firstLoopExit == null) { + firstLoopExit = loopExit; + } + lastLoopExit = loopExit; + Debug.log("Target %s Exits %s, scanning framestates...", targetBlock, loop); + newState.clearNonLiveLocals(targetBlock, liveness, true); + newState.insertLoopProxies(loopExit, getEntryState(loop)); + loopExit.setStateAfter(newState.create(bci, loopExit)); + } + + lastLoopExit.setNext(target); + return new Target(firstLoopExit, newState); + } + } + return new Target(target, state); + } + + private FrameStateBuilder getEntryState(BciBlock block) { + return entryStateArray[block.id]; + } + + private void setEntryState(BciBlock block, FrameStateBuilder entryState) { + this.entryStateArray[block.id] = entryState; + } + + private void setFirstInstruction(BciBlock block, FixedWithNextNode firstInstruction) { + this.firstInstructionArray[block.id] = firstInstruction; + } + + private FixedWithNextNode getFirstInstruction(BciBlock block) { + return firstInstructionArray[block.id]; + } + + private FixedNode createTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) { + assert probability >= 0 && probability <= 1.01 : probability; + if (isNeverExecutedCode(probability)) { + return graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); + } else { + assert block != null; + return createTarget(block, stateAfter); + } + } + + private FixedNode createTarget(BciBlock block, FrameStateBuilder state) { + return createTarget(block, state, false, false); + } + + private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) { + assert block != null && state != null; + assert !block.isExceptionEntry || state.stackSize() == 1; + + if (getFirstInstruction(block) == null) { + /* + * This is the first time we see this block as a branch target. Create and return a + * placeholder that later can be replaced with a MergeNode when we see this block again. + */ + FixedNode targetNode; + if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) { + setFirstInstruction(block, lastInstr); + lastInstr = null; + } else { + setFirstInstruction(block, graph.add(new BeginNode())); + } + targetNode = getFirstInstruction(block); + Target target = checkLoopExit(targetNode, block, state); + FixedNode result = target.fixed; + FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state; + setEntryState(block, currentEntryState); + currentEntryState.clearNonLiveLocals(block, liveness, true); + + Debug.log("createTarget %s: first visit, result: %s", block, targetNode); + return result; + } + + // We already saw this block before, so we have to merge states. + if (!getEntryState(block).isCompatibleWith(state)) { + throw bailout("stacks do not match; bytecodes would not verify"); + } + + if (getFirstInstruction(block) instanceof LoopBeginNode) { + assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch"; + /* + * Backward loop edge. We need to create a special LoopEndNode and merge with the loop + * begin node created before. + */ + LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block); + LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin)); + Target target = checkLoopExit(loopEnd, block, state); + FixedNode result = target.fixed; + getEntryState(block).merge(loopBegin, target.state); + + Debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result); + return result; + } + assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch"; + assert getFirstInstruction(block).next() == null : "bytecodes already parsed for block"; + + if (getFirstInstruction(block) instanceof AbstractBeginNode && !(getFirstInstruction(block) instanceof AbstractMergeNode)) { + /* + * This is the second time we see this block. Create the actual MergeNode and the End + * Node for the already existing edge. + */ + AbstractBeginNode beginNode = (AbstractBeginNode) getFirstInstruction(block); + + // The EndNode for the already existing edge. + EndNode end = graph.add(new EndNode()); + // The MergeNode that replaces the placeholder. + AbstractMergeNode mergeNode = graph.add(new MergeNode()); + FixedNode next = beginNode.next(); + + if (beginNode.predecessor() instanceof ControlSplitNode) { + beginNode.setNext(end); + } else { + beginNode.replaceAtPredecessor(end); + beginNode.safeDelete(); + } + + mergeNode.addForwardEnd(end); + mergeNode.setNext(next); + + setFirstInstruction(block, mergeNode); + } + + AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block); + + // The EndNode for the newly merged edge. + EndNode newEnd = graph.add(new EndNode()); + Target target = checkLoopExit(newEnd, block, state); + FixedNode result = target.fixed; + getEntryState(block).merge(mergeNode, target.state); + mergeNode.addForwardEnd(newEnd); + + Debug.log("createTarget %s: merging state, result: %s", block, result); + return result; + } + + /** + * Returns a block begin node with the specified state. If the specified probability is 0, the + * block deoptimizes immediately. + */ + private AbstractBeginNode createBlockTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) { + FixedNode target = createTarget(probability, block, stateAfter); + AbstractBeginNode begin = BeginNode.begin(target); + + assert !(target instanceof DeoptimizeNode && begin instanceof BeginStateSplitNode && + ((BeginStateSplitNode) begin).stateAfter() != null) : "We are not allowed to set the stateAfter of the begin node," + + " because we have to deoptimize to a bci _before_ the actual if, so that the interpreter can update the profiling information."; + return begin; + } + + private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) { + if (target.isStatic()) { + return appendConstant(getConstantReflection().asJavaClass(target.getDeclaringClass())); + } else { + return state.loadLocal(0, JavaKind.Object); + } + } + + @SuppressWarnings("try") + protected void processBlock(BciBlock block) { + // Ignore blocks that have no predecessors by the time their bytecodes are parsed + FixedWithNextNode firstInstruction = getFirstInstruction(block); + if (firstInstruction == null) { + Debug.log("Ignoring block %s", block); + return; + } + try (Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, firstInstruction, block.isLoopHeader)) { + + lastInstr = firstInstruction; + frameState = getEntryState(block); + setCurrentFrameState(frameState); + currentBlock = block; + + if (firstInstruction instanceof AbstractMergeNode) { + setMergeStateAfter(block, firstInstruction); + } + + if (block == blockMap.getReturnBlock()) { + handleReturnBlock(); + } else if (block == blockMap.getUnwindBlock()) { + handleUnwindBlock(); + } else if (block instanceof ExceptionDispatchBlock) { + createExceptionDispatch((ExceptionDispatchBlock) block); + } else { + frameState.setRethrowException(false); + iterateBytecodesForBlock(block); + } + } + } + + private void handleUnwindBlock() { + if (parent == null) { + frameState.setRethrowException(false); + createUnwind(); + } else { + ValueNode exception = frameState.pop(JavaKind.Object); + this.unwindValue = exception; + this.beforeUnwindNode = this.lastInstr; + } + } + + private void handleReturnBlock() { + JavaKind returnKind = method.getSignature().getReturnKind().getStackKind(); + ValueNode x = returnKind == JavaKind.Void ? null : frameState.pop(returnKind); + assert frameState.stackSize() == 0; + beforeReturn(x, returnKind); + this.returnValue = x; + this.beforeReturnNode = this.lastInstr; + } + + private void setMergeStateAfter(BciBlock block, FixedWithNextNode firstInstruction) { + AbstractMergeNode abstractMergeNode = (AbstractMergeNode) firstInstruction; + if (abstractMergeNode.stateAfter() == null) { + int bci = block.startBci; + if (block instanceof ExceptionDispatchBlock) { + bci = ((ExceptionDispatchBlock) block).deoptBci; + } + abstractMergeNode.setStateAfter(createFrameState(bci, abstractMergeNode)); + } + } + + private void createUnwind() { + assert frameState.stackSize() == 1 : frameState; + ValueNode exception = frameState.pop(JavaKind.Object); + synchronizedEpilogue(BytecodeFrame.AFTER_EXCEPTION_BCI, null, null); + append(new UnwindNode(exception)); + } + + private void synchronizedEpilogue(int bci, ValueNode currentReturnValue, JavaKind currentReturnValueKind) { + if (method.isSynchronized()) { + if (currentReturnValue != null) { + frameState.push(currentReturnValueKind, currentReturnValue); + } + genMonitorExit(methodSynchronizedObject, currentReturnValue, bci); + assert !frameState.rethrowException(); + } + if (frameState.lockDepth(false) != 0) { + throw bailout("unbalanced monitors: too few exits exiting frame"); + } + } + + private void createExceptionDispatch(ExceptionDispatchBlock block) { + assert frameState.stackSize() == 1 : frameState; + if (block.handler.isCatchAll()) { + assert block.getSuccessorCount() == 1; + appendGoto(block.getSuccessor(0)); + return; + } + + JavaType catchType = block.handler.getCatchType(); + if (graphBuilderConfig.eagerResolving()) { + catchType = lookupType(block.handler.catchTypeCPI(), INSTANCEOF); + } + if (catchType instanceof ResolvedJavaType) { + TypeReference checkedCatchType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) catchType); + + if (graphBuilderConfig.getSkippedExceptionTypes() != null) { + for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) { + if (skippedType.isAssignableFrom(checkedCatchType.getType())) { + BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1); + ValueNode exception = frameState.stack[0]; + FixedNode trueSuccessor = graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); + FixedNode nextDispatch = createTarget(nextBlock, frameState); + append(new IfNode(graph.addOrUniqueWithInputs(createInstanceOf(checkedCatchType, exception)), trueSuccessor, nextDispatch, 0)); + return; + } + } + } + + BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1); + ValueNode exception = frameState.stack[0]; + /* Anchor for the piNode, which must be before any LoopExit inserted by createTarget. */ + BeginNode piNodeAnchor = graph.add(new BeginNode()); + ObjectStamp checkedStamp = StampFactory.objectNonNull(checkedCatchType); + PiNode piNode = graph.addWithoutUnique(new PiNode(exception, checkedStamp)); + frameState.pop(JavaKind.Object); + frameState.push(JavaKind.Object, piNode); + FixedNode catchSuccessor = createTarget(block.getSuccessor(0), frameState); + frameState.pop(JavaKind.Object); + frameState.push(JavaKind.Object, exception); + FixedNode nextDispatch = createTarget(nextBlock, frameState); + piNodeAnchor.setNext(catchSuccessor); + IfNode ifNode = append(new IfNode(graph.unique(createInstanceOf(checkedCatchType, exception)), piNodeAnchor, nextDispatch, 0.5)); + assert ifNode.trueSuccessor() == piNodeAnchor; + piNode.setGuard(ifNode.trueSuccessor()); + } else { + handleUnresolvedExceptionType(catchType); + } + } + + private void appendGoto(BciBlock successor) { + FixedNode targetInstr = createTarget(successor, frameState, true, true); + if (lastInstr != null && lastInstr != targetInstr) { + lastInstr.setNext(targetInstr); + } + } + + @SuppressWarnings("try") + protected void iterateBytecodesForBlock(BciBlock block) { + if (block.isLoopHeader) { + // Create the loop header block, which later will merge the backward branches of + // the loop. + controlFlowSplit = true; + LoopBeginNode loopBegin = appendLoopBegin(this.lastInstr); + lastInstr = loopBegin; + + // Create phi functions for all local variables and operand stack slots. + frameState.insertLoopPhis(liveness, block.loopId, loopBegin, forceLoopPhis(), stampFromValueForForcedPhis()); + loopBegin.setStateAfter(createFrameState(block.startBci, loopBegin)); + + /* + * We have seen all forward branches. All subsequent backward branches will merge to the + * loop header. This ensures that the loop header has exactly one non-loop predecessor. + */ + setFirstInstruction(block, loopBegin); + /* + * We need to preserve the frame state builder of the loop header so that we can merge + * values for phi functions, so make a copy of it. + */ + setEntryState(block, frameState.copy()); + + Debug.log(" created loop header %s", loopBegin); + } else if (lastInstr instanceof MergeNode) { + /* + * All inputs of non-loop phi nodes are known by now. We can infer the stamp for the + * phi, so that parsing continues with more precise type information. + */ + frameState.inferPhiStamps((AbstractMergeNode) lastInstr); + } + assert lastInstr.next() == null : "instructions already appended at block " + block; + Debug.log(" frameState: %s", frameState); + + lastInstr = finishInstruction(lastInstr, frameState); + + int endBCI = stream.endBCI(); + + stream.setBCI(block.startBci); + int bci = block.startBci; + BytecodesParsed.add(block.endBci - bci); + + /* Reset line number for new block */ + if (graphBuilderConfig.insertFullInfopoints()) { + previousLineNumber = -1; + } + + while (bci < endBCI) { + if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) { + currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : -1; + if (currentLineNumber != previousLineNumber) { + genInfoPointNode(InfopointReason.BYTECODE_POSITION, null); + previousLineNumber = currentLineNumber; + } + } + + // read the opcode + int opcode = stream.currentBC(); + assert traceState(); + assert traceInstruction(bci, opcode, bci == block.startBci); + if (parent == null && bci == entryBCI) { + if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) { + throw new JsrNotSupportedBailout("OSR into a JSR scope is not supported"); + } + EntryMarkerNode x = append(new EntryMarkerNode()); + frameState.insertProxies(value -> graph.unique(new EntryProxyNode(value, x))); + x.setStateAfter(createFrameState(bci, x)); + } + + try (DebugCloseable context = openNodeContext()) { + processBytecode(bci, opcode); + } catch (BailoutException e) { + // Don't wrap bailouts as parser errors + throw e; + } catch (Throwable e) { + throw asParserError(e); + } + + if (lastInstr == null || lastInstr.next() != null) { + break; + } + + stream.next(); + bci = stream.currentBCI(); + + assert block == currentBlock; + assert checkLastInstruction(); + lastInstr = finishInstruction(lastInstr, frameState); + if (bci < endBCI) { + if (bci > block.endBci) { + assert !block.getSuccessor(0).isExceptionEntry; + assert block.numNormalSuccessors() == 1; + // we fell through to the next block, add a goto and break + appendGoto(block.getSuccessor(0)); + break; + } + } + } + } + + private DebugCloseable openNodeContext() { + if (graphBuilderConfig.trackNodeSourcePosition() && !parsingIntrinsic()) { + return graph.withNodeSourcePosition(createBytecodePosition()); + } + return null; + } + + /* Also a hook for subclasses. */ + protected boolean forceLoopPhis() { + return graph.isOSR(); + } + + /* Hook for subclasses. */ + protected boolean stampFromValueForForcedPhis() { + return false; + } + + protected boolean checkLastInstruction() { + if (lastInstr instanceof BeginNode) { + // ignore + } else if (lastInstr instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) lastInstr; + if (stateSplit.hasSideEffect()) { + assert stateSplit.stateAfter() != null : "side effect " + lastInstr + " requires a non-null stateAfter"; + } + } + return true; + } + + /* Also a hook for subclasses. */ + protected boolean disableLoopSafepoint() { + return parsingIntrinsic(); + } + + private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext) { + EndNode preLoopEnd = graph.add(new EndNode()); + LoopBeginNode loopBegin = graph.add(new LoopBeginNode()); + if (disableLoopSafepoint()) { + loopBegin.disableSafepoint(); + } + fixedWithNext.setNext(preLoopEnd); + // Add the single non-loop predecessor of the loop header. + loopBegin.addForwardEnd(preLoopEnd); + return loopBegin; + } + + /** + * Hook for subclasses to modify the last instruction or add other instructions. + * + * @param instr The last instruction (= fixed node) which was added. + * @param state The current frame state. + * @return Returns the (new) last instruction. + */ + protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, FrameStateBuilder state) { + return instr; + } + + private void genInfoPointNode(InfopointReason reason, ValueNode escapedReturnValue) { + if (!parsingIntrinsic() && graphBuilderConfig.insertFullInfopoints()) { + append(new FullInfopointNode(reason, createFrameState(bci(), null), escapedReturnValue)); + } + } + + private boolean traceState() { + if (Debug.isEnabled() && BytecodeParserOptions.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_STATE && Debug.isLogEnabled()) { + frameState.traceState(); + } + return true; + } + + protected void genIf(ValueNode x, Condition cond, ValueNode y) { + assert x.getStackKind() == y.getStackKind(); + assert currentBlock.getSuccessorCount() == 2; + BciBlock trueBlock = currentBlock.getSuccessor(0); + BciBlock falseBlock = currentBlock.getSuccessor(1); + + FrameState stateBefore = null; + ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); + if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { + stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + } + + if (trueBlock == falseBlock) { + // The target block is the same independent of the condition. + appendGoto(trueBlock); + return; + } + + ValueNode a = x; + ValueNode b = y; + + // Check whether the condition needs to mirror the operands. + if (cond.canonicalMirror()) { + a = y; + b = x; + } + + // Create the logic node for the condition. + LogicNode condition = createLogicNode(cond, a, b); + + // Check whether the condition needs to negate the result. + boolean negate = cond.canonicalNegate(); + + // Remove a logic negation node and fold it into the negate boolean. + if (condition instanceof LogicNegationNode) { + LogicNegationNode logicNegationNode = (LogicNegationNode) condition; + negate = !negate; + condition = logicNegationNode.getValue(); + } + + if (condition instanceof LogicConstantNode) { + genConstantTargetIf(trueBlock, falseBlock, negate, condition); + } else { + if (condition.graph() == null) { + condition = graph.unique(condition); + } + + // Need to get probability based on current bci. + double probability = branchProbability(); + + if (negate) { + BciBlock tmpBlock = trueBlock; + trueBlock = falseBlock; + falseBlock = tmpBlock; + probability = 1 - probability; + } + + if (isNeverExecutedCode(probability)) { + append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, true)); + if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { + profilingPlugin.profileGoto(this, method, bci(), falseBlock.startBci, stateBefore); + } + appendGoto(falseBlock); + return; + } else if (isNeverExecutedCode(1 - probability)) { + append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, false)); + if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { + profilingPlugin.profileGoto(this, method, bci(), trueBlock.startBci, stateBefore); + } + appendGoto(trueBlock); + return; + } + + if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { + profilingPlugin.profileIf(this, method, bci(), condition, trueBlock.startBci, falseBlock.startBci, stateBefore); + } + + int oldBci = stream.currentBCI(); + int trueBlockInt = checkPositiveIntConstantPushed(trueBlock); + if (trueBlockInt != -1) { + int falseBlockInt = checkPositiveIntConstantPushed(falseBlock); + if (falseBlockInt != -1) { + if (tryGenConditionalForIf(trueBlock, falseBlock, condition, oldBci, trueBlockInt, falseBlockInt)) { + return; + } + } + } + + this.controlFlowSplit = true; + FixedNode trueSuccessor = createTarget(trueBlock, frameState, false, false); + FixedNode falseSuccessor = createTarget(falseBlock, frameState, false, true); + ValueNode ifNode = genIfNode(condition, trueSuccessor, falseSuccessor, probability); + postProcessIfNode(ifNode); + append(ifNode); + if (parsingIntrinsic()) { + if (x instanceof BranchProbabilityNode) { + ((BranchProbabilityNode) x).simplify(null); + } else if (y instanceof BranchProbabilityNode) { + ((BranchProbabilityNode) y).simplify(null); + } + } + } + } + + /** + * Hook for subclasses to generate custom nodes before an IfNode. + */ + @SuppressWarnings("unused") + protected void postProcessIfNode(ValueNode node) { + } + + private boolean tryGenConditionalForIf(BciBlock trueBlock, BciBlock falseBlock, LogicNode condition, int oldBci, int trueBlockInt, int falseBlockInt) { + if (gotoOrFallThroughAfterConstant(trueBlock) && gotoOrFallThroughAfterConstant(falseBlock) && trueBlock.getSuccessor(0) == falseBlock.getSuccessor(0)) { + genConditionalForIf(trueBlock, condition, oldBci, trueBlockInt, falseBlockInt, false); + return true; + } else if (this.parent != null && returnAfterConstant(trueBlock) && returnAfterConstant(falseBlock)) { + genConditionalForIf(trueBlock, condition, oldBci, trueBlockInt, falseBlockInt, true); + return true; + } + return false; + } + + private void genConditionalForIf(BciBlock trueBlock, LogicNode condition, int oldBci, int trueBlockInt, int falseBlockInt, boolean genReturn) { + ConstantNode trueValue = graph.unique(ConstantNode.forInt(trueBlockInt)); + ConstantNode falseValue = graph.unique(ConstantNode.forInt(falseBlockInt)); + ValueNode conditionalNode = ConditionalNode.create(condition, trueValue, falseValue); + if (conditionalNode.graph() == null) { + conditionalNode = graph.addOrUnique(conditionalNode); + } + if (genReturn) { + JavaKind returnKind = method.getSignature().getReturnKind().getStackKind(); + this.genReturn(conditionalNode, returnKind); + } else { + frameState.push(JavaKind.Int, conditionalNode); + appendGoto(trueBlock.getSuccessor(0)); + stream.setBCI(oldBci); + } + } + + private LogicNode createLogicNode(Condition cond, ValueNode a, ValueNode b) { + LogicNode condition; + assert !a.getStackKind().isNumericFloat(); + if (cond == Condition.EQ || cond == Condition.NE) { + if (a.getStackKind() == JavaKind.Object) { + condition = genObjectEquals(a, b); + } else { + condition = genIntegerEquals(a, b); + } + } else { + assert a.getStackKind() != JavaKind.Object && !cond.isUnsigned(); + condition = genIntegerLessThan(a, b); + } + return condition; + } + + private void genConstantTargetIf(BciBlock trueBlock, BciBlock falseBlock, boolean negate, LogicNode condition) { + LogicConstantNode constantLogicNode = (LogicConstantNode) condition; + boolean value = constantLogicNode.getValue(); + if (negate) { + value = !value; + } + BciBlock nextBlock = falseBlock; + if (value) { + nextBlock = trueBlock; + } + int startBci = nextBlock.startBci; + int targetAtStart = stream.readUByte(startBci); + if (targetAtStart == Bytecodes.GOTO && nextBlock.getPredecessorCount() == 1) { + // This is an empty block. Skip it. + BciBlock successorBlock = nextBlock.successors.get(0); + ProfilingPlugin profilingPlugin = graphBuilderConfig.getPlugins().getProfilingPlugin(); + if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + profilingPlugin.profileGoto(this, method, bci(), successorBlock.startBci, stateBefore); + } + appendGoto(successorBlock); + assert nextBlock.numNormalSuccessors() == 1; + } else { + ProfilingPlugin profilingPlugin = graphBuilderConfig.getPlugins().getProfilingPlugin(); + if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + profilingPlugin.profileGoto(this, method, bci(), nextBlock.startBci, stateBefore); + } + appendGoto(nextBlock); + } + } + + private int checkPositiveIntConstantPushed(BciBlock block) { + stream.setBCI(block.startBci); + int currentBC = stream.currentBC(); + if (currentBC >= Bytecodes.ICONST_0 && currentBC <= Bytecodes.ICONST_5) { + int constValue = currentBC - Bytecodes.ICONST_0; + return constValue; + } + return -1; + } + + private boolean gotoOrFallThroughAfterConstant(BciBlock block) { + stream.setBCI(block.startBci); + int currentBCI = stream.nextBCI(); + stream.setBCI(currentBCI); + int currentBC = stream.currentBC(); + return stream.currentBCI() > block.endBci || currentBC == Bytecodes.GOTO || currentBC == Bytecodes.GOTO_W; + } + + private boolean returnAfterConstant(BciBlock block) { + stream.setBCI(block.startBci); + int currentBCI = stream.nextBCI(); + stream.setBCI(currentBCI); + int currentBC = stream.currentBC(); + return currentBC == Bytecodes.IRETURN; + } + + @Override + public StampProvider getStampProvider() { + return stampProvider; + } + + @Override + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + + @Override + public void push(JavaKind slotKind, ValueNode value) { + assert value.isAlive(); + frameState.push(slotKind, value); + } + + @Override + public ConstantReflectionProvider getConstantReflection() { + return constantReflection; + } + + @Override + public ConstantFieldProvider getConstantFieldProvider() { + return constantFieldProvider; + } + + /** + * Gets the graph being processed by this builder. + */ + @Override + public StructuredGraph getGraph() { + return graph; + } + + @Override + public BytecodeParser getParent() { + return parent; + } + + @Override + public IntrinsicContext getIntrinsic() { + return intrinsicContext; + } + + @Override + public String toString() { + Formatter fmt = new Formatter(); + BytecodeParser bp = this; + String indent = ""; + while (bp != null) { + if (bp != this) { + fmt.format("%n%s", indent); + } + fmt.format("%s [bci: %d, intrinsic: %s]", bp.code.asStackTraceElement(bp.bci()), bp.bci(), bp.parsingIntrinsic()); + fmt.format("%n%s", new BytecodeDisassembler().disassemble(bp.code, bp.bci(), bp.bci() + 10)); + bp = bp.parent; + indent += " "; + } + return fmt.toString(); + } + + @Override + public BailoutException bailout(String string) { + FrameState currentFrameState = createFrameState(bci(), null); + StackTraceElement[] elements = GraphUtil.approxSourceStackTraceElement(currentFrameState); + BailoutException bailout = new PermanentBailoutException(string); + throw GraphUtil.createBailoutException(string, bailout, elements); + } + + private FrameState createFrameState(int bci, StateSplit forStateSplit) { + if (currentBlock != null && bci > currentBlock.endBci) { + frameState.clearNonLiveLocals(currentBlock, liveness, false); + } + return frameState.create(bci, forStateSplit); + } + + @Override + public void setStateAfter(StateSplit sideEffect) { + assert sideEffect.hasSideEffect(); + FrameState stateAfter = createFrameState(stream.nextBCI(), sideEffect); + sideEffect.setStateAfter(stateAfter); + } + + protected NodeSourcePosition createBytecodePosition() { + return frameState.createBytecodePosition(bci()); + } + + public void setCurrentFrameState(FrameStateBuilder frameState) { + this.frameState = frameState; + } + + protected final BytecodeStream getStream() { + return stream; + } + + @Override + public int bci() { + return stream.currentBCI(); + } + + public void loadLocal(int index, JavaKind kind) { + ValueNode value = frameState.loadLocal(index, kind); + frameState.push(kind, value); + } + + public void storeLocal(JavaKind kind, int index) { + ValueNode value = frameState.pop(kind); + frameState.storeLocal(index, kind, value); + } + + private void genLoadConstant(int cpi, int opcode) { + Object con = lookupConstant(cpi, opcode); + + if (con instanceof JavaType) { + // this is a load of class constant which might be unresolved + JavaType type = (JavaType) con; + if (type instanceof ResolvedJavaType) { + frameState.push(JavaKind.Object, appendConstant(getConstantReflection().asJavaClass((ResolvedJavaType) type))); + } else { + handleUnresolvedLoadConstant(type); + } + } else if (con instanceof JavaConstant) { + JavaConstant constant = (JavaConstant) con; + frameState.push(constant.getJavaKind(), appendConstant(constant)); + } else { + throw new Error("lookupConstant returned an object of incorrect type"); + } + } + + private void genLoadIndexed(JavaKind kind) { + ValueNode index = frameState.pop(JavaKind.Int); + ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object), index); + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleLoadIndexed(this, array, index, kind)) { + return; + } + } + + frameState.push(kind, append(genLoadIndexed(array, index, kind))); + } + + private void genStoreIndexed(JavaKind kind) { + ValueNode value = frameState.pop(kind); + ValueNode index = frameState.pop(JavaKind.Int); + ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object), index); + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleStoreIndexed(this, array, index, kind, value)) { + return; + } + } + + genStoreIndexed(array, index, kind, value); + } + + private void genArithmeticOp(JavaKind kind, int opcode) { + ValueNode y = frameState.pop(kind); + ValueNode x = frameState.pop(kind); + ValueNode v; + switch (opcode) { + case IADD: + case LADD: + v = genIntegerAdd(x, y); + break; + case FADD: + case DADD: + v = genFloatAdd(x, y); + break; + case ISUB: + case LSUB: + v = genIntegerSub(x, y); + break; + case FSUB: + case DSUB: + v = genFloatSub(x, y); + break; + case IMUL: + case LMUL: + v = genIntegerMul(x, y); + break; + case FMUL: + case DMUL: + v = genFloatMul(x, y); + break; + case FDIV: + case DDIV: + v = genFloatDiv(x, y); + break; + case FREM: + case DREM: + v = genFloatRem(x, y); + break; + default: + throw shouldNotReachHere(); + } + frameState.push(kind, append(v)); + } + + private void genIntegerDivOp(JavaKind kind, int opcode) { + ValueNode y = frameState.pop(kind); + ValueNode x = frameState.pop(kind); + ValueNode v; + switch (opcode) { + case IDIV: + case LDIV: + v = genIntegerDiv(x, y); + break; + case IREM: + case LREM: + v = genIntegerRem(x, y); + break; + default: + throw shouldNotReachHere(); + } + frameState.push(kind, append(v)); + } + + private void genNegateOp(JavaKind kind) { + ValueNode x = frameState.pop(kind); + frameState.push(kind, append(genNegateOp(x))); + } + + private void genShiftOp(JavaKind kind, int opcode) { + ValueNode s = frameState.pop(JavaKind.Int); + ValueNode x = frameState.pop(kind); + ValueNode v; + switch (opcode) { + case ISHL: + case LSHL: + v = genLeftShift(x, s); + break; + case ISHR: + case LSHR: + v = genRightShift(x, s); + break; + case IUSHR: + case LUSHR: + v = genUnsignedRightShift(x, s); + break; + default: + throw shouldNotReachHere(); + } + frameState.push(kind, append(v)); + } + + private void genLogicOp(JavaKind kind, int opcode) { + ValueNode y = frameState.pop(kind); + ValueNode x = frameState.pop(kind); + ValueNode v; + switch (opcode) { + case IAND: + case LAND: + v = genAnd(x, y); + break; + case IOR: + case LOR: + v = genOr(x, y); + break; + case IXOR: + case LXOR: + v = genXor(x, y); + break; + default: + throw shouldNotReachHere(); + } + frameState.push(kind, append(v)); + } + + private void genCompareOp(JavaKind kind, boolean isUnorderedLess) { + ValueNode y = frameState.pop(kind); + ValueNode x = frameState.pop(kind); + frameState.push(JavaKind.Int, append(genNormalizeCompare(x, y, isUnorderedLess))); + } + + private void genFloatConvert(FloatConvert op, JavaKind from, JavaKind to) { + ValueNode input = frameState.pop(from); + frameState.push(to, append(genFloatConvert(op, input))); + } + + private void genSignExtend(JavaKind from, JavaKind to) { + ValueNode input = frameState.pop(from); + if (from != from.getStackKind()) { + input = append(genNarrow(input, from.getBitCount())); + } + frameState.push(to, append(genSignExtend(input, to.getBitCount()))); + } + + private void genZeroExtend(JavaKind from, JavaKind to) { + ValueNode input = frameState.pop(from); + if (from != from.getStackKind()) { + input = append(genNarrow(input, from.getBitCount())); + } + frameState.push(to, append(genZeroExtend(input, to.getBitCount()))); + } + + private void genNarrow(JavaKind from, JavaKind to) { + ValueNode input = frameState.pop(from); + frameState.push(to, append(genNarrow(input, to.getBitCount()))); + } + + private void genIncrement() { + int index = getStream().readLocalIndex(); + int delta = getStream().readIncrement(); + ValueNode x = frameState.loadLocal(index, JavaKind.Int); + ValueNode y = appendConstant(JavaConstant.forInt(delta)); + frameState.storeLocal(index, JavaKind.Int, append(genIntegerAdd(x, y))); + } + + private void genIfZero(Condition cond) { + ValueNode y = appendConstant(JavaConstant.INT_0); + ValueNode x = frameState.pop(JavaKind.Int); + genIf(x, cond, y); + } + + private void genIfNull(Condition cond) { + ValueNode y = appendConstant(JavaConstant.NULL_POINTER); + ValueNode x = frameState.pop(JavaKind.Object); + genIf(x, cond, y); + } + + private void genIfSame(JavaKind kind, Condition cond) { + ValueNode y = frameState.pop(kind); + ValueNode x = frameState.pop(kind); + genIf(x, cond, y); + } + + protected JavaType lookupType(int cpi, int bytecode) { + maybeEagerlyResolve(cpi, bytecode); + JavaType result = constantPool.lookupType(cpi, bytecode); + assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType; + return result; + } + + private JavaMethod lookupMethod(int cpi, int opcode) { + maybeEagerlyResolve(cpi, opcode); + JavaMethod result = constantPool.lookupMethod(cpi, opcode); + /* + * In general, one cannot assume that the declaring class being initialized is useful, since + * the actual concrete receiver may be a different class (except for static calls). Also, + * interfaces are initialized only under special circumstances, so that this assertion would + * often fail for interface calls. + */ + assert !graphBuilderConfig.unresolvedIsError() || + (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result; + return result; + } + + private JavaField lookupField(int cpi, int opcode) { + maybeEagerlyResolve(cpi, opcode); + JavaField result = constantPool.lookupField(cpi, method, opcode); + if (graphBuilderConfig.eagerResolving()) { + assert result instanceof ResolvedJavaField : "Not resolved: " + result; + ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass(); + if (!declaringClass.isInitialized()) { + assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass; + declaringClass.initialize(); + } + } + assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; + return result; + } + + private Object lookupConstant(int cpi, int opcode) { + maybeEagerlyResolve(cpi, opcode); + Object result = constantPool.lookupConstant(cpi); + assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; + return result; + } + + private void maybeEagerlyResolve(int cpi, int bytecode) { + if (intrinsicContext != null) { + constantPool.loadReferencedType(cpi, bytecode); + } else if (graphBuilderConfig.eagerResolving()) { + /* + * Since we're potentially triggering class initialization here, we need synchronization + * to mitigate the potential for class initialization related deadlock being caused by + * the compiler (e.g., https://github.com/graalvm/graal-core/pull/232/files#r90788550). + */ + synchronized (BytecodeParser.class) { + constantPool.loadReferencedType(cpi, bytecode); + } + } + } + + private JavaTypeProfile getProfileForTypeCheck(TypeReference type) { + if (parsingIntrinsic() || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || type.isExact()) { + return null; + } else { + return profilingInfo.getTypeProfile(bci()); + } + } + + private void genCheckCast() { + int cpi = getStream().readCPI(); + JavaType type = lookupType(cpi, CHECKCAST); + ValueNode object = frameState.pop(JavaKind.Object); + + if (!(type instanceof ResolvedJavaType)) { + handleUnresolvedCheckCast(type, object); + return; + } + TypeReference checkedType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) type); + JavaTypeProfile profile = getProfileForTypeCheck(checkedType); + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleCheckCast(this, object, checkedType.getType(), profile)) { + return; + } + } + + ValueNode castNode = null; + if (profile != null) { + if (profile.getNullSeen().isFalse()) { + object = appendNullCheck(object); + ResolvedJavaType singleType = profile.asSingleType(); + if (singleType != null && checkedType.getType().isAssignableFrom(singleType)) { + LogicNode typeCheck = append(createInstanceOf(TypeReference.createExactTrusted(singleType), object, profile)); + if (typeCheck.isTautology()) { + castNode = object; + } else { + FixedGuardNode fixedGuard = append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, false)); + castNode = append(new PiNode(object, StampFactory.objectNonNull(TypeReference.createExactTrusted(singleType)), fixedGuard)); + } + } + } + } + if (castNode == null) { + LogicNode condition = genUnique(createInstanceOfAllowNull(checkedType, object, null)); + if (condition.isTautology()) { + castNode = object; + } else { + FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false)); + castNode = append(new PiNode(object, StampFactory.object(checkedType), fixedGuard)); + } + } + frameState.push(JavaKind.Object, castNode); + } + + private ValueNode appendNullCheck(ValueNode object) { + if (object.stamp() instanceof AbstractPointerStamp) { + AbstractPointerStamp stamp = (AbstractPointerStamp) object.stamp(); + if (stamp.nonNull()) { + return object; + } + } + + LogicNode isNull = append(IsNullNode.create(object)); + FixedGuardNode fixedGuard = append(new FixedGuardNode(isNull, DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true)); + return append(new PiNode(object, object.stamp().join(StampFactory.objectNonNull()), fixedGuard)); + } + + private void genInstanceOf() { + int cpi = getStream().readCPI(); + JavaType type = lookupType(cpi, INSTANCEOF); + ValueNode object = frameState.pop(JavaKind.Object); + + if (!(type instanceof ResolvedJavaType)) { + handleUnresolvedInstanceOf(type, object); + return; + } + TypeReference resolvedType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) type); + JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleInstanceOf(this, object, resolvedType.getType(), profile)) { + return; + } + } + + LogicNode instanceOfNode = null; + if (profile != null) { + if (profile.getNullSeen().isFalse()) { + object = appendNullCheck(object); + ResolvedJavaType singleType = profile.asSingleType(); + if (singleType != null) { + LogicNode typeCheck = append(createInstanceOf(TypeReference.createExactTrusted(singleType), object, profile)); + if (!typeCheck.isTautology()) { + append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile)); + } + instanceOfNode = LogicConstantNode.forBoolean(resolvedType.getType().isAssignableFrom(singleType)); + } + } + } + if (instanceOfNode == null) { + instanceOfNode = createInstanceOf(resolvedType, object, null); + } + frameState.push(JavaKind.Int, append(genConditional(genUnique(instanceOfNode)))); + } + + void genNewInstance(int cpi) { + JavaType type = lookupType(cpi, NEW); + + if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) { + handleUnresolvedNewInstance(type); + return; + } + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + + ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes(); + if (skippedExceptionTypes != null) { + for (ResolvedJavaType exceptionType : skippedExceptionTypes) { + if (exceptionType.isAssignableFrom(resolvedType)) { + append(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, RuntimeConstraint)); + return; + } + } + } + + ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin(); + if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType)) { + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + classInitializationPlugin.apply(this, resolvedType, stateBefore); + } + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleNewInstance(this, resolvedType)) { + return; + } + } + + frameState.push(JavaKind.Object, append(createNewInstance(resolvedType, true))); + } + + /** + * Gets the kind of array elements for the array type code that appears in a + * {@link Bytecodes#NEWARRAY} bytecode. + * + * @param code the array type code + * @return the kind from the array type code + */ + private static Class arrayTypeCodeToClass(int code) { + switch (code) { + case 4: + return boolean.class; + case 5: + return char.class; + case 6: + return float.class; + case 7: + return double.class; + case 8: + return byte.class; + case 9: + return short.class; + case 10: + return int.class; + case 11: + return long.class; + default: + throw new IllegalArgumentException("unknown array type code: " + code); + } + } + + private void genNewPrimitiveArray(int typeCode) { + ResolvedJavaType elementType = metaAccess.lookupJavaType(arrayTypeCodeToClass(typeCode)); + ValueNode length = frameState.pop(JavaKind.Int); + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleNewArray(this, elementType, length)) { + return; + } + } + + frameState.push(JavaKind.Object, append(createNewArray(elementType, length, true))); + } + + private void genNewObjectArray(int cpi) { + JavaType type = lookupType(cpi, ANEWARRAY); + + if (!(type instanceof ResolvedJavaType)) { + ValueNode length = frameState.pop(JavaKind.Int); + handleUnresolvedNewObjectArray(type, length); + return; + } + + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + + ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); + if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType.getArrayClass())) { + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + classInitializationPlugin.apply(this, resolvedType.getArrayClass(), stateBefore); + } + + ValueNode length = frameState.pop(JavaKind.Int); + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleNewArray(this, resolvedType, length)) { + return; + } + } + + frameState.push(JavaKind.Object, append(createNewArray(resolvedType, length, true))); + } + + private void genNewMultiArray(int cpi) { + JavaType type = lookupType(cpi, MULTIANEWARRAY); + int rank = getStream().readUByte(bci() + 3); + ValueNode[] dims = new ValueNode[rank]; + + if (!(type instanceof ResolvedJavaType)) { + for (int i = rank - 1; i >= 0; i--) { + dims[i] = frameState.pop(JavaKind.Int); + } + handleUnresolvedNewMultiArray(type, dims); + return; + } + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + + ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); + if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType.getArrayClass())) { + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + classInitializationPlugin.apply(this, resolvedType.getArrayClass(), stateBefore); + } + + for (int i = rank - 1; i >= 0; i--) { + dims[i] = frameState.pop(JavaKind.Int); + } + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleNewMultiArray(this, resolvedType, dims)) { + return; + } + } + + frameState.push(JavaKind.Object, append(createNewMultiArray(resolvedType, dims))); + } + + private void genGetField(JavaField field) { + ValueNode receiver = emitExplicitExceptions(frameState.pop(JavaKind.Object), null); + + if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { + handleUnresolvedLoadField(field, receiver); + return; + } + ResolvedJavaField resolvedField = (ResolvedJavaField) field; + + if (!parsingIntrinsic() && GeneratePIC.getValue()) { + graph.recordField(resolvedField); + } + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleLoadField(this, receiver, resolvedField)) { + return; + } + } + + frameState.push(field.getJavaKind(), append(genLoadField(receiver, resolvedField))); + if (resolvedField.getName().equals("referent") && resolvedField.getDeclaringClass().equals(metaAccess.lookupJavaType(Reference.class))) { + LocationIdentity referentIdentity = new FieldLocationIdentity(resolvedField); + append(new MembarNode(0, referentIdentity)); + } + } + + /** + * @param receiver the receiver of an object based operation + * @param index the index of an array based operation that is to be tested for out of bounds. + * This is null for a non-array operation. + * @return the receiver value possibly modified to have a tighter stamp + */ + protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) { + assert receiver != null; + if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.OmitAll) { + return receiver; + } + if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.Profile && (profilingInfo == null || + (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue()))) { + return receiver; + } + + ValueNode nonNullReceiver = emitExplicitNullCheck(receiver); + if (index != null) { + ValueNode length = append(genArrayLength(nonNullReceiver)); + emitExplicitBoundsCheck(index, length); + } + EXPLICIT_EXCEPTIONS.increment(); + return nonNullReceiver; + } + + private void genPutField(JavaField field) { + ValueNode value = frameState.pop(field.getJavaKind()); + ValueNode receiver = emitExplicitExceptions(frameState.pop(JavaKind.Object), null); + + if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { + handleUnresolvedStoreField(field, value, receiver); + return; + } + ResolvedJavaField resolvedField = (ResolvedJavaField) field; + + if (!parsingIntrinsic() && GeneratePIC.getValue()) { + graph.recordField(resolvedField); + } + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleStoreField(this, receiver, resolvedField, value)) { + return; + } + } + + if (resolvedField.isFinal() && method.isConstructor()) { + finalBarrierRequired = true; + } + genStoreField(receiver, resolvedField, value); + } + + private void genGetStatic(JavaField field) { + if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { + handleUnresolvedLoadField(field, null); + return; + } + ResolvedJavaField resolvedField = (ResolvedJavaField) field; + + if (!parsingIntrinsic() && GeneratePIC.getValue()) { + graph.recordField(resolvedField); + } + + /* + * Javac does not allow use of "$assertionsDisabled" for a field name but Eclipse does, in + * which case a suffix is added to the generated field. + */ + if ((parsingIntrinsic() || graphBuilderConfig.omitAssertions()) && resolvedField.isSynthetic() && resolvedField.getName().startsWith("$assertionsDisabled")) { + frameState.push(field.getJavaKind(), ConstantNode.forBoolean(true, graph)); + return; + } + + ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); + if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedField.getDeclaringClass())) { + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + classInitializationPlugin.apply(this, resolvedField.getDeclaringClass(), stateBefore); + } + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleLoadStaticField(this, resolvedField)) { + return; + } + } + + frameState.push(field.getJavaKind(), append(genLoadField(null, resolvedField))); + } + + private void genPutStatic(JavaField field) { + ValueNode value = frameState.pop(field.getJavaKind()); + if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { + handleUnresolvedStoreField(field, value, null); + return; + } + ResolvedJavaField resolvedField = (ResolvedJavaField) field; + + if (!parsingIntrinsic() && GeneratePIC.getValue()) { + graph.recordField(resolvedField); + } + + ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); + if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedField.getDeclaringClass())) { + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + classInitializationPlugin.apply(this, resolvedField.getDeclaringClass(), stateBefore); + } + + for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { + if (plugin.handleStoreStaticField(this, resolvedField, value)) { + return; + } + } + + genStoreField(null, resolvedField, value); + } + + private double[] switchProbability(int numberOfCases, int bci) { + double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci)); + if (prob != null) { + assert prob.length == numberOfCases; + } else { + Debug.log("Missing probability (switch) in %s at bci %d", method, bci); + prob = new double[numberOfCases]; + for (int i = 0; i < numberOfCases; i++) { + prob[i] = 1.0d / numberOfCases; + } + } + assert allPositive(prob); + return prob; + } + + private static boolean allPositive(double[] a) { + for (double d : a) { + if (d < 0) { + return false; + } + } + return true; + } + + static class SuccessorInfo { + final int blockIndex; + int actualIndex; + + SuccessorInfo(int blockSuccessorIndex) { + this.blockIndex = blockSuccessorIndex; + actualIndex = -1; + } + } + + private void genSwitch(BytecodeSwitch bs) { + int bci = bci(); + ValueNode value = frameState.pop(JavaKind.Int); + + int nofCases = bs.numberOfCases(); + double[] keyProbabilities = switchProbability(nofCases + 1, bci); + + Map bciToBlockSuccessorIndex = new HashMap<>(); + for (int i = 0; i < currentBlock.getSuccessorCount(); i++) { + assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci); + if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) { + bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i)); + } + } + + ArrayList actualSuccessors = new ArrayList<>(); + int[] keys = new int[nofCases]; + int[] keySuccessors = new int[nofCases + 1]; + int deoptSuccessorIndex = -1; + int nextSuccessorIndex = 0; + boolean constantValue = value.isConstant(); + for (int i = 0; i < nofCases + 1; i++) { + if (i < nofCases) { + keys[i] = bs.keyAt(i); + } + + if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) { + if (deoptSuccessorIndex < 0) { + deoptSuccessorIndex = nextSuccessorIndex++; + actualSuccessors.add(null); + } + keySuccessors[i] = deoptSuccessorIndex; + } else { + int targetBci = i >= nofCases ? bs.defaultTarget() : bs.targetAt(i); + SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci); + if (info.actualIndex < 0) { + info.actualIndex = nextSuccessorIndex++; + actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex)); + } + keySuccessors[i] = info.actualIndex; + } + } + + genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors); + + } + + protected boolean isNeverExecutedCode(double probability) { + return probability == 0 && optimisticOpts.removeNeverExecutedCode(); + } + + protected double branchProbability() { + if (profilingInfo == null) { + return 0.5; + } + assert assertAtIfBytecode(); + double probability = profilingInfo.getBranchTakenProbability(bci()); + if (probability < 0) { + assert probability == -1 : "invalid probability"; + Debug.log("missing probability in %s at bci %d", code, bci()); + probability = 0.5; + } + + if (!optimisticOpts.removeNeverExecutedCode()) { + if (probability == 0) { + probability = 0.0000001; + } else if (probability == 1) { + probability = 0.999999; + } + } + return probability; + } + + private boolean assertAtIfBytecode() { + int bytecode = stream.currentBC(); + switch (bytecode) { + 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 IFNULL: + case IFNONNULL: + return true; + } + assert false : String.format("%x is not an if bytecode", bytecode); + return true; + } + + public final void processBytecode(int bci, int opcode) { + int cpi; + + // @formatter:off + // Checkstyle: stop + switch (opcode) { + case NOP : /* nothing to do */ break; + case ACONST_NULL : frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER)); break; + case ICONST_M1 : // fall through + case ICONST_0 : // fall through + case ICONST_1 : // fall through + case ICONST_2 : // fall through + case ICONST_3 : // fall through + case ICONST_4 : // fall through + case ICONST_5 : frameState.push(JavaKind.Int, appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; + case LCONST_0 : // fall through + case LCONST_1 : frameState.push(JavaKind.Long, appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; + case FCONST_0 : // fall through + case FCONST_1 : // fall through + case FCONST_2 : frameState.push(JavaKind.Float, appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; + case DCONST_0 : // fall through + case DCONST_1 : frameState.push(JavaKind.Double, appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; + case BIPUSH : frameState.push(JavaKind.Int, appendConstant(JavaConstant.forInt(stream.readByte()))); break; + case SIPUSH : frameState.push(JavaKind.Int, appendConstant(JavaConstant.forInt(stream.readShort()))); break; + case LDC : // fall through + case LDC_W : // fall through + case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; + case ILOAD : loadLocal(stream.readLocalIndex(), JavaKind.Int); break; + case LLOAD : loadLocal(stream.readLocalIndex(), JavaKind.Long); break; + case FLOAD : loadLocal(stream.readLocalIndex(), JavaKind.Float); break; + case DLOAD : loadLocal(stream.readLocalIndex(), JavaKind.Double); break; + case ALOAD : loadLocal(stream.readLocalIndex(), JavaKind.Object); break; + case ILOAD_0 : // fall through + case ILOAD_1 : // fall through + case ILOAD_2 : // fall through + case ILOAD_3 : loadLocal(opcode - ILOAD_0, JavaKind.Int); break; + case LLOAD_0 : // fall through + case LLOAD_1 : // fall through + case LLOAD_2 : // fall through + case LLOAD_3 : loadLocal(opcode - LLOAD_0, JavaKind.Long); break; + case FLOAD_0 : // fall through + case FLOAD_1 : // fall through + case FLOAD_2 : // fall through + case FLOAD_3 : loadLocal(opcode - FLOAD_0, JavaKind.Float); break; + case DLOAD_0 : // fall through + case DLOAD_1 : // fall through + case DLOAD_2 : // fall through + case DLOAD_3 : loadLocal(opcode - DLOAD_0, JavaKind.Double); break; + case ALOAD_0 : // fall through + case ALOAD_1 : // fall through + case ALOAD_2 : // fall through + case ALOAD_3 : loadLocal(opcode - ALOAD_0, JavaKind.Object); break; + case IALOAD : genLoadIndexed(JavaKind.Int ); break; + case LALOAD : genLoadIndexed(JavaKind.Long ); break; + case FALOAD : genLoadIndexed(JavaKind.Float ); break; + case DALOAD : genLoadIndexed(JavaKind.Double); break; + case AALOAD : genLoadIndexed(JavaKind.Object); break; + case BALOAD : genLoadIndexed(JavaKind.Byte ); break; + case CALOAD : genLoadIndexed(JavaKind.Char ); break; + case SALOAD : genLoadIndexed(JavaKind.Short ); break; + case ISTORE : storeLocal(JavaKind.Int, stream.readLocalIndex()); break; + case LSTORE : storeLocal(JavaKind.Long, stream.readLocalIndex()); break; + case FSTORE : storeLocal(JavaKind.Float, stream.readLocalIndex()); break; + case DSTORE : storeLocal(JavaKind.Double, stream.readLocalIndex()); break; + case ASTORE : storeLocal(JavaKind.Object, stream.readLocalIndex()); break; + case ISTORE_0 : // fall through + case ISTORE_1 : // fall through + case ISTORE_2 : // fall through + case ISTORE_3 : storeLocal(JavaKind.Int, opcode - ISTORE_0); break; + case LSTORE_0 : // fall through + case LSTORE_1 : // fall through + case LSTORE_2 : // fall through + case LSTORE_3 : storeLocal(JavaKind.Long, opcode - LSTORE_0); break; + case FSTORE_0 : // fall through + case FSTORE_1 : // fall through + case FSTORE_2 : // fall through + case FSTORE_3 : storeLocal(JavaKind.Float, opcode - FSTORE_0); break; + case DSTORE_0 : // fall through + case DSTORE_1 : // fall through + case DSTORE_2 : // fall through + case DSTORE_3 : storeLocal(JavaKind.Double, opcode - DSTORE_0); break; + case ASTORE_0 : // fall through + case ASTORE_1 : // fall through + case ASTORE_2 : // fall through + case ASTORE_3 : storeLocal(JavaKind.Object, opcode - ASTORE_0); break; + case IASTORE : genStoreIndexed(JavaKind.Int ); break; + case LASTORE : genStoreIndexed(JavaKind.Long ); break; + case FASTORE : genStoreIndexed(JavaKind.Float ); break; + case DASTORE : genStoreIndexed(JavaKind.Double); break; + case AASTORE : genStoreIndexed(JavaKind.Object); break; + case BASTORE : genStoreIndexed(JavaKind.Byte ); break; + case CASTORE : genStoreIndexed(JavaKind.Char ); break; + case SASTORE : genStoreIndexed(JavaKind.Short ); break; + case POP : // fall through + case POP2 : // fall through + case DUP : // fall through + case DUP_X1 : // fall through + case DUP_X2 : // fall through + case DUP2 : // fall through + case DUP2_X1 : // fall through + case DUP2_X2 : // fall through + case SWAP : frameState.stackOp(opcode); break; + case IADD : // fall through + case ISUB : // fall through + case IMUL : genArithmeticOp(JavaKind.Int, opcode); break; + case IDIV : // fall through + case IREM : genIntegerDivOp(JavaKind.Int, opcode); break; + case LADD : // fall through + case LSUB : // fall through + case LMUL : genArithmeticOp(JavaKind.Long, opcode); break; + case LDIV : // fall through + case LREM : genIntegerDivOp(JavaKind.Long, opcode); break; + case FADD : // fall through + case FSUB : // fall through + case FMUL : // fall through + case FDIV : // fall through + case FREM : genArithmeticOp(JavaKind.Float, opcode); break; + case DADD : // fall through + case DSUB : // fall through + case DMUL : // fall through + case DDIV : // fall through + case DREM : genArithmeticOp(JavaKind.Double, opcode); break; + case INEG : genNegateOp(JavaKind.Int); break; + case LNEG : genNegateOp(JavaKind.Long); break; + case FNEG : genNegateOp(JavaKind.Float); break; + case DNEG : genNegateOp(JavaKind.Double); break; + case ISHL : // fall through + case ISHR : // fall through + case IUSHR : genShiftOp(JavaKind.Int, opcode); break; + case IAND : // fall through + case IOR : // fall through + case IXOR : genLogicOp(JavaKind.Int, opcode); break; + case LSHL : // fall through + case LSHR : // fall through + case LUSHR : genShiftOp(JavaKind.Long, opcode); break; + case LAND : // fall through + case LOR : // fall through + case LXOR : genLogicOp(JavaKind.Long, opcode); break; + case IINC : genIncrement(); break; + case I2F : genFloatConvert(FloatConvert.I2F, JavaKind.Int, JavaKind.Float); break; + case I2D : genFloatConvert(FloatConvert.I2D, JavaKind.Int, JavaKind.Double); break; + case L2F : genFloatConvert(FloatConvert.L2F, JavaKind.Long, JavaKind.Float); break; + case L2D : genFloatConvert(FloatConvert.L2D, JavaKind.Long, JavaKind.Double); break; + case F2I : genFloatConvert(FloatConvert.F2I, JavaKind.Float, JavaKind.Int); break; + case F2L : genFloatConvert(FloatConvert.F2L, JavaKind.Float, JavaKind.Long); break; + case F2D : genFloatConvert(FloatConvert.F2D, JavaKind.Float, JavaKind.Double); break; + case D2I : genFloatConvert(FloatConvert.D2I, JavaKind.Double, JavaKind.Int); break; + case D2L : genFloatConvert(FloatConvert.D2L, JavaKind.Double, JavaKind.Long); break; + case D2F : genFloatConvert(FloatConvert.D2F, JavaKind.Double, JavaKind.Float); break; + case L2I : genNarrow(JavaKind.Long, JavaKind.Int); break; + case I2L : genSignExtend(JavaKind.Int, JavaKind.Long); break; + case I2B : genSignExtend(JavaKind.Byte, JavaKind.Int); break; + case I2S : genSignExtend(JavaKind.Short, JavaKind.Int); break; + case I2C : genZeroExtend(JavaKind.Char, JavaKind.Int); break; + case LCMP : genCompareOp(JavaKind.Long, false); break; + case FCMPL : genCompareOp(JavaKind.Float, true); break; + case FCMPG : genCompareOp(JavaKind.Float, false); break; + case DCMPL : genCompareOp(JavaKind.Double, true); break; + case DCMPG : genCompareOp(JavaKind.Double, false); break; + case IFEQ : genIfZero(Condition.EQ); break; + case IFNE : genIfZero(Condition.NE); break; + case IFLT : genIfZero(Condition.LT); break; + case IFGE : genIfZero(Condition.GE); break; + case IFGT : genIfZero(Condition.GT); break; + case IFLE : genIfZero(Condition.LE); break; + case IF_ICMPEQ : genIfSame(JavaKind.Int, Condition.EQ); break; + case IF_ICMPNE : genIfSame(JavaKind.Int, Condition.NE); break; + case IF_ICMPLT : genIfSame(JavaKind.Int, Condition.LT); break; + case IF_ICMPGE : genIfSame(JavaKind.Int, Condition.GE); break; + case IF_ICMPGT : genIfSame(JavaKind.Int, Condition.GT); break; + case IF_ICMPLE : genIfSame(JavaKind.Int, Condition.LE); break; + case IF_ACMPEQ : genIfSame(JavaKind.Object, Condition.EQ); break; + case IF_ACMPNE : genIfSame(JavaKind.Object, Condition.NE); break; + case GOTO : genGoto(); break; + case JSR : genJsr(stream.readBranchDest()); break; + case RET : genRet(stream.readLocalIndex()); break; + case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; + case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; + case IRETURN : genReturn(frameState.pop(JavaKind.Int), JavaKind.Int); break; + case LRETURN : genReturn(frameState.pop(JavaKind.Long), JavaKind.Long); break; + case FRETURN : genReturn(frameState.pop(JavaKind.Float), JavaKind.Float); break; + case DRETURN : genReturn(frameState.pop(JavaKind.Double), JavaKind.Double); break; + case ARETURN : genReturn(frameState.pop(JavaKind.Object), JavaKind.Object); break; + case RETURN : genReturn(null, JavaKind.Void); break; + case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; + case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; + case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; + case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; + case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; + case NEW : genNewInstance(stream.readCPI()); break; + case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; + case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; + case ARRAYLENGTH : genArrayLength(); break; + case ATHROW : genThrow(); break; + case CHECKCAST : genCheckCast(); break; + case INSTANCEOF : genInstanceOf(); break; + case MONITORENTER : genMonitorEnter(frameState.pop(JavaKind.Object), stream.nextBCI()); break; + case MONITOREXIT : genMonitorExit(frameState.pop(JavaKind.Object), null, stream.nextBCI()); break; + case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; + case IFNULL : genIfNull(Condition.EQ); break; + case IFNONNULL : genIfNull(Condition.NE); break; + case GOTO_W : genGoto(); break; + case JSR_W : genJsr(stream.readBranchDest()); break; + case BREAKPOINT : throw new PermanentBailoutException("concurrent setting of breakpoint"); + default : throw new PermanentBailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); + } + // @formatter:on + // Checkstyle: resume + } + + private void genArrayLength() { + ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object), null); + frameState.push(JavaKind.Int, append(genArrayLength(array))); + } + + @Override + public ResolvedJavaMethod getMethod() { + return method; + } + + @Override + public Bytecode getCode() { + return code; + } + + public FrameStateBuilder getFrameStateBuilder() { + return frameState; + } + + protected boolean traceInstruction(int bci, int opcode, boolean blockStart) { + if (Debug.isEnabled() && BytecodeParserOptions.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) { + traceInstructionHelper(bci, opcode, blockStart); + } + return true; + } + + private void traceInstructionHelper(int bci, int opcode, boolean blockStart) { + StringBuilder sb = new StringBuilder(40); + sb.append(blockStart ? '+' : '|'); + if (bci < 10) { + sb.append(" "); + } else if (bci < 100) { + sb.append(' '); + } + sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); + for (int i = bci + 1; i < stream.nextBCI(); ++i) { + sb.append(' ').append(stream.readUByte(i)); + } + if (!currentBlock.getJsrScope().isEmpty()) { + sb.append(' ').append(currentBlock.getJsrScope()); + } + Debug.log("%s", sb); + } + + @Override + public boolean parsingIntrinsic() { + return intrinsicContext != null; + } + + @Override + public BytecodeParser getNonIntrinsicAncestor() { + BytecodeParser ancestor = parent; + while (ancestor != null && ancestor.parsingIntrinsic()) { + ancestor = ancestor.parent; + } + return ancestor; + } + + static String nSpaces(int n) { + return n == 0 ? "" : format("%" + n + "s", ""); + } + + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean assertionsEnabled = false; + assert assertionsEnabled = true; + return assertionsEnabled; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java 2016-12-07 13:50:56.912288775 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, 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.java; + +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.StableOptionValue; + +/** + * Options related to {@link BytecodeParser}. + * + * Note: This must be a top level class to work around for + * Eclipse bug 477597. + */ +public class BytecodeParserOptions { + // @formatter:off + @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug) + public static final OptionValue TraceBytecodeParserLevel = new OptionValue<>(0); + + @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert) + public static final StableOptionValue InlineDuringParsing = new StableOptionValue<>(true); + + @Option(help = "Inlines intrinsic methods during bytecode parsing.", type = OptionType.Expert) + public static final StableOptionValue InlineIntrinsicsDuringParsing = new StableOptionValue<>(true); + + @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue TraceInlineDuringParsing = new StableOptionValue<>(false); + + @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue TraceParserPlugins = new StableOptionValue<>(false); + + @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue InlineDuringParsingMaxDepth = new StableOptionValue<>(10); + + @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue DumpDuringGraphBuilding = new StableOptionValue<>(false); + + @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug) + public static final OptionValue HideSubstitutionStates = new OptionValue<>(false); + + @Option(help = "Use intrinsics guarded by a virtual dispatch test at indirect call sites.", type = OptionType.Debug) + public static final OptionValue UseGuardedIntrinsics = new OptionValue<>(true); + // @formatter:on +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java 2016-12-07 13:50:57.177300422 -0800 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2011, 2014, 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.java; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.ControlSplitNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.LoopExitNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.phases.Phase; +import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; + +public final class ComputeLoopFrequenciesClosure extends ReentrantNodeIterator.NodeIteratorClosure { + + private static final ComputeLoopFrequenciesClosure INSTANCE = new ComputeLoopFrequenciesClosure(); + + private ComputeLoopFrequenciesClosure() { + // nothing to do + } + + @Override + protected Double processNode(FixedNode node, Double currentState) { + // normal nodes never change the probability of a path + return currentState; + } + + @Override + protected Double merge(AbstractMergeNode merge, List states) { + // a merge has the sum of all predecessor probabilities + return states.stream().collect(Collectors.summingDouble(d -> d)); + } + + @Override + protected Double afterSplit(AbstractBeginNode node, Double oldState) { + // a control split splits up the probability + ControlSplitNode split = (ControlSplitNode) node.predecessor(); + return oldState * split.probability(node); + } + + @Override + protected Map processLoop(LoopBeginNode loop, Double initialState) { + Map exitStates = ReentrantNodeIterator.processLoop(this, loop, 1D).exitStates; + + double exitProbability = exitStates.values().stream().mapToDouble(d -> d).sum(); + exitProbability = Math.min(1D, exitProbability); + if (exitProbability < ControlFlowGraph.MIN_PROBABILITY) { + exitProbability = ControlFlowGraph.MIN_PROBABILITY; + } + assert exitProbability <= 1D && exitProbability >= 0D; + double loopFrequency = 1D / exitProbability; + loop.setLoopFrequency(loopFrequency); + + double adjustmentFactor = initialState * loopFrequency; + exitStates.replaceAll((exitNode, probability) -> multiplySaturate(probability, adjustmentFactor)); + + return exitStates; + } + + /** + * Multiplies a and b and saturates the result to {@link ControlFlowGraph#MAX_PROBABILITY}. + */ + public static double multiplySaturate(double a, double b) { + double r = a * b; + if (r > ControlFlowGraph.MAX_PROBABILITY) { + return ControlFlowGraph.MAX_PROBABILITY; + } + return r; + } + + /** + * Computes the frequencies of all loops in the given graph. This is done by performing a + * reverse postorder iteration and computing the probability of all fixed nodes. The combined + * probability of all exits of a loop can be used to compute the loop's expected frequency. + */ + public static void compute(StructuredGraph graph) { + if (graph.hasLoops()) { + ReentrantNodeIterator.apply(INSTANCE, graph.start(), 1D); + } + } + + public static class ComputeLoopFrequencyPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + compute(graph); + } + } + + public static final ComputeLoopFrequencyPhase PHASE_INSTANCE = new ComputeLoopFrequencyPhase(); + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/DefaultSuitesProvider.java 2016-12-07 13:50:57.443312115 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, 2015, 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.java; + +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.Suites; + +public class DefaultSuitesProvider extends SuitesProviderBase { + + private final CompilerConfiguration compilerConfiguration; + + public DefaultSuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) { + super(); + this.defaultGraphBuilderSuite = createGraphBuilderSuite(plugins); + this.compilerConfiguration = compilerConfiguration; + } + + @Override + public Suites createSuites() { + return Suites.createSuites(compilerConfiguration); + } + + protected PhaseSuite createGraphBuilderSuite(Plugins plugins) { + PhaseSuite suite = new PhaseSuite<>(); + suite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getDefault(plugins))); + return suite; + } + + @Override + public LIRSuites createLIRSuites() { + return Suites.createLIRSuites(compilerConfiguration); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java 2016-12-07 13:50:57.707323718 -0800 @@ -0,0 +1,1000 @@ +/* + * Copyright (c) 2012, 2016, 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.java; + +import static org.graalvm.compiler.bytecode.Bytecodes.DUP; +import static org.graalvm.compiler.bytecode.Bytecodes.DUP2; +import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X1; +import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X2; +import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X1; +import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X2; +import static org.graalvm.compiler.bytecode.Bytecodes.POP; +import static org.graalvm.compiler.bytecode.Bytecodes.POP2; +import static org.graalvm.compiler.bytecode.Bytecodes.SWAP; +import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; +import static org.graalvm.compiler.java.BytecodeParserOptions.HideSubstitutionStates; +import static org.graalvm.compiler.nodes.FrameState.TWO_SLOT_MARKER; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +import org.graalvm.compiler.bytecode.Bytecode; +import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.java.BciBlockMapping.BciBlock; +import org.graalvm.compiler.nodeinfo.Verbosity; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.LoopExitNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.ProxyNode; +import org.graalvm.compiler.nodes.StateSplit; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.ValuePhiNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool; +import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.SideEffectsState; +import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin; +import org.graalvm.compiler.nodes.java.MonitorIdNode; +import org.graalvm.compiler.nodes.util.GraphUtil; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Signature; + +public final class FrameStateBuilder implements SideEffectsState { + + private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; + private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; + + private final BytecodeParser parser; + private final GraphBuilderTool tool; + private final Bytecode code; + private int stackSize; + protected final ValueNode[] locals; + protected final ValueNode[] stack; + private ValueNode[] lockedObjects; + private boolean canVerifyKind; + + /** + * @see BytecodeFrame#rethrowException + */ + private boolean rethrowException; + + private MonitorIdNode[] monitorIds; + private final StructuredGraph graph; + private FrameState outerFrameState; + + /** + * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more + * than one when the current block contains no side-effects but merging predecessor blocks do. + */ + private List sideEffects; + + private JavaConstant constantReceiver; + + /** + * Creates a new frame state builder for the given method and the given target graph. + * + * @param method the method whose frame is simulated + * @param graph the target graph of Graal nodes created by the builder + */ + public FrameStateBuilder(GraphBuilderTool tool, ResolvedJavaMethod method, StructuredGraph graph) { + this(tool, new ResolvedJavaMethodBytecode(method), graph); + } + + /** + * Creates a new frame state builder for the given code attribute, method and the given target + * graph. + * + * @param code the bytecode in which the frame exists + * @param graph the target graph of Graal nodes created by the builder + */ + public FrameStateBuilder(GraphBuilderTool tool, Bytecode code, StructuredGraph graph) { + this.tool = tool; + if (tool instanceof BytecodeParser) { + this.parser = (BytecodeParser) tool; + } else { + this.parser = null; + } + this.code = code; + this.locals = allocateArray(code.getMaxLocals()); + this.stack = allocateArray(Math.max(1, code.getMaxStackSize())); + this.lockedObjects = allocateArray(0); + + assert graph != null; + + this.monitorIds = EMPTY_MONITOR_ARRAY; + this.graph = graph; + this.canVerifyKind = true; + } + + public void disableKindVerification() { + canVerifyKind = false; + } + + public void initializeFromArgumentsArray(ValueNode[] arguments) { + + int javaIndex = 0; + int index = 0; + if (!getMethod().isStatic()) { + // set the receiver + locals[javaIndex] = arguments[index]; + javaIndex = 1; + index = 1; + constantReceiver = locals[0].asJavaConstant(); + } + Signature sig = getMethod().getSignature(); + int max = sig.getParameterCount(false); + for (int i = 0; i < max; i++) { + JavaKind kind = sig.getParameterKind(i); + locals[javaIndex] = arguments[index]; + javaIndex++; + if (kind.needsTwoSlots()) { + locals[javaIndex] = TWO_SLOT_MARKER; + javaIndex++; + } + index++; + } + } + + public void initializeForMethodStart(Assumptions assumptions, boolean eagerResolve, Plugins plugins) { + + int javaIndex = 0; + int index = 0; + ResolvedJavaMethod method = getMethod(); + ResolvedJavaType originalType = method.getDeclaringClass(); + if (!method.isStatic()) { + // add the receiver + FloatingNode receiver = null; + StampPair receiverStamp = null; + if (plugins != null) { + receiverStamp = plugins.getOverridingStamp(tool, originalType, true); + } + if (receiverStamp == null) { + receiverStamp = StampFactory.forDeclaredType(assumptions, originalType, true); + } + + if (plugins != null) { + for (ParameterPlugin plugin : plugins.getParameterPlugins()) { + receiver = plugin.interceptParameter(tool, index, receiverStamp); + if (receiver != null) { + break; + } + } + } + if (receiver == null) { + receiver = new ParameterNode(javaIndex, receiverStamp); + } + + locals[javaIndex] = graph.addOrUnique(receiver); + javaIndex = 1; + index = 1; + } + Signature sig = method.getSignature(); + int max = sig.getParameterCount(false); + ResolvedJavaType accessingClass = originalType; + for (int i = 0; i < max; i++) { + JavaType type = sig.getParameterType(i, accessingClass); + if (eagerResolve) { + type = type.resolve(accessingClass); + } + JavaKind kind = type.getJavaKind(); + StampPair stamp = null; + if (plugins != null) { + stamp = plugins.getOverridingStamp(tool, type, false); + } + if (stamp == null) { + stamp = StampFactory.forDeclaredType(assumptions, type, false); + } + + FloatingNode param = null; + if (plugins != null) { + for (ParameterPlugin plugin : plugins.getParameterPlugins()) { + param = plugin.interceptParameter(tool, index, stamp); + if (param != null) { + break; + } + } + } + if (param == null) { + param = new ParameterNode(index, stamp); + } + + locals[javaIndex] = graph.addOrUnique(param); + javaIndex++; + if (kind.needsTwoSlots()) { + locals[javaIndex] = TWO_SLOT_MARKER; + javaIndex++; + } + index++; + } + } + + private FrameStateBuilder(FrameStateBuilder other) { + this.parser = other.parser; + this.tool = other.tool; + this.code = other.code; + this.stackSize = other.stackSize; + this.locals = other.locals.clone(); + this.stack = other.stack.clone(); + this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone(); + this.rethrowException = other.rethrowException; + this.canVerifyKind = other.canVerifyKind; + + assert locals.length == code.getMaxLocals(); + assert stack.length == Math.max(1, code.getMaxStackSize()); + + assert other.graph != null; + graph = other.graph; + monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone(); + + assert locals.length == code.getMaxLocals(); + assert stack.length == Math.max(1, code.getMaxStackSize()); + assert lockedObjects.length == monitorIds.length; + } + + private static ValueNode[] allocateArray(int length) { + return length == 0 ? EMPTY_ARRAY : new ValueNode[length]; + } + + public ResolvedJavaMethod getMethod() { + return code.getMethod(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[locals: ["); + for (int i = 0; i < locals.length; i++) { + sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i] == TWO_SLOT_MARKER ? "#" : locals[i].toString(Verbosity.Id)); + } + sb.append("] stack: ["); + for (int i = 0; i < stackSize; i++) { + sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i] == TWO_SLOT_MARKER ? "#" : stack[i].toString(Verbosity.Id)); + } + sb.append("] locks: ["); + for (int i = 0; i < lockedObjects.length; i++) { + sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id)); + } + sb.append("]"); + if (rethrowException) { + sb.append(" rethrowException"); + } + sb.append("]"); + return sb.toString(); + } + + public FrameState create(int bci, StateSplit forStateSplit) { + if (parser != null && parser.parsingIntrinsic()) { + return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit); + } + + // Skip intrinsic frames + return create(bci, parser != null ? parser.getNonIntrinsicAncestor() : null, false, null, null); + } + + /** + * @param pushedValues if non-null, values to {@link #push(JavaKind, ValueNode)} to the stack + * before creating the {@link FrameState} + */ + public FrameState create(int bci, BytecodeParser parent, boolean duringCall, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) { + if (outerFrameState == null && parent != null) { + assert !parent.parsingIntrinsic() : "must already have the next non-intrinsic ancestor"; + outerFrameState = parent.getFrameStateBuilder().create(parent.bci(), parent.getNonIntrinsicAncestor(), true, null, null); + } + if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { + FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, false, JavaKind.Void, new JavaKind[]{JavaKind.Object}, new ValueNode[]{stack[0]}); + return newFrameState; + } + if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { + throw shouldNotReachHere(); + } + + if (pushedValues != null) { + assert pushedSlotKinds.length == pushedValues.length; + int stackSizeToRestore = stackSize; + for (int i = 0; i < pushedValues.length; i++) { + push(pushedSlotKinds[i], pushedValues[i]); + } + FrameState res = graph.add(new FrameState(outerFrameState, code, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall)); + stackSize = stackSizeToRestore; + return res; + } else { + if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { + assert outerFrameState == null; + clearLocals(); + } + return graph.add(new FrameState(outerFrameState, code, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall)); + } + } + + public NodeSourcePosition createBytecodePosition(int bci) { + BytecodeParser parent = parser.getParent(); + if (HideSubstitutionStates.getValue()) { + if (parser.parsingIntrinsic()) { + // Attribute to the method being replaced + return new NodeSourcePosition(constantReceiver, parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1); + } + // Skip intrinsic frames + parent = parser.getNonIntrinsicAncestor(); + } + return create(null, constantReceiver, bci, parent); + } + + private NodeSourcePosition create(NodeSourcePosition o, JavaConstant receiver, int bci, BytecodeParser parent) { + NodeSourcePosition outer = o; + if (outer == null && parent != null) { + outer = parent.getFrameStateBuilder().createBytecodePosition(parent.bci()); + } + if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { + return FrameState.toSourcePosition(outerFrameState); + } + if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { + throw shouldNotReachHere(); + } + return new NodeSourcePosition(receiver, outer, code.getMethod(), bci); + } + + public FrameStateBuilder copy() { + return new FrameStateBuilder(this); + } + + public boolean isCompatibleWith(FrameStateBuilder other) { + assert code.equals(other.code) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; + assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds"; + + if (stackSize() != other.stackSize()) { + return false; + } + for (int i = 0; i < stackSize(); i++) { + ValueNode x = stack[i]; + ValueNode y = other.stack[i]; + assert x != null && y != null; + if (x != y && (x == TWO_SLOT_MARKER || x.isDeleted() || y == TWO_SLOT_MARKER || y.isDeleted() || x.getStackKind() != y.getStackKind())) { + return false; + } + } + if (lockedObjects.length != other.lockedObjects.length) { + return false; + } + for (int i = 0; i < lockedObjects.length; i++) { + if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) { + throw new PermanentBailoutException("unbalanced monitors"); + } + } + return true; + } + + public void merge(AbstractMergeNode block, FrameStateBuilder other) { + assert isCompatibleWith(other); + + for (int i = 0; i < localsSize(); i++) { + locals[i] = merge(locals[i], other.locals[i], block); + } + for (int i = 0; i < stackSize(); i++) { + stack[i] = merge(stack[i], other.stack[i], block); + } + for (int i = 0; i < lockedObjects.length; i++) { + lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block); + assert monitorIds[i] == other.monitorIds[i]; + } + + if (sideEffects == null) { + sideEffects = other.sideEffects; + } else { + if (other.sideEffects != null) { + sideEffects.addAll(other.sideEffects); + } + } + } + + private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { + if (currentValue == null || currentValue.isDeleted()) { + return null; + } else if (block.isPhiAtMerge(currentValue)) { + if (otherValue == null || otherValue == TWO_SLOT_MARKER || otherValue.isDeleted() || currentValue.getStackKind() != otherValue.getStackKind()) { + // This phi must be dead anyway, add input of correct stack kind to keep the graph + // invariants. + ((PhiNode) currentValue).addInput(ConstantNode.defaultForKind(currentValue.getStackKind(), graph)); + } else { + ((PhiNode) currentValue).addInput(otherValue); + } + return currentValue; + } else if (currentValue != otherValue) { + if (currentValue == TWO_SLOT_MARKER || otherValue == TWO_SLOT_MARKER) { + return null; + } else if (otherValue == null || otherValue.isDeleted() || currentValue.getStackKind() != otherValue.getStackKind()) { + return null; + } + assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue); + return createValuePhi(currentValue, otherValue, block); + } else { + return currentValue; + } + } + + private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { + ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block)); + for (int i = 0; i < block.phiPredecessorCount(); i++) { + phi.addInput(currentValue); + } + phi.addInput(otherValue); + assert phi.valueCount() == block.phiPredecessorCount() + 1; + return phi; + } + + public void inferPhiStamps(AbstractMergeNode block) { + for (int i = 0; i < localsSize(); i++) { + inferPhiStamp(block, locals[i]); + } + for (int i = 0; i < stackSize(); i++) { + inferPhiStamp(block, stack[i]); + } + for (int i = 0; i < lockedObjects.length; i++) { + inferPhiStamp(block, lockedObjects[i]); + } + } + + private static void inferPhiStamp(AbstractMergeNode block, ValueNode node) { + if (block.isPhiAtMerge(node)) { + node.inferStamp(); + } + } + + public void insertLoopPhis(LocalLiveness liveness, int loopId, LoopBeginNode loopBegin, boolean forcePhis, boolean stampFromValueForForcedPhis) { + for (int i = 0; i < localsSize(); i++) { + boolean changedInLoop = liveness.localIsChangedInLoop(loopId, i); + if (forcePhis || changedInLoop) { + locals[i] = createLoopPhi(loopBegin, locals[i], stampFromValueForForcedPhis && !changedInLoop); + } + } + for (int i = 0; i < stackSize(); i++) { + stack[i] = createLoopPhi(loopBegin, stack[i], false); + } + for (int i = 0; i < lockedObjects.length; i++) { + lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i], false); + } + } + + public void insertLoopProxies(LoopExitNode loopExit, FrameStateBuilder loopEntryState) { + for (int i = 0; i < localsSize(); i++) { + ValueNode value = locals[i]; + if (value != null && value != TWO_SLOT_MARKER && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + locals[i] = ProxyNode.forValue(value, loopExit, graph); + } + } + for (int i = 0; i < stackSize(); i++) { + ValueNode value = stack[i]; + if (value != null && value != TWO_SLOT_MARKER && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + stack[i] = ProxyNode.forValue(value, loopExit, graph); + } + } + for (int i = 0; i < lockedObjects.length; i++) { + ValueNode value = lockedObjects[i]; + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph); + } + } + } + + public void insertProxies(Function proxyFunction) { + for (int i = 0; i < localsSize(); i++) { + ValueNode value = locals[i]; + if (value != null && value != TWO_SLOT_MARKER) { + Debug.log(" inserting proxy for %s", value); + locals[i] = proxyFunction.apply(value); + } + } + for (int i = 0; i < stackSize(); i++) { + ValueNode value = stack[i]; + if (value != null && value != TWO_SLOT_MARKER) { + Debug.log(" inserting proxy for %s", value); + stack[i] = proxyFunction.apply(value); + } + } + for (int i = 0; i < lockedObjects.length; i++) { + ValueNode value = lockedObjects[i]; + if (value != null) { + Debug.log(" inserting proxy for %s", value); + lockedObjects[i] = proxyFunction.apply(value); + } + } + } + + private ValueNode createLoopPhi(AbstractMergeNode block, ValueNode value, boolean stampFromValue) { + if (value == null || value == TWO_SLOT_MARKER) { + return value; + } + assert !block.isPhiAtMerge(value) : "phi function for this block already created"; + + ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(stampFromValue ? value.stamp() : value.stamp().unrestricted(), block)); + phi.addInput(value); + return phi; + } + + /** + * Adds a locked monitor to this frame state. + * + * @param object the object whose monitor will be locked. + */ + public void pushLock(ValueNode object, MonitorIdNode monitorId) { + assert object.isAlive() && object.getStackKind() == JavaKind.Object : "unexpected value: " + object; + lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1); + monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1); + lockedObjects[lockedObjects.length - 1] = object; + monitorIds[monitorIds.length - 1] = monitorId; + assert lockedObjects.length == monitorIds.length; + } + + /** + * Removes a locked monitor from this frame state. + * + * @return the object whose monitor was removed from the locks list. + */ + public ValueNode popLock() { + try { + return lockedObjects[lockedObjects.length - 1]; + } finally { + lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1); + monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1); + assert lockedObjects.length == monitorIds.length; + } + } + + public MonitorIdNode peekMonitorId() { + return monitorIds[monitorIds.length - 1]; + } + + /** + * @return the current lock depth + */ + public int lockDepth(boolean includeParents) { + int depth = lockedObjects.length; + assert depth == monitorIds.length; + if (includeParents && parser.getParent() != null) { + depth += parser.getParent().frameState.lockDepth(true); + } + return depth; + } + + public boolean contains(ValueNode value) { + for (int i = 0; i < localsSize(); i++) { + if (locals[i] == value) { + return true; + } + } + for (int i = 0; i < stackSize(); i++) { + if (stack[i] == value) { + return true; + } + } + assert lockedObjects.length == monitorIds.length; + for (int i = 0; i < lockedObjects.length; i++) { + if (lockedObjects[i] == value || monitorIds[i] == value) { + return true; + } + } + return false; + } + + public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) { + /* + * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to + * remove it for normal compilations, but not for OSR compilations - otherwise dead object + * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with + * Kind.Illegal, because the conflicting branch might not have been parsed. + */ + if (!parser.graphBuilderConfig.clearNonLiveLocals()) { + return; + } + if (liveIn) { + for (int i = 0; i < locals.length; i++) { + if (!liveness.localIsLiveIn(block, i)) { + assert locals[i] != TWO_SLOT_MARKER || locals[i - 1] == null : "Clearing of second slot must have cleared the first slot too"; + locals[i] = null; + } + } + } else { + for (int i = 0; i < locals.length; i++) { + if (!liveness.localIsLiveOut(block, i)) { + assert locals[i] != TWO_SLOT_MARKER || locals[i - 1] == null : "Clearing of second slot must have cleared the first slot too"; + locals[i] = null; + } + } + } + } + + /** + * Clears all local variables. + */ + public void clearLocals() { + for (int i = 0; i < locals.length; i++) { + locals[i] = null; + } + } + + /** + * @see BytecodeFrame#rethrowException + */ + public boolean rethrowException() { + return rethrowException; + } + + /** + * @see BytecodeFrame#rethrowException + */ + public void setRethrowException(boolean b) { + rethrowException = b; + } + + /** + * Returns the size of the local variables. + * + * @return the size of the local variables + */ + public int localsSize() { + return locals.length; + } + + /** + * Gets the current size (height) of the stack. + */ + public int stackSize() { + return stackSize; + } + + private boolean verifyKind(JavaKind slotKind, ValueNode x) { + assert x != null; + assert x != TWO_SLOT_MARKER; + assert slotKind.getSlotCount() > 0; + + if (canVerifyKind) { + assert x.getStackKind() == slotKind.getStackKind(); + } + return true; + } + + /** + * Loads the local variable at the specified index, checking that the returned value is non-null + * and that two-stack values are properly handled. + * + * @param i the index of the local variable to load + * @param slotKind the kind of the local variable from the point of view of the bytecodes + * @return the instruction that produced the specified local + */ + public ValueNode loadLocal(int i, JavaKind slotKind) { + ValueNode x = locals[i]; + assert verifyKind(slotKind, x); + assert slotKind.needsTwoSlots() ? locals[i + 1] == TWO_SLOT_MARKER : (i == locals.length - 1 || locals[i + 1] != TWO_SLOT_MARKER); + return x; + } + + /** + * Stores a given local variable at the specified index. If the value occupies two slots, then + * the next local variable index is also overwritten. + * + * @param i the index at which to store + * @param slotKind the kind of the local variable from the point of view of the bytecodes + * @param x the instruction which produces the value for the local + */ + public void storeLocal(int i, JavaKind slotKind, ValueNode x) { + assert verifyKind(slotKind, x); + + if (locals[i] == TWO_SLOT_MARKER) { + /* Writing the second slot of a two-slot value invalidates the first slot. */ + locals[i - 1] = null; + } + locals[i] = x; + if (slotKind.needsTwoSlots()) { + /* Writing a two-slot value: mark the second slot. */ + locals[i + 1] = TWO_SLOT_MARKER; + } else if (i < locals.length - 1 && locals[i + 1] == TWO_SLOT_MARKER) { + /* + * Writing a one-slot value to an index previously occupied by a two-slot value: clear + * the old marker of the second slot. + */ + locals[i + 1] = null; + } + } + + /** + * Pushes an instruction onto the stack with the expected type. + * + * @param slotKind the kind of the stack element from the point of view of the bytecodes + * @param x the instruction to push onto the stack + */ + public void push(JavaKind slotKind, ValueNode x) { + assert verifyKind(slotKind, x); + + xpush(x); + if (slotKind.needsTwoSlots()) { + xpush(TWO_SLOT_MARKER); + } + } + + public void pushReturn(JavaKind slotKind, ValueNode x) { + if (slotKind != JavaKind.Void) { + push(slotKind, x); + } + } + + /** + * Pops an instruction off the stack with the expected type. + * + * @param slotKind the kind of the stack element from the point of view of the bytecodes + * @return the instruction on the top of the stack + */ + public ValueNode pop(JavaKind slotKind) { + if (slotKind.needsTwoSlots()) { + ValueNode s = xpop(); + assert s == TWO_SLOT_MARKER; + } + ValueNode x = xpop(); + assert verifyKind(slotKind, x); + return x; + } + + private void xpush(ValueNode x) { + assert x != null; + stack[stackSize++] = x; + } + + private ValueNode xpop() { + ValueNode result = stack[--stackSize]; + assert result != null; + return result; + } + + private ValueNode xpeek() { + ValueNode result = stack[stackSize - 1]; + assert result != null; + return result; + } + + /** + * Pop the specified number of slots off of this stack and return them as an array of + * instructions. + * + * @return an array containing the arguments off of the stack + */ + public ValueNode[] popArguments(int argSize) { + ValueNode[] result = allocateArray(argSize); + for (int i = argSize - 1; i >= 0; i--) { + ValueNode x = xpop(); + if (x == TWO_SLOT_MARKER) { + /* Ignore second slot of two-slot value. */ + x = xpop(); + } + assert x != null && x != TWO_SLOT_MARKER; + result[i] = x; + } + return result; + } + + /** + * Clears all values on this stack. + */ + public void clearStack() { + stackSize = 0; + } + + /** + * Performs a raw stack operation as defined in the Java bytecode specification. + * + * @param opcode The Java bytecode. + */ + public void stackOp(int opcode) { + switch (opcode) { + case POP: { + ValueNode w1 = xpop(); + assert w1 != TWO_SLOT_MARKER; + break; + } + case POP2: { + xpop(); + ValueNode w2 = xpop(); + assert w2 != TWO_SLOT_MARKER; + break; + } + case DUP: { + ValueNode w1 = xpeek(); + assert w1 != TWO_SLOT_MARKER; + xpush(w1); + break; + } + case DUP_X1: { + ValueNode w1 = xpop(); + ValueNode w2 = xpop(); + assert w1 != TWO_SLOT_MARKER; + xpush(w1); + xpush(w2); + xpush(w1); + break; + } + case DUP_X2: { + ValueNode w1 = xpop(); + ValueNode w2 = xpop(); + ValueNode w3 = xpop(); + assert w1 != TWO_SLOT_MARKER; + xpush(w1); + xpush(w3); + xpush(w2); + xpush(w1); + break; + } + case DUP2: { + ValueNode w1 = xpop(); + ValueNode w2 = xpop(); + xpush(w2); + xpush(w1); + xpush(w2); + xpush(w1); + break; + } + case DUP2_X1: { + ValueNode w1 = xpop(); + ValueNode w2 = xpop(); + ValueNode w3 = xpop(); + xpush(w2); + xpush(w1); + xpush(w3); + xpush(w2); + xpush(w1); + break; + } + case DUP2_X2: { + ValueNode w1 = xpop(); + ValueNode w2 = xpop(); + ValueNode w3 = xpop(); + ValueNode w4 = xpop(); + xpush(w2); + xpush(w1); + xpush(w4); + xpush(w3); + xpush(w2); + xpush(w1); + break; + } + case SWAP: { + ValueNode w1 = xpop(); + ValueNode w2 = xpop(); + assert w1 != TWO_SLOT_MARKER; + assert w2 != TWO_SLOT_MARKER; + xpush(w1); + xpush(w2); + break; + } + default: + throw shouldNotReachHere(); + } + } + + @Override + public int hashCode() { + int result = hashCode(locals, locals.length); + result *= 13; + result += hashCode(stack, this.stackSize); + return result; + } + + private static int hashCode(Object[] a, int length) { + int result = 1; + for (int i = 0; i < length; ++i) { + Object element = a[i]; + result = 31 * result + (element == null ? 0 : System.identityHashCode(element)); + } + return result; + } + + private static boolean equals(ValueNode[] a, ValueNode[] b, int length) { + for (int i = 0; i < length; ++i) { + if (a[i] != b[i]) { + return false; + } + } + return true; + } + + @Override + public boolean equals(Object otherObject) { + if (otherObject instanceof FrameStateBuilder) { + FrameStateBuilder other = (FrameStateBuilder) otherObject; + if (!other.code.equals(code)) { + return false; + } + if (other.stackSize != stackSize) { + return false; + } + if (other.parser != parser) { + return false; + } + if (other.tool != tool) { + return false; + } + if (other.rethrowException != rethrowException) { + return false; + } + if (other.graph != graph) { + return false; + } + if (other.locals.length != locals.length) { + return false; + } + return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) && + equals(other.monitorIds, monitorIds, monitorIds.length); + } + return false; + } + + @Override + public boolean isAfterSideEffect() { + return sideEffects != null; + } + + @Override + public Iterable sideEffects() { + return sideEffects; + } + + @Override + public void addSideEffect(StateSplit sideEffect) { + assert sideEffect != null; + assert sideEffect.hasSideEffect(); + if (sideEffects == null) { + sideEffects = new ArrayList<>(4); + } + sideEffects.add(sideEffect); + } + + public void traceState() { + Debug.log("| state [nr locals = %d, stack depth = %d, method = %s]", localsSize(), stackSize(), getMethod()); + for (int i = 0; i < localsSize(); ++i) { + ValueNode value = locals[i]; + Debug.log("| local[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value); + } + for (int i = 0; i < stackSize(); ++i) { + ValueNode value = stack[i]; + Debug.log("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/GraphBuilderPhase.java 2016-12-07 13:50:57.973335410 -0800 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2009, 2016, 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.java; + +import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; +import org.graalvm.compiler.nodes.spi.StampProvider; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.tiers.HighTierContext; + +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Parses the bytecodes of a method and builds the IR graph. + */ +public class GraphBuilderPhase extends BasePhase { + + private final GraphBuilderConfiguration graphBuilderConfig; + + public GraphBuilderPhase(GraphBuilderConfiguration config) { + this.graphBuilderConfig = config; + } + + @Override + public boolean checkContract() { + return false; + } + + @Override + protected void run(StructuredGraph graph, HighTierContext context) { + new Instance(context.getMetaAccess(), context.getStampProvider(), context.getConstantReflection(), context.getConstantFieldProvider(), graphBuilderConfig, context.getOptimisticOptimizations(), + null).run(graph); + } + + public GraphBuilderConfiguration getGraphBuilderConfig() { + return graphBuilderConfig; + } + + // Fully qualified name is a workaround for JDK-8056066 + public static class Instance extends org.graalvm.compiler.phases.Phase { + + protected final MetaAccessProvider metaAccess; + protected final StampProvider stampProvider; + protected final ConstantReflectionProvider constantReflection; + protected final ConstantFieldProvider constantFieldProvider; + protected final GraphBuilderConfiguration graphBuilderConfig; + protected final OptimisticOptimizations optimisticOpts; + private final IntrinsicContext initialIntrinsicContext; + + public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, + GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { + this.graphBuilderConfig = graphBuilderConfig; + this.optimisticOpts = optimisticOpts; + this.metaAccess = metaAccess; + this.stampProvider = stampProvider; + this.constantReflection = constantReflection; + this.constantFieldProvider = constantFieldProvider; + this.initialIntrinsicContext = initialIntrinsicContext; + } + + @Override + public boolean checkContract() { + return false; + } + + @Override + protected void run(StructuredGraph graph) { + createBytecodeParser(graph, null, graph.method(), graph.getEntryBCI(), initialIntrinsicContext).buildRootMethod(); + } + + /* Hook for subclasses of Instance to provide a subclass of BytecodeParser. */ + protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { + return new BytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrNotSupportedBailout.java 2016-12-07 13:50:58.239347102 -0800 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011, 2011, 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.java; + +import org.graalvm.compiler.common.PermanentBailoutException; + +public class JsrNotSupportedBailout extends PermanentBailoutException { + + private static final long serialVersionUID = -7476925652727154272L; + + public JsrNotSupportedBailout(String reason) { + super(reason); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrScope.java 2016-12-07 13:50:58.506358838 -0800 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011, 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.java; + +public class JsrScope { + + public static final JsrScope EMPTY_SCOPE = new JsrScope(); + + private final long scope; + + private JsrScope(long scope) { + this.scope = scope; + } + + public JsrScope() { + this.scope = 0; + } + + public int nextReturnAddress() { + return (int) (scope & 0xffff); + } + + public JsrScope push(int jsrReturnBci) { + if ((scope & 0xffff000000000000L) != 0) { + throw new JsrNotSupportedBailout("only four jsr nesting levels are supported"); + } + return new JsrScope((scope << 16) | jsrReturnBci); + } + + public boolean isEmpty() { + return scope == 0; + } + + public boolean isPrefixOf(JsrScope other) { + return (scope & other.scope) == scope; + } + + public JsrScope pop() { + return new JsrScope(scope >>> 16); + } + + @Override + public int hashCode() { + return (int) (scope ^ (scope >>> 32)); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + return obj != null && getClass() == obj.getClass() && scope == ((JsrScope) obj).scope; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + long tmp = scope; + sb.append(" ["); + while (tmp != 0) { + sb.append(", ").append(tmp & 0xffff); + tmp = tmp >>> 16; + } + sb.append(']'); + return sb.toString(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LargeLocalLiveness.java 2016-12-07 13:50:58.771370486 -0800 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2009, 2015, 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.java; + +import java.util.BitSet; + +import org.graalvm.compiler.java.BciBlockMapping.BciBlock; + +public final class LargeLocalLiveness extends LocalLiveness { + private BitSet[] localsLiveIn; + private BitSet[] localsLiveOut; + private BitSet[] localsLiveGen; + private BitSet[] localsLiveKill; + private BitSet[] localsChangedInLoop; + + public LargeLocalLiveness(BciBlock[] blocks, int maxLocals, int loopCount) { + super(blocks); + int blocksSize = blocks.length; + localsLiveIn = new BitSet[blocksSize]; + localsLiveOut = new BitSet[blocksSize]; + localsLiveGen = new BitSet[blocksSize]; + localsLiveKill = new BitSet[blocksSize]; + for (int i = 0; i < blocksSize; i++) { + localsLiveIn[i] = new BitSet(maxLocals); + localsLiveOut[i] = new BitSet(maxLocals); + localsLiveGen[i] = new BitSet(maxLocals); + localsLiveKill[i] = new BitSet(maxLocals); + } + localsChangedInLoop = new BitSet[loopCount]; + for (int i = 0; i < loopCount; ++i) { + localsChangedInLoop[i] = new BitSet(maxLocals); + } + } + + @Override + protected String debugLiveIn(int blockID) { + return localsLiveIn[blockID].toString(); + } + + @Override + protected String debugLiveOut(int blockID) { + return localsLiveOut[blockID].toString(); + } + + @Override + protected String debugLiveGen(int blockID) { + return localsLiveGen[blockID].toString(); + } + + @Override + protected String debugLiveKill(int blockID) { + return localsLiveKill[blockID].toString(); + } + + @Override + protected int liveOutCardinality(int blockID) { + return localsLiveOut[blockID].cardinality(); + } + + @Override + protected void propagateLiveness(int blockID, int successorID) { + localsLiveOut[blockID].or(localsLiveIn[successorID]); + } + + @Override + protected void updateLiveness(int blockID) { + BitSet liveIn = localsLiveIn[blockID]; + liveIn.clear(); + liveIn.or(localsLiveOut[blockID]); + liveIn.andNot(localsLiveKill[blockID]); + liveIn.or(localsLiveGen[blockID]); + } + + @Override + protected void loadOne(int blockID, int local) { + if (!localsLiveKill[blockID].get(local)) { + localsLiveGen[blockID].set(local); + } + } + + @Override + protected void storeOne(int blockID, int local) { + if (!localsLiveGen[blockID].get(local)) { + localsLiveKill[blockID].set(local); + } + + BciBlock block = blocks[blockID]; + long tmp = block.loops; + int pos = 0; + while (tmp != 0) { + if ((tmp & 1L) == 1L) { + this.localsChangedInLoop[pos].set(local); + } + tmp >>>= 1; + ++pos; + } + } + + @Override + public boolean localIsLiveIn(BciBlock block, int local) { + return block.getId() >= Integer.MAX_VALUE ? true : localsLiveIn[block.getId()].get(local); + } + + @Override + public boolean localIsLiveOut(BciBlock block, int local) { + return block.getId() >= Integer.MAX_VALUE ? true : localsLiveOut[block.getId()].get(local); + } + + @Override + public boolean localIsChangedInLoop(int loopId, int local) { + return localsChangedInLoop[loopId].get(local); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LocalLiveness.java 2016-12-07 13:50:59.035382091 -0800 @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2009, 2015, 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.java; + +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.IINC; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.RET; + +import org.graalvm.compiler.bytecode.BytecodeStream; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.java.BciBlockMapping.BciBlock; + +/** + * Encapsulates the liveness calculation, so that subclasses for locals ≤ 64 and locals > 64 + * can be implemented. + */ +public abstract class LocalLiveness { + protected final BciBlock[] blocks; + + public static LocalLiveness compute(BytecodeStream stream, BciBlock[] blocks, int maxLocals, int loopCount) { + LocalLiveness liveness = maxLocals <= 64 ? new SmallLocalLiveness(blocks, maxLocals, loopCount) : new LargeLocalLiveness(blocks, maxLocals, loopCount); + liveness.computeLiveness(stream); + return liveness; + } + + protected LocalLiveness(BciBlock[] blocks) { + this.blocks = blocks; + } + + void computeLiveness(BytecodeStream stream) { + for (BciBlock block : blocks) { + computeLocalLiveness(stream, block); + } + + boolean changed; + int iteration = 0; + do { + assert traceIteration(iteration); + changed = false; + for (int i = blocks.length - 1; i >= 0; i--) { + BciBlock block = blocks[i]; + int blockID = block.getId(); + assert traceStart(block, blockID); + + boolean blockChanged = (iteration == 0); + if (block.getSuccessorCount() > 0) { + int oldCardinality = liveOutCardinality(blockID); + for (BciBlock sux : block.getSuccessors()) { + assert traceSuccessor(sux); + propagateLiveness(blockID, sux.getId()); + } + blockChanged |= (oldCardinality != liveOutCardinality(blockID)); + } + + if (blockChanged) { + updateLiveness(blockID); + assert traceEnd(block, blockID); + } + changed |= blockChanged; + } + iteration++; + } while (changed); + } + + private static boolean traceIteration(int iteration) { + Debug.log("Iteration %d", iteration); + return true; + } + + private boolean traceEnd(BciBlock block, int blockID) { + if (Debug.isLogEnabled()) { + Debug.logv(" end B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID), + debugLiveKill(blockID)); + } + return true; + } + + private boolean traceSuccessor(BciBlock sux) { + if (Debug.isLogEnabled()) { + Debug.log(" Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId())); + } + return true; + } + + private boolean traceStart(BciBlock block, int blockID) { + if (Debug.isLogEnabled()) { + Debug.logv(" start B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID), + debugLiveKill(blockID)); + } + return true; + } + + /** + * Returns whether the local is live at the beginning of the given block. + */ + public abstract boolean localIsLiveIn(BciBlock block, int local); + + /** + * Returns whether the local is set in the given loop. + */ + public abstract boolean localIsChangedInLoop(int loopId, int local); + + /** + * Returns whether the local is live at the end of the given block. + */ + public abstract boolean localIsLiveOut(BciBlock block, int local); + + /** + * Returns a string representation of the liveIn values of the given block. + */ + protected abstract String debugLiveIn(int blockID); + + /** + * Returns a string representation of the liveOut values of the given block. + */ + protected abstract String debugLiveOut(int blockID); + + /** + * Returns a string representation of the liveGen values of the given block. + */ + protected abstract String debugLiveGen(int blockID); + + /** + * Returns a string representation of the liveKill values of the given block. + */ + protected abstract String debugLiveKill(int blockID); + + /** + * Returns the number of live locals at the end of the given block. + */ + protected abstract int liveOutCardinality(int blockID); + + /** + * Adds all locals the are in the liveIn of the successor to the liveOut of the block. + */ + protected abstract void propagateLiveness(int blockID, int successorID); + + /** + * Calculates a new liveIn for the given block from liveOut, liveKill and liveGen. + */ + protected abstract void updateLiveness(int blockID); + + /** + * Adds the local to liveGen if it wasn't already killed in this block. + */ + protected abstract void loadOne(int blockID, int local); + + /** + * Add this local to liveKill if it wasn't already generated in this block. + */ + protected abstract void storeOne(int blockID, int local); + + private void computeLocalLiveness(BytecodeStream stream, BciBlock block) { + if (block.startBci < 0 || block.endBci < 0) { + return; + } + int blockID = block.getId(); + int localIndex; + stream.setBCI(block.startBci); + while (stream.currentBCI() <= block.endBci) { + switch (stream.currentBC()) { + case LLOAD: + case DLOAD: + loadTwo(blockID, stream.readLocalIndex()); + break; + case LLOAD_0: + case DLOAD_0: + loadTwo(blockID, 0); + break; + case LLOAD_1: + case DLOAD_1: + loadTwo(blockID, 1); + break; + case LLOAD_2: + case DLOAD_2: + loadTwo(blockID, 2); + break; + case LLOAD_3: + case DLOAD_3: + loadTwo(blockID, 3); + break; + case IINC: + localIndex = stream.readLocalIndex(); + loadOne(blockID, localIndex); + storeOne(blockID, localIndex); + break; + case ILOAD: + case FLOAD: + case ALOAD: + case RET: + loadOne(blockID, stream.readLocalIndex()); + break; + case ILOAD_0: + case FLOAD_0: + case ALOAD_0: + loadOne(blockID, 0); + break; + case ILOAD_1: + case FLOAD_1: + case ALOAD_1: + loadOne(blockID, 1); + break; + case ILOAD_2: + case FLOAD_2: + case ALOAD_2: + loadOne(blockID, 2); + break; + case ILOAD_3: + case FLOAD_3: + case ALOAD_3: + loadOne(blockID, 3); + break; + + case LSTORE: + case DSTORE: + storeTwo(blockID, stream.readLocalIndex()); + break; + case LSTORE_0: + case DSTORE_0: + storeTwo(blockID, 0); + break; + case LSTORE_1: + case DSTORE_1: + storeTwo(blockID, 1); + break; + case LSTORE_2: + case DSTORE_2: + storeTwo(blockID, 2); + break; + case LSTORE_3: + case DSTORE_3: + storeTwo(blockID, 3); + break; + case ISTORE: + case FSTORE: + case ASTORE: + storeOne(blockID, stream.readLocalIndex()); + break; + case ISTORE_0: + case FSTORE_0: + case ASTORE_0: + storeOne(blockID, 0); + break; + case ISTORE_1: + case FSTORE_1: + case ASTORE_1: + storeOne(blockID, 1); + break; + case ISTORE_2: + case FSTORE_2: + case ASTORE_2: + storeOne(blockID, 2); + break; + case ISTORE_3: + case FSTORE_3: + case ASTORE_3: + storeOne(blockID, 3); + break; + } + stream.next(); + } + } + + private void loadTwo(int blockID, int local) { + loadOne(blockID, local); + loadOne(blockID, local + 1); + } + + private void storeTwo(int blockID, int local) { + storeOne(blockID, local); + storeOne(blockID, local + 1); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/SmallLocalLiveness.java 2016-12-07 13:50:59.301393782 -0800 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2009, 2015, 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.java; + +import org.graalvm.compiler.java.BciBlockMapping.BciBlock; + +public final class SmallLocalLiveness extends LocalLiveness { + /* + * local n is represented by the bit accessible as (1 << n) + */ + + private final long[] localsLiveIn; + private final long[] localsLiveOut; + private final long[] localsLiveGen; + private final long[] localsLiveKill; + private final long[] localsChangedInLoop; + private final int maxLocals; + + public SmallLocalLiveness(BciBlock[] blocks, int maxLocals, int loopCount) { + super(blocks); + this.maxLocals = maxLocals; + int blockSize = blocks.length; + localsLiveIn = new long[blockSize]; + localsLiveOut = new long[blockSize]; + localsLiveGen = new long[blockSize]; + localsLiveKill = new long[blockSize]; + localsChangedInLoop = new long[loopCount]; + } + + private String debugString(long value) { + StringBuilder str = new StringBuilder("{"); + long current = value; + for (int i = 0; i < maxLocals; i++) { + if ((current & 1L) == 1L) { + if (str.length() > 1) { + str.append(", "); + } + str.append(i); + } + current >>= 1; + } + return str.append('}').toString(); + } + + @Override + protected String debugLiveIn(int blockID) { + return debugString(localsLiveIn[blockID]); + } + + @Override + protected String debugLiveOut(int blockID) { + return debugString(localsLiveOut[blockID]); + } + + @Override + protected String debugLiveGen(int blockID) { + return debugString(localsLiveGen[blockID]); + } + + @Override + protected String debugLiveKill(int blockID) { + return debugString(localsLiveKill[blockID]); + } + + @Override + protected int liveOutCardinality(int blockID) { + return Long.bitCount(localsLiveOut[blockID]); + } + + @Override + protected void propagateLiveness(int blockID, int successorID) { + localsLiveOut[blockID] |= localsLiveIn[successorID]; + } + + @Override + protected void updateLiveness(int blockID) { + localsLiveIn[blockID] = (localsLiveOut[blockID] & ~localsLiveKill[blockID]) | localsLiveGen[blockID]; + } + + @Override + protected void loadOne(int blockID, int local) { + long bit = 1L << local; + if ((localsLiveKill[blockID] & bit) == 0L) { + localsLiveGen[blockID] |= bit; + } + } + + @Override + protected void storeOne(int blockID, int local) { + long bit = 1L << local; + if ((localsLiveGen[blockID] & bit) == 0L) { + localsLiveKill[blockID] |= bit; + } + + BciBlock block = blocks[blockID]; + long tmp = block.loops; + int pos = 0; + while (tmp != 0) { + if ((tmp & 1L) == 1L) { + this.localsChangedInLoop[pos] |= bit; + } + tmp >>>= 1; + ++pos; + } + } + + @Override + public boolean localIsLiveIn(BciBlock block, int local) { + int blockID = block.getId(); + return blockID >= Integer.MAX_VALUE ? false : (localsLiveIn[blockID] & (1L << local)) != 0L; + } + + @Override + public boolean localIsLiveOut(BciBlock block, int local) { + int blockID = block.getId(); + return blockID >= Integer.MAX_VALUE ? false : (localsLiveOut[blockID] & (1L << local)) != 0L; + } + + @Override + public boolean localIsChangedInLoop(int loopId, int local) { + return (localsChangedInLoop[loopId] & (1L << local)) != 0L; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/SuitesProviderBase.java 2016-12-07 13:50:59.566405430 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012, 2015, 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.java; + +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.options.DerivedOptionValue; +import org.graalvm.compiler.options.DerivedOptionValue.OptionSupplier; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.Suites; +import org.graalvm.compiler.phases.tiers.SuitesCreator; + +public abstract class SuitesProviderBase implements SuitesCreator { + + protected final DerivedOptionValue defaultSuites; + protected PhaseSuite defaultGraphBuilderSuite; + protected final DerivedOptionValue defaultLIRSuites; + + private class SuitesSupplier implements OptionSupplier { + + private static final long serialVersionUID = 2677805381215454728L; + + @Override + public Suites get() { + Suites suites = createSuites(); + suites.setImmutable(); + return suites; + } + + } + + private class LIRSuitesSupplier implements OptionSupplier { + + private static final long serialVersionUID = 312070237227476252L; + + @Override + public LIRSuites get() { + LIRSuites lirSuites = createLIRSuites(); + lirSuites.setImmutable(); + return lirSuites; + } + + } + + public SuitesProviderBase() { + this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier()); + this.defaultLIRSuites = new DerivedOptionValue<>(new LIRSuitesSupplier()); + } + + @Override + public final Suites getDefaultSuites() { + return defaultSuites.getValue(); + } + + @Override + public PhaseSuite getDefaultGraphBuilderSuite() { + return defaultGraphBuilderSuite; + } + + @Override + public final LIRSuites getDefaultLIRSuites() { + return defaultLIRSuites.getValue(); + } + + @Override + public abstract LIRSuites createLIRSuites(); + + @Override + public abstract Suites createSuites(); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/overview.html 2016-12-07 13:50:59.830417034 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.jtt project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/JTTTest.java 2016-12-07 13:51:00.095428682 -0800 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2012, 2015, 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.jtt; + +import static java.lang.reflect.Modifier.isStatic; + +import java.util.Collections; +import java.util.Set; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Assert; + +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +/** + * Base class for the JTT tests. + *

    + * These tests are executed twice: once with arguments passed to the execution and once with the + * arguments bound to the test's parameters during compilation. The latter is a good test of + * canonicalization. + */ +public class JTTTest extends GraalCompilerTest { + + public static final class DummyTestClass { + } + + protected static final Set EMPTY = Collections. emptySet(); + /** + * The arguments which, if non-null, will replace the Locals in the test method's graph. + */ + Object[] argsToBind; + + public JTTTest() { + Assert.assertNotNull(getCodeCache()); + } + + @Override + protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) { + StructuredGraph graph = super.parseEager(m, allowAssumptions, compilationId); + if (argsToBind != null) { + Object receiver = isStatic(m.getModifiers()) ? null : this; + Object[] args = argsWithReceiver(receiver, argsToBind); + JavaType[] parameterTypes = m.toParameterTypes(); + assert parameterTypes.length == args.length; + for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { + JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[param.index()].getJavaKind(), args[param.index()]); + ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph); + param.replaceAtUsages(replacement); + } + } + return graph; + } + + @Override + protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) { + return super.getCode(method, graph, argsToBind != null); + } + + Double delta; + + @Override + protected void assertDeepEquals(Object expected, Object actual) { + if (delta != null) { + Assert.assertEquals(((Number) expected).doubleValue(), ((Number) actual).doubleValue(), delta); + } else { + super.assertDeepEquals(expected, actual); + } + } + + @SuppressWarnings("hiding") + protected void runTestWithDelta(double delta, String name, Object... args) { + this.delta = Double.valueOf(delta); + runTest(name, args); + } + + protected void runTest(String name, Object... args) { + runTest(EMPTY, name, args); + } + + protected void runTest(Set shouldNotDeopt, String name, Object... args) { + runTest(shouldNotDeopt, true, false, name, args); + } + + protected void runTest(Set shouldNotDeopt, boolean bind, boolean noProfile, String name, Object... args) { + ResolvedJavaMethod method = getResolvedJavaMethod(name); + Object receiver = method.isStatic() ? null : this; + + Result expect = executeExpected(method, receiver, args); + + if (noProfile) { + method.reprofile(); + } + + testAgainstExpected(method, expect, shouldNotDeopt, receiver, args); + if (args.length > 0 && bind) { + if (noProfile) { + method.reprofile(); + } + + this.argsToBind = args; + testAgainstExpected(method, expect, shouldNotDeopt, receiver, args); + this.argsToBind = null; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/ConstantPhiTest.java 2016-12-07 13:51:00.360440330 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, 2015, 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.jtt.backend; + +import static org.graalvm.compiler.api.directives.GraalDirectives.LIKELY_PROBABILITY; +import static org.graalvm.compiler.api.directives.GraalDirectives.injectBranchProbability; + +import java.lang.reflect.Method; + +import org.junit.Test; + +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.jtt.JTTTest; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; + +public class ConstantPhiTest extends JTTTest { + + public static int test(int i, int x) throws Throwable { + int r; + if (injectBranchProbability(LIKELY_PROBABILITY, i < 0)) { + r = 42; + } else { + r = x; + } + destroyCallerSavedValues(); + return r; + } + + protected static void destroyCallerSavedValues() throws Throwable { + Class c = ConstantPhiTest.class; + Method m = c.getMethod("destroyCallerSavedValues0"); + m.invoke(null); + } + + public static void destroyCallerSavedValues0() { + } + + @Test + @SuppressWarnings("try") + public void run0() { + try (OverrideScope os = OptionValue.override(GraalOptions.MaximumInliningSize, -1)) { + runTest("test", 0, 0xDEADDEAD); + } + } + + @Test + @SuppressWarnings("try") + public void run1() { + try (OverrideScope os = OptionValue.override(GraalOptions.MaximumInliningSize, -1)) { + runTest("test", -1, 0xDEADDEAD); + } + } + + @Test + @SuppressWarnings("try") + public void run2() { + try (OverrideScope os = OptionValue.override(GraalOptions.MaximumInliningSize, -1)) { + runTest("test", 1, 0xDEADDEAD); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/EmptyMethodTest.java 2016-12-07 13:51:00.624451934 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, 2016, 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.jtt.backend; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.jtt.JTTTest; + +public class EmptyMethodTest extends JTTTest { + + public static void test() { + GraalDirectives.spillRegisters(); + } + + @Test + public void run() { + runTest("test"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/LargeConstantSectionTest.java 2016-12-07 13:51:00.888463539 -0800 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2015, 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.jtt.backend; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; +import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.IFNE; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.LADD; +import static jdk.internal.org.objectweb.asm.Opcodes.LCMP; +import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0; +import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; + +import org.junit.BeforeClass; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.jtt.JTTTest; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.test.ExportingClassLoader; + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; + +public class LargeConstantSectionTest extends JTTTest { + private static final String NAME = "LargeConstantSection"; + private static final long LARGE_CONSTANT = 0xF0F0F0F0F0L; + private static LargeConstantClassLoader LOADER; + + @BeforeClass + public static void before() { + LOADER = new LargeConstantClassLoader(LargeConstantSectionTest.class.getClassLoader()); + } + + public abstract static class LargeConstantAbstract { + public abstract long run(long i); + } + + public static long test(LargeConstantAbstract a, long i) throws Exception { + return a.run(GraalDirectives.opaque(i)); + } + + public static class LargeConstantClassLoader extends ExportingClassLoader { + public LargeConstantClassLoader(ClassLoader parent) { + super(parent); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals(NAME)) { + String graalDirectivesClassName = GraalDirectives.class.getName().replace('.', '/'); + int numberIfBlocks = 1100; // Each if block contains three constants + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + String abstractClassName = Type.getInternalName(LargeConstantAbstract.class); + cw.visit(52, ACC_PUBLIC + ACC_SUPER, NAME, null, abstractClassName, null); + + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, abstractClassName, "", "()V", false); + mv.visitInsn(RETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitMaxs(1, 1); + mv.visitEnd(); + + mv = cw.visitMethod(ACC_PUBLIC, "run", "(J)J", null, null); + mv.visitCode(); + Label nextIf = new Label(); + for (int i = 0; i < numberIfBlocks; i++) { + mv.visitLabel(nextIf); + mv.visitFrame(Opcodes.F_NEW, 2, new Object[]{abstractClassName, Opcodes.LONG}, 0, new Object[]{}); + mv.visitVarInsn(LLOAD, 1); + mv.visitLdcInsn(new Long(LARGE_CONSTANT + i)); + mv.visitInsn(LCMP); + nextIf = new Label(); + mv.visitJumpInsn(IFNE, nextIf); + mv.visitLdcInsn(new Long(LARGE_CONSTANT + i + numberIfBlocks)); + mv.visitMethodInsn(INVOKESTATIC, graalDirectivesClassName, "opaque", "(J)J", false); + mv.visitLdcInsn(new Long(LARGE_CONSTANT + i + numberIfBlocks * 2)); + mv.visitMethodInsn(INVOKESTATIC, graalDirectivesClassName, "opaque", "(J)J", false); + mv.visitInsn(LADD); + mv.visitInsn(LRETURN); + } + mv.visitLabel(nextIf); + mv.visitFrame(Opcodes.F_NEW, 2, new Object[]{abstractClassName, Opcodes.LONG}, 0, new Object[]{}); + mv.visitInsn(LCONST_0); + mv.visitInsn(LRETURN); + Label l9 = new Label(); + mv.visitLabel(l9); + mv.visitMaxs(4, 6); + mv.visitEnd(); + + cw.visitEnd(); + + byte[] bytes = cw.toByteArray(); + return defineClass(name, bytes, 0, bytes.length); + } else { + return super.findClass(name); + } + } + } + + @Test + @SuppressWarnings("try") + public void run0() throws Exception { + try (OverrideScope os = OptionValue.override(GraalOptions.InlineEverything, true)) { + runTest("test", LOADER.findClass(NAME).newInstance(), 0L); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aaload.java 2016-12-07 13:51:01.153475186 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_aaload extends JTTTest { + + static Object[] array = {null, null, ""}; + + public static Object test(int arg) { + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aaload_1.java 2016-12-07 13:51:01.418486834 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_aaload_1 extends JTTTest { + + static Object[][] array = {{null}, {null}, {""}}; + + public static Object test(int arg) { + return array[arg][0]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aastore.java 2016-12-07 13:51:01.684498526 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_aastore extends JTTTest { + + static Object[] param = {new Object(), null, "h"}; + static Object[] array1 = {null, null, null}; + static String[] array2 = {null, null, null}; + + public static int test(boolean a, int indx) { + Object[] array = a ? array1 : array2; + Object val; + val = param[indx]; + array[indx] = val; + return indx; + } + + @Test + public void run0() throws Throwable { + runTest("test", true, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", true, 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", true, 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", false, 1); + } + + @Test + public void run4() throws Throwable { + runTest("test", false, 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_0.java 2016-12-07 13:51:01.948510130 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_aload_0 extends JTTTest { + + public static Object test(Object arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", "x"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_1.java 2016-12-07 13:51:02.214521822 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_aload_1 extends JTTTest { + + @SuppressWarnings("unused") + public static Object test(int i, Object arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, null); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, "x"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_2.java 2016-12-07 13:51:02.479533470 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_aload_2 extends JTTTest { + + @SuppressWarnings("unused") + public static Object test(int i, int j, Object arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 1, null); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1, "x"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_3.java 2016-12-07 13:51:02.745545162 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_aload_3 extends JTTTest { + + @SuppressWarnings("unused") + public static Object test(int i, int j, int k, Object arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 1, 1, "x"); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1, 1, null); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_anewarray.java 2016-12-07 13:51:03.009556766 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_anewarray extends JTTTest { + + @SuppressWarnings("unused") + public static int test(int a) { + final BC_anewarray[] v = new BC_anewarray[3]; + if (v != null) { + return a; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_areturn.java 2016-12-07 13:51:03.281568722 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_areturn extends JTTTest { + + public static Object test(Object a) { + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", ""); + } + + @Test + public void run2() throws Throwable { + runTest("test", "this"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_arraylength.java 2016-12-07 13:51:03.546580370 -0800 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_arraylength extends JTTTest { + + static byte[] array0 = {1, 2}; + static char[] array1 = {'a', 'b', 'c', 'd'}; + static short[] array2 = {1, 2, 3, 4, 5, 6}; + static int[] array3 = {1, 2, 3}; + static long[] array4 = {1L, 2L, 3L, 4L}; + static float[] array5 = {0.1f, 0.2f}; + static double[] array6 = {0.1, 0.2, 0.3, 0.4}; + static Object[] array7 = new Object[5]; + static boolean[] array8 = {false, true, false}; + + public static int testByte(byte[] arg) { + return arg.length; + } + + public static int testChar(char[] arg) { + return arg.length; + } + + public static int testShort(short[] arg) { + return arg.length; + } + + public static int testInt(int[] arg) { + return arg.length; + } + + public static int testLong(long[] arg) { + return arg.length; + } + + public static int testFloat(float[] arg) { + return arg.length; + } + + public static int testDouble(double[] arg) { + return arg.length; + } + + public static int testObject(Object[] arg) { + return arg.length; + } + + public static int testBoolean(boolean[] arg) { + return arg.length; + } + + @Test + public void run0() throws Throwable { + runTest("testByte", array0); + } + + @Test + public void run1() throws Throwable { + runTest("testChar", array1); + } + + @Test + public void run2() throws Throwable { + runTest("testShort", array2); + } + + @Test + public void run3() throws Throwable { + runTest("testInt", array3); + } + + @Test + public void run4() throws Throwable { + runTest("testLong", array4); + } + + @Test + public void run5() throws Throwable { + runTest("testFloat", array5); + } + + @Test + public void run6() throws Throwable { + runTest("testDouble", array6); + } + + @Test + public void run7() throws Throwable { + runTest("testObject", new Object[]{array7}); + } + + @Test + public void run8() throws Throwable { + runTest("testBoolean", array8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_athrow.java 2016-12-07 13:51:03.812592062 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_athrow extends JTTTest { + + static Throwable throwable = new Throwable(); + + public static int test(int arg) throws Throwable { + if (arg == 2) { + throw throwable; + } + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_baload.java 2016-12-07 13:51:04.078603754 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_baload extends JTTTest { + + static boolean[] array = {true, false, true, false}; + + public static boolean test(int arg) { + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_bastore.java 2016-12-07 13:51:04.343615402 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_bastore extends JTTTest { + + static boolean[] array = {false, false, false, false}; + + public static boolean test(int arg, boolean val) { + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, true); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, false); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, true); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, false); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_caload.java 2016-12-07 13:51:04.614627313 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_caload extends JTTTest { + + static char[] array = {'\000', 'a', ' ', 10000}; + + public static char test(int arg) { + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_castore.java 2016-12-07 13:51:04.879638961 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_castore extends JTTTest { + + static char[] array = {0, 0, 0, 0}; + + public static char test(int arg, char val) { + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, ((char) 97)); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, ((char) 65)); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, ((char) 42)); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, ((char) 120)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast01.java 2016-12-07 13:51:05.144650609 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_checkcast01 extends JTTTest { + + private static class TestClass { + } + + static Object object2 = new Object(); + static Object object3 = ""; + static Object object4 = new TestClass(); + + public static int test(int arg) { + Object obj; + if (arg == 2) { + obj = object2; + } else if (arg == 3) { + obj = object3; + } else if (arg == 4) { + obj = object4; + } else { + obj = null; + } + final TestClass bc = (TestClass) obj; + if (bc != null) { + return arg; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast02.java 2016-12-07 13:51:05.412662389 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_checkcast02 extends JTTTest { + + private static class TestClass { + } + + static Object[] o1 = {new Object()}; + static String[] o2 = {""}; + static TestClass[] o3 = {new TestClass()}; + + public static int test(int arg) { + Object obj = null; + if (arg == 0) { + obj = o1; + } + if (arg == 1) { + obj = o2; + } + if (arg == 2) { + obj = o3; + } + Object[] r = (Object[]) obj; + return r == null ? -1 : -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast03.java 2016-12-07 13:51:05.678674081 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/** + * Tests the checkcast works, when casting an array of interface. + */ +public class BC_checkcast03 extends JTTTest { + + public interface IObject { + + } + + private static class BaseClass { + + } + + private static class TestClass extends BaseClass implements IObject { + } + + static TestClass[] a1 = {new TestClass()}; + + public static BaseClass[] getBaseClassArray() { + return a1; + } + + public static IObject[] test() { + return (IObject[]) getBaseClassArray(); + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2f.java 2016-12-07 13:51:05.942685685 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_d2f extends JTTTest { + + public static float test(double d) { + return (float) d; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1.06d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2i01.java 2016-12-07 13:51:06.207697333 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_d2i01 extends JTTTest { + + public static int test(double d) { + return (int) d; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1.06d); + } + + @Test + public void run3() throws Throwable { + runTest("test", -156.82743d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2i02.java 2016-12-07 13:51:06.473709025 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_d2i02 extends JTTTest { + + private static double[] inputs = {-1.3e44d, Double.NEGATIVE_INFINITY, Double.NaN, Double.POSITIVE_INFINITY, 1.3e44d}; + + public static int test(int i) { + return (int) inputs[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l01.java 2016-12-07 13:51:06.740720761 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_d2l01 extends JTTTest { + + public static long test(double d) { + return (long) d; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1.06d); + } + + @Test + public void run3() throws Throwable { + runTest("test", -156.82743d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l02.java 2016-12-07 13:51:07.005732408 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_d2l02 extends JTTTest { + + private static double[] inputs = {-1.3e44d, Double.NEGATIVE_INFINITY, Double.NaN, Double.POSITIVE_INFINITY, 1.3e44d}; + + public static long test(int i) { + return (long) inputs[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l03.java 2016-12-07 13:51:07.269744012 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_d2l03 extends JTTTest { + + public static long test(double divider) { + return (long) (((long) divider) * divider); + } + + @Test + public void run0() throws Throwable { + runTest("test", 34.5D); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dadd.java 2016-12-07 13:51:07.534755660 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dadd extends JTTTest { + + public static double test(double a, double b) { + return a + b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0d, 0.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d, 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 253.11d, 54.43d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_daload.java 2016-12-07 13:51:07.799767308 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_daload extends JTTTest { + + static double[] array = {0.0, -1.1, 4.32, 6.06}; + + public static double test(int arg) { + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dastore.java 2016-12-07 13:51:08.066779044 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dastore extends JTTTest { + + static double[] array = {0, 0, 0, 0}; + + public static double test(int arg, double val) { + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0.01d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, -1.4d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, 0.01d); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, -1.4d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp01.java 2016-12-07 13:51:08.333790780 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dcmp01 extends JTTTest { + + public static boolean test(double a, double b) { + return a < b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0d, -0.1d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 78.00d, 78.001d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp02.java 2016-12-07 13:51:08.598802428 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dcmp02 extends JTTTest { + + public static boolean test(double a) { + return (a / a) < 0.0; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0d); + } + + @Test + public void run3() throws Throwable { + runTest("test", -0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp03.java 2016-12-07 13:51:08.866814208 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dcmp03 extends JTTTest { + + public static boolean test(double a) { + return (a / a) > 0.0; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0d); + } + + @Test + public void run3() throws Throwable { + runTest("test", -0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp04.java 2016-12-07 13:51:09.131825856 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dcmp04 extends JTTTest { + + public static boolean test(double a) { + return (a / a) <= 0.0; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0d); + } + + @Test + public void run3() throws Throwable { + runTest("test", -0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp05.java 2016-12-07 13:51:09.396837503 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dcmp05 extends JTTTest { + + public static boolean test(double a) { + return (a / a) >= 0.0; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp06.java 2016-12-07 13:51:09.661849151 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dcmp06 extends JTTTest { + + public static boolean test(double a) { + return 0.0 < (a / a); + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp07.java 2016-12-07 13:51:09.925860755 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dcmp07 extends JTTTest { + + public static boolean test(double a) { + return 0.0 > (a / a); + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp08.java 2016-12-07 13:51:10.190872403 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dcmp08 extends JTTTest { + + public static boolean test(double a) { + return 0.0 <= (a / a); + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp09.java 2016-12-07 13:51:10.456884095 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dcmp09 extends JTTTest { + + public static boolean test(double a) { + return 0.0 >= (a / a); + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp10.java 2016-12-07 13:51:10.721895743 -0800 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dcmp10 extends JTTTest { + + public static boolean test(int x) { + double a = 0; + double b = 0; + switch (x) { + case 0: + a = Double.POSITIVE_INFINITY; + b = 1; + break; + case 1: + a = 1; + b = Double.POSITIVE_INFINITY; + break; + case 2: + a = Double.NEGATIVE_INFINITY; + b = 1; + break; + case 3: + a = 1; + b = Double.NEGATIVE_INFINITY; + break; + case 4: + a = Double.NEGATIVE_INFINITY; + b = Double.NEGATIVE_INFINITY; + break; + case 5: + a = Double.NEGATIVE_INFINITY; + b = Double.POSITIVE_INFINITY; + break; + case 6: + a = Double.NaN; + b = Double.POSITIVE_INFINITY; + break; + case 7: + a = 1; + b = Double.NaN; + break; + case 8: + a = 1; + b = -0.0d / 0.0d; + break; + } + return a <= b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ddiv.java 2016-12-07 13:51:10.986907391 -0800 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2007, 2016, 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.jtt.bytecode; + +import org.junit.Test; + +public class BC_ddiv extends BC_double_base { + + public static double test(double a, double b) { + return a / b; + } + + @Test + public void ddiv() { + runTest("test", x, y); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dmul.java 2016-12-07 13:51:11.249918951 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dmul extends JTTTest { + + public static double test(double a, double b) { + return a * b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 311.0D, 10D); + } + + @Test + public void run1() throws Throwable { + runTest("test", 11.2D, 2.0D); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dneg.java 2016-12-07 13:51:11.515930643 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2007, 2016, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dneg extends JTTTest { + + public static double test(double a, double b, int which) { + double result1 = -a; + double result2 = -b; + double result = 0.0; + if (which == 0) { + result = result1; + } else { + result = result2; + } + return result; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0d, 1.0d, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1.01d, -2.01d, 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 7263.8734d, 8263.8734d, 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0.0d, 1.0d, 1); + } + + @Test + public void run4() throws Throwable { + runTest("test", -1.01d, -2.01d, 1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 7263.8734d, 8263.8734d, 1); + } + + public static double test2(double a, double b) { + return -(a - b); + } + + @Test + public void run6() throws Throwable { + runTest("test2", -1.0d, -1.0d); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dneg2.java 2016-12-07 13:51:11.781942335 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dneg2 extends JTTTest { + + public static double test(double a) { + return 1 / (-a); + } + + @Test + public void run0() throws Throwable { + runTest("test", -0.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_double_base.java 2016-12-07 13:51:12.045953939 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016, 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.jtt.bytecode; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import org.graalvm.compiler.jtt.JTTTest; + +@RunWith(Parameterized.class) +public abstract class BC_double_base extends JTTTest { + + /** Some interesting values. */ + private static final double[] values = { + 0.0d, + -0.0d, + 1.0d, + -1.0d, + Double.POSITIVE_INFINITY, + Double.NEGATIVE_INFINITY, + Double.NaN, + 10.0d, + -10.0d, + 311.0d, + -311.0d, + }; + + @Parameters(name = "{0}, {1}") + public static Collection data() { + List d = new ArrayList<>(); + for (int i = 0; i < values.length; i++) { + double x = values[i]; + for (int j = 0; j < values.length; j++) { + double y = values[j]; + d.add(new Object[]{x, y}); + } + } + return d; + } + + @Parameter(value = 0) public double x; + @Parameter(value = 1) public double y; +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_drem.java 2016-12-07 13:51:12.311965631 -0800 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2007, 2016, 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.jtt.bytecode; + +import org.junit.Test; + +public class BC_drem extends BC_double_base { + + public static double test(double a, double b) { + return a % b; + } + + @Test + public void drem() { + runTest("test", x, y); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dreturn.java 2016-12-07 13:51:12.576977279 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dreturn extends JTTTest { + + public static double test(double a) { + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.1d); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1.4d); + } + + @Test + public void run3() throws Throwable { + runTest("test", 256.33d); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1000.001d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dsub.java 2016-12-07 13:51:12.841988926 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dsub extends JTTTest { + + public static double test(double a, double b) { + return a - b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0d, 0.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0d, 1.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 253.11d, 54.43d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dsub2.java 2016-12-07 13:51:13.106000531 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_dsub2 extends JTTTest { + + public static double test(double a) { + return 1.0 / (0.0 - a); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0d); + } + + public static double test2(double a) { + return a - a; + } + + @Test + public void run1() { + runTest("test2", 17.3); + } + + @Test + public void run2() { + runTest("test2", Double.NaN); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2d.java 2016-12-07 13:51:13.371012178 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_f2d extends JTTTest { + + public static double test(float d) { + return d; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2.00f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2i01.java 2016-12-07 13:51:13.637023870 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_f2i01 extends JTTTest { + + public static int test(float d) { + return (int) d; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1.06f); + } + + @Test + public void run3() throws Throwable { + runTest("test", -156.82743f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2i02.java 2016-12-07 13:51:13.902035518 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_f2i02 extends JTTTest { + + private static float[] inputs = {-1.3e22f, Float.NEGATIVE_INFINITY, Float.NaN, Float.POSITIVE_INFINITY, 1.3e22f}; + + public static int test(int i) { + return (int) inputs[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2l01.java 2016-12-07 13:51:14.168047210 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_f2l01 extends JTTTest { + + public static long test(float d) { + return (long) d; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1.06f); + } + + @Test + public void run3() throws Throwable { + runTest("test", -156.82743f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2l02.java 2016-12-07 13:51:14.433058858 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_f2l02 extends JTTTest { + + private static float[] inputs = {-1.3e22f, Float.NEGATIVE_INFINITY, Float.NaN, Float.POSITIVE_INFINITY, 1.3e22f}; + + public static long test(int i) { + return (long) inputs[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fadd.java 2016-12-07 13:51:14.698070506 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fadd extends JTTTest { + + public static float test(float a, float b) { + return a + b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0f, 0.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f, 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 253.11f, 54.43f); + } + + @Test + public void run3() throws Throwable { + runTest("test", Float.MAX_VALUE, Float.MIN_VALUE); + } + + @Test + public void run4() throws Throwable { + runTest("test", Float.MAX_VALUE / 2, Float.MAX_VALUE / 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_faload.java 2016-12-07 13:51:14.964082198 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_faload extends JTTTest { + + static float[] array = {0.0f, -1.1f, 4.32f, 6.06f}; + + public static float test(int arg) { + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fastore.java 2016-12-07 13:51:15.229093845 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fastore extends JTTTest { + + static float[] array = {0, 0, 0, 0}; + + public static float test(int arg, float val) { + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0.01f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, -1.4f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, 0.01f); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, -1.4f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp01.java 2016-12-07 13:51:15.493105449 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fcmp01 extends JTTTest { + + public static boolean test(float a, float b) { + return a < b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0f, -0.1f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 78.00f, 78.001f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp02.java 2016-12-07 13:51:15.758117097 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fcmp02 extends JTTTest { + + public static boolean test(float a) { + return (a / a) < 0.0f; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp03.java 2016-12-07 13:51:16.023128745 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fcmp03 extends JTTTest { + + public static boolean test(float a) { + return (a / a) > 0.0f; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp04.java 2016-12-07 13:51:16.286140305 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fcmp04 extends JTTTest { + + public static boolean test(float a) { + return (a / a) <= 0.0f; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp05.java 2016-12-07 13:51:16.551151953 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fcmp05 extends JTTTest { + + public static boolean test(float a) { + return (a / a) >= 0.0f; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp06.java 2016-12-07 13:51:16.817163645 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fcmp06 extends JTTTest { + + public static boolean test(float a) { + return 0.0f < (a / a); + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp07.java 2016-12-07 13:51:17.080175205 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fcmp07 extends JTTTest { + + public static boolean test(float a) { + return 0.0f > (a / a); + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp08.java 2016-12-07 13:51:17.345186853 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fcmp08 extends JTTTest { + + public static boolean test(float a) { + return 0.0f <= (a / a); + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp09.java 2016-12-07 13:51:17.610198501 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fcmp09 extends JTTTest { + + public static boolean test(float a) { + return 0.0f >= (a / a); + } + + @Test + public void run0() throws Throwable { + runTest("test", -1.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp10.java 2016-12-07 13:51:17.874210104 -0800 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fcmp10 extends JTTTest { + + public static boolean test(int x) { + float a = 0; + float b = 0; + switch (x) { + case 0: + a = Float.POSITIVE_INFINITY; + b = 1; + break; + case 1: + a = 1; + b = Float.POSITIVE_INFINITY; + break; + case 2: + a = Float.NEGATIVE_INFINITY; + b = 1; + break; + case 3: + a = 1; + b = Float.NEGATIVE_INFINITY; + break; + case 4: + a = Float.NEGATIVE_INFINITY; + b = Float.NEGATIVE_INFINITY; + break; + case 5: + a = Float.NEGATIVE_INFINITY; + b = Float.POSITIVE_INFINITY; + break; + case 6: + a = Float.NaN; + b = Float.POSITIVE_INFINITY; + break; + case 7: + a = 1; + b = Float.NaN; + break; + case 8: + a = 1; + b = -0.0f / 0.0f; + break; + } + return a <= b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fdiv.java 2016-12-07 13:51:18.139221752 -0800 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2007, 2016, 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.jtt.bytecode; + +import org.junit.Test; + +public class BC_fdiv extends BC_float_base { + + public static float test(float a, float b) { + return a / b; + } + + @Test + public void fdiv() { + runTest("test", x, y); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fload.java 2016-12-07 13:51:18.403233356 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fload extends JTTTest { + + public static float test(float arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1f); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1.01f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fload_2.java 2016-12-07 13:51:18.668245004 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fload_2 extends JTTTest { + + @SuppressWarnings("unused") + public static float test(float i, float arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0f, -1f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0f, -1.01f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_float_base.java 2016-12-07 13:51:18.933256652 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016, 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.jtt.bytecode; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import org.graalvm.compiler.jtt.JTTTest; + +@RunWith(Parameterized.class) +public abstract class BC_float_base extends JTTTest { + + /** Some interesting values. */ + private static final float[] values = { + 0.0f, + -0.0f, + 1.0f, + -1.0f, + Float.POSITIVE_INFINITY, + Float.NEGATIVE_INFINITY, + Float.NaN, + 10.0f, + -10.0f, + 311.0f, + -311.0f, + }; + + @Parameters(name = "{0}, {1}") + public static Collection data() { + List d = new ArrayList<>(); + for (int i = 0; i < values.length; i++) { + float x = values[i]; + for (int j = 0; j < values.length; j++) { + float y = values[j]; + d.add(new Object[]{x, y}); + } + } + return d; + } + + @Parameter(value = 0) public float x; + @Parameter(value = 1) public float y; + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fmul.java 2016-12-07 13:51:19.197268256 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fmul extends JTTTest { + + public static float test(float a, float b) { + return a * b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 311.0f, 10f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 11.2f, 2.0f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fneg.java 2016-12-07 13:51:19.462279904 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2016, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fneg extends JTTTest { + + public static float test(float a) { + return -a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1.01f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 7263.8734f); + } + + public static float test2(float a, float b) { + return -(a - b); + } + + @Test + public void run3() throws Throwable { + runTest("test2", -1.0f, -1.0f); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_frem.java 2016-12-07 13:51:19.727291551 -0800 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2007, 2016, 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.jtt.bytecode; + +import org.junit.Test; + +public class BC_frem extends BC_float_base { + + public static float test(float a, float b) { + return a % b; + } + + @Test + public void frem() { + runTest("test", x, y); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_freturn.java 2016-12-07 13:51:19.991303155 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_freturn extends JTTTest { + + public static float test(float a) { + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.1f); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1.4f); + } + + @Test + public void run3() throws Throwable { + runTest("test", 256.33f); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1000.001f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fsub.java 2016-12-07 13:51:20.257314847 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_fsub extends JTTTest { + + public static float test(float a, float b) { + return a - b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0f, 0.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0f, 1.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 253.11f, 54.43f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield.java 2016-12-07 13:51:20.523326539 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_getfield extends JTTTest { + + private static BC_getfield object = new BC_getfield(); + + private int field = 13; + + public static int test() { + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_b.java 2016-12-07 13:51:20.787338143 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_getfield_b extends JTTTest { + + static class FieldHolder { + FieldHolder(byte field) { + this.field = field; + } + + private byte field; + } + + public static byte test(FieldHolder object) { + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", new FieldHolder((byte) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", new FieldHolder(Byte.MAX_VALUE)); + } + + @Test + public void run2() throws Throwable { + runTest("test", new FieldHolder(Byte.MIN_VALUE)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_c.java 2016-12-07 13:51:21.052349791 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_getfield_c extends JTTTest { + + static class FieldHolder { + FieldHolder(char field) { + this.field = field; + } + + private char field; + } + + public static char test(FieldHolder object) { + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", new FieldHolder('A')); + } + + @Test + public void run1() throws Throwable { + runTest("test", new FieldHolder(Character.MAX_VALUE)); + } + + @Test + public void run2() throws Throwable { + runTest("test", new FieldHolder(Character.MIN_VALUE)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_d.java 2016-12-07 13:51:21.317361439 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_getfield_d extends JTTTest { + + static class FieldHolder { + FieldHolder(double field) { + this.field = field; + } + + private double field; + } + + public static double test(FieldHolder object) { + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", new FieldHolder(0.0D)); + } + + @Test + public void run1() throws Throwable { + runTest("test", new FieldHolder(Double.MAX_VALUE)); + } + + @Test + public void run2() throws Throwable { + runTest("test", new FieldHolder(Double.MIN_VALUE)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_f.java 2016-12-07 13:51:21.583373130 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_getfield_f extends JTTTest { + + static class FieldHolder { + FieldHolder(float field) { + this.field = field; + } + + private float field; + } + + public static float test(FieldHolder object) { + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", new FieldHolder(0.0F)); + } + + @Test + public void run1() throws Throwable { + runTest("test", new FieldHolder(Float.MAX_VALUE)); + } + + @Test + public void run2() throws Throwable { + runTest("test", new FieldHolder(Float.MIN_VALUE)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_i.java 2016-12-07 13:51:21.847384734 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_getfield_i extends JTTTest { + + static class FieldHolder { + FieldHolder(int field) { + this.field = field; + } + + private int field; + } + + public static int test(FieldHolder object) { + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", new FieldHolder(0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", new FieldHolder(Integer.MAX_VALUE)); + } + + @Test + public void run2() throws Throwable { + runTest("test", new FieldHolder(Integer.MIN_VALUE)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_l.java 2016-12-07 13:51:22.112396382 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_getfield_l extends JTTTest { + + static class FieldHolder { + FieldHolder(long field) { + this.field = field; + } + + private long field; + } + + public static long test(FieldHolder object) { + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", new FieldHolder(0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", new FieldHolder(Long.MAX_VALUE)); + } + + @Test + public void run2() throws Throwable { + runTest("test", new FieldHolder(Long.MIN_VALUE)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_o.java 2016-12-07 13:51:22.377408030 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_getfield_o extends JTTTest { + + static class FieldHolder { + FieldHolder(Object field) { + this.field = field; + } + + private Object field; + } + + public static Object test(FieldHolder object) { + return object.field == null ? null : object.field.getClass(); + } + + @Test + public void run0() throws Throwable { + runTest("test", new FieldHolder(null)); + } + + @Test + public void run1() throws Throwable { + runTest("test", new FieldHolder("field")); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_s.java 2016-12-07 13:51:22.641419634 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_getfield_s extends JTTTest { + + static class FieldHolder { + FieldHolder(short field) { + this.field = field; + } + + private short field; + } + + public static short test(FieldHolder object) { + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", new FieldHolder((short) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", new FieldHolder(Short.MAX_VALUE)); + } + + @Test + public void run2() throws Throwable { + runTest("test", new FieldHolder(Short.MIN_VALUE)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_z.java 2016-12-07 13:51:22.905431238 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_getfield_z extends JTTTest { + + static class FieldHolder { + FieldHolder(boolean field) { + this.field = field; + } + + private boolean field; + } + + public static boolean test(FieldHolder object) { + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", new FieldHolder(true)); + } + + @Test + public void run1() throws Throwable { + runTest("test", new FieldHolder(false)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_b.java 2016-12-07 13:51:23.170442885 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_getstatic_b extends JTTTest { + + private static byte field = 11; + + public static byte test() { + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_c.java 2016-12-07 13:51:23.434454489 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_getstatic_c extends JTTTest { + + private static char field = 11; + + public static char test() { + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_d.java 2016-12-07 13:51:23.699466137 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_getstatic_d extends JTTTest { + + private static double field = 11; + + public static double test() { + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_f.java 2016-12-07 13:51:23.962477697 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_getstatic_f extends JTTTest { + + private static float field = 11; + + public static float test() { + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_i.java 2016-12-07 13:51:24.227489345 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_getstatic_i extends JTTTest { + + private static int field = 11; + + public static int test() { + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_l.java 2016-12-07 13:51:24.493501037 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_getstatic_l extends JTTTest { + + private static long field = 11; + + public static long test() { + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_s.java 2016-12-07 13:51:24.758512684 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_getstatic_s extends JTTTest { + + private static short field = 11; + + public static short test() { + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_z.java 2016-12-07 13:51:25.023524333 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_getstatic_z extends JTTTest { + + private static boolean field = true; + + public static boolean test() { + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2b.java 2016-12-07 13:51:25.287535936 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_i2b extends JTTTest { + + public static byte test(int a) { + return (byte) a; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 255); + } + + @Test + public void run3() throws Throwable { + runTest("test", 128); + } + + public static int testInt(int a) { + return (byte) a; + } + + @Test + public void runI0() throws Throwable { + runTest("testInt", -1); + } + + @Test + public void runI1() throws Throwable { + runTest("testInt", 2); + } + + @Test + public void runI2() throws Throwable { + runTest("testInt", 255); + } + + @Test + public void runI3() throws Throwable { + runTest("testInt", 128); + } + + public static long testLong(int a) { + return (byte) a; + } + + @Test + public void runL0() throws Throwable { + runTest("testLong", -1); + } + + @Test + public void runL1() throws Throwable { + runTest("testLong", 2); + } + + @Test + public void runL2() throws Throwable { + runTest("testLong", 255); + } + + @Test + public void runL3() throws Throwable { + runTest("testLong", 128); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2c.java 2016-12-07 13:51:25.552547584 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_i2c extends JTTTest { + + public static char test(int a) { + return (char) a; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 645); + } + + @Test + public void run2() throws Throwable { + runTest("test", 65535); + } + + public static int testInt(int a) { + return (char) a; + } + + @Test + public void runI0() throws Throwable { + runTest("testInt", -1); + } + + @Test + public void runI1() throws Throwable { + runTest("testInt", 645); + } + + @Test + public void runI2() throws Throwable { + runTest("testInt", 65535); + } + + public static long testLong(int a) { + return (char) a; + } + + @Test + public void runL0() throws Throwable { + runTest("testLong", -1); + } + + @Test + public void runL1() throws Throwable { + runTest("testLong", 645); + } + + @Test + public void runL2() throws Throwable { + runTest("testLong", 65535); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2d.java 2016-12-07 13:51:25.820559364 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_i2d extends JTTTest { + + public static double test(int a) { + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -34); + } + + @Test + public void run3() throws Throwable { + runTest("test", Integer.MIN_VALUE); + } + + @Test + public void run4() throws Throwable { + runTest("test", Integer.MAX_VALUE); + } + + @Test + public void run5() throws Throwable { + runTest("test", 34); + } + + @Test + public void run6() throws Throwable { + runTest("test", new Integer(Short.MAX_VALUE)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2f.java 2016-12-07 13:51:26.085571012 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_i2f extends JTTTest { + + public static float test(int a) { + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -34); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2l.java 2016-12-07 13:51:26.351582703 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_i2l extends JTTTest { + + public static long test(int a) { + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483647); + } + + @Test + public void run5() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run6() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2s.java 2016-12-07 13:51:26.617594395 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_i2s extends JTTTest { + + public static short test(int a) { + return (short) a; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 34); + } + + @Test + public void run2() throws Throwable { + runTest("test", 65535); + } + + @Test + public void run3() throws Throwable { + runTest("test", 32768); + } + + public static int testInt(int a) { + return (short) a; + } + + @Test + public void runI0() throws Throwable { + runTest("testInt", -1); + } + + @Test + public void runI1() throws Throwable { + runTest("testInt", 34); + } + + @Test + public void runI2() throws Throwable { + runTest("testInt", 65535); + } + + @Test + public void runI3() throws Throwable { + runTest("testInt", 32768); + } + + public static long testLong(int a) { + return (short) a; + } + + @Test + public void runL0() throws Throwable { + runTest("testLong", -1); + } + + @Test + public void runL1() throws Throwable { + runTest("testLong", 34); + } + + @Test + public void runL2() throws Throwable { + runTest("testLong", 65535); + } + + @Test + public void runL3() throws Throwable { + runTest("testLong", 32768); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd.java 2016-12-07 13:51:26.882606043 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iadd extends JTTTest { + + public static int test(int a, int b) { + return a + b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 33, 67); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1, -1); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648, 1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2147483647, 1); + } + + @Test + public void run6() throws Throwable { + runTest("test", -2147483647, -2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd2.java 2016-12-07 13:51:27.147617691 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iadd2 extends JTTTest { + + public static int test(byte a, byte b) { + return a + b; + } + + @Test + public void run0() throws Throwable { + runTest("test", ((byte) 1), ((byte) 2)); + } + + @Test + public void run1() throws Throwable { + runTest("test", ((byte) 0), ((byte) -1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", ((byte) 33), ((byte) 67)); + } + + @Test + public void run3() throws Throwable { + runTest("test", ((byte) 1), ((byte) -1)); + } + + @Test + public void run4() throws Throwable { + runTest("test", ((byte) -128), ((byte) 1)); + } + + @Test + public void run5() throws Throwable { + runTest("test", ((byte) 127), ((byte) 1)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd3.java 2016-12-07 13:51:27.414629426 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iadd3 extends JTTTest { + + public static int test(short a, short b) { + return a + b; + } + + @Test + public void run0() throws Throwable { + runTest("test", ((short) 1), ((short) 2)); + } + + @Test + public void run1() throws Throwable { + runTest("test", ((short) 0), ((short) -1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", ((short) 33), ((short) 67)); + } + + @Test + public void run3() throws Throwable { + runTest("test", ((short) 1), ((short) -1)); + } + + @Test + public void run4() throws Throwable { + runTest("test", ((short) -128), ((short) 1)); + } + + @Test + public void run5() throws Throwable { + runTest("test", ((short) 127), ((short) 1)); + } + + @Test + public void run6() throws Throwable { + runTest("test", ((short) -32768), ((short) 1)); + } + + @Test + public void run7() throws Throwable { + runTest("test", ((short) 32767), ((short) 1)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const0.java 2016-12-07 13:51:27.679641074 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iadd_const0 extends JTTTest { + + public static int test(int a, int b, boolean neg) { + int x = GraalDirectives.opaque(a); + if (!neg) { + return x + b; + } + return x - b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 42, 1, false); + } + + @Test + public void run1() throws Throwable { + runTest("test", 42, -1, false); + } + + @Test + public void run2() throws Throwable { + runTest("test", 42, 1, true); + } + + @Test + public void run3() throws Throwable { + runTest("test", 42, -1, true); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const1.java 2016-12-07 13:51:27.944652722 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iadd_const1 extends JTTTest { + + public static int test(byte a, byte b, boolean neg) { + byte x = GraalDirectives.opaque(a); + if (!neg) { + return x + b; + } + return x - b; + } + + @Test + public void run0() throws Throwable { + runTest("test", (byte) 42, (byte) 1, false); + } + + @Test + public void run1() throws Throwable { + runTest("test", (byte) 42, (byte) -1, false); + } + + @Test + public void run2() throws Throwable { + runTest("test", (byte) 42, (byte) 1, true); + } + + @Test + public void run3() throws Throwable { + runTest("test", (byte) 42, (byte) -1, true); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const2.java 2016-12-07 13:51:28.208664326 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iadd_const2 extends JTTTest { + + public static int test(short a, short b, boolean neg) { + short x = GraalDirectives.opaque(a); + if (!neg) { + return x + b; + } + return x - b; + } + + @Test + public void run0() throws Throwable { + runTest("test", (short) 42, (short) 1, false); + } + + @Test + public void run1() throws Throwable { + runTest("test", (short) 42, (short) -1, false); + } + + @Test + public void run2() throws Throwable { + runTest("test", (short) 42, (short) 1, true); + } + + @Test + public void run3() throws Throwable { + runTest("test", (short) 42, (short) -1, true); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const3.java 2016-12-07 13:51:28.472675930 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iadd_const3 extends JTTTest { + + public static long test(long a, long b, boolean neg) { + long x = GraalDirectives.opaque(a); + if (!neg) { + return x + b; + } + return x - b; + } + + @Test + public void run0() throws Throwable { + runTest("test", (long) 42, (long) 1, false); + } + + @Test + public void run1() throws Throwable { + runTest("test", (long) 42, (long) -1, false); + } + + @Test + public void run2() throws Throwable { + runTest("test", (long) 42, (long) 1, true); + } + + @Test + public void run3() throws Throwable { + runTest("test", (long) 42, (long) -1, true); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iaload.java 2016-12-07 13:51:28.736687534 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iaload extends JTTTest { + + static int[] array = {0, -1, 4, 1000000000}; + + public static int test(int arg) { + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iand.java 2016-12-07 13:51:29.000699137 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iand extends JTTTest { + + public static int test(int a, int b) { + return a & b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31, 63); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6, 4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648, 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iastore.java 2016-12-07 13:51:29.265710785 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iastore extends JTTTest { + + static int[] array = {0, 0, 0, 0}; + + public static int test(int arg, int val) { + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, 11); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, -14); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iconst.java 2016-12-07 13:51:29.529722389 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iconst extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return 0; + } + if (arg == 1) { + return 1; + } + if (arg == 2) { + return 2; + } + if (arg == 3) { + return 3; + } + if (arg == 4) { + return 4; + } + if (arg == 5) { + return 5; + } + return 375; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_idiv.java 2016-12-07 13:51:29.793733993 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_idiv extends JTTTest { + + public static int test(int a, int b) { + return a / b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 256, 4); + } + + @Test + public void run3() throws Throwable { + runTest("test", 135, 7); + } + + public static int testStrictlyPositive(int b) { + return 64 / ((b & 7) + 1); + } + + @Test + public void run4() throws Throwable { + runTest("testStrictlyPositive", 6); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_idiv2.java 2016-12-07 13:51:30.057745597 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_idiv2 extends JTTTest { + + public static int test(int a, int b) { + return a / b; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648, -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2147483648, 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq.java 2016-12-07 13:51:30.325757376 -0800 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifeq extends JTTTest { + + public static int test(int a) { + int n = 0; + if (a == 0) { + n += 1; + } else { + n -= 1; + } + if (a != 0) { + n -= 1; + } else { + n += 1; + } + return n; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run3() { + runTest("testb", 0xff); + } + + /** + * Tests if the if does work properly on byte stamp. + */ + public static int testb(int b) { + byte x = (byte) b; + int y = x & 0xff; + if (y == 0xff) { + // Just do anything else to force jump instead of conditional move + y = (int) (System.currentTimeMillis() >> 32); + } + return y; + } + + @Test + public void run4() { + runTest("tests", 0xffff); + } + + /** + * Tests if the if does work properly on short stamp. + */ + public static int tests(int b) { + short x = (short) b; + int y = x & 0xffff; + if (y == 0xffff) { + // Just do anything else to force jump instead of conditional move + y = (int) (System.currentTimeMillis() >> 32); + } + return y; + } + + @Test + public void run5() { + runTest("testc", 0xffff); + } + + /** + * Tests if the if does work properly on char stamp (boils down to short, just to cover all the + * java types). + */ + public static int testc(int b) { + char x = (char) b; + int y = x & 0xffff; + if (y == 0xffff) { + // Just do anything else to force jump instead of conditional move + y = (int) (System.currentTimeMillis() >> 32); + } + return y; + } + + // the same with conditional move + @Test + public void run6() { + runTest("testCondb", 0xff); + } + + /** + * Tests if the if does work properly on byte stamp. + */ + public static boolean testCondb(int b) { + byte x = (byte) b; + int y = x & 0xff; + return y == 0xff; + } + + @Test + public void run7() { + runTest("testConds", 0xffff); + } + + /** + * Tests if the if does work properly on short stamp. + */ + public static boolean testConds(int b) { + short x = (short) b; + int y = x & 0xffff; + return y == 0xffff; + } + + @Test + public void run8() { + runTest("testCondc", 0xffff); + } + + /** + * Tests if the if does work properly on char type. + */ + public static boolean testCondc(int b) { + char x = (char) b; + int y = x & 0xffff; + return y == 0xffff; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq_2.java 2016-12-07 13:51:30.592769112 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifeq_2 extends JTTTest { + + public static boolean test(int a) { + return a == 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq_3.java 2016-12-07 13:51:30.856780716 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifeq_3 extends JTTTest { + + public static boolean test(int a) { + return a != 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge.java 2016-12-07 13:51:31.121792364 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifge extends JTTTest { + + public static int test(int a) { + int n = 0; + if (a >= 0) { + n += 1; + } else { + n -= 1; + } + if (a < 0) { + n -= 1; + } else { + n += 1; + } + return n; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge_2.java 2016-12-07 13:51:31.385803968 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifge_2 extends JTTTest { + + public static boolean test(int a, int b) { + return a >= b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1, 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -100); + } + + @Test + public void run4() throws Throwable { + runTest("test", -1, 0); + } + + @Test + public void run5() throws Throwable { + runTest("test", -12, -12); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge_3.java 2016-12-07 13:51:31.652815703 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifge_3 extends JTTTest { + + public static boolean test(int a, int b) { + return a < b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1, 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -100); + } + + @Test + public void run4() throws Throwable { + runTest("test", -1, 0); + } + + @Test + public void run5() throws Throwable { + runTest("test", -12, -12); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifgt.java 2016-12-07 13:51:31.916827307 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifgt extends JTTTest { + + public static int test(int a) { + int n = 0; + if (a > 0) { + n += 1; + } else { + n -= 1; + } + if (a <= 0) { + n -= 1; + } else { + n += 1; + } + return n; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmplt1.java 2016-12-07 13:51:32.181838955 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ificmplt1 extends JTTTest { + + public static int test(int a) { + return a < 1 ? 12 : 13; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmplt2.java 2016-12-07 13:51:32.446850603 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ificmplt2 extends JTTTest { + + public static int test(int a) { + return a > 1 ? 13 : 12; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmpne1.java 2016-12-07 13:51:32.711862250 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ificmpne1 extends JTTTest { + + public static int test(int a) { + return a == 1 ? 12 : 13; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmpne2.java 2016-12-07 13:51:32.977873942 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ificmpne2 extends JTTTest { + + public static int test(int a) { + return a != 1 ? 13 : 12; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifle.java 2016-12-07 13:51:33.242885590 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifle extends JTTTest { + + public static int test(int a) { + int n = 0; + if (a <= 0) { + n += 1; + } else { + n -= 1; + } + if (a > 0) { + n -= 1; + } else { + n += 1; + } + return n; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iflt.java 2016-12-07 13:51:33.507897238 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iflt extends JTTTest { + + public static int test(int a) { + int n = 0; + if (a < 0) { + n += 1; + } else { + n -= 1; + } + if (a >= 0) { + n -= 1; + } else { + n += 1; + } + return n; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifne.java 2016-12-07 13:51:33.771908841 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifne extends JTTTest { + + public static int test(int a) { + int n = 0; + if (a != 0) { + n += 1; + } else { + n -= 1; + } + if (a == 0) { + n -= 1; + } else { + n += 1; + } + return n; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull.java 2016-12-07 13:51:34.035920445 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifnonnull extends JTTTest { + + public static int test(Object a) { + int n = 0; + if (a == null) { + n += 1; + } else { + n -= 1; + } + if (a != null) { + n -= 1; + } else { + n += 1; + } + return n; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", ""); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull_2.java 2016-12-07 13:51:34.300932093 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifnonnull_2 extends JTTTest { + + public static boolean test(Object a) { + return a != null; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", ""); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull_3.java 2016-12-07 13:51:34.564943697 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifnonnull_3 extends JTTTest { + + public static int test(Object a) { + if (a != null) { + return 1; + } + return 2; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", ""); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull.java 2016-12-07 13:51:34.827955257 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifnull extends JTTTest { + + public static int test(Object a) { + int n = 0; + if (a != null) { + n += 1; + } else { + n -= 1; + } + if (a == null) { + n -= 1; + } else { + n += 1; + } + return n; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", ""); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull_2.java 2016-12-07 13:51:35.093966948 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifnull_2 extends JTTTest { + + public static boolean test(Object a) { + return a == null; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", ""); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull_3.java 2016-12-07 13:51:35.358978596 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ifnull_3 extends JTTTest { + + public static int test(Object a) { + if (a == null) { + return 1; + } + return 2; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", ""); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_1.java 2016-12-07 13:51:35.621990156 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iinc_1 extends JTTTest { + + public static int test(int a) { + int arg = a; + arg += 1; + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 4); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_2.java 2016-12-07 13:51:35.887001804 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iinc_2 extends JTTTest { + + public static int test(int a) { + int arg = a; + arg += 2; + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 4); + } + + @Test + public void run3() throws Throwable { + runTest("test", -2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_3.java 2016-12-07 13:51:36.152013451 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iinc_3 extends JTTTest { + + public static int test(int a) { + int arg = a; + arg += 51; + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 4); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_4.java 2016-12-07 13:51:36.418025143 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iinc_4 extends JTTTest { + + public static int test(int a) { + int arg = a; + arg += 512; + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 4); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0.java 2016-12-07 13:51:36.685036879 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iload_0 extends JTTTest { + + public static int test(int arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1000345); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0_1.java 2016-12-07 13:51:36.949048483 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iload_0_1 extends JTTTest { + + public static int test(int arg) { + return arg + 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1000345); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0_2.java 2016-12-07 13:51:37.214060130 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iload_0_2 extends JTTTest { + + public static int test(int arg) { + int i = arg; + return i; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1000345); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_1.java 2016-12-07 13:51:37.480071822 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iload_1 extends JTTTest { + + @SuppressWarnings("unused") + public static int test(int i, int arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1, 1000345); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_1_1.java 2016-12-07 13:51:37.744083426 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iload_1_1 extends JTTTest { + + public static int test(int i) { + int arg = 0; + return i + arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1000345); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_2.java 2016-12-07 13:51:38.009095074 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iload_2 extends JTTTest { + + @SuppressWarnings("unused") + public static int test(int i, int j, int arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 1, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1, 1, 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1, 1, 1000345); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_3.java 2016-12-07 13:51:38.274106721 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iload_3 extends JTTTest { + + @SuppressWarnings("unused") + public static int test(int i, int j, int k, int arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 1, 1, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1, 1, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1, 1, 1, 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1, 1, 1, 1000345); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_imul.java 2016-12-07 13:51:38.542118501 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_imul extends JTTTest { + + public static int test(int a, int b) { + return a * b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 33, 67); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1, -1); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648, 1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2147483647, -1); + } + + @Test + public void run6() throws Throwable { + runTest("test", -2147483648, -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ineg.java 2016-12-07 13:51:38.805130061 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ineg extends JTTTest { + + public static int test(int a) { + return -a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 7263); + } + + @Test + public void run3() throws Throwable { + runTest("test", -2147483648); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_instanceof.java 2016-12-07 13:51:39.068141621 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_instanceof extends JTTTest { + + private static class TestClass { + } + + static Object object2 = new Object(); + static Object object3 = ""; + static Object object4 = new TestClass(); + + public static boolean test(int arg) { + Object obj; + if (arg == 2) { + obj = object2; + } else if (arg == 3) { + obj = object3; + } else if (arg == 4) { + obj = object4; + } else { + obj = null; + } + return obj instanceof TestClass; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_instanceof01.java 2016-12-07 13:51:39.333153268 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.core.phases.HighTier; +import org.graalvm.compiler.jtt.JTTTest; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; +import org.graalvm.compiler.phases.tiers.Suites; + +/** + * Tests the instanceof works, when casting an array of interface. + */ +public class BC_instanceof01 extends JTTTest { + + public interface IObject { + + } + + public interface IDerivedObject extends IObject { + + } + + private static class BaseClass { + + } + + private static class TestClass extends BaseClass implements IObject { + } + + private static class DerivedTestClass extends BaseClass implements IDerivedObject { + + } + + static TestClass[] a1 = {new TestClass()}; + static DerivedTestClass[] a2 = {new DerivedTestClass()}; + + public static BaseClass[] getBaseClassArray() { + return a1; + } + + public static BaseClass[] getDerivedBaseClassArray() { + return a2; + } + + public static boolean test() { + return getBaseClassArray() instanceof IObject[]; + } + + public static int testConditionalElimination() { + BaseClass[] result = getDerivedBaseClassArray(); + if (result instanceof IDerivedObject[]) { + if (result instanceof IObject[]) { + return 1; + } else { + return 2; + } + } else { + return 3; + } + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + + @Override + @SuppressWarnings("try") + protected Suites getSuites() { + try (OverrideScope scope = OptionValue.override(HighTier.Options.Inline, false)) { + return super.getSuites(); + } + } + + @Test + public void run1() throws Throwable { + runTest("testConditionalElimination"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokeinterface.java 2016-12-07 13:51:39.600165004 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_invokeinterface extends JTTTest { + + public interface ITest { + + int id(int a); + } + + static class IClass implements ITest { + + @Override + public int id(int a) { + return a; + } + } + + static ITest object = new IClass(); + + public static int test(int a) { + return object.id(a); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokespecial.java 2016-12-07 13:51:39.865176652 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_invokespecial extends JTTTest { + + private static class TestClass { + @SuppressWarnings("static-method") + private int id(int i) { + return i; + } + } + + static TestClass object = new TestClass(); + + public static int test(int a) { + return object.id(a); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokespecial2.java 2016-12-07 13:51:40.130188299 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_invokespecial2 extends JTTTest { + + private static class TestClass { + @SuppressWarnings("static-method") + private int id(int i) { + return 4 + i; + } + } + + static TestClass object = new TestClass(); + + public static int test(int a) { + return 3 + object.id(a); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokestatic.java 2016-12-07 13:51:40.395199947 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_invokestatic extends JTTTest { + + public static int test(int a) { + return id(a); + } + + public static int id(int i) { + return i; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokevirtual.java 2016-12-07 13:51:40.659211551 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_invokevirtual extends JTTTest { + + private static class TestClass { + public int id(int i) { + return i; + } + } + + static TestClass object = new TestClass(); + + public static int test(int a) { + return object.id(a); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ior.java 2016-12-07 13:51:40.923223155 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ior extends JTTTest { + + public static int test(int a, int b) { + return a | b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31, 63); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6, 4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648, 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem.java 2016-12-07 13:51:41.187234758 -0800 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_irem extends JTTTest { + + public static int test(int a, int b) { + return a % b; + } + + // Left as constant + public static int test2(int b) { + return 13 % b; + } + + // Right as constant + public static int test3(int a) { + return a % 13; + } + + // Tests if the zero extension works fine with 64 bit registers behind + public static long test4(int a, int b) { + int ra = Math.abs(a % b); + int rb = Math.abs(a) % b; + return ra << 32 | rb; + } + + // Test if sign extension works on architectures with 64 bit registers only + public static int test5(int a, int b) { + return (a + 0xFF) % (b + 0xFF); + } + + // Test if sign extension works on architectures with 64 bit registers only + public static int test6(int a, int b) { + return (a - 0xFF) % (b - 0xFF); + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 256, 4); + } + + @Test + public void run3() throws Throwable { + runTest("test", 135, 7); + } + + @Test + public void run20() throws Throwable { + runTest("test2", 2); + } + + @Test + public void run21() throws Throwable { + runTest("test2", 20000000); + } + + @Test + public void run22() throws Throwable { + runTest("test2", -20000000); + } + + @Test + public void run30() throws Throwable { + runTest("test3", 2); + } + + @Test + public void run31() throws Throwable { + runTest("test3", 200000000); + } + + @Test + public void run32() throws Throwable { + runTest("test3", -200000000); + } + + @Test + public void run41() throws Throwable { + runTest("test4", -100000, 3000000); + } + + @Test + public void run42() throws Throwable { + runTest("test4", -100000, 30); + } + + @Test + public void run43() throws Throwable { + runTest("test4", -1000000, -30); + } + + @Test + public void run51() { + runTest("test5", Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + @Test + public void run61() { + runTest("test6", Integer.MIN_VALUE, Integer.MIN_VALUE); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem2.java 2016-12-07 13:51:41.452246406 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_irem2 extends JTTTest { + + public static int test(int a, int b) { + return a % b; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648, -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2147483648, 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem3.java 2016-12-07 13:51:41.719258142 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_irem3 extends JTTTest { + + public static int test(int a) { + return a % 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1000); + } + + @Test + public void run3() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run4() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ireturn.java 2016-12-07 13:51:41.983269745 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ireturn extends JTTTest { + + public static int test(int a) { + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 256); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ishl.java 2016-12-07 13:51:42.247281349 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ishl extends JTTTest { + + public static int test(int a, int b) { + return a << b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31, 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6, 4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648, 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ishr.java 2016-12-07 13:51:42.511292953 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ishr extends JTTTest { + + public static int test(int a, int b) { + return a >> b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 67, 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31, 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6, 4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648, 16); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_isub.java 2016-12-07 13:51:42.776304601 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_isub extends JTTTest { + + public static int test(int a, int b) { + return a - b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 33, -67); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1, 1); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648, -1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2147483647, -1); + } + + @Test + public void run6() throws Throwable { + runTest("test", -2147483647, 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iushr.java 2016-12-07 13:51:43.041316249 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_iushr extends JTTTest { + + public static int test(int a, int b) { + return a >>> b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 67, 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31, 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6, 4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648, 16); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ixor.java 2016-12-07 13:51:43.306327896 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ixor extends JTTTest { + + public static int test(int a, int b) { + return a ^ b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31, 63); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6, 4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648, 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2d.java 2016-12-07 13:51:43.570339500 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_l2d extends JTTTest { + + public static double test(long a) { + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -74652389L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2f.java 2016-12-07 13:51:43.835351148 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_l2f extends JTTTest { + + public static float test(long a) { + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -74652389L); + } + + @Test + public void run3() throws Throwable { + runTest("test", Long.MAX_VALUE); + } + + @Test + public void run4() throws Throwable { + runTest("test", Long.MIN_VALUE); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2i.java 2016-12-07 13:51:44.100362796 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_l2i extends JTTTest { + + public static int test(long a) { + return (int) a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3L); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483647L); + } + + @Test + public void run5() throws Throwable { + runTest("test", -2147483648L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 2147483647L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2i_2.java 2016-12-07 13:51:44.365374443 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_l2i_2 extends JTTTest { + + static Object[] array = {null}; + + public static Object test(long a) { + long arg = a; + arg = arg << 32; + return array[(int) arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 123456789L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ladd.java 2016-12-07 13:51:44.629386047 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ladd extends JTTTest { + + public static long test(long a, long b) { + return a + b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0L, -1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 33L, 67L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1L, -1L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648L, 1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2147483647L, 1L); + } + + @Test + public void run6() throws Throwable { + runTest("test", -2147483647L, -2L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ladd2.java 2016-12-07 13:51:44.894397694 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ladd2 extends JTTTest { + + public static long test(int a, int b) { + return a + (long) b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 33, 67); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1, -1); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648, 1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2147483647, 1); + } + + @Test + public void run6() throws Throwable { + runTest("test", -2147483647, -2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_laload.java 2016-12-07 13:51:45.159409342 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_laload extends JTTTest { + + static long[] array = {0L, -1L, 4L, 1000000000000L}; + + public static long test(int arg) { + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_land.java 2016-12-07 13:51:45.425421034 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_land extends JTTTest { + + public static long test(long a, long b) { + return a & b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0L, -1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31L, 63L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6L, 4L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648L, 1L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lastore.java 2016-12-07 13:51:45.690432681 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lastore extends JTTTest { + + static long[] array = {0, 0, 0, 0}; + + public static long test(int arg, long val) { + final long[] array2 = arg == -2 ? null : BC_lastore.array; + array2[arg] = val; + return array2[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, -1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, 11L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, -14L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lcmp.java 2016-12-07 13:51:45.955444329 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lcmp extends JTTTest { + + public static boolean test(long a, long b) { + return a < b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L, -1L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 77L, 78L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1L, 0L); + } + + /** + * Test with ugly numbers (which probably does not fit into one instruction. + * + * @throws Throwable + */ + @Test + public void run3() throws Throwable { + runTest("test", 293521900824L, 97726785831L); + } + + /** + * Test with big numbers where it makes difference if the value is handled with 64 bits. + * + * @throws Throwable + */ + @Test + public void run4() throws Throwable { + runTest("test", -1L, Long.MIN_VALUE); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_01.java 2016-12-07 13:51:46.221456021 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ldc_01 extends JTTTest { + + public static int test() { + return -123; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_02.java 2016-12-07 13:51:46.485467625 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ldc_02 extends JTTTest { + + public static float test() { + return -2.4f; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_03.java 2016-12-07 13:51:46.751479316 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ldc_03 extends JTTTest { + + public static long test() { + return -123L; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_04.java 2016-12-07 13:51:47.015490920 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ldc_04 extends JTTTest { + + public static String test() { + return "xyz"; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_05.java 2016-12-07 13:51:47.278502480 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ldc_05 extends JTTTest { + + public static double test() { + return -2.33d; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_06.java 2016-12-07 13:51:47.542514083 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2009, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ldc_06 extends JTTTest { + + public static String test() { + return test2().getName(); + } + + static Class test2() { + return BC_ldc_06.class; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv.java 2016-12-07 13:51:47.806525687 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ldiv extends JTTTest { + + public static long test(long a, long b) { + return a / b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2L, -1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 256L, 4L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 135L, 7L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv2.java 2016-12-07 13:51:48.070537291 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ldiv2 extends JTTTest { + + public static long MIN = Long.MIN_VALUE; + public static long MAX = Long.MAX_VALUE; + + public static long test(long a, long b) { + return a / b; + } + + @Test + public void run0() throws Throwable { + runTest("test", MIN, -1L); + } + + @Test + public void run1() throws Throwable { + runTest("test", MIN, 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", MIN, MAX); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv3.java 2016-12-07 13:51:48.335548939 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ldiv3 extends JTTTest { + + public static long PLUS7 = 7; + public static long PLUS3 = 3; + public static long MIN7 = -7; + public static long MIN3 = -3; + + public static long test(long a, long b) { + return a / b; + } + + @Test + public void run0() throws Throwable { + runTest("test", PLUS7, 2L); + runTest("test", PLUS3, 2L); + runTest("test", MIN7, 2L); + runTest("test", MIN3, 2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", PLUS7, -4L); + runTest("test", PLUS3, -4L); + runTest("test", MIN7, -4L); + runTest("test", MIN3, -4L); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_0.java 2016-12-07 13:51:48.601560630 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lload_0 extends JTTTest { + + public static long test(long arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -3L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 10000L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_01.java 2016-12-07 13:51:48.865572234 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +@SuppressWarnings("unused") +public class BC_lload_01 extends JTTTest { + + public static long test(int i) { + return test1(null); + } + + public static int test1(Object o0) { + long x = 1; + return 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", -3); + } + + @Test + public void run2() throws Throwable { + runTest("test", 100); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_1.java 2016-12-07 13:51:49.130583882 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lload_1 extends JTTTest { + + @SuppressWarnings("unused") + public static long test(int i, long arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 1L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, -3L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1, 10000L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_2.java 2016-12-07 13:51:49.394595485 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lload_2 extends JTTTest { + + @SuppressWarnings("unused") + public static long test(int i, int j, long arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 1, 1L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1, -3L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1, 1, 10000L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_3.java 2016-12-07 13:51:49.660607177 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lload_3 extends JTTTest { + + @SuppressWarnings("unused") + public static long test(int i, int j, int k, long arg) { + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 1, 1, 1L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1, 1, -3L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1, 1, 1, 10000L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lmul.java 2016-12-07 13:51:49.924618781 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lmul extends JTTTest { + + public static long test(long a, long b) { + return a * b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0L, -1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 33L, 67L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1L, -1L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648L, 1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2147483647L, -1L); + } + + @Test + public void run6() throws Throwable { + runTest("test", -2147483648L, -1L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 1000000L, 1000000L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lneg.java 2016-12-07 13:51:50.188630384 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lneg extends JTTTest { + + public static long test(long a) { + return -a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 7263L); + } + + @Test + public void run3() throws Throwable { + runTest("test", -2147483648L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch01.java 2016-12-07 13:51:50.453642032 -0800 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lookupswitch01 extends JTTTest { + + public static int test(int a) { + switch (a) { + case 67: + return 0; + case 97: + return 1; + case 107: + return 2; + case 133: + return 3; + case 212: + return 4; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 66); + } + + @Test + public void run3() throws Throwable { + runTest("test", 67); + } + + @Test + public void run4() throws Throwable { + runTest("test", 68); + } + + @Test + public void run5() throws Throwable { + runTest("test", 96); + } + + @Test + public void run6() throws Throwable { + runTest("test", 97); + } + + @Test + public void run7() throws Throwable { + runTest("test", 98); + } + + @Test + public void run8() throws Throwable { + runTest("test", 106); + } + + @Test + public void run9() throws Throwable { + runTest("test", 107); + } + + @Test + public void run10() throws Throwable { + runTest("test", 108); + } + + @Test + public void run11() throws Throwable { + runTest("test", 132); + } + + @Test + public void run12() throws Throwable { + runTest("test", 133); + } + + @Test + public void run13() throws Throwable { + runTest("test", 134); + } + + @Test + public void run14() throws Throwable { + runTest("test", 211); + } + + @Test + public void run15() throws Throwable { + runTest("test", 212); + } + + @Test + public void run16() throws Throwable { + runTest("test", 213); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch02.java 2016-12-07 13:51:50.719653724 -0800 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lookupswitch02 extends JTTTest { + + public static int test(int a) { + final int b = a; + switch (b) { + case 67: + return 0; + case 97: + return 1; + case 107: + return 2; + case 133: + return 3; + case 212: + return 4; + case -122: + return 5; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 66); + } + + @Test + public void run3() throws Throwable { + runTest("test", 67); + } + + @Test + public void run4() throws Throwable { + runTest("test", 68); + } + + @Test + public void run5() throws Throwable { + runTest("test", 96); + } + + @Test + public void run6() throws Throwable { + runTest("test", 97); + } + + @Test + public void run7() throws Throwable { + runTest("test", 98); + } + + @Test + public void run8() throws Throwable { + runTest("test", 106); + } + + @Test + public void run9() throws Throwable { + runTest("test", 107); + } + + @Test + public void run10() throws Throwable { + runTest("test", 108); + } + + @Test + public void run11() throws Throwable { + runTest("test", 132); + } + + @Test + public void run12() throws Throwable { + runTest("test", 133); + } + + @Test + public void run13() throws Throwable { + runTest("test", 134); + } + + @Test + public void run14() throws Throwable { + runTest("test", 211); + } + + @Test + public void run15() throws Throwable { + runTest("test", 212); + } + + @Test + public void run16() throws Throwable { + runTest("test", 213); + } + + @Test + public void run17() throws Throwable { + runTest("test", -121); + } + + @Test + public void run18() throws Throwable { + runTest("test", -122); + } + + @Test + public void run19() throws Throwable { + runTest("test", -123); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch03.java 2016-12-07 13:51:50.984665371 -0800 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lookupswitch03 extends JTTTest { + + public static int test(int a) { + final int b = a + 10; + switch (b) { + case 77: + return 0; + case 107: + return 1; + case 117: + return 2; + case 143: + return 3; + case 222: + return 4; + case -112: + return 5; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 66); + } + + @Test + public void run3() throws Throwable { + runTest("test", 67); + } + + @Test + public void run4() throws Throwable { + runTest("test", 68); + } + + @Test + public void run5() throws Throwable { + runTest("test", 96); + } + + @Test + public void run6() throws Throwable { + runTest("test", 97); + } + + @Test + public void run7() throws Throwable { + runTest("test", 98); + } + + @Test + public void run8() throws Throwable { + runTest("test", 106); + } + + @Test + public void run9() throws Throwable { + runTest("test", 107); + } + + @Test + public void run10() throws Throwable { + runTest("test", 108); + } + + @Test + public void run11() throws Throwable { + runTest("test", 132); + } + + @Test + public void run12() throws Throwable { + runTest("test", 133); + } + + @Test + public void run13() throws Throwable { + runTest("test", 134); + } + + @Test + public void run14() throws Throwable { + runTest("test", 211); + } + + @Test + public void run15() throws Throwable { + runTest("test", 212); + } + + @Test + public void run16() throws Throwable { + runTest("test", 213); + } + + @Test + public void run17() throws Throwable { + runTest("test", -121); + } + + @Test + public void run18() throws Throwable { + runTest("test", -122); + } + + @Test + public void run19() throws Throwable { + runTest("test", -123); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch04.java 2016-12-07 13:51:51.249677019 -0800 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lookupswitch04 extends JTTTest { + + public static int test(int a) { + final int b = a + 8; + final int c = b + 2; + switch (c) { + case 77: + return 0; + case 107: + return 1; + case 117: + return 2; + case 143: + return 3; + case 222: + return 4; + case -112: + return 5; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 66); + } + + @Test + public void run3() throws Throwable { + runTest("test", 67); + } + + @Test + public void run4() throws Throwable { + runTest("test", 68); + } + + @Test + public void run5() throws Throwable { + runTest("test", 96); + } + + @Test + public void run6() throws Throwable { + runTest("test", 97); + } + + @Test + public void run7() throws Throwable { + runTest("test", 98); + } + + @Test + public void run8() throws Throwable { + runTest("test", 106); + } + + @Test + public void run9() throws Throwable { + runTest("test", 107); + } + + @Test + public void run10() throws Throwable { + runTest("test", 108); + } + + @Test + public void run11() throws Throwable { + runTest("test", 132); + } + + @Test + public void run12() throws Throwable { + runTest("test", 133); + } + + @Test + public void run13() throws Throwable { + runTest("test", 134); + } + + @Test + public void run14() throws Throwable { + runTest("test", 211); + } + + @Test + public void run15() throws Throwable { + runTest("test", 212); + } + + @Test + public void run16() throws Throwable { + runTest("test", 213); + } + + @Test + public void run17() throws Throwable { + runTest("test", -121); + } + + @Test + public void run18() throws Throwable { + runTest("test", -122); + } + + @Test + public void run19() throws Throwable { + runTest("test", -123); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch05.java 2016-12-07 13:51:51.514688667 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lookupswitch05 extends JTTTest { + + public static Object test(int a) { + switch (a) { + default: + return new String(); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lor.java 2016-12-07 13:51:51.780700358 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lor extends JTTTest { + + public static long test(long a, long b) { + return a | b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0L, -1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31L, 63L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6L, 4L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648L, 1L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lrem.java 2016-12-07 13:51:52.043711918 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lrem extends JTTTest { + + public static long test(long a, long b) { + return a % b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2L, -1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 256L, 4L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 135L, 7L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lrem2.java 2016-12-07 13:51:52.309723610 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lrem2 extends JTTTest { + + public static long test(long a, long b) { + return a % b; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L, -1L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -9223372036854775808L, 1L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lreturn.java 2016-12-07 13:51:52.573735213 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lreturn extends JTTTest { + + public static long test(long a) { + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 256L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1000000000000L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshl.java 2016-12-07 13:51:52.838746861 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lshl extends JTTTest { + + public static long test(long a, int b) { + return a << b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0L, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31L, 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6L, 4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648L, 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshr.java 2016-12-07 13:51:53.103758509 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lshr extends JTTTest { + + public static long test(long a, int b) { + return a >> b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 67L, 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31L, 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6L, 4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648L, 16); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshr02.java 2016-12-07 13:51:53.366770068 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lshr02 extends JTTTest { + + public static long test0(long arg) { + long a = arg >> 32; + return a >> 32; + } + + @Test + public void run0a() throws Throwable { + runTest("test0", 1L); + } + + @Test + public void run0b() throws Throwable { + runTest("test0", 0L); + } + + @Test + public void run0c() throws Throwable { + runTest("test0", -1L); + } + + @Test + public void run0d() throws Throwable { + runTest("test0", Long.MAX_VALUE); + } + + @Test + public void run0e() throws Throwable { + runTest("test0", Long.MIN_VALUE); + } + + /* testcase for a postive stamp */ + public static int test1(long[] arg) { + int a = arg.length >> 16; + return a >> 16; + } + + @Test + public void run1a() throws Throwable { + long[] arg = new long[0x100]; + runTest("test1", arg); + } + + /* testcase for a strictly negative stamp */ + public static int test2(long[] arg) { + int a = (-arg.length - 1) >> 16; + return a >> 16; + } + + @Test + public void run2a() throws Throwable { + long[] arg = new long[0x100]; + runTest("test2", arg); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lsub.java 2016-12-07 13:51:53.632781760 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lsub extends JTTTest { + + public static long test(long a, long b) { + return a - b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, -2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0L, 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 33L, -67L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1L, 1L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648L, -1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2147483647L, -1L); + } + + @Test + public void run6() throws Throwable { + runTest("test", -2147483647L, 2L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lushr.java 2016-12-07 13:51:53.896793364 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lushr extends JTTTest { + + public static long test(long a, int b) { + return a >>> b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 67L, 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31L, 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6L, 4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648L, 16); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lxor.java 2016-12-07 13:51:54.162805055 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lxor extends JTTTest { + + public static long test(long a, long b) { + return a ^ b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0L, -1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 31L, 63L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6L, 4L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -2147483648L, 1L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_monitorenter.java 2016-12-07 13:51:54.427816703 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_monitorenter extends JTTTest { + + static DummyTestClass object = new DummyTestClass(); + + public static int test(int arg) { + synchronized (object) { + return arg; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_monitorenter02.java 2016-12-07 13:51:54.691828307 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_monitorenter02 extends JTTTest { + + static DummyTestClass object = new DummyTestClass(); + + public static int test(int arg, int arg2) { + int result = arg; + synchronized (object) { + result = arg / arg2; + } + synchronized (object) { + result = arg / arg2; + } + return result; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2, 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray01.java 2016-12-07 13:51:54.956839954 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_multianewarray01 extends JTTTest { + + public static int test(int a) { + final DummyTestClass[][] v = new DummyTestClass[3][3]; + return v != null ? a : -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray02.java 2016-12-07 13:51:55.219851514 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_multianewarray02 extends JTTTest { + + public static int test(int a) { + final DummyTestClass[][][][] v = new DummyTestClass[3][3][3][3]; + return v != null ? a : -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray03.java 2016-12-07 13:51:55.484863162 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_multianewarray03 extends JTTTest { + + public static int test(int a) { + final BC_multianewarray03[][][][] v = new BC_multianewarray03[a][a][a][a]; + return v.length + v[0].length + v[0][0].length + v[0][0][0].length; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray04.java 2016-12-07 13:51:55.749874809 -0800 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_multianewarray04 extends JTTTest { + + public static int test(int a) { + int i = 1; + + i += testByte(a); + i += testBoolean(a); + i += testChar(a); + i += testShort(a); + i += testInt(a); + i += testFloat(a); + i += testLong(a); + i += testDouble(a); + + return i; + } + + private static int testDouble(int a) { + double[][] b2 = new double[a][a]; + double[][][] b3 = new double[a][a][a]; + double[][][][] b4 = new double[a][a][a][a]; + double[][][][][] b5 = new double[a][a][a][a][a]; + double[][][][][][] b6 = new double[a][a][a][a][a][a]; + return b2.length + b3.length + b4.length + b5.length + b6.length; + } + + private static int testLong(int a) { + long[][] b2 = new long[a][a]; + long[][][] b3 = new long[a][a][a]; + long[][][][] b4 = new long[a][a][a][a]; + long[][][][][] b5 = new long[a][a][a][a][a]; + long[][][][][][] b6 = new long[a][a][a][a][a][a]; + return b2.length + b3.length + b4.length + b5.length + b6.length; + } + + private static int testFloat(int a) { + float[][] b2 = new float[a][a]; + float[][][] b3 = new float[a][a][a]; + float[][][][] b4 = new float[a][a][a][a]; + float[][][][][] b5 = new float[a][a][a][a][a]; + float[][][][][][] b6 = new float[a][a][a][a][a][a]; + return b2.length + b3.length + b4.length + b5.length + b6.length; + } + + private static int testInt(int a) { + int[][] b2 = new int[a][a]; + int[][][] b3 = new int[a][a][a]; + int[][][][] b4 = new int[a][a][a][a]; + int[][][][][] b5 = new int[a][a][a][a][a]; + int[][][][][][] b6 = new int[a][a][a][a][a][a]; + return b2.length + b3.length + b4.length + b5.length + b6.length; + } + + private static int testShort(int a) { + short[][] b2 = new short[a][a]; + short[][][] b3 = new short[a][a][a]; + short[][][][] b4 = new short[a][a][a][a]; + short[][][][][] b5 = new short[a][a][a][a][a]; + short[][][][][][] b6 = new short[a][a][a][a][a][a]; + return b2.length + b3.length + b4.length + b5.length + b6.length; + } + + private static int testChar(int a) { + char[][] b2 = new char[a][a]; + char[][][] b3 = new char[a][a][a]; + char[][][][] b4 = new char[a][a][a][a]; + char[][][][][] b5 = new char[a][a][a][a][a]; + char[][][][][][] b6 = new char[a][a][a][a][a][a]; + return b2.length + b3.length + b4.length + b5.length + b6.length; + } + + private static int testBoolean(int a) { + boolean[][] b2 = new boolean[a][a]; + boolean[][][] b3 = new boolean[a][a][a]; + boolean[][][][] b4 = new boolean[a][a][a][a]; + boolean[][][][][] b5 = new boolean[a][a][a][a][a]; + boolean[][][][][][] b6 = new boolean[a][a][a][a][a][a]; + return b2.length + b3.length + b4.length + b5.length + b6.length; + } + + private static int testByte(int a) { + byte[][] b2 = new byte[a][a]; + byte[][][] b3 = new byte[a][a][a]; + byte[][][][] b4 = new byte[a][a][a][a]; + byte[][][][][] b5 = new byte[a][a][a][a][a]; + byte[][][][][][] b6 = new byte[a][a][a][a][a][a]; + return b2.length + b3.length + b4.length + b5.length + b6.length; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_new.java 2016-12-07 13:51:56.014886457 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_new extends JTTTest { + + @SuppressWarnings("unused") + public static int test(int a) { + new DummyTestClass(); + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_newarray.java 2016-12-07 13:51:56.277898016 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_newarray extends JTTTest { + + @SuppressWarnings("all") + public static int test(int a) { + if (new boolean[3] == null) { + return -1; + } + if (new char[3] == null) { + return -1; + } + if (new float[3] == null) { + return -1; + } + if (new double[3] == null) { + return -1; + } + if (new byte[3] == null) { + return -1; + } + if (new short[3] == null) { + return -1; + } + if (new int[3] == null) { + return -1; + } + if (new long[3] == null) { + return -1; + } + + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_01.java 2016-12-07 13:51:56.542909664 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_putfield_01 extends JTTTest { + + private static class TestClass { + private int field; + } + + private static TestClass object = new TestClass(); + + public static int test(int arg) { + object.field = arg; + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", -4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_02.java 2016-12-07 13:51:56.810921444 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_putfield_02 extends JTTTest { + + private static class TestClass { + private Object field; + } + + private static TestClass object = new TestClass(); + + public static Object test(Object arg) { + object.field = arg; + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", "0"); + } + + @Test + public void run1() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run2() throws Throwable { + runTest("test", "string"); + } + + @Test + public void run3() throws Throwable { + runTest("test", "-4"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_03.java 2016-12-07 13:51:57.075933091 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_putfield_03 extends JTTTest { + + private static class TestClass { + private volatile int field; + } + + private static TestClass object = new TestClass(); + + public static int test(int arg) { + object.field = arg; + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", -4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_04.java 2016-12-07 13:51:57.341944783 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_putfield_04 extends JTTTest { + + private static class TestClass { + private volatile Object field; + } + + private static TestClass object = new TestClass(); + + public static Object test(Object arg) { + object.field = arg; + return object.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", "0"); + } + + @Test + public void run1() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run2() throws Throwable { + runTest("test", "string"); + } + + @Test + public void run3() throws Throwable { + runTest("test", "-4"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putstatic.java 2016-12-07 13:51:57.607956475 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_putstatic extends JTTTest { + + private static int field; + + public static int test(int a) { + field = a; + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_saload.java 2016-12-07 13:51:57.871968078 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_saload extends JTTTest { + + static short[] array = {0, -1, 4, 10000}; + + public static short test(int arg) { + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_sastore.java 2016-12-07 13:51:58.136979726 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_sastore extends JTTTest { + + static short[] array = {0, 0, 0, 0}; + + public static short test(int arg, short val) { + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, ((short) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, ((short) -1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, ((short) 11)); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, ((short) -14)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch.java 2016-12-07 13:51:58.407991637 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_tableswitch extends JTTTest { + + public static int test(int a) { + switch (a) { + case 0: + return 10; + case 1: + return 20; + case 2: + return 30; + case 4: + return 40; + case 5: + return 50; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 2); + } + + @Test + public void run4() throws Throwable { + runTest("test", 3); + } + + @Test + public void run5() throws Throwable { + runTest("test", 4); + } + + @Test + public void run6() throws Throwable { + runTest("test", 5); + } + + @Test + public void run7() throws Throwable { + runTest("test", 6); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch2.java 2016-12-07 13:51:58.674003329 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_tableswitch2 extends JTTTest { + + public static int test(int a) { + switch (a) { + case 5: + return 55; + case 6: + return 66; + case 7: + return 77; + } + return 11; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 5); + } + + @Test + public void run4() throws Throwable { + runTest("test", 6); + } + + @Test + public void run5() throws Throwable { + runTest("test", 7); + } + + @Test + public void run6() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch3.java 2016-12-07 13:51:58.938014932 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_tableswitch3 extends JTTTest { + + public static int test(int a) { + switch (a) { + case -2: + return 22; + case -1: + return 11; + case 0: + return 33; + case 1: + return 77; + } + return 99; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2); + } + + @Test + public void run2() throws Throwable { + runTest("test", -3); + } + + @Test + public void run3() throws Throwable { + runTest("test", -4); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2); + } + + @Test + public void run6() throws Throwable { + runTest("test", 10); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch4.java 2016-12-07 13:51:59.204026624 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_tableswitch4 extends JTTTest { + + public static int test(int a) { + switch (a) { + case -5: + return 55; + case -4: + return 44; + case -3: + return 33; + } + return 11; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", -5); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4); + } + + @Test + public void run5() throws Throwable { + runTest("test", -3); + } + + @Test + public void run6() throws Throwable { + runTest("test", -8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_wide01.java 2016-12-07 13:51:59.468038227 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_wide01 extends JTTTest { + + @SuppressWarnings("unused") + public static int test(int arg) { + + // Checkstyle: stop + long i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15; + long j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + long k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15; + long l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15; + long m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15; + long n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15; + long o0, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15; + long p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15; + long q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14, q15; + long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15; + // Checkstyle: resume + + int i255 = 10; + return arg + i255 + 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_wide02.java 2016-12-07 13:51:59.734049919 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_wide02 extends JTTTest { + + @SuppressWarnings("unused") + public static int test(int arg) { + + // Checkstyle: stop + long i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15; + long j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + long k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15; + long l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15; + long m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15; + long n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15; + long o0, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15; + long p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15; + long q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14, q15; + long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15; + // Checkstyle: resume + + int i255 = 9; + i255++; + return arg + i255 + 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aaload0.java 2016-12-07 13:51:59.999061566 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_aaload0 extends JTTTest { + + static Object[] array = {null, null, ""}; + + public static Object test(int arg) { + final Object[] obj = arg == -2 ? null : array; + return obj[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aaload1.java 2016-12-07 13:52:00.263073170 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_aaload1 extends JTTTest { + + static Object[] array = {null, null, ""}; + + public static Object test(int arg) { + final Object[] obj = arg == -2 ? null : array; + try { + return obj[arg]; + } catch (NullPointerException e) { + return null; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aastore0.java 2016-12-07 13:52:00.529084862 -0800 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_aastore0 extends JTTTest { + + static Object[] param = {new Object(), null, "h"}; + static Object[] arr = {null, null, null}; + static String[] arr2 = {null, null, null}; + + public static int test(boolean a, int indx) { + Object[] array = a ? arr : arr2; + Object val; + if (indx == -2) { + array = null; + val = null; + } else { + val = param[indx]; + } + array[indx] = val; + return indx; + } + + @Test + public void run0() throws Throwable { + runTest("test", true, -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", true, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", true, 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", true, 1); + } + + @Test + public void run4() throws Throwable { + runTest("test", true, 2); + } + + @Test + public void run5() throws Throwable { + runTest("test", true, 3); + } + + @Test + public void run6() throws Throwable { + runTest("test", false, 0); + } + + @Test + public void run7() throws Throwable { + runTest("test", false, 1); + } + + @Test + public void run8() throws Throwable { + runTest("test", false, 2); + } + + @Test + public void run9() throws Throwable { + runTest("test", false, 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aastore1.java 2016-12-07 13:52:00.794096509 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_aastore1 extends JTTTest { + + static Object[] param = {new Object(), null, "h"}; + static Object[] arr = {null, null, null}; + static String[] arr2 = {null, null, null}; + + public static int test(boolean a, int indx) { + try { + Object[] array = a ? arr : arr2; + Object val; + if (indx == -2) { + array = null; + val = null; + } else { + val = param[indx]; + } + array[indx] = val; + return indx; + } catch (NullPointerException e) { + return 5; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", true, -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", true, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", true, 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", true, 1); + } + + @Test + public void run4() throws Throwable { + runTest("test", true, 2); + } + + @Test + public void run5() throws Throwable { + runTest("test", true, 3); + } + + @Test + public void run6() throws Throwable { + runTest("test", false, 0); + } + + @Test + public void run7() throws Throwable { + runTest("test", false, 1); + } + + @Test + public void run8() throws Throwable { + runTest("test", false, 2); + } + + @Test + public void run9() throws Throwable { + runTest("test", false, 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_anewarray.java 2016-12-07 13:52:01.059108157 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_anewarray extends JTTTest { + + @SuppressWarnings("unused") + public static int test(int a) { + final DummyTestClass[] v = new DummyTestClass[a]; + if (v != null) { + return a; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_arraylength.java 2016-12-07 13:52:01.324119805 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_arraylength extends JTTTest { + + static int[] arr = {1, 2, 3}; + static char[] arr2 = {'a', 'b', 'c', 'd'}; + static Object[] arr3 = new Object[5]; + + @SuppressWarnings("all") + public static int test(int arg) { + if (arg == 0) { + int[] array = null; + return array.length; + } + if (arg == 1) { + return arr.length; + } + if (arg == 2) { + return arr2.length; + } + if (arg == 3) { + return arr3.length; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow0.java 2016-12-07 13:52:01.590131496 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_athrow0 extends JTTTest { + + static Throwable throwable = new Throwable(); + + public static int test(int arg) throws Throwable { + if (arg == 2) { + throw throwable; + } + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow1.java 2016-12-07 13:52:01.855143144 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_athrow1 extends JTTTest { + + static Throwable throwable = new Throwable(); + + public static int test(int arg) throws Throwable { + if (arg == 2) { + throw throwable; + } + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow2.java 2016-12-07 13:52:02.119154748 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_athrow2 extends JTTTest { + + static Throwable throwable = new Throwable(); + + public static int test(int arg) throws Throwable { + if (arg == 2) { + throw throwable; + } else if (arg == 3) { + throw null; + } + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow3.java 2016-12-07 13:52:02.383166351 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_athrow3 extends JTTTest { + + static Throwable throwable = new Throwable(); + + public static int test(int arg) throws Throwable { + if (arg == 2) { + throw2(); + } else if (arg == 3) { + throw1(); + } + return arg; + } + + private static void throw2() throws Throwable { + throw throwable; + } + + private static void throw1() throws Throwable { + throw null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_baload.java 2016-12-07 13:52:02.649178042 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_baload extends JTTTest { + + static boolean[] arr = {true, false, true, false}; + + public static boolean test(int arg) { + final boolean[] array = arg == -2 ? null : arr; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_bastore.java 2016-12-07 13:52:02.915189734 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_bastore extends JTTTest { + + static boolean[] arr = {false, false, false, false}; + + public static boolean test(int arg, boolean val) { + final boolean[] array = arg == -2 ? null : arr; + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2, true); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1, false); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, true); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4, true); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_caload.java 2016-12-07 13:52:03.179201338 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_caload extends JTTTest { + + static char[] arr = {'\000', 'a', ' ', 10000}; + + public static char test(int arg) { + final char[] array = arg == -2 ? null : arr; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_castore.java 2016-12-07 13:52:03.445213029 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_castore extends JTTTest { + + static char[] arr = {0, 0, 0, 0}; + + public static char test(int arg, char val) { + final char[] array = arg == -2 ? null : arr; + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2, ((char) 97)); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1, ((char) 99)); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, ((char) 97)); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4, ((char) 97)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast.java 2016-12-07 13:52:03.709224633 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_checkcast extends JTTTest { + + static Object object2 = new Object(); + static Object object3 = ""; + static Object object4 = new DummyTestClass(); + + public static int test(int arg) { + Object obj = null; + if (arg == 2) { + obj = object2; + } + if (arg == 3) { + obj = object3; + } + if (arg == 4) { + obj = object4; + } + final DummyTestClass bc = (DummyTestClass) obj; + if (bc == null) { + return arg; + } + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast1.java 2016-12-07 13:52:03.973236236 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_checkcast1 extends JTTTest { + + static Object object2 = new Object(); + static Object object3 = ""; + static Object object4 = new DummyTestClass(); + + public static int test(int arg) { + Object obj = null; + if (arg == 2) { + obj = object2; + } + if (arg == 3) { + obj = object3; + } + if (arg == 4) { + obj = object4; + } + final DummyTestClass bc = (DummyTestClass) obj; + if (bc == null) { + return arg; + } + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast2.java 2016-12-07 13:52:04.238247884 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_checkcast2 extends JTTTest { + + static Object object2 = new Object(); + static Object object3 = ""; + static Object object4 = new DummyTestClass(); + + public static int test(int arg) { + Object obj; + if (arg == 2) { + obj = object2; + } else if (arg == 3) { + obj = object3; + } else if (arg == 4) { + obj = object4; + } else { + obj = null; + } + final DummyTestClass bc = (DummyTestClass) obj; + if (bc != null) { + return arg; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast3.java 2016-12-07 13:52:04.503259532 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_checkcast3 extends JTTTest { + + static Object[] o1 = {new Object()}; + static String[] o2 = {""}; + static DummyTestClass[] o3 = {new DummyTestClass()}; + + public static int test(int arg) { + Object obj = null; + if (arg == 0) { + obj = o1; + } + if (arg == 1) { + obj = o2; + } + if (arg == 2) { + obj = o3; + } + Object[] r = (DummyTestClass[]) obj; + return r == null ? -1 : -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast4.java 2016-12-07 13:52:04.769271223 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public final class BC_checkcast4 extends JTTTest { + + static Object object2 = new Object(); + static Object object3 = ""; + static Object object4 = new DummyTestClass(); + + public static int test(int arg) { + Object obj; + if (arg == 2) { + obj = object2; + } else if (arg == 3) { + obj = object3; + } else if (arg == 4) { + obj = object4; + } else { + obj = null; + } + final DummyTestClass bc = (DummyTestClass) obj; + if (bc != null) { + return arg; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast5.java 2016-12-07 13:52:05.033282827 -0800 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_checkcast5 extends JTTTest { + + static Object object2 = new Object(); + static Object object3 = ""; + static Object object4 = new DummyTestClass(); + + public static int test(int arg) { + Object obj; + if (arg == 2) { + obj = object2; + } else if (arg == 3) { + obj = object3; + } else if (arg == 4) { + obj = object4; + } else { + obj = null; + } + try { + final DummyTestClass bc = (DummyTestClass) obj; + if (bc != null) { + return arg; + } + } catch (ClassCastException e) { + return -5; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast6.java 2016-12-07 13:52:05.299294518 -0800 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public final class BC_checkcast6 extends JTTTest { + + static Object object2 = new Object(); + static Object object3 = ""; + static Object object4 = new DummyTestClass(); + + public static int test(int arg) { + Object obj; + if (arg == 2) { + obj = object2; + } else if (arg == 3) { + obj = object3; + } else if (arg == 4) { + obj = object4; + } else { + obj = null; + } + try { + final DummyTestClass bc = (DummyTestClass) obj; + if (bc != null) { + return arg; + } + } catch (ClassCastException e) { + return -5; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_daload.java 2016-12-07 13:52:05.564306166 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_daload extends JTTTest { + + static double[] arr = {0.0, -1.1, 4.32, 6.06}; + + public static double test(int arg) { + final double[] array = arg == -2 ? null : arr; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_dastore.java 2016-12-07 13:52:05.829317814 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_dastore extends JTTTest { + + static double[] arr = {0, 0, 0, 0}; + + public static double test(int arg, double val) { + final double[] array = arg == -2 ? null : arr; + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2, 0.01d); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1, -1.4d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, 0.01d); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4, 0.01d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_faload.java 2016-12-07 13:52:06.092329373 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_faload extends JTTTest { + + static float[] arr = {0.0f, -1.1f, 4.32f, 6.06f}; + + public static float test(int arg) { + final float[] array = arg == -2 ? null : arr; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_fastore.java 2016-12-07 13:52:06.356340977 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_fastore extends JTTTest { + + static float[] arr = {0, 0, 0, 0}; + + public static float test(int arg, float val) { + final float[] array = arg == -2 ? null : arr; + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2, 0.01f); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1, -1.4f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, 0.01f); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4, 0.01f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_getfield.java 2016-12-07 13:52:06.621352625 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_getfield extends JTTTest { + + private static class TestClass { + private int field = 13; + } + + private static TestClass object = new TestClass(); + + public static int test(int arg) { + final TestClass obj = (arg == 3) ? null : object; + return obj.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_getfield1.java 2016-12-07 13:52:06.885364228 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_getfield1 extends JTTTest { + + private static class TestClass { + private int field = 13; + } + + public static void test(TestClass arg) { + @SuppressWarnings("unused") + int i = arg.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + // tests that the null check isn't removed along with the read + runTest(EMPTY, true, true, "test", (Object) null); + } + + @Test + public void run2() throws Throwable { + runTest("test", new TestClass()); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_iaload.java 2016-12-07 13:52:07.151375919 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_iaload extends JTTTest { + + static int[] arr = {0, -1, 4, 1000000000}; + + public static int test(int arg) { + final int[] array = arg == -2 ? null : arr; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4); + } + + @Test + public void run4() throws Throwable { + runTest("test", Integer.MIN_VALUE); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_iastore.java 2016-12-07 13:52:07.416387567 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_iastore extends JTTTest { + + static int[] arr = {0, 0, 0, 0}; + + public static int test(int arg, int val) { + final int[] array = arg == -2 ? null : arr; + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1, 3); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4, 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_idiv.java 2016-12-07 13:52:07.681399215 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_idiv extends JTTTest { + + public static int test(int a, int b) { + return a / b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 11, 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_idiv2.java 2016-12-07 13:52:07.947410906 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_idiv2 extends JTTTest { + + public static int test(int a, int b) { + try { + return a / b; + } catch (Exception e) { + return -11; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 11, 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokespecial01.java 2016-12-07 13:52:08.211422510 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_invokespecial01 extends JTTTest { + + private static class TestClass { + @SuppressWarnings("static-method") + private boolean method() { + return true; + } + } + + private static final TestClass obj = new TestClass(); + + public static boolean test(int arg) { + TestClass object = null; + if (arg == 0) { + object = obj; + } + return object.method(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokevirtual01.java 2016-12-07 13:52:08.476434157 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_invokevirtual01 extends JTTTest { + + private static class TestClass { + public boolean method() { + return true; + } + } + + private static final TestClass obj = new TestClass(); + + public static boolean test(int arg) { + TestClass object = null; + if (arg == 0) { + object = obj; + } + return object.method(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokevirtual02.java 2016-12-07 13:52:08.744445937 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_invokevirtual02 extends JTTTest { + + private static class TestClass { + @SuppressWarnings("static-method") + public final boolean method() { + return true; + } + } + + private static final TestClass obj = new TestClass(); + + public static boolean test(int arg) { + TestClass object = null; + if (arg == 0) { + object = obj; + } + return object.method(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_irem.java 2016-12-07 13:52:09.008457540 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_irem extends JTTTest { + + public static int test(int a, int b) { + return a % b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 11, 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_laload.java 2016-12-07 13:52:09.271469100 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_laload extends JTTTest { + + static long[] arr = {0L, -1L, 4L, 1000000000000L}; + + public static long test(int arg) { + final long[] array = arg == -2 ? null : arr; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_lastore.java 2016-12-07 13:52:09.536480747 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_lastore extends JTTTest { + + static long[] arr = {0, 0, 0, 0}; + + public static long test(int arg, long val) { + final long[] array = arg == -2 ? null : arr; + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2, 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1, 3L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, 0L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4, 0L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_ldiv.java 2016-12-07 13:52:09.800492351 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_ldiv extends JTTTest { + + public static long test(long a, long b) { + return a / b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 11L, 0L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_ldiv2.java 2016-12-07 13:52:10.066504043 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_ldiv2 extends JTTTest { + + public static long test(long a, long b) { + try { + return a / b; + } catch (Exception e) { + return -11; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 11L, 0L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 11L, 1000000000000L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1000000000000L, 11L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1000000000000L, 0L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_lrem.java 2016-12-07 13:52:10.331515690 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_lrem extends JTTTest { + + public static long test(long a, long b) { + return a % b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1L, 2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 11L, 0L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_monitorenter.java 2016-12-07 13:52:10.597527382 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_monitorenter extends JTTTest { + + static DummyTestClass object = new DummyTestClass(); + + public static boolean test(boolean arg) { + final Object o = arg ? object : null; + synchronized (o) { + return arg; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", true); + } + + @Test + public void run1() throws Throwable { + runTest("test", false); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_multianewarray.java 2016-12-07 13:52:10.863539073 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_multianewarray extends JTTTest { + + @SuppressWarnings("unused") + public static int test(int a, int b) { + final DummyTestClass[][] v = new DummyTestClass[a][b]; + if (v != null) { + return a; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1, 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_newarray.java 2016-12-07 13:52:11.128550721 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_newarray extends JTTTest { + + @SuppressWarnings("all") + public static int test(int a) { + if (new boolean[a] == null) { + return -1; + } + if (new char[a] == null) { + return -1; + } + if (new float[a] == null) { + return -1; + } + if (new double[a] == null) { + return -1; + } + if (new byte[a] == null) { + return -1; + } + if (new short[a] == null) { + return -1; + } + if (new int[a] == null) { + return -1; + } + if (new long[a] == null) { + return -1; + } + + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_putfield.java 2016-12-07 13:52:11.392562324 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_putfield extends JTTTest { + + private static class TestClass { + private int field; + } + + private static TestClass object = new TestClass(); + + public static int test(int arg) { + final TestClass obj = arg == 3 ? null : object; + obj.field = arg; + return obj.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 3); + } + + @Test + public void run2() throws Throwable { + runTest("test", -4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_saload.java 2016-12-07 13:52:11.658574016 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_saload extends JTTTest { + + static short[] arr = {0, -1, 4, 10000}; + + public static short test(int arg) { + final short[] array = arg == -2 ? null : arr; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_sastore.java 2016-12-07 13:52:11.923585663 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_sastore extends JTTTest { + + static short[] arr = {0, 0, 0, 0}; + + public static short test(int arg, short val) { + final short[] array = arg == -2 ? null : arr; + array[arg] = val; + return array[arg]; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2, ((short) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1, ((short) 3)); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, ((short) 0)); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4, ((short) 0)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop01.java 2016-12-07 13:52:12.187597267 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_Loop01 extends JTTTest { + + public static int test(int arg) { + int accum = 0; + for (int i = 0; i < arg; i++) { + try { + accum += div(20, i); + } catch (ArithmeticException e) { + accum -= 100; + } + } + return accum; + } + + static int div(int a, int b) { + return a / (b % 3); + } + + @Test + public void run0() throws Throwable { + runTest("test", 4); + } + + @Test + public void run1() throws Throwable { + runTest("test", 5); + } + + @Test + public void run2() throws Throwable { + runTest("test", 6); + } + + @Test + public void run3() throws Throwable { + runTest("test", 7); + } + + @Test + public void run4() throws Throwable { + runTest("test", 30); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop02.java 2016-12-07 13:52:12.451608871 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_Loop02 extends JTTTest { + + public static int test(int arg) { + int accum = 0; + for (int i = 0; i < arg; i++) { + try { + accum += div(20, i); + } catch (IllegalArgumentException e) { + accum -= 100; + } + } + return accum; + } + + static int div(int a, int b) { + if (b % 3 == 0) { + throw new IllegalArgumentException(); + } + return a / (b % 3); + } + + @Test + public void run0() throws Throwable { + runTest("test", 4); + } + + @Test + public void run1() throws Throwable { + runTest("test", 5); + } + + @Test + public void run2() throws Throwable { + runTest("test", 6); + } + + @Test + public void run3() throws Throwable { + runTest("test", 7); + } + + @Test + public void run4() throws Throwable { + runTest("test", 30); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop03.java 2016-12-07 13:52:12.716620518 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_Loop03 extends JTTTest { + + public static int test(int arg) { + int accum = 0; + for (int i = 0; i < arg; i++) { + try { + accum += div(20, i); + } catch (Catch_Loop03_Exception1 e) { + accum -= 100; + } + } + return accum; + } + + static int div(int a, int b) { + if (b % 3 == 0) { + throw new Catch_Loop03_Exception1(); + } + return a / (b % 3); + } + + @Test + public void run0() throws Throwable { + runTest("test", 4); + } + + @Test + public void run1() throws Throwable { + runTest("test", 5); + } + + @Test + public void run2() throws Throwable { + runTest("test", 6); + } + + @Test + public void run3() throws Throwable { + runTest("test", 7); + } + + @Test + public void run4() throws Throwable { + runTest("test", 30); + } + +} + +@SuppressWarnings("serial") +class Catch_Loop03_Exception1 extends RuntimeException { +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NASE_1.java 2016-12-07 13:52:12.980632122 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NASE_1 extends JTTTest { + + @SuppressWarnings("unused") + public static int test(int a) { + try { + int[] v = new int[a]; + if (v != null) { + return v.length; + } + return -1; + } catch (NegativeArraySizeException e) { + return 100; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", -34); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 20); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NASE_2.java 2016-12-07 13:52:13.244643725 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NASE_2 extends JTTTest { + + @SuppressWarnings("unused") + public static int test(int a) { + try { + DummyTestClass[] v = new DummyTestClass[a]; + if (v != null) { + return v.length; + } + return -1; + } catch (NegativeArraySizeException e) { + return 100; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", -34); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 20); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_00.java 2016-12-07 13:52:13.509655373 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_00 extends JTTTest { + + public static int test(int a) { + int[] array = a > 0 ? new int[3] : null; + try { + return array.length; + } catch (NullPointerException npe) { + return -1; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", -3); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_01.java 2016-12-07 13:52:13.774667020 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_01 extends JTTTest { + + public static int test(int a) { + try { + if (a >= 0) { + throw new NullPointerException(); + } + } catch (NullPointerException npe) { + return a; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_02.java 2016-12-07 13:52:14.039678668 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_02 extends JTTTest { + + public static int test(int a) { + try { + throwNPE(a); + } catch (NullPointerException npe) { + return a; + } + return -1; + } + + private static void throwNPE(int a) { + if (a >= 0) { + throw new NullPointerException(); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_03.java 2016-12-07 13:52:14.306690403 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_03 extends JTTTest { + + @SuppressWarnings("all") + public static int test(int a) { + try { + if (a >= 0) { + final Object o = null; + return o.hashCode(); + } + } catch (NullPointerException npe) { + return a; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_04.java 2016-12-07 13:52:14.571702051 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_04 extends JTTTest { + + private int field = 45; + + @SuppressWarnings("all") + public static int test(int a) { + try { + if (a >= 0) { + final Catch_NPE_04 obj = null; + return obj.field; + } + } catch (NullPointerException npe) { + return a; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_05.java 2016-12-07 13:52:14.835713654 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_05 extends JTTTest { + + private int field = 45; + + public static int test(int a) { + try { + return throwNPE(a); + } catch (NullPointerException npe) { + return a; + } + } + + @SuppressWarnings("all") + private static int throwNPE(int a) { + if (a >= 0) { + final Catch_NPE_05 obj = null; + return obj.field; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_06.java 2016-12-07 13:52:15.100725302 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_06 extends JTTTest { + + public static int test(String string) { + try { + return string.hashCode(); + } catch (NullPointerException npe) { + return -1; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", ""); + } + + @Test + public void run1() throws Throwable { + runTest("test", (Object) null); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_07.java 2016-12-07 13:52:15.364736905 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_07 extends JTTTest { + + @SuppressWarnings("serial") + public static class MyThrowable extends Throwable { + } + + @SuppressWarnings("unused") + public static int foo(Throwable t) { + try { + throw t; + } catch (Throwable t1) { + if (t1 == null) { + return -1; + } + if (t1 instanceof NullPointerException) { + return 0; + } + if (t1 instanceof MyThrowable) { + return 1; + } + return -2; + } + } + + public static int test(int i) { + Throwable t = (i == 0) ? null : new MyThrowable(); + try { + return foo(t); + } catch (Throwable t1) { + return -3; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_08.java 2016-12-07 13:52:15.627748465 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_08 extends JTTTest { + + public static int test(int a) { + try { + throwNPE(a); + } catch (NullPointerException npe) { + return a; + } + return -1; + } + + @SuppressWarnings("unused") + private static void throwNPE(int a) { + throw null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_09.java 2016-12-07 13:52:15.892760112 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_09 extends JTTTest { + + public static int test(int a) { + int r = 0; + try { + r = 0; + throwNPE(a); + r = 1; + throwNPE(a - 1); + } catch (NullPointerException e) { + return r + 10; + } + return r; + } + + private static void throwNPE(int a) { + if (a == 0) { + throw null; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_10.java 2016-12-07 13:52:16.157771760 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_10 extends JTTTest { + + public static int test(int a) { + int r = 0; + try { + r = 0; + if (a == 0) { + throw null; + } + r = 1; + if (a - 1 == 0) { + throw null; + } + } catch (NullPointerException e) { + return r + 10; + } + return r; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_11.java 2016-12-07 13:52:16.421783364 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_NPE_11 extends JTTTest { + + public static int test(int a) { + int r = 0; + try { + r = 0; + throwE(a); + r = 1; + throwE(a - 1); + } catch (ArithmeticException e) { + return r + 10; + } + return r; + } + + private static int throwE(int a) { + return 1 / a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_01.java 2016-12-07 13:52:16.687795055 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_StackOverflowError_01 extends JTTTest { + + private static void recurse() { + recurse(); + } + + public static int test() throws StackOverflowError { + recurse(); + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_02.java 2016-12-07 13:52:16.950806615 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_StackOverflowError_02 extends JTTTest { + + private static void recurse() { + recurse(); + } + + public static int test() { + try { + recurse(); + } catch (StackOverflowError stackOverflowError) { + // tests that the guard page was reset and a second SOE can be handled + recurse(); + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_03.java 2016-12-07 13:52:17.216818306 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/** + * Some basic checking of the stack trace produced after a StackOverflowError. + */ +public class Catch_StackOverflowError_03 extends JTTTest { + + private static final int PASS = 0; + private static final int FAIL = 1; + + private static void recurseA() { + recurseB(); + } + + private static void recurseB() { + recurseA(); + } + + public static int test() { + try { + recurseA(); + } catch (StackOverflowError stackOverflowError) { + // Check that a method does not appear to be calling itself in the stack trace + // and check that recurse* is only called by either recurse* or test + StackTraceElement[] elements = null; + elements = stackOverflowError.getStackTrace(); + if (elements.length == 0) { + // Not much we can do about this perfectly legal situation + return PASS; + } + String lastMethodName = elements[0].getMethodName(); + for (int i = 1; i < elements.length; ++i) { + String methodName = elements[i].getMethodName(); + + // Skip top-of-stack until we find a method with name "recurse*". + if (!methodName.startsWith("recurse")) { + continue; + } + + // We reached the test method => done. + if (methodName.equals("test")) { + break; + } + + // Stack elements must alternate between recurseA and recurseB + if (lastMethodName.equals(methodName) || (!methodName.equals("recurseA") && !methodName.equals("recurseB"))) { + return FAIL; + } + + lastMethodName = methodName; + } + + return PASS; + } + + return FAIL; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two01.java 2016-12-07 13:52:17.482829997 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_Two01 extends JTTTest { + + public static String test(int arg) { + try { + throwSomething(arg); + } catch (NullPointerException e) { + return e.getClass().getName(); + } catch (ArithmeticException e) { + return e.getClass().getName(); + } + return "none"; + } + + private static void throwSomething(int arg) { + if (arg == 0) { + throw new NullPointerException(); + } + if (arg == 1) { + throw new ArithmeticException(); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two02.java 2016-12-07 13:52:17.746841601 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_Two02 extends JTTTest { + + public static String test(int arg) { + try { + throwSomething(arg + 10); + } catch (NullPointerException e) { + return e.getClass().getName(); + } catch (ArithmeticException e) { + return e.getClass().getName(); + } + return "none" + (arg + 10); + } + + private static void throwSomething(int arg) { + if (arg == 10) { + throw new NullPointerException(); + } + if (arg == 11) { + throw new ArithmeticException(); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two03.java 2016-12-07 13:52:18.011853249 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_Two03 extends JTTTest { + + public static String test(int arg) { + int r = 0; + try { + r = 1; + throwSomething(r + arg); + r = 2; + throwSomething(r + arg); + r = 3; + throwSomething(r + arg); + r = 4; + } catch (NullPointerException e) { + return e.getClass().getName() + r; + } catch (ArithmeticException e) { + return e.getClass().getName() + r; + } + return "none" + r; + } + + private static void throwSomething(int arg) { + if (arg == 5) { + throw new NullPointerException(); + } + if (arg == 6) { + throw new ArithmeticException(); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved.java 2016-12-07 13:52:18.276864896 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_Unresolved extends JTTTest { + + public static boolean executed; + + public static int test(int arg) { + executed = false; + try { + helper1(arg); + helper2(arg); + } catch (Catch_Unresolved_Exception1 e) { + return 1; + } catch (Catch_Unresolved_Exception2 e) { + return 2; + } + return 0; + } + + private static void helper1(int arg) { + if (executed) { + throw new IllegalStateException("helper1 may only be called once"); + } + executed = true; + if (arg == 1) { + throw new Catch_Unresolved_Exception1(); + } else if (arg == 2) { + throw new Catch_Unresolved_Exception2(); + } + } + + private static void helper2(int arg) { + if (arg != 0) { + throw new IllegalStateException("helper2 can only be called if arg==0"); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} + +@SuppressWarnings("serial") +class Catch_Unresolved_Exception1 extends RuntimeException { +} + +@SuppressWarnings("serial") +class Catch_Unresolved_Exception2 extends RuntimeException { +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved01.java 2016-12-07 13:52:18.540876500 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_Unresolved01 extends JTTTest { + + public static boolean executed; + + public static int test(int arg) { + executed = false; + try { + helper1(arg); + } catch (Catch_Unresolved_Exception3 e) { + return 1; + } catch (Catch_Unresolved_Exception4 e) { + return 2; + } + return 0; + } + + private static void helper1(int arg) { + if (executed) { + throw new IllegalStateException("helper1 may only be called once"); + } + executed = true; + if (arg == 1) { + throw new Catch_Unresolved_Exception3(); + } else if (arg == 2) { + throw new Catch_Unresolved_Exception4(); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} + +@SuppressWarnings("serial") +class Catch_Unresolved_Exception3 extends RuntimeException { +} + +@SuppressWarnings("serial") +class Catch_Unresolved_Exception4 extends RuntimeException { +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved02.java 2016-12-07 13:52:18.805888147 -0800 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_Unresolved02 extends JTTTest { + + public static boolean executed; + public static int value; + + public static int test(int arg) { + executed = false; + int result = 0; + try { + result = value + helper1(arg) + helper2(arg); + } catch (Catch_Unresolved02_Exception1 e) { + return 1 + result; + } catch (Catch_Unresolved02_Exception2 e) { + return 2 + result; + } + return result; + } + + private static int helper1(int arg) { + if (executed) { + throw new IllegalStateException("helper1 may only be called once"); + } + executed = true; + if (arg == 1) { + throw new Catch_Unresolved02_Exception1(); + } else if (arg == 2) { + throw new Catch_Unresolved02_Exception2(); + } + return 0; + } + + private static int helper2(int arg) { + if (arg != 0) { + throw new IllegalStateException("helper2 can only be called if arg==0"); + } + return 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} + +@SuppressWarnings("serial") +class Catch_Unresolved02_Exception1 extends RuntimeException { +} + +@SuppressWarnings("serial") +class Catch_Unresolved02_Exception2 extends RuntimeException { +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved03.java 2016-12-07 13:52:19.070899795 -0800 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Catch_Unresolved03 extends JTTTest { + + public static boolean executed; + public static int value; + + public static int test(int arg) { + executed = false; + int result = 0; + try { + result = value + helper1(arg) + helper2(arg); + } catch (Catch_Unresolved03_Exception1 e) { + if (arg == 1) { + return 1; + } + return new Catch_Unresolved03_UnresolvedClass().value(); + } + return result; + } + + private static int helper1(int arg) { + if (executed) { + throw new IllegalStateException("helper1 may only be called once"); + } + executed = true; + if (arg == 1 || arg == 2) { + throw new Catch_Unresolved03_Exception1(); + } + return 0; + } + + private static int helper2(int arg) { + if (arg != 0) { + throw new IllegalStateException("helper2 can only be called if arg==0"); + } + return 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} + +@SuppressWarnings("serial") +class Catch_Unresolved03_Exception1 extends RuntimeException { +} + +class Catch_Unresolved03_UnresolvedClass { + + public int value() { + return 2; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Locals.java 2016-12-07 13:52:19.336911486 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Except_Locals extends JTTTest { + + public static int test(String a, String b) { + int x = 0; + try { + x = 1; + a.toString(); + x = 2; + b.toString(); + } catch (NullPointerException e) { + return x; + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", null, null); + } + + @Test + public void run1() throws Throwable { + runTest("test", "", null); + } + + @Test + public void run2() throws Throwable { + runTest("test", "", ""); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized01.java 2016-12-07 13:52:19.601923134 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Except_Synchronized01 extends JTTTest { + + private static class TestClass { + final int x = 1; + + @SuppressWarnings("all") + public synchronized int test2(int i) throws Exception { + try { + TestClass object = null; + return object.x; + } catch (NullPointerException e) { + return 2; + } + } + } + + static final TestClass object = new TestClass(); + + public static int test(int i) throws Exception { + if (i == 0) { + return 0; + } + return object.test2(i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized02.java 2016-12-07 13:52:19.867934825 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Except_Synchronized02 extends JTTTest { + + private static class TestClass { + + final int x = 1; + + @SuppressWarnings("all") + public synchronized int test2(int i) throws Exception { + while (true) { + try { + TestClass object = null; + return object.x; + } catch (NullPointerException e) { + return 2; + } + } + } + } + + static final TestClass object = new TestClass(); + + public static int test(int i) throws Exception { + if (i == 0) { + return 0; + } + return object.test2(i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized03.java 2016-12-07 13:52:20.132946473 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Except_Synchronized03 extends JTTTest { + + private static class TestClass { + int x = 1; + + @SuppressWarnings("all") + public synchronized int test2(int i) throws Exception { + while (true) { + try { + synchronized (this) { + TestClass object = null; + return object.x; + } + } catch (NullPointerException e) { + return 2; + } + } + } + } + + static final TestClass object = new TestClass(); + + public static int test(int i) throws Exception { + if (i == 0) { + return 0; + } + return object.test2(i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized04.java 2016-12-07 13:52:20.395958032 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Except_Synchronized04 extends JTTTest { + + private static class TestClass { + + final int x = 1; + + @SuppressWarnings("all") + public int test2(int i) throws Exception { + try { + synchronized (Except_Synchronized04.class) { + TestClass object = null; + return object.x; + } + } catch (NullPointerException e) { + return 2; + } + } + } + + static final TestClass object = new TestClass(); + + public static int test(int i) throws Exception { + if (i == 0) { + return 0; + } + return object.test2(i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized05.java 2016-12-07 13:52:20.660969680 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Except_Synchronized05 extends JTTTest { + + static class Foo { + + Object field; + + public synchronized Object bar(int arg) { + try { + String f = foo1(arg); + if (f == null) { + field = new Object(); + } + } catch (NullPointerException e) { + // do nothing + } + return field; + } + + public Object baz(int arg) { + synchronized (this) { + try { + String f = foo1(arg); + if (f == null) { + field = new Object(); + } + } catch (NullPointerException e) { + // do nothing + } + return field; + } + } + + @SuppressWarnings("static-method") + private String foo1(int arg) { + if (arg == 0) { + throw null; + } + return null; + } + + } + + public static int test(int arg) { + Foo obj = new Foo(); + int a = obj.bar(arg) != null ? 1 : 0; + int b = obj.baz(arg) != null ? 1 : 0; + return a + b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Finally01.java 2016-12-07 13:52:20.925981328 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Finally01 extends JTTTest { + + /** + * @param arg + */ + @SuppressWarnings("finally") + public static int test(int arg) { + try { + return 0; + } finally { + return -1; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Finally02.java 2016-12-07 13:52:21.190992975 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Finally02 extends JTTTest { + + public static int test() { + try { + a(); + } finally { + b(); + } + + return c(); + } + + static int a() { + return 0; + } + + static int b() { + return -3; + } + + static int c() { + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_AIOOBE_00.java 2016-12-07 13:52:21.455004578 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class StackTrace_AIOOBE_00 extends JTTTest { + + private static int[] array = new int[3]; + + public static int test(int a) { + try { + return array[a]; + } catch (ArrayIndexOutOfBoundsException npe) { + for (StackTraceElement e : npe.getStackTrace()) { + if (e.getClassName().equals(StackTrace_AIOOBE_00.class.getName()) && e.getMethodName().equals("test")) { + return -1; + } + } + } + return -2; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_CCE_00.java 2016-12-07 13:52:21.721016270 -0800 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class StackTrace_CCE_00 extends JTTTest { + + static Object object2 = new Object(); + static Object object3 = ""; + static Object object4 = new DummyTestClass(); + + public static int test(int arg) { + Object obj = null; + if (arg == 2) { + obj = object2; + } + if (arg == 3) { + obj = object3; + } + if (arg == 4) { + obj = object4; + } + try { + final DummyTestClass bc = (DummyTestClass) obj; + if (bc == null) { + return arg; + } + return arg; + } catch (ClassCastException npe) { + for (StackTraceElement e : npe.getStackTrace()) { + if (e.getClassName().equals(StackTrace_CCE_00.class.getName()) && e.getMethodName().equals("test")) { + return -100; + } + } + return -200; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + + @Test + public void run3() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_00.java 2016-12-07 13:52:21.987027961 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class StackTrace_NPE_00 extends JTTTest { + + public static int test(int a) { + int[] array = a > 0 ? new int[3] : null; + try { + return array.length; + } catch (NullPointerException npe) { + for (StackTraceElement e : npe.getStackTrace()) { + if (e.getClassName().equals(StackTrace_NPE_00.class.getName())) { + return -1; + } + } + return -2; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", -3); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_01.java 2016-12-07 13:52:22.254039696 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class StackTrace_NPE_01 extends JTTTest { + + @SuppressWarnings("all") + public static int test(int a) { + try { + if (a >= 0) { + final Object o = null; + return o.hashCode(); + } + } catch (NullPointerException npe) { + for (StackTraceElement e : npe.getStackTrace()) { + if (e.getClassName().equals(StackTrace_NPE_01.class.getName()) && e.getMethodName().equals("test")) { + return a; + } + } + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_02.java 2016-12-07 13:52:22.519051344 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class StackTrace_NPE_02 extends JTTTest { + + private static String[] trace = {"test1", "test"}; + + public static int test(int a) { + try { + if (a >= 0) { + return test1(); + } + } catch (NullPointerException npe) { + String thisClass = StackTrace_NPE_02.class.getName(); + StackTraceElement[] stackTrace = npe.getStackTrace(); + for (int i = 0; i < stackTrace.length; i++) { + StackTraceElement e = stackTrace[i]; + if (e.getClassName().equals(thisClass)) { + for (int j = 0; j < trace.length; j++) { + StackTraceElement f = stackTrace[i + j]; + if (!f.getClassName().equals(thisClass)) { + return -2; + } + if (!f.getMethodName().equals(trace[j])) { + return -3; + } + } + return 0; + } + } + } + return -1; + } + + @SuppressWarnings("all") + private static int test1() { + final Object o = null; + return o.hashCode(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_03.java 2016-12-07 13:52:22.784062991 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class StackTrace_NPE_03 extends JTTTest { + + private static String[] trace = {"test2", "test1", "test"}; + + public static int test(int a) { + try { + if (a >= 0) { + return test1(); + } + } catch (NullPointerException npe) { + String thisClass = StackTrace_NPE_03.class.getName(); + StackTraceElement[] stackTrace = npe.getStackTrace(); + for (int i = 0; i < stackTrace.length; i++) { + StackTraceElement e = stackTrace[i]; + if (e.getClassName().equals(thisClass)) { + for (int j = 0; j < trace.length; j++) { + StackTraceElement f = stackTrace[i + j]; + if (!f.getClassName().equals(thisClass)) { + return -2; + } + if (!f.getMethodName().equals(trace[j])) { + return -3; + } + } + return 0; + } + } + } + return -1; + } + + private static int test1() { + return test2(); + } + + private static int test2() { + throw new NullPointerException(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch01.java 2016-12-07 13:52:23.049074639 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Throw_InCatch01 extends JTTTest { + + public static boolean test(int i) throws Exception { + if (i == 0) { + return true; + } + try { + throw new Exception(); + } catch (Exception e) { + throw e; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch02.java 2016-12-07 13:52:23.313086242 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Throw_InCatch02 extends JTTTest { + + public static boolean test(int i) throws Exception { + if (i == 0) { + return true; + } + try { + throwE(); + } catch (Exception e) { + throwE(e); + } + return false; + } + + private static void throwE(Exception e) throws Exception { + throw e; + } + + private static void throwE() throws Exception { + throw new Exception(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch03.java 2016-12-07 13:52:23.578097890 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Throw_InCatch03 extends JTTTest { + + public static boolean test(int i) throws Exception { + if (i == 0) { + return true; + } + try { + throwE(); + } catch (Exception e) { + throw e; + } + return false; + } + + private static void throwE() throws Exception { + throw new Exception(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InNested.java 2016-12-07 13:52:23.845109625 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Throw_InNested extends JTTTest { + + public static int test(int i) throws Exception { + return 42 + test2(i); + } + + public static int test2(int i) throws Exception { + try { + return test3(i); + } catch (Exception e) { + return 5; + } + } + + private static int test3(int i) { + if (i == 0) { + throw new RuntimeException(); + } + return i; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_NPE_01.java 2016-12-07 13:52:24.109121228 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Throw_NPE_01 extends JTTTest { + + public static int test(int i) throws Exception { + int a = test2(i); + a = a + 1; + return a; + } + + public static int test2(int i) { + if (i < 0) { + throw null; + } + return i; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized01.java 2016-12-07 13:52:24.374132876 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Throw_Synchronized01 extends JTTTest { + + public static synchronized boolean test(int i) throws Exception { + return i == 0 || test2(i); + } + + @SuppressWarnings("unused") + public static boolean test2(int i) throws Exception { + throw new Exception(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized02.java 2016-12-07 13:52:24.639144523 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Throw_Synchronized02 extends JTTTest { + + public static synchronized boolean test(int i) throws Exception { + if (i == 0) { + return true; + } + throw new Exception(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized03.java 2016-12-07 13:52:24.904156171 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Throw_Synchronized03 extends JTTTest { + + public static synchronized boolean test(int i) throws Exception { + if (i == 0) { + return true; + } + return test2(i); + } + + @SuppressWarnings("unused") + public static synchronized boolean test2(int i) throws Exception { + throw new Exception(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized04.java 2016-12-07 13:52:25.168167774 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Throw_Synchronized04 extends JTTTest { + + private static class TestClass { + @SuppressWarnings("unused") + public synchronized boolean test2(int i) throws Exception { + throw new Exception(); + } + } + + static final TestClass object = new TestClass(); + + public static boolean test(int i) throws Exception { + if (i == 0) { + return true; + } + return object.test2(i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized05.java 2016-12-07 13:52:25.434179466 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.except; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Throw_Synchronized05 extends JTTTest { + + private static class TestClass { + @SuppressWarnings("unused") + public synchronized boolean test2(int i) throws Exception { + try { + throw new Exception(); + } catch (Exception e) { + // do nothing and then rethrow + throw e; + } + } + } + + static final TestClass object = new TestClass(); + + public static boolean test(int i) throws Exception { + if (i == 0) { + return true; + } + return object.test2(i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/UntrustedInterfaces.java 2016-12-07 13:52:25.702191245 -0800 @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2014, 2014, 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.jtt.except; + +import org.junit.BeforeClass; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; +import org.graalvm.compiler.test.ExportingClassLoader; + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; + +public class UntrustedInterfaces extends JTTTest { + + public interface CallBack { + int callBack(TestInterface ti); + } + + private interface TestInterface { + int method(); + } + + /** + * What a GoodPill would look like. + * + *

    +     * private static final class GoodPill extends Pill {
    +     *     public void setField() {
    +     *         field = new TestConstant();
    +     *     }
    +     *
    +     *     public void setStaticField() {
    +     *         staticField = new TestConstant();
    +     *     }
    +     *
    +     *     public int callMe(CallBack callback) {
    +     *         return callback.callBack(new TestConstant());
    +     *     }
    +     *
    +     *     public TestInterface get() {
    +     *         return new TestConstant();
    +     *     }
    +     * }
    +     *
    +     * private static final class TestConstant implements TestInterface {
    +     *     public int method() {
    +     *         return 42;
    +     *     }
    +     * }
    +     * 
    + */ + public abstract static class Pill { + public static TestInterface staticField; + public TestInterface field; + + public abstract void setField(); + + public abstract void setStaticField(); + + public abstract int callMe(CallBack callback); + + public abstract TestInterface get(); + } + + public int callBack(TestInterface list) { + return list.method(); + } + + public int staticFieldInvoke(Pill pill) { + pill.setStaticField(); + return Pill.staticField.method(); + } + + public int fieldInvoke(Pill pill) { + pill.setField(); + return pill.field.method(); + } + + public int argumentInvoke(Pill pill) { + return pill.callMe(ti -> ti.method()); + } + + public int returnInvoke(Pill pill) { + return pill.get().method(); + } + + @SuppressWarnings("cast") + public boolean staticFieldInstanceof(Pill pill) { + pill.setStaticField(); + return Pill.staticField instanceof TestInterface; + } + + @SuppressWarnings("cast") + public boolean fieldInstanceof(Pill pill) { + pill.setField(); + return pill.field instanceof TestInterface; + } + + @SuppressWarnings("cast") + public int argumentInstanceof(Pill pill) { + return pill.callMe(ti -> ti instanceof TestInterface ? 42 : 24); + } + + @SuppressWarnings("cast") + public boolean returnInstanceof(Pill pill) { + return pill.get() instanceof TestInterface; + } + + public TestInterface staticFieldCheckcast(Pill pill) { + pill.setStaticField(); + return TestInterface.class.cast(Pill.staticField); + } + + public TestInterface fieldCheckcast(Pill pill) { + pill.setField(); + return TestInterface.class.cast(pill.field); + } + + public int argumentCheckcast(Pill pill) { + return pill.callMe(ti -> TestInterface.class.cast(ti).method()); + } + + public TestInterface returnCheckcast(Pill pill) { + return TestInterface.class.cast(pill.get()); + } + + private static Pill poisonPill; + + // Checkstyle: stop + @BeforeClass + public static void setUp() throws InstantiationException, IllegalAccessException, ClassNotFoundException { + poisonPill = (Pill) new PoisonLoader().findClass(PoisonLoader.POISON_IMPL_NAME).newInstance(); + } + + // Checkstyle: resume + + @Test + public void testStaticField0() { + runTest("staticFieldInvoke", poisonPill); + } + + @Test + public void testStaticField1() { + runTest("staticFieldInstanceof", poisonPill); + } + + @Test + public void testStaticField2() { + runTest("staticFieldCheckcast", poisonPill); + } + + @Test + public void testField0() { + runTest("fieldInvoke", poisonPill); + } + + @Test + public void testField1() { + runTest("fieldInstanceof", poisonPill); + } + + @Test + public void testField2() { + runTest("fieldCheckcast", poisonPill); + } + + @Test + public void testArgument0() { + runTest("argumentInvoke", poisonPill); + } + + @Test + public void testArgument1() { + runTest("argumentInstanceof", poisonPill); + } + + @Test + public void testArgument2() { + runTest("argumentCheckcast", poisonPill); + } + + @Test + public void testReturn0() { + runTest("returnInvoke", poisonPill); + } + + @Test + public void testReturn1() { + runTest("returnInstanceof", poisonPill); + } + + @Test + public void testReturn2() { + runTest("returnCheckcast", poisonPill); + } + + private static class PoisonLoader extends ExportingClassLoader { + public static final String POISON_IMPL_NAME = "org.graalvm.compiler.jtt.except.PoisonPill"; + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals(POISON_IMPL_NAME)) { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + + cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, POISON_IMPL_NAME.replace('.', '/'), null, Type.getInternalName(Pill.class), null); + // constructor + MethodVisitor constructor = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); + constructor.visitCode(); + constructor.visitVarInsn(Opcodes.ALOAD, 0); + constructor.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Pill.class), "", "()V", false); + constructor.visitInsn(Opcodes.RETURN); + constructor.visitMaxs(0, 0); + constructor.visitEnd(); + + MethodVisitor setList = cw.visitMethod(Opcodes.ACC_PUBLIC, "setField", "()V", null, null); + setList.visitCode(); + setList.visitVarInsn(Opcodes.ALOAD, 0); + setList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); + setList.visitInsn(Opcodes.DUP); + setList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "", "()V", false); + setList.visitFieldInsn(Opcodes.PUTFIELD, Type.getInternalName(Pill.class), "field", Type.getDescriptor(TestInterface.class)); + setList.visitInsn(Opcodes.RETURN); + setList.visitMaxs(0, 0); + setList.visitEnd(); + + MethodVisitor setStaticList = cw.visitMethod(Opcodes.ACC_PUBLIC, "setStaticField", "()V", null, null); + setStaticList.visitCode(); + setStaticList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); + setStaticList.visitInsn(Opcodes.DUP); + setStaticList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "", "()V", false); + setStaticList.visitFieldInsn(Opcodes.PUTSTATIC, Type.getInternalName(Pill.class), "staticField", Type.getDescriptor(TestInterface.class)); + setStaticList.visitInsn(Opcodes.RETURN); + setStaticList.visitMaxs(0, 0); + setStaticList.visitEnd(); + + MethodVisitor callMe = cw.visitMethod(Opcodes.ACC_PUBLIC, "callMe", Type.getMethodDescriptor(Type.INT_TYPE, Type.getType(CallBack.class)), null, null); + callMe.visitCode(); + callMe.visitVarInsn(Opcodes.ALOAD, 1); + callMe.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); + callMe.visitInsn(Opcodes.DUP); + callMe.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "", "()V", false); + callMe.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.getInternalName(CallBack.class), "callBack", Type.getMethodDescriptor(Type.INT_TYPE, Type.getType(TestInterface.class)), true); + callMe.visitInsn(Opcodes.IRETURN); + callMe.visitMaxs(0, 0); + callMe.visitEnd(); + + MethodVisitor getList = cw.visitMethod(Opcodes.ACC_PUBLIC, "get", Type.getMethodDescriptor(Type.getType(TestInterface.class)), null, null); + getList.visitCode(); + getList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); + getList.visitInsn(Opcodes.DUP); + getList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "", "()V", false); + getList.visitInsn(Opcodes.ARETURN); + getList.visitMaxs(0, 0); + getList.visitEnd(); + + cw.visitEnd(); + + byte[] bytes = cw.toByteArray(); + return defineClass(name, bytes, 0, bytes.length); + } + return super.findClass(name); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate01.java 2016-12-07 13:52:25.968202937 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_allocate01 extends JTTTest { + + public static int test(int count) { + int sum = 0; + for (int i = 0; i < count; i++) { + sum += i; + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 80); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate02.java 2016-12-07 13:52:26.232214540 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_allocate02 extends JTTTest { + + public static int test(int count) { + int sum = 0; + for (int i = 0; i < count; i++) { + final Integer j = new Integer(i); + sum += j; + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 100); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate03.java 2016-12-07 13:52:26.498226232 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_allocate03 extends JTTTest { + + public static int test(int count) { + @SuppressWarnings("unused") + final int sum = 0; + String text = ""; + for (int i = 0; i < count; i++) { + text += '.'; + } + return text.length(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 100); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate04.java 2016-12-07 13:52:26.764237923 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_allocate04 extends JTTTest { + + public static int test(int count) { + int[] a = new int[count]; + + for (int i = 0; i < a.length; i++) { + a[i] = i; + } + + int i = 0; + int iwrap = count - 1; + int sum = 0; + + while (i < count) { + sum += (a[i] + a[iwrap]) / 2; + iwrap = i; + i++; + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 80); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array01.java 2016-12-07 13:52:27.029249570 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_array01 extends JTTTest { + + public static int[] array = new int[40]; + + public static int test(int count) { + int sum = 0; + for (int i = 0; i < count; i++) { + array[i] = i; + sum += array[i]; + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 40); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array02.java 2016-12-07 13:52:27.292261130 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_array02 extends JTTTest { + + public static byte[] b = new byte[40]; + public static char[] c = new char[40]; + public static short[] s = new short[40]; + public static int[] iArray = new int[40]; + public static long[] l = new long[40]; + public static float[] f = new float[40]; + public static double[] d = new double[40]; + + public static int test(int count) { + int sum = 0; + for (int x = 0; x < count; x++) { + b[x] = (byte) x; + c[x] = (char) x; + s[x] = (short) x; + iArray[x] = x; + l[x] = x; + f[x] = x; + d[x] = x; + sum += b[x] + c[x] + s[x] + iArray[x] + l[x] + f[x] + d[x]; + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 40); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array03.java 2016-12-07 13:52:27.557272777 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_array03 extends JTTTest { + + public static byte[] b = new byte[40]; + public static char[] c = new char[40]; + + public static int test(int count) { + int sum = 0; + for (int i = 0; i < count; i++) { + sum += b.length + c.length; + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 40); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array04.java 2016-12-07 13:52:27.822284425 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_array04 extends JTTTest { + + public static byte[] b = new byte[40]; + public static char[] c = new char[40]; + + public static int test(int count) { + int sum = 0; + + for (int i = 0; i < b.length; i++) { + b[i] = (byte) i; + c[i] = (char) i; + } + + for (int j = 0; j < 10; j++) { + try { + for (int i = 0; i < count; i++) { + sum += b[i] + c[i]; + } + } catch (IndexOutOfBoundsException e) { + sum += j; + } + } + + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 80); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_control01.java 2016-12-07 13:52:28.086296028 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_control01 extends JTTTest { + + public static int test(int count) { + int i1 = 1; + int i2 = 2; + int i3 = 3; + int i4 = 4; + + for (int i = 0; i < count; i++) { + i1 = i2; + i2 = i3; + i3 = i4; + i4 = i1; + + i1 = i2; + i2 = i3; + i3 = i4; + i4 = i1; + + i1 = i2; + i2 = i3; + i3 = i4; + i4 = i1; + + i1 = i2; + i2 = i3; + i3 = i4; + i4 = i1; + } + + return i1 + i2 * 10 + i3 * 100 + i4 * 1000; + } + + @Test + public void run0() throws Throwable { + runTest("test", 40); + } + + @Test + public void run1() throws Throwable { + runTest("test", 80); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_control02.java 2016-12-07 13:52:28.351307676 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_control02 extends JTTTest { + + public static int test(int count) { + int sum = 0; + for (int i = 0; i < count; i++) { + switch (i) { + case 30: + sum += 30; + break; + case 31: + sum += 31; + break; + case 32: + sum += 32; + break; + case 33: + sum += 33; + break; + case 34: + sum += 34; + break; + case 35: + sum += 35; + break; + case 36: + sum += 36; + break; + case 37: + sum += 37; + break; + case 38: + sum += 38; + break; + case 39: + sum += 39; + break; + case 40: + sum += 40; + break; + case 41: + sum += 41; + break; + case 42: + sum += 42; + break; + default: + sum += 1; + break; + } + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 60); + } + + @Test + public void run1() throws Throwable { + runTest("test", 100); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_convert01.java 2016-12-07 13:52:28.616319323 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_convert01 extends JTTTest { + + public static int test(int count) { + double sum = 0; + for (int i = 0; i < count; i++) { + sum = (int) sum + i; + } + return (int) sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 100); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_count.java 2016-12-07 13:52:28.881330971 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Runs: 10 = 55; 20 = 210; 30 = 465; 40 = 820; + */ +@SuppressWarnings("unused") +public class HP_count extends JTTTest { + + public static int test(int count) { + float unusedFloat = 0; + double dub = 0; + int sum = 0; + double unusedDouble = 0; + for (int i = 0; i <= count; i++) { + if (i > 20) { + sum += i; + } else { + sum += i; + } + dub += sum; + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 40); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_dead01.java 2016-12-07 13:52:29.145342574 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_dead01 extends JTTTest { + + public static int test(int count) { + int sum = 0; + for (int i = 0; i <= count; i++) { + int a = i + i; + int b = i / 2 * i - 10; + @SuppressWarnings("unused") + int c = a + b; + int d = a; + sum += d; + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 10); + } + + @Test + public void run1() throws Throwable { + runTest("test", 20); + } + + @Test + public void run2() throws Throwable { + runTest("test", 30); + } + + @Test + public void run3() throws Throwable { + runTest("test", 40); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_demo01.java 2016-12-07 13:52:29.411354266 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_demo01 extends JTTTest { + + public static int test(int count) { + int sum = 0; + + for (int i = 0; i < count; i++) { + int[] ia = new int[count]; + long[] la = new long[count]; + float[] fa = new float[count]; + double[] da = new double[count]; + sum += ia[i] = (int) (la[i] = (long) (fa[i] = (float) (da[i] = i))); + } + + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 80); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field01.java 2016-12-07 13:52:29.682366176 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_field01 extends JTTTest { + + public static int a; + public static int b; + public static int c; + + public static int test(int count) { + for (int i = 0; i <= count; i++) { + if (i > 5) { + a += i; + } else if (i > 7) { + b += i; + } else { + c += i; + } + } + return a + b + c; + } + + @Override + public void before(ResolvedJavaMethod m) { + a = 0; + b = 0; + c = 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 40); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field02.java 2016-12-07 13:52:29.947377824 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Runs: 10 = 55; 20 = 210; 30 = 465; 40 = 820; + */ +public class HP_field02 extends JTTTest { + + private static class TestClass { + public int a; + public int b; + public int c; + + public int run(int count) { + for (int i = 0; i <= count; i++) { + if (i > 5) { + a += i; + } else if (i > 7) { + b += i; + } else { + c += i; + } + } + return a + b + c; + } + } + + public static int test(int count) { + return new TestClass().run(count); + } + + @Test + public void run0() throws Throwable { + runTest("test", 40); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field03.java 2016-12-07 13:52:30.211389428 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_field03 extends JTTTest { + + public static byte b; + public static char c; + public static short s; + public static int i; + public static long l; + public static float f; + public static double d; + + public static int test(int count) { + for (int x = 0; x <= count; x++) { + b += x; + c += x; + s += x; + i += x; + l += x; + f += x; + d += x; + } + return (int) (b + c + s + i + l + f + d); + } + + @Override + public void before(ResolvedJavaMethod m) { + b = 0; + c = 0; + s = 0; + i = 0; + l = 0L; + f = 0.0F; + d = 0.0D; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1000); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field04.java 2016-12-07 13:52:30.481401295 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_field04 extends JTTTest { + + private static class TestClass { + public byte b; + public char c; + public short s; + public int i; + public long l; + public float f; + public double d; + + public int run(int count) { + for (int x = 0; x <= count; x++) { + b += x; + c += x; + s += x; + i += x; + l += x; + f += x; + d += x; + } + return (int) (b + c + s + i + l + f + d); + } + } + + public static int test(int count) { + return new TestClass().run(count); + } + + @Test + public void run0() throws Throwable { + runTest("test", 40); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1000); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_idea.java 2016-12-07 13:52:30.745412898 -0800 @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop + +package org.graalvm.compiler.jtt.hotpath; + +import java.util.Random; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class HP_idea extends JTTTest { + + public boolean test() { + buildTestData(); + Do(); + return verify(); + } + + // Declare class data. Byte buffer plain1 holds the original + // data for encryption, crypt1 holds the encrypted data, and + // plain2 holds the decrypted data, which should match plain1 + // byte for byte. + + int array_rows; + + byte[] plain1; // Buffer for plaintext data. + byte[] crypt1; // Buffer for encrypted data. + byte[] plain2; // Buffer for decrypted data. + + short[] userkey; // Key for encryption/decryption. + int[] Z; // Encryption subkey (userkey derived). + int[] DK; // Decryption subkey (userkey derived). + + void Do() { + cipher_idea(plain1, crypt1, Z); // Encrypt plain1. + cipher_idea(crypt1, plain2, DK); // Decrypt. + } + + /* + * buildTestData + * + * Builds the data used for the test -- each time the test is run. + */ + + void buildTestData() { + // Create three byte arrays that will be used (and reused) for + // encryption/decryption operations. + + plain1 = new byte[array_rows]; + crypt1 = new byte[array_rows]; + plain2 = new byte[array_rows]; + + Random rndnum = new Random(136506717L); // Create random number generator. + + // Allocate three arrays to hold keys: userkey is the 128-bit key. + // Z is the set of 16-bit encryption subkeys derived from userkey, + // while DK is the set of 16-bit decryption subkeys also derived + // from userkey. NOTE: The 16-bit values are stored here in + // 32-bit int arrays so that the values may be used in calculations + // as if they are unsigned. Each 64-bit block of plaintext goes + // through eight processing rounds involving six of the subkeys + // then a final output transform with four of the keys; (8 * 6) + // + 4 = 52 subkeys. + + userkey = new short[8]; // User key has 8 16-bit shorts. + Z = new int[52]; // Encryption subkey (user key derived). + DK = new int[52]; // Decryption subkey (user key derived). + + // Generate user key randomly; eight 16-bit values in an array. + + for (int i = 0; i < 8; i++) { + // Again, the random number function returns int. Converting + // to a short type preserves the bit pattern in the lower 16 + // bits of the int and discards the rest. + + userkey[i] = (short) rndnum.nextInt(); + } + + // Compute encryption and decryption subkeys. + + calcEncryptKey(); + calcDecryptKey(); + + // Fill plain1 with "text." + for (int i = 0; i < array_rows; i++) { + plain1[i] = (byte) i; + + // Converting to a byte + // type preserves the bit pattern in the lower 8 bits of the + // int and discards the rest. + } + } + + /* + * calcEncryptKey + * + * Builds the 52 16-bit encryption subkeys Z[] from the user key and stores in 32-bit int array. + * The routing corrects an error in the source code in the Schnier book. Basically, the sense of + * the 7- and 9-bit shifts are reversed. It still works reversed, but would encrypted code would + * not decrypt with someone else's IDEA code. + */ + + private void calcEncryptKey() { + int j; // Utility variable. + + for (int i = 0; i < 52; i++) { + // Zero out the 52-int Z array. + Z[i] = 0; + } + + for (int i = 0; i < 8; i++) // First 8 subkeys are userkey itself. + { + Z[i] = userkey[i] & 0xffff; // Convert "unsigned" + // short to int. + } + + // Each set of 8 subkeys thereafter is derived from left rotating + // the whole 128-bit key 25 bits to left (once between each set of + // eight keys and then before the last four). Instead of actually + // rotating the whole key, this routine just grabs the 16 bits + // that are 25 bits to the right of the corresponding subkey + // eight positions below the current subkey. That 16-bit extent + // straddles two array members, so bits are shifted left in one + // member and right (with zero fill) in the other. For the last + // two subkeys in any group of eight, those 16 bits start to + // wrap around to the first two members of the previous eight. + + for (int i = 8; i < 52; i++) { + j = i % 8; + if (j < 6) { + Z[i] = ((Z[i - 7] >>> 9) | (Z[i - 6] << 7)) // Shift and combine. + & 0xFFFF; // Just 16 bits. + continue; // Next iteration. + } + + if (j == 6) // Wrap to beginning for second chunk. + { + Z[i] = ((Z[i - 7] >>> 9) | (Z[i - 14] << 7)) & 0xFFFF; + continue; + } + + // j == 7 so wrap to beginning for both chunks. + + Z[i] = ((Z[i - 15] >>> 9) | (Z[i - 14] << 7)) & 0xFFFF; + } + } + + /* + * calcDecryptKey + * + * Builds the 52 16-bit encryption subkeys DK[] from the encryption- subkeys Z[]. DK[] is a + * 32-bit int array holding 16-bit values as unsigned. + */ + + private void calcDecryptKey() { + int j, k; // Index counters. + int t1, t2, t3; // Temps to hold decrypt subkeys. + + t1 = inv(Z[0]); // Multiplicative inverse (mod x10001). + t2 = -Z[1] & 0xffff; // Additive inverse, 2nd encrypt subkey. + t3 = -Z[2] & 0xffff; // Additive inverse, 3rd encrypt subkey. + + DK[51] = inv(Z[3]); // Multiplicative inverse (mod x10001). + DK[50] = t3; + DK[49] = t2; + DK[48] = t1; + + j = 47; // Indices into temp and encrypt arrays. + k = 4; + for (int i = 0; i < 7; i++) { + t1 = Z[k++]; + DK[j--] = Z[k++]; + DK[j--] = t1; + t1 = inv(Z[k++]); + t2 = -Z[k++] & 0xffff; + t3 = -Z[k++] & 0xffff; + DK[j--] = inv(Z[k++]); + DK[j--] = t2; + DK[j--] = t3; + DK[j--] = t1; + } + + t1 = Z[k++]; + DK[j--] = Z[k++]; + DK[j--] = t1; + t1 = inv(Z[k++]); + t2 = -Z[k++] & 0xffff; + t3 = -Z[k++] & 0xffff; + DK[j--] = inv(Z[k++]); + DK[j--] = t3; + DK[j--] = t2; + DK[j--] = t1; + } + + /* + * cipher_idea + * + * IDEA encryption/decryption algorithm. It processes plaintext in 64-bit blocks, one at a time, + * breaking the block into four 16-bit unsigned subblocks. It goes through eight rounds of + * processing using 6 new subkeys each time, plus four for last step. The source text is in + * array text1, the destination text goes into array text2 The routine represents 16-bit + * subblocks and subkeys as type int so that they can be treated more easily as unsigned. + * Multiplication modulo 0x10001 interprets a zero sub-block as 0x10000; it must to fit in 16 + * bits. + */ + + @SuppressWarnings("static-method") + private void cipher_idea(byte[] text1, byte[] text2, int[] key) { + + int i1 = 0; // Index into first text array. + int i2 = 0; // Index into second text array. + int ik; // Index into key array. + int x1, x2, x3, x4, t1, t2; // Four "16-bit" blocks, two temps. + int r; // Eight rounds of processing. + + for (int i = 0; i < text1.length; i += 8) { + + ik = 0; // Restart key index. + r = 8; // Eight rounds of processing. + + // Load eight plain1 bytes as four 16-bit "unsigned" integers. + // Masking with 0xff prevents sign extension with cast to int. + + x1 = text1[i1++] & 0xff; // Build 16-bit x1 from 2 bytes, + x1 |= (text1[i1++] & 0xff) << 8; // assuming low-order byte first. + x2 = text1[i1++] & 0xff; + x2 |= (text1[i1++] & 0xff) << 8; + x3 = text1[i1++] & 0xff; + x3 |= (text1[i1++] & 0xff) << 8; + x4 = text1[i1++] & 0xff; + x4 |= (text1[i1++] & 0xff) << 8; + + do { + // 1) Multiply (modulo 0x10001), 1st text sub-block + // with 1st key sub-block. + + x1 = (int) ((long) x1 * key[ik++] % 0x10001L & 0xffff); + + // 2) Add (modulo 0x10000), 2nd text sub-block + // with 2nd key sub-block. + + x2 = x2 + key[ik++] & 0xffff; + + // 3) Add (modulo 0x10000), 3rd text sub-block + // with 3rd key sub-block. + + x3 = x3 + key[ik++] & 0xffff; + + // 4) Multiply (modulo 0x10001), 4th text sub-block + // with 4th key sub-block. + + x4 = (int) ((long) x4 * key[ik++] % 0x10001L & 0xffff); + + // 5) XOR results from steps 1 and 3. + + t2 = x1 ^ x3; + + // 6) XOR results from steps 2 and 4. + // Included in step 8. + + // 7) Multiply (modulo 0x10001), result of step 5 + // with 5th key sub-block. + + t2 = (int) ((long) t2 * key[ik++] % 0x10001L & 0xffff); + + // 8) Add (modulo 0x10000), results of steps 6 and 7. + + t1 = t2 + (x2 ^ x4) & 0xffff; + + // 9) Multiply (modulo 0x10001), result of step 8 + // with 6th key sub-block. + + t1 = (int) ((long) t1 * key[ik++] % 0x10001L & 0xffff); + + // 10) Add (modulo 0x10000), results of steps 7 and 9. + + t2 = t1 + t2 & 0xffff; + + // 11) XOR results from steps 1 and 9. + + x1 ^= t1; + + // 14) XOR results from steps 4 and 10. (Out of order). + + x4 ^= t2; + + // 13) XOR results from steps 2 and 10. (Out of order). + + t2 ^= x2; + + // 12) XOR results from steps 3 and 9. (Out of order). + + x2 = x3 ^ t1; + + x3 = t2; // Results of x2 and x3 now swapped. + + } while (--r != 0); // Repeats seven more rounds. + + // Final output transform (4 steps). + + // 1) Multiply (modulo 0x10001), 1st text-block + // with 1st key sub-block. + + x1 = (int) ((long) x1 * key[ik++] % 0x10001L & 0xffff); + + // 2) Add (modulo 0x10000), 2nd text sub-block + // with 2nd key sub-block. It says x3, but that is to undo swap + // of subblocks 2 and 3 in 8th processing round. + + x3 = x3 + key[ik++] & 0xffff; + + // 3) Add (modulo 0x10000), 3rd text sub-block + // with 3rd key sub-block. It says x2, but that is to undo swap + // of subblocks 2 and 3 in 8th processing round. + + x2 = x2 + key[ik++] & 0xffff; + + // 4) Multiply (modulo 0x10001), 4th text-block + // with 4th key sub-block. + + x4 = (int) ((long) x4 * key[ik++] % 0x10001L & 0xffff); + + // Repackage from 16-bit sub-blocks to 8-bit byte array text2. + + text2[i2++] = (byte) x1; + text2[i2++] = (byte) (x1 >>> 8); + text2[i2++] = (byte) x3; // x3 and x2 are switched + text2[i2++] = (byte) (x3 >>> 8); // only in name. + text2[i2++] = (byte) x2; + text2[i2++] = (byte) (x2 >>> 8); + text2[i2++] = (byte) x4; + text2[i2++] = (byte) (x4 >>> 8); + + } // End for loop. + + } // End routine. + + /* + * mul + * + * Performs multiplication, modulo (2**16)+1. This code is structured on the assumption that + * untaken branches are cheaper than taken branches, and that the compiler doesn't schedule + * branches. Java: Must work with 32-bit int and one 64-bit long to keep 16-bit values and their + * products "unsigned." The routine assumes that both a and b could fit in 16 bits even though + * they come in as 32-bit ints. Lots of "& 0xFFFF" masks here to keep things 16-bit. Also, + * because the routine stores mod (2**16)+1 results in a 2**16 space, the result is truncated to + * zero whenever the result would zero, be 2**16. And if one of the multiplicands is 0, the + * result is not zero, but (2**16) + 1 minus the other multiplicand (sort of an additive inverse + * mod 0x10001). + * + * NOTE: The java conversion of this routine works correctly, but is half the speed of using + * Java's modulus division function (%) on the multiplication with a 16-bit masking of the + * result--running in the Symantec Caje IDE. So it's not called for now; the test uses Java % + * instead. + */ + + /* + * private int mul(int a, int b) throws ArithmeticException { long p; // Large enough to catch + * 16-bit multiply // without hitting sign bit. if (a != 0) { if (b != 0) { p = (long) a * b; b + * = (int) p & 0xFFFF; // Lower 16 bits. a = (int) p >>> 16; // Upper 16 bits. + * + * return (b - a + (b < a ? 1 : 0) & 0xFFFF); } else return ((1 - a) & 0xFFFF); // If b = 0, + * then same as // 0x10001 - a. } else // If a = 0, then return return((1 - b) & 0xFFFF); // + * same as 0x10001 - b. } + */ + + /* + * inv + * + * Compute multiplicative inverse of x, modulo (2**16)+1 using extended Euclid's GCD (greatest + * common divisor) algorithm. It is unrolled twice to avoid swapping the meaning of the + * registers. And some subtracts are changed to adds. Java: Though it uses signed 32-bit ints, + * the interpretation of the bits within is strictly unsigned 16-bit. + */ + + public int inv(int x) { + int x2 = x; + int t0, t1; + int q, y; + + if (x2 <= 1) { + return (x2); // 0 and 1 are self-inverse. + } + + t1 = 0x10001 / x2; // (2**16+1)/x; x is >= 2, so fits 16 bits. + y = 0x10001 % x2; + if (y == 1) { + return ((1 - t1) & 0xFFFF); + } + + t0 = 1; + do { + q = x2 / y; + x2 = x2 % y; + t0 += q * t1; + if (x2 == 1) { + return (t0); + } + q = y / x2; + y = y % x2; + t1 += q * t0; + } while (y != 1); + + return ((1 - t1) & 0xFFFF); + } + + boolean verify() { + boolean error; + for (int i = 0; i < array_rows; i++) { + error = (plain1[i] != plain2[i]); + if (error) { + return false; + } + } + return true; + } + + /* + * freeTestData + * + * Nulls arrays and forces garbage collection to free up memory. + */ + + void freeTestData() { + plain1 = null; + crypt1 = null; + plain2 = null; + userkey = null; + Z = null; + DK = null; + } + + public HP_idea() { + array_rows = 3000; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + + @Test + public void runInv() { + runTest("inv", 724); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_inline01.java 2016-12-07 13:52:31.010424546 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_inline01 extends JTTTest { + + public static int test(int count) { + int sum = 0; + for (int i = 0; i < count; i++) { + sum += foo(i); + } + return sum; + } + + public static int foo(int x) { + if (x < 15) { + return bar(x); + } + return bar(x + 1); + } + + public static int bar(int x) { + return x + 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 20); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_inline02.java 2016-12-07 13:52:31.274436149 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_inline02 extends JTTTest { + + public static int test(int count) { + int sum = 0; + for (int i = 0; i < count; i++) { + sum += foo(i, sum); + } + return sum; + } + + public static int foo(int x, int y) { + if (x < 18) { + return bar(x, x - y); + } + return bar(x, x + y); + } + + public static int bar(int x, int y) { + if (x < 15) { + return car(x, x + y); + } + return x - 1; + } + + @SuppressWarnings("unused") + public static int car(int x, int y) { + if (x < 13) { + return x + 1; + } + return x - 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 20); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_invoke01.java 2016-12-07 13:52:31.539447796 -0800 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop + +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_invoke01 extends JTTTest { + + private static int sum; + + public static int test(int count) { + sum = 0; + final Instruction[] instructions = new Instruction[]{new Instruction.Add(), new Instruction.Sub(), new Instruction.Mul(), new Instruction.Div()}; + final Visitor v = new Visitor(); + for (int i = 0; i < count; i++) { + instructions[i % 4].accept(v); + } + return sum; + } + + public static abstract class Instruction { + + public abstract void accept(Visitor v); + + public static abstract class Binary extends Instruction { + + } + + public static class Add extends Binary { + + @Override + public void accept(Visitor v) { + v.visit(this); + } + } + + public static class Sub extends Binary { + + @Override + public void accept(Visitor v) { + v.visit(this); + } + } + + public static class Mul extends Binary { + + @Override + public void accept(Visitor v) { + v.visit(this); + } + } + + public static class Div extends Binary { + + @Override + public void accept(Visitor v) { + v.visit(this); + } + } + } + + @SuppressWarnings("unused") + public static class Visitor { + + public void visit(Instruction.Add i) { + sum += 7; + } + + public void visit(Instruction.Sub i) { + sum += 194127; + } + + public void visit(Instruction.Mul i) { + sum += 18991; + } + + public void visit(Instruction.Div i) { + sum += 91823; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 40); + } + + @Test + public void run1() throws Throwable { + runTest("test", 80); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_life.java 2016-12-07 13:52:31.806459532 -0800 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import java.util.Random; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_life extends JTTTest { + + public static int test(int generations) { + reset(); + for (int i = 0; i < generations; ++i) { + step(); + } + int sum = 0; + for (int row = 0; row < rows; ++row) { + for (int col = 0; col < cols; ++col) { + boolean value = cell(row, col); + sum += (row * 15223242 + col * 21623234) ^ ((value ? 1 : 0) * 15323142); + } + } + return sum; + } + + private static final int rows = 20; + private static final int cols = 20; + private static boolean cells[] = new boolean[rows * cols]; + + private static boolean cell(int row, int col) { + return ((row >= 0) && (row < rows) && (col >= 0) && (col < cols) && cells[row * cols + col]); + } + + private static boolean step() { + boolean next[] = new boolean[rows * cols]; + boolean changed = false; + for (int row = rows - 1; row >= 0; --row) { + int row_offset = row * cols; + for (int col = cols - 1; col >= 0; --col) { + int count = 0; + if (cell(row - 1, col - 1)) { + count++; + } + if (cell(row - 1, col)) { + count++; + } + if (cell(row - 1, col + 1)) { + count++; + } + if (cell(row, col - 1)) { + count++; + } + if (cell(row, col + 1)) { + count++; + } + if (cell(row + 1, col - 1)) { + count++; + } + if (cell(row + 1, col)) { + count++; + } + if (cell(row + 1, col + 1)) { + count++; + } + boolean old_state = cells[row_offset + col]; + boolean new_state = (!old_state && count == 3) || (old_state && (count == 2 || count == 3)); + if (!changed && new_state != old_state) { + changed = true; + } + next[row_offset + col] = new_state; + } + } + cells = next; + return changed; + } + + private static void reset() { + Random random = new Random(0); + boolean cells2[] = HP_life.cells; + for (int offset = 0; offset < cells2.length; ++offset) { + cells2[offset] = random.nextDouble() > 0.5; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_nest01.java 2016-12-07 13:52:32.071471179 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_nest01 extends JTTTest { + + public static int test(int count) { + int sum = 0; + for (int i = 0; i < count; i++) { + sum += i; + for (int j = 0; j < count; j++) { + sum += j; + } + for (int j = 0; j < count; j++) { + sum += j; + } + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 15); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_nest02.java 2016-12-07 13:52:32.335482783 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_nest02 extends JTTTest { + + public static int test(int count) { + int sum = 0; + for (int i = 0; i < count; i++) { + sum += i; + sum = foo(count, sum); + sum = foo(count, sum); + } + return sum; + } + + private static int foo(int count, int s) { + int sum = s; + for (int j = 0; j < count; j++) { + sum += j; + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 15); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_scope01.java 2016-12-07 13:52:32.599494386 -0800 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_scope01 extends JTTTest { + + public static int test(int count) { + int sum = 0; + + for (int k = 0; k < count; k++) { + { + int i = 1; + sum += i; + } + { + float f = 3; + sum += f; + } + { + long l = 7; + sum += l; + } + { + double d = 11; + sum += d; + } + } + + for (int k = 0; k < count; k++) { + if (k < 20) { + int i = 1; + sum += i; + } else { + float f = 3; + sum += f; + } + } + + for (int k = 0; k < count; k++) { + int i = 3; + for (int j = 0; j < count; j++) { + float f = 7; + sum += i + f; + } + } + + for (int k = 0; k < count; k++) { + for (int j = 0; j < count; j++) { + float f = 7; + sum += j + f; + } + int i = 3; + sum += i; + } + + return sum; + } + + @Ignore + @Test + public void run0() throws Throwable { + runTest("test", 40); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_scope02.java 2016-12-07 13:52:32.868506209 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_scope02 extends JTTTest { + + public static int test(int count) { + int sum = 0; + // Although sum is not explicitly read in the tree below it is implicitly read + // by the guard bail-out. + for (int i = 0; i < count; i++) { + if (i > 20) { + break; // We need to write back either the original value of sum, or the previous + // iteration's value. + } + sum = i; + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 40); + } + + @Test + public void run1() throws Throwable { + runTest("test", 22); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_series.java 2016-12-07 13:52:33.133517857 -0800 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop + +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_series extends JTTTest { + + public static double test(int count) { + final int arrayRows = count; + final double[][] testArray = new double[2][arrayRows]; + double omega; // Fundamental frequency. + testArray[0][0] = TrapezoidIntegrate(0.0, // Lower bound. + 2.0, // Upper bound. + 1000, // # of steps. + 0.0, // No omega*n needed. + 0) / 2.0; // 0 = term A[0]. + omega = 3.1415926535897932; + for (int i = 1; i < arrayRows; i++) { + testArray[0][i] = TrapezoidIntegrate(0.0, 2.0, 1000, omega * i, 1); // 1 = cosine + // term. + testArray[1][i] = TrapezoidIntegrate(0.0, 2.0, 1000, omega * i, 2); // 2 = sine + // term. + } + final double ref[][] = {{2.8729524964837996, 0.0}, {1.1161046676147888, -1.8819691893398025}, {0.34429060398168704, -1.1645642623320958}, {0.15238898702519288, -0.8143461113044298}}; + double error = 0.0; + double sum = 0.0; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 2; j++) { + error += Math.abs(testArray[j][i] - ref[i][j]); + sum += testArray[j][i]; + } + } + return sum + error; + } + + private static double TrapezoidIntegrate(double x0, // Lower bound. + double x1, // Upper bound. + int ns, // # of steps. + double omegan, // omega * n. + int select) // Term type. + { + int nsteps = ns; + double x; // Independent variable. + double dx; // Step size. + double rvalue; // Return value. + + x = x0; + dx = (x1 - x0) / nsteps; + rvalue = thefunction(x0, omegan, select) / 2.0; + if (nsteps != 1) { + --nsteps; // Already done 1 step. + while (--nsteps > 0) { + x += dx; + rvalue += thefunction(x, omegan, select); + } + } + rvalue = (rvalue + thefunction(x1, omegan, select) / 2.0) * dx; + return (rvalue); + } + + private static double thefunction(double x, // Independent variable. + double omegan, // Omega * term. + int select) // Choose type. + { + switch (select) { + case 0: + return (Math.pow(x + 1.0, x)); + case 1: + return (Math.pow(x + 1.0, x) * Math.cos(omegan * x)); + case 2: + return (Math.pow(x + 1.0, x) * Math.sin(omegan * x)); + } + return (0.0); + } + + /* + * This test is sensible to the implementation of Math.pow, cos and sin. Since for these + * functions, the specs says "The computed result must be within 1 ulp of the exact result", + * different implementation may return different results. The 11 ulp delta allowed for test(100) + * tries to account for that but is not guaranteed to work forever. + */ + @Ignore("failure-prone because of the variabiliy of pow/cos/sin") + @Test + public void run0() throws Throwable { + double expected = 0.6248571921291398d; + runTestWithDelta(11 * Math.ulp(expected), "test", 100); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_trees01.java 2016-12-07 13:52:33.414530207 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.hotpath; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class HP_trees01 extends JTTTest { + + public static int test(int count) { + int sum = 0; + for (int i = 0; i < count; i++) { + if (i < 100) { + sum += 1; + } else if (i < 200) { + sum += 3; + } else if (i < 300) { + sum += 5; + } else if (i < 400) { + sum += 7; + } else if (i < 500) { + sum += 11; + } + + if (i % 5 == 0) { + sum += 1; + } else if (i % 5 == 1) { + sum += 3; + } else if (i % 5 == 2) { + sum += 5; + } else if (i % 5 == 3) { + sum += 7; + } else if (i % 5 == 4) { + sum += 11; + } + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1000); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6186134.java 2016-12-07 13:52:33.678541811 -0800 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.hotspot; + +import java.util.ArrayList; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.core.common.util.ArraySet; +import org.graalvm.compiler.jtt.JTTTest; + +// @formatter:off +public class Test6186134 extends JTTTest { + + public static class TestClass { + + int num = 0; + + public TestClass(int n) { + num = n; + } + + public boolean more() { + return num-- > 0; + } + + public ArrayList test1() { + ArrayList res = new ArrayList<>(); + int maxResults = Integer.MAX_VALUE; + int n = 0; + boolean more = more(); + while ((n++ < maxResults) && more) { + res.add(new Object()); + more = more(); + } + return res; + } + + } + + public static int test(int n) { + for (int i = 0; i < n; i++) { + TestClass t = new TestClass(10); + int size = t.test1().size(); + if (size != 10) { + return 97; + } + } + return 0; + } + + @Before + public void setUp() { + /* Ensure that ArrayList is _not_ a leaf class (otherwise code installation may fail due to a failed leaf type dependency). */ + UNSAFE.ensureClassInitialized(ArraySet.class); + } + + @Test + public void run0() throws Throwable { + runTest("test", 100); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6196102.java 2016-12-07 13:52:33.942553415 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.hotspot; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/** + * @bug 6196102 + * @summary Integer seems to be greater than {@link Integer#MAX_VALUE}. + * + * @run main Test6196102 + */ +public class Test6196102 extends JTTTest { + + public static String test() { + int i1 = 0; + int i2 = Integer.MAX_VALUE; + + while (i1 >= 0) { + i1++; + if (i1 > i2) { + return "E R R O R: " + i1; + } + } + return "ok"; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6753639.java 2016-12-07 13:52:34.207565062 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.hotspot; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/** + * @test + * @bug 6753639 + * @summary Strange optimisation in for loop with cyclic integer condition + * + * @run main/othervm -Xbatch Test6753639 + */ +// @formatter:off +public class Test6753639 extends JTTTest { + + public static int test() { + int end = Integer.MAX_VALUE; + int count = 0; + for (int i = Integer.MAX_VALUE - 5; i <= end; i++) { + count++; + if (count > 100000) { + return 95; + } + } + return 97; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6823354.java 2016-12-07 13:52:34.472576709 -0800 @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.hotspot; + +//@formatter:off + +/** + * @test + * @bug 6823354 + * @summary These methods can be instrinsified by using bit scan, bit test, and population count instructions. + * + * @run main/othervm -Xcomp -XX:CompileOnly=Test6823354.lzcomp,Test6823354.tzcomp,.dolzcomp,.dotzcomp Test6823354 + */ + +import java.net.URLClassLoader; + +// Checkstyle: stop +public class Test6823354 { + // Arrays of corner case values. + static final int[] ia = new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE }; + static final long[] la = new long[] { 0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE }; + + public static void main(String[] args) throws Exception { + // Load the classes and the methods. + Integer.numberOfLeadingZeros(0); + Integer.numberOfTrailingZeros(0); + Long.numberOfLeadingZeros(0); + Long.numberOfTrailingZeros(0); + + lz(); + tz(); + } + + static void lz() throws Exception { + // int + + // Test corner cases. + for (int i = 0; i < ia.length; i++) { + int x = ia[i]; + check(x, lzcomp(x), lzint(x)); + } + + // Test all possible return values. + for (int i = 0; i < Integer.SIZE; i++) { + int x = 1 << i; + check(x, lzcomp(x), lzint(x)); + } + + String classname = Test6823354.class.getName() + "$lzconI"; + + // Test Ideal optimizations (constant values). + for (int i = 0; i < ia.length; i++) { + testclass(classname, ia[i]); + } + + // Test Ideal optimizations (constant values). + for (int i = 0; i < Integer.SIZE; i++) { + int x = 1 << i; + testclass(classname, x); + } + + + // long + + // Test corner cases. + for (int i = 0; i < ia.length; i++) { + long x = la[i]; + check(x, lzcomp(x), lzint(x)); + } + + // Test all possible return values. + for (int i = 0; i < Long.SIZE; i++) { + long x = 1L << i; + check(x, lzcomp(x), lzint(x)); + } + + classname = Test6823354.class.getName() + "$lzconL"; + + // Test Ideal optimizations (constant values). + for (int i = 0; i < la.length; i++) { + testclass(classname, la[i]); + } + + // Test Ideal optimizations (constant values). + for (int i = 0; i < Long.SIZE; i++) { + long x = 1L << i; + testclass(classname, x); + } + } + + static void tz() throws Exception { + // int + + // Test corner cases. + for (int i = 0; i < ia.length; i++) { + int x = ia[i]; + check(x, tzcomp(x), tzint(x)); + } + + // Test all possible return values. + for (int i = 0; i < Integer.SIZE; i++) { + int x = 1 << i; + check(x, tzcomp(x), tzint(x)); + } + + String classname = Test6823354.class.getName() + "$tzconI"; + + // Test Ideal optimizations (constant values). + for (int i = 0; i < ia.length; i++) { + testclass(classname, ia[i]); + } + + // Test Ideal optimizations (constant values). + for (int i = 0; i < Integer.SIZE; i++) { + int x = 1 << i; + testclass(classname, x); + } + + + // long + + // Test corner cases. + for (int i = 0; i < la.length; i++) { + long x = la[i]; + check(x, tzcomp(x), tzint(x)); + } + + // Test all possible return values. + for (int i = 0; i < Long.SIZE; i++) { + long x = 1L << i; + check(x, tzcomp(x), tzint(x)); + } + + classname = Test6823354.class.getName() + "$tzconL"; + + // Test Ideal optimizations (constant values). + for (int i = 0; i < la.length; i++) { + testclass(classname, la[i]); + } + + // Test Ideal optimizations (constant values). + for (int i = 0; i < Long.SIZE; i++) { + long x = 1L << i; + testclass(classname, x); + } + } + + static void check(int value, int result, int expected) { + if (result != expected) + throw new InternalError(value + " failed: " + result + " != " + expected); + } + + static void check(long value, long result, long expected) { + if (result != expected) + throw new InternalError(value + " failed: " + result + " != " + expected); + } + + static int lzint( int i) { return Integer.numberOfLeadingZeros(i); } + static int lzcomp(int i) { return Integer.numberOfLeadingZeros(i); } + + static int lzint( long l) { return Long.numberOfLeadingZeros(l); } + static int lzcomp(long l) { return Long.numberOfLeadingZeros(l); } + + static int tzint( int i) { return Integer.numberOfTrailingZeros(i); } + static int tzcomp(int i) { return Integer.numberOfTrailingZeros(i); } + + static int tzint( long l) { return Long.numberOfTrailingZeros(l); } + static int tzcomp(long l) { return Long.numberOfTrailingZeros(l); } + + static void testclass(String classname, int x) throws Exception { + System.setProperty("value", "" + x); + loadandrunclass(classname); + } + + static void testclass(String classname, long x) throws Exception { + System.setProperty("value", "" + x); + loadandrunclass(classname); + } + + static void loadandrunclass(String classname) throws Exception { + Class cl = Class.forName(classname); + URLClassLoader apploader = (URLClassLoader) cl.getClassLoader(); + ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent()); + Class c = loader.loadClass(classname); + Runnable r = (Runnable) c.newInstance(); + r.run(); + } + + public static class lzconI implements Runnable { + static final int VALUE; + + static { + int value = 0; + try { + value = Integer.decode(System.getProperty("value")); + } catch (Throwable e) {} + VALUE = value; + } + + @Override + public void run() { check(VALUE, lzint(VALUE), dolzcomp()); } + static int dolzcomp() { return lzcomp(VALUE); } + } + + public static class lzconL implements Runnable { + static final long VALUE; + + static { + long value = 0; + try { + value = Long.decode(System.getProperty("value")); + } catch (Throwable e) {} + VALUE = value; + } + + @Override + public void run() { check(VALUE, lzint(VALUE), dolzcomp()); } + static int dolzcomp() { return lzcomp(VALUE); } + } + + public static class tzconI implements Runnable { + static final int VALUE; + + static { + int value = 0; + try { + value = Integer.decode(System.getProperty("value")); + } catch (Throwable e) {} + VALUE = value; + } + + @Override + public void run() { check(VALUE, tzint(VALUE), dotzcomp()); } + static int dotzcomp() { return tzcomp(VALUE); } + } + + public static class tzconL implements Runnable { + static final long VALUE; + + static { + long value = 0; + try { + value = Long.decode(System.getProperty("value")); + } catch (Throwable e) {} + VALUE = value; + } + + @Override + public void run() { check(VALUE, tzint(VALUE), dotzcomp()); } + static int dotzcomp() { return tzcomp(VALUE); } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6850611.java 2016-12-07 13:52:34.736588313 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.hotspot; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +//@formatter:off + +/** + * @test + * @bug 6850611 + * @summary int / long arithmetic seems to be broken in 1.6.0_14 HotSpot Server VM (Win XP) + * + * @run main Test6850611 + */ + +public class Test6850611 extends JTTTest { + + public static int test() { + // for (int j = 0; j < 5; ++j) { + long x = 0; + for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; ++i) { + x += i; + } + if (x != -4294967295L) { + return 97; + } + // } + return 95; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6959129.java 2016-12-07 13:52:35.001599960 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.hotspot; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Test6959129 extends JTTTest { + + public static long test() { + int min = Integer.MAX_VALUE - 30000; + int max = Integer.MAX_VALUE; + return maxMoves(min, max); + } + + /** + * Imperative implementation that returns the length hailstone moves for a given number. + */ + public static long hailstoneLengthImp(long n2) { + long n = n2; + long moves = 0; + while (n != 1) { + if (n <= 1) { + throw new IllegalStateException(); + } + if (isEven(n)) { + n = n / 2; + } else { + n = 3 * n + 1; + } + ++moves; + } + return moves; + } + + private static boolean isEven(long n) { + return n % 2 == 0; + } + + /** + * Returns the maximum length of the hailstone sequence for numbers between min to max. + * + * For rec1 - Assume that min is bigger than max. + */ + public static long maxMoves(int min, int max) { + long maxmoves = 0; + for (int n = min; n <= max; n++) { + long moves = hailstoneLengthImp(n); + if (moves > maxmoves) { + maxmoves = moves; + } + } + return maxmoves; + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test7005594.java 2016-12-07 13:52:35.265611564 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.hotspot; + +//@formatter:off + +/** + * @test + * @bug 7005594 + * @summary Array overflow not handled correctly with loop optimzations + * + * @run shell Test7005594.sh + */ +public class Test7005594 { + + private static int test0(byte[] a) { + int result = 0; + for (int i = 0; i < a.length; i += ((0x7fffffff >> 1) + 1)) { + result += a[i]; + } + return result; + } + + public static int test() { + byte[] a = new byte[(0x7fffffff >> 1) + 2]; + try { + test0(a); + } catch (ArrayIndexOutOfBoundsException e) { + return 95; + } + return 97; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/CharacterBits.java 2016-12-07 13:52:35.530623211 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, 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.jtt.jdk; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class CharacterBits extends JTTTest { + @SuppressWarnings("unused") private static char init = Character.reverseBytes((char) 42); + private static char original = 0x1708; + + public static char test(char o) { + return Character.reverseBytes(o); + } + + @Test + public void run0() { + runTest("test", original); + } + + @Test + public void run1() { + runTest("test", (char) 0x1708L); + } + + @Test + public void run2() { + runTest("test", (char) 0); + runTest("test", (char) 1); + runTest("test", (char) -1); + runTest("test", (char) 0x00ff); + runTest("test", (char) 0xff00); + runTest("test", (char) 0xffff); + runTest("test", (char) 0x3fff); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Class_getName.java 2016-12-07 13:52:35.794634814 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.jdk; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Class_getName extends JTTTest { + + public static String test(int a) { + if (a == 0) { + return String.class.getName(); + } + return ""; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/DivideUnsigned.java 2016-12-07 13:52:36.059646462 -0800 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, 2015, 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.jtt.jdk; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class DivideUnsigned extends JTTTest { + + public static int divUInt(int a, int b) { + return Integer.divideUnsigned(a, b); + } + + public static int remUInt(int a, int b) { + return Integer.remainderUnsigned(a, b); + } + + public static long divULong(long a, long b) { + return Long.divideUnsigned(a, b); + } + + public static long remULong(long a, long b) { + return Long.remainderUnsigned(a, b); + } + + public void testInt(int a, int b) { + runTest("divUInt", a, b); + runTest("remUInt", a, b); + } + + public void testLong(long a, long b) { + runTest("divULong", a, b); + runTest("remULong", a, b); + } + + @Test + public void testIntPP() { + testInt(5, 2); + } + + @Test + public void testIntNP() { + testInt(-5, 2); + } + + @Test + public void testIntPN() { + testInt(5, -2); + } + + @Test + public void testIntNN() { + testInt(-5, -2); + } + + @Test + public void testLongPP() { + testLong(5, 2); + } + + @Test + public void testLongNP() { + testLong(-5, 2); + } + + @Test + public void testLongPN() { + testLong(5, -2); + } + + @Test + public void testLongNN() { + testLong(-5, -2); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/EnumMap01.java 2016-12-07 13:52:36.323658065 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.jdk; + +import java.util.EnumMap; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class EnumMap01 extends JTTTest { + + private static final EnumMap map = new EnumMap<>(Enum.class); + + static { + map.put(Enum.A, "A"); + map.put(Enum.B, "B"); + map.put(Enum.C, "C"); + } + + public static String test(int i) { + return map.get(Enum.values()[i]); + } + + private enum Enum { + A, + B, + C + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/EnumMap02.java 2016-12-07 13:52:36.588669713 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.jdk; + +import java.util.EnumMap; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class EnumMap02 extends JTTTest { + + public static String test(int i) { + EnumMap map = new EnumMap<>(Enum.class); + map.put(Enum.A, "A"); + map.put(Enum.B, "B"); + map.put(Enum.C, "C"); + return map.get(Enum.values()[i]); + } + + private enum Enum { + A, + B, + C + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/IntegerBits.java 2016-12-07 13:52:36.855681448 -0800 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2012, 2012, 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.jtt.jdk; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class IntegerBits extends JTTTest { + + @SuppressWarnings("unused") private static int init = Integer.reverseBytes(42); + private static int original = 0x01020304; + private static int v = 0b1000; + private static int zero = 0; + + public static int test(int o) { + return Integer.reverseBytes(o); + } + + public static int test2(int o) { + return Integer.numberOfLeadingZeros(o); + } + + public static int test3(int o) { + return Integer.numberOfTrailingZeros(o); + } + + public static int test4(int o) { + return Integer.bitCount(o); + } + + @Test + public void run0() { + runTest("test", original); + } + + @Test + public void run1() { + runTest("test3", v); + } + + @Test + public void run2() { + runTest("test2", v); + } + + @Test + public void run3() { + runTest("test3", zero); + } + + @Test + public void run4() { + runTest("test2", zero); + } + + @Test + public void run5() { + runTest("test", 0x01020304); + } + + @Test + public void run6() { + runTest("test3", 0b1000); + } + + @Test + public void run7() { + runTest("test2", 0b1000); + } + + @Test + public void run8() { + runTest("test3", 0); + } + + @Test + public void run9() { + runTest("test2", 0); + } + + @Test + public void run10() { + runTest("test4", 0xffffffff); + } + + @Test + public void run11() { + runTest("test2", 0xFFFFFFFF); + } + + @Test + public void run12() { + runTest("test2", 0x7FFFFFFF); + } + + @Test + public void run17() { + runTest("test2", 0x80000000); + } + + @Test + public void run18() { + runTest("test2", 0x40000000); + } + + @Test + public void run13() { + runTest("test3", 0x7FFFFFFF); + } + + @Test + public void run14() { + runTest("test3", 0xFFFFFFFF); + } + + @Test + public void run15() { + runTest("test3", 0x80000000); + } + + @Test + public void run16() { + runTest("test3", 0x40000000); + } + + @Test + public void run19() { + runTest("test4", 0x80000000); + } + + @Test + public void run20() { + runTest("test4", 0x40000000); + } + + @Test + public void run21() { + runTest("test4", 0x00000001); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/LongBits.java 2016-12-07 13:52:37.120693095 -0800 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012, 2012, 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.jtt.jdk; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class LongBits extends JTTTest { + + @SuppressWarnings("unused") private static long init = Long.reverseBytes(42); + private static long original = 0x0102030405060708L; + private static long v = 0b1000L; + private static long v2 = 0x0100000000L; + private static long zero = 0L; + + public static long test(long o) { + return Long.reverseBytes(o); + } + + public static int test2(long o) { + return Long.numberOfLeadingZeros(o); + } + + public static int test3(long o) { + return Long.numberOfTrailingZeros(o); + } + + public static int test4(long o) { + return Long.bitCount(o); + } + + @Test + public void run0() { + runTest("test", original); + } + + @Test + public void run1() { + runTest("test3", v); + } + + @Test + public void run2() { + runTest("test2", v); + } + + @Test + public void run3() { + runTest("test3", zero); + } + + @Test + public void run4() { + runTest("test2", zero); + } + + @Test + public void run5() { + runTest("test", 0x0102030405060708L); + } + + @Test + public void run6() { + runTest("test3", 0b1000L); + } + + @Test + public void run7() { + runTest("test2", 0b1000L); + } + + @Test + public void run8() { + runTest("test3", 0L); + } + + @Test + public void run9() { + runTest("test2", 0L); + } + + @Test + public void run10() { + runTest("test2", v2); + } + + @Test + public void run11() { + runTest("test3", v2); + } + + @Test + public void run12() { + runTest("test2", 0x0100000000L); + } + + @Test + public void run13() { + runTest("test3", 0x0100000000L); + } + + @Test + public void run14() { + runTest("test4", 0L); + runTest("test4", 1L); + runTest("test4", 0xffff00ffL); + runTest("test4", 0xffffffffL); + runTest("test4", 0x3ffffffffL); + runTest("test4", 0xffffffff3L); + runTest("test4", 0xffffffffffffffffL); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/ShortBits.java 2016-12-07 13:52:37.384704699 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, 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.jtt.jdk; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class ShortBits extends JTTTest { + @SuppressWarnings("unused") private static short init = Short.reverseBytes((short) 42); + private static short original = 0x1708; + + public static short test(short o) { + return Short.reverseBytes(o); + } + + @Test + public void run0() { + runTest("test", original); + } + + @Test + public void run1() { + runTest("test", (short) 0x1708L); + } + + @Test + public void run2() { + runTest("test", (short) 0); + runTest("test", (short) 1); + runTest("test", (short) -1); + runTest("test", (short) 0x00ff); + runTest("test", (short) 0xff00); + runTest("test", (short) 0xffff); + runTest("test", (short) 0x3fff); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_currentTimeMillis01.java 2016-12-07 13:52:37.650716390 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.jdk; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class System_currentTimeMillis01 extends JTTTest { + + public static int test() { + long start = System.currentTimeMillis(); + for (int i = 0; i < 10000000; i++) { + if (System.currentTimeMillis() - start > 0) { + return 1; + } + } + return 0; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_currentTimeMillis02.java 2016-12-07 13:52:37.914727994 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.jdk; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class System_currentTimeMillis02 extends JTTTest { + + static void m(long[] times) { + times[1] = System.currentTimeMillis() - times[0]; + } + + public static boolean test() { + long[] times = new long[2]; // { start, delta } + times[0] = System.currentTimeMillis(); + times[1] = 0; + // force compilation: + for (int i = 0; i < 5000; i++) { + m(times); + } + times[0] = System.currentTimeMillis(); + times[1] = 0; + for (int i = 0; times[1] == 0 && i < 5000000; i++) { + m(times); + // do nothing. + } + // better get at least 100 millisecond resolution. + return times[1] >= 1 && times[1] < 100; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_nanoTime01.java 2016-12-07 13:52:38.179739641 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.jdk; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class System_nanoTime01 extends JTTTest { + + public static int test() { + long start = System.nanoTime(); + for (int i = 0; i < 10000000; i++) { + if (System.nanoTime() - start > 0) { + return 1; + } + } + return 0; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_nanoTime02.java 2016-12-07 13:52:38.444751288 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.jdk; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class System_nanoTime02 extends JTTTest { + + public static boolean test() { + long minDelta = Long.MAX_VALUE; + + // the first call to System.nanoTime might take a long time due to call resolution + for (int c = 0; c < 10; c++) { + long start = System.nanoTime(); + long delta = 0; + int i; + for (i = 0; delta == 0 && i < 50000; i++) { + delta = System.nanoTime() - start; + // do nothing. + } + if (delta < minDelta) { + minDelta = delta; + } + } + + // better get at least 30 microsecond resolution. + return minDelta > 1 && minDelta < 30000; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_setOut.java 2016-12-07 13:52:38.708762892 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.jdk; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class System_setOut extends JTTTest { + + public static int test(int n) throws Exception { + PrintStream oldOut = System.out; + int sum = 0; + for (int i = 0; i < 10; i++) { + ByteArrayOutputStream ba = new ByteArrayOutputStream(n * 10); + PrintStream newOut = new PrintStream(ba); + System.setOut(newOut); + doPrint(n); + sum += ba.size(); + } + + System.setOut(oldOut); + return sum; + } + + private static void doPrint(int n) { + PrintStream out = System.out; + for (int i = 0; i < n; i++) { + out.print('x'); + } + } + + public static void main(String[] args) throws Exception { + PrintStream out = System.out; + out.println(test(10000)); + } + + @Test + public void run0() throws Throwable { + runTest("test", 10000); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Thread_setName.java 2016-12-07 13:52:38.972774495 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.jdk; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Thread_setName extends JTTTest { + + public static String test(String name) { + String oldName = Thread.currentThread().getName(); + Thread.currentThread().setName(name); + String name2 = Thread.currentThread().getName(); + Thread.currentThread().setName(oldName); + return name2; + } + + @Test + public void run0() throws Throwable { + runTest("test", "abc"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/UnsafeAccess01.java 2016-12-07 13:52:39.236786099 -0800 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.jdk; + +import java.lang.reflect.Field; + +import org.junit.Test; + +import sun.misc.Unsafe; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class UnsafeAccess01 extends JTTTest { + + private static int randomValue = 100; + private static final Unsafe unsafe; + private static final long offset; + private static Object staticObject = new TestClass(); + + static { + unsafe = getUnsafe(); + Field field = null; + try { + field = TestClass.class.getDeclaredField("field"); + } catch (NoSuchFieldException e) { + } catch (SecurityException e) { + } + offset = unsafe.objectFieldOffset(field); + } + + private static class TestClass { + private int field = 42; + } + + public static int test() { + final TestClass object = new TestClass(); + final int value = unsafe.getInt(object, offset); + return value; + } + + static Unsafe getUnsafe() { + try { + final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + return (Unsafe) unsafeField.get(null); + } catch (Exception e) { + throw new Error(e); + } + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + + @Test + public void runDiamond() throws Throwable { + runTest("testDiamond"); + } + + public static int testDiamond() { + + final Object object = staticObject; + final int oldValue = ((TestClass) object).field; + + if (randomValue == 100) { + unsafe.putInt(object, offset, 41); + } else { + unsafe.putInt(object, offset, 40); + } + unsafe.putInt(object, offset, 42); + return oldValue; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/UnsafeAllocateInstance01.java 2016-12-07 13:52:39.501797746 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.jdk; + +import java.util.AbstractList; +import java.util.List; + +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/* + */ +public class UnsafeAllocateInstance01 extends JTTTest { + + int field01 = 42; + + public static int testInstance() throws SecurityException, InstantiationException { + UnsafeAllocateInstance01 newObject = (UnsafeAllocateInstance01) UNSAFE.allocateInstance(UnsafeAllocateInstance01.class); + return newObject.field01; + } + + public static void testClassForException(Class clazz) throws SecurityException, InstantiationException { + UNSAFE.allocateInstance(clazz); + } + + @Override + protected Result executeExpected(ResolvedJavaMethod method, Object receiver, Object... args) { + if (args.length == 1) { + /* + * HotSpot will crash if the C2 intrinsic for this is used with array classes, so just + * handle it explicitly so that we can still exercise Graal. + */ + Class cl = (Class) args[0]; + if (cl.isArray()) { + return new Result(null, new InstantiationException(cl.getName())); + } + } + return super.executeExpected(method, receiver, args); + } + + @Test + public void run0() throws Throwable { + runTest("testInstance"); + } + + @Test + public void run1() throws Throwable { + runTest("testClassForException", UnsafeAllocateInstance01[].class); + } + + @Test + public void run7() throws Throwable { + runTest("testClassForException", UnsafeAllocateInstance01.class); + } + + @Test + public void run2() throws Throwable { + runTest("testClassForException", AbstractList.class); + } + + @Test + public void run3() throws Throwable { + runTest("testClassForException", List.class); + } + + @Test + public void run4() throws Throwable { + runTest("testClassForException", Class.class); + } + + @Ignore("Currently crashes hotspot because primitive classes aren't handled") + @Test + public void run5() throws Throwable { + runTest("testClassForException", void.class); + } + + @Ignore("Currently crashes hotspot because primitive classes aren't handled") + @Test + public void run6() throws Throwable { + runTest("testClassForException", int.class); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Unsafe_compareAndSwap.java 2016-12-07 13:52:39.766809393 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.jdk; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Test; + +import sun.misc.Unsafe; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Unsafe_compareAndSwap extends JTTTest { + + static final Unsafe unsafe = UnsafeAccess01.getUnsafe(); + static final long valueOffset; + static { + try { + valueOffset = unsafe.objectFieldOffset(Unsafe_compareAndSwap.class.getDeclaredField("value")); + } catch (Exception ex) { + throw new Error(ex); + } + } + + public static String test(Unsafe_compareAndSwap u, Object o, String expected, String newValue) { + // First arg is not an array - can use a field write barrier + unsafe.compareAndSwapObject(u, valueOffset, expected, newValue); + // Not known if first arg is an array - different write barrier may be used + unsafe.compareAndSwapObject(o, valueOffset, expected, newValue); + + return instance.value; + } + + private String value; + + private static final Unsafe_compareAndSwap instance = new Unsafe_compareAndSwap(); + + @Override + protected void before(ResolvedJavaMethod m) { + instance.value = "a"; + } + + @Test + public void run0() throws Throwable { + runTest("test", instance, instance, "a", "b"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Unsafe_compareAndSwapNullCheck.java 2016-12-07 13:52:40.030820997 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008, 2014, 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.jtt.jdk; + +import org.junit.Test; + +import sun.misc.Unsafe; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Unsafe_compareAndSwapNullCheck extends JTTTest { + + static final Unsafe unsafe = UnsafeAccess01.getUnsafe(); + static final long valueOffset; + static { + try { + valueOffset = unsafe.objectFieldOffset(Unsafe_compareAndSwap.class.getDeclaredField("value")); + } catch (Exception ex) { + throw new Error(ex); + } + } + + long value; + long lng; + + public static void test(Unsafe_compareAndSwapNullCheck u, long expected, long newValue) { + @SuppressWarnings("unused") + long l = u.lng; + unsafe.compareAndSwapLong(u, valueOffset, expected, newValue); + } + + @Test + public void run0() throws Throwable { + runTest(EMPTY, false, true, "test", null, 1L, 2L); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Boxed_TYPE_01.java 2016-12-07 13:52:40.296832688 -0800 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Boxed_TYPE_01 extends JTTTest { + + public static String test(int i) { + if (i == 0) { + return Boolean.TYPE.getName(); + } + if (i == 1) { + return Byte.TYPE.getName(); + } + if (i == 2) { + return Character.TYPE.getName(); + } + if (i == 3) { + return Double.TYPE.getName(); + } + if (i == 4) { + return Float.TYPE.getName(); + } + if (i == 5) { + return Integer.TYPE.getName(); + } + if (i == 6) { + return Long.TYPE.getName(); + } + if (i == 7) { + return Short.TYPE.getName(); + } + if (i == 8) { + return Void.TYPE.getName(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Bridge_method01.java 2016-12-07 13:52:40.561844335 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Bridge_method01 extends JTTTest { + + private abstract static class Wrap { + + abstract T get(); + } + + private static class IWrap extends Wrap { + + @Override + Integer get() { + return 1; + } + } + + private static Wrap wrapped = new IWrap(); + + public static int test() { + return wrapped.get(); + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/ClassLoader_loadClass01.java 2016-12-07 13:52:40.826855983 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.lang; + +import java.net.URL; +import java.net.URLClassLoader; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public final class ClassLoader_loadClass01 extends JTTTest { + + public static String test(int i) throws ClassNotFoundException { + final URLClassLoader classLoader = new URLClassLoader(new URL[0], String.class.getClassLoader()); + if (i == 0) { + return classLoader.loadClass("java.lang.String").toString(); + } else if (i == 1) { + return classLoader.loadClass("[Ljava.lang.String;").toString(); + } else if (i == 2) { + return classLoader.loadClass("java.lang.String[]").toString(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_Literal01.java 2016-12-07 13:52:41.090867586 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_Literal01 extends JTTTest { + + public static String test(int i) { + if (i == 0) { + return Object.class.toString(); + } + if (i == 1) { + return String.class.toString(); + } + if (i == 2) { + return Class.class.toString(); + } + if (i == 3) { + return Class_Literal01.class.toString(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_asSubclass01.java 2016-12-07 13:52:41.356879278 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_asSubclass01 extends JTTTest { + + public static int test(int i) { + if (i == 0) { + if (Object.class.asSubclass(String.class) == null) { + return -1; + } + } + if (i == 1) { + if (String.class.asSubclass(Object.class) == null) { + return -1; + } + } + if (i == 2) { + if (Object.class.asSubclass(Class_asSubclass01.class) == null) { + return -1; + } + } + if (i == 3) { + if (Class_asSubclass01.class.asSubclass(Object.class) == null) { + return -1; + } + } + return i; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_cast01.java 2016-12-07 13:52:41.620890881 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_cast01 extends JTTTest { + + static final String string = ""; + static final Object object = new Object(); + static final DummyTestClass thisObject = new DummyTestClass(); + + public static int test(int i) { + if (i == 0) { + if (Object.class.cast(string) == null) { + return -1; + } + } + if (i == 1) { + if (String.class.cast(object) == null) { + return -1; + } + } + if (i == 2) { + if (Object.class.cast(thisObject) == null) { + return -1; + } + } + if (i == 3) { + if (DummyTestClass.class.cast(object) == null) { + return -1; + } + } + return i; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + + @Test + public void run3() throws Throwable { + runTest("test", 2); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_cast02.java 2016-12-07 13:52:41.885902528 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_cast02 extends JTTTest { + + static final String string = ""; + static final Object object = new Object(); + static final DummyTestClass thisObject = new DummyTestClass(); + + public static int test(int i) { + if (i == 0) { + if (Object.class.cast(null) == null) { + return -1; + } + } + if (i == 1) { + if (String.class.cast(null) == null) { + return -1; + } + } + if (i == 2) { + if (Object.class.cast(null) == null) { + return -1; + } + } + if (i == 3) { + if (DummyTestClass.class.cast(null) == null) { + return -1; + } + } + return i; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName01.java 2016-12-07 13:52:42.150914176 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_forName01 extends JTTTest { + + public static String test(int i) throws ClassNotFoundException { + if (i == 0) { + return Class.forName("java.lang.Object").toString(); + } + if (i == 1) { + return Class.forName("java.lang.String").toString(); + } + if (i == 2) { + return Class.forName("org.graalvm.compiler.jtt.lang.Class_forName01").toString(); + } + if (i == 3) { + return Class.forName("xyxzz.xyzyzyz.XXYYY").toString(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName02.java 2016-12-07 13:52:42.415925823 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_forName02 extends JTTTest { + + public static String test(int i) throws ClassNotFoundException { + String clname = null; + Class cl = null; + if (i == 0) { + clname = "java.lang.Object"; + cl = Object.class; + } else if (i == 1) { + clname = "java.lang.String"; + cl = String.class; + } else if (i == 2) { + clname = "org.graalvm.compiler.jtt.lang.Class_forName02"; + cl = Class_forName02.class; + } else if (i == 3) { + clname = "xyzz.zyxy.XYXY"; + cl = Class_forName02.class; + } + if (clname != null) { + return Class.forName(clname, false, cl.getClassLoader()).toString(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName03.java 2016-12-07 13:52:42.679937426 -0800 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import java.net.URL; +import java.net.URLClassLoader; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public final class Class_forName03 extends JTTTest { + + public static String test(int i) throws ClassNotFoundException { + String clname = null; + Class cl = null; + if (i == 0) { + clname = "java.lang.Object[]"; + cl = Object.class; + } else if (i == 1) { + clname = "[Ljava.lang.String;"; + cl = String.class; + } else if (i == 2) { + clname = "[Ljava/lang/String;"; + cl = String.class; + } else if (i == 3) { + clname = "[I"; + cl = Class_forName03.class; + } else if (i == 4) { + clname = "[java.lang.Object;"; + cl = Class_forName03.class; + } + if (clname != null) { + return Class.forName(clname, false, new URLClassLoader(new URL[0], cl.getClassLoader())).toString(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName04.java 2016-12-07 13:52:42.943949030 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public final class Class_forName04 extends JTTTest { + + public static String test(int i) throws ClassNotFoundException { + String clname = null; + if (i == 0) { + clname = "java.lang.Object[]"; + } else if (i == 1) { + clname = "[Ljava.lang.String;"; + } else if (i == 2) { + clname = "[Ljava/lang/String;"; + } else if (i == 3) { + clname = "[I"; + } else if (i == 4) { + clname = "[java.lang.Object;"; + } + if (clname != null) { + return Class.forName(clname).toString(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName05.java 2016-12-07 13:52:43.209960721 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.lang; + +import java.net.URL; +import java.net.URLClassLoader; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public final class Class_forName05 extends JTTTest { + + public static String test(int i) throws ClassNotFoundException { + final URLClassLoader classLoader = new URLClassLoader(new URL[0], String.class.getClassLoader()); + if (i == 0) { + return Class.forName("java.lang.String", false, classLoader).toString(); + } else if (i == 1) { + return Class.forName("[Ljava.lang.String;", false, classLoader).toString(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getComponentType01.java 2016-12-07 13:52:43.472972281 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_getComponentType01 extends JTTTest { + + public static String test(int i) { + Class cl = Object.class; + if (i == 0) { + cl = int.class; + } else if (i == 1) { + cl = int[].class; + } else if (i == 2) { + cl = Object.class; + } else if (i == 3) { + cl = Object[].class; + } else if (i == 4) { + cl = Class_getComponentType01.class; + } else if (i == 5) { + cl = Cloneable.class; + } else if (i == 6) { + cl = Object[][].class; + } else if (i == 7) { + cl = void.class; + } + cl = cl.getComponentType(); + if (cl == null) { + return null; + } + return cl.getName(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getInterfaces01.java 2016-12-07 13:52:43.736983884 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010, 2014, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public final class Class_getInterfaces01 extends JTTTest { + + public static Class[] test(Class clazz) { + return clazz.getInterfaces(); + } + + interface I1 { + + } + + interface I2 extends I1 { + + } + + static class C1 implements I1 { + + } + + static class C2 implements I2 { + + } + + static class C12 implements I1, I2 { + + } + + @Test + public void run0() throws Throwable { + runTest("test", I1.class); + } + + @Test + public void run1() throws Throwable { + runTest("test", I2.class); + } + + @Test + public void run2() throws Throwable { + runTest("test", C1.class); + } + + @Test + public void run3() throws Throwable { + runTest("test", C2.class); + } + + @Test + public void run4() throws Throwable { + runTest("test", C12.class); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getModifiers01.java 2016-12-07 13:52:44.000995487 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.lang; + +import java.io.Serializable; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_getModifiers01 extends JTTTest { + + private static class PrivateStatic { + } + + private static final class PrivateStaticFinal { + } + + private static class Private { + } + + public static int test(Class c) { + return c.getModifiers(); + } + + @Test + public void run0() throws Throwable { + runTest("test", Object.class); + runTest("test", Object[].class); + } + + @Test + public void run1() throws Throwable { + runTest("test", Serializable.class); + runTest("test", Serializable[].class); + } + + @Test + public void run2() throws Throwable { + runTest("test", void.class); + } + + @Test + public void run3() throws Throwable { + runTest("test", int.class); + runTest("test", int[].class); + } + + @Test + public void run4() throws Throwable { + runTest("test", Private.class); + runTest("test", Private[].class); + } + + @Test + public void run5() throws Throwable { + runTest("test", PrivateStatic.class); + runTest("test", PrivateStatic[].class); + } + + @Test + public void run6() throws Throwable { + runTest("test", PrivateStaticFinal.class); + runTest("test", PrivateStaticFinal[].class); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getModifiers02.java 2016-12-07 13:52:44.266007135 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_getModifiers02 extends JTTTest { + + public static int test(int i) { + if (i == 0) { + return int.class.getModifiers(); + } + if (i == 1) { + return int[].class.getModifiers(); + } + if (i == 2) { + return Object[][].class.getModifiers(); + } + return Class_getModifiers02.class.getModifiers(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getName01.java 2016-12-07 13:52:44.530018738 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_getName01 extends JTTTest { + + public static String test(int i) { + if (i == 0) { + return Object.class.getName(); + } else if (i == 1) { + return Class.class.getName(); + } else if (i == 2) { + return Class_getName01.class.getName(); + } else if (i == 3) { + return "a string".getClass() == String.class ? "true" : "false"; + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getName02.java 2016-12-07 13:52:44.794030342 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_getName02 extends JTTTest { + + public static String test(int i) { + if (i == 0) { + return int.class.getName(); + } + if (i == 1) { + return int[].class.getName(); + } + if (i == 2) { + return Object[][].class.getName(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSimpleName01.java 2016-12-07 13:52:45.058041945 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +/* + */ +package org.graalvm.compiler.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_getSimpleName01 extends JTTTest { + + public static String test(int i) { + if (i == 0) { + return Object.class.getSimpleName(); + } + if (i == 1) { + return Class.class.getSimpleName(); + } + if (i == 2) { + return Class_getSimpleName01.class.getSimpleName(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSimpleName02.java 2016-12-07 13:52:45.322053548 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +/* + */ +package org.graalvm.compiler.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_getSimpleName02 extends JTTTest { + + public static String test(int i) { + if (i == 0) { + return int.class.getSimpleName(); + } + if (i == 1) { + return int[].class.getSimpleName(); + } + if (i == 2) { + return Object[][].class.getSimpleName(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSuperClass01.java 2016-12-07 13:52:45.589065284 -0800 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_getSuperClass01 extends JTTTest { + + public static String test(int i) { + Class cl = Object.class; + if (i == 0) { + cl = int.class; + } else if (i == 1) { + cl = Object.class; + } else if (i == 2) { + cl = int[].class; + } else if (i == 3) { + cl = Cloneable.class; + } else if (i == 4) { + cl = Integer.class; + } else if (i == 5) { + cl = Class.class; + } else if (i == 6) { + cl = Class_getSuperClass01.class; + } + cl = cl.getSuperclass(); + if (cl == null) { + return null; + } + return cl.getName(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isArray01.java 2016-12-07 13:52:45.855076975 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isArray01 extends JTTTest { + + public static boolean test(int i) { + if (i == 0) { + return int.class.isArray(); + } + if (i == 1) { + return int[].class.isArray(); + } + if (i == 2) { + return Object.class.isArray(); + } + if (i == 3) { + return Object[].class.isArray(); + } + if (i == 4) { + return Class_isArray01.class.isArray(); + } + if (i == 5) { + return Cloneable.class.isArray(); + } + if (i == 6) { + return Runnable.class.isArray(); + } + if (i == 7) { + return void.class.isArray(); + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom01.java 2016-12-07 13:52:46.119088578 -0800 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isAssignableFrom01 extends JTTTest { + + public static boolean test(int i) { + Class source = Object.class; + if (i == 0) { + source = int.class; + } + if (i == 1) { + source = int[].class; + } + if (i == 2) { + source = float.class; + } + if (i == 3) { + source = byte.class; + } + if (i == 4) { + source = Runnable.class; + } + if (i == 5) { + source = Class_isAssignableFrom01.class; + } + if (i == 6) { + source = Object[].class; + } + return int.class.isAssignableFrom(source); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom02.java 2016-12-07 13:52:46.385100270 -0800 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isAssignableFrom02 extends JTTTest { + + public static boolean test(int i) { + Class source = Object.class; + if (i == 0) { + source = int.class; + } + if (i == 1) { + source = int[].class; + } + if (i == 2) { + source = float.class; + } + if (i == 3) { + source = byte.class; + } + if (i == 4) { + source = Runnable.class; + } + if (i == 5) { + source = Class_isAssignableFrom02.class; + } + if (i == 6) { + source = Object[].class; + } + return Object.class.isAssignableFrom(source); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom03.java 2016-12-07 13:52:46.650111917 -0800 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isAssignableFrom03 extends JTTTest implements Cloneable { + + public static boolean test(int i) { + Class source = Object.class; + if (i == 0) { + source = int.class; + } + if (i == 1) { + source = int[].class; + } + if (i == 2) { + source = float.class; + } + if (i == 3) { + source = Cloneable.class; + } + if (i == 4) { + source = Runnable.class; + } + if (i == 5) { + source = Class_isAssignableFrom03.class; + } + if (i == 6) { + source = Object[].class; + } + return Cloneable.class.isAssignableFrom(source); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance01.java 2016-12-07 13:52:46.915123564 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isInstance01 extends JTTTest { + + static final String string = ""; + static final Object obj = new Object(); + static final DummyTestClass thisObject = new DummyTestClass(); + + public static boolean test(int i) { + Object object = null; + if (i == 0) { + object = obj; + } + if (i == 1) { + object = string; + } + if (i == 2) { + object = thisObject; + } + return Object.class.isInstance(object); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance02.java 2016-12-07 13:52:47.179135168 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isInstance02 extends JTTTest { + + static final String string = ""; + static final Object obj = new Object(); + static final DummyTestClass thisObject = new DummyTestClass(); + + public static boolean test(int i) { + Object object = null; + if (i == 0) { + object = obj; + } + if (i == 1) { + object = string; + } + if (i == 2) { + object = thisObject; + } + return String.class.isInstance(object); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance03.java 2016-12-07 13:52:47.443146771 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isInstance03 extends JTTTest { + + static final String string = ""; + static final Object obj = new Object(); + static final DummyTestClass thisObject = new DummyTestClass(); + + public static boolean test(int i) { + Object object = null; + if (i == 0) { + object = obj; + } + if (i == 1) { + object = string; + } + if (i == 2) { + object = thisObject; + } + return DummyTestClass.class.isInstance(object); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance04.java 2016-12-07 13:52:47.708158418 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isInstance04 extends JTTTest { + + static final String string = ""; + static final Object[] oarray = {}; + static final String[] sarray = {}; + + public static boolean test(int i) { + Object object = null; + if (i == 0) { + object = oarray; + } + if (i == 1) { + object = string; + } + if (i == 2) { + object = sarray; + } + return String[].class.isInstance(object); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance05.java 2016-12-07 13:52:47.972170022 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isInstance05 extends JTTTest { + + static final String string = ""; + static final Object obj = new Object(); + static final int[] array = {}; + + public static boolean test(int i) { + Object object = null; + if (i == 0) { + object = obj; + } + if (i == 1) { + object = string; + } + if (i == 2) { + object = array; + } + return int[].class.isInstance(object); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance06.java 2016-12-07 13:52:48.238181713 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isInstance06 extends JTTTest { + + private static class TestClass implements Cloneable { + } + + static final String string = ""; + static final Object obj = new Object(); + static final String[] sarray = {}; + static final Object thisObject = new TestClass(); + + public static boolean test(int i) { + Object object = null; + if (i == 0) { + object = obj; + } + if (i == 1) { + object = string; + } + if (i == 2) { + object = sarray; + } + if (i == 3) { + object = thisObject; + } + return Cloneable.class.isInstance(object); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance07.java 2016-12-07 13:52:48.504193404 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isInstance07 extends JTTTest { + + static final String string = ""; + static final Object obj = new Object(); + static final String[] sarray = {}; + static final Object thisObject = new DummyTestClass(); + + public static boolean test(int i, Class c) { + Object object = null; + if (i == 0) { + object = obj; + } + if (i == 1) { + object = string; + } + if (i == 2) { + object = thisObject; + } + return c.isInstance(object); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, String.class); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, String.class); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, String.class); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, String.class); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInterface01.java 2016-12-07 13:52:48.769205052 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isInterface01 extends JTTTest { + + public static boolean test(int i) { + if (i == 0) { + return int.class.isInterface(); + } + if (i == 1) { + return int[].class.isInterface(); + } + if (i == 2) { + return Object.class.isInterface(); + } + if (i == 3) { + return Object[].class.isInterface(); + } + if (i == 4) { + return Class_isInterface01.class.isInterface(); + } + if (i == 5) { + return Cloneable.class.isInterface(); + } + if (i == 6) { + return Runnable.class.isInterface(); + } + if (i == 7) { + return void.class.isInterface(); + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isPrimitive01.java 2016-12-07 13:52:49.034216699 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_isPrimitive01 extends JTTTest { + + public static boolean test(int i) { + if (i == 0) { + return int.class.isPrimitive(); + } + if (i == 1) { + return int[].class.isPrimitive(); + } + if (i == 2) { + return Object.class.isPrimitive(); + } + if (i == 3) { + return Object[].class.isPrimitive(); + } + if (i == 4) { + return Class_isPrimitive01.class.isPrimitive(); + } + if (i == 5) { + return Cloneable.class.isPrimitive(); + } + if (i == 6) { + return Runnable.class.isPrimitive(); + } + if (i == 7) { + return void.class.isPrimitive(); + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_01.java 2016-12-07 13:52:49.298228302 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Double_01 extends JTTTest { + + public static boolean test() { + return Double.doubleToLongBits(Double.longBitsToDouble(0x7ff8000000000088L)) == 0x7ff8000000000000L; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_conditional.java 2016-12-07 13:52:49.563239950 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.bytecode.BC_double_base; + +public final class Double_conditional extends BC_double_base { + + public static double test(double x, double y) { + if (x == y) { + return y; + } + return x; + } + + public static double conditional(double x, double y) { + return x == y ? x : y; + } + + @Test + public void runEquals() throws Throwable { + runTest("test", x, y); + } + + @Test + public void runConditional() throws Throwable { + runTest("conditional", x, y); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_toString.java 2016-12-07 13:52:49.828251597 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public final class Double_toString extends JTTTest { + + public static String test() { + double z1 = 0.4363485526704198; + double z2 = -0.43536514763046896; + double z3 = z1 + z2; + return Double.toString(z3); + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_01.java 2016-12-07 13:52:50.093263244 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Float_01 extends JTTTest { + + public static boolean test(float f) { + return /* Float.isNaN(f); */f != f; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.5f); + } + + @Test + public void run3() throws Throwable { + runTest("test", java.lang.Float.NaN); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_02.java 2016-12-07 13:52:50.358274892 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Float_02 extends JTTTest { + + public static boolean test(float f) { + return f != 1.0f; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1.0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2.0f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.5f); + } + + @Test + public void run3() throws Throwable { + runTest("test", java.lang.Float.NaN); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_03.java 2016-12-07 13:52:50.621286451 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Float_03 extends JTTTest { + + public static boolean test() { + return Float.floatToIntBits(Float.intBitsToFloat(0x7fc00088)) == 0x7fc00000; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_conditional.java 2016-12-07 13:52:50.885298054 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.bytecode.BC_float_base; + +public final class Float_conditional extends BC_float_base { + + public static float test(float x, float y) { + if (x == y) { + return y; + } + return x; + } + + public static float conditional(float x, float y) { + return x == y ? x : y; + } + + @Test + public void runEquals() throws Throwable { + runTest("test", x, y); + } + + @Test + public void runConditional() throws Throwable { + runTest("conditional", x, y); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater01.java 2016-12-07 13:52:51.149309658 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_greater01 extends JTTTest { + + public static boolean test(int i) { + if (i > 0) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2); + } + + @Test + public void run6() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater02.java 2016-12-07 13:52:51.414321305 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_greater02 extends JTTTest { + + public static boolean test(int i) { + if (i > 5) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 4); + } + + @Test + public void run6() throws Throwable { + runTest("test", 5); + } + + @Test + public void run7() throws Throwable { + runTest("test", 6); + } + + @Test + public void run8() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater03.java 2016-12-07 13:52:51.682333084 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_greater03 extends JTTTest { + + public static boolean test(int i) { + if (i > -5) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -6); + } + + @Test + public void run2() throws Throwable { + runTest("test", -5); + } + + @Test + public void run3() throws Throwable { + runTest("test", -4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1); + } + + @Test + public void run7() throws Throwable { + runTest("test", 2); + } + + @Test + public void run8() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual01.java 2016-12-07 13:52:51.947344732 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_greaterEqual01 extends JTTTest { + + public static boolean test(int i) { + if (i >= 0) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2); + } + + @Test + public void run6() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual02.java 2016-12-07 13:52:52.211356335 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_greaterEqual02 extends JTTTest { + + public static boolean test(int i) { + if (i >= 5) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 4); + } + + @Test + public void run6() throws Throwable { + runTest("test", 5); + } + + @Test + public void run7() throws Throwable { + runTest("test", 6); + } + + @Test + public void run8() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual03.java 2016-12-07 13:52:52.476367982 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_greaterEqual03 extends JTTTest { + + public static boolean test(int i) { + if (i >= -5) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -6); + } + + @Test + public void run2() throws Throwable { + runTest("test", -5); + } + + @Test + public void run3() throws Throwable { + runTest("test", -4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1); + } + + @Test + public void run7() throws Throwable { + runTest("test", 2); + } + + @Test + public void run8() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less01.java 2016-12-07 13:52:52.741379630 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_less01 extends JTTTest { + + public static boolean test(int i) { + if (i < 0) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2); + } + + @Test + public void run6() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less02.java 2016-12-07 13:52:53.005391233 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_less02 extends JTTTest { + + public static boolean test(int i) { + if (i < 5) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less03.java 2016-12-07 13:52:53.269402836 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_less03 extends JTTTest { + + public static boolean test(int i) { + if (i < -5) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -6); + } + + @Test + public void run2() throws Throwable { + runTest("test", -5); + } + + @Test + public void run3() throws Throwable { + runTest("test", -4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1); + } + + @Test + public void run7() throws Throwable { + runTest("test", 2); + } + + @Test + public void run8() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual01.java 2016-12-07 13:52:53.535414527 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_lessEqual01 extends JTTTest { + + public static boolean test(int i) { + if (i <= 0) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2); + } + + @Test + public void run6() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual02.java 2016-12-07 13:52:53.800426175 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_lessEqual02 extends JTTTest { + + public static boolean test(int i) { + if (i <= 5) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual03.java 2016-12-07 13:52:54.064437778 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Int_lessEqual03 extends JTTTest { + + public static boolean test(int i) { + if (i <= -5) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run1() throws Throwable { + runTest("test", -6); + } + + @Test + public void run2() throws Throwable { + runTest("test", -5); + } + + @Test + public void run3() throws Throwable { + runTest("test", -4); + } + + @Test + public void run4() throws Throwable { + runTest("test", -1); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1); + } + + @Test + public void run7() throws Throwable { + runTest("test", 2); + } + + @Test + public void run8() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/JDK_ClassLoaders01.java 2016-12-07 13:52:54.327449338 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class JDK_ClassLoaders01 extends JTTTest { + + public static boolean test(int i) { + if (i == 0) { + return Object.class.getClassLoader() == null; + } + if (i == 1) { + return Class.class.getClassLoader() == null; + } + if (i == 2) { + return String.class.getClassLoader() == null; + } + if (i == 3) { + return Thread.class.getClassLoader() == null; + } + if (i == 4) { + return System.class.getClassLoader() == null; + } + if (i == 5) { + return ClassLoader.class.getClassLoader() == null; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/JDK_ClassLoaders02.java 2016-12-07 13:52:54.595461117 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import java.net.URLClassLoader; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class JDK_ClassLoaders02 extends JTTTest { + + public static boolean test() { + ClassLoader classLoader = JDK_ClassLoaders02.class.getClassLoader(); + return classLoader == null || classLoader instanceof URLClassLoader; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/LambdaEagerTest.java 2016-12-07 13:52:54.859472720 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2014, 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.jtt.lang; + +import java.util.EnumSet; +import java.util.function.IntBinaryOperator; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Test; + +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.options.OptionValue.OverrideScope; + +public class LambdaEagerTest extends GraalCompilerTest { + + private static final EnumSet UNRESOLVED_UNREACHED = EnumSet.of(DeoptimizationReason.Unresolved, DeoptimizationReason.UnreachedCode); + + private static int doBinary(IntBinaryOperator op, int x, int y) { + return op.applyAsInt(x, y); + } + + private static int add(int x, int y) { + return x + y; + } + + public static int nonCapturing(int x, int y) { + return doBinary((a, b) -> a + b, x, y); + } + + public static int nonCapturing2(int x, int y) { + return doBinary(LambdaEagerTest::add, x, y); + } + + public static int capturing(int x, int y, int z) { + return doBinary((a, b) -> a + b - z, x, y); + } + + @Test + public void testEagerResolveNonCapturing01() { + Result expected = new Result(3, null); + testAgainstExpected(getResolvedJavaMethod("nonCapturing"), expected, UNRESOLVED_UNREACHED, 1, 2); + } + + @Test + public void testEagerResolveNonCapturing02() { + Result expected = new Result(3, null); + testAgainstExpected(getResolvedJavaMethod("nonCapturing2"), expected, UNRESOLVED_UNREACHED, 1, 2); + } + + @Test + public void testEagerResolveCapturing() { + Result expected = new Result(0, null); + testAgainstExpected(getResolvedJavaMethod("capturing"), expected, UNRESOLVED_UNREACHED, 1, 2, 3); + } + + @Override + @SuppressWarnings("try") + protected InstalledCode getCode(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile) { + try (OverrideScope scope = OptionValue.override(GraalOptions.InlineEverything, true)) { + return super.getCode(installedCodeOwner, graph, forceCompile); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater01.java 2016-12-07 13:52:55.123484323 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public final class Long_greater01 extends JTTTest { + + public static boolean test(long i) { + if (i > 0L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater02.java 2016-12-07 13:52:55.387495927 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Long_greater02 extends JTTTest { + + public static boolean test(long i) { + if (i > 5L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 4L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 5L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 6L); + } + + @Test + public void run8() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater03.java 2016-12-07 13:52:55.652507574 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Long_greater03 extends JTTTest { + + public static boolean test(long i) { + if (i > -5L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -6L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -5L); + } + + @Test + public void run3() throws Throwable { + runTest("test", -4L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run8() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual01.java 2016-12-07 13:52:55.917519221 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Long_greaterEqual01 extends JTTTest { + + public static boolean test(long i) { + if (i >= 0L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual02.java 2016-12-07 13:52:56.184530956 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Long_greaterEqual02 extends JTTTest { + + public static boolean test(long i) { + if (i >= 5L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 4L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 5L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 6L); + } + + @Test + public void run8() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual03.java 2016-12-07 13:52:56.450542648 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Long_greaterEqual03 extends JTTTest { + + public static boolean test(long i) { + if (i >= -5L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -6L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -5L); + } + + @Test + public void run3() throws Throwable { + runTest("test", -4L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run8() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less01.java 2016-12-07 13:52:56.715554295 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Long_less01 extends JTTTest { + + public static boolean test(long i) { + if (i < 0L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less02.java 2016-12-07 13:52:56.979565899 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Long_less02 extends JTTTest { + + public static boolean test(long i) { + if (i < 5L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less03.java 2016-12-07 13:52:57.244577546 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Long_less03 extends JTTTest { + + public static boolean test(long i) { + if (i < -5L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -6L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -5L); + } + + @Test + public void run3() throws Throwable { + runTest("test", -4L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run8() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual01.java 2016-12-07 13:52:57.509589193 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Long_lessEqual01 extends JTTTest { + + public static boolean test(long i) { + if (i <= 0L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -2L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2L); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual02.java 2016-12-07 13:52:57.775600884 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Long_lessEqual02 extends JTTTest { + + public static boolean test(long i) { + if (i <= 5L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual03.java 2016-12-07 13:52:58.040612531 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Long_lessEqual03 extends JTTTest { + + public static boolean test(long i) { + if (i <= -5L) { + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", -9223372036854775808L); + } + + @Test + public void run1() throws Throwable { + runTest("test", -6L); + } + + @Test + public void run2() throws Throwable { + runTest("test", -5L); + } + + @Test + public void run3() throws Throwable { + runTest("test", -4L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run8() throws Throwable { + runTest("test", 9223372036854775807L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_reverseBytes01.java 2016-12-07 13:52:58.304624135 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Long_reverseBytes01 extends JTTTest { + + public static long test(long val) { + return Long.reverseBytes(val); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0x1122334455667708L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_reverseBytes02.java 2016-12-07 13:52:58.569635782 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Long_reverseBytes02 extends JTTTest { + + public static long test(long val) { + return (((val >> 56) & 0xff) << 0) | (((val >> 48) & 0xff) << 8) | (((val >> 40) & 0xff) << 16) | (((val >> 32) & 0xff) << 24) | (((val >> 24) & 0xff) << 32) | (((val >> 16) & 0xff) << 40) | + (((val >> 8) & 0xff) << 48) | (((val >> 0) & 0xff) << 56); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0x1122334455667708L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_abs.java 2016-12-07 13:52:58.833647385 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Math_abs extends JTTTest { + + @SuppressWarnings("serial") + public static class NaN extends Throwable { + } + + public static double test(double arg) throws NaN { + double v = Math.abs(arg); + if (Double.isNaN(v)) { + // NaN can't be tested against itself + throw new NaN(); + } + return v; + } + + @Test + public void run0() throws Throwable { + runTest("test", 5.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", -5.0d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0.0d); + } + + @Test + public void run3() throws Throwable { + runTest("test", -0.0d); + } + + @Test + public void run4() throws Throwable { + runTest("test", java.lang.Double.NEGATIVE_INFINITY); + } + + @Test + public void run5() throws Throwable { + runTest("test", java.lang.Double.POSITIVE_INFINITY); + } + + @Test + public void run6() throws Throwable { + runTest("test", java.lang.Double.NaN); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_cos.java 2016-12-07 13:52:59.098659033 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Math_cos extends JTTTest { + + @SuppressWarnings("serial") + public static class NaN extends Throwable { + } + + public static double test(double arg) throws NaN { + double v = Math.cos(arg); + if (Double.isNaN(v)) { + // NaN can't be tested against itself + throw new NaN(); + } + return v; + } + + @Test + public void run0() throws Throwable { + runTest("test", java.lang.Double.NaN); + } + + @Test + public void run1() throws Throwable { + runTest("test", java.lang.Double.NEGATIVE_INFINITY); + } + + @Test + public void run2() throws Throwable { + runTest("test", java.lang.Double.POSITIVE_INFINITY); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exact.java 2016-12-07 13:52:59.361670592 -0800 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, 2015, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Math_exact extends JTTTest { + + public static int testIntAddExact(int a, int b) { + return Math.addExact(a, b); + } + + @Test + public void runTestIntAddExact() throws Throwable { + runTest("testIntAddExact", 1, 2); + runTest("testIntAddExact", 1, Integer.MAX_VALUE); + runTest("testIntAddExact", -1, Integer.MIN_VALUE); + } + + public static long testLongAddExact(long a, long b) { + return Math.addExact(a, b); + } + + @Test + public void runTestLongAddExact() throws Throwable { + runTest("testLongAddExact", 1L, 2L); + runTest("testLongAddExact", 1L, Long.MAX_VALUE); + runTest("testLongAddExact", -1L, Long.MIN_VALUE); + } + + public static int testIntSubExact(int a, int b) { + return Math.subtractExact(a, b); + } + + @Test + public void runTestIntSubExact() throws Throwable { + runTest("testIntSubExact", 1, 2); + runTest("testIntSubExact", -2, Integer.MAX_VALUE); + runTest("testIntSubExact", 2, Integer.MIN_VALUE); + } + + public static long testLongSubExact(long a, long b) { + return Math.subtractExact(a, b); + } + + @Test + public void runTestLongSubExact() throws Throwable { + runTest("testLongSubExact", 1L, 2L); + runTest("testLongSubExact", -2L, Long.MAX_VALUE); + runTest("testLongSubExact", 2L, Long.MIN_VALUE); + } + + public static int testIntMulExact(int a, int b) { + return Math.multiplyExact(a, b); + } + + @Test + public void runTestIntMulExact() throws Throwable { + runTest("testIntMulExact", 1, 2); + runTest("testIntMulExact", -2, Integer.MAX_VALUE); + runTest("testIntMulExact", 2, Integer.MIN_VALUE); + } + + public static long testLongMulExact(long a, long b) { + return Math.multiplyExact(a, b); + } + + @Test + public void runTestLongMulExact() throws Throwable { + runTest("testLongMulExact", 1L, 2L); + runTest("testLongMulExact", 2L, Long.MAX_VALUE); + runTest("testLongMulExact", -2L, Long.MIN_VALUE); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exp.java 2016-12-07 13:52:59.625682195 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.lang; + +import org.junit.Ignore; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Math_exp extends JTTTest { + + public static double test(double arg) { + return Math.exp(arg); + } + + @Test + public void run0() { + runTest("test", java.lang.Double.NaN); + } + + @Test + public void run1() { + runTest("test", java.lang.Double.NEGATIVE_INFINITY); + } + + @Test + public void run2() { + runTest("test", java.lang.Double.POSITIVE_INFINITY); + } + + @Test + public void run3() { + runTest("test", -1D); + } + + @Test + public void run4() { + runTest("test", -0.0D); + } + + @Test + public void run5() { + runTest("test", 0.0D); + } + + @Ignore("java.lang.AssertionError: expected:<2.718281828459045> but was:<2.7182818284590455>") + @Test + public void run6() { + runTest("test", 1.0D); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log.java 2016-12-07 13:52:59.889693799 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Math_log extends JTTTest { + + @SuppressWarnings("serial") + public static class NaN extends Throwable { + } + + public static double test(double arg) throws NaN { + double v = Math.log(arg); + if (Double.isNaN(v)) { + // NaN can't be tested against itself + throw new NaN(); + } + return v; + } + + @Test + public void run0() throws Throwable { + runTest("test", java.lang.Math.E); + } + + @Test + public void run1() throws Throwable { + runTest("test", java.lang.Double.NaN); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1.0d); + } + + @Test + public void run3() throws Throwable { + runTest("test", java.lang.Double.NEGATIVE_INFINITY); + } + + @Test + public void run4() throws Throwable { + runTest("test", java.lang.Double.POSITIVE_INFINITY); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0.0d); + } + + @Test + public void run6() throws Throwable { + runTest("test", -0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log10.java 2016-12-07 13:53:00.152705358 -0800 @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2003, 2016, 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.jtt.lang; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +import org.junit.Before; +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; + +import org.graalvm.compiler.jtt.JTTTest; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * This has been converted to JUnit from the jtreg test test/java/lang/Math/Log10Tests.java in JDK8. + */ +@RunWith(Parameterized.class) +public final class Math_log10 extends JTTTest { + + static final double LN_10 = StrictMath.log(10.0); + + @Parameter(value = 0) public double input; + @Parameter(value = 1) public Number input2; + @Parameter(value = 2) public Number result; + @Parameter(value = 3) public Condition condition; + public Double computedResult; + + enum Condition { + EQUALS, + THREE_ULPS, + MONOTONICITY + } + + public static double log10(double v) { + return Math.log10(v); + } + + public static boolean log10Monotonicity(double v, double v2) { + return Math.log10(v) < Math.log(v2); + } + + @Test + public void testLog10() { + if (condition == Condition.MONOTONICITY) { + runTest("log10Monotonicity", input, input2.doubleValue()); + } else { + runTest("log10", input); + } + } + + public static double strictLog10(double v) { + return StrictMath.log10(v); + } + + public static boolean strictLog10Monotonicity(double v, double v2) { + return StrictMath.log10(v) < StrictMath.log(v2); + } + + @Test + public void testStrictLog10() { + if (condition == Condition.MONOTONICITY) { + runTest("strictLog10Monotonicity", input, input2.doubleValue()); + } else { + runTest("strictLog10", input); + } + } + + @Before + public void before() { + computedResult = null; + } + + private static boolean checkFor3ulps(double expected, double result) { + return Math.abs(result - expected) / Math.ulp(expected) <= 3; + } + + @Override + protected void assertDeepEquals(Object expected, Object actual) { + if (this.condition == Condition.THREE_ULPS) { + double actualValue = ((Number) actual).doubleValue(); + assertTrue("differs by more than 3 ulps: " + result.doubleValue() + "," + actualValue, checkFor3ulps(result.doubleValue(), actualValue)); + if (computedResult != null && actualValue != computedResult) { + /* + * This test detects difference in the actual result between the built in + * implementation and what Graal does. If it reaches this test then the value was + * within 3 ulps but differs in the exact amount. + * + * System.err.println("value for " + input + " is within 3 ulps but differs from + * computed value: " + computedResult + " " + actualValue); + */ + } + } else { + super.assertDeepEquals(expected, actual); + } + } + + @Override + protected Result executeExpected(ResolvedJavaMethod method, Object receiver, Object... args) { + Result actual = super.executeExpected(method, receiver, args); + if (actual.returnValue instanceof Number) { + computedResult = ((Number) actual.returnValue).doubleValue(); + assertDeepEquals(computedResult, actual.returnValue); + } + return actual; + } + + static void addEqualityTest(List tests, double input, double expected) { + tests.add(new Object[]{input, null, expected, Condition.EQUALS}); + } + + static void add3UlpTest(List tests, double input, double expected) { + tests.add(new Object[]{input, null, expected, Condition.THREE_ULPS}); + } + + static void addMonotonicityTest(List tests, double input, double input2) { + tests.add(new Object[]{input, input2, null, Condition.MONOTONICITY}); + } + + @Parameters(name = "{index}") + public static Collection data() { + List tests = new ArrayList<>(); + + addEqualityTest(tests, Double.NaN, Double.NaN); + addEqualityTest(tests, Double.longBitsToDouble(0x7FF0000000000001L), Double.NaN); + addEqualityTest(tests, Double.longBitsToDouble(0xFFF0000000000001L), Double.NaN); + addEqualityTest(tests, Double.longBitsToDouble(0x7FF8555555555555L), Double.NaN); + addEqualityTest(tests, Double.longBitsToDouble(0xFFF8555555555555L), Double.NaN); + addEqualityTest(tests, Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), Double.NaN); + addEqualityTest(tests, Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), Double.NaN); + addEqualityTest(tests, Double.longBitsToDouble(0x7FFDeadBeef00000L), Double.NaN); + addEqualityTest(tests, Double.longBitsToDouble(0xFFFDeadBeef00000L), Double.NaN); + addEqualityTest(tests, Double.longBitsToDouble(0x7FFCafeBabe00000L), Double.NaN); + addEqualityTest(tests, Double.longBitsToDouble(0xFFFCafeBabe00000L), Double.NaN); + addEqualityTest(tests, Double.NEGATIVE_INFINITY, Double.NaN); + addEqualityTest(tests, -8.0, Double.NaN); + addEqualityTest(tests, -1.0, Double.NaN); + addEqualityTest(tests, -Double.MIN_NORMAL, Double.NaN); + addEqualityTest(tests, -Double.MIN_VALUE, Double.NaN); + addEqualityTest(tests, -0.0, -Double.POSITIVE_INFINITY); + addEqualityTest(tests, +0.0, -Double.POSITIVE_INFINITY); + addEqualityTest(tests, +1.0, 0.0); + addEqualityTest(tests, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + + // Test log10(10^n) == n for integer n; 10^n, n < 0 is not + // exactly representable as a floating-point value -- up to + // 10^22 can be represented exactly + double testCase = 1.0; + for (int i = 0; i < 23; i++) { + addEqualityTest(tests, testCase, i); + testCase *= 10.0; + } + + // Test for gross inaccuracy by comparing to log; should be + // within a few ulps of log(x)/log(10) + Random rand = new java.util.Random(0L); + for (int i = 0; i < 10000; i++) { + double input = Double.longBitsToDouble(rand.nextLong()); + if (!Double.isFinite(input)) { + continue; // avoid testing NaN and infinite values + } else { + input = Math.abs(input); + + double expected = StrictMath.log(input) / LN_10; + if (!Double.isFinite(expected)) { + continue; // if log(input) overflowed, try again + } else { + add3UlpTest(tests, input, expected); + } + } + } + + double z = Double.NaN; + // Test inputs greater than 1.0. + double[] input = new double[40]; + int half = input.length / 2; + // Initialize input to the 40 consecutive double values + // "centered" at 1.0. + double up = Double.NaN; + double down = Double.NaN; + for (int i = 0; i < half; i++) { + if (i == 0) { + input[half] = 1.0; + up = Math.nextUp(1.0); + down = Math.nextDown(1.0); + } else { + input[half + i] = up; + input[half - i] = down; + up = Math.nextUp(up); + down = Math.nextDown(down); + } + } + input[0] = Math.nextDown(input[1]); + for (int i = 0; i < input.length; i++) { + // Test accuracy. + z = input[i] - 1.0; + double expected = (z - (z * z) * 0.5) / LN_10; + add3UlpTest(tests, input[i], expected); + + // Test monotonicity + if (i > 0) { + addMonotonicityTest(tests, input[i - 1], input[i]); + } + } + + return tests; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_pow.java 2016-12-07 13:53:00.417717005 -0800 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Math_pow extends JTTTest { + + public static double test(double x, double y) { + return Math.pow(x, y); + } + + @Test + public void run0() throws Throwable { + runTest("test", 2d, 0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2d, 0.5d); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2d, 0.5d); + } + + @Test + public void run3() throws Throwable { + runTest("test", 2d, 1d); + } + + @Test + public void run4() throws Throwable { + runTest("test", 2d, -1d); + } + + @Test + public void run5() throws Throwable { + runTest("test", 2d, 2d); + } + + @Test + public void run6() throws Throwable { + runTest("test", 2d, 3.1d); + } + + @Test + public void run7() throws Throwable { + runTest("test", 2d, Double.NaN); + } + + @Test + public void run8() throws Throwable { + runTest("test", Double.NaN, 0d); + } + + @Test + public void run9() throws Throwable { + runTest("test", Double.NaN, 23d); + } + + @Test + public void run10() throws Throwable { + runTest("test", 0.999998, 1500000.0); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_round.java 2016-12-07 13:53:00.682728653 -0800 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, 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.jtt.lang; + +import java.util.ArrayList; +import java.util.Collection; + +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; + +import org.graalvm.compiler.jtt.JTTTest; + +@RunWith(Parameterized.class) +public class Math_round extends JTTTest { + + @Parameter(value = 0) public double input; + + public static double rint(double arg) { + return Math.rint(arg); + } + + @Test + public void runRint() throws Throwable { + runTest("rint", input); + } + + public static double floor(double arg) { + return Math.floor(arg); + } + + @Test + public void runFloor() throws Throwable { + runTest("floor", input); + } + + public static double ceil(double arg) { + return Math.ceil(arg); + } + + @Test + public void runCeil() throws Throwable { + runTest("ceil", input); + } + + @Parameters(name = "{0}") + public static Collection data() { + ArrayList tests = new ArrayList<>(); + for (int i = -3; i < 3; i++) { + addTest(tests, i); + addTest(tests, i + 0.2); + addTest(tests, i + 0.5); + addTest(tests, i + 0.7); + } + addTest(tests, -0.0); + addTest(tests, Double.NaN); + addTest(tests, Double.NEGATIVE_INFINITY); + addTest(tests, Double.POSITIVE_INFINITY); + return tests; + } + + private static void addTest(ArrayList tests, double input) { + tests.add(new Object[]{input}); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sin.java 2016-12-07 13:53:00.946740256 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Math_sin extends JTTTest { + + @SuppressWarnings("serial") + public static class NaN extends Throwable { + } + + public static double test(double arg) throws NaN { + double v = Math.sin(arg) * Math.sin(arg * 5); + if (Double.isNaN(v)) { + // NaN can't be tested against itself + throw new NaN(); + } + return v; + } + + @Test + public void runFirst() throws Throwable { + /* + * Execute Double.isNaN enough times to create a profile indicating that the path returning + * false is never taken. Then compile and execute the test with a NaN value to test that + * deoptimization works in the case of an uncommon trap inlined into an intrinsic. Of + * course, this relies on Double.isNaN never having yet been called with NaN. if it has, + * this test is equivalent to run0. + */ + for (int i = 0; i < 10000; i++) { + Double.isNaN(1D); + } + executeActual(getResolvedJavaMethod("test"), null, java.lang.Double.NaN); + } + + @Test + public void run0() throws Throwable { + runTest("test", java.lang.Double.NaN); + } + + @Test + public void run1() throws Throwable { + runTest("test", java.lang.Double.NEGATIVE_INFINITY); + } + + @Test + public void run2() throws Throwable { + runTest("test", java.lang.Double.POSITIVE_INFINITY); + } + + @Test + public void run3() throws Throwable { + runTest("test", -0.0d); + } + + @Test + public void run4() throws Throwable { + runTest("test", 0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sqrt.java 2016-12-07 13:53:01.211751903 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Math_sqrt extends JTTTest { + + @SuppressWarnings("serial") + public static class NaN extends Throwable { + } + + public static double test(double arg) throws NaN { + double v = Math.sqrt(arg); + if (Double.isNaN(v)) { + // NaN can't be tested against itself + throw new NaN(); + } + return v; + } + + @Test + public void run0() throws Throwable { + runTest("test", 4.0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", java.lang.Double.NaN); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1.0d); + } + + @Test + public void run3() throws Throwable { + runTest("test", java.lang.Double.NEGATIVE_INFINITY); + } + + @Test + public void run4() throws Throwable { + runTest("test", java.lang.Double.POSITIVE_INFINITY); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0.0d); + } + + @Test + public void run6() throws Throwable { + runTest("test", -0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_tan.java 2016-12-07 13:53:01.475763506 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Math_tan extends JTTTest { + + @SuppressWarnings("serial") + public static class NaN extends Throwable { + } + + public static double test(double arg) throws NaN { + double v = Math.tan(arg); + if (Double.isNaN(v)) { + // NaN can't be tested against itself + throw new NaN(); + } + return v; + } + + @Test + public void run0() throws Throwable { + runTest("test", java.lang.Double.NaN); + } + + @Test + public void run1() throws Throwable { + runTest("test", java.lang.Double.NEGATIVE_INFINITY); + } + + @Test + public void run2() throws Throwable { + runTest("test", java.lang.Double.POSITIVE_INFINITY); + } + + @Test + public void run3() throws Throwable { + runTest("test", -0.0d); + } + + @Test + public void run4() throws Throwable { + runTest("test", 0.0d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_clone01.java 2016-12-07 13:53:01.741775198 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Object_clone01 extends JTTTest { + + private static class TestClass { + @SuppressWarnings("unused") + private boolean tryClone(int i) throws CloneNotSupportedException { + return this == this.clone(); + } + } + + static final TestClass field = new TestClass(); + + public static boolean test(int i) throws CloneNotSupportedException { + return field.tryClone(i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_clone02.java 2016-12-07 13:53:02.005786801 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Object_clone02 extends JTTTest { + + private static class TestClass implements Cloneable { + @SuppressWarnings("unused") + private boolean tryClone(int i) throws CloneNotSupportedException { + return this == this.clone(); + } + } + + static final TestClass field = new TestClass(); + + public static boolean test(int i) throws CloneNotSupportedException { + return field.tryClone(i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_equals01.java 2016-12-07 13:53:02.269798404 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Object_equals01 extends JTTTest { + + public static DummyTestClass field = new DummyTestClass(); + + public static boolean test(int i) { + final Object obj1 = new Object(); + final Object obj2 = new Object(); + switch (i) { + case 0: + return obj1.equals(field); + case 1: + return obj1.equals(obj2); + case 2: + return obj1.equals(null); + case 3: + return obj1.equals(obj1); + case 4: + return field.equals(field); + case 5: + return obj2.equals(field); + case 6: + return obj2.equals(obj2); + case 7: + return obj2.equals(null); + case 8: + return obj2.equals(obj1); + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_getClass01.java 2016-12-07 13:53:02.532809964 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Object_getClass01 extends JTTTest { + + static final Object object = new Object(); + static final Object string = new String(); + static final DummyTestClass thisObject = new DummyTestClass(); + + public static String test(int i) { + if (i == 0) { + return object.getClass().toString(); + } + if (i == 1) { + return string.getClass().toString(); + } + if (i == 2) { + return thisObject.getClass().toString(); + } + if (i == 3) { + return thisObject.getClass().getClass().toString(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_hashCode01.java 2016-12-07 13:53:02.796821567 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Object_hashCode01 extends JTTTest { + + public static boolean test() { + final Object o1 = new Object(); + final Object o2 = new Object(); + return o1.hashCode() != 0 || o2.hashCode() != 0; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_hashCode02.java 2016-12-07 13:53:03.061833214 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import java.time.DayOfWeek; +import java.util.HashMap; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Object_hashCode02 extends JTTTest { + + public static final Object obj1 = new Object(); + public static final Object obj2 = DayOfWeek.FRIDAY; + public static final Object obj3 = new HashMap<>(); + + public static int test(int a) { + if (a == 1) { + return obj1.hashCode(); + } + if (a == 2) { + return obj2.hashCode(); + } + return obj3.hashCode(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notify01.java 2016-12-07 13:53:03.326844861 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Object_notify01 extends JTTTest { + + static final Object object = new Object(); + + public static boolean test() { + object.notify(); + return true; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notify02.java 2016-12-07 13:53:03.591856509 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Object_notify02 extends JTTTest { + + static final Object object = new Object(); + + public static boolean test() { + synchronized (object) { + object.notify(); + } + return true; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notifyAll01.java 2016-12-07 13:53:03.856868156 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Object_notifyAll01 extends JTTTest { + + static final Object obj = new Object(); + + public static boolean test() { + obj.notifyAll(); + return true; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notifyAll02.java 2016-12-07 13:53:04.121879803 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Object_notifyAll02 extends JTTTest { + + static final Object object = new Object(); + + public static boolean test() { + synchronized (object) { + object.notifyAll(); + } + return true; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_toString01.java 2016-12-07 13:53:04.386891450 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Object_toString01 extends JTTTest { + + private static class TestClass { + @Override + public String toString() { + return string; + } + } + + static final String string = "Object_toString01"; + static final Object object = new Object(); + + public static boolean test(int i) { + if (i == 0) { + return object.toString() != null; + } + if (i == 1) { + return new TestClass().toString() == string; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_toString02.java 2016-12-07 13:53:04.650903054 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +/* + */ +package org.graalvm.compiler.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Object_toString02 extends JTTTest { + + private static class TestClass { + @Override + public String toString() { + return "XYZ"; + } + } + + static final Object obj = new TestClass(); + + public static String test(int i) { + Object object = null; + if (i == 0) { + object = obj; + } else if (i == 1) { + object = "string"; + } else if (i == 2) { + object = "string".getClass(); + } + return object.toString(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait01.java 2016-12-07 13:53:04.914914657 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Object_wait01 extends JTTTest { + + static final Object object = new Object(); + + public static boolean test() throws InterruptedException { + object.wait(); + return true; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait02.java 2016-12-07 13:53:05.178926260 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Object_wait02 extends JTTTest { + + static final Object object = new Object(); + + public static boolean test() throws InterruptedException { + synchronized (object) { + object.wait(1); + } + return true; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait03.java 2016-12-07 13:53:05.443937907 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Object_wait03 extends JTTTest { + + static final Object object = new Object(); + + public static boolean test() throws InterruptedException { + synchronized (object) { + object.wait(1, 1); + } + return true; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/ProcessEnvironment_init.java 2016-12-07 13:53:05.706949467 -0800 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.lang; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class ProcessEnvironment_init extends JTTTest { + + private static HashMap theEnvironment; + public static Map theUnmodifiableEnvironment; + + public static int test(int v) { + + byte[][] environ = environ(); + theEnvironment = new HashMap<>(environ.length / 2 + 3); + + for (int i = environ.length - 1; i > 0; i -= 2) { + theEnvironment.put(Variable.valueOf(environ[i - 1]), Value.valueOf(environ[i])); + } + + theUnmodifiableEnvironment = Collections.unmodifiableMap(new StringEnvironment(theEnvironment)); + + return v; + } + + @SuppressWarnings("serial") + private static final class StringEnvironment extends HashMap { + + @SuppressWarnings("unused") + StringEnvironment(HashMap theenvironment) { + } + } + + private static final class Variable { + + @SuppressWarnings("unused") + public static Object valueOf(byte[] bs) { + return new Object(); + } + } + + private static final class Value { + + @SuppressWarnings("unused") + public static Object valueOf(byte[] bs) { + return new Object(); + } + } + + private static byte[][] environ() { + return new byte[3][3]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/StringCoding_Scale.java 2016-12-07 13:53:05.971961115 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class StringCoding_Scale extends JTTTest { + + public static float maxCharPerByte = 1.0f; + + public static int test(int i) { + return scale(i, maxCharPerByte); + } + + // Copy of java.lang.StringCode.scale + private static int scale(int len, float expansionFactor) { + // We need to perform double, not float, arithmetic; otherwise + // we lose low order bits when len is larger than 2**24. + return (int) (len * (double) expansionFactor); + } + + @Test + public void run0() throws Throwable { + runTest("test", 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern01.java 2016-12-07 13:53:06.236972762 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class String_intern01 extends JTTTest { + + public static boolean test() { + // Checkstyle: stop + return "id".intern() == "id"; + // Checkstyle: resume + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern02.java 2016-12-07 13:53:06.502984453 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class String_intern02 extends JTTTest { + + public static boolean test(int i) { + return ("id" + i).intern() == ("id" + i).intern(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern03.java 2016-12-07 13:53:06.769996188 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class String_intern03 extends JTTTest { + + public static boolean test(int i) { + return ("id" + i).intern().equals("id" + i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_valueOf01.java 2016-12-07 13:53:07.033007746 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class String_valueOf01 extends JTTTest { + + public static String test(int i) { + Object result = null; + if (i == 1) { + result = "string"; + } + return String.valueOf(result); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/System_identityHashCode01.java 2016-12-07 13:53:07.300019482 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.lang; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class System_identityHashCode01 extends JTTTest { + + private static final Object object0 = new Object(); + private static final Object object1 = new Object(); + private static final Object object2 = new Object(); + + private static final int hash0 = System.identityHashCode(object0); + private static final int hash1 = System.identityHashCode(object1); + private static final int hash2 = System.identityHashCode(object2); + + public static boolean test(int i) { + if (i == 0) { + return hash0 == System.identityHashCode(object0); + } + if (i == 1) { + return hash1 == System.identityHashCode(object1); + } + if (i == 2) { + return hash2 == System.identityHashCode(object2); + } + if (i == 3) { + return 0 == System.identityHashCode(null); + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/DegeneratedLoop.java 2016-12-07 13:53:07.564031085 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class DegeneratedLoop extends JTTTest { + + public static String test(int a) { + int arg = a; + for (;;) { + try { + arg++; + break; + } catch (Unresolved iioe) { + } + } + return "ok-" + arg; + } + + @SuppressWarnings("serial") + public static class Unresolved extends RuntimeException { + + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop01.java 2016-12-07 13:53:07.829042733 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop01 extends JTTTest { + + public static boolean test() { + int x = 1; + + for (int i = 0; i < 10; i++) { + int y = m(); + if (x == 1) { + return true; + } + x = y; + } + return false; + } + + private static int m() { + return 2; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop02.java 2016-12-07 13:53:08.095054423 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop02 extends JTTTest { + + public static boolean test(int arg) { + int x = arg; + + for (int i = 0; i < 10; i++) { + int y = m(); + if (x == 1) { + return true; + } + x = y; + } + return false; + } + + private static int m() { + return 2; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop03.java 2016-12-07 13:53:08.359066027 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop03 extends JTTTest { + + public static int test(int count) { + int i1 = 1; + int i2 = 2; + int i4 = 4; + + for (int i = 0; i < count; i++) { + i1 = i2; + i2 = 7; + i4 = i1; + } + return i1 + i2 * 10 + i4 * 1000; + } + + @Test + public void run0() throws Throwable { + runTest("test", 10); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop04.java 2016-12-07 13:53:08.622077586 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop04 extends JTTTest { + + public static int test(int count) { + int i1 = 1; + int i2 = 2; + int i3 = 3; + int i4 = 4; + + for (int i = 0; i < count; i++) { + i1 = i2; + i2 = i3; + i3 = i4; + i4 = i1; + } + return i1 + i2 * 10 + i3 * 100 + i4 * 1000; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 10); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop05.java 2016-12-07 13:53:08.887089234 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop05 extends JTTTest { + + @SuppressWarnings("unused") + public static String test(int a) { + int arg = a; + int count = 0; + while (--arg > 0) { + count++; + new Object(); + } + return "ok" + count; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 25); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop06.java 2016-12-07 13:53:09.152100881 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop06 extends JTTTest { + + public static String test(int a) { + int arg = a; + int count = 0; + while (--arg > 0) { + count++; + foo(); + } + return "ok" + count; + } + + static void foo() { + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 25); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop07.java 2016-12-07 13:53:09.417112528 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Loop07 extends JTTTest { + + public static String test(int arg) { + int count = arg; + for (int i = 0; i < arg; i++) { + count++; + } + return "ok" + count; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 25); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop07_2.java 2016-12-07 13:53:09.681124131 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014, 2014, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Loop07_2 extends JTTTest { + + public static int test(int arg) { + int count = arg; + for (int i = 0; i < arg; i++) { + count++; + } + return count; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 25); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop08.java 2016-12-07 13:53:09.944135691 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop08 extends JTTTest { + + public static int test(int arg) { + int a = 0; + for (int i = 0; i < arg; i++) { + a += i; + } + return a; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 25); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop09.java 2016-12-07 13:53:10.209147338 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop09 extends JTTTest { + + private static int cnt; + + public static String test(int arg) { + cnt = 0; + int count = arg; + for (int i = 0; i < arg; i++) { + count++; + foo(); + } + return "ok" + count + "-" + cnt; + } + + static void foo() { + cnt++; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 25); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop09_2.java 2016-12-07 13:53:10.473158941 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop09_2 extends JTTTest { + + private static int cnt; + + public static int test(int arg) { + cnt = 0; + int count = arg; + for (int i = 0; i < arg; i++) { + count++; + foo(); + } + return count - cnt; + } + + static void foo() { + cnt++; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 25); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop11.java 2016-12-07 13:53:10.738170588 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop11 extends JTTTest { + + public static int test(int a) { + int arg = a; + int v = 0; + while (arg-- > 0) { + v = 1; + } + return v; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop12.java 2016-12-07 13:53:11.003182235 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop12 extends JTTTest { + + private static int[] source = new int[]{10, 15, 20, 25, 30}; + + public static int test(int arg) { + int i = 0; + if (source[i] != arg) { + while (++i <= 5 && source[i] != arg) { + // nothing + } + } + return i; + } + + @Test + public void run0() throws Throwable { + runTest("test", 10); + } + + @Test + public void run1() throws Throwable { + runTest("test", 15); + } + + @Test + public void run2() throws Throwable { + runTest("test", 30); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop13.java 2016-12-07 13:53:11.268193883 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop13 extends JTTTest { + + public static class Loop { + + private int index; + private Object[] nodes = new Object[]{null, null, new Object(), null, null, new Object(), null}; + private int size = nodes.length; + + public Loop(int start) { + index = start; + } + + public void test0() { + if (index < size) { + do { + index++; + } while (index < size && nodes[index] == null); + } + } + + public int getIndex() { + return index; + } + + } + + public static int test(int arg) { + Loop loop = new Loop(arg); + loop.test0(); + return loop.getIndex(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + + @Test + public void run3() throws Throwable { + runTest("test", 6); + } + + @Test + public void run4() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop14.java 2016-12-07 13:53:11.533205530 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Loop14 extends JTTTest { + + private static int value; + + public static int test(int arg) { + return calc(arg); + } + + public static int calc(int arg) { + int result = 0; + for (int k = 0; k < arg; ++k) { + value = 5; + for (int i = 0; i < arg; ++i) { + for (int j = 0; j < arg; ++j) { + } + result += value; + } + } + return result; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop15.java 2016-12-07 13:53:11.798217177 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Loop15 extends JTTTest { + + public static int test(int arg) { + Object o = null; + int result = 10; + for (int k = 0; k < arg; ++k) { + if (o == null) { + o = new Object(); + } + if (k >= 5) { + break; + } + result++; + } + return result + (o == null ? 0 : 1); + } + + @Test + public void run0() throws Throwable { + runTest("test", 5); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 10); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop16.java 2016-12-07 13:53:12.061228736 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests exiting 2 loops at the same time with escape-analysed values flowing out of loops + */ +public class Loop16 extends JTTTest { + + private static class TestClass { + public int a; + public int b; + public int c; + + public int run(int count) { + l1: for (int i = 0; i <= count; i++) { + if (i > 5) { + for (int j = 0; j < i; j++) { + a += i; + if (a > 500) { + break l1; + } + } + } else if (i > 7) { + b += i; + } else { + c += i; + } + } + return a + b + c; + } + } + + public static int test(int count) { + return new TestClass().run(count); + } + + @Test + public void run0() throws Throwable { + runTest("test", 40); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop17.java 2016-12-07 13:53:12.324240296 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Test around an object that escapes directly from inside a loop (no virtual phi on the loop) + */ +public class Loop17 extends JTTTest { + + private static class L { + + public int a; + public int b; + public int c; + + public L(int a, int b, int c) { + this.a = a; + this.b = b; + this.c = c; + } + } + + public static int test(int count) { + int i = 0; + L l; + do { + l = new L(i, i + 1, i + 2); + } while (++i < count); + + return l.a + l.b * 10 + l.c * 100; + } + + @Test + public void run0() throws Throwable { + runTest("test", new L(4, 4, 4).a); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopEscape.java 2016-12-07 13:53:12.591252031 -0800 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2012, 2012, 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. + */ +// Checkstyle: stop +package org.graalvm.compiler.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Test around an object that escapes directly from inside a loop (no virtual phi on the loop) + */ +public class LoopEscape extends JTTTest { + + public static L ll = new L(0, 1, 2); + + private static class L { + + public int a; + public int b; + public int c; + + public L(int a, int b, int c) { + this.a = a; + this.b = b; + this.c = c; + } + } + + public static int test0(int count) { + L l = new L(5, 5, 5); + for (int i = 0; i < count; i++) { + l.a++; + l.b--; + l.c = 4; + } + + return l.a + l.b * 10 + l.c * 100; + } + + public static int test1(int count) { + L l = new L(5, 5, 5); + for (int i = 0; i < count; i++) { + if (l.a % 2 == 0) { + l.a++; + l.b--; + l.c = 4; + } else { + l.a++; + } + } + + return l.a + l.b * 10 + l.c * 100; + } + + @Test + public void run10() throws Throwable { + runTest("test1", 0); + } + + @Test + public void run11() throws Throwable { + runTest("test1", 1); + } + + @Test + public void run12() throws Throwable { + runTest("test1", 2); + } + + @Test + public void run00() throws Throwable { + runTest("test0", 0); + } + + @Test + public void run01() throws Throwable { + runTest("test0", 1); + } + + @Test + public void run02() throws Throwable { + runTest("test0", 2); + } + + @Test + public void run05() throws Throwable { + runTest("test0", 5); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopInline.java 2016-12-07 13:53:12.855263634 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class LoopInline extends JTTTest { + + public static int test(int arg) { + int count = 0; + for (int i = 0; i < arg; i++) { + count += foo(i); + if (count > 15) { + count -= foo(3); + break; + } + } + return count; + } + + public static int foo(int t) { + int sum = 0; + for (int i = 0; i < t; i++) { + sum += i; + if (i == 4) { + sum += foo2(sum); + break; + } + } + return sum; + } + + public static int foo2(int i) { + int j = i; + int sum = 0; + while (j > 0) { + sum += j * j; + j--; + } + return sum; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopLastIndexOf.java 2016-12-07 13:53:13.120275281 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * see java.lang.String.lastIndexOf(char[], int, int, char[], int ,int, int) + */ +public class LoopLastIndexOf extends JTTTest { + + private static final char[] v1 = new char[]{'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'}; + private static final char[] v2 = new char[]{'d', 'a'}; + private static final char[] v3 = new char[]{'d', 'b', 'c'}; + private static final char[] v4 = new char[]{'z', 'a', 'b', 'c'}; + + public static int test(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndexParam) { + int rightIndex = sourceCount - targetCount; + int fromIndex = fromIndexParam; + if (fromIndex < 0) { + return -1; + } + if (fromIndex > rightIndex) { + fromIndex = rightIndex; + } + /* Empty string always matches. */ + if (targetCount == 0) { + return fromIndex; + } + + int strLastIndex = targetOffset + targetCount - 1; + char strLastChar = target[strLastIndex]; + int min = sourceOffset + targetCount - 1; + int i = min + fromIndex; + + startSearchForLastChar: while (true) { + while (i >= min && source[i] != strLastChar) { + i--; + } + if (i < min) { + return -1; + } + int j = i - 1; + int start = j - (targetCount - 1); + int k = strLastIndex - 1; + + while (j > start) { + if (source[j--] != target[k--]) { + i--; + continue startSearchForLastChar; + } + } + return start - sourceOffset + 1; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", v1, 0, v1.length, v2, 0, v2.length, 10); + } + + @Test + public void run1() throws Throwable { + runTest("test", v1, 0, v1.length, v3, 0, v3.length, 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", v1, 0, v1.length, v4, 0, v4.length, 10); + } + + @Test + public void run3() throws Throwable { + runTest("test", v1, 1, v1.length - 1, v3, 0, v3.length, 10); + } + + @Test + // (expected = ArrayIndexOutOfBoundsException.class) + public void run4() throws Throwable { + runTest("test", v1, 1, v1.length, v3, 0, v3.length, 10); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopNewInstance.java 2016-12-07 13:53:13.385286929 -0800 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.loop; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class LoopNewInstance extends JTTTest { + + public static Blop initBlop = new Blop(); + + @SuppressWarnings("unused") + public static int test(int arg) { + for (int i = 0; i < arg; i++) { + new Blop(); + } + return count; + } + + private static int count; + + private static class Blop { + + private boolean exists; + + Blop() { + if (!exists) { + count++; + } + exists = true; + } + } + + @Override + protected void before(ResolvedJavaMethod m) { + count = 0; + } + + @Test + public void run0() throws Throwable { + count = 0; + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + count = 0; + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopParseLong.java 2016-12-07 13:53:13.649298532 -0800 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class LoopParseLong extends JTTTest { + + @SuppressWarnings("unused") + public static long testShortened(String s, int radix) throws NumberFormatException { + long result = 0; + boolean negative = false; + int len = s.length(); + char firstChar = s.charAt(0); + if (firstChar < '0') { + if (firstChar == '-') { + negative = true; + } else if (firstChar != '+') { + throw new NumberFormatException(); + } + if (len == 1) { + throw new NumberFormatException(); + } + } + return result; + } + + public static long test(String s, int radix) throws NumberFormatException { + if (s == null) { + throw new NumberFormatException("null"); + } + if (radix < Character.MIN_RADIX) { + throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX"); + } + if (radix > Character.MAX_RADIX) { + throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX"); + } + long result = 0; + boolean negative = false; + int i = 0; + int len = s.length(); + long limit = -Long.MAX_VALUE; + long multmin; + int digit; + if (len > 0) { + char firstChar = s.charAt(0); + if (firstChar < '0') { + if (firstChar == '-') { + negative = true; + limit = Long.MIN_VALUE; + } else if (firstChar != '+') { + throw new NumberFormatException(); + } + if (len == 1) { + throw new NumberFormatException(); + } + i++; + } + multmin = limit / radix; + while (i < len) { + digit = Character.digit(s.charAt(i++), radix); + if (digit < 0) { + throw new NumberFormatException(); + } + if (result < multmin) { + throw new NumberFormatException(); + } + result *= radix; + if (result < limit + digit) { + throw new NumberFormatException(); + } + result -= digit; + } + } else { + throw new NumberFormatException(); + } + return negative ? result : -result; + } + + @Test + public void run0() throws Throwable { + runTest("testShortened", "7", 10); + } + + @Test + public void run1() throws Throwable { + runTest("testShortened", "-100", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", "7", 10); + } + + @Test + public void run3() throws Throwable { + runTest("test", "-100", 10); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopPhi.java 2016-12-07 13:53:13.912310091 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ + +public class LoopPhi extends JTTTest { + + public static int test(int arg) { + for (int i = 0; i < arg; i++) { + testHelper(1, 1, 1, 1, 1, 1); + } + return testHelper(1, 1, 1, 1, 1, 1); + } + + public static int testHelper(int j1, int j2, int j3, int j4, int j5, int j6) { + int i1 = j1; + int i2 = j2; + int i3 = j3; + int i4 = j4; + int i5 = j5; + int i6 = j6; + + if (i1 == 0) { + i1 = 2; + } else { + i2 = 2; + } + for (int i = 0; i < 10; i++) { + if (i == 0) { + i3 = 2; + } else { + i4 = 2; + } + + for (int j = 0; j < 10; j++) { + if (j == 0) { + i5 = 2; + } else { + i6 = 2; + } + } + } + + return i1 + i2 + i3 + i4 + i5 + i6; + } + + @Test + public void run0() throws Throwable { + runTest("test", 50000); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopPhiResolutionTest.java 2016-12-07 13:53:14.175321650 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 2015, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class LoopPhiResolutionTest extends JTTTest { + + public static int test(int count) { + int i1 = 1; + int i2 = 2; + int i3 = 3; + int i4 = 4; + + for (int i = 0; i < count; i++) { + i1 = wormhole(i1); + i2 = wormhole(i2); + i3 = wormhole(i2); + i4 = wormhole(i4); + } + return i1 + i2 * 10 + i3 * 100 + i4 * 1000; + } + + private static int wormhole(int x) { + return (int) GraalDirectives.opaque((long) x); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 10); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopSpilling.java 2016-12-07 13:53:14.439333254 -0800 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, 2015, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class LoopSpilling extends JTTTest { + + private static final int ITERATION = 64; + + /** + * Modification of sun.security.provider.SHA2.implCompress(). + */ + void test(int[] state) { + + int a1 = state[0]; + int b1 = state[1]; + int c1 = state[2]; + int d1 = state[3]; + int e1 = state[4]; + int f1 = state[5]; + int g1 = state[6]; + int h1 = state[7]; + + // 2nd + int a2 = state[8]; + int b2 = state[9]; + int c2 = state[10]; + int d2 = state[11]; + int e2 = state[12]; + int f2 = state[13]; + int g2 = state[14]; + int h2 = state[15]; + + for (int i = 0; i < ITERATION; i++) { + h1 = g1; + g1 = f1; + f1 = e1; + e1 = d1; + d1 = c1; + c1 = b1; + b1 = a1; + a1 = h1; + // 2nd + h2 = g2; + g2 = f2; + f2 = e2; + e2 = d2; + d2 = c2; + c2 = b2; + b2 = a2; + a2 = h2; + } + state[0] += a1; + state[1] += b1; + state[2] += c1; + state[3] += d1; + state[4] += e1; + state[5] += f1; + state[6] += g1; + state[7] += h1; + // 2nd + state[8] += a2; + state[9] += b2; + state[10] += c2; + state[11] += d2; + state[12] += e2; + state[13] += f2; + state[14] += g2; + state[15] += h2; + } + + private static final int[] INITIAL_HASHES = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4, 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + + @Test + public void run0() throws Throwable { + runTest("test", supply(() -> INITIAL_HASHES.clone())); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopSwitch01.java 2016-12-07 13:53:14.703344857 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class LoopSwitch01 extends JTTTest { + + static int count = 0; + + @SuppressWarnings("unused") + public static String test() { + String line; + while ((line = string()) != null) { + switch (line.charAt(0)) { + case 'a': + new Object(); + break; + case 'b': + new Object(); + break; + default: + new Object(); + break; + } + } + return "ok" + count; + } + + private static String string() { + if (count == 0) { + return null; + } + count--; + return "" + ('a' + count); + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopUnroll.java 2016-12-07 13:53:14.966356416 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class LoopUnroll extends JTTTest { + + public static int test(int input) { + int ret = 2; + int current = input; + for (int i = 0; i < 7; i++) { + ret *= 2 + current; + current /= 50; + } + return ret; + } + + @Test + public void run0() throws Throwable { + runTest("test", 42); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/SpillLoopPhiVariableAtDefinition.java 2016-12-07 13:53:15.229367975 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 2015, 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.jtt.loop; + +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.jtt.JTTTest; + +public class SpillLoopPhiVariableAtDefinition extends JTTTest { + + public static int test(int arg) { + int count = arg; + for (int i = 0; i < arg; i++) { + GraalDirectives.bindToRegister(count); + GraalDirectives.spillRegisters(); + GraalDirectives.bindToRegister(count); + if (i == 0) { + GraalDirectives.spillRegisters(); + continue; + } + GraalDirectives.spillRegisters(); + count++; + } + return count; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 25); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ArrayCompare01.java 2016-12-07 13:53:15.494379623 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class ArrayCompare01 extends JTTTest { + + static final long[] a1 = {1, 2, 3, -5}; + static final long[] a2 = {1, 2, 3, -5}; + static final long[] a3 = {1, 2, 4, -5}; + + public static boolean test(int arg) { + if (arg == 0) { + return compare(a1, a2); + } + if (arg == 1) { + return compare(a1, a3); + } + return false; + } + + static boolean compare(long[] a, long[] b) { + if (a.length == b.length) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + return false; + } + } + return true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ArrayCompare02.java 2016-12-07 13:53:15.757391182 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class ArrayCompare02 extends JTTTest { + + static final long[] a1 = {1, 1, 1, 1, 1, 1}; + static final long[] a2 = {1, 1, 1, 2, 1, 1}; + static final long[] a3 = {1, 1, 2, 2, 3, 3}; + + public static boolean test(int arg) { + if (arg == 0) { + return compare(a1); + } + if (arg == 1) { + return compare(a2); + } + if (arg == 2) { + return compare(a3); + } + return false; + } + + static boolean compare(long[] a) { + return a[0] == a[1] & a[2] == a[3] & a[4] == a[5]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BC_invokevirtual2.java 2016-12-07 13:53:16.021402785 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_invokevirtual2 extends JTTTest { + + static Unresolved object; + + public static class Unresolved { + + public int id(int i) { + return i; + } + } + + private static Unresolved object() { + if (object == null) { + object = new Unresolved(); + } + return object; + } + + public static int test(int a) { + return object().id(a); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigByteParams01.java 2016-12-07 13:53:16.285414388 -0800 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigByteParams01 extends JTTTest { + + public static int test(int num) { + int sum = 0; + if (num == 0) { + sum += testA((byte) 0, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testA((byte) 1, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testA((byte) 2, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testA((byte) 3, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testA((byte) 4, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testA((byte) 5, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testA((byte) 6, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testA((byte) 7, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testA((byte) 8, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + } else if (num == 1) { + sum += testB(0, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testB(1, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testB(2, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testB(3, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testB(4, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testB(5, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testB(6, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testB(7, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + sum += testB(8, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + } else if (num == 2) { + for (int i = 0; i < 9; i++) { + sum += testA(i, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + } + } else if (num == 3) { + for (int i = 0; i < 9; i++) { + sum += testB(i, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9); + } + } + return sum; + } + + private static int testA(int choice, byte p0, byte p1, byte p2, byte p3, byte p4, byte p5, byte p6, byte p7, byte p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + private static long testB(int choice, long p0, long p1, long p2, long p3, long p4, long p5, long p6, long p7, long p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigDoubleParams02.java 2016-12-07 13:53:16.550426035 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigDoubleParams02 extends JTTTest { + + public static double test(int choice, double p0, double p1, double p2, double p3, double p4, double p5, double p6, double p7, double p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigFloatParams01.java 2016-12-07 13:53:16.815437683 -0800 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigFloatParams01 extends JTTTest { + + public static double test(int num) { + double sum = 0; + if (num == 0) { + sum += testA(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(1, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(2, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(3, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(4, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(5, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(6, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(7, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(8, 1, 2, 3, 4, 5, 6, 7, 8, 9); + } else if (num == 1) { + sum += testB(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(1, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(2, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(3, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(4, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(5, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(6, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(7, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(8, 1, 2, 3, 4, 5, 6, 7, 8, 9); + } else if (num == 2) { + for (int i = 0; i < 9; i++) { + sum += testA(i, 1, 2, 3, 4, 5, 6, 7, 8, 9); + } + } else if (num == 3) { + for (int i = 0; i < 9; i++) { + sum += testB(i, 1, 2, 3, 4, 5, 6, 7, 8, 9); + } + } + return sum; + } + + private static float testA(int choice, float p0, float p1, float p2, float p3, float p4, float p5, float p6, float p7, float p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + private static double testB(int choice, double p0, double p1, double p2, double p3, double p4, double p5, double p6, double p7, double p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigFloatParams02.java 2016-12-07 13:53:17.079449286 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigFloatParams02 extends JTTTest { + + public static float test(int choice, float p0, float p1, float p2, float p3, float p4, float p5, float p6, float p7, float p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigIntParams01.java 2016-12-07 13:53:17.344460933 -0800 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigIntParams01 extends JTTTest { + + public static int test(int num) { + int sum = 0; + if (num == 0) { + sum += testA(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(1, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(2, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(3, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(4, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(5, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(6, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(7, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(8, 1, 2, 3, 4, 5, 6, 7, 8, 9); + } else if (num == 1) { + sum += testB(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(1, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(2, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(3, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(4, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(5, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(6, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(7, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testB(8, 1, 2, 3, 4, 5, 6, 7, 8, 9); + } else if (num == 2) { + for (int i = 0; i < 9; i++) { + sum += testA(i, 1, 2, 3, 4, 5, 6, 7, 8, 9); + } + } else if (num == 3) { + for (int i = 0; i < 9; i++) { + sum += testB(i, 1, 2, 3, 4, 5, 6, 7, 8, 9); + } + } + return sum; + } + + private static int testA(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + private static long testB(int choice, long p0, long p1, long p2, long p3, long p4, long p5, long p6, long p7, long p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigIntParams02.java 2016-12-07 13:53:17.608472536 -0800 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigIntParams02 extends JTTTest { + + public static int test(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 1, 2, 3, 4, 5, 6, 7, -8, -9); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1, 2, 3, 4, 5, 6, 7, -8, -9); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, 1, 2, 3, 4, 5, 6, 7, -8, -9); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, 1, 2, 3, 4, 5, 6, 7, -8, -9); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4, 1, 2, 3, 4, 5, 6, 7, -8, -9); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5, 1, 2, 3, 4, 5, 6, 7, -8, -9); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6, 1, 2, 3, 4, 5, 6, 7, -8, -9); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7, 1, 2, 3, 4, 5, 6, 7, -8, -9); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8, 1, 2, 3, 4, 5, 6, 7, -8, -9); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigInterfaceParams01.java 2016-12-07 13:53:17.871484096 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigInterfaceParams01 extends JTTTest { + + public static String test(boolean b, String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) { + I i = b ? new A() : new B(); + return i.test(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); + } + + interface I { + + String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9); + } + + static class A implements I { + + @Override + public String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) { + return "A" + p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9; + } + } + + static class B implements I { + + @Override + public String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) { + return "B" + p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", true, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); + } + + @Test + public void run1() throws Throwable { + runTest("test", false, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigLongParams02.java 2016-12-07 13:53:18.137495787 -0800 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigLongParams02 extends JTTTest { + + public static long test(int choice, long p0, long p1, long p2, long p3, long p4, long p5, long p6, long p7, long p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams01.java 2016-12-07 13:53:18.402507434 -0800 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigMixedParams01 extends JTTTest { + + public static double test(int num) { + double sum = 0; + if (num == 0) { + sum += testA(0, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + sum += testA(1, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + sum += testA(2, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + sum += testA(3, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + sum += testA(4, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + sum += testA(5, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + sum += testA(6, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + sum += testA(7, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + sum += testA(8, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + } else if (num == 1) { + sum += testB(0, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + sum += testB(1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + sum += testB(2, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + sum += testB(3, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + sum += testB(4, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + sum += testB(5, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + sum += testB(6, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + sum += testB(7, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + sum += testB(8, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + } else if (num == 2) { + for (int i = 0; i < 9; i++) { + sum += testA(i, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + } + } else if (num == 3) { + for (int i = 0; i < 9; i++) { + sum += testB(i, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + } + } + return sum; + } + + @SuppressWarnings("unused") + private static float testA(int choice, int i0, int i1, int i2, int i3, float p0, float p1, float p2, float p3, int i4, int i5, float p4, float p5, float p6, float p7, float p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @SuppressWarnings("unused") + private static double testB(int choice, int i0, int i1, int i2, double p0, double p1, double p2, double p3, int i3, int i4, double p4, double p5, double p6, double p7, double p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams02.java 2016-12-07 13:53:18.667519081 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigMixedParams02 extends JTTTest { + + @SuppressWarnings("unused") + public static float test(int choice, int i0, int i1, int i2, int i3, float p0, float p1, float p2, float p3, int i4, int i5, float p4, float p5, float p6, float p7, float p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams03.java 2016-12-07 13:53:18.931530684 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigMixedParams03 extends JTTTest { + + @SuppressWarnings("unused") + public static double test(int choice, int i0, int i1, int i2, int i3, double p0, double p1, double p2, double p3, int i4, int i5, double p4, double p5, double p6, double p7, double p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams04.java 2016-12-07 13:53:19.195542288 -0800 @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +package org.graalvm.compiler.jtt.micro; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/** + * Tests different alignment on the stack with extended parameters (index > 5). + */ +public class BigMixedParams04 extends JTTTest { + + @SuppressWarnings("unused") + public static long test(int choice, int i0, int i1, int i2, int i3, double d1, double d2, boolean bo1, boolean bo2, byte by, short sh, char ch, int in) { + switch (choice) { + case 0: + return bo1 ? 1L : 2L; + case 1: + return bo2 ? 1L : 2L; + case 2: + return by; + case 3: + return sh; + case 4: + return ch; + case 5: + return in; + } + return 42; + } + + /** + * Test SPARC mixed params with double/single float register overlapping. + * + * @param f1 + * @param d2 + * @param f3 + * @return Must always return the argument d2 + */ + @SuppressWarnings("all") + public static double test2(int i1, float f1, double d2, float f3, +// @formatter:off + double ad1, + double ad2, + double ad3, + double ad4, + double ad5, + double ad6, + double ad7, + double ad8, + double ad9, + double ad10, + double ad11, + double ad12, + double ad13, + double ad14, + double ad15, + double ad16, + float af1, + float af2, + float af3, + float af4, + float af5, + float af6, + float af7, + float af8, + float af9, + float af10, + float af11, + float af12, + float af13, + float af14, + float af15, + float af16 + // @formatter:on + ) { + + // now do something with the locals to make sure the locals don't get optimized away. + for (int i = 0; i < i1; i++) { + af1 += f1; + af2 += f1; + af3 += f1; + af4 += f1; + af5 += f1; + af6 += f1; + af7 += f1; + af8 += f1; + af9 += f1; + af10 += f1; + af11 += f1; + af12 += f1; + af13 += f1; + af14 += f1; + af15 += f1; + af16 += f1; + ad1 += f1; + ad2 += f1; + ad3 += f1; + ad4 += f1; + ad5 += f1; + ad6 += f1; + ad7 += f1; + ad8 += f1; + ad9 += f1; + ad10 += f1; + ad11 += f1; + ad12 += f1; + ad13 += f1; + ad14 += f1; + ad15 += f1; + ad16 += f1; + } + // @formatter:off + boolean orderFloat = + af1 < af2 && + af2 < af3 && + af3 < af4 && + af4 < af5 && + af5 < af6 && + af6 < af7 && + af7 < af8 && + af8 < af9 && + af9 < af10 && + af10 < af11 && + af11 < af12 && + af12 < af13 && + af13 < af14 && + af14 < af15 && + af15 < af16; + boolean orderDouble = + ad1 < ad2 && + ad2 < ad3 && + ad3 < ad4 && + ad4 < ad5 && + ad5 < ad6 && + ad6 < ad7 && + ad7 < ad8 && + ad8 < ad9 && + ad9 < ad10 && + ad10 < ad11 && + ad11 < ad12 && + ad12 < ad13 && + ad13 < ad14 && + ad14 < ad15 && + ad15 < ad16; + // @formatter:on + if (orderDouble && orderFloat) { + return f1 + d2 + f3; // this should not be destroyed + } + Assert.fail(); + return 0.0; + } + + /** + * Test SPARC mixed params with double/single float register overlapping. + * + * @param f1 + * @param d2 + * @param f3 + * @return Must always return the argument d2 + */ + @SuppressWarnings("all") + public static double test3(boolean f, int idx, +// @formatter:off + double ad1, + double ad2, + double ad3, + double ad4, + double ad5, + double ad6, + double ad7, + double ad8, + double ad9, + double ad10, + double ad11, + double ad12, + double ad13, + double ad14, + double ad15, + double ad16, + float af1, + float af2, + float af3, + float af4, + float af5, + float af6, + float af7, + float af8, + float af9, + float af10, + float af11, + float af12, + float af13, + float af14, + float af15, + float af16 + ) { + switch(f ? idx + 16 : idx) { + case 1 : return ad1; + case 2 : return ad2; + case 3 : return ad3; + case 4 : return ad4; + case 5 : return ad5; + case 6 : return ad6; + case 7 : return ad7; + case 8 : return ad8; + case 9 : return ad9; + case 10: return ad10; + case 11: return ad11; + case 12: return ad12; + case 13: return ad13; + case 14: return ad14; + case 15: return ad15; + case 16: return ad16; + case 1 + 16: return af1; + case 2 + 16: return af2; + case 3 + 16: return af3; + case 4 + 16: return af4; + case 5 + 16: return af5; + case 6 + 16: return af6; + case 7 + 16: return af7; + case 8 + 16: return af8; + case 9 + 16: return af9; + case 10 + 16: return af10; + case 11 + 16: return af11; + case 12 + 16: return af12; + case 13 + 16: return af13; + case 14 + 16: return af14; + case 15 + 16: return af15; + case 16 + 16: return af16; + } + Assert.fail(); // should not reach here + return 0; + + } + // @formatter:on + + @Test + public void run0() throws Throwable { + runTest("test", 0, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF); + } + + @Test + public void run6() throws Throwable { + // @formatter:off + runTest("test2", 20, 1.0f, -3.2912948246387967943231233d, 3.0f, + 1d, + 2d, + 3d, + 4d, + 5d, + 6d, + 7d, + 8d, + 9d, + 10d, + 11d, + 12d, + 13d, + 14d, + 15d, + 16d, + 1f, + 2f, + 3f, + 4f, + 5f, + 6f, + 7f, + 8f, + 9f, + 10f, + 11f, + 12f, + 13f, + 14f, + 15f, + 16f + ); + // @formatter:on + } + + @Test + public void run7() throws Throwable { + // @formatter:off + for (int i = 0; i < 32 * 2; i++) { + runTest("test3", i % 2 == 0, i / 2, + 1d, + 2d, + 3d, + 4d, + 5d, + 6d, + 7d, + 8d, + 9d, + 10d, + 11d, + 12d, + 13d, + 14d, + 15d, + 16d, + 1f, + 2f, + 3f, + 4f, + 5f, + 6f, + 7f, + 8f, + 9f, + 10f, + 11f, + 12f, + 13f, + 14f, + 15f, + 16f + ); + } + // @formatter:on + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigObjectParams01.java 2016-12-07 13:53:19.461553979 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigObjectParams01 extends JTTTest { + + @SuppressWarnings("unused") + public static String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) { + return p0; + } + + @Test + public void run0() throws Throwable { + runTest("test", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "a", null, null, null, null, null, null, null, null, null); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigObjectParams02.java 2016-12-07 13:53:19.726565626 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigObjectParams02 extends JTTTest { + + public static String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) { + return p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9; + } + + @Test + public void run0() throws Throwable { + runTest("test", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigParamsAlignment.java 2016-12-07 13:53:19.990577229 -0800 @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + */ +/* + */ +package org.graalvm.compiler.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BigParamsAlignment extends JTTTest { + + public static int test(int num) { + int sum = 0; + if (num == 0) { + sum += testA(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(1, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(2, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(3, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(4, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(5, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(6, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(7, 1, 2, 3, 4, 5, 6, 7, 8, 9); + sum += testA(8, 1, 2, 3, 4, 5, 6, 7, 8, 9); + } else if (num == 1) { + sum += testB(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + sum += testB(1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + sum += testB(2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + sum += testB(3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + sum += testB(4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + sum += testB(5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + sum += testB(6, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + sum += testB(7, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + sum += testB(8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + sum += testB(9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } else if (num == 2) { + for (int i = 0; i < 9; i++) { + sum += testA(i, 1, 2, 3, 4, 5, 6, 7, 8, 9); + } + } else if (num == 3) { + for (int i = 0; i < 10; i++) { + sum += testB(i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + } else if (num == 4) { + for (int i = 0; i < 11; i++) { + sum += testC(i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + } + } else if (num == 5) { + for (int i = 0; i < 12; i++) { + sum += testD(i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); + } + } + return sum; + } + + private static int testA(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + private static int testB(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + case 9: + return p9; + } + return 42; + } + + private static int testC(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + case 9: + return p9; + case 10: + return p10; + } + return 42; + } + + private static int testD(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + case 9: + return p9; + case 10: + return p10; + case 11: + return p11; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigShortParams01.java 2016-12-07 13:53:20.254588832 -0800 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigShortParams01 extends JTTTest { + + public static int test(int num) { + int sum = 0; + if (num == 0) { + sum += testA((short) 0, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testA((short) 1, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testA((short) 2, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testA((short) 3, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testA((short) 4, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testA((short) 5, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testA((short) 6, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testA((short) 7, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testA((short) 8, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + } else if (num == 1) { + sum += testB(0, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testB(1, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testB(2, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testB(3, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testB(4, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testB(5, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testB(6, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testB(7, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + sum += testB(8, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + } else if (num == 2) { + for (int i = 0; i < 9; i++) { + sum += testA(i, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + } + } else if (num == 3) { + for (int i = 0; i < 9; i++) { + sum += testB(i, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9); + } + } + return sum; + } + + private static int testA(int choice, short p0, short p1, short p2, short p3, short p4, short p5, short p6, short p7, short p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + private static long testB(int choice, long p0, long p1, long p2, long p3, long p4, long p5, long p6, long p7, long p8) { + switch (choice) { + case 0: + return p0; + case 1: + return p1; + case 2: + return p2; + case 3: + return p3; + case 4: + return p4; + case 5: + return p5; + case 6: + return p6; + case 7: + return p7; + case 8: + return p8; + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigVirtualParams01.java 2016-12-07 13:53:20.519600479 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BigVirtualParams01 extends JTTTest { + + public static String test(boolean b, String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) { + I i = b ? new A() : new B(); + return i.test(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); + } + + abstract static class I { + + abstract String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9); + } + + static class A extends I { + + @Override + public String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) { + return "A" + p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9; + } + } + + static class B extends I { + + @Override + public String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) { + return "B" + p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", true, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); + } + + @Test + public void run1() throws Throwable { + runTest("test", false, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Bubblesort.java 2016-12-07 13:53:20.784612126 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Bubblesort extends JTTTest { + + public static int test(int num) { + final int[] array = {23, 8, -9, 5, 882, 0, 0, 1}; + + for (int i = 0; i < array.length; i++) { + for (int j = i + 1; j < array.length; j++) { + if (array[j] < array[i]) { + final int tmp = array[i]; + array[i] = array[j]; + array[j] = tmp; + } + } + } + return array[num]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ConstantLoadTest.java 2016-12-07 13:53:21.048623730 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015, 2015, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class ConstantLoadTest extends JTTTest { + + private static final class MyClass { + public long a; + public long b; + + MyClass(long a, long b) { + this.a = a; + this.b = b; + } + } + + private static final MyClass myClass = new MyClass(Long.MIN_VALUE, Long.MAX_VALUE); + private static final long myLong = Long.MAX_VALUE; + + public static long test(int arg) { + if (arg == 0) { + return myClass.a / arg + myLong; + } + if (arg == 1) { + return myClass.b - arg + myLong; + } + long r = 1; + for (int i = 0; i < arg; i++) { + r *= i; + } + return r; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Fibonacci.java 2016-12-07 13:53:21.313635377 -0800 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Fibonacci extends JTTTest { + + public static int test(int num) { + if (num <= 0) { + return 0; + } + int n1 = 0; + int n2 = 1; + for (int i = 1; i < num; i++) { + final int next = n2 + n1; + n1 = n2; + n2 = next; + } + return n2; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/FloatingReads.java 2016-12-07 13:53:21.577646980 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class FloatingReads extends JTTTest { + + public static long init = Runtime.getRuntime().totalMemory(); + private final int f = 10; + private int a; + private int b; + private int c; + + public int test(int d) { + a = 3; + b = 5; + c = 7; + for (int i = 0; i < d; i++) { + if (i % 2 == 0) { + a += b; + } + if (i % 4 == 0) { + b += c; + } else if (i % 3 == 0) { + b -= a; + } + if (i % 5 == 0) { + for (int j = 0; j < i; j++) { + c += a; + } + a -= f; + } + b = a ^ c; + if (i % 6 == 0) { + c--; + } else if (i % 7 == 0) { + Runtime.getRuntime().totalMemory(); + } + } + return a + b + c; + } + + @Test + public void run0() { + runTest("test", 10); + } + + @Test + public void run1() { + runTest("test", 1000); + } + + @Test + public void run2() { + runTest("test", 1); + } + + @Test + public void run3() { + runTest("test", 0); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_01.java 2016-12-07 13:53:21.842658627 -0800 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014, 2014, 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.jtt.micro; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class InvokeInterface_01 extends JTTTest { + + interface I { + + int plus(int a); + } + + abstract static class A implements I { + + @Override + public int plus(int a) { + return a; + } + } + + static class C1 extends A { + } + + static class C2 extends A { + } + + static class C3 extends A { + } + + static class C4 extends A { + } + + static class C5 extends A { + } + + static class C6 extends A { + } + + static class C7 extends A { + } + + static class C8 extends A { + } + + static class C9 extends A { + } + + static class C10 extends A { + } + + static class C11 extends A { + } + + static class C12 extends A { + } + + static class C13 extends A { + } + + static class C14 extends A { + } + + static class C15 extends A { + } + + public static int test(I i, int a) { + return i.plus(a); + } + + @Before + public void setUp() { + I[] x = new I[]{new C1(), new C2(), new C3(), new C4(), new C5(), new C6(), new C7(), new C8(), new C9(), new C10(), new C11(), new C12(), new C13(), new C14(), new C15()}; + int a = 0; + for (I i : x) { + i.plus(a++); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", new C1(), 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", new C2(), 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_02.java 2016-12-07 13:53:22.106670231 -0800 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014, 2014, 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.jtt.micro; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class InvokeInterface_02 extends JTTTest { + + interface I { + + int plus(int a); + } + + static class A implements I { + + @Override + public int plus(int a) { + return a; + } + } + + static class C1 extends A { + } + + static class C2 extends A { + } + + static class C3 extends A { + } + + static class C4 extends A { + } + + static class C5 extends A { + } + + static class C6 extends A { + } + + static class C7 extends A { + } + + static class C8 extends A { + } + + static class C9 extends A { + } + + static class C10 extends A { + } + + static class C11 extends A { + } + + static class C12 extends A { + } + + static class C13 extends A { + } + + static class C14 extends A { + } + + static class C15 extends A { + } + + public static int test(I i, int a) { + return i.plus(a); + } + + @Before + public void setUp() { + I[] x = new I[]{new C1(), new C2(), new C3(), new C4(), new C5(), new C6(), new C7(), new C8(), new C9(), new C10(), new C11(), new C12(), new C13(), new C14(), new C15()}; + int a = 0; + for (I i : x) { + i.plus(a++); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", new C1(), 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", new C2(), 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_03.java 2016-12-07 13:53:22.371681878 -0800 @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2014, 2014, 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.jtt.micro; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class InvokeInterface_03 extends JTTTest { + + interface I { + + int plus(int a); + } + + abstract static class A implements I { + } + + static class C1 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C2 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C3 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C4 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C5 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C6 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C7 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C8 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C9 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C10 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C11 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C12 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C13 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C14 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C15 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + public static int test(I i, int a) { + return i.plus(a); + } + + @Before + public void setUp() { + I[] x = new I[]{new C1(), new C2(), new C3(), new C4(), new C5(), new C6(), new C7(), new C8(), new C9(), new C10(), new C11(), new C12(), new C13(), new C14(), new C15()}; + int a = 0; + for (I i : x) { + i.plus(a++); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", new C1(), 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", new C2(), 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_04.java 2016-12-07 13:53:22.635693481 -0800 @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2014, 2014, 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.jtt.micro; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class InvokeInterface_04 extends JTTTest { + + interface I { + + int plus(int a); + } + + abstract static class A implements I { + @Override + public abstract int plus(int a); + } + + static class C1 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C2 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C3 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C4 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C5 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C6 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C7 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C8 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C9 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C10 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C11 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C12 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C13 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C14 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + static class C15 extends A { + + @Override + public int plus(int a) { + return a; + } + } + + public static int test(I i, int a) { + return i.plus(a); + } + + @Before + public void setUp() { + I[] x = new I[]{new C1(), new C2(), new C3(), new C4(), new C5(), new C6(), new C7(), new C8(), new C9(), new C10(), new C11(), new C12(), new C13(), new C14(), new C15()}; + int a = 0; + for (I i : x) { + i.plus(a++); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", new C1(), 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", new C2(), 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeVirtual_01.java 2016-12-07 13:53:22.900705128 -0800 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class InvokeVirtual_01 extends JTTTest { + + static class A { + + int plus(int a) { + return a; + } + } + + static class B extends A { + + @Override + int plus(int a) { + return a + 10; + } + } + + static class C extends A { + + @Override + int plus(int a) { + return a + 20; + } + } + + static A aObject = new A(); + static A bObject = new B(); + static A cObject = new C(); + + public static int test(int a) { + if (a == 0) { + return aObject.plus(a); + } + if (a == 1) { + return bObject.plus(a); + } + if (a == 2) { + return cObject.plus(a); + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeVirtual_02.java 2016-12-07 13:53:23.165716775 -0800 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class InvokeVirtual_02 extends JTTTest { + + static class A { + + long plus(long a) { + return a; + } + } + + static class B extends A { + + @Override + long plus(long a) { + return a + 10; + } + } + + static class C extends A { + + @Override + long plus(long a) { + return a + 20; + } + } + + static A objectA = new A(); + static A objectB = new B(); + static A objectC = new C(); + + public static long test(long a) { + if (a == 0) { + return objectA.plus(a); + } + if (a == 1) { + return objectB.plus(a); + } + if (a == 2) { + return objectC.plus(a); + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Matrix01.java 2016-12-07 13:53:23.429728378 -0800 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Matrix01 extends JTTTest { + + public static class Matrix { + + final int id; + + Matrix(int id) { + this.id = id; + } + } + + public static int test(int arg) { + if (arg == 0) { + return matrix1(3) + matrix1(5); + } + if (arg == 1) { + return matrix2(3) + matrix2(5); + } + if (arg == 2) { + return matrix3(3) + matrix3(5); + } + if (arg == 3) { + return matrix4(3) + matrix4(5); + } + if (arg == 4) { + return matrix5(3) + matrix5(5); + } + return 42; + } + + static int matrix1(int size) { + Matrix[] matrix = new Matrix[size]; + fillMatrix(matrix, size); + int count = 0; + for (Matrix m : matrix) { + if (m != null) { + count++; + } + } + return count; + } + + static int matrix2(int size) { + Matrix[][] matrix = new Matrix[size][size]; + fillMatrix(matrix, size * size); + int count = 0; + for (Matrix[] n : matrix) { + for (Matrix m : n) { + if (m != null) { + count++; + } + } + } + return count; + } + + static int matrix3(int size) { + Matrix[][][] matrix = new Matrix[size][5][size]; + fillMatrix(matrix, size * size * size); + int count = 0; + for (Matrix[][] o : matrix) { + for (Matrix[] n : o) { + for (Matrix m : n) { + if (m != null) { + count++; + } + } + } + } + return count; + } + + static int matrix4(int size) { + Matrix[][][][] matrix = new Matrix[size][2][size][3]; + fillMatrix(matrix, size * size * size * size); + int count = 0; + for (Matrix[][][] p : matrix) { + for (Matrix[][] o : p) { + for (Matrix[] n : o) { + for (Matrix m : n) { + if (m != null) { + count++; + } + } + } + } + } + return count; + } + + static int matrix5(int size) { + Matrix[][][][][] matrix = new Matrix[size][size][3][4][size]; + fillMatrix(matrix, size * size * size * size * size); + int count = 0; + for (Matrix[][][][] q : matrix) { + for (Matrix[][][] p : q) { + for (Matrix[][] o : p) { + for (Matrix[] n : o) { + for (Matrix m : n) { + if (m != null) { + count++; + } + } + } + } + } + } + return count; + } + + static void fillMatrix(Object[] matrix, int total) { + for (int i = 0; i < 10000; i += 7) { + int number = i % total; + set(matrix, number); + } + } + + static void set(Object[] matrix, int number) { + int val = number; + Object[] array = matrix; + while (!(array instanceof Matrix[])) { + int index = val % array.length; + val = val / array.length; + array = (Object[]) array[index]; + } + ((Matrix[]) array)[val % array.length] = new Matrix(number); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ReferenceMap01.java 2016-12-07 13:53:23.693739982 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class ReferenceMap01 extends JTTTest { + + public static Integer val1 = new Integer(3); + public static Integer val2 = new Integer(4); + + @SuppressWarnings("unused") + private static String foo(String[] a) { + String[] args = new String[]{"78"}; + Integer i1 = new Integer(1); + Integer i2 = new Integer(2); + Integer i3 = val1; + Integer i4 = val2; + Integer i5 = new Integer(5); + Integer i6 = new Integer(6); + Integer i7 = new Integer(7); + Integer i8 = new Integer(8); + Integer i9 = new Integer(9); + Integer i10 = new Integer(10); + Integer i11 = new Integer(11); + Integer i12 = new Integer(12); + + System.gc(); + int sum = i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + i12; + return args[0] + sum; + } + + public static int test() { + return Integer.valueOf(foo(new String[]{"asdf"})); + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/StrangeFrames.java 2016-12-07 13:53:23.957751585 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +@SuppressWarnings("unused") +public class StrangeFrames extends JTTTest { + + public static boolean test(int arg) { + empty(); + oneOperandStackSlot(); + twoOperandStackSlots(); + oneLocalSlot(); + return true; + } + + static void empty() { + // do nothing. + } + + static void oneOperandStackSlot() { + new DummyTestClass(); + } + + static void twoOperandStackSlots() { + two(new DummyTestClass(), new DummyTestClass()); + } + + static void oneLocalSlot() { + int a; + } + + static void two(Object a, Object b) { + Object c = b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/String_format01.java 2016-12-07 13:53:24.222763232 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class String_format01 extends JTTTest { + + public static String test(String s) { + return String.format("Hello %s", s); + } + + @Test + public void run0() throws Throwable { + runTest("test", "World"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "New World Order"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/String_format02.java 2016-12-07 13:53:24.486774835 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class String_format02 extends JTTTest { + + public static String test(int val) { + return String.format("Hello %d", val); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", -11); + } + + @Test + public void run2() throws Throwable { + runTest("test", -2147483648); + } + + @Test + public void run3() throws Throwable { + runTest("test", 2147483647); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_String01.java 2016-12-07 13:53:24.750786438 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class VarArgs_String01 extends JTTTest { + + public static String test(int arg) { + if (arg == 4) { + return get(0); + } + return get(arg, "a", null, "test"); + } + + private static String get(int index, String... args) { + return args[index]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_Unroll.java 2016-12-07 13:53:25.016798129 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 2015, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class VarArgs_Unroll extends JTTTest { + + public static boolean test(String a, String b) { + return check(a, b); + } + + private static boolean check(String... args) { + if (args.length == 0) { + return true; + } + String s = args[0]; + for (String t : args) { + if (!t.equals(s)) { + return false; + } + } + return true; + } + + @Test + public void run0() throws Throwable { + runTest("test", "ab", "ab"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "ab", "abc"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_boolean01.java 2016-12-07 13:53:25.280809732 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class VarArgs_boolean01 extends JTTTest { + + public static boolean test(int arg) { + if (arg == 4) { + return get(0); + } + return get(arg, true, false, true); + } + + private static boolean get(int index, boolean... args) { + return args[index]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_byte01.java 2016-12-07 13:53:25.544821336 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class VarArgs_byte01 extends JTTTest { + + public static byte test(int arg) { + if (arg == 4) { + return get(0); + } + return get(arg, (byte) 1, (byte) 2, (byte) 3); + } + + private static byte get(int index, byte... args) { + return args[index]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_char01.java 2016-12-07 13:53:25.808832939 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class VarArgs_char01 extends JTTTest { + + public static char test(int arg) { + if (arg == 4) { + return get(0); + } + return get(arg, 'a', 'b', 'c'); + } + + private static char get(int index, char... args) { + return args[index]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_double01.java 2016-12-07 13:53:26.077844762 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class VarArgs_double01 extends JTTTest { + + public static double test(int arg) { + if (arg == 4) { + return get(0); + } + return get(arg, 0.0d, 1.0d, 2.0d); + } + + private static double get(int index, double... args) { + return args[index]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_float01.java 2016-12-07 13:53:26.342856409 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class VarArgs_float01 extends JTTTest { + + public static float test(int arg) { + if (arg == 4) { + return get(0); + } + return get(arg, 0.0f, 1.0f, 2.0f); + } + + private static float get(int index, float... args) { + return args[index]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_int01.java 2016-12-07 13:53:26.606868012 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class VarArgs_int01 extends JTTTest { + + public static int test(int arg) { + if (arg == 4) { + return get(0); + } + return get(arg, 0, 1, 2); + } + + private static int get(int index, int... args) { + return args[index]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_long01.java 2016-12-07 13:53:26.874879791 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class VarArgs_long01 extends JTTTest { + + public static long test(int arg) { + if (arg == 4) { + return get(0); + } + return get(arg, 0L, 1L, 2L); + } + + private static long get(int index, long... args) { + return args[index]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_short01.java 2016-12-07 13:53:27.138891394 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.micro; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class VarArgs_short01 extends JTTTest { + + public static short test(int arg) { + if (arg == 4) { + return get(0); + } + return get(arg, (short) 0, (short) 1, (short) 2); + } + + private static short get(int index, short... args) { + return args[index]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_01.java 2016-12-07 13:53:27.402902997 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class ABCE_01 extends JTTTest { + + public static int[] array = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + public static int test(int a) { + int arg = a; + for (int i = 0; i < array.length; i++) { + arg += array[i]; + } + return arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_02.java 2016-12-07 13:53:27.665914557 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class ABCE_02 extends JTTTest { + + public static int[] array = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + public static int test(int arg) { + int r = 0; + for (int i = 0; i < arg; i++) { + r += array[i]; + } + return r; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 20); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_03.java 2016-12-07 13:53:27.929926160 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class ABCE_03 extends JTTTest { + + private static final int[] ARRAY1 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + private static final int[] ARRAY2 = new int[]{1}; + + public static int test(int arg) { + int[] array = arg == 0 ? ARRAY2 : ARRAY1; + int r = 0; + for (int i = 0; i < arg; i++) { + r += array[i]; + } + return r; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 20); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy01.java 2016-12-07 13:53:28.193937763 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests calls to the array copy method. + */ +public class ArrayCopy01 extends JTTTest { + + public static Object[] src = new Object[]{null, null}; + public static Object[] dest = new Object[]{null, null}; + static { + // Ensure System is resolved + System.arraycopy(src, 0, src, 0, src.length); + } + + public static int test(int srcPos, int destPos, int length) { + System.arraycopy(src, srcPos, dest, destPos, length); + return 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1, 0, 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -1, 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 0, 0, 2); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0, 1, 2); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1, 0, 2); + } + + @Test + public void run7() throws Throwable { + runTest("test", 1, 1, -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy02.java 2016-12-07 13:53:28.456949323 -0800 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests calls to the array copy method. + */ +public class ArrayCopy02 extends JTTTest { + + public static int[] src = new int[]{0, 1, 2, 3, 4, 5}; + public static int[] dest0 = new int[]{5, 4, 3, 2, 1, 0}; + public static int[] dest = new int[]{5, 4, 3, 2, 1, 0}; + static { + // Ensure System is resolved + System.arraycopy(src, 0, src, 0, src.length); + } + + @Before + public void setUp() { + System.currentTimeMillis(); + for (int i = 0; i < dest.length; i++) { + dest[i] = dest0[i]; + } + } + + public static int[] test(int srcPos, int destPos, int length) { + System.arraycopy(src, srcPos, dest, destPos, length); + return dest; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1, 0, 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -1, 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 0, 0, 2); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0, 1, 6); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1, 0, 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 1, 1, -1); + } + + @Test + public void run8() throws Throwable { + runTest("test", 0, 1, 2); + } + + @Test + public void run9() throws Throwable { + runTest("test", 1, 0, 2); + } + + @Test + public void run10() throws Throwable { + runTest("test", 1, 1, 2); + } + + @Test + public void run11() throws Throwable { + runTest("test", 0, 0, 6); + } + + @Test + public void run12() throws Throwable { + runTest("test", 0, 1, 5); + } + + @Test + public void run13() throws Throwable { + runTest("test", 1, 0, 5); + } + + @Test + public void run14() throws Throwable { + runTest("test", 1, 1, 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy03.java 2016-12-07 13:53:28.719960881 -0800 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests calls to the array copy method. + */ +public class ArrayCopy03 extends JTTTest { + + public static byte[] src = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + public static byte[] dest0 = new byte[]{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + public static byte[] dest = new byte[]{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + static { + // Ensure System is resolved + System.arraycopy(src, 0, src, 0, src.length); + } + + @Before + public void setUp() { + System.currentTimeMillis(); + for (int i = 0; i < dest.length; i++) { + dest[i] = dest0[i]; + } + } + + public static byte[] test(int srcPos, int destPos, int length) { + System.arraycopy(src, srcPos, dest, destPos, length); + return dest; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1, 0, 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -1, 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 0, 0, 2); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0, 1, 11); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1, 0, 11); + } + + @Test + public void run7() throws Throwable { + runTest("test", 1, 1, -1); + } + + @Test + public void run8() throws Throwable { + runTest("test", 0, 1, 2); + } + + @Test + public void run9() throws Throwable { + runTest("test", 1, 0, 2); + } + + @Test + public void run10() throws Throwable { + runTest("test", 1, 1, 2); + } + + @Test + public void run11() throws Throwable { + runTest("test", 0, 0, 6); + } + + @Test + public void run12() throws Throwable { + runTest("test", 0, 1, 5); + } + + @Test + public void run13() throws Throwable { + runTest("test", 1, 0, 5); + } + + @Test + public void run14() throws Throwable { + runTest("test", 1, 1, 5); + } + + @Test + public void run15() throws Throwable { + runTest("test", 0, 0, 11); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy04.java 2016-12-07 13:53:28.982972441 -0800 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests calls to the array copy method. + */ +public class ArrayCopy04 extends JTTTest { + + public static byte[] array = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + public static byte[] array0 = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + static { + // Ensure System is resolved + System.arraycopy(array, 0, array, 0, array.length); + } + + @Before + public void setUp() { + System.currentTimeMillis(); + for (int i = 0; i < array.length; i++) { + array[i] = array0[i]; + } + } + + public static byte[] test(int srcPos, int destPos, int length) { + System.arraycopy(array, srcPos, array, destPos, length); + return array; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1, 0, 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -1, 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 0, 0, 2); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0, 1, 11); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1, 0, 11); + } + + @Test + public void run7() throws Throwable { + runTest("test", 1, 1, -1); + } + + @Test + public void run8() throws Throwable { + runTest("test", 0, 1, 2); + } + + @Test + public void run9() throws Throwable { + runTest("test", 1, 0, 2); + } + + @Test + public void run10() throws Throwable { + runTest("test", 1, 1, 2); + } + + @Test + public void run11() throws Throwable { + runTest("test", 0, 0, 6); + } + + @Test + public void run12() throws Throwable { + runTest("test", 0, 1, 5); + } + + @Test + public void run13() throws Throwable { + runTest("test", 1, 0, 5); + } + + @Test + public void run14() throws Throwable { + runTest("test", 1, 1, 5); + } + + @Test + public void run15() throws Throwable { + runTest("test", 0, 0, 11); + } + + @Test + public void run16() throws Throwable { + runTest("test", 0, 1, 10); + } + + @Test + public void run17() throws Throwable { + runTest("test", 1, 0, 10); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy05.java 2016-12-07 13:53:29.247984088 -0800 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests calls to the array copy method. + */ +public class ArrayCopy05 extends JTTTest { + + public static char[] array = new char[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + public static char[] array0 = new char[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + static { + // Ensure System is resolved + System.arraycopy(array, 0, array, 0, array.length); + } + + @Before + public void setUp() { + System.currentTimeMillis(); + for (int i = 0; i < array.length; i++) { + array[i] = array0[i]; + } + } + + public static char[] test(int srcPos, int destPos, int length) { + System.arraycopy(array, srcPos, array, destPos, length); + return array; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1, 0, 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -1, 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 0, 0, 2); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0, 1, 11); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1, 0, 11); + } + + @Test + public void run7() throws Throwable { + runTest("test", 1, 1, -1); + } + + @Test + public void run8() throws Throwable { + runTest("test", 0, 1, 2); + } + + @Test + public void run9() throws Throwable { + runTest("test", 1, 0, 2); + } + + @Test + public void run10() throws Throwable { + runTest("test", 1, 1, 2); + } + + @Test + public void run11() throws Throwable { + runTest("test", 0, 0, 6); + } + + @Test + public void run12() throws Throwable { + runTest("test", 0, 1, 5); + } + + @Test + public void run13() throws Throwable { + runTest("test", 1, 0, 5); + } + + @Test + public void run14() throws Throwable { + runTest("test", 1, 1, 5); + } + + @Test + public void run15() throws Throwable { + runTest("test", 0, 0, 11); + } + + @Test + public void run16() throws Throwable { + runTest("test", 0, 1, 10); + } + + @Test + public void run17() throws Throwable { + runTest("test", 1, 0, 10); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy06.java 2016-12-07 13:53:29.512995735 -0800 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests calls to the array copy method. + */ +public class ArrayCopy06 extends JTTTest { + + public static short[] array = new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + public static short[] array0 = new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + static { + // Ensure System is resolved + System.arraycopy(array, 0, array, 0, array.length); + } + + @Before + public void setUp() { + System.currentTimeMillis(); + for (int i = 0; i < array.length; i++) { + array[i] = array0[i]; + } + } + + public static short[] test(int srcPos, int destPos, int length) { + System.arraycopy(array, srcPos, array, destPos, length); + return array; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, 0, -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", -1, 0, 0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -1, 0); + } + + @Test + public void run4() throws Throwable { + runTest("test", 0, 0, 2); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0, 1, 11); + } + + @Test + public void run6() throws Throwable { + runTest("test", 1, 0, 11); + } + + @Test + public void run7() throws Throwable { + runTest("test", 1, 1, -1); + } + + @Test + public void run8() throws Throwable { + runTest("test", 0, 1, 2); + } + + @Test + public void run9() throws Throwable { + runTest("test", 1, 0, 2); + } + + @Test + public void run10() throws Throwable { + runTest("test", 1, 1, 2); + } + + @Test + public void run11() throws Throwable { + runTest("test", 0, 0, 6); + } + + @Test + public void run12() throws Throwable { + runTest("test", 0, 1, 5); + } + + @Test + public void run13() throws Throwable { + runTest("test", 1, 0, 5); + } + + @Test + public void run14() throws Throwable { + runTest("test", 1, 1, 5); + } + + @Test + public void run15() throws Throwable { + runTest("test", 0, 0, 11); + } + + @Test + public void run16() throws Throwable { + runTest("test", 0, 1, 10); + } + + @Test + public void run17() throws Throwable { + runTest("test", 1, 0, 10); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopyGeneric.java 2016-12-07 13:53:29.777007338 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests calls to the array copy method. + */ +public class ArrayCopyGeneric extends JTTTest { + + public Object[] arraysFrom; + public Object[] arraysTo; + + public void init() { + arraysFrom = new Object[]{new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + new long[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new float[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}; + arraysTo = new Object[]{new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + new long[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new float[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}; + } + + public Object test() { + init(); + + for (int i = 0; i < arraysFrom.length; i++) { + Object from = arraysFrom[i]; + Object to = arraysTo[i]; + System.arraycopy(from, 1, to, 2, 2); + System.arraycopy(from, 8, to, 7, 2); + } + return arraysTo; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayLength01.java 2016-12-07 13:53:30.041018940 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of array length operations. + */ +public class ArrayLength01 extends JTTTest { + + public static final int SIZE = 8; + public static final byte[] arr = new byte[5]; + + public static int test(int arg) { + if (arg == 0) { + return arr.length; + } + if (arg == 1) { + return new byte[6].length; + } + if (arg == 2) { + return new Object[7].length; + } + if (arg == 3) { + return new Class[SIZE][].length; + } + if (arg == 4) { + return new int[arg].length; + } + return 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_idiv_16.java 2016-12-07 13:53:30.306030588 -0800 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_idiv_16 extends JTTTest { + + public static int test(int i, int arg) { + if (i == 0) { + final int constant = 16; + return arg / constant; + } + return arg / 16; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, 16); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, 17); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -1); + } + + @Test + public void run4() throws Throwable { + runTest("test", 0, -16); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0, -17); + } + + @Test + public void run6() throws Throwable { + runTest("test", 0, -1024); + } + + @Test + public void run7() throws Throwable { + runTest("test", 1, 0); + } + + @Test + public void run8() throws Throwable { + runTest("test", 1, 16); + } + + @Test + public void run9() throws Throwable { + runTest("test", 1, 17); + } + + @Test + public void run10() throws Throwable { + runTest("test", 1, -1); + } + + @Test + public void run11() throws Throwable { + runTest("test", 1, -16); + } + + @Test + public void run12() throws Throwable { + runTest("test", 1, -17); + } + + @Test + public void run13() throws Throwable { + runTest("test", 1, -1024); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_idiv_4.java 2016-12-07 13:53:30.570042192 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_idiv_4 extends JTTTest { + + public static int test(int arg) { + return arg / 4; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 4); + } + + @Test + public void run2() throws Throwable { + runTest("test", 5); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4); + } + + @Test + public void run5() throws Throwable { + runTest("test", -5); + } + + @Test + public void run6() throws Throwable { + runTest("test", -256); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_imul_16.java 2016-12-07 13:53:30.834053795 -0800 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_imul_16 extends JTTTest { + + public static int test(int i, int arg) { + if (i == 0) { + final int mult = 16; + return arg * mult; + } + return arg * 16; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, 16); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, 17); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -1); + } + + @Test + public void run4() throws Throwable { + runTest("test", 0, -16); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0, -17); + } + + @Test + public void run6() throws Throwable { + runTest("test", 0, 2147483647); + } + + @Test + public void run7() throws Throwable { + runTest("test", 0, -2147483648); + } + + @Test + public void run8() throws Throwable { + runTest("test", 1, 0); + } + + @Test + public void run9() throws Throwable { + runTest("test", 1, 16); + } + + @Test + public void run10() throws Throwable { + runTest("test", 1, 17); + } + + @Test + public void run11() throws Throwable { + runTest("test", 1, -1); + } + + @Test + public void run12() throws Throwable { + runTest("test", 1, -16); + } + + @Test + public void run13() throws Throwable { + runTest("test", 1, -17); + } + + @Test + public void run14() throws Throwable { + runTest("test", 1, 2147483647); + } + + @Test + public void run15() throws Throwable { + runTest("test", 1, -2147483648); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_imul_4.java 2016-12-07 13:53:31.098065398 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_imul_4 extends JTTTest { + + public static int test(int arg) { + return arg * 4; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 4); + } + + @Test + public void run2() throws Throwable { + runTest("test", 5); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4); + } + + @Test + public void run5() throws Throwable { + runTest("test", -5); + } + + @Test + public void run6() throws Throwable { + runTest("test", -256); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_ldiv_16.java 2016-12-07 13:53:31.361076957 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ldiv_16 extends JTTTest { + + public static long test(long arg) { + return arg / 16; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 16L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 17L); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -16L); + } + + @Test + public void run5() throws Throwable { + runTest("test", -17L); + } + + @Test + public void run6() throws Throwable { + runTest("test", -1024L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_ldiv_4.java 2016-12-07 13:53:31.626088604 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_ldiv_4 extends JTTTest { + + public static long test(long arg) { + return arg / 4; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 4L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 5L); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4L); + } + + @Test + public void run5() throws Throwable { + runTest("test", -5L); + } + + @Test + public void run6() throws Throwable { + runTest("test", -256L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lmul_16.java 2016-12-07 13:53:31.892100295 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lmul_16 extends JTTTest { + + public static long test(long arg) { + return arg * 16; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 16L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 17L); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -16L); + } + + @Test + public void run5() throws Throwable { + runTest("test", -17L); + } + + @Test + public void run6() throws Throwable { + runTest("test", -1024L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lmul_4.java 2016-12-07 13:53:32.155111855 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lmul_4 extends JTTTest { + + public static long test(long arg) { + return arg * 4; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 4L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 5L); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1L); + } + + @Test + public void run4() throws Throwable { + runTest("test", -4L); + } + + @Test + public void run5() throws Throwable { + runTest("test", -5L); + } + + @Test + public void run6() throws Throwable { + runTest("test", -256L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C16.java 2016-12-07 13:53:32.420123501 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lshr_C16 extends JTTTest { + + public static long test(long a) { + return a >> 16; + } + + @Test + public void run0() throws Throwable { + runTest("test", 87224824140L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C24.java 2016-12-07 13:53:32.684135105 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lshr_C24 extends JTTTest { + + public static long test(long a) { + return a >> 24; + } + + @Test + public void run0() throws Throwable { + runTest("test", 87224824140L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C32.java 2016-12-07 13:53:32.948146708 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BC_lshr_C32 extends JTTTest { + + public static long test(long a) { + return a >> 32; + } + + @Test + public void run0() throws Throwable { + runTest("test", 87224824140L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BlockSkip01.java 2016-12-07 13:53:33.211158267 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class BlockSkip01 extends JTTTest { + + public static boolean test(int arg) { + int x = 1; + + if (arg > 2) { + x = 2; + } else { + x = 1; + } + return m(x) == 2; + } + + private static int m(int x) { + return x + 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BoxingIdentity.java 2016-12-07 13:53:33.475169870 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BoxingIdentity extends JTTTest { + interface ArrayMirror { + Object get(int i); + } + + static class IntArray implements ArrayMirror { + final int[] array; + + IntArray() { + this.array = new int[8]; + } + + @Override + public Object get(int i) { + return array[i]; + } + } + + public int testIntArray(Object m) { + ArrayMirror a = new IntArray(); + if (a.get(0) != m) { + return 42; + } + return 41; + } + + @Test + public void runIntArray() { + runTest("testIntArray", 0); + runTest("testIntArray", 1); + } + + public boolean isTrue(Object obj) { + return obj == Boolean.valueOf(true); + } + + @Test + public void runIsTrue() { + runTest("isTrue", true); + runTest("isTrue", false); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Cmov01.java 2016-12-07 13:53:33.739181473 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Cmov01 extends JTTTest { + + public static boolean test(int a, int b) { + boolean result = a < b || a == b; + return result; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1, -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1, 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Cmov02.java 2016-12-07 13:53:34.003193077 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Cmov02 extends JTTTest { + + public static int test(double a, double b, int v1, int v2) { + return a < b ? v1 : v2; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1.0, 1.1, 1, 2); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0, -1.1, 1, 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1.0, java.lang.Double.NaN, 1, 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Conditional01.java 2016-12-07 13:53:34.266204636 -0800 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import java.util.Random; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +@SuppressWarnings("unused") +public class Conditional01 extends JTTTest { + + private static class TestClass { + private int nextPC; + private int pc; + private boolean aC; + private boolean aH; + private boolean aN; + private boolean aZ; + private boolean aV; + private boolean aS; + private int cyclesConsumed; + private int[] sram = new int[RAM_SIZE]; + + public void visit(CPC i) { + nextPC = pc + 2; + int tmp0 = getRegisterByte(i.r1); + int tmp1 = getRegisterByte(i.r2); + int tmp2 = bit(aC); + int tmp3 = tmp0 - tmp1 - tmp2; + boolean tmp4 = ((tmp0 & 128) != 0); + boolean tmp5 = ((tmp1 & 128) != 0); + boolean tmp6 = ((tmp3 & 128) != 0); + boolean tmp7 = ((tmp0 & 8) != 0); + boolean tmp8 = ((tmp1 & 8) != 0); + boolean tmp9 = ((tmp3 & 8) != 0); + aH = !tmp7 && tmp8 || tmp8 && tmp9 || tmp9 && !tmp7; + aC = !tmp4 && tmp5 || tmp5 && tmp6 || tmp6 && !tmp4; + aN = tmp6; + aZ = low(tmp3) == 0 && aZ; + aV = tmp4 && !tmp5 && !tmp6 || !tmp4 && tmp5 && tmp6; + aS = (aN != aV); + cyclesConsumed++; + } + + public int getRegisterByte(Register r1) { + if ((r1.val % 10) == 0) { + return sram[r1.num]; + } + return r1.val; + } + + public int low(int tmp3) { + return tmp3 & 0x01; + } + + public int bit(boolean c2) { + return c2 ? 1 : 0; + } + } + + private static final int RAM_SIZE = 0x100; + private static final int init = new Random().nextInt(); + private static final int init1 = new Register().val; + private static final Register init2 = new CPC().r1; + + public static int test(int arg) { + TestClass c = new TestClass(); + Random rnd = new Random(); + for (int i = 0; i < arg; i++) { + CPC i2 = new CPC(); + i2.r1 = new Register(); + i2.r1.val = i; + i2.r1.num = i + RAM_SIZE - 20; + i2.r2 = new Register(); + i2.r2.val = rnd.nextInt(); + i2.r2.num = rnd.nextInt(RAM_SIZE); + try { + c.visit(i2); + } catch (RuntimeException re) { + + } + } + return c.cyclesConsumed; + } + + private static class Register { + + int val; + int num; + } + + private static class CPC { + + public Register r1; + public Register r2; + + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 10); + } + + @Test + public void run2() throws Throwable { + runTest("test", 20); + } + + @Test + public void run3() throws Throwable { + runTest("test", 40); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination01.java 2016-12-07 13:53:34.531216282 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class ConditionalElimination01 extends JTTTest { + + private static int x; + private static Object o = new Object(); + + private static class A { + + A(int y) { + this.y = y; + } + + int y; + } + + @Override + protected void before(ResolvedJavaMethod method) { + super.before(method); + x = 0; + } + + public int test(A a) { + if (o == null) { + return -1; + } + if (a == null) { + return -2; + } + if (o == null) { + return -3; + } + x = 3; + return a.y + x; + } + + @Test + public void run0() throws Throwable { + runTest("test", new A(5)); + } + + @Test + public void run1() throws Throwable { + runTest("test", new Object[]{null}); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination02.java 2016-12-07 13:53:34.795227886 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import java.util.EnumSet; + +import jdk.vm.ci.meta.DeoptimizationReason; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class ConditionalElimination02 extends JTTTest { + + private static Object o = null; + + private static class A { + + A(int y) { + this.y = y; + } + + int y; + } + + public int test(A a, boolean isNull, boolean isVeryNull) { + if (o == null) { + if (!isNull) { + if (o == null) { + return a.y; + } + } + if (!isVeryNull) { + if (o == null) { + return a.y; + } + } + } + return -1; + } + + @Test + public void run0() throws Throwable { + runTest(EnumSet.of(DeoptimizationReason.NullCheckException), "test", new A(5), false, false); + } + + @Test + public void run1() throws Throwable { + runTest(EnumSet.of(DeoptimizationReason.NullCheckException), "test", new Object[]{null, true, true}); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConvertCompare.java 2016-12-07 13:53:35.058239445 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class ConvertCompare extends JTTTest { + public static boolean test(int a, float d) { + return a == (double) d; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 2.87f); + } + + public static boolean testChar42(int x) { + return ((char) x) == 42; + } + + @Test + public void run1() { + runTest("testChar42", 42); + } + + @Test + public void run2() { + runTest("testChar42", (int) Character.MAX_VALUE); + } + + public static boolean testCharMax(int x) { + return ((char) x) == Character.MAX_VALUE; + } + + @Test + public void run3() { + runTest("testCharMax", 42); + } + + @Test + public void run4() { + runTest("testCharMax", (int) Character.MAX_VALUE); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/DeadCode01.java 2016-12-07 13:53:35.321251004 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class DeadCode01 extends JTTTest { + + public static int test(int a) { + int arg = a; + int p = arg; + if (p > 2) { + p += 1; + arg += 10; + } else { + p += 2; + arg += 20; + if (p > 3) { + p += 1; + arg += 10; + if (p > 4) { + p += 1; + arg += 10; + } else { + p += 2; + arg += 20; + } + } else { + p += 2; + arg += 20; + } + } + return p; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 6); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/DeadCode02.java 2016-12-07 13:53:35.585262607 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class DeadCode02 extends JTTTest { + + public static int test() { + int i = 0; + while (true) { + i++; + if (test2()) { + break; + } + } + return i; + } + + public static boolean test2() { + return true; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Cast01.java 2016-12-07 13:53:35.849274210 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Fold_Cast01 extends JTTTest { + + private static class TestClass { + int field = 9; + } + + static final Object object = new TestClass(); + + public static int test(int arg) { + if (arg == 0) { + return ((TestClass) object).field; + } + if (arg == 1) { + Object obj = new TestClass(); + return ((TestClass) obj).field; + } + if (arg == 2) { + return ((TestClass) null).field; + } + return 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert01.java 2016-12-07 13:53:36.116285945 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Fold_Convert01 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return i2b(); + } + if (arg == 1) { + return i2s(); + } + if (arg == 2) { + return i2c(); + } + return 0; + } + + public static int i2b() { + int x = 0x00000080; + return (byte) x; + } + + public static int i2s() { + int x = 0x00008000; + return (short) x; + } + + public static int i2c() { + int x = 0xffffffff; + return (char) x; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert02.java 2016-12-07 13:53:36.380297549 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Fold_Convert02 extends JTTTest { + + public static long test(long arg) { + if (arg == 0) { + return i2l(); + } + if (arg == 1) { + return f2l(); + } + if (arg == 2) { + return d2l(); + } + return 0; + } + + public static long i2l() { + int x = 0x80000000; + return x; + } + + public static long f2l() { + float x = -33.1f; + return (long) x; + } + + public static long d2l() { + double x = -78.1d; + return (long) x; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert03.java 2016-12-07 13:53:36.645309196 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of float conversions + */ +public class Fold_Convert03 extends JTTTest { + + public static float test(float arg) { + if (arg == 0) { + return i2f(); + } + if (arg == 1) { + return l2f(); + } + if (arg == 2) { + return d2f(); + } + return 0; + } + + public static float i2f() { + int x = 1024; + return x; + } + + public static float l2f() { + long x = -33; + return x; + } + + public static float d2f() { + double x = -78.1d; + return (float) x; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0F); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0F); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2.0F); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert04.java 2016-12-07 13:53:36.909320799 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of float conversions + */ +public class Fold_Convert04 extends JTTTest { + + public static double test(double arg) { + if (arg == 0) { + return l2d(); + } + if (arg == 1) { + return f2d(); + } + return 0; + } + + public static double l2d() { + long x = 1024; + return x; + } + + public static double f2d() { + float x = -1.25f; + return x; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0.0D); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1.0D); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double01.java 2016-12-07 13:53:37.172332358 -0800 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of float operations. + */ +public class Fold_Double01 extends JTTTest { + + public static double test(double arg) { + if (arg == 0) { + return add(); + } + if (arg == 1) { + return sub(); + } + if (arg == 2) { + return mul(); + } + if (arg == 3) { + return div(); + } + if (arg == 4) { + return mod(); + } + return 0; + } + + public static double add() { + double x = 3; + return x + 7; + } + + public static double sub() { + double x = 15; + return x - 4; + } + + public static double mul() { + double x = 6; + return x * 2; + } + + public static double div() { + double x = 26; + return x / 2; + } + + public static double mod() { + double x = 29; + return x % 15; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2d); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3d); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double02.java 2016-12-07 13:53:37.436343961 -0800 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer comparisons. + */ +public class Fold_Double02 extends JTTTest { + + public static boolean test(int arg) { + if (arg == 0) { + return equ(); + } + if (arg == 1) { + return neq(); + } + if (arg == 2) { + return geq(); + } + if (arg == 3) { + return ge(); + } + if (arg == 4) { + return ltq(); + } + if (arg == 5) { + return lt(); + } + return false; + } + + static boolean equ() { + double x = 34; + return x == 34; + } + + static boolean neq() { + double x = 34; + return x != 33; + } + + static boolean geq() { + double x = 34; + return x >= 33; + } + + static boolean ge() { + double x = 34; + return x > 35; + } + + static boolean ltq() { + double x = 34; + return x <= 32; + } + + static boolean lt() { + double x = 34; + return x < 31; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double03.java 2016-12-07 13:53:37.701355608 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Fold_Double03 extends JTTTest { + + private static final double MINUS_ZERO = 1 / Double.NEGATIVE_INFINITY; + + public static double test(int t, double a) { + double v; + if (t == 0) { + v = a * 0.0; + } else { + v = a * MINUS_ZERO; + } + return 1 / v; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 5.0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 5.0); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, -5.0); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1, -5.0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Float01.java 2016-12-07 13:53:37.965367211 -0800 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of float operations. + */ +public class Fold_Float01 extends JTTTest { + + public static float test(float arg) { + if (arg == 0) { + return add(); + } + if (arg == 1) { + return sub(); + } + if (arg == 2) { + return mul(); + } + if (arg == 3) { + return div(); + } + if (arg == 4) { + return mod(); + } + return 0; + } + + public static float add() { + float x = 3; + return x + 7; + } + + public static float sub() { + float x = 15; + return x - 4; + } + + public static float mul() { + float x = 6; + return x * 2; + } + + public static float div() { + float x = 26; + return x / 2; + } + + public static float mod() { + float x = 29; + return x % 15; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2f); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3f); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Float02.java 2016-12-07 13:53:38.229378815 -0800 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer comparisons. + */ +public class Fold_Float02 extends JTTTest { + + public static boolean test(int arg) { + if (arg == 0) { + return equ(); + } + if (arg == 1) { + return neq(); + } + if (arg == 2) { + return geq(); + } + if (arg == 3) { + return ge(); + } + if (arg == 4) { + return ltq(); + } + if (arg == 5) { + return lt(); + } + return false; + } + + static boolean equ() { + float x = 34; + return x == 34; + } + + static boolean neq() { + float x = 34; + return x != 33; + } + + static boolean geq() { + float x = 34; + return x >= 33; + } + + static boolean ge() { + float x = 34; + return x > 35; + } + + static boolean ltq() { + float x = 34; + return x <= 32; + } + + static boolean lt() { + float x = 34; + return x < 31; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_InstanceOf01.java 2016-12-07 13:53:38.493390418 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Fold_InstanceOf01 extends JTTTest { + + static final Object object = new DummyTestClass(); + + public static boolean test(int arg) { + if (arg == 0) { + return object instanceof DummyTestClass; + } + if (arg == 1) { + Object obj = new DummyTestClass(); + return obj instanceof DummyTestClass; + } + if (arg == 2) { + return null instanceof DummyTestClass; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Int01.java 2016-12-07 13:53:38.758402065 -0800 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Fold_Int01 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return add(); + } + if (arg == 1) { + return sub(); + } + if (arg == 2) { + return mul(); + } + if (arg == 3) { + return div(); + } + if (arg == 4) { + return mod(); + } + if (arg == 5) { + return and(); + } + if (arg == 6) { + return or(); + } + if (arg == 7) { + return xor(); + } + return 0; + } + + public static int add() { + int x = 3; + return x + 7; + } + + public static int sub() { + int x = 15; + return x - 4; + } + + public static int mul() { + int x = 6; + return x * 2; + } + + public static int div() { + int x = 26; + return x / 2; + } + + public static int mod() { + int x = 29; + return x % 15; + } + + public static int and() { + int x = 31; + return x & 15; + } + + public static int or() { + int x = 16; + return x | 16; + } + + public static int xor() { + int x = 0; + return x ^ 17; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Int02.java 2016-12-07 13:53:39.021413624 -0800 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer comparisons. + */ +public class Fold_Int02 extends JTTTest { + + public static boolean test(int arg) { + if (arg == 0) { + return equ(); + } + if (arg == 1) { + return neq(); + } + if (arg == 2) { + return geq(); + } + if (arg == 3) { + return ge(); + } + if (arg == 4) { + return ltq(); + } + if (arg == 5) { + return lt(); + } + return false; + } + + static boolean equ() { + int x = 34; + return x == 34; + } + + static boolean neq() { + int x = 34; + return x != 33; + } + + static boolean geq() { + int x = 34; + return x >= 33; + } + + static boolean ge() { + int x = 34; + return x > 35; + } + + static boolean ltq() { + int x = 34; + return x <= 32; + } + + static boolean lt() { + int x = 34; + return x < 31; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Long01.java 2016-12-07 13:53:39.285425227 -0800 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Fold_Long01 extends JTTTest { + + public static long test(long arg) { + if (arg == 0) { + return add(); + } + if (arg == 1) { + return sub(); + } + if (arg == 2) { + return mul(); + } + if (arg == 3) { + return div(); + } + if (arg == 4) { + return mod(); + } + if (arg == 5) { + return and(); + } + if (arg == 6) { + return or(); + } + if (arg == 7) { + return xor(); + } + return 0; + } + + public static long add() { + long x = 3; + return x + 7; + } + + public static long sub() { + long x = 15; + return x - 4; + } + + public static long mul() { + long x = 6; + return x * 2; + } + + public static long div() { + long x = 26; + return x / 2; + } + + public static long mod() { + long x = 29; + return x % 15; + } + + public static long and() { + long x = 31; + return x & 15; + } + + public static long or() { + long x = 16; + return x | 16; + } + + public static long xor() { + long x = 0; + return x ^ 17; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Long02.java 2016-12-07 13:53:39.549436830 -0800 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer comparisons. + */ +public class Fold_Long02 extends JTTTest { + + public static boolean test(int arg) { + if (arg == 0) { + return equ(); + } + if (arg == 1) { + return neq(); + } + if (arg == 2) { + return geq(); + } + if (arg == 3) { + return ge(); + } + if (arg == 4) { + return ltq(); + } + if (arg == 5) { + return lt(); + } + return false; + } + + static boolean equ() { + long x = 34; + return x == 34; + } + + static boolean neq() { + long x = 34; + return x != 33; + } + + static boolean geq() { + long x = 34; + return x >= 33; + } + + static boolean ge() { + long x = 34; + return x > 35; + } + + static boolean ltq() { + long x = 34; + return x <= 32; + } + + static boolean lt() { + long x = 34; + return x < 31; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Math01.java 2016-12-07 13:53:39.812448389 -0800 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Fold_Math01 extends JTTTest { + + public static double test(int arg) { + switch (arg) { + case 0: + return abs(); + case 1: + return sin(); + case 2: + return cos(); + case 3: + return tan(); + case 4: + return atan2(); + case 5: + return sqrt(); + case 6: + return log(); + case 7: + return log10(); + case 8: + return pow(); + case 9: + return exp(); + case 10: + return min(); + case 11: + return max(); + } + return 42; + } + + private static double abs() { + return Math.abs(-10.0d); + } + + private static double sin() { + return Math.sin(0.15d); + } + + private static double cos() { + return Math.cos(0.15d); + } + + private static double tan() { + return Math.tan(0.15d); + } + + private static double atan2() { + return Math.atan2(0.15d, 3.1d); + } + + private static double sqrt() { + return Math.sqrt(144d); + } + + private static double log() { + return Math.log(3.15d); + } + + private static double log10() { + return Math.log10(0.15d); + } + + private static double pow() { + return Math.pow(2.15d, 6.1d); + } + + private static double exp() { + return Math.log(3.15d); + } + + private static int min() { + return Math.min(2, -1); + } + + private static int max() { + return Math.max(2, -1); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + + @Test + public void run9() throws Throwable { + runTest("test", 9); + } + + @Test + public void run10() throws Throwable { + runTest("test", 10); + } + + @Test + public void run11() throws Throwable { + runTest("test", 11); + } + + @Test + public void run12() throws Throwable { + runTest("test", 12); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/InferStamp01.java 2016-12-07 13:53:40.076459992 -0800 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/** + * test some stamps in combination with full loop unrolling and shifts. + */ +public class InferStamp01 extends JTTTest { + + public static int testi0(int arg) { + int a = arg; + for (int i = 0; i < 2; i++) { + a = a >> 16; + } + return a; + } + + @Test + public void runi0() throws Throwable { + runTest("testi0", 0x7788_99aa); + } + + @Test + public void runi0neg() throws Throwable { + runTest("testi0", 0xf788_99aa); + } + + public static int testi1(int arg) { + int a = arg; + for (int i = 0; i < 2; i++) { + a = a >>> 16; + } + return a; + } + + @Test + public void runi1() throws Throwable { + runTest("testi1", 0x7788_99aa); + } + + @Test + public void runi1neg() throws Throwable { + runTest("testi1", 0xf788_99aa); + } + + public static int testi2(int arg) { + int a = arg; + for (int i = 0; i < 2; i++) { + a = a << 16; + } + return a; + } + + @Test + public void runi2() throws Throwable { + runTest("testi2", 0x7788_99aa); + } + + @Test + public void runi2neg() throws Throwable { + runTest("testi2", 0xf788_99aa); + } + + public static long testl0(long arg) { + long a = arg; + for (long i = 0; i < 2; i++) { + a = a >> 32; + } + return a; + } + + @Test + public void runl0() throws Throwable { + runTest("testl0", 0x3344_5566_7788_99aaL); + } + + @Test + public void runl0neg() throws Throwable { + runTest("testl0", 0xf344_5566_7788_99aaL); + } + + public static long testl1(long arg) { + long a = arg; + for (long i = 0; i < 2; i++) { + a = a >>> 32; + } + return a; + } + + @Test + public void runl1() throws Throwable { + runTest("testl1", 0x3344_5566_7788_99aaL); + } + + @Test + public void runl1neg() throws Throwable { + runTest("testl1", 0xf344_5566_7788_99aaL); + } + + public static long testl2(long arg) { + long a = arg; + for (long i = 0; i < 2; i++) { + a = a << 32; + } + return a; + } + + @Test + public void runl2() throws Throwable { + runTest("testl2", 0x3344_5566_7788_99aaL); + } + + @Test + public void runl2neg() throws Throwable { + runTest("testl2", 0xf344_5566_7788_99aaL); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Inline01.java 2016-12-07 13:53:40.340471595 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Inline01 extends JTTTest { + + public static int test(int arg) { + return arg + nobranch(true) + nobranch(false) + nobranch(true) + nobranch(false); + } + + static int nobranch(boolean f) { + if (f) { + return 0; + } + return 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Inline02.java 2016-12-07 13:53:40.604483198 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Inline02 extends JTTTest { + + public static int test(int arg) { + return arg + nobranch(true, arg) + nobranch(false, arg) + nobranch(true, arg) + nobranch(false, arg); + } + + static int nobranch(boolean f, int v) { + if (f) { + return v; + } + return 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/LLE_01.java 2016-12-07 13:53:40.868494802 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Test case for local load elimination. It makes sure that the second field store is not eliminated, because + * it is recognized that the first store changes the field "field1", so it is no longer guaranteed that it + * has its default value 0. + */ +public class LLE_01 extends JTTTest { + + private static class TestClass { + int field1; + } + + public static int test() { + TestClass o = new TestClass(); + o.field1 = 1; + o.field1 = 0; + return o.field1; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/List_reorder_bug.java 2016-12-07 13:53:41.133506449 -0800 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +@SuppressWarnings("unused") +public class List_reorder_bug extends JTTTest { + + private static class TestClass { + String s; + + private void print(String s2) { + this.s = s2; + } + + private void match(Object a, int src, int id, int seq) { + print("match: " + src + ", " + id); + List item = list; + List itemPrev = null; + while (item != null) { + if (item.id == id) { + if (item.bool) { + outcall(item.id); + } + if (itemPrev != null) { + itemPrev.next = item.next; + } else { + list = item.next; + } + + item.next = null; + return; + } + + itemPrev = item; + item = item.next; + } + } + } + + static class List { + + List(int id) { + this.id = id; + } + + List next; + int id; + boolean bool = true; + } + + private static List list; + + public static boolean test(int i) { + list = new List(5); + list.next = new List(6); + new TestClass().match(new Object(), 27, 6, 0); + return list.next == null; + } + + static int globalId; + + private static void outcall(int id) { + globalId = id; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Logic0.java 2016-12-07 13:53:41.397518052 -0800 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Logic0 extends JTTTest { + + public static int test(int a, int b) { + if (((a != 0 ? 1 : 0) & (a != b ? 1 : 0)) != 0) { + return 42; + } + return 11; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 0, 33); + } + + @Test + public void run2() throws Throwable { + runTest("test", 33, 66); + } + + @Test + public void run3() throws Throwable { + runTest("test", 33, 67); + } + + @Test + public void run4() throws Throwable { + runTest("test", 33, 33); + } + + @Test + public void run5() throws Throwable { + runTest("test", 0, 32); + } + + @Test + public void run6() throws Throwable { + runTest("test", 32, 66); + } + + @Test + public void run7() throws Throwable { + runTest("test", 32, 67); + } + + @Test + public void run8() throws Throwable { + runTest("test", 32, 32); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/LongToSomethingArray01.java 2016-12-07 13:53:41.660529611 -0800 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/** + * inspired by java.security.SecureRandom.longToByteArray(long). + * + */ +public class LongToSomethingArray01 extends JTTTest { + + public static byte[] longToByteArray(long arg) { + long l = arg; + byte[] ret = new byte[8]; + for (int i = 0; i < 8; i++) { + ret[i] = (byte) (l & 0xff); + l = l >> 8; + } + return ret; + } + + @Test + public void runB0() throws Throwable { + runTest("longToByteArray", 0x1122_3344_5566_7788L); + } + + public static short[] longToShortArray(long arg) { + long l = arg; + short[] ret = new short[4]; + for (int i = 0; i < 4; i++) { + ret[i] = (short) (l & 0xffff); + l = l >> 16; + } + return ret; + } + + @Test + public void runS0() throws Throwable { + runTest("longToShortArray", 0x1122_3344_5566_7788L); + } + + public static int[] longToIntArray(long arg) { + long l = arg; + int[] ret = new int[2]; + for (int i = 0; i < 2; i++) { + ret[i] = (int) (l & 0xffff_ffff); + l = l >> 32; + } + return ret; + } + + @Test + public void runI0() throws Throwable { + runTest("longToIntArray", 0x1122_3344_5566_7788L); + } + + public static long[] longToLongArray(long arg) { + long l = arg; + long[] ret = new long[1]; + for (int i = 0; i < 1; i++) { + ret[i] = l & 0xffff_ffff_ffff_ffffL; + l = l >> 64; + } + return ret; + } + + @Test + public void runL0() throws Throwable { + runTest("longToLongArray", 0x1122_3344_5566_7788L); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_01.java 2016-12-07 13:53:41.925541258 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Test case for null check elimination. + */ +public class NCE_01 extends JTTTest { + + private static class TestClass { + int field1 = 22; + int field2 = 23; + } + + public static TestClass object = new TestClass(); + + public static int test() { + TestClass o = object; + int i = o.field1; + // expected null check elimination here + return o.field2 + i; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_02.java 2016-12-07 13:53:42.190552905 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Test case for null check elimination. + */ +public class NCE_02 extends JTTTest { + + public static class TestClass { + int field1; + int field2 = 23; + } + + public static TestClass object = new TestClass(); + + public static int test() { + TestClass o = object; + o.field1 = 11; + // expect non-null + o.field1 = 22; + // expect non-null + return o.field2; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_03.java 2016-12-07 13:53:42.454564508 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Test case for null check elimination. + */ +public class NCE_03 extends JTTTest { + + public static class TestClass { + int field1; + int field2 = 23; + } + + private static boolean cond = true; + public static TestClass object = new TestClass(); + + public static int test() { + TestClass o = object; + o.field1 = 11; + if (cond) { + // expect non-null + o.field1 = 22; + } + // expect non-null + return o.field2; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_04.java 2016-12-07 13:53:42.717576067 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Test case for null check elimination. + */ +public class NCE_04 extends JTTTest { + + public static class TestClass { + int field1; + int field2 = 23; + } + + private static boolean cond = true; + public static TestClass object = new TestClass(); + + public static int test() { + TestClass o = object; + if (cond) { + o.field1 = 22; + } else { + o.field1 = 11; + } + // expect non-null + return o.field2; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive01.java 2016-12-07 13:53:42.982587714 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class NCE_FlowSensitive01 extends JTTTest { + + public static String test(String arg) { + if (arg != null) { + return arg.toString(); + } + return null; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", "x"); + } + + @Test + public void run2() throws Throwable { + runTest("test", "yay"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive02.java 2016-12-07 13:53:43.247599361 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class NCE_FlowSensitive02 extends JTTTest { + + @SuppressWarnings("all") + public static String test(String arg) { + if (arg != null) { + return arg.toString(); + } + return arg.toString(); + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", "x"); + } + + @Test + public void run2() throws Throwable { + runTest("test", "yay"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive03.java 2016-12-07 13:53:43.511610964 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class NCE_FlowSensitive03 extends JTTTest { + + public static String test(String arg) { + if ("x".equals(arg)) { + if (arg == null) { + return "null"; + } + } else { + if (arg == null) { + return "null"; + } + } + // arg cannot be null here + return arg.toString(); + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", "x"); + } + + @Test + public void run2() throws Throwable { + runTest("test", "yay"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive04.java 2016-12-07 13:53:43.776622611 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class NCE_FlowSensitive04 extends JTTTest { + + public static String test(String arg2) { + String arg = arg2; + if (arg == null) { + arg = "null"; + } + // arg cannot be null here + return arg.toString(); + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + runTest("test", "x"); + } + + @Test + public void run2() throws Throwable { + runTest("test", "yay"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive05.java 2016-12-07 13:53:44.040634215 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class NCE_FlowSensitive05 extends JTTTest { + + private static PrintStream ps = new PrintStream(new ByteArrayOutputStream()); + + public static String test(Object arg) { + + // An artificial loop to trigger iterative NCE. + while (arg != null) { + ps.println(arg); + } + + // The upcast must still include the null check. + return (String) arg; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte01.java 2016-12-07 13:53:44.305645862 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Narrow_byte01 extends JTTTest { + + public static byte val; + + public static byte test(byte b) { + val = b; + return val; + } + + @Test + public void run0() throws Throwable { + runTest("test", ((byte) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", ((byte) 1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", ((byte) -1)); + } + + @Test + public void run3() throws Throwable { + runTest("test", ((byte) 110)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte02.java 2016-12-07 13:53:44.568657421 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Narrow_byte02 extends JTTTest { + + static class Byte { + + byte foo; + } + + static Byte val = new Byte(); + + public static byte test(byte b) { + val.foo = b; + return val.foo; + } + + @Test + public void run0() throws Throwable { + runTest("test", ((byte) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", ((byte) 1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", ((byte) -1)); + } + + @Test + public void run3() throws Throwable { + runTest("test", ((byte) 110)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte03.java 2016-12-07 13:53:44.833669068 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Narrow_byte03 extends JTTTest { + + static byte[] val = new byte[4]; + + public static byte test(byte b) { + val[0] = b; + return val[0]; + } + + @Test + public void run0() throws Throwable { + runTest("test", ((byte) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", ((byte) 1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", ((byte) -1)); + } + + @Test + public void run3() throws Throwable { + runTest("test", ((byte) 110)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char01.java 2016-12-07 13:53:45.097680671 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Narrow_char01 extends JTTTest { + + public static char val; + + public static char test(char b) { + val = b; + return val; + } + + @Test + public void run0() throws Throwable { + runTest("test", ((char) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", ((char) 1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", ((char) 255)); + } + + @Test + public void run3() throws Throwable { + runTest("test", ((char) 65000)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char02.java 2016-12-07 13:53:45.361692274 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Narrow_char02 extends JTTTest { + + static class Char { + + char foo; + } + + static Char val = new Char(); + + public static char test(char b) { + val.foo = b; + return val.foo; + } + + @Test + public void run0() throws Throwable { + runTest("test", ((char) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", ((char) 1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", ((char) 255)); + } + + @Test + public void run3() throws Throwable { + runTest("test", ((char) 65000)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char03.java 2016-12-07 13:53:45.627703965 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Narrow_char03 extends JTTTest { + + static char[] val = new char[4]; + + public static char test(char b) { + val[0] = b; + return val[0]; + } + + @Test + public void run0() throws Throwable { + runTest("test", ((char) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", ((char) 1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", ((char) 255)); + } + + @Test + public void run3() throws Throwable { + runTest("test", ((char) 65000)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short01.java 2016-12-07 13:53:45.892715612 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Narrow_short01 extends JTTTest { + + public static short val; + + public static short test(short b) { + val = b; + return val; + } + + @Test + public void run0() throws Throwable { + runTest("test", ((short) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", ((short) 1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", ((short) -1)); + } + + @Test + public void run3() throws Throwable { + runTest("test", ((short) 23110)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short02.java 2016-12-07 13:53:46.157727259 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Narrow_short02 extends JTTTest { + + static class Short { + + short foo; + } + + static Short val = new Short(); + + public static short test(short b) { + val.foo = b; + return val.foo; + } + + @Test + public void run0() throws Throwable { + runTest("test", ((short) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", ((short) 1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", ((short) -1)); + } + + @Test + public void run3() throws Throwable { + runTest("test", ((short) 23110)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short03.java 2016-12-07 13:53:46.423738950 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Narrow_short03 extends JTTTest { + + static short[] val = new short[4]; + + public static short test(short b) { + val[0] = b; + return val[0]; + } + + @Test + public void run0() throws Throwable { + runTest("test", ((short) 0)); + } + + @Test + public void run1() throws Throwable { + runTest("test", ((short) 1)); + } + + @Test + public void run2() throws Throwable { + runTest("test", ((short) -1)); + } + + @Test + public void run3() throws Throwable { + runTest("test", ((short) 23110)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NestedLoop_EA.java 2016-12-07 13:53:46.688750597 -0800 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011, 2012, 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.jtt.optimize; + +import java.util.ListIterator; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.Suites; +import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; + +public class NestedLoop_EA extends JTTTest { + + @Override + protected Suites createSuites() { + Suites suites = super.createSuites(); + ListIterator> position = suites.getHighTier().findPhase(PartialEscapePhase.class); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + // incremental canonicalizer of PEA is missing some important canonicalization (TODO?) + position.add(canonicalizer); + position.add(new PartialEscapePhase(true, canonicalizer)); + return suites; + } + + static class Frame { + Object[] objects = new Object[10]; + } + + static final int RESULT_SLOT = 0; + static final int K_SLOT = 1; + static final int I_SLOT = 2; + static final int ARG_SLOT = 3; + static final int STACK_BASE = 4; + + static class Pointer { + public int sp = STACK_BASE; + } + + public static int simpleLoop(int arg) { + Frame f = new Frame(); + Pointer p = new Pointer(); + f.objects[ARG_SLOT] = arg; + f.objects[RESULT_SLOT] = 0; + f.objects[K_SLOT] = 0; + for (; (int) f.objects[K_SLOT] < (int) f.objects[ARG_SLOT];) { + + f.objects[RESULT_SLOT] = (int) f.objects[RESULT_SLOT] + 5; + + f.objects[++p.sp] = f.objects[K_SLOT]; + f.objects[++p.sp] = 1; + int result = (int) f.objects[p.sp] + (int) f.objects[p.sp - 1]; + p.sp--; + f.objects[p.sp] = result; + f.objects[K_SLOT] = (int) f.objects[p.sp]; + p.sp--; + } + return (int) f.objects[RESULT_SLOT]; + } + + @Test + public void run0() throws Throwable { + runTest("simpleLoop", 5); + } + + public static int nestedLoop(int arg) { + Frame f = new Frame(); + Pointer p = new Pointer(); + f.objects[ARG_SLOT] = arg; + f.objects[RESULT_SLOT] = 0; + f.objects[K_SLOT] = 0; + for (; (int) f.objects[K_SLOT] < (int) f.objects[ARG_SLOT];) { + + f.objects[I_SLOT] = 0; + for (; (int) f.objects[I_SLOT] < (int) f.objects[ARG_SLOT];) { + f.objects[RESULT_SLOT] = (int) f.objects[RESULT_SLOT] + 5; + + f.objects[++p.sp] = f.objects[I_SLOT]; + f.objects[++p.sp] = 1; + int result = (int) f.objects[p.sp] + (int) f.objects[p.sp - 1]; + p.sp--; + f.objects[p.sp] = result; + f.objects[I_SLOT] = (int) f.objects[p.sp]; + p.sp--; + } + + f.objects[++p.sp] = f.objects[K_SLOT]; + f.objects[++p.sp] = 1; + int result = (int) f.objects[p.sp] + (int) f.objects[p.sp - 1]; + p.sp--; + f.objects[p.sp] = result; + f.objects[K_SLOT] = (int) f.objects[p.sp]; + p.sp--; + } + return (int) f.objects[RESULT_SLOT]; + } + + @Test + public void run1() throws Throwable { + runTest("nestedLoop", 5); + } + + @Override + protected boolean checkHighTierGraph(StructuredGraph graph) { + assert graph.getNodes().filter(CommitAllocationNode.class).count() == 0 : "all allocations should be virtualized"; + return true; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi01.java 2016-12-07 13:53:46.952762200 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Phi01 extends JTTTest { + + public static class Phi { + + int f; + + Phi(int f) { + this.f = f; + } + } + + public static int test(int arg) { + return test2(new Phi(arg), arg); + } + + private static int test2(Phi p, int a) { + int arg = a; + if (arg > 2) { + p.f += 1; + arg += 1; + } else { + p.f += 2; + arg += 2; + if (arg > 3) { + p.f += 1; + arg += 1; + if (arg > 4) { + p.f += 1; + arg += 1; + } else { + p.f += 2; + arg += 2; + } + } else { + p.f += 2; + arg += 2; + } + } + return arg + p.f; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 6); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi02.java 2016-12-07 13:53:47.215773759 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Phi02 extends JTTTest { + + public static class Phi { + + int f; + + Phi(int f) { + this.f = f; + } + } + + public static int test(int arg) { + return test2(new Phi(arg), arg); + } + + private static int test2(Phi p, int a) { + int arg = a; + if (arg > 2) { + inc(p, 1); + arg += 1; + } else { + inc(p, 2); + arg += 2; + if (arg > 3) { + inc(p, 1); + arg += 1; + if (arg > 4) { + inc(p, 1); + arg += 1; + } else { + inc(p, 2); + arg += 2; + } + } else { + inc(p, 2); + arg += 2; + } + } + return arg + p.f; + } + + private static void inc(Phi p, int inc) { + p.f += inc; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 6); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi03.java 2016-12-07 13:53:47.479785362 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Phi03 extends JTTTest { + + public static class Phi { + + int f; + + Phi(int f) { + this.f = f; + } + } + + public static int test(int arg) { + return test2(new Phi(arg), arg); + } + + private static int test2(Phi p, int a) { + int arg = a; + if (arg > 2) { + inc(p, 1); + arg += 1; + } else { + inc(p, 2); + arg += 2; + if (arg > 3) { + inc(p, 1); + arg += 1; + if (arg > 4) { + inc(p, 1); + arg += 1; + } else { + inc(p, 2); + arg += 2; + } + } else { + inc(p, 2); + arg += 2; + } + } + return p.f; + } + + private static void inc(Phi p, int inc) { + p.f += inc; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 6); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ReassociateConstants.java 2016-12-07 13:53:47.742796921 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012, 2012, 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.jtt.optimize; + +import org.junit.Assert; +import org.junit.Test; + +public class ReassociateConstants { + + public static int rnd = (int) (Math.random() * 100); + + @Test + public void run0() throws Throwable { + Assert.assertEquals(rnd + 3, 1 + (rnd + 2)); + Assert.assertEquals(rnd + 3, (rnd + 2) + 1); + Assert.assertEquals(rnd + 3, 1 + (2 + rnd)); + Assert.assertEquals(rnd + 3, (2 + rnd) + 1); + + Assert.assertEquals(-1 - rnd, 1 - (rnd + 2)); + Assert.assertEquals(rnd + 1, (rnd + 2) - 1); + Assert.assertEquals(-1 - rnd, 1 - (2 + rnd)); + Assert.assertEquals(rnd + 1, (2 + rnd) - 1); + + Assert.assertEquals(rnd - 1, 1 + (rnd - 2)); + Assert.assertEquals(rnd - 1, (rnd - 2) + 1); + Assert.assertEquals(-rnd + 3, 1 + (2 - rnd)); + Assert.assertEquals(-rnd + 3, (2 - rnd) + 1); + + Assert.assertEquals(-rnd + 3, 1 - (rnd - 2)); + Assert.assertEquals(rnd - 3, (rnd - 2) - 1); + Assert.assertEquals(rnd + -1, 1 - (2 - rnd)); + Assert.assertEquals(-rnd + 1, (2 - rnd) - 1); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Convert01.java 2016-12-07 13:53:48.006808525 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization integer conversions. + */ +public class Reduce_Convert01 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return i2b(arg + 10); + } + if (arg == 1) { + return i2s(arg + 10); + } + if (arg == 2) { + return i2c(arg + 10); + } + return 0; + } + + public static int i2b(int arg) { + int x = (byte) arg; + return (byte) x; + } + + public static int i2s(int arg) { + int x = (short) arg; + return (short) x; + } + + public static int i2c(int arg) { + int x = (char) arg; + return (char) x; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Double01.java 2016-12-07 13:53:48.269820084 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of double operations. + */ +public class Reduce_Double01 extends JTTTest { + + public static double test(double arg) { + if (arg == 0) { + return add(10); + } + if (arg == 1) { + return sub(11); + } + if (arg == 2) { + return mul(12); + } + if (arg == 3) { + return div(13); + } + return 0; + } + + public static double add(double x) { + return x + 0; + } + + public static double sub(double x) { + return x - 0; + } + + public static double mul(double x) { + return x * 1; + } + + public static double div(double x) { + return x / 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2d); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Float01.java 2016-12-07 13:53:48.534831731 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of float operations. + */ +public class Reduce_Float01 extends JTTTest { + + public static float test(float arg) { + if (arg == 0) { + return add(10); + } + if (arg == 1) { + return sub(11); + } + if (arg == 2) { + return mul(12); + } + if (arg == 3) { + return div(13); + } + return 0; + } + + public static float add(float x) { + return x + 0; + } + + public static float sub(float x) { + return x - 0; + } + + public static float mul(float x) { + return x * 1; + } + + public static float div(float x) { + return x / 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2f); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int01.java 2016-12-07 13:53:48.798843334 -0800 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Reduce_Int01 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return add(10); + } + if (arg == 1) { + return sub(11); + } + if (arg == 2) { + return mul(12); + } + if (arg == 3) { + return div(13); + } + if (arg == 4) { + return mod(); + } + if (arg == 5) { + return and(15); + } + if (arg == 6) { + return or(16); + } + if (arg == 7) { + return xor(17); + } + return 0; + } + + public static int add(int x) { + return x + 0; + } + + public static int sub(int x) { + return x - 0; + } + + public static int mul(int x) { + return x * 1; + } + + public static int div(int x) { + return x / 1; + } + + public static int mod() { + return 14; + } + + public static int and(int x) { + return x & -1; + } + + public static int or(int x) { + return x | 0; + } + + public static int xor(int x) { + return x ^ 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int02.java 2016-12-07 13:53:49.063854981 -0800 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Reduce_Int02 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return add(10); + } + if (arg == 1) { + return sub(); + } + if (arg == 2) { + return mul(12); + } + if (arg == 3) { + return div(); + } + if (arg == 4) { + return mod(); + } + if (arg == 5) { + return and(15); + } + if (arg == 6) { + return or(16); + } + if (arg == 7) { + return xor(17); + } + return 0; + } + + public static int add(int x) { + return 0 + x; + } + + public static int sub() { + return 11; + } + + public static int mul(int x) { + return 1 * x; + } + + public static int div() { + return 13; + } + + public static int mod() { + return 14; + } + + public static int and(int x) { + return -1 & x; + } + + public static int or(int x) { + return 0 | x; + } + + public static int xor(int x) { + return 0 ^ x; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int03.java 2016-12-07 13:53:49.327866584 -0800 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Reduce_Int03 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return add(5); + } + if (arg == 1) { + return sub(10); + } + if (arg == 2) { + return mul(5); + } + if (arg == 3) { + return div(5); + } + if (arg == 4) { + return mod(5); + } + if (arg == 5) { + return and(15); + } + if (arg == 6) { + return or(16); + } + if (arg == 7) { + return xor(17); + } + return 0; + } + + public static int add(int x) { + return x + x; + } + + public static int sub(int x) { + return x - x; + } + + public static int mul(int x) { + return x * x; + } + + public static int div(int x) { + return x / x; + } + + public static int mod(int x) { + return x % x; + } + + public static int and(int x) { + return x & x; + } + + public static int or(int x) { + return x | x; + } + + public static int xor(int x) { + return x ^ x; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int04.java 2016-12-07 13:53:49.592878231 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Reduce_Int04 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return mul0(arg + 10); + } + if (arg == 1) { + return mul1(arg + 9); + } + return 0; + } + + public static int mul0(int x) { + return x * 4; + } + + public static int mul1(int x) { + return x * 65536; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_IntShift01.java 2016-12-07 13:53:49.855889790 -0800 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of integer operations. + */ +public class Reduce_IntShift01 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return shift0(arg + 10); + } + if (arg == 1) { + return shift1(arg + 10); + } + if (arg == 2) { + return shift2(arg + 10); + } + if (arg == 3) { + return shift3(arg + 10); + } + if (arg == 4) { + return shift4(arg + 10); + } + if (arg == 5) { + return shift5(arg + 10); + } + return 0; + } + + public static int shift0(int x) { + return x >> 0; + } + + public static int shift1(int x) { + return x >>> 0; + } + + public static int shift2(int x) { + return x << 0; + } + + public static int shift3(int x) { + return x >> 64; + } + + public static int shift4(int x) { + return x >>> 64; + } + + public static int shift5(int x) { + return x << 64; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_IntShift02.java 2016-12-07 13:53:50.118901349 -0800 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of integer operations. + */ +public class Reduce_IntShift02 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return shift0(arg + 80); + } + if (arg == 1) { + return shift1(arg + 0x8000000a); + } + if (arg == 2) { + return shift2(arg + 192); + } + if (arg == 3) { + return shift3(arg + 208); + } + if (arg == 4) { + return shift4(arg); + } + if (arg == 5) { + return shift5(arg); + } + return 0; + } + + public static int shift0(int x) { + return x >>> 3 << 3; + } + + public static int shift1(int x) { + return x << 3 >>> 3; + } + + public static int shift2(int x) { + return x >> 3 >> 1; + } + + public static int shift3(int x) { + return x >>> 3 >>> 1; + } + + public static int shift4(int x) { + return x << 3 << 1; + } + + public static int shift5(int x) { + return x << 16 << 17; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long01.java 2016-12-07 13:53:50.382912952 -0800 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Reduce_Long01 extends JTTTest { + + public static long test(long arg) { + if (arg == 0) { + return add(10); + } + if (arg == 1) { + return sub(11); + } + if (arg == 2) { + return mul(12); + } + if (arg == 3) { + return div(13); + } + if (arg == 4) { + return mod(); + } + if (arg == 5) { + return and(15); + } + if (arg == 6) { + return or(16); + } + if (arg == 7) { + return xor(17); + } + return 0; + } + + public static long add(long x) { + return x + 0; + } + + public static long sub(long x) { + return x - 0; + } + + public static long mul(long x) { + return x * 1; + } + + public static long div(long x) { + return x / 1; + } + + public static long mod() { + return 14; + } + + public static long and(long x) { + return x & -1; + } + + public static long or(long x) { + return x | 0; + } + + public static long xor(long x) { + return x ^ 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long02.java 2016-12-07 13:53:50.646924555 -0800 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Reduce_Long02 extends JTTTest { + + public static long test(long arg) { + if (arg == 0) { + return add(10); + } + if (arg == 1) { + return sub(); + } + if (arg == 2) { + return mul(12); + } + if (arg == 3) { + return div(); + } + if (arg == 4) { + return mod(); + } + if (arg == 5) { + return and(15); + } + if (arg == 6) { + return or(16); + } + if (arg == 7) { + return xor(17); + } + return 0; + } + + public static long add(long x) { + return 0 + x; + } + + public static long sub() { + return 11; + } + + public static long mul(long x) { + return 1 * x; + } + + public static long div() { + return 13; + } + + public static long mod() { + return 14; + } + + public static long and(long x) { + return -1 & x; + } + + public static long or(long x) { + return 0 | x; + } + + public static long xor(long x) { + return 0 ^ x; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long03.java 2016-12-07 13:53:50.909936114 -0800 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Reduce_Long03 extends JTTTest { + + public static long test(long arg) { + if (arg == 0) { + return add(5); + } + if (arg == 1) { + return sub(10); + } + if (arg == 2) { + return mul(5); + } + if (arg == 3) { + return div(5); + } + if (arg == 4) { + return mod(5); + } + if (arg == 5) { + return and(15); + } + if (arg == 6) { + return or(16); + } + if (arg == 7) { + return xor(17); + } + return 0; + } + + public static long add(long x) { + return x + x; + } + + public static long sub(long x) { + return x - x; + } + + public static long mul(long x) { + return x * x; + } + + public static long div(long x) { + return x / x; + } + + public static long mod(long x) { + return x % x; + } + + public static long and(long x) { + return x & x; + } + + public static long or(long x) { + return x | x; + } + + public static long xor(long x) { + return x ^ x; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5L); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6L); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long04.java 2016-12-07 13:53:51.173947718 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class Reduce_Long04 extends JTTTest { + + public static long test(long arg) { + if (arg == 0) { + return mul0(arg + 10); + } + if (arg == 1) { + return mul1(arg + 9); + } + return 0; + } + + public static long mul0(long x) { + return x * 4; + } + + public static long mul1(long x) { + return x * 8589934592L; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_LongShift01.java 2016-12-07 13:53:51.436959277 -0800 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of integer operations. + */ +public class Reduce_LongShift01 extends JTTTest { + + public static long test(long arg) { + if (arg == 0) { + return shift0(arg + 10); + } + if (arg == 1) { + return shift1(arg + 10); + } + if (arg == 2) { + return shift2(arg + 10); + } + if (arg == 3) { + return shift3(arg + 10); + } + if (arg == 4) { + return shift4(arg + 10); + } + if (arg == 5) { + return shift5(arg + 10); + } + return 0; + } + + public static long shift0(long x) { + return x >> 0; + } + + public static long shift1(long x) { + return x >>> 0; + } + + public static long shift2(long x) { + return x << 0; + } + + public static long shift3(long x) { + return x >> 64; + } + + public static long shift4(long x) { + return x >>> 64; + } + + public static long shift5(long x) { + return x << 64; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4L); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_LongShift02.java 2016-12-07 13:53:51.702970968 -0800 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of integer operations. + */ +public class Reduce_LongShift02 extends JTTTest { + + public static long test(long arg) { + if (arg == 0) { + return shift0(arg + 80); + } + if (arg == 1) { + return shift1(arg + 0x800000000000000aL); + } + if (arg == 2) { + return shift2(arg + 192); + } + if (arg == 3) { + return shift3(arg + 208); + } + if (arg == 4) { + return shift4(arg); + } + return 0; + } + + public static long shift0(long x) { + return x >>> 3 << 3; + } + + public static long shift1(long x) { + return x << 3 >>> 3; + } + + public static long shift2(long x) { + return x >> 3 >> 1; + } + + public static long shift3(long x) { + return x >>> 3 >>> 1; + } + + public static long shift4(long x) { + return x << 3 << 1; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3L); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/SchedulingBug_01.java 2016-12-07 13:53:51.967982615 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, 2015, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class SchedulingBug_01 extends JTTTest { + + private static class VolatileBoxHolder { + volatile Integer box; + } + + public static int test(VolatileBoxHolder a, VolatileBoxHolder b) { + int value = a.box; + int result = 0; + if (b.box != null) { + result += value; + } + return result + value; + } + + @Test + public void run0() throws Throwable { + runTest("test", new VolatileBoxHolder(), new VolatileBoxHolder()); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/SignExtendShort.java 2016-12-07 13:53:52.230994174 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class SignExtendShort extends JTTTest { + + public static int val; + + public static boolean test(short[] b) { + val = b[2]; + int x = 0; + return val >= x; + } + + @Test + public void run0() throws Throwable { + runTest("test", new short[]{0, 0, 0}); + } + + @Test + public void run1() throws Throwable { + runTest("test", new short[]{0, 0, 1}); + } + + @Test + public void run2() throws Throwable { + runTest("test", new short[]{0, 0, -1}); + } + + @Test + public void run3() throws Throwable { + runTest("test", new short[]{0, 0, Short.MAX_VALUE}); + } + + @Test + public void run4() throws Throwable { + runTest("test", new short[]{0, 0, Short.MIN_VALUE}); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Switch01.java 2016-12-07 13:53:52.496005821 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of switches. + */ +public class Switch01 extends JTTTest { + + public static int test(int arg) { + switch (arg) { + default: + return 1; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Switch02.java 2016-12-07 13:53:52.760017424 -0800 @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of switches. + */ +public class Switch02 extends JTTTest { + private static char staticCharVal = 0; + private static short staticShortVal = 0; + private static byte staticByteVal = 0; + + public static int test(int arg) { + switch (arg) { + case 1: + return 2; + default: + return 1; + } + } + + public static int test2char(char arg) { + int result = 392123; + Object x = null; + char val = staticCharVal != 0 ? staticCharVal : arg; + switch (val) { + case (char) 0xFFFF: + result = 23212 / val; + break; + case (char) 0xFFFF - 3: + result = 932991439 / val; + break; + case (char) 0xFFFF - 6: + result = 47329561 / val; + break; + case (char) 0xFFFF - 9: + result = 1950976984 / val; + break; + case (char) 0xFFFF - 10: + result = 97105581 / val; + switch (result) { + case 1: + result = 321; + break; + default: + result = 2391; + break; + } + break; + case (char) 0xFFFF - 12: + result = 99757362 / val; + break; + case (char) 0xFFFF - 15: + result = 912573 / val; + x = new LinkedList<>(); + break; + case (char) 0xFFFF - 18: + x = new HashSet<>(); + result = 876765 / val; + break; + case (char) 0xFFFF - 19: + result = 75442917 / val; + break; + case (char) 0xFFFF - 21: + result = 858112498 / val; + x = new HashMap<>(); + break; + default: + result = 34324341 / val; + } + result = result + (x == null ? 0 : x.hashCode()); + return result; + } + + public static int test2short(short arg) { + int result = 392123; + Object x = null; + short val = staticShortVal != 0 ? staticShortVal : arg; + switch (val) { + case (short) -0x7FFF: + result = 23212 / val; + break; + case (short) -0x7FFF + 3: + result = 932991439 / val; + break; + case (short) -0x7FFF + 6: + result = 47329561 / val; + break; + case (short) -0x7FFF + 9: + result = 1950976984 / val; + break; + case (short) -0x7FFF + 10: + result = 97105581 / val; + switch (result) { + case 1: + result = 321; + break; + default: + result = 2391; + break; + } + break; + case (short) -0x7FFF + 12: + result = 99757362 / val; + break; + case (short) -0x7FFF + 15: + result = 912573 / val; + x = new LinkedList<>(); + break; + case (short) -0x7FFF + 18: + x = new HashSet<>(); + result = 876765 / val; + break; + case (short) -0x7FFF + 19: + result = 75442917 / val; + break; + case (short) -0x7FFF + 21: + result = 858112498 / val; + x = new HashMap<>(); + break; + default: + result = 34324341 / val; + } + result = result + (x == null ? 0 : x.hashCode()); + return result; + } + + public static int test2byte(byte arg) { + int result = 392123; + Object x = null; + byte val = staticByteVal != 0 ? staticByteVal : arg; + switch (val) { + case (byte) -0x7F: + result = 23212 / val; + break; + case (byte) -0x7F + 3: + result = 932991439 / val; + break; + case (byte) -0x7F + 6: + result = 47329561 / val; + break; + case (byte) -0x7F + 9: + result = 1950976984 / val; + break; + case (byte) -0x7F + 10: + result = 97105581 / val; + switch (result) { + case 1: + result = 321; + break; + default: + result = 2391; + break; + } + break; + case (byte) -0x7F + 12: + result = 99757362 / val; + break; + case (byte) -0x7F + 15: + result = 912573 / val; + x = new LinkedList<>(); + break; + case (byte) -0x7F + 18: + x = new HashSet<>(); + result = 876765 / val; + break; + case (byte) -0x7F + 19: + result = 75442917 / val; + break; + case (byte) -0x7F + 20: + result = 856261268 / val; + break; + case (byte) -0x7F + 21: + result = 858112498 / val; + x = new HashMap<>(); + break; + default: + result = 34324341 / val; + } + result = result + (x == null ? 0 : x.hashCode()); + return result; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test2char", (char) (0x0)); + runTest("test2char", (char) (0xFFFF)); + runTest("test2char", (char) (0xFFFF - 21)); // miss + runTest("test2char", (char) (0xFFFF - 22)); // hit + runTest("test2char", (char) (0xFFFF - 23)); // miss (out of bound) + + staticCharVal = (char) 0xFFFF; + runTest("test2char", (char) 0); + staticCharVal = (char) (0xFFFF - 21); + runTest("test2char", (char) 0xFFFF); + staticCharVal = (char) (0xFFFF - 22); + runTest("test2char", (char) 0xFFFF); + staticCharVal = (char) (0xFFFF - 23); + runTest("test2char", (char) 0xFFFF); + } + + @Test + public void run3() throws Throwable { + runTest("test2short", (short) 0x0); + runTest("test2short", (short) -0x7FFF); + runTest("test2short", (short) (-0x7FFF + 21)); // Miss + runTest("test2short", (short) (-0x7FFF + 22)); // hit + runTest("test2short", (short) (-0x7FFF + 23)); // miss (out of bound) + runTest("test2short", (short) 0x7FFF); // miss (out of bound) + + staticShortVal = (short) -0x7FFF; + runTest("test2short", (short) 0); + staticShortVal = (short) (-0x7FFF + 21); + runTest("test2short", (short) 0); + staticShortVal = (short) (-0x7FFF + 22); + runTest("test2short", (short) 0); + staticShortVal = (short) (-0x7FFF + 23); + runTest("test2short", (short) 0); + staticShortVal = (short) 0x7FFF; + runTest("test2short", (short) 0); + } + + @Test + public void run4() throws Throwable { + runTest("test2byte", (byte) 0); + runTest("test2byte", (byte) -0x7F); + runTest("test2byte", (byte) (-0x7F + 21)); // Miss + runTest("test2byte", (byte) (-0x7F + 22)); // hit + runTest("test2byte", (byte) (-0x7F + 23)); // miss (out of bound) + runTest("test2byte", (byte) 0x7F); // miss (out of bound) + + staticByteVal = (byte) -0x7F; + runTest("test2short", (short) 0); + staticByteVal = (byte) (-0x7F + 21); + runTest("test2short", (short) 0); + staticByteVal = (byte) (-0x7F + 22); + runTest("test2short", (short) 0); + staticByteVal = (byte) (-0x7F + 23); + runTest("test2short", (short) 0); + staticByteVal = (byte) 0x7F; + runTest("test2short", (short) 0); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/TypeCastElem.java 2016-12-07 13:53:53.024029027 -0800 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class TypeCastElem extends JTTTest { + + interface Int1 { + + int do1(); + } + + interface Int2 { + + int do2(); + } + + interface Int3 extends Int1 { + + int do3(); + } + + public static class ClassA implements Int1 { + + private int a; + + public ClassA(int a) { + this.a = a; + } + + @Override + public int do1() { + return a; + } + } + + public static class ClassB extends ClassA implements Int2 { + + int b; + + public ClassB(int a, int b) { + super(a); + this.b = b; + } + + @Override + public int do2() { + return b; + } + } + + public static class ClassC implements Int3 { + + private int a; + private int b; + + public ClassC(int a, int b) { + this.a = a; + this.b = b; + } + + @Override + public int do3() { + return b; + } + + @Override + public int do1() { + return a; + } + + } + + public static int test1(Object o) { + if (o instanceof ClassB) { + ClassB b = (ClassB) o; + if (o instanceof Int1) { + return b.b - b.b + 1; + } + return 7; + } + return 3; + } + + public static int test2(Object o) { + Object b = o; + if (o instanceof ClassB) { + ClassA a = (ClassA) o; + if (b instanceof Int1) { + return ((Int1) a).do1(); + } + return 7; + } + return 3; + } + + public static int test3(Object o) { + Object b = o; + boolean t = o instanceof Int3; + if (t) { + Int1 a = (Int1) b; + return a.do1(); + } + return 3; + } + + public static int test(int a, int b, int c) { + ClassA ca = new ClassA(a); + ClassB cb = new ClassB(a, b); + ClassC cc = new ClassC(c, c); + int sum1 = test1(ca) + test1(cb) * 10 + test1(cc) * 100; + int sum2 = test2(ca) + test2(cb) * 10 + test2(cc) * 100; + int sum3 = test3(ca) + test3(cb) * 10 + test3(cc) * 100; + int result = sum1 * 5 + sum2 * 7 + sum3 * 9; + return result; + } + + @Test + public void run0() throws Throwable { + runTest("test", 10, 13, 25); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/UnsafeDeopt.java 2016-12-07 13:53:53.288040630 -0800 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.optimize; + +import java.lang.reflect.Field; +import java.nio.ByteBuffer; + +import org.junit.Test; +import org.junit.internal.AssumptionViolatedException; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.jtt.JTTTest; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import sun.misc.Unsafe; + +public class UnsafeDeopt extends JTTTest { + private static final Unsafe unsafe; + + static { + try { + final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + unsafe = (Unsafe) unsafeField.get(null); + } catch (Exception e) { + throw new Error(e); + } + } + + public static int readWriteReadUnsafe(long addr, int m) { + int original = unsafe.getInt(addr); + if (original != 0) { + return -m; + } + unsafe.putInt(addr, m); + if (m > 10) { + if (m > 20) { + GraalDirectives.deoptimize(); + } + unsafe.putInt(addr + 4, m); + } + return unsafe.getInt(addr); + } + + public static int readWriteReadByteBuffer(ByteBuffer buffer, int m) { + int original = buffer.getInt(0); + if (original != 0) { + return -m; + } + buffer.putInt(0, m); + if (m > 10) { + if (m > 20) { + GraalDirectives.deoptimize(); + buffer.putInt(4, m); + } + } + return buffer.getInt(0); + } + + public long createBuffer() { + long addr = unsafe.allocateMemory(32); + unsafe.setMemory(addr, 32, (byte) 0); + return addr; + } + + public void disposeBuffer(long addr) { + unsafe.freeMemory(addr); + } + + @Test + public void testUnsafe() { + int m = 42; + long addr1 = createBuffer(); + long addr2 = createBuffer(); + try { + ResolvedJavaMethod method = getResolvedJavaMethod("readWriteReadUnsafe"); + Object receiver = method.isStatic() ? null : this; + Result expect = executeExpected(method, receiver, addr1, m); + if (getCodeCache() == null) { + return; + } + testAgainstExpected(method, expect, receiver, addr2, m); + } catch (AssumptionViolatedException e) { + // Suppress so that subsequent calls to this method within the + // same Junit @Test annotated method can proceed. + } finally { + disposeBuffer(addr1); + disposeBuffer(addr2); + } + } + + @Test + public void testByteBuffer() { + int m = 42; + try { + ResolvedJavaMethod method = getResolvedJavaMethod("readWriteReadByteBuffer"); + Object receiver = method.isStatic() ? null : this; + Result expect = executeExpected(method, receiver, ByteBuffer.allocateDirect(32), m); + if (getCodeCache() == null) { + return; + } + ByteBuffer warmupBuffer = ByteBuffer.allocateDirect(32); + for (int i = 0; i < 10000; ++i) { + readWriteReadByteBuffer(warmupBuffer, (i % 50) + 1); + warmupBuffer.putInt(0, 0); + } + testAgainstExpected(method, expect, receiver, ByteBuffer.allocateDirect(32), m); + } catch (AssumptionViolatedException e) { + // Suppress so that subsequent calls to this method within the + // same Junit @Test annotated method can proceed. + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Cast01.java 2016-12-07 13:53:53.552052233 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class VN_Cast01 extends JTTTest { + + private static class TestClass { + int field = 9; + } + + static final Object object = new TestClass(); + + public static int test(int arg) { + if (arg == 0) { + return test1(); + } + if (arg == 1) { + return test2(); + } + if (arg == 2) { + return test3(); + } + return 0; + } + + private static int test1() { + Object o = object; + TestClass a = (TestClass) o; + TestClass b = (TestClass) o; + return a.field + b.field; + } + + private static int test2() { + Object obj = new TestClass(); + TestClass a = (TestClass) obj; + TestClass b = (TestClass) obj; + return a.field + b.field; + } + + @SuppressWarnings("all") + private static int test3() { + Object o = null; + TestClass a = (TestClass) o; + TestClass b = (TestClass) o; + return a.field + b.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Cast02.java 2016-12-07 13:53:53.816063836 -0800 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class VN_Cast02 extends JTTTest { + + private static class TestClass { + int field = 9; + } + + private static boolean cond = true; + static final Object object = new TestClass(); + + public static int test(int arg) { + if (arg == 0) { + return test1(); + } + if (arg == 1) { + return test2(); + } + if (arg == 2) { + return test3(); + } + return 0; + } + + private static int test1() { + Object o = object; + TestClass a = (TestClass) o; + if (cond) { + TestClass b = (TestClass) o; + return a.field + b.field; + } + return 0; + } + + private static int test2() { + Object obj = new TestClass(); + TestClass a = (TestClass) obj; + if (cond) { + TestClass b = (TestClass) obj; + return a.field + b.field; + } + return 0; + } + + @SuppressWarnings("all") + private static int test3() { + Object o = null; + TestClass a = (TestClass) o; + if (cond) { + TestClass b = (TestClass) o; + return a.field + b.field; + } + return 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Convert01.java 2016-12-07 13:53:54.078075351 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization integer conversions. + */ +public class VN_Convert01 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return i2b(arg + 10); + } + if (arg == 1) { + return i2s(arg + 10); + } + if (arg == 2) { + return i2c(arg + 10); + } + return 0; + } + + public static int i2b(int arg) { + int x = (byte) arg; + int y = (byte) arg; + return x + y; + } + + public static int i2s(int arg) { + int x = (short) arg; + int y = (short) arg; + return x + y; + } + + public static int i2c(int arg) { + int x = (char) arg; + int y = (char) arg; + return x + y; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Convert02.java 2016-12-07 13:53:54.342086954 -0800 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization integer conversions. + */ +public class VN_Convert02 extends JTTTest { + + private static boolean cond = true; + + public static int test(int arg) { + if (arg == 0) { + return i2b(arg + 10); + } + if (arg == 1) { + return i2s(arg + 10); + } + if (arg == 2) { + return i2c(arg + 10); + } + return 0; + } + + public static int i2b(int arg) { + int x = (byte) arg; + if (cond) { + int y = (byte) arg; + return x + y; + } + return 0; + } + + public static int i2s(int arg) { + int x = (short) arg; + if (cond) { + int y = (short) arg; + return x + y; + } + return 0; + } + + public static int i2c(int arg) { + int x = (char) arg; + if (cond) { + int y = (char) arg; + return x + y; + } + return 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Double01.java 2016-12-07 13:53:54.607098601 -0800 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of float operations. + */ +public class VN_Double01 extends JTTTest { + + public static double test(double arg) { + if (arg == 0) { + return add(arg + 10); + } + if (arg == 1) { + return sub(arg + 10); + } + if (arg == 2) { + return mul(arg + 10); + } + if (arg == 3) { + return div(arg + 10); + } + return 0; + } + + public static double add(double x) { + double c = 1; + double t = x + c; + double u = x + c; + return t + u; + } + + public static double sub(double x) { + double c = 1; + double t = x - c; + double u = x - c; + return t - u; + } + + public static double mul(double x) { + double c = 1; + double t = x * c; + double u = x * c; + return t * u; + } + + public static double div(double x) { + double c = 1; + double t = x / c; + double u = x / c; + return t / u; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2d); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Double02.java 2016-12-07 13:53:54.871110204 -0800 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of float operations. + */ +public class VN_Double02 extends JTTTest { + + private static boolean cond = true; + + public static double test(double arg) { + if (arg == 0) { + return add(arg + 10); + } + if (arg == 1) { + return sub(arg + 10); + } + if (arg == 2) { + return mul(arg + 10); + } + if (arg == 3) { + return div(arg + 10); + } + return 0; + } + + public static double add(double x) { + double c = 1.0d; + double t = x + c; + if (cond) { + double u = x + c; + return t + u; + } + return 1; + } + + public static double sub(double x) { + double c = 1.0d; + double t = x - c; + if (cond) { + double u = x - c; + return t - u; + } + return 1; + } + + public static double mul(double x) { + double c = 1.0d; + double t = x * c; + if (cond) { + double u = x * c; + return t * u; + } + return 1.0d; + } + + public static double div(double x) { + double c = 1.0d; + double t = x / c; + if (cond) { + double u = x / c; + return t / u; + } + return 1.0d; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2d); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Field01.java 2016-12-07 13:53:55.134121763 -0800 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class VN_Field01 extends JTTTest { + + private static class TestClass { + int field = 9; + } + + static final TestClass object = new TestClass(); + + public static int test(int arg) { + if (arg == 0) { + return test1(); + } + if (arg == 1) { + return test2(); + } + if (arg == 2) { + return test3(); + } + return 0; + } + + private static int test1() { + TestClass a = object; + return a.field + a.field; + } + + private static int test2() { + TestClass a = object; + TestClass b = object; + return a.field + b.field; + } + + @SuppressWarnings("all") + private static int test3() { + TestClass a = null; + TestClass b = null; + return a.field + b.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Field02.java 2016-12-07 13:53:55.398133366 -0800 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests constant folding of integer operations. + */ +public class VN_Field02 extends JTTTest { + + private static class TestClass { + int field = 9; + } + + private static boolean cond = true; + static final TestClass object = new TestClass(); + + public static int test(int arg) { + if (arg == 0) { + return test1(); + } + if (arg == 1) { + return test2(); + } + if (arg == 2) { + return test3(); + } + return 0; + } + + private static int test1() { + TestClass a = object; + int c = a.field; + if (cond) { + return c + a.field; + } + return 0; + } + + private static int test2() { + TestClass a = object; + if (cond) { + TestClass b = object; + return a.field + b.field; + } + return 0; + } + + @SuppressWarnings("all") + private static int test3() { + TestClass a = null; + if (cond) { + TestClass b = null; + return a.field + b.field; + } + return 0; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Float01.java 2016-12-07 13:53:55.663145013 -0800 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of float operations. + */ +public class VN_Float01 extends JTTTest { + + public static float test(float arg) { + if (arg == 0) { + return add(arg + 10); + } + if (arg == 1) { + return sub(arg + 10); + } + if (arg == 2) { + return mul(arg + 10); + } + if (arg == 3) { + return div(arg + 10); + } + return 0; + } + + public static float add(float x) { + float c = 1; + float t = x + c; + float u = x + c; + return t + u; + } + + public static float sub(float x) { + float c = 1; + float t = x - c; + float u = x - c; + return t - u; + } + + public static float mul(float x) { + float c = 1; + float t = x * c; + float u = x * c; + return t * u; + } + + public static float div(float x) { + float c = 1; + float t = x / c; + float u = x / c; + return t / u; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2f); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Float02.java 2016-12-07 13:53:55.927156616 -0800 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of float operations. + */ +public class VN_Float02 extends JTTTest { + + private static boolean cond = true; + + public static float test(float arg) { + if (arg == 0) { + return add(arg + 10); + } + if (arg == 1) { + return sub(arg + 10); + } + if (arg == 2) { + return mul(arg + 10); + } + if (arg == 3) { + return div(arg + 10); + } + return 0; + } + + public static float add(float x) { + float c = 1.0f; + float t = x + c; + if (cond) { + float u = x + c; + return t + u; + } + return 1.0f; + } + + public static float sub(float x) { + float c = 1.0f; + float t = x - c; + if (cond) { + float u = x - c; + return t - u; + } + return 1.0f; + } + + public static float mul(float x) { + float c = 1.0f; + float t = x * c; + if (cond) { + float u = x * c; + return t * u; + } + return 1.0f; + } + + public static float div(float x) { + float c = 1.0f; + float t = x / c; + if (cond) { + float u = x / c; + return t / u; + } + return 1.0f; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2f); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf01.java 2016-12-07 13:53:56.197168483 -0800 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests value numbering of instanceof operations. + */ +public class VN_InstanceOf01 extends JTTTest { + + static final Object object = new DummyTestClass(); + + public static boolean test(int arg) { + if (arg == 0) { + return foo1(); + } + if (arg == 1) { + return foo2(); + } + if (arg == 2) { + return foo3(); + } + // do nothing + return false; + } + + private static boolean foo1() { + boolean a = object instanceof DummyTestClass; + boolean b = object instanceof DummyTestClass; + return a | b; + } + + private static boolean foo2() { + Object obj = new DummyTestClass(); + boolean a = obj instanceof DummyTestClass; + boolean b = obj instanceof DummyTestClass; + return a | b; + } + + private static boolean foo3() { + boolean a = null instanceof DummyTestClass; + boolean b = null instanceof DummyTestClass; + return a | b; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf02.java 2016-12-07 13:53:56.461180086 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests value numbering of instanceof operations. + */ +public class VN_InstanceOf02 extends JTTTest { + + private static boolean cond = true; + + static final Object object = new DummyTestClass(); + + public static boolean test(int arg) { + if (arg == 0) { + return foo1(); + } + if (arg == 1) { + return foo2(); + } + if (arg == 2) { + return foo3(); + } + // do nothing + return false; + } + + private static boolean foo1() { + boolean a = object instanceof DummyTestClass; + if (cond) { + boolean b = object instanceof DummyTestClass; + return a | b; + } + return false; + } + + private static boolean foo2() { + Object obj = new DummyTestClass(); + boolean a = obj instanceof DummyTestClass; + if (cond) { + boolean b = obj instanceof DummyTestClass; + return a | b; + } + return false; + } + + private static boolean foo3() { + boolean a = null instanceof DummyTestClass; + if (cond) { + boolean b = null instanceof DummyTestClass; + return a | b; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf03.java 2016-12-07 13:53:56.729191865 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests value numbering of instanceof operations. + */ +public class VN_InstanceOf03 extends JTTTest { + + private static boolean cond = true; + + static final Object object = new DummyTestClass(); + + public static boolean test() { + return foo(); + } + + private static boolean foo() { + Object obj = new DummyTestClass(); + boolean a = obj instanceof DummyTestClass; + if (cond) { + boolean b = obj instanceof DummyTestClass; + return a | b; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int01.java 2016-12-07 13:53:56.993203468 -0800 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests value numbering of integer operations. + */ +public class VN_Int01 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return add(arg); + } + if (arg == 1) { + return sub(arg); + } + if (arg == 2) { + return mul(arg); + } + if (arg == 3) { + return div(arg); + } + if (arg == 4) { + return mod(arg); + } + if (arg == 5) { + return and(arg); + } + if (arg == 6) { + return or(arg); + } + if (arg == 7) { + return xor(arg); + } + return 0; + } + + public static int add(int x) { + int c = 3; + int t = x + c; + int u = x + c; + return t + u; + } + + public static int sub(int x) { + int c = 3; + int t = x - c; + int u = x - c; + return t - u; + } + + public static int mul(int x) { + int i = 3; + int t = x * i; + int u = x * i; + return t * u; + } + + public static int div(int x) { + int i = 9; + int t = i / x; + int u = i / x; + return t / u; + } + + public static int mod(int x) { + int i = 7; + int t = i % x; + int u = i % x; + return t % u; + } + + public static int and(int x) { + int i = 7; + int t = i & x; + int u = i & x; + return t & u; + } + + public static int or(int x) { + int i = 7; + int t = i | x; + int u = i | x; + return t | u; + } + + public static int xor(int x) { + int i = 7; + int t = i ^ x; + int u = i ^ x; + return t ^ u; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int02.java 2016-12-07 13:53:57.257215071 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of integer operations. + */ +public class VN_Int02 extends JTTTest { + + public static int test(int arg) { + if (arg == 0) { + return shift0(arg + 10); + } + if (arg == 1) { + return shift1(arg + 10); + } + if (arg == 2) { + return shift2(arg + 10); + } + return 0; + } + + public static int shift0(int x) { + int c = 1; + int t = x >> c; + int u = x >> c; + return t + u; + } + + public static int shift1(int x) { + int c = 1; + int t = x >>> c; + int u = x >>> c; + return t + u; + } + + public static int shift2(int x) { + int c = 1; + int t = x << c; + int u = x << c; + return t + u; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int03.java 2016-12-07 13:53:57.522226718 -0800 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests value numbering of integer operations. + */ +public class VN_Int03 extends JTTTest { + + private static boolean cond = true; + + public static int test(int arg) { + if (arg == 0) { + return add(arg); + } + if (arg == 1) { + return sub(arg); + } + if (arg == 2) { + return mul(arg); + } + if (arg == 3) { + return div(arg); + } + if (arg == 4) { + return mod(arg); + } + if (arg == 5) { + return and(arg); + } + if (arg == 6) { + return or(arg); + } + if (arg == 7) { + return xor(arg); + } + return 0; + } + + public static int add(int x) { + int c = 3; + int t = x + c; + if (cond) { + int u = x + c; + return t + u; + } + return 0; + } + + public static int sub(int x) { + int c = 3; + int t = x - c; + if (cond) { + int u = x - c; + return t - u; + } + return 3; + } + + public static int mul(int x) { + int i = 3; + int t = x * i; + if (cond) { + int u = x * i; + return t * u; + } + return 3; + } + + public static int div(int x) { + int i = 9; + int t = i / x; + if (cond) { + int u = i / x; + return t / u; + } + return 9; + } + + public static int mod(int x) { + int i = 7; + int t = i % x; + if (cond) { + int u = i % x; + return t % u; + } + return 7; + } + + public static int and(int x) { + int i = 7; + int t = i & x; + if (cond) { + int u = i & x; + return t & u; + } + return 7; + } + + public static int or(int x) { + int i = 7; + int t = i | x; + if (cond) { + int u = i | x; + return t | u; + } + return 7; + } + + public static int xor(int x) { + int i = 7; + int t = i ^ x; + if (cond) { + int u = i ^ x; + return t ^ u; + } + return 7; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long01.java 2016-12-07 13:53:57.786238321 -0800 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests value numbering of long operations. + */ +public class VN_Long01 extends JTTTest { + + public static long test(int arg) { + if (arg == 0) { + return add(arg); + } + if (arg == 1) { + return sub(arg); + } + if (arg == 2) { + return mul(arg); + } + if (arg == 3) { + return div(arg); + } + if (arg == 4) { + return mod(arg); + } + if (arg == 5) { + return and(arg); + } + if (arg == 6) { + return or(arg); + } + if (arg == 7) { + return xor(arg); + } + return 0; + } + + public static long add(long x) { + long t = x + 3; + long u = x + 3; + return t + u; + } + + public static long sub(long x) { + long t = x - 3; + long u = x - 3; + return t - u; + } + + public static long mul(long x) { + long t = x * 3; + long u = x * 3; + return t * u; + } + + public static long div(long x) { + long t = 9 / x; + long u = 9 / x; + return t / u; + } + + public static long mod(long x) { + long t = 7 % x; + long u = 7 % x; + return t % u; + } + + public static long and(long x) { + long t = 7 & x; + long u = 7 & x; + return t & u; + } + + public static long or(long x) { + long t = 7 | x; + long u = 7 | x; + return t | u; + } + + public static long xor(long x) { + long t = 7 ^ x; + long u = 7 ^ x; + return t ^ u; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long02.java 2016-12-07 13:53:58.049249880 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests optimization of integer operations. + */ +public class VN_Long02 extends JTTTest { + + public static long test(int arg) { + if (arg == 0) { + return shift0(arg + 10); + } + if (arg == 1) { + return shift1(arg + 10); + } + if (arg == 2) { + return shift2(arg + 10); + } + return 0; + } + + public static long shift0(long x) { + long c = 1; + long t = x >> c; + long u = x >> c; + return t + u; + } + + public static long shift1(long x) { + long c = 1; + long t = x >>> c; + long u = x >>> c; + return t + u; + } + + public static long shift2(long x) { + long c = 1; + long t = x << c; + long u = x << c; + return t + u; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long03.java 2016-12-07 13:53:58.314261527 -0800 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests value numbering of long operations. + */ +public class VN_Long03 extends JTTTest { + + private static boolean cond = true; + + public static long test(int arg) { + if (arg == 0) { + return add(arg); + } + if (arg == 1) { + return sub(arg); + } + if (arg == 2) { + return mul(arg); + } + if (arg == 3) { + return div(arg); + } + if (arg == 4) { + return mod(arg); + } + if (arg == 5) { + return and(arg); + } + if (arg == 6) { + return or(arg); + } + if (arg == 7) { + return xor(arg); + } + return 0; + } + + public static long add(long x) { + long t = x + 3; + if (cond) { + long u = x + 3; + return t + u; + } + return 3; + } + + public static long sub(long x) { + long t = x - 3; + if (cond) { + long u = x - 3; + return t - u; + } + return 3; + } + + public static long mul(long x) { + long t = x * 3; + if (cond) { + long u = x * 3; + return t * u; + } + return 3; + } + + public static long div(long x) { + long t = 9 / x; + if (cond) { + long u = 9 / x; + return t / u; + } + return 9; + } + + public static long mod(long x) { + long t = 7 % x; + if (cond) { + long u = 7 % x; + return t % u; + } + return 7; + } + + public static long and(long x) { + long t = 7 & x; + if (cond) { + long u = 7 & x; + return t & u; + } + return 7; + } + + public static long or(long x) { + long t = 7 | x; + if (cond) { + long u = 7 | x; + return t | u; + } + return 7; + } + + public static long xor(long x) { + long t = 7 ^ x; + if (cond) { + long u = 7 ^ x; + return t ^ u; + } + return 7; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Loop01.java 2016-12-07 13:53:58.585273438 -0800 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + * Tests value numbering of integer operations. + */ +public class VN_Loop01 extends JTTTest { + + private static boolean cond1 = true; + private static boolean cond2 = true; + + public static int test(int arg) { + if (arg == 0) { + return test1(arg); + } + if (arg == 1) { + return test2(arg); + } + if (arg == 2) { + return test3(arg); + } + if (arg == 3) { + return test4(arg); + } + return 0; + } + + public static int test1(int x) { + int c = 3; + int t = x + c; + while (cond1) { + if (cond2) { + int u = x + c; // GVN should recognize u == t + return t + u; + } + } + return 3; // GVN should recognize 3 == 3 + } + + public static int test2(int x) { + int c = 3; + while (cond1) { + int t = x + c; + if (cond2) { + int u = x + c; // GVN should recognize u == t + return t + u; + } + } + return 3; + } + + public static int test3(int x) { + int c = 3; + int t = x + c; + while (cond1) { + if (cond2) { + int u = x + c; // GVN should recognize u == t + return t + u; + } + int u = x + c; // GVN should recognize u == t + return t + u; + } + return 3; // GVN should recognize 3 == 3 + } + + public static int test4(int x) { + int c = 3; + int t = x + c; + while (cond1) { + if (!cond2) { + int u = x + c; + return t + u; + } + int u = x + c; + return t + u; + } + return 3; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get01.java 2016-12-07 13:53:58.850285085 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_get01 extends JTTTest { + + private static final String[] array = {"0", "1", "2"}; + + public static String test(int i) { + return (String) Array.get(array, i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get02.java 2016-12-07 13:53:59.112296600 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_get02 extends JTTTest { + + private static final int[] array = {11, 21, 42}; + + public static int test(int i) { + return (Integer) Array.get(array, i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get03.java 2016-12-07 13:53:59.376308203 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_get03 extends JTTTest { + + private static final byte[] array = {11, 21, 42}; + + public static byte test(int i) { + return (Byte) Array.get(array, i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getBoolean01.java 2016-12-07 13:53:59.641319850 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_getBoolean01 extends JTTTest { + + private static final boolean[] array = {true, false, true}; + + public static boolean test(int i) { + return Array.getBoolean(array, i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getByte01.java 2016-12-07 13:53:59.906331497 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_getByte01 extends JTTTest { + + private static final byte[] array = {11, 21, 42}; + + public static byte test(int i) { + return Array.getByte(array, i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getChar01.java 2016-12-07 13:54:00.170343099 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_getChar01 extends JTTTest { + + private static final char[] array = {11, 21, 42}; + + public static char test(int i) { + return Array.getChar(array, i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getDouble01.java 2016-12-07 13:54:00.435354747 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_getDouble01 extends JTTTest { + + private static final double[] array = {11.1d, 21.1d, 42.1d}; + + public static double test(int i) { + return Array.getDouble(array, i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getFloat01.java 2016-12-07 13:54:00.700366394 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_getFloat01 extends JTTTest { + + private static final float[] array = {11.1f, 21.1f, 42.1f}; + + public static float test(int i) { + return Array.getFloat(array, i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getInt01.java 2016-12-07 13:54:00.964377997 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_getInt01 extends JTTTest { + + private static final int[] array = {11, 21, 42}; + + public static int test(int i) { + return Array.getInt(array, i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getLength01.java 2016-12-07 13:54:01.228389600 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_getLength01 extends JTTTest { + + private static final int[] array0 = {11, 21, 42}; + private static final boolean[] array1 = {true, true, false, false}; + private static final String[] array2 = {"String"}; + + public static int test(int i) { + Object array = null; + if (i == 0) { + array = array0; + } else if (i == 1) { + array = array1; + } else if (i == 2) { + array = array2; + } + return Array.getLength(array); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getLong01.java 2016-12-07 13:54:01.493401247 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_getLong01 extends JTTTest { + + private static final long[] array = {11, 21, 42}; + + public static long test(int i) { + return Array.getLong(array, i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getShort01.java 2016-12-07 13:54:01.758412894 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_getShort01 extends JTTTest { + + private static final short[] array = {11, 21, 42}; + + public static short test(int i) { + return Array.getShort(array, i); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance01.java 2016-12-07 13:54:02.023424541 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_newInstance01 extends JTTTest { + + public static boolean test(int i) { + return Array.newInstance(Array_newInstance01.class, i) != null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + + @Test + public void run3() throws Throwable { + runTest("test", -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance02.java 2016-12-07 13:54:02.286436100 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_newInstance02 extends JTTTest { + + public static boolean test(int i) { + Class javaClass; + if (i == 2) { + javaClass = void.class; + } else if (i == 3) { + javaClass = null; + } else { + javaClass = int.class; + } + return Array.newInstance(javaClass, 0) != null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance03.java 2016-12-07 13:54:02.550447702 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_newInstance03 extends JTTTest { + + public static boolean test(int i) { + Class javaClass; + if (i == 2) { + javaClass = int.class; + } else if (i == 3) { + javaClass = Object.class; + } else { + javaClass = Array_newInstance03.class; + } + return Array.newInstance(javaClass, 0).getClass().getComponentType() == javaClass; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance04.java 2016-12-07 13:54:02.814459305 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_newInstance04 extends JTTTest { + + public static boolean test(int i, int j) { + final int[] dims = {i, j}; + return Array.newInstance(Array_newInstance04.class, dims) != null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2, 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3, 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 0, -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance05.java 2016-12-07 13:54:03.078470908 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_newInstance05 extends JTTTest { + + public static boolean test(int i, int j) { + final int[] dims = {i, j}; + Class javaClass; + if (i == 2) { + javaClass = void.class; + } else if (i == 3) { + javaClass = null; + } else { + javaClass = int.class; + } + return Array.newInstance(javaClass, dims) != null; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1, 3); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2, 3); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3, 4); + } + + @Test + public void run3() throws Throwable { + runTest("test", 1, -1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance06.java 2016-12-07 13:54:03.341482468 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_newInstance06 extends JTTTest { + + public static boolean test(int i) { + final int[] dims = {i, 3}; + Class javaClass; + if (i == 2) { + javaClass = int.class; + } else if (i == 3) { + javaClass = Object.class; + } else { + javaClass = Array_newInstance06.class; + } + return Array.newInstance(javaClass, dims).getClass().getComponentType().getComponentType() == javaClass; + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + + @Test + public void run1() throws Throwable { + runTest("test", 2); + } + + @Test + public void run2() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set01.java 2016-12-07 13:54:03.605494071 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_set01 extends JTTTest { + + private static final String[] array = {"x", "x", "x"}; + + public static String test(int i, String value) { + Array.set(array, i, value); + return array[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, "1"); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, "2"); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, "XXd"); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, "--"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set02.java 2016-12-07 13:54:03.869505674 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_set02 extends JTTTest { + + private static final int[] array = {-1, -1, -1}; + + public static int test(int i, int value) { + Array.set(array, i, value); + return array[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 11); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 21); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, 42); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set03.java 2016-12-07 13:54:04.134517320 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_set03 extends JTTTest { + + private static final byte[] array = {-1, -1, -1}; + + public static byte test(int i, byte value) { + Array.set(array, i, value); + return array[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, ((byte) 11)); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, ((byte) 21)); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, ((byte) 42)); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, ((byte) 0)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setBoolean01.java 2016-12-07 13:54:04.399528968 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_setBoolean01 extends JTTTest { + + private static final boolean[] array = {false, false, false}; + + public static boolean test(int i, boolean value) { + Array.setBoolean(array, i, value); + return array[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, true); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, false); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2, true); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, false); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setByte01.java 2016-12-07 13:54:04.662540527 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_setByte01 extends JTTTest { + + private static final byte[] array = {-1, -1, -1}; + + public static byte test(int i, byte value) { + Array.setByte(array, i, value); + return array[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, ((byte) 11)); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, ((byte) 21)); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, ((byte) 42)); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, ((byte) 0)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setChar01.java 2016-12-07 13:54:04.927552173 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_setChar01 extends JTTTest { + + private static final char[] array = {0, 0, 0}; + + public static char test(int i, char value) { + Array.setChar(array, i, value); + return array[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, ((char) 11)); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, ((char) 21)); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, ((char) 42)); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, ((char) 0)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setDouble01.java 2016-12-07 13:54:05.191563776 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_setDouble01 extends JTTTest { + + private static final double[] array = {-1, -1, -1}; + + public static double test(int i, double value) { + Array.setDouble(array, i, value); + return array[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 11.1d); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 21.1d); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, 42.1d); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, 0.1d); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setFloat01.java 2016-12-07 13:54:05.456575423 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_setFloat01 extends JTTTest { + + private static final float[] array = {-1, -1, -1}; + + public static float test(int i, float value) { + Array.setFloat(array, i, value); + return array[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 11.1f); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 21.1f); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, 42.1f); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, 0.1f); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setInt01.java 2016-12-07 13:54:05.722587114 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_setInt01 extends JTTTest { + + private static final int[] array = {-1, -1, -1}; + + public static int test(int i, int value) { + Array.setInt(array, i, value); + return array[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 11); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 21); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, 42); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setLong01.java 2016-12-07 13:54:05.986598717 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_setLong01 extends JTTTest { + + private static final long[] array = {-1, -1, -1}; + + public static long test(int i, long value) { + Array.setLong(array, i, value); + return array[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, 11L); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, 21L); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, 42L); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, 0L); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setShort01.java 2016-12-07 13:54:06.249610276 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Array; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Array_setShort01 extends JTTTest { + + private static final short[] array = {-1, -1, -1}; + + public static short test(int i, short value) { + Array.setShort(array, i, value); + return array[i]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0, ((short) 11)); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1, ((short) 21)); + } + + @Test + public void run2() throws Throwable { + runTest("test", 0, ((short) 42)); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3, ((short) 0)); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getDeclaredField01.java 2016-12-07 13:54:06.513621879 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Class_getDeclaredField01 extends JTTTest { + + static String field; + static int f2; + + public static String test(String input) throws NoSuchFieldException { + return Class_getDeclaredField01.class.getDeclaredField(input).getName(); + } + + public static void main(String[] args) { + field = args[0]; + } + + @Test + public void run0() throws Throwable { + runTest("test", "test"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "field"); + } + + @Test + public void run2() throws Throwable { + runTest("test", "f2"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getDeclaredMethod01.java 2016-12-07 13:54:06.779633570 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Class_getDeclaredMethod01 extends JTTTest { + + static String field; + + public static String test(String input) throws NoSuchMethodException { + return Class_getDeclaredMethod01.class.getDeclaredMethod(input, String[].class).getName(); + } + + public static void main(String[] args) { + field = args[0]; + } + + @Test + public void run0() throws Throwable { + runTest("test", "test"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "main"); + } + + @Test + public void run2() throws Throwable { + runTest("test", "xx"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getField01.java 2016-12-07 13:54:07.042645129 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Class_getField01 extends JTTTest { + + public static String field; + public String field2; + String field3; + + public static String test(String input) throws NoSuchFieldException { + return Class_getField01.class.getField(input).getName(); + } + + @Test + public void run0() throws Throwable { + runTest("test", "test"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "field"); + } + + @Test + public void run2() throws Throwable { + runTest("test", "field2"); + } + + @Test + public void run3() throws Throwable { + runTest("test", "field3"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getField02.java 2016-12-07 13:54:07.306656732 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Class_getField02 extends JTTTest { + + public static String field; + public String field2; + String field3; + + public static String test(String input) throws NoSuchFieldException { + return Class_getField02b.class.getField(input).getName(); + } + + static class Class_getField02b extends Class_getField02 { + + public String field4; + } + + @Test + public void run0() throws Throwable { + runTest("test", "test"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "field"); + } + + @Test + public void run2() throws Throwable { + runTest("test", "field2"); + } + + @Test + public void run3() throws Throwable { + runTest("test", "field3"); + } + + @Test + public void run4() throws Throwable { + runTest("test", "field4"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getMethod01.java 2016-12-07 13:54:07.571668379 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Class_getMethod01 extends JTTTest { + + static String field; + + public static String test(String input) throws NoSuchMethodException { + return Class_getMethod01.class.getMethod(input, String[].class).getName(); + } + + public static void main(String[] args) { + field = args[0]; + } + + @Test + public void run0() throws Throwable { + runTest("test", "test"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "main"); + } + + @Test + public void run2() throws Throwable { + runTest("test", "xx"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getMethod02.java 2016-12-07 13:54:07.834679938 -0800 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Class_getMethod02 extends JTTTest { + + static String field; + + public static String test(int arg) throws NoSuchMethodException { + if (arg == 0) { + return Class_getMethod02.class.getMethod("test").getName(); + } else if (arg == 1) { + return Class_getMethod02.class.getMethod("test", int.class).getName(); + } else if (arg == 2) { + return Class_getMethod02.class.getMethod("main").getName(); + } else if (arg == 3) { + return Class_getMethod02.class.getMethod("main", String[].class).getName(); + } else if (arg == 4) { + return Class_getMethod02.class.getMethod("").getName(); + } else if (arg == 5) { + return Class_getMethod02.class.getMethod("").getName(); + } + return null; + } + + public static void main(String[] args) { + field = args[0]; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance01.java 2016-12-07 13:54:08.103691761 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_newInstance01 extends JTTTest { + + public static boolean test(int i) throws IllegalAccessException, InstantiationException { + if (i == 0) { + return Class_newInstance01.class.newInstance() != null; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance02.java 2016-12-07 13:54:08.368703408 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_newInstance02 extends JTTTest { + + public static boolean test(int i) throws IllegalAccessException, InstantiationException { + if (i == 0) { + // note: we rely on the other class here. + return Class_newInstance07.Class_newInstance.class.newInstance() != null; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance03.java 2016-12-07 13:54:08.633715055 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Class_newInstance03 extends JTTTest { + + public abstract static class AbstractClass { + } + + public static boolean test(int i) throws IllegalAccessException, InstantiationException { + if (i == 0) { + return AbstractClass.class.newInstance() != null; + } else if (i == 1) { + return Cloneable.class.newInstance() != null; + } else if (i == 2) { + return int[].class.newInstance() != null; + } else if (i == 3) { + return int.class.newInstance() != null; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance06.java 2016-12-07 13:54:08.898726702 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_newInstance06 extends JTTTest { + + public static final class Class_newInstance { + + @SuppressWarnings("unused") + private Class_newInstance(int i) { + // do nothing. xx + } + } + + public static boolean test(int i) throws IllegalAccessException, InstantiationException { + if (i == 0) { + return Class_newInstance.class.newInstance() != null; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance07.java 2016-12-07 13:54:09.161738261 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Class_newInstance07 extends JTTTest { + + public static final class Class_newInstance { + + private Class_newInstance() throws Exception { + throw new Exception(); + } + } + + public static boolean test(int i) throws IllegalAccessException, InstantiationException { + if (i == 0) { + return Class_newInstance.class.newInstance() != null; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get01.java 2016-12-07 13:54:09.427749952 -0800 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Field_get01 extends JTTTest { + + public static final byte byteField = 11; + public static final short shortField = 12; + public static final char charField = 13; + public static final int intField = 14; + public static final long longField = 15; + public static final float floatField = 16; + public static final double doubleField = 17; + public static final boolean booleanField = true; + + public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException { + if (arg == 0) { + return Field_get01.class.getField("byteField").get(null).equals(byteField); + } else if (arg == 1) { + return Field_get01.class.getField("shortField").get(null).equals(shortField); + } else if (arg == 2) { + return Field_get01.class.getField("charField").get(null).equals(charField); + } else if (arg == 3) { + return Field_get01.class.getField("intField").get(null).equals(intField); + } else if (arg == 4) { + return Field_get01.class.getField("longField").get(null).equals(longField); + } else if (arg == 5) { + return Field_get01.class.getField("floatField").get(null).equals(floatField); + } else if (arg == 6) { + return Field_get01.class.getField("doubleField").get(null).equals(doubleField); + } else if (arg == 7) { + return Field_get01.class.getField("booleanField").get(null).equals(booleanField); + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get02.java 2016-12-07 13:54:09.692761599 -0800 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Field_get02 extends JTTTest { + + public static class TestClass { + public final byte byteField = 11; + public final short shortField = 12; + public final char charField = 13; + public final int intField = 14; + public final long longField = 15; + public final float floatField = 16; + public final double doubleField = 17; + public final boolean booleanField = true; + } + + private static final TestClass object = new TestClass(); + + public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException { + if (arg == 0) { + return TestClass.class.getField("byteField").get(object).equals(object.byteField); + } else if (arg == 1) { + return TestClass.class.getField("shortField").get(object).equals(object.shortField); + } else if (arg == 2) { + return TestClass.class.getField("charField").get(object).equals(object.charField); + } else if (arg == 3) { + return TestClass.class.getField("intField").get(object).equals(object.intField); + } else if (arg == 4) { + return TestClass.class.getField("longField").get(object).equals(object.longField); + } else if (arg == 5) { + return TestClass.class.getField("floatField").get(object).equals(object.floatField); + } else if (arg == 6) { + return TestClass.class.getField("doubleField").get(object).equals(object.doubleField); + } else if (arg == 7) { + return TestClass.class.getField("booleanField").get(object).equals(object.booleanField); + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get03.java 2016-12-07 13:54:09.957773245 -0800 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.Field; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Field_get03 extends JTTTest { + + private static Field ByteField; + private static Field ShortField; + private static Field CharField; + private static Field IntField; + private static Field LongField; + private static Field FloatField; + private static Field DoubleField; + private static Field BooleanField; + + static { + try { + ByteField = TestClass.class.getField("byteField"); + ShortField = TestClass.class.getField("shortField"); + CharField = TestClass.class.getField("charField"); + IntField = TestClass.class.getField("intField"); + LongField = TestClass.class.getField("longField"); + FloatField = TestClass.class.getField("floatField"); + DoubleField = TestClass.class.getField("doubleField"); + BooleanField = TestClass.class.getField("booleanField"); + } catch (SecurityException | NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + + private static class TestClass { + public final byte byteField = 11; + public final short shortField = 12; + public final char charField = 13; + public final int intField = 14; + public final long longField = 15; + public final float floatField = 16; + public final double doubleField = 17; + public final boolean booleanField = true; + } + + private static final TestClass object = new TestClass(); + + public static boolean test(int arg) throws IllegalAccessException { + if (arg == 0) { + return ByteField.get(object).equals(object.byteField); + } else if (arg == 1) { + return ShortField.get(object).equals(object.shortField); + } else if (arg == 2) { + return CharField.get(object).equals(object.charField); + } else if (arg == 3) { + return IntField.get(object).equals(object.intField); + } else if (arg == 4) { + return LongField.get(object).equals(object.longField); + } else if (arg == 5) { + return FloatField.get(object).equals(object.floatField); + } else if (arg == 6) { + return DoubleField.get(object).equals(object.doubleField); + } else if (arg == 7) { + return BooleanField.get(object).equals(object.booleanField); + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get04.java 2016-12-07 13:54:10.221784848 -0800 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Field_get04 extends JTTTest { + + private static class TestClass { + public final byte byteField = 11; + public final short shortField = 12; + public final char charField = 13; + public final int intField = 14; + public final long longField = 15; + public final float floatField = 16; + public final double doubleField = 17; + public final boolean booleanField = true; + } + + private static final TestClass object = new TestClass(); + + public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException { + if (arg == 0) { + return TestClass.class.getField("byteField").getByte(object) == object.byteField; + } else if (arg == 1) { + return TestClass.class.getField("shortField").getShort(object) == object.shortField; + } else if (arg == 2) { + return TestClass.class.getField("charField").getChar(object) == object.charField; + } else if (arg == 3) { + return TestClass.class.getField("intField").getInt(object) == object.intField; + } else if (arg == 4) { + return TestClass.class.getField("longField").getLong(object) == object.longField; + } else if (arg == 5) { + return TestClass.class.getField("floatField").getFloat(object) == object.floatField; + } else if (arg == 6) { + return TestClass.class.getField("doubleField").getDouble(object) == object.doubleField; + } else if (arg == 7) { + return TestClass.class.getField("booleanField").getBoolean(object) == object.booleanField; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_getType01.java 2016-12-07 13:54:10.486796495 -0800 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Field_getType01 extends JTTTest { + + public static final byte byteField = 11; + public static final short shortField = 12; + public static final char charField = 13; + public static final int intField = 14; + public static final long longField = 15; + public static final float floatField = 16; + public static final double doubleField = 17; + public static final boolean booleanField = true; + + public static boolean test(int arg) throws NoSuchFieldException { + if (arg == 0) { + return Field_getType01.class.getField("byteField").getType() == byte.class; + } else if (arg == 1) { + return Field_getType01.class.getField("shortField").getType() == short.class; + } else if (arg == 2) { + return Field_getType01.class.getField("charField").getType() == char.class; + } else if (arg == 3) { + return Field_getType01.class.getField("intField").getType() == int.class; + } else if (arg == 4) { + return Field_getType01.class.getField("longField").getType() == long.class; + } else if (arg == 5) { + return Field_getType01.class.getField("floatField").getType() == float.class; + } else if (arg == 6) { + return Field_getType01.class.getField("doubleField").getType() == double.class; + } else if (arg == 7) { + return Field_getType01.class.getField("booleanField").getType() == boolean.class; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set01.java 2016-12-07 13:54:10.749808054 -0800 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Field_set01 extends JTTTest { + + public static byte byteField; + public static short shortField; + public static char charField; + public static int intField; + public static long longField; + public static float floatField; + public static double doubleField; + public static boolean booleanField; + + public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException { + if (arg == 0) { + Field_set01.class.getField("byteField").set(null, Byte.valueOf((byte) 11)); + return byteField == 11; + } else if (arg == 1) { + Field_set01.class.getField("shortField").set(null, Short.valueOf((short) 12)); + return shortField == 12; + } else if (arg == 2) { + Field_set01.class.getField("charField").set(null, Character.valueOf((char) 13)); + return charField == 13; + } else if (arg == 3) { + Field_set01.class.getField("intField").set(null, Integer.valueOf(14)); + return intField == 14; + } else if (arg == 4) { + Field_set01.class.getField("longField").set(null, Long.valueOf(15L)); + return longField == 15; + } else if (arg == 5) { + Field_set01.class.getField("floatField").set(null, Float.valueOf(16)); + return floatField == 16; + } else if (arg == 6) { + Field_set01.class.getField("doubleField").set(null, Double.valueOf(17)); + return doubleField == 17; + } else if (arg == 7) { + Field_set01.class.getField("booleanField").set(null, true); + return booleanField == true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set02.java 2016-12-07 13:54:11.014819701 -0800 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Field_set02 extends JTTTest { + + private static class TestClass { + public byte byteField; + public short shortField; + public char charField; + public int intField; + public long longField; + public float floatField; + public double doubleField; + public boolean booleanField; + } + + private static final TestClass object = new TestClass(); + + public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException { + if (arg == 0) { + TestClass.class.getField("byteField").set(object, Byte.valueOf((byte) 11)); + return object.byteField == 11; + } else if (arg == 1) { + TestClass.class.getField("shortField").set(object, Short.valueOf((short) 12)); + return object.shortField == 12; + } else if (arg == 2) { + TestClass.class.getField("charField").set(object, Character.valueOf((char) 13)); + return object.charField == 13; + } else if (arg == 3) { + TestClass.class.getField("intField").set(object, Integer.valueOf(14)); + return object.intField == 14; + } else if (arg == 4) { + TestClass.class.getField("longField").set(object, Long.valueOf(15L)); + return object.longField == 15; + } else if (arg == 5) { + TestClass.class.getField("floatField").set(object, Float.valueOf(16)); + return object.floatField == 16; + } else if (arg == 6) { + TestClass.class.getField("doubleField").set(object, Double.valueOf(17)); + return object.doubleField == 17; + } else if (arg == 7) { + TestClass.class.getField("booleanField").set(object, true); + return object.booleanField == true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set03.java 2016-12-07 13:54:11.279831348 -0800 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Field_set03 extends JTTTest { + + private static class TestClass { + public byte byteField; + public short shortField; + public char charField; + public int intField; + public long longField; + public float floatField; + public double doubleField; + public boolean booleanField; + } + + private static final TestClass object = new TestClass(); + + public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException { + if (arg == 0) { + TestClass.class.getField("byteField").setByte(object, (byte) 11); + return object.byteField == 11; + } else if (arg == 1) { + TestClass.class.getField("shortField").setShort(object, (short) 12); + return object.shortField == 12; + } else if (arg == 2) { + TestClass.class.getField("charField").setChar(object, (char) 13); + return object.charField == 13; + } else if (arg == 3) { + TestClass.class.getField("intField").setInt(object, 14); + return object.intField == 14; + } else if (arg == 4) { + TestClass.class.getField("longField").setLong(object, 15L); + return object.longField == 15; + } else if (arg == 5) { + TestClass.class.getField("floatField").setFloat(object, 16); + return object.floatField == 16; + } else if (arg == 6) { + TestClass.class.getField("doubleField").setDouble(object, 17); + return object.doubleField == 17; + } else if (arg == 7) { + TestClass.class.getField("booleanField").setBoolean(object, true); + return object.booleanField == true; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test + public void run5() throws Throwable { + runTest("test", 5); + } + + @Test + public void run6() throws Throwable { + runTest("test", 6); + } + + @Test + public void run7() throws Throwable { + runTest("test", 7); + } + + @Test + public void run8() throws Throwable { + runTest("test", 8); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_except01.java 2016-12-07 13:54:11.543842951 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.reflect; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Invoke_except01 extends JTTTest { + + public static class TestClass { + public static int method(int[] arg) { + return arg.length; + } + } + + public static int test(int arg) throws IllegalAccessException, InvocationTargetException { + Object[] args; + if (arg == 0) { + args = new Object[]{new int[0]}; + } else if (arg == 1) { + args = new Object[]{new int[3]}; + } else if (arg == 2) { + args = new Object[]{null}; + } else if (arg == 3) { + args = new Object[]{new char[3]}; + } else { + args = null; + } + for (Method m : TestClass.class.getDeclaredMethods()) { + if ("method".equals(m.getName())) { + return (Integer) m.invoke(null, args); + } + } + return 42; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main01.java 2016-12-07 13:54:11.809854642 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.InvocationTargetException; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Invoke_main01 extends JTTTest { + + public static class TestClass { + public static void main(String[] args) { + field = args[0]; + } + } + + static String field; + + public static String test(String input) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + field = null; + final String[] args = {input}; + TestClass.class.getMethod("main", String[].class).invoke(null, new Object[]{args}); + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test", "test1"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "test2"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main02.java 2016-12-07 13:54:12.074866289 -0800 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.InvocationTargetException; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Invoke_main02 extends JTTTest { + + public static class TestClass { + public static void main(String[] args) { + field = args[0]; + } + } + + static String field; + + public static String test(String input) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + field = null; + final String[] args = {input}; + TestClass.class.getDeclaredMethod("main", String[].class).invoke(null, new Object[]{args}); + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test", "test1"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "test2"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main03.java 2016-12-07 13:54:12.337877848 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Invoke_main03 extends JTTTest { + + public static class TestClass { + public static void main(String[] args) { + field = args[0]; + } + } + + static String field; + + public static String test(String input) throws IllegalAccessException, InvocationTargetException { + field = null; + final String[] args = {input}; + for (Method m : TestClass.class.getDeclaredMethods()) { + if ("main".equals(m.getName())) { + m.invoke(null, new Object[]{args}); + } + } + return field; + } + + @Test + public void run0() throws Throwable { + runTest("test", "test1"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "test2"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_virtual01.java 2016-12-07 13:54:12.602889495 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Invoke_virtual01 extends JTTTest { + + static final HelperTest helper = new HelperTest(55); + + public static int test(int input) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + if (input == 1) { + final Method m = HelperTest.class.getDeclaredMethod("getInt"); + Object o = m.invoke(helper); + return ((Integer) o).intValue(); + } + return 0; + } + + public static class HelperTest { + + private int intField; + + public int getInt() { + return intField; + } + + public HelperTest(int i) { + intField = i; + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 1); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Method_getParameterTypes01.java 2016-12-07 13:54:12.866901098 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +@SuppressWarnings("unused") +public class Method_getParameterTypes01 extends JTTTest { + + public static int test(int arg) throws NoSuchMethodException { + if (arg == 0) { + return Method_getParameterTypes01.class.getMethod("method1").getParameterTypes().length; + } else if (arg == 1) { + return Method_getParameterTypes01.class.getMethod("method2", int.class).getParameterTypes().length; + } else if (arg == 2) { + return Method_getParameterTypes01.class.getMethod("method3", int.class, Object.class).getParameterTypes().length; + } + return -1; + } + + public int method1() { + return 0; + } + + public void method2(int arg1) { + } + + public void method3(int arg1, Object arg2) { + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Method_getReturnType01.java 2016-12-07 13:54:13.130912701 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.reflect; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class Method_getReturnType01 extends JTTTest { + + public static String test(int arg) throws NoSuchMethodException { + if (arg == 0) { + return Method_getReturnType01.class.getMethod("method1").getReturnType().getName(); + } else if (arg == 1) { + return Method_getReturnType01.class.getMethod("method2").getReturnType().getName(); + } else if (arg == 2) { + return Method_getReturnType01.class.getMethod("method3").getReturnType().getName(); + } + return null; + } + + public int method1() { + return 0; + } + + public String method2() { + return null; + } + + public void method3() { + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_contended01.java 2016-12-07 13:54:13.395924348 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Monitor_contended01 extends JTTTest { + + private static class TestClass implements Runnable { + boolean started = false; + boolean acquired = false; + + @Override + public void run() { + // signal that we have started up so first thread will release lock + synchronized (cond) { + started = true; + cond.notifyAll(); + } + synchronized (obj) { + + } + // signal that we have successfully acquired and released the monitor + synchronized (cond) { + acquired = true; + cond.notifyAll(); + } + } + } + + static final Object cond = new Object(); + static final Object obj = new Object(); + + public static boolean test() throws InterruptedException { + // test contention for monitor + final TestClass object = new TestClass(); + synchronized (obj) { + new Thread(object).start(); + // wait for other thread to startup and contend + synchronized (cond) { + cond.wait(1000); + if (!object.started) { + return false; + } + } + } + // wait for other thread to acquire monitor and then exit + synchronized (cond) { + cond.wait(1000); + } + return object.acquired; + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_notowner01.java 2016-12-07 13:54:13.661936039 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Monitor_notowner01 extends JTTTest { + + static Object monitor = new Object(); + static Object finished = new Object(); + + public static boolean test() throws InterruptedException { + final BadRunnable badRunnable = new BadRunnable(); + synchronized (monitor) { + new Thread(badRunnable).start(); + synchronized (finished) { + finished.wait(1000); + } + } + return badRunnable.caught; + } + + static class BadRunnable implements Runnable { + + protected boolean caught = false; + + @Override + public void run() { + try { + // we don't own this! + monitor.wait(); + } catch (InterruptedException ex) { + + } catch (IllegalMonitorStateException ex) { + caught = true; + synchronized (finished) { + finished.notifyAll(); + } + } + } + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter01.java 2016-12-07 13:54:13.926947685 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Monitorenter01 extends JTTTest { + + static final Object object = new Object(); + + public static boolean test() { + // test nested locking. + synchronized (object) { + synchronized (object) { + return true; + } + } + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter02.java 2016-12-07 13:54:14.189959245 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Monitorenter02 extends JTTTest { + + static final Object object = new Object(); + + public static boolean test() { + // test nested locking. + synchronized (object) { + return test2(); + } + } + + private static boolean test2() { + synchronized (object) { + return true; + } + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait01.java 2016-12-07 13:54:14.453970847 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Object_wait01 extends JTTTest { + + private static class TestClass implements Runnable { + @Override + public void run() { + int i = 0; + while (i++ < 1000000 && !done) { + synchronized (object) { + count++; + object.notifyAll(); + } + } + } + } + + static volatile int count = 0; + static volatile boolean done; + static final Object object = new Object(); + + public static boolean test(int i) throws InterruptedException { + count = 0; + done = false; + new Thread(new TestClass()).start(); + synchronized (object) { + while (count < i) { + object.wait(); + } + done = true; + return count >= i; + } + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test(timeout = 20000) + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test(timeout = 20000) + public void run2() throws Throwable { + runTest("test", 3); + } + + @Test(timeout = 20000) + public void run3() throws Throwable { + runTest("test", 15); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait02.java 2016-12-07 13:54:14.716982407 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Object_wait02 extends JTTTest { + + private static class TestClass implements Runnable { + @Override + public void run() { + try { + Thread.sleep(sleep); + } catch (InterruptedException ex) { + + } + synchronized (object) { + done = true; + object.notifyAll(); + } + } + } + + static volatile boolean done; + static final Object object = new Object(); + static int sleep; + + public static boolean test(int i) throws InterruptedException { + done = false; + sleep = i * 200; + new Thread(new TestClass()).start(); + synchronized (object) { + while (!done) { + object.wait(200); + } + } + return done; + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test(timeout = 20000) + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test(timeout = 20000) + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait03.java 2016-12-07 13:54:14.979993966 -0800 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Object_wait03 extends JTTTest { + + private static class TestClass implements Runnable { + @Override + public void run() { + try { + Thread.sleep(sleep); + } catch (InterruptedException ex) { + + } + synchronized (object) { + done = true; + object.notifyAll(); + } + } + } + + static volatile boolean done; + static final Object object = new Object(); + static int sleep; + + public static boolean test(int i) throws InterruptedException { + done = false; + sleep = i * 200; + synchronized (object) { + new Thread(new TestClass()).start(); + dowait(); + } + return done; + } + + private static void dowait() throws InterruptedException { + synchronized (object) { + while (!done) { + object.wait(200); + } + } + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test(timeout = 20000) + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test(timeout = 20000) + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait04.java 2016-12-07 13:54:15.245005612 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Object_wait04 extends JTTTest { + + private static class TestClass implements Runnable { + @Override + public void run() { + try { + Thread.sleep(sleep); + } catch (InterruptedException ex) { + + } + synchronized (object) { + done = true; + object.notifyAll(); + } + } + } + + static volatile boolean done; + static final Object object = new Object(); + static int sleep; + + public static boolean test(int i) throws InterruptedException { + done = false; + sleep = i * 50; + synchronized (object) { + new Thread(new TestClass()).start(); + dowait(i); + } + return done; + } + + private static void dowait(int i) throws InterruptedException { + if (i == 0) { + while (!done) { + object.wait(100); + } + } else { + synchronized (object) { + dowait(i - 1); + } + } + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test(timeout = 20000) + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test(timeout = 20000) + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test(timeout = 20000) + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test(timeout = 20000) + public void run4() throws Throwable { + runTest("test", 4); + } + + @Test(timeout = 20000) + public void run5() throws Throwable { + runTest("test", 5); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/SynchronizedLoopExit01.java 2016-12-07 13:54:15.509017215 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + */ +package org.graalvm.compiler.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/** + * Inspired by {@code com.sun.media.sound.DirectAudioDevice$DirectDL.drain()}. + * + * Two loop exits hold a monitor while merging. + * + */ +public final class SynchronizedLoopExit01 extends JTTTest { + + protected Object object = new Object(); + protected volatile boolean drained = false; + protected volatile boolean someBoolean = true; + + public boolean test() { + boolean b = true; + while (!drained) { + synchronized (object) { + boolean c = b = someBoolean; + if (c || drained) { + break; + } + } + } + return b; + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal01.java 2016-12-07 13:54:15.774028863 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class ThreadLocal01 extends JTTTest { + + private static final ThreadLocal local = new ThreadLocal<>(); + + public static int test(int i) { + local.set(i + 5); + return local.get(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal02.java 2016-12-07 13:54:16.038040465 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class ThreadLocal02 extends JTTTest { + + public static int test(int i) { + ThreadLocal local = new ThreadLocal<>(); + local.set(i + 5); + return local.get(); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal03.java 2016-12-07 13:54:16.302052068 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ +public class ThreadLocal03 extends JTTTest { + + static final ThreadLocal local = new ThreadLocal<>(); + + public static int test(int i) { + int sum = 0; + for (int j = 0; j < i; j++) { + TThread t = new TThread(); + t.input = 10 + j; + t.run(); + try { + t.join(); + } catch (InterruptedException e) { + return -1; + } + sum += t.output; + } + return sum; + } + + private static class TThread extends Thread { + + int input; + int output; + + @Override + public void run() { + local.set(input + 5); + output = local.get(); + } + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_currentThread01.java 2016-12-07 13:54:16.566063671 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Thread_currentThread01 extends JTTTest { + + public static boolean test() { + return Thread.currentThread() != null; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_getState01.java 2016-12-07 13:54:16.832075362 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Thread_getState01 extends JTTTest { + + public static boolean test() { + return Thread.currentThread().getState() == Thread.State.RUNNABLE; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_getState02.java 2016-12-07 13:54:17.095086921 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Thread_getState02 extends JTTTest { + + public static boolean test() { + return new Thread().getState() == Thread.State.NEW; + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_holdsLock01.java 2016-12-07 13:54:17.359098524 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Thread_holdsLock01 extends JTTTest { + + static final Object monitor = new Object(); + + public static boolean test(int i) { + if (i == 0) { + synchronized (monitor) { + return Thread.holdsLock(monitor); + } + } else if (i == 1) { + synchronized (monitor) { + // do nothing. + } + return Thread.holdsLock(monitor); + } else if (i == 2) { + return Thread.holdsLock(null); + } + return Thread.holdsLock(monitor); + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isAlive01.java 2016-12-07 13:54:17.624110171 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Thread_isAlive01 extends JTTTest { + + public static boolean test() { + return Thread.currentThread().isAlive(); + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted01.java 2016-12-07 13:54:17.888121773 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Thread_isInterrupted01 extends JTTTest { + + public static boolean test() { + return Thread.currentThread().isInterrupted(); + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted02.java 2016-12-07 13:54:18.152133377 -0800 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Assert; +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +//Test all, mainly monitors +public class Thread_isInterrupted02 extends JTTTest { + + private static final Object start = new Object(); + private static final Object end = new Object(); + private static int waitTime; + + @SuppressWarnings("unused") + public static boolean test(int i, int time) throws InterruptedException { + waitTime = time; + final Thread thread = new Thread(); + synchronized (thread) { + // start the thread and wait for it + thread.setDaemon(true); // in case the thread gets stuck + thread.start(); + while (!thread.wait1Condition) { + thread.wait(10000); + } + } + synchronized (start) { + thread.interrupt(); + thread.sentInterrupt = true; + } + synchronized (end) { + while (!thread.wait2Condition) { + end.wait(10000); + } + } + return thread.interrupted; + } + + private static class Thread extends java.lang.Thread { + + private boolean interrupted; + private boolean sentInterrupt; + private boolean wait1Condition; + private boolean wait2Condition; + + @Override + public void run() { + try { + synchronized (start) { + synchronized (this) { + // signal test thread that we are running + wait1Condition = true; + notify(); + } + // wait for the condition, which should be interrupted + while (!sentInterrupt) { + if (waitTime == 0) { + start.wait(); + } else { + start.wait(waitTime); + } + if (Thread.interrupted()) { + throw new InterruptedException(); + } + } + Assert.fail("should not reach here - was not interrupted"); + } + } catch (InterruptedException e) { + // interrupted successfully. + interrupted = true; + synchronized (end) { + // notify the other thread we are done + wait2Condition = true; + end.notify(); + } + } + } + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test", 0, 0); + } + + @Test(timeout = 20000) + public void run1() throws Throwable { + runTest("test", 1, 500); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted03.java 2016-12-07 13:54:18.419145111 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ + +// Interrupted while sleeping, throws an interrupted exception +public class Thread_isInterrupted03 extends JTTTest { + + public static boolean test() throws InterruptedException { + final Thread1 thread = new Thread1(); + thread.start(); + Thread.sleep(1000); + thread.interrupt(); + Thread.sleep(1000); + // Did thread get interrupted? + final boolean result = thread.getInterrupted(); + // This stops the thread even if the interrupt didn't! + thread.setInterrupted(true); + return result; + } + + private static class Thread1 extends java.lang.Thread { + + private boolean interrupted = false; + + @Override + public void run() { + while (!interrupted) { + try { + sleep(10000); + } catch (InterruptedException e) { + interrupted = true; + } + } + } + + public void setInterrupted(boolean val) { + interrupted = val; + } + + public boolean getInterrupted() { + return interrupted; + } + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted04.java 2016-12-07 13:54:18.684156758 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ + +// Interrupted while running, do nothing, just set the flag and continue +// (thomaswue) This test will exercise deoptimization on HotSpot, because a volatile unloaded field is accessed. +// (thomaswue) The temporary result variable is needed, because in order to query the isInterrupted flag, the thread must be alive. +public class Thread_isInterrupted04 extends JTTTest { + + public static boolean test() throws InterruptedException { + final Thread1 thread = new Thread1(); + thread.start(); + while (!thread.running) { + Thread.sleep(10); + } + Thread.sleep(100); + thread.interrupt(); + boolean result = thread.isInterrupted(); + thread.setStop(true); + return result; + } + + public static class Thread1 extends java.lang.Thread { + + private volatile boolean stop = false; + public volatile boolean running = false; + public long i = 0; + + @Override + public void run() { + running = true; + while (!stop) { + i++; + } + } + + public void setStop(boolean value) { + stop = value; + } + + } + + @Test + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted05.java 2016-12-07 13:54:18.950168449 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +/* + */ + +// Interrupted during wait, with interrupter joining +public class Thread_isInterrupted05 extends JTTTest { + + public static boolean test() throws InterruptedException { + final WaitInterruptee waitInterruptee = new WaitInterruptee(); + waitInterruptee.start(); + waitInterruptee.interrupt(); + waitInterruptee.join(); + + if (waitInterruptee.throwable != null) { + throw new RuntimeException(waitInterruptee.throwable); + } + return true; + } + + static class WaitInterruptee extends Thread { + + Throwable throwable; + + WaitInterruptee() { + super("WaitInterruptee"); + } + + @Override + public void run() { + try { + synchronized (this) { + try { + wait(); + } catch (InterruptedException ex) { + } + } + } catch (Throwable t) { + throwable = t; + } + } + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join01.java 2016-12-07 13:54:19.215180096 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Thread_join01 extends JTTTest { + + private static class TestClass implements Runnable { + @Override + public void run() { + cont = false; + } + } + + static volatile boolean cont; + + public static boolean test() throws InterruptedException { + cont = true; + final Thread thread = new Thread(new TestClass()); + thread.start(); + thread.join(); + return cont; + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join02.java 2016-12-07 13:54:19.479191699 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * + * This test sleeps the thread that is joined to, which should ensure that the joining thread + * actually does wait for completeion. + */ +package org.graalvm.compiler.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Thread_join02 extends JTTTest { + + private static class TestClass implements Runnable { + @Override + public void run() { + try { + Thread.sleep(200); + } catch (InterruptedException ex) { + } + cont = false; + } + } + + static volatile boolean cont; + + public static boolean test() throws InterruptedException { + cont = true; + final Thread thread = new Thread(new TestClass()); + thread.start(); + thread.join(); + return cont; + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join03.java 2016-12-07 13:54:19.745203390 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2012, 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. + */ +/* + * + * This test sleeps the joining thread, which should enure that the joinee is + * terminated by the time the join occurs. + */ +package org.graalvm.compiler.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Thread_join03 extends JTTTest { + + private static class TestClass implements Runnable { + @Override + public void run() { + cont = false; + } + } + + static volatile boolean cont; + + public static boolean test() throws InterruptedException { + cont = true; + final Thread thread = new Thread(new TestClass()); + thread.start(); + Thread.sleep(200); + thread.join(); + return cont; + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_new01.java 2016-12-07 13:54:20.009214992 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Thread_new01 extends JTTTest { + + public static boolean test(int i) { + if (i == 0) { + return new Thread() != null; + } + if (i == 1) { + return new Thread("Thread_new01") != null; + } + if (i == 2) { + return new Thread(new Thread()) != null; + } + if (i == 3) { + return new Thread(new Thread(), "Thread_new01") != null; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_new02.java 2016-12-07 13:54:20.273226595 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class Thread_new02 extends JTTTest { + + private static class TestClass implements Runnable { + @Override + public void run() { + // do nothing. + } + } + + static final TestClass thisObject = new TestClass(); + + public static boolean test(int i) { + if (i == 0) { + return new Thread() != null; + } + if (i == 1) { + return new Thread("Thread_new01") != null; + } + if (i == 2) { + return new Thread(thisObject) != null; + } + if (i == 3) { + return new Thread(thisObject, "Thread_new01") != null; + } + return false; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 2); + } + + @Test + public void run3() throws Throwable { + runTest("test", 3); + } + + @Test + public void run4() throws Throwable { + runTest("test", 4); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_setPriority01.java 2016-12-07 13:54:20.539238286 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Thread_setPriority01 extends JTTTest { + + public static boolean test(int i) { + final Thread currentThread = Thread.currentThread(); + final int prev = currentThread.getPriority(); + currentThread.setPriority(i); + currentThread.setPriority(prev); + return true; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", 1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 5); + } + + @Test + public void run3() throws Throwable { + runTest("test", 10); + } + + @Test + public void run4() throws Throwable { + runTest("test", 11); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_sleep01.java 2016-12-07 13:54:20.803249889 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Thread_sleep01 extends JTTTest { + + public static boolean test(int i) throws InterruptedException { + final long before = System.currentTimeMillis(); + Thread.sleep(i); + return System.currentTimeMillis() - before >= i; + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test", 10); + } + + @Test(timeout = 20000) + public void run1() throws Throwable { + runTest("test", 20); + } + + @Test(timeout = 20000) + public void run2() throws Throwable { + runTest("test", 100); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_yield01.java 2016-12-07 13:54:21.066261448 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2007, 2012, 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.jtt.threads; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public final class Thread_yield01 extends JTTTest { + + public static boolean test() { + Thread.yield(); + return true; + } + + @Test(timeout = 20000) + public void run0() throws Throwable { + runTest("test"); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64AddressValue.java 2016-12-07 13:54:21.332273139 -0800 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.aarch64; + +import java.util.EnumSet; + +import org.graalvm.compiler.asm.aarch64.AArch64Address; +import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ExtendType; +import org.graalvm.compiler.lir.CompositeValue; +import org.graalvm.compiler.lir.InstructionValueConsumer; +import org.graalvm.compiler.lir.InstructionValueProcedure; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; + +public final class AArch64AddressValue extends CompositeValue { + private static final EnumSet flags = EnumSet.of(OperandFlag.REG, OperandFlag.ILLEGAL); + + @Component({OperandFlag.REG, OperandFlag.ILLEGAL}) protected AllocatableValue base; + @Component({OperandFlag.REG, OperandFlag.ILLEGAL}) protected AllocatableValue offset; + private final int immediate; + + /** + * Whether register offset should be scaled or not. + */ + private final boolean scaled; + private final AddressingMode addressingMode; + + public AArch64AddressValue(ValueKind kind, AllocatableValue base, AllocatableValue offset, int immediate, boolean scaled, AddressingMode addressingMode) { + super(kind); + this.base = base; + this.offset = offset; + this.immediate = immediate; + this.scaled = scaled; + this.addressingMode = addressingMode; + } + + private static Register toRegister(AllocatableValue value) { + if (value.equals(Value.ILLEGAL)) { + return AArch64.zr; + } else { + return ((RegisterValue) value).getRegister(); + } + } + + public AllocatableValue getBase() { + return base; + } + + public AllocatableValue getOffset() { + return offset; + } + + public int getImmediate() { + return immediate; + } + + public boolean isScaled() { + return scaled; + } + + public AddressingMode getAddressingMode() { + return addressingMode; + } + + public AArch64Address toAddress() { + Register baseReg = toRegister(base); + Register offsetReg = toRegister(offset); + AArch64Assembler.ExtendType extendType = addressingMode == AddressingMode.EXTENDED_REGISTER_OFFSET ? ExtendType.SXTW : null; + return AArch64Address.createAddress(addressingMode, baseReg, offsetReg, immediate, scaled, extendType); + } + + @Override + public CompositeValue forEachComponent(LIRInstruction inst, LIRInstruction.OperandMode mode, InstructionValueProcedure proc) { + AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags); + AllocatableValue newOffset = (AllocatableValue) proc.doValue(inst, offset, mode, flags); + if (!base.identityEquals(newBase) || !offset.identityEquals(newOffset)) { + return new AArch64AddressValue(getValueKind(), newBase, newOffset, immediate, scaled, addressingMode); + } + return this; + } + + @Override + protected void visitEachComponent(LIRInstruction inst, LIRInstruction.OperandMode mode, InstructionValueConsumer proc) { + proc.visitValue(inst, base, mode, flags); + proc.visitValue(inst, offset, mode, flags); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticLIRGeneratorTool.java 2016-12-07 13:54:21.597284786 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 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.lir.aarch64; + +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; + +import jdk.vm.ci.aarch64.AArch64Kind; +import jdk.vm.ci.meta.Value; + +/** + * This interface can be used to generate AArch64 LIR for arithmetic operations. + */ +public interface AArch64ArithmeticLIRGeneratorTool extends ArithmeticLIRGeneratorTool { + + Value emitCountLeadingZeros(Value value); + + Value emitCountTrailingZeros(Value value); + + void emitCompareOp(AArch64Kind cmpKind, Variable left, Value right); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java 2016-12-07 13:54:21.864296521 -0800 @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.ARITHMETIC; +import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.LOGICAL; +import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.NONE; +import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.SHIFT; +import static jdk.vm.ci.aarch64.AArch64.zr; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64Assembler; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaConstant; + +public enum AArch64ArithmeticOp { + // TODO At least add and sub *can* be used with SP, so this should be supported + NEG, + NOT, + ADD(ARITHMETIC), + ADDS(ARITHMETIC), + SUB(ARITHMETIC), + SUBS(ARITHMETIC), + MUL, + DIV, + SMULH, + UMULH, + REM, + UDIV, + UREM, + AND(LOGICAL), + ANDS(LOGICAL), + OR(LOGICAL), + XOR(LOGICAL), + SHL(SHIFT), + LSHR(SHIFT), + ASHR(SHIFT), + ABS, + + FADD, + FSUB, + FMUL, + FDIV, + FREM, + FNEG, + FABS, + SQRT; + + /** + * Specifies what constants can be used directly without having to be loaded into a register + * with the given instruction. + */ + public enum ARMv8ConstantCategory { + NONE, + LOGICAL, + ARITHMETIC, + SHIFT + } + + public final ARMv8ConstantCategory category; + + AArch64ArithmeticOp(ARMv8ConstantCategory category) { + this.category = category; + } + + AArch64ArithmeticOp() { + this(NONE); + } + + public static class UnaryOp extends AArch64LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(UnaryOp.class); + + @Opcode private final AArch64ArithmeticOp opcode; + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; + + public UnaryOp(AArch64ArithmeticOp opcode, AllocatableValue result, AllocatableValue x) { + super(TYPE); + this.opcode = opcode; + this.result = result; + this.x = x; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register dst = asRegister(result); + Register src = asRegister(x); + int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; + switch (opcode) { + case NEG: + masm.sub(size, dst, zr, src); + break; + case FNEG: + masm.fneg(size, dst, src); + break; + case NOT: + masm.not(size, dst, src); + break; + case ABS: + masm.cmp(size, src, 0); + masm.csneg(size, dst, src, ConditionFlag.LT); + break; + case FABS: + masm.fabs(size, dst, src); + break; + case SQRT: + masm.fsqrt(size, dst, src); + break; + default: + throw GraalError.shouldNotReachHere("op=" + opcode.name()); + } + } + } + + public static class BinaryConstOp extends AArch64LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryConstOp.class); + + @Opcode private final AArch64ArithmeticOp op; + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue a; + private final JavaConstant b; + + public BinaryConstOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, JavaConstant b) { + super(TYPE); + this.op = op; + this.result = result; + this.a = a; + this.b = b; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + assert op.category != NONE; + Register dst = asRegister(result); + Register src = asRegister(a); + int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; + switch (op) { + case ADD: + // Don't use asInt() here, since we can't use asInt on a long variable, even + // if the constant easily fits as an int. + assert AArch64MacroAssembler.isArithmeticImmediate(b.asLong()); + masm.add(size, dst, src, (int) b.asLong()); + break; + case SUB: + // Don't use asInt() here, since we can't use asInt on a long variable, even + // if the constant easily fits as an int. + assert AArch64MacroAssembler.isArithmeticImmediate(b.asLong()); + masm.sub(size, dst, src, (int) b.asLong()); + break; + case AND: + // XXX Should this be handled somewhere else? + if (size == 32 && b.asLong() == 0xFFFF_FFFFL) { + masm.mov(size, dst, src); + } else { + masm.and(size, dst, src, b.asLong()); + } + break; + case ANDS: + masm.ands(size, dst, src, b.asLong()); + break; + case OR: + masm.or(size, dst, src, b.asLong()); + break; + case XOR: + masm.eor(size, dst, src, b.asLong()); + break; + case SHL: + masm.shl(size, dst, src, b.asLong()); + break; + case LSHR: + masm.lshr(size, dst, src, b.asLong()); + break; + case ASHR: + masm.ashr(size, dst, src, b.asLong()); + break; + default: + throw GraalError.shouldNotReachHere("op=" + op.name()); + } + } + } + + public static class BinaryOp extends AArch64LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryOp.class); + + @Opcode private final AArch64ArithmeticOp op; + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue a; + @Use({REG}) protected AllocatableValue b; + + public BinaryOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, AllocatableValue b) { + super(TYPE); + this.op = op; + this.result = result; + this.a = a; + this.b = b; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register dst = asRegister(result); + Register src1 = asRegister(a); + Register src2 = asRegister(b); + int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; + switch (op) { + case ADD: + masm.add(size, dst, src1, src2); + break; + case ADDS: + masm.adds(size, dst, src1, src2); + break; + case SUB: + masm.sub(size, dst, src1, src2); + break; + case SUBS: + masm.subs(size, dst, src1, src2); + break; + case MUL: + masm.mul(size, dst, src1, src2); + break; + case UMULH: + masm.umulh(size, dst, src1, src2); + break; + case SMULH: + masm.smulh(size, dst, src1, src2); + break; + case DIV: + masm.sdiv(size, dst, src1, src2); + break; + case UDIV: + masm.udiv(size, dst, src1, src2); + break; + case AND: + masm.and(size, dst, src1, src2); + break; + case ANDS: + masm.ands(size, dst, src1, src2); + break; + case OR: + masm.or(size, dst, src1, src2); + break; + case XOR: + masm.eor(size, dst, src1, src2); + break; + case SHL: + masm.shl(size, dst, src1, src2); + break; + case LSHR: + masm.lshr(size, dst, src1, src2); + break; + case ASHR: + masm.ashr(size, dst, src1, src2); + break; + case FADD: + masm.fadd(size, dst, src1, src2); + break; + case FSUB: + masm.fsub(size, dst, src1, src2); + break; + case FMUL: + masm.fmul(size, dst, src1, src2); + break; + case FDIV: + masm.fdiv(size, dst, src1, src2); + break; + default: + throw GraalError.shouldNotReachHere("op=" + op.name()); + } + } + } + + /** + * Class used for instructions that have to reuse one of their arguments. This only applies to + * the remainder instructions at the moment, since we have to compute n % d using rem = n - + * TruncatingDivision(n, d) * d + * + * TODO (das) Replace the remainder nodes in the LIR. + */ + public static class BinaryCompositeOp extends AArch64LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryCompositeOp.class); + @Opcode private final AArch64ArithmeticOp op; + @Def({REG}) protected AllocatableValue result; + @Alive({REG}) protected AllocatableValue a; + @Alive({REG}) protected AllocatableValue b; + + public BinaryCompositeOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, AllocatableValue b) { + super(TYPE); + this.op = op; + this.result = result; + this.a = a; + this.b = b; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register dst = asRegister(result); + Register src1 = asRegister(a); + Register src2 = asRegister(b); + int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; + switch (op) { + case REM: + masm.rem(size, dst, src1, src2); + break; + case UREM: + masm.urem(size, dst, src1, src2); + break; + case FREM: + masm.frem(size, dst, src1, src2); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + } + + public static class AddSubShiftOp extends AArch64LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(AddSubShiftOp.class); + + @Opcode private final AArch64ArithmeticOp op; + @Def(REG) protected AllocatableValue result; + @Use(REG) protected AllocatableValue src1; + @Use(REG) protected AllocatableValue src2; + private final AArch64MacroAssembler.ShiftType shiftType; + private final int shiftAmt; + + /** + * Computes result = src1 src2 . + */ + public AddSubShiftOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue src1, AllocatableValue src2, AArch64MacroAssembler.ShiftType shiftType, int shiftAmt) { + super(TYPE); + assert op == ADD || op == SUB; + this.op = op; + this.result = result; + this.src1 = src1; + this.src2 = src2; + this.shiftType = shiftType; + this.shiftAmt = shiftAmt; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; + switch (op) { + case ADD: + masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), shiftType, shiftAmt); + break; + case SUB: + masm.sub(size, asRegister(result), asRegister(src1), asRegister(src2), shiftType, shiftAmt); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + } + + public static class ExtendedAddShiftOp extends AArch64LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(ExtendedAddShiftOp.class); + @Def(REG) protected AllocatableValue result; + @Use(REG) protected AllocatableValue src1; + @Use(REG) protected AllocatableValue src2; + private final AArch64Assembler.ExtendType extendType; + private final int shiftAmt; + + /** + * Computes result = src1 + extendType(src2) << shiftAmt. + * + * @param extendType defines how src2 is extended to the same size as src1. + * @param shiftAmt must be in range 0 to 4. + */ + public ExtendedAddShiftOp(AllocatableValue result, AllocatableValue src1, AllocatableValue src2, AArch64Assembler.ExtendType extendType, int shiftAmt) { + super(TYPE); + this.result = result; + this.src1 = src1; + this.src2 = src2; + this.extendType = extendType; + this.shiftAmt = shiftAmt; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; + masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), extendType, shiftAmt); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BitManipulationOp.java 2016-12-07 13:54:22.129308167 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013, 2016, 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.lir.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Bit manipulation ops for ARMv8 ISA. + */ +public class AArch64BitManipulationOp extends AArch64LIRInstruction { + public enum BitManipulationOpCode { + BSF, + BSR, + BSWP, + CLZ, + } + + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64BitManipulationOp.class); + + @Opcode private final BitManipulationOpCode opcode; + @Def protected AllocatableValue result; + @Use({REG}) protected AllocatableValue input; + + public AArch64BitManipulationOp(BitManipulationOpCode opcode, AllocatableValue result, AllocatableValue input) { + super(TYPE); + this.opcode = opcode; + this.result = result; + this.input = input; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register dst = asRegister(result); + Register src = asRegister(input); + final int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; + switch (opcode) { + case CLZ: + masm.clz(size, dst, src); + break; + case BSR: + // BSR == - 1 - CLZ(input) + masm.clz(size, dst, src); + masm.neg(size, dst, dst); + masm.add(size, dst, dst, size - 1); + break; + case BSF: + // BSF == CLZ(rev(input)) + masm.rev(size, dst, src); + masm.clz(size, dst, dst); + break; + case BSWP: + masm.rev(size, dst, src); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BlockEndOp.java 2016-12-07 13:54:22.395319858 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 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.lir.aarch64; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.StandardOp.AbstractBlockEndOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +public abstract class AArch64BlockEndOp extends AbstractBlockEndOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64BlockEndOp.class); + + protected AArch64BlockEndOp(LIRInstructionClass c) { + super(c); + } + + @Override + public final void emitCode(CompilationResultBuilder crb) { + emitCode(crb, (AArch64MacroAssembler) crb.asm); + } + + protected abstract void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BreakpointOp.java 2016-12-07 13:54:22.660331505 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AArch64ExceptionCode; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.meta.Value; + +@Opcode("BREAKPOINT") +public class AArch64BreakpointOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64BreakpointOp.class); + + /** + * A set of values loaded into the Java ABI parameter locations (for inspection by a debugger). + */ + @Use({REG, STACK}) private Value[] parameters; + + public AArch64BreakpointOp(Value[] parameters) { + super(TYPE); + this.parameters = parameters; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + masm.brk(AArch64ExceptionCode.BREAKPOINT); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java 2016-12-07 13:54:22.925343152 -0800 @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.aarch64.AArch64.r8; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.InvokeTarget; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +public class AArch64Call { + + public abstract static class CallOp extends AArch64LIRInstruction { + @Def({REG, ILLEGAL}) protected Value result; + @Use({REG, STACK}) protected Value[] parameters; + @Temp({REG, STACK}) protected Value[] temps; + @State protected LIRFrameState state; + + protected CallOp(LIRInstructionClass c, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(c); + this.result = result; + this.parameters = parameters; + this.state = state; + this.temps = addStackSlotsToTemporaries(parameters, temps); + assert temps != null; + } + + @Override + public boolean destroysCallerSavedRegisters() { + return true; + } + } + + public abstract static class MethodCallOp extends CallOp { + protected final ResolvedJavaMethod callTarget; + + protected MethodCallOp(LIRInstructionClass c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(c, result, parameters, temps, state); + this.callTarget = callTarget; + } + } + + @Opcode("CALL_INDIRECT") + public static class IndirectCallOp extends MethodCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(IndirectCallOp.class); + + @Use({REG}) protected Value targetAddress; + + public IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) { + this(TYPE, callTarget, result, parameters, temps, targetAddress, state); + } + + protected IndirectCallOp(LIRInstructionClass c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, + LIRFrameState state) { + super(c, callTarget, result, parameters, temps, state); + this.targetAddress = targetAddress; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register target = asRegister(targetAddress); + indirectCall(crb, masm, target, callTarget, state); + } + + @Override + public void verify() { + super.verify(); + assert isRegister(targetAddress) : "The current register allocator cannot handle variables to be used at call sites, " + "it must be in a fixed register for now"; + } + } + + @Opcode("CALL_DIRECT") + public abstract static class DirectCallOp extends MethodCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectCallOp.class); + + public DirectCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(TYPE, target, result, parameters, temps, state); + } + + protected DirectCallOp(LIRInstructionClass c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(c, callTarget, result, parameters, temps, state); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + directCall(crb, masm, callTarget, null, state); + } + } + + public abstract static class ForeignCallOp extends CallOp { + protected final ForeignCallLinkage callTarget; + protected final Label label; + + protected ForeignCallOp(LIRInstructionClass c, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state, Label label) { + super(c, result, parameters, temps, state); + this.callTarget = callTarget; + this.label = label; + } + + @Override + public boolean destroysCallerSavedRegisters() { + return callTarget.destroysRegisters(); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + emitCall(crb, masm); + } + + protected abstract void emitCall(CompilationResultBuilder crb, AArch64MacroAssembler masm); + } + + @Opcode("NEAR_FOREIGN_CALL") + public static class DirectNearForeignCallOp extends ForeignCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class); + + public DirectNearForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state, Label label) { + super(TYPE, callTarget, result, parameters, temps, state, label); + } + + @Override + protected void emitCall(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + directCall(crb, masm, callTarget, null, state, label); + } + } + + @Opcode("FAR_FOREIGN_CALL") + public static class DirectFarForeignCallOp extends ForeignCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class); + + public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state, Label label) { + super(TYPE, callTarget, result, parameters, temps, state, label); + } + + @Override + protected void emitCall(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + // We can use any scratch register we want, since we know that they have been saved + // before calling. + directCall(crb, masm, callTarget, r8, state, label); + } + } + + /** + * Tests whether linkage can be called directly under all circumstances without the need for a + * scratch register. + * + * Note this is a pessimistic assumption: This may return false despite a near call/jump being + * adequate. + * + * @param linkage Foreign call description + * @return true if foreign call can be called directly and does not need a scratch register to + * load the address into. + */ + public static boolean isNearCall(ForeignCallLinkage linkage) { + long maxOffset = linkage.getMaxCallTargetOffset(); + return maxOffset != -1 && AArch64MacroAssembler.isBranchImmediateOffset(maxOffset); + } + + public static void directCall(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info) { + directCall(crb, masm, callTarget, scratch, info, null); + } + + public static void directCall(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info, Label label) { + int before = masm.position(); + if (scratch != null) { + /* + * Offset might not fit into a 28-bit immediate, generate an indirect call with a 64-bit + * immediate address which is fixed up by HotSpot. + */ + masm.movNativeAddress(scratch, 0L); + masm.blr(scratch); + } else { + // Address is fixed up by HotSpot. + masm.bl(0); + } + if (label != null) { + // We need this label to be the return address. + masm.bind(label); + } + int after = masm.position(); + crb.recordDirectCall(before, after, callTarget, info); + crb.recordExceptionHandlers(after, info); + masm.ensureUniquePC(); + } + + public static void indirectCall(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { + int before = masm.position(); + masm.blr(dst); + int after = masm.position(); + crb.recordIndirectCall(before, after, callTarget, info); + crb.recordExceptionHandlers(after, info); + masm.ensureUniquePC(); + } + + public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget target) { + int before = masm.position(); + // Address is fixed up later by c++ code. + masm.jmp(); + int after = masm.position(); + crb.recordDirectCall(before, after, target, null); + masm.ensureUniquePC(); + } + + public static void indirectJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register dst, InvokeTarget target) { + int before = masm.position(); + masm.jmp(dst); + int after = masm.position(); + crb.recordIndirectCall(before, after, target, null); + masm.ensureUniquePC(); + } + + public static void directConditionalJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget target, AArch64Assembler.ConditionFlag cond) { + int before = masm.position(); + masm.branchConditionally(cond); + int after = masm.position(); + crb.recordDirectCall(before, after, target, null); + masm.ensureUniquePC(); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Compare.java 2016-12-07 13:54:23.190354799 -0800 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.aarch64.AArch64Kind; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.Value; + +public class AArch64Compare { + + public static class CompareOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareOp.class); + + @Use protected Value x; + @Use({REG, CONST}) protected Value y; + + public CompareOp(Value x, Value y) { + super(TYPE); + assert ((AArch64Kind) x.getPlatformKind()).isInteger() && ((AArch64Kind) y.getPlatformKind()).isInteger(); + assert x.getPlatformKind() == y.getPlatformKind(); + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + gpCompare(masm, x, y); + } + } + + /** + * Compares integer values x and y. + * + * @param x integer value to compare. May not be null. + * @param y integer value to compare. May not be null. + */ + public static void gpCompare(AArch64MacroAssembler masm, Value x, Value y) { + final int size = x.getPlatformKind().getSizeInBytes() * Byte.SIZE; + if (isRegister(y)) { + masm.cmp(size, asRegister(x), asRegister(y)); + } else { + JavaConstant constant = asJavaConstant(y); + if (constant.isDefaultForKind()) { + masm.cmp(size, asRegister(x), 0); + } else { + final long longValue = constant.asLong(); + assert NumUtil.isInt(longValue); + int maskedValue; + switch (constant.getJavaKind()) { + case Boolean: + case Byte: + maskedValue = (int) (longValue & 0xFF); + break; + case Char: + case Short: + maskedValue = (int) (longValue & 0xFFFF); + break; + case Int: + case Long: + maskedValue = (int) longValue; + break; + default: + throw GraalError.shouldNotReachHere(); + } + masm.cmp(size, asRegister(x), maskedValue); + } + } + } + + public static class FloatCompareOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(FloatCompareOp.class); + + @Use protected Value x; + @Use({REG, CONST}) protected Value y; + private final Condition condition; + private final boolean unorderedIsTrue; + + public FloatCompareOp(Value x, Value y, Condition condition, boolean unorderedIsTrue) { + super(TYPE); + assert !isJavaConstant(y) || isFloatCmpConstant(y, condition, unorderedIsTrue); + this.x = x; + this.y = y; + this.condition = condition; + this.unorderedIsTrue = unorderedIsTrue; + } + + /** + * Checks if val can be used as a constant for the gpCompare operation or not. + */ + public static boolean isFloatCmpConstant(Value val, Condition condition, boolean unorderedIsTrue) { + // If the condition is "EQ || unordered" or "NE && unordered" we have to use 2 registers + // in any case. + if (!(condition == Condition.EQ && unorderedIsTrue || condition == Condition.NE && !unorderedIsTrue)) { + return false; + } + return isJavaConstant(val) && asJavaConstant(val).isDefaultForKind(); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + assert isRegister(x); + int size = x.getPlatformKind().getSizeInBytes() * Byte.SIZE; + if (isRegister(y)) { + masm.fcmp(size, asRegister(x), asRegister(y)); + // There is no condition code for "EQ || unordered" nor one for "NE && unordered", + // so we have to fix them up ourselves. + // In both cases we combine the asked for condition into the EQ, respectively NE + // condition, i.e. + // if EQ && unoreredIsTrue, then the EQ flag will be set if the two values gpCompare + // unequal but are + // unordered. + if (condition == Condition.EQ && unorderedIsTrue) { + // if f1 ordered f2: + // result = f1 == f2 + // else: + // result = EQUAL + int nzcv = 0b0100; // EQUAL -> Z = 1 + masm.fccmp(size, asRegister(x), asRegister(y), nzcv, AArch64Assembler.ConditionFlag.VC); + } else if (condition == Condition.NE && !unorderedIsTrue) { + // if f1 ordered f2: + // result = f1 != f2 + // else: + // result = !NE == EQUAL + int nzcv = 0b0100; // EQUAL -> Z = 1 + masm.fccmp(size, asRegister(x), asRegister(y), nzcv, AArch64Assembler.ConditionFlag.VC); + } + } else { + // cmp against +0.0 + masm.fcmpZero(size, asRegister(x)); + } + } + + @Override + public void verify() { + assert x.getPlatformKind().equals(y.getPlatformKind()) : "a: " + x + " b: " + y; + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java 2016-12-07 13:54:23.456366490 -0800 @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2013, 2016, 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.lir.aarch64; + +import static jdk.vm.ci.code.ValueUtil.asAllocatableValue; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import java.util.function.Function; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.aarch64.AArch64Address; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.PatchLabelKind; +import org.graalvm.compiler.code.CompilationResult.JumpTable; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.ConstantValue; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.aarch64.AArch64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.Value; + +public class AArch64ControlFlow { + + /** + * Compares integer register to 0 and branches if condition is true. Condition may only be equal + * or non-equal. + */ + // TODO (das) where do we need this? + // public static class CompareAndBranchOp extends AArch64LIRInstruction implements + // StandardOp.BranchOp { + // private final ConditionFlag condition; + // private final LabelRef destination; + // @Use({REG}) private Value x; + // + // public CompareAndBranchOp(Condition condition, LabelRef destination, Value x) { + // assert condition == Condition.EQ || condition == Condition.NE; + // assert ARMv8.isGpKind(x.getKind()); + // this.condition = condition == Condition.EQ ? ConditionFlag.EQ : ConditionFlag.NE; + // this.destination = destination; + // this.x = x; + // } + // + // @Override + // public void emitCode(CompilationResultBuilder crb, ARMv8MacroAssembler masm) { + // int size = ARMv8.bitsize(x.getKind()); + // if (condition == ConditionFlag.EQ) { + // masm.cbz(size, asRegister(x), destination.label()); + // } else { + // masm.cbnz(size, asRegister(x), destination.label()); + // } + // } + // } + + public static class BranchOp extends AArch64BlockEndOp implements StandardOp.BranchOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BranchOp.class); + + private final AArch64Assembler.ConditionFlag condition; + private final LabelRef trueDestination; + private final LabelRef falseDestination; + + private final double trueDestinationProbability; + + public BranchOp(AArch64Assembler.ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { + super(TYPE); + this.condition = condition; + this.trueDestination = trueDestination; + this.falseDestination = falseDestination; + this.trueDestinationProbability = trueDestinationProbability; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + /* + * Explanation: Depending on what the successor edge is, we can use the fall-through to + * optimize the generated code. If neither is a successor edge, use the branch + * probability to try to take the conditional jump as often as possible to avoid + * executing two instructions instead of one. + */ + if (crb.isSuccessorEdge(trueDestination)) { + masm.branchConditionally(condition.negate(), falseDestination.label()); + } else if (crb.isSuccessorEdge(falseDestination)) { + masm.branchConditionally(condition, trueDestination.label()); + } else if (trueDestinationProbability < 0.5) { + masm.branchConditionally(condition.negate(), falseDestination.label()); + masm.jmp(trueDestination.label()); + } else { + masm.branchConditionally(condition, trueDestination.label()); + masm.jmp(falseDestination.label()); + } + } + + } + + @Opcode("CMOVE") + public static class CondMoveOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CondMoveOp.class); + + @Def protected Value result; + @Use protected Value trueValue; + @Use protected Value falseValue; + private final AArch64Assembler.ConditionFlag condition; + + public CondMoveOp(Variable result, AArch64Assembler.ConditionFlag condition, Value trueValue, Value falseValue) { + super(TYPE); + assert trueValue.getPlatformKind() == falseValue.getPlatformKind() && trueValue.getPlatformKind() == result.getPlatformKind(); + this.result = result; + this.condition = condition; + this.trueValue = trueValue; + this.falseValue = falseValue; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + AArch64Kind kind = (AArch64Kind) trueValue.getPlatformKind(); + int size = kind.getSizeInBytes() * Byte.SIZE; + if (kind.isInteger()) { + masm.cmov(size, asRegister(result), asRegister(trueValue), asRegister(falseValue), condition); + } else { + masm.fcmov(size, asRegister(result), asRegister(trueValue), asRegister(falseValue), condition); + } + } + } + + public static class StrategySwitchOp extends AArch64BlockEndOp implements StandardOp.BlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StrategySwitchOp.class); + + private final Constant[] keyConstants; + protected final SwitchStrategy strategy; + private final Function converter; + private final LabelRef[] keyTargets; + private final LabelRef defaultTarget; + @Alive protected Value key; + // TODO (das) This could be optimized: We only need the scratch register in case of a + // datapatch, or too large immediates. + @Temp protected Value scratch; + + public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, + Function converter) { + this(TYPE, strategy, keyTargets, defaultTarget, key, scratch, converter); + } + + protected StrategySwitchOp(LIRInstructionClass c, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, + Function converter) { + super(c); + this.strategy = strategy; + this.converter = converter; + this.keyConstants = strategy.getKeyConstants(); + this.keyTargets = keyTargets; + this.defaultTarget = defaultTarget; + this.key = key; + this.scratch = scratch; + assert keyConstants.length == keyTargets.length; + assert keyConstants.length == strategy.keyProbabilities.length; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + strategy.run(new SwitchClosure(asRegister(key), crb, masm)); + } + + public class SwitchClosure extends BaseSwitchClosure { + + protected final Register keyRegister; + protected final CompilationResultBuilder crb; + protected final AArch64MacroAssembler masm; + + protected SwitchClosure(Register keyRegister, CompilationResultBuilder crb, AArch64MacroAssembler masm) { + super(crb, masm, keyTargets, defaultTarget); + this.keyRegister = keyRegister; + this.crb = crb; + this.masm = masm; + } + + protected void emitComparison(Constant c) { + JavaConstant jc = (JavaConstant) c; + ConstantValue constVal = new ConstantValue(LIRKind.value(key.getPlatformKind()), c); + switch (jc.getJavaKind()) { + case Int: + long lc = jc.asLong(); + assert NumUtil.isInt(lc); + emitCompare(crb, masm, key, scratch, constVal); + break; + case Long: + emitCompare(crb, masm, key, scratch, constVal); + break; + case Object: + emitCompare(crb, masm, key, scratch, constVal); + break; + default: + throw new GraalError("switch only supported for int, long and object"); + } + } + + @Override + protected void conditionalJump(int index, Condition condition, Label target) { + emitComparison(keyConstants[index]); + masm.branchConditionally(converter.apply(condition), target); + } + } + } + + public static class TableSwitchOp extends AArch64BlockEndOp implements StandardOp.BlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(TableSwitchOp.class); + + private final int lowKey; + private final LabelRef defaultTarget; + private final LabelRef[] targets; + @Alive protected Variable keyValue; + @Temp protected Variable scratchValue; + + public TableSwitchOp(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Variable key, Variable scratch) { + super(TYPE); + this.lowKey = lowKey; + this.defaultTarget = defaultTarget; + this.targets = targets; + this.keyValue = key; + this.scratchValue = scratch; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register key = asRegister(keyValue); + Register scratch = asRegister(scratchValue); + if (lowKey != 0) { + if (AArch64MacroAssembler.isArithmeticImmediate(lowKey)) { + masm.sub(32, key, key, lowKey); + } else { + ConstantValue constVal = new ConstantValue(LIRKind.value(AArch64Kind.WORD), JavaConstant.forInt(lowKey)); + AArch64Move.move(crb, masm, scratchValue, constVal); + masm.sub(32, key, key, scratch); + } + } + if (defaultTarget != null) { + // if key is not in table range, jump to default target if it exists. + ConstantValue constVal = new ConstantValue(LIRKind.value(AArch64Kind.WORD), JavaConstant.forInt(targets.length)); + emitCompare(crb, masm, keyValue, scratchValue, constVal); + masm.branchConditionally(AArch64Assembler.ConditionFlag.HS, defaultTarget.label()); + } + + // Load the start address of the jump table - which starts 3 instructions after the adr + // - into scratch. + masm.adr(scratch, 4 * 3); + masm.ldr(32, scratch, AArch64Address.createRegisterOffsetAddress(scratch, key, /* scaled */true)); + masm.jmp(scratch); + int jumpTablePos = masm.position(); + // emit jump table entries + for (LabelRef target : targets) { + Label label = target.label(); + if (label.isBound()) { + masm.emitInt(target.label().position()); + } else { + label.addPatchAt(masm.position()); + masm.emitInt(PatchLabelKind.JUMP_ADDRESS.encoding); + } + } + JumpTable jt = new JumpTable(jumpTablePos, lowKey, lowKey + targets.length - 1, 4); + crb.compilationResult.addAnnotation(jt); + } + } + + private static void emitCompare(CompilationResultBuilder crb, AArch64MacroAssembler masm, Value key, Value scratchValue, ConstantValue c) { + long imm = c.getJavaConstant().asLong(); + final int size = key.getPlatformKind().getSizeInBytes() * Byte.SIZE; + if (AArch64MacroAssembler.isComparisonImmediate(imm)) { + masm.cmp(size, asRegister(key), (int) imm); + } else { + AArch64Move.move(crb, masm, asAllocatableValue(scratchValue), c); + masm.cmp(size, asRegister(key), asRegister(scratchValue)); + } + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64FrameMap.java 2016-12-07 13:54:23.722378180 -0800 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.aarch64; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.framemap.FrameMap; + +import jdk.vm.ci.aarch64.AArch64Kind; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.StackSlot; + +/** + * AArch64 specific frame map. + *

    + * This is the format of an AArch64 stack frame: + *

    + * + *

    + *   Base       Contents
    + *
    + *            :                                :  -----
    + *   caller   | incoming overflow argument n   |    ^
    + *   frame    :     ...                        :    | positive
    + *            | incoming overflow argument 0   |    | offsets
    + *   ---------+--------------------------------+-------------------------
    + *            | return address                 |    |            ^
    + *            | prev. frame pointer            |    |            |
    + *            +--------------------------------+    |            |
    + *            | spill slot 0                   |    | negative   |      ^
    + *    callee  :     ...                        :    v offsets    |      |
    + *    frame   | spill slot n                   |  -----        total  frame
    + *            +--------------------------------+               frame  size
    + *            | alignment padding              |               size     |
    + *            +--------------------------------+  -----          |      |
    + *            | outgoing overflow argument n   |    ^            |      |
    + *            :     ...                        :    | positive   |      |
    + *            | outgoing overflow argument 0   |    | offsets    v      v
    + *    %sp-->  +--------------------------------+---------------------------
    + *
    + * 
    + * + * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size of such + * a block may be greater than the size of a normal spill slot or the word size. + *

    + * A runtime can reserve space at the beginning of the overflow argument area. The calling + * convention can specify that the first overflow stack argument is not at offset 0, but at a + * specified offset. Use {@link CodeCacheProvider#getMinimumOutgoingSize()} to make sure that + * call-free methods also have this space reserved. Then the VM can use the memory at offset 0 + * relative to the stack pointer. + *

    + */ +public class AArch64FrameMap extends FrameMap { + // Note: Spill size includes callee save area + + /** + * Creates a new frame map for the specified method. + */ + public AArch64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) { + super(codeCache, registerConfig, referenceMapFactory); + initialSpillSize = frameSetupSize(); + spillSize = initialSpillSize; + } + + @Override + public int totalFrameSize() { + // frameSize + return address + frame pointer + return frameSize() + frameSetupSize(); + } + + private int frameSetupSize() { + // Size of return address and frame pointer that are saved in function prologue + return getTarget().arch.getWordSize() * 2; + } + + @Override + public int currentFrameSize() { + return alignFrameSize(outgoingSize + spillSize); + } + + public StackSlot allocateDeoptimizationRescueSlot() { + assert spillSize == initialSpillSize : "Deoptimization rescue slot must be the first stack slot"; + return allocateSpillSlot(LIRKind.value(AArch64Kind.QWORD)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64FrameMapBuilder.java 2016-12-07 13:54:23.986389783 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 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.lir.aarch64; + +import org.graalvm.compiler.lir.framemap.FrameMap; +import org.graalvm.compiler.lir.framemap.FrameMapBuilderImpl; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.StackSlot; + +public class AArch64FrameMapBuilder extends FrameMapBuilderImpl { + + public AArch64FrameMapBuilder(FrameMap frameMap, CodeCacheProvider codeCache, RegisterConfig registerConfig) { + super(frameMap, codeCache, registerConfig); + } + + public StackSlot allocateDeoptimizationRescueSlot() { + return ((AArch64FrameMap) getFrameMap()).allocateDeoptimizationRescueSlot(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64LIRInstruction.java 2016-12-07 13:54:24.254401562 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013, 2016, 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.lir.aarch64; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +public abstract class AArch64LIRInstruction extends LIRInstruction { + protected AArch64LIRInstruction(LIRInstructionClass c) { + super(c); + } + + @Override + public final void emitCode(CompilationResultBuilder crb) { + emitCode(crb, (AArch64MacroAssembler) crb.asm); + } + + protected abstract void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java 2016-12-07 13:54:24.520413253 -0800 @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2013, 2016, 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.lir.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED; +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static jdk.vm.ci.aarch64.AArch64.sp; +import static jdk.vm.ci.aarch64.AArch64.zr; +import static jdk.vm.ci.code.ValueUtil.asAllocatableValue; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.asStackSlot; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import org.graalvm.compiler.asm.Label; +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.ScratchRegister; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.type.DataPointerConstant; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp; +import org.graalvm.compiler.lir.StandardOp.LoadConstantOp; +import org.graalvm.compiler.lir.StandardOp.NullCheck; +import org.graalvm.compiler.lir.StandardOp.ValueMoveOp; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.aarch64.AArch64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +public class AArch64Move { + + public static class LoadInlineConstant extends AArch64LIRInstruction implements LoadConstantOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadInlineConstant.class); + + private JavaConstant constant; + @Def({REG, STACK}) AllocatableValue result; + + public LoadInlineConstant(JavaConstant constant, AllocatableValue result) { + super(TYPE); + this.constant = constant; + this.result = result; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + if (isRegister(result)) { + const2reg(crb, masm, result, constant); + } else if (isStackSlot(result)) { + StackSlot slot = asStackSlot(result); + const2stack(crb, masm, slot, constant); + } + } + + @Override + public Constant getConstant() { + return constant; + } + + @Override + public AllocatableValue getResult() { + return result; + } + } + + @Opcode("MOVE") + public static class Move extends AArch64LIRInstruction implements ValueMoveOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(Move.class); + + @Def({REG, STACK, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue input; + + public Move(AllocatableValue result, AllocatableValue input) { + super(TYPE); + this.result = result; + this.input = input; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + move(crb, masm, getResult(), getInput()); + } + + @Override + public AllocatableValue getInput() { + return input; + } + + @Override + public AllocatableValue getResult() { + return result; + } + } + + public static class LoadAddressOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadAddressOp.class); + + @Def protected AllocatableValue result; + @Use(COMPOSITE) protected AArch64AddressValue address; + + public LoadAddressOp(AllocatableValue result, AArch64AddressValue address) { + super(TYPE); + this.result = result; + this.address = address; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register dst = asRegister(result); + AArch64Address adr = address.toAddress(); + masm.loadAddress(dst, adr, address.getPlatformKind().getSizeInBytes()); + } + } + + public static class LoadDataOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadDataOp.class); + + @Def protected AllocatableValue result; + private final DataPointerConstant data; + + public LoadDataOp(AllocatableValue result, DataPointerConstant data) { + super(TYPE); + this.result = result; + this.data = data; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register dst = asRegister(result); + masm.loadAddress(dst, (AArch64Address) crb.recordDataReferenceInCode(data), data.getAlignment()); + } + } + + public static class StackLoadAddressOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StackLoadAddressOp.class); + + @Def protected AllocatableValue result; + @Use({STACK, UNINITIALIZED}) protected AllocatableValue slot; + + public StackLoadAddressOp(AllocatableValue result, AllocatableValue slot) { + super(TYPE); + assert slot instanceof VirtualStackSlot || slot instanceof StackSlot; + this.result = result; + this.slot = slot; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + AArch64Address address = (AArch64Address) crb.asAddress(slot); + PlatformKind kind = AArch64Kind.QWORD; + masm.loadAddress(asRegister(result, kind), address, kind.getSizeInBytes()); + } + } + + public static class MembarOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MembarOp.class); + + @SuppressWarnings("unused") private final int barriers; + + public MembarOp(int barriers) { + super(TYPE); + this.barriers = barriers; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + // As I understand it load acquire/store release have the same semantics as on IA64 + // and allow us to handle LoadStore, LoadLoad and StoreStore without an explicit + // barrier. + // But Graal support to figure out if a load/store is volatile is non-existant so for + // now + // just use + // memory barriers everywhere. + // if ((barrier & MemoryBarriers.STORE_LOAD) != 0) { + masm.dmb(AArch64MacroAssembler.BarrierKind.ANY_ANY); + // } + } + } + + abstract static class MemOp extends AArch64LIRInstruction implements StandardOp.ImplicitNullCheck { + + protected final AArch64Kind kind; + @Use({COMPOSITE}) protected AArch64AddressValue addressValue; + @State protected LIRFrameState state; + + MemOp(LIRInstructionClass c, AArch64Kind kind, AArch64AddressValue address, LIRFrameState state) { + super(c); + this.kind = kind; + this.addressValue = address; + this.state = state; + } + + protected abstract void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm); + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + emitMemAccess(crb, masm); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + int immediate = addressValue.getImmediate(); + if (state == null && value.equals(addressValue.getBase()) && addressValue.getOffset().equals(Value.ILLEGAL) && immediate >= 0 && immediate < implicitNullCheckLimit) { + state = nullCheckState; + return true; + } + return false; + } + } + + public static final class LoadOp extends MemOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadOp.class); + + @Def protected AllocatableValue result; + + public LoadOp(AArch64Kind kind, AllocatableValue result, AArch64AddressValue address, LIRFrameState state) { + super(TYPE, kind, address, state); + this.result = result; + } + + @Override + protected void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + AArch64Address address = addressValue.toAddress(); + Register dst = asRegister(result); + + int destSize = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; + int srcSize = kind.getSizeInBytes() * Byte.SIZE; + if (kind.isInteger()) { + // TODO How to load unsigned chars without the necessary information? + masm.ldrs(destSize, srcSize, dst, address); + } else { + assert srcSize == destSize; + masm.fldr(srcSize, dst, address); + } + } + } + + public static class StoreOp extends MemOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StoreOp.class); + @Use protected AllocatableValue input; + + public StoreOp(AArch64Kind kind, AArch64AddressValue address, AllocatableValue input, LIRFrameState state) { + super(TYPE, kind, address, state); + this.input = input; + } + + @Override + protected void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + emitStore(crb, masm, kind, addressValue.toAddress(), input); + } + } + + public static final class StoreConstantOp extends MemOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StoreConstantOp.class); + + protected final JavaConstant input; + + public StoreConstantOp(AArch64Kind kind, AArch64AddressValue address, JavaConstant input, LIRFrameState state) { + super(TYPE, kind, address, state); + this.input = input; + if (!input.isDefaultForKind()) { + throw GraalError.shouldNotReachHere("Can only store null constants to memory"); + } + } + + @Override + public void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + emitStore(crb, masm, kind, addressValue.toAddress(), zr.asValue(LIRKind.combine(addressValue))); + } + } + + public static final class NullCheckOp extends AArch64LIRInstruction implements NullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(NullCheckOp.class); + + @Use(COMPOSITE) protected AArch64AddressValue address; + @State protected LIRFrameState state; + + public NullCheckOp(AArch64AddressValue address, LIRFrameState state) { + super(TYPE); + this.address = address; + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + crb.recordImplicitException(masm.position(), state); + masm.ldr(64, zr, address.toAddress()); + } + + @Override + public Value getCheckedValue() { + return address.base; + } + + @Override + public LIRFrameState getState() { + return state; + } + } + + /** + * Compare and swap instruction. Does the following atomically: + * CAS(newVal, expected, address): + * oldVal = *address + * if oldVal == expected: + * *address = newVal + * return oldVal + * + */ + @Opcode("CAS") + public static class CompareAndSwapOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareAndSwapOp.class); + + @Def protected AllocatableValue resultValue; + @Alive protected Value expectedValue; + @Alive protected AllocatableValue newValue; + @Alive protected AllocatableValue addressValue; + @Temp protected AllocatableValue scratchValue; + + public CompareAndSwapOp(AllocatableValue result, Value expectedValue, AllocatableValue newValue, AllocatableValue addressValue, AllocatableValue scratch) { + super(TYPE); + this.resultValue = result; + this.expectedValue = expectedValue; + this.newValue = newValue; + this.addressValue = addressValue; + this.scratchValue = scratch; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + AArch64Kind kind = (AArch64Kind) expectedValue.getPlatformKind(); + assert kind.isInteger(); + final int size = kind.getSizeInBytes() * Byte.SIZE; + + Register address = asRegister(addressValue); + Register result = asRegister(resultValue); + Register newVal = asRegister(newValue); + Register scratch = asRegister(scratchValue); + // We could avoid using a scratch register here, by reusing resultValue for the stlxr + // success flag and issue a mov resultValue, expectedValue in case of success before + // returning. + Label retry = new Label(); + Label fail = new Label(); + masm.bind(retry); + masm.ldaxr(size, result, address); + AArch64Compare.gpCompare(masm, resultValue, expectedValue); + masm.branchConditionally(AArch64Assembler.ConditionFlag.NE, fail); + masm.stlxr(size, scratch, newVal, address); + // if scratch == 0 then write successful, else retry. + masm.cbnz(32, scratch, retry); + masm.bind(fail); + } + } + + private static void emitStore(@SuppressWarnings("unused") CompilationResultBuilder crb, AArch64MacroAssembler masm, AArch64Kind kind, AArch64Address dst, Value src) { + int destSize = kind.getSizeInBytes() * Byte.SIZE; + if (kind.isInteger()) { + masm.str(destSize, asRegister(src), dst); + } else { + masm.fstr(destSize, asRegister(src), dst); + } + } + + public static void move(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, Value input) { + if (isRegister(input)) { + if (isRegister(result)) { + reg2reg(crb, masm, result, asAllocatableValue(input)); + } else if (isStackSlot(result)) { + reg2stack(crb, masm, result, asAllocatableValue(input)); + } else { + throw GraalError.shouldNotReachHere(); + } + } else if (isStackSlot(input)) { + if (isRegister(result)) { + stack2reg(crb, masm, result, asAllocatableValue(input)); + } else { + throw GraalError.shouldNotReachHere(); + } + } else if (isJavaConstant(input)) { + if (isRegister(result)) { + const2reg(crb, masm, result, asJavaConstant(input)); + } else { + throw GraalError.shouldNotReachHere(); + } + } else { + throw GraalError.shouldNotReachHere(); + } + } + + private static void reg2reg(@SuppressWarnings("unused") CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) { + Register dst = asRegister(result); + Register src = asRegister(input); + if (src.equals(dst)) { + return; + } + AArch64Kind kind = (AArch64Kind) input.getPlatformKind(); + int size = kind.getSizeInBytes() * Byte.SIZE; + if (kind.isInteger()) { + masm.mov(size, dst, src); + } else { + masm.fmov(size, dst, src); + } + } + + private static void reg2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) { + AArch64Address dest = loadStackSlotAddress(crb, masm, asStackSlot(result), Value.ILLEGAL); + Register src = asRegister(input); + AArch64Kind kind = (AArch64Kind) input.getPlatformKind(); + int size = kind.getSizeInBytes() * Byte.SIZE; + if (kind.isInteger()) { + masm.str(size, src, dest); + } else { + masm.fstr(size, src, dest); + } + } + + private static void stack2reg(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) { + AArch64Kind kind = (AArch64Kind) input.getPlatformKind(); + final int size = kind.getSizeInBytes() * Byte.SIZE; + if (kind.isInteger()) { + AArch64Address src = loadStackSlotAddress(crb, masm, asStackSlot(input), result); + masm.ldr(size, asRegister(result), src); + } else { + try (ScratchRegister sc = masm.getScratchRegister()) { + AllocatableValue scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(input)); + AArch64Address src = loadStackSlotAddress(crb, masm, asStackSlot(input), scratchRegisterValue); + masm.fldr(size, asRegister(result), src); + } + } + } + + private static void const2reg(CompilationResultBuilder crb, AArch64MacroAssembler masm, Value result, JavaConstant input) { + Register dst = asRegister(result); + switch (input.getJavaKind().getStackKind()) { + case Int: + final int value = input.asInt(); + int maskedValue; + switch (input.getJavaKind()) { + case Boolean: + case Byte: + maskedValue = value & 0xFF; + break; + case Char: + case Short: + maskedValue = value & 0xFFFF; + break; + case Int: + maskedValue = value; + break; + default: + throw GraalError.shouldNotReachHere(); + } + masm.mov(dst, maskedValue); + break; + case Long: + masm.mov(dst, input.asLong()); + break; + case Float: + if (AArch64MacroAssembler.isFloatImmediate(input.asFloat())) { + masm.fmov(32, dst, input.asFloat()); + } else { + masm.fldr(32, dst, (AArch64Address) crb.asFloatConstRef(input)); + } + break; + case Double: + if (AArch64MacroAssembler.isDoubleImmediate(input.asDouble())) { + masm.fmov(64, dst, input.asDouble()); + } else { + masm.fldr(64, dst, (AArch64Address) crb.asDoubleConstRef(input)); + } + break; + case Object: + if (input.isNull()) { + masm.mov(dst, 0); + } else if (crb.target.inlineObjects) { + crb.recordInlineDataInCode(input); + masm.movNativeAddress(dst, 0xDEADDEADDEADDEADL); + } else { + masm.ldr(64, dst, (AArch64Address) crb.recordDataReferenceInCode(input, 8)); + } + break; + default: + throw GraalError.shouldNotReachHere("kind=" + input.getJavaKind().getStackKind()); + } + } + + private static void const2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm, Value result, JavaConstant constant) { + if (constant.isDefaultForKind() || constant.isNull()) { + AArch64Address resultAddress = (AArch64Address) crb.asAddress(result); + emitStore(crb, masm, (AArch64Kind) result.getPlatformKind(), resultAddress, zr.asValue(LIRKind.combine(result))); + } else { + try (ScratchRegister sc = masm.getScratchRegister()) { + Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(result)); + const2reg(crb, masm, scratchRegisterValue, constant); + AArch64Address resultAddress = (AArch64Address) crb.asAddress(result); + emitStore(crb, masm, (AArch64Kind) result.getPlatformKind(), resultAddress, scratchRegisterValue); + } + } + } + + /** + * Returns AArch64Address of given StackSlot. We cannot use CompilationResultBuilder.asAddress + * since this calls AArch64MacroAssembler.makeAddress with displacements that may be larger than + * 9-bit signed, which cannot be handled by that method. + * + * Instead we create an address ourselves. We use scaled unsigned addressing since we know the + * transfersize, which gives us a 15-bit address range (for longs/doubles) respectively a 14-bit + * range (for everything else). + * + * @param scratch Scratch register that can be used to load address. If Value.ILLEGAL this + * instruction fails if we try to access a StackSlot that is too large to be loaded + * directly. + * @return AArch64Address of given StackSlot. Uses scratch register if necessary to do so. + */ + private static AArch64Address loadStackSlotAddress(CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot slot, AllocatableValue scratch) { + int displacement = crb.frameMap.offsetForStackSlot(slot); + int transferSize = slot.getPlatformKind().getSizeInBytes(); + Register scratchReg = Value.ILLEGAL.equals(scratch) ? zr : asRegister(scratch); + return masm.makeAddress(sp, displacement, scratchReg, transferSize, /* allowOverwrite */false); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64PauseOp.java 2016-12-07 13:54:24.785424900 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 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.lir.aarch64; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +/** + * Emits a pause. + */ +@Opcode("PAUSE") +public final class AArch64PauseOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64PauseOp.class); + + public AArch64PauseOp() { + super(TYPE); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + masm.pause(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64PrefetchOp.java 2016-12-07 13:54:25.049436503 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, 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.lir.aarch64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +public final class AArch64PrefetchOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64PrefetchOp.class); + + @SuppressWarnings("unused") private final int instr; // AllocatePrefetchInstr + @Alive({COMPOSITE}) protected AArch64AddressValue address; + + public AArch64PrefetchOp(AArch64AddressValue address, int instr) { + super(TYPE); + this.address = address; + this.instr = instr; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + // TODO implement prefetch + masm.nop(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ReinterpretOp.java 2016-12-07 13:54:25.315448193 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.aarch64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.aarch64.AArch64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Instruction that reinterprets some bit pattern as a different type. It is possible to reinterpret + * the following: - int <-> float - long <-> double + */ +public class AArch64ReinterpretOp extends AArch64LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64ReinterpretOp.class); + + @Def protected AllocatableValue resultValue; + @Use protected AllocatableValue inputValue; + + public AArch64ReinterpretOp(AllocatableValue resultValue, AllocatableValue inputValue) { + super(TYPE); + AArch64Kind from = (AArch64Kind) inputValue.getPlatformKind(); + AArch64Kind to = (AArch64Kind) resultValue.getPlatformKind(); + assert from.getSizeInBytes() == to.getSizeInBytes() && from.isInteger() ^ to.isInteger(); + this.resultValue = resultValue; + this.inputValue = inputValue; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register result = asRegister(resultValue); + Register input = asRegister(inputValue); + AArch64Kind to = (AArch64Kind) resultValue.getPlatformKind(); + final int size = to.getSizeInBytes() * Byte.SIZE; + masm.fmov(size, result, input); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SignExtendOp.java 2016-12-07 13:54:25.580459840 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 2016, 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.lir.aarch64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; + +@Opcode("SIGNEXTEND") +public class AArch64SignExtendOp extends AArch64LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64SignExtendOp.class); + + @Def protected AllocatableValue resultValue; + @Use protected AllocatableValue inputValue; + private final int fromBits; + private final int toBits; + + public AArch64SignExtendOp(AllocatableValue resultValue, AllocatableValue inputValue, int fromBits, int toBits) { + super(TYPE); + this.resultValue = resultValue; + this.inputValue = inputValue; + this.fromBits = fromBits; + this.toBits = toBits; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Register result = asRegister(resultValue); + Register input = asRegister(inputValue); + masm.sxt(toBits, fromBits, result, input); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/overview.html 2016-12-07 13:54:25.843471399 -0800 @@ -0,0 +1,36 @@ + + + + + + + + +Documentation for the org.graalvm.compiler.lir.amd64 project. + + + --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64AddressValue.java 2016-12-07 13:54:26.106482958 -0800 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.isLegal; + +import java.util.EnumSet; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; +import org.graalvm.compiler.lir.CompositeValue; +import org.graalvm.compiler.lir.InstructionValueConsumer; +import org.graalvm.compiler.lir.InstructionValueProcedure; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; +import org.graalvm.compiler.lir.LIRInstruction.OperandMode; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; + +public final class AMD64AddressValue extends CompositeValue { + + @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base; + @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index; + protected final Scale scale; + protected final int displacement; + + private static final EnumSet flags = EnumSet.of(OperandFlag.REG, OperandFlag.ILLEGAL); + + public AMD64AddressValue(ValueKind kind, AllocatableValue base, int displacement) { + this(kind, base, Value.ILLEGAL, Scale.Times1, displacement); + } + + public AMD64AddressValue(ValueKind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) { + super(kind); + this.base = base; + this.index = index; + this.scale = scale; + this.displacement = displacement; + + assert scale != null; + } + + @Override + public CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) { + AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags); + AllocatableValue newIndex = (AllocatableValue) proc.doValue(inst, index, mode, flags); + if (!base.identityEquals(newBase) || !index.identityEquals(newIndex)) { + return new AMD64AddressValue(getValueKind(), newBase, newIndex, scale, displacement); + } + return this; + } + + @Override + protected void visitEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc) { + proc.visitValue(inst, base, mode, flags); + proc.visitValue(inst, index, mode, flags); + } + + private static Register toRegister(AllocatableValue value) { + if (value.equals(Value.ILLEGAL)) { + return Register.None; + } else { + RegisterValue reg = (RegisterValue) value; + return reg.getRegister(); + } + } + + public AMD64Address toAddress() { + return new AMD64Address(toRegister(base), toRegister(index), scale, displacement); + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder("["); + String sep = ""; + if (isLegal(base)) { + s.append(base); + sep = " + "; + } + if (isLegal(index)) { + s.append(sep).append(index).append(" * ").append(scale.value); + sep = " + "; + } + if (displacement < 0) { + s.append(" - ").append(-displacement); + } else if (displacement > 0) { + s.append(sep).append(displacement); + } + s.append("]"); + return s.toString(); + } + + public boolean isValidImplicitNullCheckFor(Value value, int implicitNullCheckLimit) { + return value.equals(base) && index.equals(Value.ILLEGAL) && displacement >= 0 && displacement < implicitNullCheckLimit; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof AMD64AddressValue) { + AMD64AddressValue addr = (AMD64AddressValue) obj; + return getValueKind().equals(addr.getValueKind()) && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index); + } + return false; + } + + @Override + public int hashCode() { + return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ getValueKind().hashCode(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Arithmetic.java 2016-12-07 13:54:26.370494561 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2011, 2015, 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.lir.amd64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.meta.AllocatableValue; + +public enum AMD64Arithmetic { + FREM, + DREM; + + public static class FPDivRemOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(FPDivRemOp.class); + + @Opcode private final AMD64Arithmetic opcode; + @Def protected AllocatableValue result; + @Use protected AllocatableValue x; + @Use protected AllocatableValue y; + @Temp protected AllocatableValue raxTemp; + + public FPDivRemOp(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.result = result; + this.raxTemp = AMD64.rax.asValue(LIRKind.value(AMD64Kind.DWORD)); + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Address tmp = new AMD64Address(AMD64.rsp); + masm.subq(AMD64.rsp, 8); + if (opcode == FREM) { + masm.movflt(tmp, asRegister(y)); + masm.flds(tmp); + masm.movflt(tmp, asRegister(x)); + masm.flds(tmp); + } else { + assert opcode == DREM; + masm.movdbl(tmp, asRegister(y)); + masm.fldd(tmp); + masm.movdbl(tmp, asRegister(x)); + masm.fldd(tmp); + } + + Label label = new Label(); + masm.bind(label); + masm.fprem(); + masm.fwait(); + masm.fnstswAX(); + masm.testl(AMD64.rax, 0x400); + masm.jcc(ConditionFlag.NotZero, label); + masm.fxch(1); + masm.fpop(); + + if (opcode == FREM) { + masm.fstps(tmp); + masm.movflt(asRegister(result), tmp); + } else { + masm.fstpd(tmp); + masm.movdbl(asRegister(result), tmp); + } + masm.addq(AMD64.rsp, 8); + } + + @Override + public void verify() { + super.verify(); + assert (opcode.name().startsWith("F") && result.getPlatformKind() == AMD64Kind.SINGLE && x.getPlatformKind() == AMD64Kind.SINGLE && y.getPlatformKind() == AMD64Kind.SINGLE) || + (opcode.name().startsWith("D") && result.getPlatformKind() == AMD64Kind.DOUBLE && x.getPlatformKind() == AMD64Kind.DOUBLE && y.getPlatformKind() == AMD64Kind.DOUBLE); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArithmeticLIRGeneratorTool.java 2016-12-07 13:54:26.634506164 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013, 2016, 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.lir.amd64; + +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.meta.Value; + +/** + * This interface can be used to generate AMD64 LIR for arithmetic operations. + */ +public interface AMD64ArithmeticLIRGeneratorTool extends ArithmeticLIRGeneratorTool { + + Value emitCountLeadingZeros(Value value); + + Value emitCountTrailingZeros(Value value); + + enum RoundingMode { + NEAREST(0), + DOWN(1), + UP(2), + TRUNCATE(3); + + public final int encoding; + + RoundingMode(int encoding) { + this.encoding = encoding; + } + } + + Value emitRound(Value value, RoundingMode mode); + + void emitCompareOp(AMD64Kind cmpKind, Variable left, Value right); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java 2016-12-07 13:54:26.903517987 -0800 @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; +import sun.misc.Unsafe; + +/** + * Emits code which compares two arrays of the same length. If the CPU supports any vector + * instructions specialized code is emitted to leverage these instructions. + */ +@Opcode("ARRAY_EQUALS") +public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ArrayEqualsOp.class); + + private final JavaKind kind; + private final int arrayBaseOffset; + private final int arrayIndexScale; + + @Def({REG}) protected Value resultValue; + @Alive({REG}) protected Value array1Value; + @Alive({REG}) protected Value array2Value; + @Alive({REG}) protected Value lengthValue; + @Temp({REG}) protected Value temp1; + @Temp({REG}) protected Value temp2; + @Temp({REG}) protected Value temp3; + @Temp({REG}) protected Value temp4; + @Temp({REG, ILLEGAL}) protected Value vectorTemp1; + @Temp({REG, ILLEGAL}) protected Value vectorTemp2; + + public AMD64ArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, Value result, Value array1, Value array2, Value length) { + super(TYPE); + this.kind = kind; + + Class arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass(); + this.arrayBaseOffset = UNSAFE.arrayBaseOffset(arrayClass); + this.arrayIndexScale = UNSAFE.arrayIndexScale(arrayClass); + + this.resultValue = result; + this.array1Value = array1; + this.array2Value = array2; + this.lengthValue = length; + + // Allocate some temporaries. + this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + this.temp3 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); + this.temp4 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); + + // We only need the vector temporaries if we generate SSE code. + if (supportsSSE41(tool.target())) { + this.vectorTemp1 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.vectorTemp2 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + } else { + this.vectorTemp1 = Value.ILLEGAL; + this.vectorTemp2 = Value.ILLEGAL; + } + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Register result = asRegister(resultValue); + Register array1 = asRegister(temp1); + Register array2 = asRegister(temp2); + Register length = asRegister(temp3); + + Label trueLabel = new Label(); + Label falseLabel = new Label(); + Label done = new Label(); + + // Load array base addresses. + masm.leaq(array1, new AMD64Address(asRegister(array1Value), arrayBaseOffset)); + masm.leaq(array2, new AMD64Address(asRegister(array2Value), arrayBaseOffset)); + + // Get array length in bytes. + masm.imull(length, asRegister(lengthValue), arrayIndexScale); + masm.movl(result, length); // copy + + if (supportsAVX2(crb.target)) { + emitAVXCompare(crb, masm, result, array1, array2, length, trueLabel, falseLabel); + } else if (supportsSSE41(crb.target)) { + emitSSE41Compare(crb, masm, result, array1, array2, length, trueLabel, falseLabel); + } + + emit8ByteCompare(crb, masm, result, array1, array2, length, trueLabel, falseLabel); + emitTailCompares(masm, result, array1, array2, length, trueLabel, falseLabel); + + // Return true + masm.bind(trueLabel); + masm.movl(result, 1); + masm.jmpb(done); + + // Return false + masm.bind(falseLabel); + masm.xorl(result, result); + + // That's it + masm.bind(done); + } + + /** + * Returns if the underlying AMD64 architecture supports SSE 4.1 instructions. + * + * @param target target description of the underlying architecture + * @return true if the underlying architecture supports SSE 4.1 + */ + private static boolean supportsSSE41(TargetDescription target) { + AMD64 arch = (AMD64) target.arch; + return arch.getFeatures().contains(CPUFeature.SSE4_1); + } + + /** + * Vector size used in {@link #emitSSE41Compare}. + */ + private static final int SSE4_1_VECTOR_SIZE = 16; + + /** + * Emits code that uses SSE4.1 128-bit (16-byte) vector compares. + */ + private void emitSSE41Compare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + assert supportsSSE41(crb.target); + + Register vector1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE); + Register vector2 = asRegister(vectorTemp2, AMD64Kind.DOUBLE); + + Label loop = new Label(); + Label compareTail = new Label(); + + // Compare 16-byte vectors + masm.andl(result, SSE4_1_VECTOR_SIZE - 1); // tail count (in bytes) + masm.andl(length, ~(SSE4_1_VECTOR_SIZE - 1)); // vector count (in bytes) + masm.jccb(ConditionFlag.Zero, compareTail); + + masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.negq(length); + + // Align the main loop + masm.align(crb.target.wordSize * 2); + masm.bind(loop); + masm.movdqu(vector1, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.movdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.pxor(vector1, vector2); + masm.ptest(vector1, vector1); + masm.jcc(ConditionFlag.NotZero, falseLabel); + masm.addq(length, SSE4_1_VECTOR_SIZE); + masm.jcc(ConditionFlag.NotZero, loop); + + masm.testl(result, result); + masm.jcc(ConditionFlag.Zero, trueLabel); + + /* + * Compare the remaining bytes with an unaligned memory load aligned to the end of the + * array. + */ + masm.movdqu(vector1, new AMD64Address(array1, result, Scale.Times1, -SSE4_1_VECTOR_SIZE)); + masm.movdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -SSE4_1_VECTOR_SIZE)); + masm.pxor(vector1, vector2); + masm.ptest(vector1, vector1); + masm.jcc(ConditionFlag.NotZero, falseLabel); + masm.jmp(trueLabel); + + masm.bind(compareTail); + masm.movl(length, result); + } + + /** + * Returns if the underlying AMD64 architecture supports AVX instructions. + * + * @param target target description of the underlying architecture + * @return true if the underlying architecture supports AVX + */ + private static boolean supportsAVX2(TargetDescription target) { + AMD64 arch = (AMD64) target.arch; + return arch.getFeatures().contains(CPUFeature.AVX2); + } + + /** + * Vector size used in {@link #emitAVXCompare}. + */ + private static final int AVX_VECTOR_SIZE = 32; + + private void emitAVXCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + assert supportsAVX2(crb.target); + + Register vector1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE); + Register vector2 = asRegister(vectorTemp2, AMD64Kind.DOUBLE); + + Label loop = new Label(); + Label compareTail = new Label(); + + // Compare 16-byte vectors + masm.andl(result, AVX_VECTOR_SIZE - 1); // tail count (in bytes) + masm.andl(length, ~(AVX_VECTOR_SIZE - 1)); // vector count (in bytes) + masm.jccb(ConditionFlag.Zero, compareTail); + + masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.negq(length); + + // Align the main loop + masm.align(crb.target.wordSize * 2); + masm.bind(loop); + masm.vmovdqu(vector1, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.vmovdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.vpxor(vector1, vector1, vector2); + masm.vptest(vector1, vector1); + masm.jcc(ConditionFlag.NotZero, falseLabel); + masm.addq(length, AVX_VECTOR_SIZE); + masm.jcc(ConditionFlag.NotZero, loop); + + masm.testl(result, result); + masm.jcc(ConditionFlag.Zero, trueLabel); + + /* + * Compare the remaining bytes with an unaligned memory load aligned to the end of the + * array. + */ + masm.vmovdqu(vector1, new AMD64Address(array1, result, Scale.Times1, -AVX_VECTOR_SIZE)); + masm.vmovdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -AVX_VECTOR_SIZE)); + masm.vpxor(vector1, vector1, vector2); + masm.vptest(vector1, vector1); + masm.jcc(ConditionFlag.NotZero, falseLabel); + masm.jmp(trueLabel); + + masm.bind(compareTail); + masm.movl(length, result); + } + + /** + * Vector size used in {@link #emit8ByteCompare}. + */ + private static final int VECTOR_SIZE = 8; + + /** + * Emits code that uses 8-byte vector compares. + */ + private void emit8ByteCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + Label loop = new Label(); + Label compareTail = new Label(); + + Register temp = asRegister(temp4); + + masm.andl(result, VECTOR_SIZE - 1); // tail count (in bytes) + masm.andl(length, ~(VECTOR_SIZE - 1)); // vector count (in bytes) + masm.jccb(ConditionFlag.Zero, compareTail); + + masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.negq(length); + + // Align the main loop + masm.align(crb.target.wordSize * 2); + masm.bind(loop); + masm.movq(temp, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.cmpq(temp, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + masm.addq(length, VECTOR_SIZE); + masm.jccb(ConditionFlag.NotZero, loop); + + masm.testl(result, result); + masm.jccb(ConditionFlag.Zero, trueLabel); + + /* + * Compare the remaining bytes with an unaligned memory load aligned to the end of the + * array. + */ + masm.movq(temp, new AMD64Address(array1, result, Scale.Times1, -VECTOR_SIZE)); + masm.cmpq(temp, new AMD64Address(array2, result, Scale.Times1, -VECTOR_SIZE)); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + masm.jmpb(trueLabel); + + masm.bind(compareTail); + masm.movl(length, result); + } + + /** + * Emits code to compare the remaining 1 to 4 bytes. + */ + private void emitTailCompares(AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + Label compare2Bytes = new Label(); + Label compare1Byte = new Label(); + + Register temp = asRegister(temp4); + + if (kind.getByteCount() <= 4) { + // Compare trailing 4 bytes, if any. + masm.testl(result, 4); + masm.jccb(ConditionFlag.Zero, compare2Bytes); + masm.movl(temp, new AMD64Address(array1, 0)); + masm.cmpl(temp, new AMD64Address(array2, 0)); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + + if (kind.getByteCount() <= 2) { + // Move array pointers forward. + masm.leaq(array1, new AMD64Address(array1, 4)); + masm.leaq(array2, new AMD64Address(array2, 4)); + + // Compare trailing 2 bytes, if any. + masm.bind(compare2Bytes); + masm.testl(result, 2); + masm.jccb(ConditionFlag.Zero, compare1Byte); + masm.movzwl(temp, new AMD64Address(array1, 0)); + masm.movzwl(length, new AMD64Address(array2, 0)); + masm.cmpl(temp, length); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + + // The one-byte tail compare is only required for boolean and byte arrays. + if (kind.getByteCount() <= 1) { + // Move array pointers forward before we compare the last trailing byte. + masm.leaq(array1, new AMD64Address(array1, 2)); + masm.leaq(array2, new AMD64Address(array2, 2)); + + // Compare trailing byte, if any. + masm.bind(compare1Byte); + masm.testl(result, 1); + masm.jccb(ConditionFlag.Zero, trueLabel); + masm.movzbl(temp, new AMD64Address(array1, 0)); + masm.movzbl(length, new AMD64Address(array2, 0)); + masm.cmpl(temp, length); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + } else { + masm.bind(compare1Byte); + } + } else { + masm.bind(compare2Bytes); + } + } + } + + private static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Binary.java 2016-12-07 13:54:27.168529634 -0800 @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2015, 2016, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static org.graalvm.compiler.lir.LIRValueUtil.differentRegisters; +import static org.graalvm.compiler.lir.LIRValueUtil.sameRegister; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.site.DataSectionReference; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.Value; + +/** + * AMD64 LIR instructions that have two inputs and one output. + */ +public class AMD64Binary { + + /** + * Instruction that has two {@link AllocatableValue} operands. + */ + public static class TwoOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(TwoOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; + /** + * This argument must be Alive to ensure that result and y are not assigned to the same + * register, which would break the code generation by destroying y too early. + */ + @Alive({REG, STACK}) protected AllocatableValue y; + + public TwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + if (isRegister(y)) { + opcode.emit(masm, size, asRegister(result), asRegister(y)); + } else { + assert isStackSlot(y); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y)); + } + } + } + + /** + * Instruction that has three {@link AllocatableValue} operands. + */ + public static class ThreeOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ThreeOp.class); + + @Opcode private final AMD64RRMOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; + @Use({REG, STACK}) protected AllocatableValue y; + + public ThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(y)) { + opcode.emit(masm, size, asRegister(result), asRegister(x), asRegister(y)); + } else { + assert isStackSlot(y); + opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.asAddress(y)); + } + } + } + + /** + * Commutative instruction that has two {@link AllocatableValue} operands. + */ + public static class CommutativeTwoOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CommutativeTwoOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Use({REG, STACK}) protected AllocatableValue y; + + public CommutativeTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AllocatableValue input; + if (sameRegister(result, y)) { + input = x; + } else { + AMD64Move.move(crb, masm, result, x); + input = y; + } + + if (isRegister(input)) { + opcode.emit(masm, size, asRegister(result), asRegister(input)); + } else { + assert isStackSlot(input); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input)); + } + } + } + + /** + * Commutative instruction that has three {@link AllocatableValue} operands. + */ + public static class CommutativeThreeOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CommutativeThreeOp.class); + + @Opcode private final AMD64RRMOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; + @Use({REG, STACK}) protected AllocatableValue y; + + public CommutativeThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(y)) { + opcode.emit(masm, size, asRegister(result), asRegister(x), asRegister(y)); + } else { + assert isStackSlot(y); + opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.asAddress(y)); + } + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand. + */ + public static class ConstOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ConstOp.class); + + @Opcode private final AMD64MIOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; + private final int y; + + public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { + this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, result, x, y); + } + + public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + opcode.emit(masm, size, asRegister(result), y); + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one + * {@link DataSectionReference} operand. + */ + public static class DataTwoOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DataTwoOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; + private final JavaConstant y; + + private final int alignment; + + public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { + this(opcode, size, result, x, y, y.getJavaKind().getByteCount()); + } + + public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + + this.alignment = alignment; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); + } + } + + /** + * Instruction that has two {@link AllocatableValue} operands and one + * {@link DataSectionReference} operand. + */ + public static class DataThreeOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DataThreeOp.class); + + @Opcode private final AMD64RRMOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; + private final JavaConstant y; + + private final int alignment; + + public DataThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { + this(opcode, size, result, x, y, y.getJavaKind().getByteCount()); + } + + public DataThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + + this.alignment = alignment; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one {@link AMD64AddressValue + * memory} operand. + */ + public static class MemoryTwoOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryTwoOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; + @Alive({COMPOSITE}) protected AMD64AddressValue y; + + @State protected LIRFrameState state; + + public MemoryTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, asRegister(result), y.toAddress()); + } + + @Override + public void verify() { + super.verify(); + assert differentRegisters(result, y) || sameRegister(x, y); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one {@link AMD64AddressValue + * memory} operand. + */ + public static class MemoryThreeOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryThreeOp.class); + + @Opcode private final AMD64RRMOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; + @Use({COMPOSITE}) protected AMD64AddressValue y; + + @State protected LIRFrameState state; + + public MemoryThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, asRegister(result), asRegister(x), y.toAddress()); + } + + @Override + public void verify() { + super.verify(); + assert differentRegisters(result, y) || sameRegister(x, y); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } + } + + /** + * Instruction with a separate result operand, one {@link AllocatableValue} input and one 32-bit + * immediate input. + */ + public static class RMIOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(RMIOp.class); + + @Opcode private final AMD64RMIOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + private final int y; + + public RMIOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(x)) { + opcode.emit(masm, size, asRegister(result), asRegister(x), y); + } else { + assert isStackSlot(x); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), y); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BinaryConsumer.java 2016-12-07 13:54:27.433541280 -0800 @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2015, 2016, 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.lir.amd64; + +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MROp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.site.DataSectionReference; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.VMConstant; +import jdk.vm.ci.meta.Value; + +/** + * AMD64 LIR instructions that have two input operands, but no output operand. + */ +public class AMD64BinaryConsumer { + + /** + * Instruction that has two {@link AllocatableValue} operands. + */ + public static class Op extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(Op.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Use({REG}) protected AllocatableValue x; + @Use({REG, STACK}) protected AllocatableValue y; + + public Op(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(y)) { + opcode.emit(masm, size, asRegister(x), asRegister(y)); + } else { + assert isStackSlot(y); + opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.asAddress(y)); + } + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand. + */ + public static class ConstOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ConstOp.class); + + @Opcode private final AMD64MIOp opcode; + private final OperandSize size; + + @Use({REG, STACK}) protected AllocatableValue x; + private final int y; + + public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue x, int y) { + this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y); + } + + public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) { + this(TYPE, opcode, size, x, y); + } + + protected ConstOp(LIRInstructionClass c, AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) { + super(c); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(x)) { + opcode.emit(masm, size, asRegister(x), y); + } else { + assert isStackSlot(x); + opcode.emit(masm, size, (AMD64Address) crb.asAddress(x), y); + } + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand + * that needs to be patched at runtime. + */ + public static class VMConstOp extends ConstOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(VMConstOp.class); + + protected final VMConstant c; + + public VMConstOp(AMD64MIOp opcode, AllocatableValue x, VMConstant c) { + super(TYPE, opcode, DWORD, x, 0xDEADDEAD); + this.c = c; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + crb.recordInlineDataInCode(c); + super.emitCode(crb, masm); + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one + * {@link DataSectionReference} operand. + */ + public static class DataOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DataOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Use({REG}) protected AllocatableValue x; + private final Constant y; + + private final int alignment; + + public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y) { + this(opcode, size, x, y, size.getBytes()); + } + + public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y, int alignment) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + + this.alignment = alignment; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); + } + } + + /** + * Instruction that has an {@link AllocatableValue} as first input and a + * {@link AMD64AddressValue memory} operand as second input. + */ + public static class MemoryRMOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryRMOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Use({REG}) protected AllocatableValue x; + @Use({COMPOSITE}) protected AMD64AddressValue y; + + @State protected LIRFrameState state; + + public MemoryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, asRegister(x), y.toAddress()); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } + } + + /** + * Instruction that has a {@link AMD64AddressValue memory} operand as first input and an + * {@link AllocatableValue} as second input. + */ + public static class MemoryMROp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryMROp.class); + + @Opcode private final AMD64MROp opcode; + private final OperandSize size; + + @Use({COMPOSITE}) protected AMD64AddressValue x; + @Use({REG}) protected AllocatableValue y; + + @State protected LIRFrameState state; + + public MemoryMROp(AMD64MROp opcode, OperandSize size, AMD64AddressValue x, AllocatableValue y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, x.toAddress(), asRegister(y)); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } + } + + /** + * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate + * operand. + */ + public static class MemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryConstOp.class); + + @Opcode private final AMD64MIOp opcode; + private final OperandSize size; + + @Use({COMPOSITE}) protected AMD64AddressValue x; + private final int y; + + @State protected LIRFrameState state; + + public MemoryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { + this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y, state); + } + + public MemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { + this(TYPE, opcode, size, x, y, state); + } + + protected MemoryConstOp(LIRInstructionClass c, AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { + super(c); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, x.toAddress(), y); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } + + public AMD64MIOp getOpcode() { + return opcode; + } + } + + /** + * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate + * operand that needs to be patched at runtime. + */ + public static class MemoryVMConstOp extends MemoryConstOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryVMConstOp.class); + + protected final VMConstant c; + + public MemoryVMConstOp(AMD64MIOp opcode, AMD64AddressValue x, VMConstant c, LIRFrameState state) { + super(TYPE, opcode, DWORD, x, 0xDEADDEAD, state); + this.c = c; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + crb.recordInlineDataInCode(c); + super.emitCode(crb, masm); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BlockEndOp.java 2016-12-07 13:54:27.699552971 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.StandardOp.AbstractBlockEndOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +public abstract class AMD64BlockEndOp extends AbstractBlockEndOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BlockEndOp.class); + + protected AMD64BlockEndOp(LIRInstructionClass c) { + super(c); + } + + @Override + public final void emitCode(CompilationResultBuilder crb) { + emitCode(crb, (AMD64MacroAssembler) crb.asm); + } + + public abstract void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BreakpointOp.java 2016-12-07 13:54:27.964564618 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.meta.Value; + +/** + * Emits a breakpoint. + */ +@Opcode("BREAKPOINT") +public final class AMD64BreakpointOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BreakpointOp.class); + + /** + * A set of values loaded into the Java ABI parameter locations (for inspection by a debugger). + */ + @Use({REG, STACK}) protected Value[] parameters; + + public AMD64BreakpointOp(Value[] parameters) { + super(TYPE); + this.parameters = parameters; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) { + asm.int3(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ByteSwapOp.java 2016-12-07 13:54:28.229576265 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2012, 2015, 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.lir.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.meta.Value; + +@Opcode("BSWAP") +public final class AMD64ByteSwapOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ByteSwapOp.class); + + @Def({OperandFlag.REG, OperandFlag.HINT}) protected Value result; + @Use protected Value input; + + public AMD64ByteSwapOp(Value result, Value input) { + super(TYPE); + this.result = result; + this.input = input; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, input); + switch ((AMD64Kind) input.getPlatformKind()) { + case DWORD: + masm.bswapl(ValueUtil.asRegister(result)); + break; + case QWORD: + masm.bswapq(ValueUtil.asRegister(result)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64CCall.java 2016-12-07 13:54:28.494587912 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.meta.Value; + +public final class AMD64CCall extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64CCall.class); + + @Def({REG, ILLEGAL}) protected Value result; + @Use({REG, STACK}) protected Value[] parameters; + @Use({REG}) protected Value functionPtr; + @Use({REG}) protected Value numberOfFloatingPointArguments; + + public AMD64CCall(Value result, Value functionPtr, Value numberOfFloatingPointArguments, Value[] parameters) { + super(TYPE); + this.result = result; + this.functionPtr = functionPtr; + this.parameters = parameters; + this.numberOfFloatingPointArguments = numberOfFloatingPointArguments; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + directCall(masm); + } + + private void directCall(AMD64MacroAssembler masm) { + Register reg = ValueUtil.asRegister(functionPtr); + masm.call(reg); + masm.ensureUniquePC(); + } + + @Override + public boolean destroysCallerSavedRegisters() { + return true; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java 2016-12-07 13:54:28.758599514 -0800 @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2011, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static org.graalvm.compiler.lir.LIRValueUtil.differentRegisters; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; + +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool.ZapRegistersAfterInstruction; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.InvokeTarget; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +public class AMD64Call { + + public abstract static class CallOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CallOp.class); + + @Def({REG, ILLEGAL}) protected Value result; + @Use({REG, STACK}) protected Value[] parameters; + @Temp({REG, STACK}) protected Value[] temps; + @State protected LIRFrameState state; + + protected CallOp(LIRInstructionClass c, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(c); + this.result = result; + this.parameters = parameters; + this.state = state; + this.temps = addStackSlotsToTemporaries(parameters, temps); + assert temps != null; + } + + @Override + public boolean destroysCallerSavedRegisters() { + return true; + } + } + + public abstract static class MethodCallOp extends CallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MethodCallOp.class); + + protected final ResolvedJavaMethod callTarget; + + protected MethodCallOp(LIRInstructionClass c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(c, result, parameters, temps, state); + this.callTarget = callTarget; + } + + } + + @Opcode("CALL_DIRECT") + public static class DirectCallOp extends MethodCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectCallOp.class); + + public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + this(TYPE, callTarget, result, parameters, temps, state); + } + + protected DirectCallOp(LIRInstructionClass c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(c, callTarget, result, parameters, temps, state); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + directCall(crb, masm, callTarget, null, true, state); + } + } + + @Opcode("CALL_INDIRECT") + public static class IndirectCallOp extends MethodCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(IndirectCallOp.class); + + @Use({REG}) protected Value targetAddress; + + public IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) { + this(TYPE, callTarget, result, parameters, temps, targetAddress, state); + } + + protected IndirectCallOp(LIRInstructionClass c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, + LIRFrameState state) { + super(c, callTarget, result, parameters, temps, state); + this.targetAddress = targetAddress; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + indirectCall(crb, masm, asRegister(targetAddress), callTarget, state); + } + + @Override + public void verify() { + super.verify(); + assert isRegister(targetAddress) : "The current register allocator cannot handle variables to be used at call sites, it must be in a fixed register for now"; + } + } + + public abstract static class ForeignCallOp extends CallOp implements ZapRegistersAfterInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ForeignCallOp.class); + + protected final ForeignCallLinkage callTarget; + + public ForeignCallOp(LIRInstructionClass c, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(c, result, parameters, temps, state); + this.callTarget = callTarget; + } + + @Override + public boolean destroysCallerSavedRegisters() { + return callTarget.destroysRegisters(); + } + } + + @Opcode("NEAR_FOREIGN_CALL") + public static final class DirectNearForeignCallOp extends ForeignCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class); + + public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(TYPE, linkage, result, parameters, temps, state); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + directCall(crb, masm, callTarget, null, false, state); + } + } + + @Opcode("FAR_FOREIGN_CALL") + public static final class DirectFarForeignCallOp extends ForeignCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class); + + @Temp({REG}) protected AllocatableValue callTemp; + + public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(TYPE, callTarget, result, parameters, temps, state); + /* + * The register allocator does not support virtual registers that are used at the call + * site, so use a fixed register. + */ + callTemp = AMD64.rax.asValue(LIRKind.value(AMD64Kind.QWORD)); + assert differentRegisters(parameters, callTemp); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + directCall(crb, masm, callTarget, ((RegisterValue) callTemp).getRegister(), false, state); + } + } + + public static void directCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) { + if (align) { + emitAlignmentForDirectCall(crb, masm); + } + int before = masm.position(); + if (scratch != null) { + // offset might not fit a 32-bit immediate, generate an + // indirect call with a 64-bit immediate + masm.movq(scratch, 0L); + masm.call(scratch); + } else { + masm.call(); + } + int after = masm.position(); + crb.recordDirectCall(before, after, callTarget, info); + crb.recordExceptionHandlers(after, info); + masm.ensureUniquePC(); + } + + protected static void emitAlignmentForDirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + // make sure that the displacement word of the call ends up word aligned + int offset = masm.position(); + offset += crb.target.arch.getMachineCodeCallDisplacementOffset(); + int modulus = crb.target.wordSize; + if (offset % modulus != 0) { + masm.nop(modulus - offset % modulus); + } + } + + public static void directJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target) { + int before = masm.position(); + masm.jmp(0, true); + int after = masm.position(); + crb.recordDirectCall(before, after, target, null); + masm.ensureUniquePC(); + } + + public static void directConditionalJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target, ConditionFlag cond) { + int before = masm.position(); + masm.jcc(cond, 0, true); + int after = masm.position(); + crb.recordDirectCall(before, after, target, null); + masm.ensureUniquePC(); + } + + public static void indirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { + int before = masm.position(); + masm.call(dst); + int after = masm.position(); + crb.recordIndirectCall(before, after, callTarget, info); + crb.recordExceptionHandlers(after, info); + masm.ensureUniquePC(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ClearRegisterOp.java 2016-12-07 13:54:29.023611161 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.meta.AllocatableValue; + +public class AMD64ClearRegisterOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ClearRegisterOp.class); + + @Opcode private final AMD64RMOp op; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + + public AMD64ClearRegisterOp(OperandSize size, AllocatableValue result) { + super(TYPE); + this.op = XOR.getRMOpcode(size); + this.size = size; + this.result = result; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + op.emit(masm, size, asRegister(result), asRegister(result)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java 2016-12-07 13:54:29.288622808 -0800 @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2011, 2016, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.code.CompilationResult.JumpTable; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp; +import org.graalvm.compiler.lir.StandardOp.BlockEndOp; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.Value; + +public class AMD64ControlFlow { + + public static final class ReturnOp extends AMD64BlockEndOp implements BlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ReturnOp.class); + @Use({REG, ILLEGAL}) protected Value x; + + public ReturnOp(Value x) { + super(TYPE); + this.x = x; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + crb.frameContext.leave(crb); + /* + * We potentially return to the interpreter, and that's an AVX-SSE transition. The only + * live value at this point should be the return value in either rax, or in xmm0 with + * the upper half of the register unused, so we don't destroy any value here. + */ + if (masm.supports(CPUFeature.AVX)) { + masm.vzeroupper(); + } + masm.ret(0); + } + } + + public static class BranchOp extends AMD64BlockEndOp implements StandardOp.BranchOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BranchOp.class); + protected final ConditionFlag condition; + protected final LabelRef trueDestination; + protected final LabelRef falseDestination; + + private final double trueDestinationProbability; + + public BranchOp(Condition condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { + this(intCond(condition), trueDestination, falseDestination, trueDestinationProbability); + } + + public BranchOp(ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { + this(TYPE, condition, trueDestination, falseDestination, trueDestinationProbability); + } + + protected BranchOp(LIRInstructionClass c, ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { + super(c); + this.condition = condition; + this.trueDestination = trueDestination; + this.falseDestination = falseDestination; + this.trueDestinationProbability = trueDestinationProbability; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + /* + * The strategy for emitting jumps is: If either trueDestination or falseDestination is + * the successor block, assume the block scheduler did the correct thing and jcc to the + * other. Otherwise, we need a jcc followed by a jmp. Use the branch probability to make + * sure it is more likely to branch on the jcc (= less likely to execute both the jcc + * and the jmp instead of just the jcc). In the case of loops, that means the jcc is the + * back-edge. + */ + if (crb.isSuccessorEdge(trueDestination)) { + jcc(masm, true, falseDestination); + } else if (crb.isSuccessorEdge(falseDestination)) { + jcc(masm, false, trueDestination); + } else if (trueDestinationProbability < 0.5) { + jcc(masm, true, falseDestination); + masm.jmp(trueDestination.label()); + } else { + jcc(masm, false, trueDestination); + masm.jmp(falseDestination.label()); + } + } + + protected void jcc(AMD64MacroAssembler masm, boolean negate, LabelRef target) { + masm.jcc(negate ? condition.negate() : condition, target.label()); + } + } + + public static final class FloatBranchOp extends BranchOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(FloatBranchOp.class); + protected boolean unorderedIsTrue; + + public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { + super(TYPE, floatCond(condition), trueDestination, falseDestination, trueDestinationProbability); + this.unorderedIsTrue = unorderedIsTrue; + } + + @Override + protected void jcc(AMD64MacroAssembler masm, boolean negate, LabelRef target) { + floatJcc(masm, negate ? condition.negate() : condition, negate ? !unorderedIsTrue : unorderedIsTrue, target.label()); + } + } + + public static class StrategySwitchOp extends AMD64BlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StrategySwitchOp.class); + protected final Constant[] keyConstants; + private final LabelRef[] keyTargets; + private LabelRef defaultTarget; + @Alive({REG}) protected Value key; + @Temp({REG, ILLEGAL}) protected Value scratch; + protected final SwitchStrategy strategy; + + public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { + this(TYPE, strategy, keyTargets, defaultTarget, key, scratch); + } + + protected StrategySwitchOp(LIRInstructionClass c, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { + super(c); + this.strategy = strategy; + this.keyConstants = strategy.getKeyConstants(); + this.keyTargets = keyTargets; + this.defaultTarget = defaultTarget; + this.key = key; + this.scratch = scratch; + assert keyConstants.length == keyTargets.length; + assert keyConstants.length == strategy.keyProbabilities.length; + } + + @Override + public void emitCode(final CompilationResultBuilder crb, final AMD64MacroAssembler masm) { + strategy.run(new SwitchClosure(asRegister(key), crb, masm)); + } + + public class SwitchClosure extends BaseSwitchClosure { + + protected final Register keyRegister; + protected final CompilationResultBuilder crb; + protected final AMD64MacroAssembler masm; + + protected SwitchClosure(Register keyRegister, CompilationResultBuilder crb, AMD64MacroAssembler masm) { + super(crb, masm, keyTargets, defaultTarget); + this.keyRegister = keyRegister; + this.crb = crb; + this.masm = masm; + } + + protected void emitComparison(Constant c) { + JavaConstant jc = (JavaConstant) c; + switch (jc.getJavaKind()) { + case Int: + long lc = jc.asLong(); + assert NumUtil.isInt(lc); + masm.cmpl(keyRegister, (int) lc); + break; + case Long: + masm.cmpq(keyRegister, (AMD64Address) crb.asLongConstRef(jc)); + break; + case Object: + AMD64Move.const2reg(crb, masm, asRegister(scratch), jc); + masm.cmpptr(keyRegister, asRegister(scratch)); + break; + default: + throw new GraalError("switch only supported for int, long and object"); + } + } + + @Override + protected void conditionalJump(int index, Condition condition, Label target) { + emitComparison(keyConstants[index]); + masm.jcc(intCond(condition), target); + } + } + } + + public static final class TableSwitchOp extends AMD64BlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(TableSwitchOp.class); + private final int lowKey; + private final LabelRef defaultTarget; + private final LabelRef[] targets; + @Use protected Value index; + @Temp({REG, HINT}) protected Value idxScratch; + @Temp protected Value scratch; + + public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Value index, Variable scratch, Variable idxScratch) { + super(TYPE); + this.lowKey = lowKey; + this.defaultTarget = defaultTarget; + this.targets = targets; + this.index = index; + this.scratch = scratch; + this.idxScratch = idxScratch; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Register indexReg = asRegister(index, AMD64Kind.DWORD); + Register idxScratchReg = asRegister(idxScratch, AMD64Kind.DWORD); + Register scratchReg = asRegister(scratch, AMD64Kind.QWORD); + + if (!indexReg.equals(idxScratchReg)) { + masm.movl(idxScratchReg, indexReg); + } + + // Compare index against jump table bounds + int highKey = lowKey + targets.length - 1; + if (lowKey != 0) { + // subtract the low value from the switch value + masm.subl(idxScratchReg, lowKey); + masm.cmpl(idxScratchReg, highKey - lowKey); + } else { + masm.cmpl(idxScratchReg, highKey); + } + + // Jump to default target if index is not within the jump table + if (defaultTarget != null) { + masm.jcc(ConditionFlag.Above, defaultTarget.label()); + } + + // Set scratch to address of jump table + masm.leaq(scratchReg, new AMD64Address(AMD64.rip, 0)); + final int afterLea = masm.position(); + + // Load jump table entry into scratch and jump to it + masm.movslq(idxScratchReg, new AMD64Address(scratchReg, idxScratchReg, Scale.Times4, 0)); + masm.addq(scratchReg, idxScratchReg); + masm.jmp(scratchReg); + + // Inserting padding so that jump table address is 4-byte aligned + if ((masm.position() & 0x3) != 0) { + masm.nop(4 - (masm.position() & 0x3)); + } + + // Patch LEA instruction above now that we know the position of the jump table + // TODO this is ugly and should be done differently + final int jumpTablePos = masm.position(); + final int leaDisplacementPosition = afterLea - 4; + masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition); + + // Emit jump table entries + for (LabelRef target : targets) { + Label label = target.label(); + int offsetToJumpTableBase = masm.position() - jumpTablePos; + if (label.isBound()) { + int imm32 = label.position() - jumpTablePos; + masm.emitInt(imm32); + } else { + label.addPatchAt(masm.position()); + + masm.emitByte(0); // pseudo-opcode for jump table entry + masm.emitShort(offsetToJumpTableBase); + masm.emitByte(0); // padding to make jump table entry 4 bytes wide + } + } + + JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4); + crb.compilationResult.addAnnotation(jt); + } + } + + @Opcode("CMOVE") + public static final class CondMoveOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CondMoveOp.class); + @Def({REG, HINT}) protected Value result; + @Alive({REG}) protected Value trueValue; + @Use({REG, STACK, CONST}) protected Value falseValue; + private final ConditionFlag condition; + + public CondMoveOp(Variable result, Condition condition, AllocatableValue trueValue, Value falseValue) { + super(TYPE); + this.result = result; + this.condition = intCond(condition); + this.trueValue = trueValue; + this.falseValue = falseValue; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + cmove(crb, masm, result, false, condition, false, trueValue, falseValue); + } + } + + @Opcode("CMOVE") + public static final class FloatCondMoveOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(FloatCondMoveOp.class); + @Def({REG}) protected Value result; + @Alive({REG}) protected Value trueValue; + @Alive({REG}) protected Value falseValue; + private final ConditionFlag condition; + private final boolean unorderedIsTrue; + + public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) { + super(TYPE); + this.result = result; + this.condition = floatCond(condition); + this.unorderedIsTrue = unorderedIsTrue; + this.trueValue = trueValue; + this.falseValue = falseValue; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + cmove(crb, masm, result, true, condition, unorderedIsTrue, trueValue, falseValue); + } + } + + private static void floatJcc(AMD64MacroAssembler masm, ConditionFlag condition, boolean unorderedIsTrue, Label label) { + Label endLabel = new Label(); + if (unorderedIsTrue && !trueOnUnordered(condition)) { + masm.jcc(ConditionFlag.Parity, label); + } else if (!unorderedIsTrue && trueOnUnordered(condition)) { + masm.jccb(ConditionFlag.Parity, endLabel); + } + masm.jcc(condition, label); + masm.bind(endLabel); + } + + private static void cmove(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, boolean isFloat, ConditionFlag condition, boolean unorderedIsTrue, Value trueValue, + Value falseValue) { + // check that we don't overwrite an input operand before it is used. + assert !result.equals(trueValue); + + AMD64Move.move(crb, masm, result, falseValue); + cmove(crb, masm, result, condition, trueValue); + + if (isFloat) { + if (unorderedIsTrue && !trueOnUnordered(condition)) { + cmove(crb, masm, result, ConditionFlag.Parity, trueValue); + } else if (!unorderedIsTrue && trueOnUnordered(condition)) { + cmove(crb, masm, result, ConditionFlag.Parity, falseValue); + } + } + } + + private static void cmove(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, ConditionFlag cond, Value other) { + if (isRegister(other)) { + assert !asRegister(other).equals(asRegister(result)) : "other already overwritten by previous move"; + switch ((AMD64Kind) other.getPlatformKind()) { + case BYTE: + case WORD: + case DWORD: + masm.cmovl(cond, asRegister(result), asRegister(other)); + break; + case QWORD: + masm.cmovq(cond, asRegister(result), asRegister(other)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } else { + AMD64Address addr = (AMD64Address) crb.asAddress(other); + switch ((AMD64Kind) other.getPlatformKind()) { + case BYTE: + case WORD: + case DWORD: + masm.cmovl(cond, asRegister(result), addr); + break; + case QWORD: + masm.cmovq(cond, asRegister(result), addr); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + } + + private static ConditionFlag intCond(Condition cond) { + switch (cond) { + case EQ: + return ConditionFlag.Equal; + case NE: + return ConditionFlag.NotEqual; + case LT: + return ConditionFlag.Less; + case LE: + return ConditionFlag.LessEqual; + case GE: + return ConditionFlag.GreaterEqual; + case GT: + return ConditionFlag.Greater; + case BE: + return ConditionFlag.BelowEqual; + case AE: + return ConditionFlag.AboveEqual; + case AT: + return ConditionFlag.Above; + case BT: + return ConditionFlag.Below; + default: + throw GraalError.shouldNotReachHere(); + } + } + + private static ConditionFlag floatCond(Condition cond) { + switch (cond) { + case EQ: + return ConditionFlag.Equal; + case NE: + return ConditionFlag.NotEqual; + case LT: + return ConditionFlag.Below; + case LE: + return ConditionFlag.BelowEqual; + case GE: + return ConditionFlag.AboveEqual; + case GT: + return ConditionFlag.Above; + default: + throw GraalError.shouldNotReachHere(); + } + } + + private static boolean trueOnUnordered(ConditionFlag condition) { + switch (condition) { + case AboveEqual: + case NotEqual: + case Above: + case Less: + case Overflow: + return false; + case Equal: + case BelowEqual: + case Below: + case GreaterEqual: + case NoOverflow: + return true; + default: + throw GraalError.shouldNotReachHere(); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java 2016-12-07 13:54:29.553634455 -0800 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.amd64; + +import static jdk.vm.ci.code.ValueUtil.asStackSlot; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.framemap.FrameMap; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.StackSlot; + +/** + * AMD64 specific frame map. + * + * This is the format of an AMD64 stack frame: + * + *

    + *   Base       Contents
    + *
    + *            :                                :  -----
    + *   caller   | incoming overflow argument n   |    ^
    + *   frame    :     ...                        :    | positive
    + *            | incoming overflow argument 0   |    | offsets
    + *   ---------+--------------------------------+---------------------
    + *            | return address                 |    |            ^
    + *   current  +--------------------------------+    |            |    -----
    + *   frame    |                                |    |            |      ^
    + *            : callee save area               :    |            |      |
    + *            |                                |    |            |      |
    + *            +--------------------------------+    |            |      |
    + *            | spill slot 0                   |    | negative   |      |
    + *            :     ...                        :    v offsets    |      |
    + *            | spill slot n                   |  -----        total  frame
    + *            +--------------------------------+               frame  size
    + *            | alignment padding              |               size     |
    + *            +--------------------------------+  -----          |      |
    + *            | outgoing overflow argument n   |    ^            |      |
    + *            :     ...                        :    | positive   |      |
    + *            | outgoing overflow argument 0   |    | offsets    v      v
    + *    %sp-->  +--------------------------------+---------------------------
    + *
    + * 
    + * + * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size of such + * a block may be greater than the size of a normal spill slot or the word size. + *

    + * A runtime can reserve space at the beginning of the overflow argument area. The calling + * convention can specify that the first overflow stack argument is not at offset 0, but at a + * specified offset. Use {@link CodeCacheProvider#getMinimumOutgoingSize()} to make sure that + * call-free methods also have this space reserved. Then the VM can use the memory at offset 0 + * relative to the stack pointer. + */ +public class AMD64FrameMap extends FrameMap { + + private StackSlot rbpSpillSlot; + + public AMD64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) { + super(codeCache, registerConfig, referenceMapFactory); + // (negative) offset relative to sp + total frame size + initialSpillSize = returnAddressSize(); + spillSize = initialSpillSize; + } + + @Override + public int totalFrameSize() { + return frameSize() + returnAddressSize(); + } + + @Override + public int currentFrameSize() { + return alignFrameSize(outgoingSize + spillSize - returnAddressSize()); + } + + @Override + protected int alignFrameSize(int size) { + return NumUtil.roundUp(size + returnAddressSize(), getTarget().stackAlignment) - returnAddressSize(); + } + + @Override + public int offsetForStackSlot(StackSlot slot) { + // @formatter:off + assert (!slot.getRawAddFrameSize() && slot.getRawOffset() < outgoingSize) || + (slot.getRawAddFrameSize() && slot.getRawOffset() < 0 && -slot.getRawOffset() <= spillSize) || + (slot.getRawAddFrameSize() && slot.getRawOffset() >= 0) : + String.format("RawAddFrameSize: %b RawOffset: 0x%x spillSize: 0x%x outgoingSize: 0x%x", slot.getRawAddFrameSize(), slot.getRawOffset(), spillSize, outgoingSize); + // @formatter:on + return super.offsetForStackSlot(slot); + } + + /** + * For non-leaf methods, RBP is preserved in the special stack slot required by the HotSpot + * runtime for walking/inspecting frames of such methods. + */ + StackSlot allocateRBPSpillSlot() { + assert spillSize == initialSpillSize : "RBP spill slot must be the first allocated stack slots"; + rbpSpillSlot = allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + assert asStackSlot(rbpSpillSlot).getRawOffset() == -16 : asStackSlot(rbpSpillSlot).getRawOffset(); + return rbpSpillSlot; + } + + void freeRBPSpillSlot() { + int size = spillSlotSize(LIRKind.value(AMD64Kind.QWORD)); + assert spillSize == NumUtil.roundUp(initialSpillSize + size, size) : "RBP spill slot can not be freed after allocation other stack slots"; + spillSize = initialSpillSize; + } + + public StackSlot allocateDeoptimizationRescueSlot() { + assert spillSize == initialSpillSize || spillSize == initialSpillSize + + spillSlotSize(LIRKind.value(AMD64Kind.QWORD)) : "Deoptimization rescue slot must be the first or second (if there is an RBP spill slot) stack slot"; + return allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMapBuilder.java 2016-12-07 13:54:29.817646058 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, 2014, 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.lir.amd64; + +import org.graalvm.compiler.lir.framemap.FrameMap; +import org.graalvm.compiler.lir.framemap.FrameMapBuilderImpl; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.StackSlot; + +public class AMD64FrameMapBuilder extends FrameMapBuilderImpl { + + public AMD64FrameMapBuilder(FrameMap frameMap, CodeCacheProvider codeCache, RegisterConfig registerConfig) { + super(frameMap, codeCache, registerConfig); + } + + /** + * For non-leaf methods, RBP is preserved in the special stack slot required by the HotSpot + * runtime for walking/inspecting frames of such methods. + */ + public StackSlot allocateRBPSpillSlot() { + return ((AMD64FrameMap) getFrameMap()).allocateRBPSpillSlot(); + } + + public void freeRBPSpillSlot() { + ((AMD64FrameMap) getFrameMap()).freeRBPSpillSlot(); + } + + public StackSlot allocateDeoptimizationRescueSlot() { + return ((AMD64FrameMap) getFrameMap()).allocateDeoptimizationRescueSlot(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64LIRInstruction.java 2016-12-07 13:54:30.082657705 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011, 2012, 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.lir.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +/** + * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method. + */ +public abstract class AMD64LIRInstruction extends LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64LIRInstruction.class); + + protected AMD64LIRInstruction(LIRInstructionClass c) { + super(c); + } + + @Override + public final void emitCode(CompilationResultBuilder crb) { + emitCode(crb, (AMD64MacroAssembler) crb.asm); + } + + public abstract void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathIntrinsicBinaryOp.java 2016-12-07 13:54:30.346669308 -0800 @@ -0,0 +1,2064 @@ +/* + * Copyright (c) 2011, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.ArrayDataPointerConstant; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; + +public final class AMD64MathIntrinsicBinaryOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64MathIntrinsicBinaryOp.class); + + public enum BinaryIntrinsicOpcode { + POW + } + + @Opcode private final BinaryIntrinsicOpcode opcode; + @Def protected Value result; + @Use protected Value input; + @Use protected Value secondInput; + @Temp({REG, ILLEGAL}) protected Value xmm1Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm2Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm3Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm4Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm5Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm6Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm7Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm8Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm9Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm10Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr1Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr2Temp = Value.ILLEGAL; + @Temp protected AllocatableValue rcxTemp; + @Temp({REG, ILLEGAL}) protected Value gpr4Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr5Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr6Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr7Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr8Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr9Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr10Temp = Value.ILLEGAL; + + CompilationResultBuilder internalCrb; + + public AMD64MathIntrinsicBinaryOp(LIRGeneratorTool tool, BinaryIntrinsicOpcode opcode, Value result, Value input, Value alternateInput) { + super(TYPE); + this.opcode = opcode; + this.result = result; + this.input = input; + this.secondInput = alternateInput; + if (opcode == BinaryIntrinsicOpcode.POW) { + this.gpr1Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr2Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.rcxTemp = AMD64.rcx.asValue(LIRKind.value(AMD64Kind.QWORD)); + this.gpr4Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr5Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr6Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr7Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr8Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + + this.xmm1Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm2Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm3Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm4Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm5Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm6Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm7Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm8Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm9Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm10Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + } + } + + private void setCrb(CompilationResultBuilder crb) { + internalCrb = crb; + } + + private AMD64Address externalAddress(ArrayDataPointerConstant curPtr) { + return (AMD64Address) internalCrb.recordDataReferenceInCode(curPtr); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + switch (opcode) { + case POW: + powIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), asRegister(secondInput, AMD64Kind.DOUBLE), crb, masm); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + + /* + * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM) + * Source Code + * + * ALGORITHM DESCRIPTION - POW() --------------------- + * + * Let x=2^k * mx, mx in [1,2) + * + * log2(x) calculation: + * + * Get B~1/mx based on the output of rcpps instruction (B0) B = int((B0*LH*2^9+0.5))/2^9 LH is a + * short approximation for log2(e) + * + * Reduced argument, scaled by LH: r=B*mx-LH (computed accurately in high and low parts) + * + * log2(x) result: k - log2(B) + p(r) p(r) is a degree 8 polynomial -log2(B) read from data + * table (high, low parts) log2(x) is formed from high and low parts For |x| in [1-1/32, + * 1+1/16), a slower but more accurate computation based om the same table design is performed. + * + * Main path is taken if | floor(log2(|log2(|x|)|) + floor(log2|y|) | < 8, to filter out all + * potential OF/UF cases. exp2(y*log2(x)) is computed using an 8-bit index table and a degree 5 + * polynomial + * + * Special cases: pow(-0,y) = -INF and raises the divide-by-zero exception for y an odd integer + * < 0. pow(-0,y) = +INF and raises the divide-by-zero exception for y < 0 and not an odd + * integer. pow(-0,y) = -0 for y an odd integer > 0. pow(-0,y) = +0 for y > 0 and not an odd + * integer. pow(-1,-INF) = NaN. pow(+1,y) = NaN for any y, even a NaN. pow(x,-0) = 1 for any x, + * even a NaN. pow(x,y) = a NaN and raises the invalid exception for finite x < 0 and finite + * non-integer y. pow(x,-INF) = +INF for |x|<1. pow(x,-INF) = +0 for |x|>1. pow(x,+INF) = +0 for + * |x|<1. pow(x,+INF) = +INF for |x|>1. pow(-INF,y) = -0 for y an odd integer < 0. pow(-INF,y) = + * +0 for y < 0 and not an odd integer. pow(-INF,y) = -INF for y an odd integer > 0. pow(-INF,y) + * = +INF for y > 0 and not an odd integer. pow(+INF,y) = +0 for y <0. pow(+INF,y) = +INF for y + * >0. + * + */ + + private static int[] highSigMask = { + 0x00000000, 0xfffff800, 0x00000000, 0xfffff800 + }; + + private static int[] logTwoE = { + 0x00000000, 0x3ff72000, 0x161bb241, 0xbf5dabe1 + }; + + private static int[] highmaskY = { + 0x00000000, 0xfffffff8, 0x00000000, 0xffffffff + }; + + private static int[] tExp = { + 0x00000000, 0x3ff00000, 0x00000000, 0x3b700000, 0xfa5abcbf, + 0x3ff00b1a, 0xa7609f71, 0xbc84f6b2, 0xa9fb3335, 0x3ff0163d, + 0x9ab8cdb7, 0x3c9b6129, 0x143b0281, 0x3ff02168, 0x0fc54eb6, + 0xbc82bf31, 0x3e778061, 0x3ff02c9a, 0x535b085d, 0xbc719083, + 0x2e11bbcc, 0x3ff037d4, 0xeeade11a, 0x3c656811, 0xe86e7f85, + 0x3ff04315, 0x1977c96e, 0xbc90a31c, 0x72f654b1, 0x3ff04e5f, + 0x3aa0d08c, 0x3c84c379, 0xd3158574, 0x3ff059b0, 0xa475b465, + 0x3c8d73e2, 0x0e3c1f89, 0x3ff0650a, 0x5799c397, 0xbc95cb7b, + 0x29ddf6de, 0x3ff0706b, 0xe2b13c27, 0xbc8c91df, 0x2b72a836, + 0x3ff07bd4, 0x54458700, 0x3c832334, 0x18759bc8, 0x3ff08745, + 0x4bb284ff, 0x3c6186be, 0xf66607e0, 0x3ff092bd, 0x800a3fd1, + 0xbc968063, 0xcac6f383, 0x3ff09e3e, 0x18316136, 0x3c914878, + 0x9b1f3919, 0x3ff0a9c7, 0x873d1d38, 0x3c85d16c, 0x6cf9890f, + 0x3ff0b558, 0x4adc610b, 0x3c98a62e, 0x45e46c85, 0x3ff0c0f1, + 0x06d21cef, 0x3c94f989, 0x2b7247f7, 0x3ff0cc92, 0x16e24f71, + 0x3c901edc, 0x23395dec, 0x3ff0d83b, 0xe43f316a, 0xbc9bc14d, + 0x32d3d1a2, 0x3ff0e3ec, 0x27c57b52, 0x3c403a17, 0x5fdfa9c5, + 0x3ff0efa5, 0xbc54021b, 0xbc949db9, 0xaffed31b, 0x3ff0fb66, + 0xc44ebd7b, 0xbc6b9bed, 0x28d7233e, 0x3ff10730, 0x1692fdd5, + 0x3c8d46eb, 0xd0125b51, 0x3ff11301, 0x39449b3a, 0xbc96c510, + 0xab5e2ab6, 0x3ff11edb, 0xf703fb72, 0xbc9ca454, 0xc06c31cc, + 0x3ff12abd, 0xb36ca5c7, 0xbc51b514, 0x14f204ab, 0x3ff136a8, + 0xba48dcf0, 0xbc67108f, 0xaea92de0, 0x3ff1429a, 0x9af1369e, + 0xbc932fbf, 0x934f312e, 0x3ff14e95, 0x39bf44ab, 0xbc8b91e8, + 0xc8a58e51, 0x3ff15a98, 0xb9eeab0a, 0x3c82406a, 0x5471c3c2, + 0x3ff166a4, 0x82ea1a32, 0x3c58f23b, 0x3c7d517b, 0x3ff172b8, + 0xb9d78a76, 0xbc819041, 0x8695bbc0, 0x3ff17ed4, 0xe2ac5a64, + 0x3c709e3f, 0x388c8dea, 0x3ff18af9, 0xd1970f6c, 0xbc911023, + 0x58375d2f, 0x3ff19726, 0x85f17e08, 0x3c94aadd, 0xeb6fcb75, + 0x3ff1a35b, 0x7b4968e4, 0x3c8e5b4c, 0xf8138a1c, 0x3ff1af99, + 0xa4b69280, 0x3c97bf85, 0x84045cd4, 0x3ff1bbe0, 0x352ef607, + 0xbc995386, 0x95281c6b, 0x3ff1c82f, 0x8010f8c9, 0x3c900977, + 0x3168b9aa, 0x3ff1d487, 0x00a2643c, 0x3c9e016e, 0x5eb44027, + 0x3ff1e0e7, 0x088cb6de, 0xbc96fdd8, 0x22fcd91d, 0x3ff1ed50, + 0x027bb78c, 0xbc91df98, 0x8438ce4d, 0x3ff1f9c1, 0xa097af5c, + 0xbc9bf524, 0x88628cd6, 0x3ff2063b, 0x814a8495, 0x3c8dc775, + 0x3578a819, 0x3ff212be, 0x2cfcaac9, 0x3c93592d, 0x917ddc96, + 0x3ff21f49, 0x9494a5ee, 0x3c82a97e, 0xa27912d1, 0x3ff22bdd, + 0x5577d69f, 0x3c8d34fb, 0x6e756238, 0x3ff2387a, 0xb6c70573, + 0x3c99b07e, 0xfb82140a, 0x3ff2451f, 0x911ca996, 0x3c8acfcc, + 0x4fb2a63f, 0x3ff251ce, 0xbef4f4a4, 0x3c8ac155, 0x711ece75, + 0x3ff25e85, 0x4ac31b2c, 0x3c93e1a2, 0x65e27cdd, 0x3ff26b45, + 0x9940e9d9, 0x3c82bd33, 0x341ddf29, 0x3ff2780e, 0x05f9e76c, + 0x3c9e067c, 0xe1f56381, 0x3ff284df, 0x8c3f0d7e, 0xbc9a4c3a, + 0x7591bb70, 0x3ff291ba, 0x28401cbd, 0xbc82cc72, 0xf51fdee1, + 0x3ff29e9d, 0xafad1255, 0x3c8612e8, 0x66d10f13, 0x3ff2ab8a, + 0x191690a7, 0xbc995743, 0xd0dad990, 0x3ff2b87f, 0xd6381aa4, + 0xbc410adc, 0x39771b2f, 0x3ff2c57e, 0xa6eb5124, 0xbc950145, + 0xa6e4030b, 0x3ff2d285, 0x54db41d5, 0x3c900247, 0x1f641589, + 0x3ff2df96, 0xfbbce198, 0x3c9d16cf, 0xa93e2f56, 0x3ff2ecaf, + 0x45d52383, 0x3c71ca0f, 0x4abd886b, 0x3ff2f9d2, 0x532bda93, + 0xbc653c55, 0x0a31b715, 0x3ff306fe, 0xd23182e4, 0x3c86f46a, + 0xedeeb2fd, 0x3ff31432, 0xf3f3fcd1, 0x3c8959a3, 0xfc4cd831, + 0x3ff32170, 0x8e18047c, 0x3c8a9ce7, 0x3ba8ea32, 0x3ff32eb8, + 0x3cb4f318, 0xbc9c45e8, 0xb26416ff, 0x3ff33c08, 0x843659a6, + 0x3c932721, 0x66e3fa2d, 0x3ff34962, 0x930881a4, 0xbc835a75, + 0x5f929ff1, 0x3ff356c5, 0x5c4e4628, 0xbc8b5cee, 0xa2de883b, + 0x3ff36431, 0xa06cb85e, 0xbc8c3144, 0x373aa9cb, 0x3ff371a7, + 0xbf42eae2, 0xbc963aea, 0x231e754a, 0x3ff37f26, 0x9eceb23c, + 0xbc99f5ca, 0x6d05d866, 0x3ff38cae, 0x3c9904bd, 0xbc9e958d, + 0x1b7140ef, 0x3ff39a40, 0xfc8e2934, 0xbc99a9a5, 0x34e59ff7, + 0x3ff3a7db, 0xd661f5e3, 0xbc75e436, 0xbfec6cf4, 0x3ff3b57f, + 0xe26fff18, 0x3c954c66, 0xc313a8e5, 0x3ff3c32d, 0x375d29c3, + 0xbc9efff8, 0x44ede173, 0x3ff3d0e5, 0x8c284c71, 0x3c7fe8d0, + 0x4c123422, 0x3ff3dea6, 0x11f09ebc, 0x3c8ada09, 0xdf1c5175, + 0x3ff3ec70, 0x7b8c9bca, 0xbc8af663, 0x04ac801c, 0x3ff3fa45, + 0xf956f9f3, 0xbc97d023, 0xc367a024, 0x3ff40822, 0xb6f4d048, + 0x3c8bddf8, 0x21f72e2a, 0x3ff4160a, 0x1c309278, 0xbc5ef369, + 0x2709468a, 0x3ff423fb, 0xc0b314dd, 0xbc98462d, 0xd950a897, + 0x3ff431f5, 0xe35f7999, 0xbc81c7dd, 0x3f84b9d4, 0x3ff43ffa, + 0x9704c003, 0x3c8880be, 0x6061892d, 0x3ff44e08, 0x04ef80d0, + 0x3c489b7a, 0x42a7d232, 0x3ff45c20, 0x82fb1f8e, 0xbc686419, + 0xed1d0057, 0x3ff46a41, 0xd1648a76, 0x3c9c944b, 0x668b3237, + 0x3ff4786d, 0xed445733, 0xbc9c20f0, 0xb5c13cd0, 0x3ff486a2, + 0xb69062f0, 0x3c73c1a3, 0xe192aed2, 0x3ff494e1, 0x5e499ea0, + 0xbc83b289, 0xf0d7d3de, 0x3ff4a32a, 0xf3d1be56, 0x3c99cb62, + 0xea6db7d7, 0x3ff4b17d, 0x7f2897f0, 0xbc8125b8, 0xd5362a27, + 0x3ff4bfda, 0xafec42e2, 0x3c7d4397, 0xb817c114, 0x3ff4ce41, + 0x690abd5d, 0x3c905e29, 0x99fddd0d, 0x3ff4dcb2, 0xbc6a7833, + 0x3c98ecdb, 0x81d8abff, 0x3ff4eb2d, 0x2e5d7a52, 0xbc95257d, + 0x769d2ca7, 0x3ff4f9b2, 0xd25957e3, 0xbc94b309, 0x7f4531ee, + 0x3ff50841, 0x49b7465f, 0x3c7a249b, 0xa2cf6642, 0x3ff516da, + 0x69bd93ef, 0xbc8f7685, 0xe83f4eef, 0x3ff5257d, 0x43efef71, + 0xbc7c998d, 0x569d4f82, 0x3ff5342b, 0x1db13cad, 0xbc807abe, + 0xf4f6ad27, 0x3ff542e2, 0x192d5f7e, 0x3c87926d, 0xca5d920f, + 0x3ff551a4, 0xefede59b, 0xbc8d689c, 0xdde910d2, 0x3ff56070, + 0x168eebf0, 0xbc90fb6e, 0x36b527da, 0x3ff56f47, 0x011d93ad, + 0x3c99bb2c, 0xdbe2c4cf, 0x3ff57e27, 0x8a57b9c4, 0xbc90b98c, + 0xd497c7fd, 0x3ff58d12, 0x5b9a1de8, 0x3c8295e1, 0x27ff07cc, + 0x3ff59c08, 0xe467e60f, 0xbc97e2ce, 0xdd485429, 0x3ff5ab07, + 0x054647ad, 0x3c96324c, 0xfba87a03, 0x3ff5ba11, 0x4c233e1a, + 0xbc9b77a1, 0x8a5946b7, 0x3ff5c926, 0x816986a2, 0x3c3c4b1b, + 0x90998b93, 0x3ff5d845, 0xa8b45643, 0xbc9cd6a7, 0x15ad2148, + 0x3ff5e76f, 0x3080e65e, 0x3c9ba6f9, 0x20dceb71, 0x3ff5f6a3, + 0xe3cdcf92, 0xbc89eadd, 0xb976dc09, 0x3ff605e1, 0x9b56de47, + 0xbc93e242, 0xe6cdf6f4, 0x3ff6152a, 0x4ab84c27, 0x3c9e4b3e, + 0xb03a5585, 0x3ff6247e, 0x7e40b497, 0xbc9383c1, 0x1d1929fd, + 0x3ff633dd, 0xbeb964e5, 0x3c984710, 0x34ccc320, 0x3ff64346, + 0x759d8933, 0xbc8c483c, 0xfebc8fb7, 0x3ff652b9, 0xc9a73e09, + 0xbc9ae3d5, 0x82552225, 0x3ff66238, 0x87591c34, 0xbc9bb609, + 0xc70833f6, 0x3ff671c1, 0x586c6134, 0xbc8e8732, 0xd44ca973, + 0x3ff68155, 0x44f73e65, 0x3c6038ae, 0xb19e9538, 0x3ff690f4, + 0x9aeb445d, 0x3c8804bd, 0x667f3bcd, 0x3ff6a09e, 0x13b26456, + 0xbc9bdd34, 0xfa75173e, 0x3ff6b052, 0x2c9a9d0e, 0x3c7a38f5, + 0x750bdabf, 0x3ff6c012, 0x67ff0b0d, 0xbc728956, 0xddd47645, + 0x3ff6cfdc, 0xb6f17309, 0x3c9c7aa9, 0x3c651a2f, 0x3ff6dfb2, + 0x683c88ab, 0xbc6bbe3a, 0x98593ae5, 0x3ff6ef92, 0x9e1ac8b2, + 0xbc90b974, 0xf9519484, 0x3ff6ff7d, 0x25860ef6, 0xbc883c0f, + 0x66f42e87, 0x3ff70f74, 0xd45aa65f, 0x3c59d644, 0xe8ec5f74, + 0x3ff71f75, 0x86887a99, 0xbc816e47, 0x86ead08a, 0x3ff72f82, + 0x2cd62c72, 0xbc920aa0, 0x48a58174, 0x3ff73f9a, 0x6c65d53c, + 0xbc90a8d9, 0x35d7cbfd, 0x3ff74fbd, 0x618a6e1c, 0x3c9047fd, + 0x564267c9, 0x3ff75feb, 0x57316dd3, 0xbc902459, 0xb1ab6e09, + 0x3ff77024, 0x169147f8, 0x3c9b7877, 0x4fde5d3f, 0x3ff78069, + 0x0a02162d, 0x3c9866b8, 0x38ac1cf6, 0x3ff790b9, 0x62aadd3e, + 0x3c9349a8, 0x73eb0187, 0x3ff7a114, 0xee04992f, 0xbc841577, + 0x0976cfdb, 0x3ff7b17b, 0x8468dc88, 0xbc9bebb5, 0x0130c132, + 0x3ff7c1ed, 0xd1164dd6, 0x3c9f124c, 0x62ff86f0, 0x3ff7d26a, + 0xfb72b8b4, 0x3c91bddb, 0x36cf4e62, 0x3ff7e2f3, 0xba15797e, + 0x3c705d02, 0x8491c491, 0x3ff7f387, 0xcf9311ae, 0xbc807f11, + 0x543e1a12, 0x3ff80427, 0x626d972b, 0xbc927c86, 0xadd106d9, + 0x3ff814d2, 0x0d151d4d, 0x3c946437, 0x994cce13, 0x3ff82589, + 0xd41532d8, 0xbc9d4c1d, 0x1eb941f7, 0x3ff8364c, 0x31df2bd5, + 0x3c999b9a, 0x4623c7ad, 0x3ff8471a, 0xa341cdfb, 0xbc88d684, + 0x179f5b21, 0x3ff857f4, 0xf8b216d0, 0xbc5ba748, 0x9b4492ed, + 0x3ff868d9, 0x9bd4f6ba, 0xbc9fc6f8, 0xd931a436, 0x3ff879ca, + 0xd2db47bd, 0x3c85d2d7, 0xd98a6699, 0x3ff88ac7, 0xf37cb53a, + 0x3c9994c2, 0xa478580f, 0x3ff89bd0, 0x4475202a, 0x3c9d5395, + 0x422aa0db, 0x3ff8ace5, 0x56864b27, 0x3c96e9f1, 0xbad61778, + 0x3ff8be05, 0xfc43446e, 0x3c9ecb5e, 0x16b5448c, 0x3ff8cf32, + 0x32e9e3aa, 0xbc70d55e, 0x5e0866d9, 0x3ff8e06a, 0x6fc9b2e6, + 0xbc97114a, 0x99157736, 0x3ff8f1ae, 0xa2e3976c, 0x3c85cc13, + 0xd0282c8a, 0x3ff902fe, 0x85fe3fd2, 0x3c9592ca, 0x0b91ffc6, + 0x3ff9145b, 0x2e582524, 0xbc9dd679, 0x53aa2fe2, 0x3ff925c3, + 0xa639db7f, 0xbc83455f, 0xb0cdc5e5, 0x3ff93737, 0x81b57ebc, + 0xbc675fc7, 0x2b5f98e5, 0x3ff948b8, 0x797d2d99, 0xbc8dc3d6, + 0xcbc8520f, 0x3ff95a44, 0x96a5f039, 0xbc764b7c, 0x9a7670b3, + 0x3ff96bdd, 0x7f19c896, 0xbc5ba596, 0x9fde4e50, 0x3ff97d82, + 0x7c1b85d1, 0xbc9d185b, 0xe47a22a2, 0x3ff98f33, 0xa24c78ec, + 0x3c7cabda, 0x70ca07ba, 0x3ff9a0f1, 0x91cee632, 0xbc9173bd, + 0x4d53fe0d, 0x3ff9b2bb, 0x4df6d518, 0xbc9dd84e, 0x82a3f090, + 0x3ff9c491, 0xb071f2be, 0x3c7c7c46, 0x194bb8d5, 0x3ff9d674, + 0xa3dd8233, 0xbc9516be, 0x19e32323, 0x3ff9e863, 0x78e64c6e, + 0x3c7824ca, 0x8d07f29e, 0x3ff9fa5e, 0xaaf1face, 0xbc84a9ce, + 0x7b5de565, 0x3ffa0c66, 0x5d1cd533, 0xbc935949, 0xed8eb8bb, + 0x3ffa1e7a, 0xee8be70e, 0x3c9c6618, 0xec4a2d33, 0x3ffa309b, + 0x7ddc36ab, 0x3c96305c, 0x80460ad8, 0x3ffa42c9, 0x589fb120, + 0xbc9aa780, 0xb23e255d, 0x3ffa5503, 0xdb8d41e1, 0xbc9d2f6e, + 0x8af46052, 0x3ffa674a, 0x30670366, 0x3c650f56, 0x1330b358, + 0x3ffa799e, 0xcac563c7, 0x3c9bcb7e, 0x53c12e59, 0x3ffa8bfe, + 0xb2ba15a9, 0xbc94f867, 0x5579fdbf, 0x3ffa9e6b, 0x0ef7fd31, + 0x3c90fac9, 0x21356eba, 0x3ffab0e5, 0xdae94545, 0x3c889c31, + 0xbfd3f37a, 0x3ffac36b, 0xcae76cd0, 0xbc8f9234, 0x3a3c2774, + 0x3ffad5ff, 0xb6b1b8e5, 0x3c97ef3b, 0x995ad3ad, 0x3ffae89f, + 0x345dcc81, 0x3c97a1cd, 0xe622f2ff, 0x3ffafb4c, 0x0f315ecd, + 0xbc94b2fc, 0x298db666, 0x3ffb0e07, 0x4c80e425, 0xbc9bdef5, + 0x6c9a8952, 0x3ffb20ce, 0x4a0756cc, 0x3c94dd02, 0xb84f15fb, + 0x3ffb33a2, 0x3084d708, 0xbc62805e, 0x15b749b1, 0x3ffb4684, + 0xe9df7c90, 0xbc7f763d, 0x8de5593a, 0x3ffb5972, 0xbbba6de3, + 0xbc9c71df, 0x29f1c52a, 0x3ffb6c6e, 0x52883f6e, 0x3c92a8f3, + 0xf2fb5e47, 0x3ffb7f76, 0x7e54ac3b, 0xbc75584f, 0xf22749e4, + 0x3ffb928c, 0x54cb65c6, 0xbc9b7216, 0x30a1064a, 0x3ffba5b0, + 0x0e54292e, 0xbc9efcd3, 0xb79a6f1f, 0x3ffbb8e0, 0xc9696205, + 0xbc3f52d1, 0x904bc1d2, 0x3ffbcc1e, 0x7a2d9e84, 0x3c823dd0, + 0xc3f3a207, 0x3ffbdf69, 0x60ea5b53, 0xbc3c2623, 0x5bd71e09, + 0x3ffbf2c2, 0x3f6b9c73, 0xbc9efdca, 0x6141b33d, 0x3ffc0628, + 0xa1fbca34, 0xbc8d8a5a, 0xdd85529c, 0x3ffc199b, 0x895048dd, + 0x3c811065, 0xd9fa652c, 0x3ffc2d1c, 0x17c8a5d7, 0xbc96e516, + 0x5fffd07a, 0x3ffc40ab, 0xe083c60a, 0x3c9b4537, 0x78fafb22, + 0x3ffc5447, 0x2493b5af, 0x3c912f07, 0x2e57d14b, 0x3ffc67f1, + 0xff483cad, 0x3c92884d, 0x8988c933, 0x3ffc7ba8, 0xbe255559, + 0xbc8e76bb, 0x9406e7b5, 0x3ffc8f6d, 0x48805c44, 0x3c71acbc, + 0x5751c4db, 0x3ffca340, 0xd10d08f5, 0xbc87f2be, 0xdcef9069, + 0x3ffcb720, 0xd1e949db, 0x3c7503cb, 0x2e6d1675, 0x3ffccb0f, + 0x86009092, 0xbc7d220f, 0x555dc3fa, 0x3ffcdf0b, 0x53829d72, + 0xbc8dd83b, 0x5b5bab74, 0x3ffcf315, 0xb86dff57, 0xbc9a08e9, + 0x4a07897c, 0x3ffd072d, 0x43797a9c, 0xbc9cbc37, 0x2b08c968, + 0x3ffd1b53, 0x219a36ee, 0x3c955636, 0x080d89f2, 0x3ffd2f87, + 0x719d8578, 0xbc9d487b, 0xeacaa1d6, 0x3ffd43c8, 0xbf5a1614, + 0x3c93db53, 0xdcfba487, 0x3ffd5818, 0xd75b3707, 0x3c82ed02, + 0xe862e6d3, 0x3ffd6c76, 0x4a8165a0, 0x3c5fe87a, 0x16c98398, + 0x3ffd80e3, 0x8beddfe8, 0xbc911ec1, 0x71ff6075, 0x3ffd955d, + 0xbb9af6be, 0x3c9a052d, 0x03db3285, 0x3ffda9e6, 0x696db532, + 0x3c9c2300, 0xd63a8315, 0x3ffdbe7c, 0x926b8be4, 0xbc9b76f1, + 0xf301b460, 0x3ffdd321, 0x78f018c3, 0x3c92da57, 0x641c0658, + 0x3ffde7d5, 0x8e79ba8f, 0xbc9ca552, 0x337b9b5f, 0x3ffdfc97, + 0x4f184b5c, 0xbc91a5cd, 0x6b197d17, 0x3ffe1167, 0xbd5c7f44, + 0xbc72b529, 0x14f5a129, 0x3ffe2646, 0x817a1496, 0xbc97b627, + 0x3b16ee12, 0x3ffe3b33, 0x31fdc68b, 0xbc99f4a4, 0xe78b3ff6, + 0x3ffe502e, 0x80a9cc8f, 0x3c839e89, 0x24676d76, 0x3ffe6539, + 0x7522b735, 0xbc863ff8, 0xfbc74c83, 0x3ffe7a51, 0xca0c8de2, + 0x3c92d522, 0x77cdb740, 0x3ffe8f79, 0x80b054b1, 0xbc910894, + 0xa2a490da, 0x3ffea4af, 0x179c2893, 0xbc9e9c23, 0x867cca6e, + 0x3ffeb9f4, 0x2293e4f2, 0x3c94832f, 0x2d8e67f1, 0x3ffecf48, + 0xb411ad8c, 0xbc9c93f3, 0xa2188510, 0x3ffee4aa, 0xa487568d, + 0x3c91c68d, 0xee615a27, 0x3ffefa1b, 0x86a4b6b0, 0x3c9dc7f4, + 0x1cb6412a, 0x3fff0f9c, 0x65181d45, 0xbc932200, 0x376bba97, + 0x3fff252b, 0xbf0d8e43, 0x3c93a1a5, 0x48dd7274, 0x3fff3ac9, + 0x3ed837de, 0xbc795a5a, 0x5b6e4540, 0x3fff5076, 0x2dd8a18b, + 0x3c99d3e1, 0x798844f8, 0x3fff6632, 0x3539343e, 0x3c9fa37b, + 0xad9cbe14, 0x3fff7bfd, 0xd006350a, 0xbc9dbb12, 0x02243c89, + 0x3fff91d8, 0xa779f689, 0xbc612ea8, 0x819e90d8, 0x3fffa7c1, + 0xf3a5931e, 0x3c874853, 0x3692d514, 0x3fffbdba, 0x15098eb6, + 0xbc796773, 0x2b8f71f1, 0x3fffd3c2, 0x966579e7, 0x3c62eb74, + 0x6b2a23d9, 0x3fffe9d9, 0x7442fde3, 0x3c74a603 + }; + + private static int[] eCoeff = { + 0xe78a6731, 0x3f55d87f, 0xd704a0c0, 0x3fac6b08, 0x6fba4e77, + 0x3f83b2ab, 0xff82c58f, 0x3fcebfbd, 0xfefa39ef, 0x3fe62e42, + 0x00000000, 0x00000000 + }; + + private static int[] coeffH = { + 0x00000000, 0xbfd61a00, 0x00000000, 0xbf5dabe1 + }; + + private static int[] highmaskLogX = { + 0xf8000000, 0xffffffff, 0x00000000, 0xfffff800 + }; + + private static int[] halfmask = { + 0xf8000000, 0xffffffff, 0xf8000000, 0xffffffff + }; + + private static int[] coeffPow = { + 0x6dc96112, 0xbf836578, 0xee241472, 0xbf9b0301, 0x9f95985a, + 0xbfb528db, 0xb3841d2a, 0xbfd619b6, 0x518775e3, 0x3f9004f2, + 0xac8349bb, 0x3fa76c9b, 0x486ececc, 0x3fc4635e, 0x161bb241, + 0xbf5dabe1, 0x9f95985a, 0xbfb528db, 0xf8b5787d, 0x3ef2531e, + 0x486ececb, 0x3fc4635e, 0x412055cc, 0xbdd61bb2 + }; + + private static int[] lTblPow = { + 0x00000000, 0x3ff00000, 0x00000000, 0x00000000, 0x20000000, + 0x3feff00a, 0x96621f95, 0x3e5b1856, 0xe0000000, 0x3fefe019, + 0xe5916f9e, 0xbe325278, 0x00000000, 0x3fefd02f, 0x859a1062, + 0x3e595fb7, 0xc0000000, 0x3fefc049, 0xb245f18f, 0xbe529c38, + 0xe0000000, 0x3fefb069, 0xad2880a7, 0xbe501230, 0x60000000, + 0x3fefa08f, 0xc8e72420, 0x3e597bd1, 0x80000000, 0x3fef90ba, + 0xc30c4500, 0xbe5d6c75, 0xe0000000, 0x3fef80ea, 0x02c63f43, + 0x3e2e1318, 0xc0000000, 0x3fef7120, 0xb3d4cccc, 0xbe44c52a, + 0x00000000, 0x3fef615c, 0xdbd91397, 0xbe4e7d6c, 0xa0000000, + 0x3fef519c, 0x65c5cd68, 0xbe522dc8, 0xa0000000, 0x3fef41e2, + 0x46d1306c, 0xbe5a840e, 0xe0000000, 0x3fef322d, 0xd2980e94, + 0x3e5071af, 0xa0000000, 0x3fef227e, 0x773abade, 0xbe5891e5, + 0xa0000000, 0x3fef12d4, 0xdc6bf46b, 0xbe5cccbe, 0xe0000000, + 0x3fef032f, 0xbc7247fa, 0xbe2bab83, 0x80000000, 0x3feef390, + 0xbcaa1e46, 0xbe53bb3b, 0x60000000, 0x3feee3f6, 0x5f6c682d, + 0xbe54c619, 0x80000000, 0x3feed461, 0x5141e368, 0xbe4b6d86, + 0xe0000000, 0x3feec4d1, 0xec678f76, 0xbe369af6, 0x80000000, + 0x3feeb547, 0x41301f55, 0xbe2d4312, 0x60000000, 0x3feea5c2, + 0x676da6bd, 0xbe4d8dd0, 0x60000000, 0x3fee9642, 0x57a891c4, + 0x3e51f991, 0xa0000000, 0x3fee86c7, 0xe4eb491e, 0x3e579bf9, + 0x20000000, 0x3fee7752, 0xfddc4a2c, 0xbe3356e6, 0xc0000000, + 0x3fee67e1, 0xd75b5bf1, 0xbe449531, 0x80000000, 0x3fee5876, + 0xbd423b8e, 0x3df54fe4, 0x60000000, 0x3fee4910, 0x330e51b9, + 0x3e54289c, 0x80000000, 0x3fee39af, 0x8651a95f, 0xbe55aad6, + 0xa0000000, 0x3fee2a53, 0x5e98c708, 0xbe2fc4a9, 0xe0000000, + 0x3fee1afc, 0x0989328d, 0x3e23958c, 0x40000000, 0x3fee0bab, + 0xee642abd, 0xbe425dd8, 0xa0000000, 0x3fedfc5e, 0xc394d236, + 0x3e526362, 0x20000000, 0x3feded17, 0xe104aa8e, 0x3e4ce247, + 0xc0000000, 0x3fedddd4, 0x265a9be4, 0xbe5bb77a, 0x40000000, + 0x3fedce97, 0x0ecac52f, 0x3e4a7cb1, 0xe0000000, 0x3fedbf5e, + 0x124cb3b8, 0x3e257024, 0x80000000, 0x3fedb02b, 0xe6d4febe, + 0xbe2033ee, 0x20000000, 0x3feda0fd, 0x39cca00e, 0xbe3ddabc, + 0xc0000000, 0x3fed91d3, 0xef8a552a, 0xbe543390, 0x40000000, + 0x3fed82af, 0xb8e85204, 0x3e513850, 0xe0000000, 0x3fed738f, + 0x3d59fe08, 0xbe5db728, 0x40000000, 0x3fed6475, 0x3aa7ead1, + 0x3e58804b, 0xc0000000, 0x3fed555f, 0xf8a35ba9, 0xbe5298b0, + 0x00000000, 0x3fed464f, 0x9a88dd15, 0x3e5a8cdb, 0x40000000, + 0x3fed3743, 0xb0b0a190, 0x3e598635, 0x80000000, 0x3fed283c, + 0xe2113295, 0xbe5c1119, 0x80000000, 0x3fed193a, 0xafbf1728, + 0xbe492e9c, 0x60000000, 0x3fed0a3d, 0xe4a4ccf3, 0x3e19b90e, + 0x20000000, 0x3fecfb45, 0xba3cbeb8, 0x3e406b50, 0xc0000000, + 0x3fecec51, 0x110f7ddd, 0x3e0d6806, 0x40000000, 0x3fecdd63, + 0x7dd7d508, 0xbe5a8943, 0x80000000, 0x3fecce79, 0x9b60f271, + 0xbe50676a, 0x80000000, 0x3fecbf94, 0x0b9ad660, 0x3e59174f, + 0x60000000, 0x3fecb0b4, 0x00823d9c, 0x3e5bbf72, 0x20000000, + 0x3feca1d9, 0x38a6ec89, 0xbe4d38f9, 0x80000000, 0x3fec9302, + 0x3a0b7d8e, 0x3e53dbfd, 0xc0000000, 0x3fec8430, 0xc6826b34, + 0xbe27c5c9, 0xc0000000, 0x3fec7563, 0x0c706381, 0xbe593653, + 0x60000000, 0x3fec669b, 0x7df34ec7, 0x3e461ab5, 0xe0000000, + 0x3fec57d7, 0x40e5e7e8, 0xbe5c3dae, 0x00000000, 0x3fec4919, + 0x5602770f, 0xbe55219d, 0xc0000000, 0x3fec3a5e, 0xec7911eb, + 0x3e5a5d25, 0x60000000, 0x3fec2ba9, 0xb39ea225, 0xbe53c00b, + 0x80000000, 0x3fec1cf8, 0x967a212e, 0x3e5a8ddf, 0x60000000, + 0x3fec0e4c, 0x580798bd, 0x3e5f53ab, 0x00000000, 0x3febffa5, + 0xb8282df6, 0xbe46b874, 0x20000000, 0x3febf102, 0xe33a6729, + 0x3e54963f, 0x00000000, 0x3febe264, 0x3b53e88a, 0xbe3adce1, + 0x60000000, 0x3febd3ca, 0xc2585084, 0x3e5cde9f, 0x80000000, + 0x3febc535, 0xa335c5ee, 0xbe39fd9c, 0x20000000, 0x3febb6a5, + 0x7325b04d, 0x3e42ba15, 0x60000000, 0x3feba819, 0x1564540f, + 0x3e3a9f35, 0x40000000, 0x3feb9992, 0x83fff592, 0xbe5465ce, + 0xa0000000, 0x3feb8b0f, 0xb9da63d3, 0xbe4b1a0a, 0x80000000, + 0x3feb7c91, 0x6d6f1ea4, 0x3e557657, 0x00000000, 0x3feb6e18, + 0x5e80a1bf, 0x3e4ddbb6, 0x00000000, 0x3feb5fa3, 0x1c9eacb5, + 0x3e592877, 0xa0000000, 0x3feb5132, 0x6d40beb3, 0xbe51858c, + 0xa0000000, 0x3feb42c6, 0xd740c67b, 0x3e427ad2, 0x40000000, + 0x3feb345f, 0xa3e0ccee, 0xbe5c2fc4, 0x40000000, 0x3feb25fc, + 0x8e752b50, 0xbe3da3c2, 0xc0000000, 0x3feb179d, 0xa892e7de, + 0x3e1fb481, 0xc0000000, 0x3feb0943, 0x21ed71e9, 0xbe365206, + 0x20000000, 0x3feafaee, 0x0e1380a3, 0x3e5c5b7b, 0x20000000, + 0x3feaec9d, 0x3c3d640e, 0xbe5dbbd0, 0x60000000, 0x3feade50, + 0x8f97a715, 0x3e3a8ec5, 0x20000000, 0x3fead008, 0x23ab2839, + 0x3e2fe98a, 0x40000000, 0x3feac1c4, 0xf4bbd50f, 0x3e54d8f6, + 0xe0000000, 0x3feab384, 0x14757c4d, 0xbe48774c, 0xc0000000, + 0x3feaa549, 0x7c7b0eea, 0x3e5b51bb, 0x20000000, 0x3fea9713, + 0xf56f7013, 0x3e386200, 0xe0000000, 0x3fea88e0, 0xbe428ebe, + 0xbe514af5, 0xe0000000, 0x3fea7ab2, 0x8d0e4496, 0x3e4f9165, + 0x60000000, 0x3fea6c89, 0xdbacc5d5, 0xbe5c063b, 0x20000000, + 0x3fea5e64, 0x3f19d970, 0xbe5a0c8c, 0x20000000, 0x3fea5043, + 0x09ea3e6b, 0x3e5065dc, 0x80000000, 0x3fea4226, 0x78df246c, + 0x3e5e05f6, 0x40000000, 0x3fea340e, 0x4057d4a0, 0x3e431b2b, + 0x40000000, 0x3fea25fa, 0x82867bb5, 0x3e4b76be, 0xa0000000, + 0x3fea17ea, 0x9436f40a, 0xbe5aad39, 0x20000000, 0x3fea09df, + 0x4b5253b3, 0x3e46380b, 0x00000000, 0x3fe9fbd8, 0x8fc52466, + 0xbe386f9b, 0x20000000, 0x3fe9edd5, 0x22d3f344, 0xbe538347, + 0x60000000, 0x3fe9dfd6, 0x1ac33522, 0x3e5dbc53, 0x00000000, + 0x3fe9d1dc, 0xeabdff1d, 0x3e40fc0c, 0xe0000000, 0x3fe9c3e5, + 0xafd30e73, 0xbe585e63, 0xe0000000, 0x3fe9b5f3, 0xa52f226a, + 0xbe43e8f9, 0x20000000, 0x3fe9a806, 0xecb8698d, 0xbe515b36, + 0x80000000, 0x3fe99a1c, 0xf2b4e89d, 0x3e48b62b, 0x20000000, + 0x3fe98c37, 0x7c9a88fb, 0x3e44414c, 0x00000000, 0x3fe97e56, + 0xda015741, 0xbe5d13ba, 0xe0000000, 0x3fe97078, 0x5fdace06, + 0x3e51b947, 0x00000000, 0x3fe962a0, 0x956ca094, 0x3e518785, + 0x40000000, 0x3fe954cb, 0x01164c1d, 0x3e5d5b57, 0xc0000000, + 0x3fe946fa, 0xe63b3767, 0xbe4f84e7, 0x40000000, 0x3fe9392e, + 0xe57cc2a9, 0x3e34eda3, 0xe0000000, 0x3fe92b65, 0x8c75b544, + 0x3e5766a0, 0xc0000000, 0x3fe91da1, 0x37d1d087, 0xbe5e2ab1, + 0x80000000, 0x3fe90fe1, 0xa953dc20, 0x3e5fa1f3, 0x80000000, + 0x3fe90225, 0xdbd3f369, 0x3e47d6db, 0xa0000000, 0x3fe8f46d, + 0x1c9be989, 0xbe5e2b0a, 0xa0000000, 0x3fe8e6b9, 0x3c93d76a, + 0x3e5c8618, 0xe0000000, 0x3fe8d909, 0x2182fc9a, 0xbe41aa9e, + 0x20000000, 0x3fe8cb5e, 0xe6b3539d, 0xbe530d19, 0x60000000, + 0x3fe8bdb6, 0x49e58cc3, 0xbe3bb374, 0xa0000000, 0x3fe8b012, + 0xa7cfeb8f, 0x3e56c412, 0x00000000, 0x3fe8a273, 0x8d52bc19, + 0x3e1429b8, 0x60000000, 0x3fe894d7, 0x4dc32c6c, 0xbe48604c, + 0xc0000000, 0x3fe8873f, 0x0c868e56, 0xbe564ee5, 0x00000000, + 0x3fe879ac, 0x56aee828, 0x3e5e2fd8, 0x60000000, 0x3fe86c1c, + 0x7ceab8ec, 0x3e493365, 0xc0000000, 0x3fe85e90, 0x78d4dadc, + 0xbe4f7f25, 0x00000000, 0x3fe85109, 0x0ccd8280, 0x3e31e7a2, + 0x40000000, 0x3fe84385, 0x34ba4e15, 0x3e328077, 0x80000000, + 0x3fe83605, 0xa670975a, 0xbe53eee5, 0xa0000000, 0x3fe82889, + 0xf61b77b2, 0xbe43a20a, 0xa0000000, 0x3fe81b11, 0x13e6643b, + 0x3e5e5fe5, 0xc0000000, 0x3fe80d9d, 0x82cc94e8, 0xbe5ff1f9, + 0xa0000000, 0x3fe8002d, 0x8a0c9c5d, 0xbe42b0e7, 0x60000000, + 0x3fe7f2c1, 0x22a16f01, 0x3e5d9ea0, 0x20000000, 0x3fe7e559, + 0xc38cd451, 0x3e506963, 0xc0000000, 0x3fe7d7f4, 0x9902bc71, + 0x3e4503d7, 0x40000000, 0x3fe7ca94, 0xdef2a3c0, 0x3e3d98ed, + 0xa0000000, 0x3fe7bd37, 0xed49abb0, 0x3e24c1ff, 0xe0000000, + 0x3fe7afde, 0xe3b0be70, 0xbe40c467, 0x00000000, 0x3fe7a28a, + 0xaf9f193c, 0xbe5dff6c, 0xe0000000, 0x3fe79538, 0xb74cf6b6, + 0xbe258ed0, 0xa0000000, 0x3fe787eb, 0x1d9127c7, 0x3e345fb0, + 0x40000000, 0x3fe77aa2, 0x1028c21d, 0xbe4619bd, 0xa0000000, + 0x3fe76d5c, 0x7cb0b5e4, 0x3e40f1a2, 0xe0000000, 0x3fe7601a, + 0x2b1bc4ad, 0xbe32e8bb, 0xe0000000, 0x3fe752dc, 0x6839f64e, + 0x3e41f57b, 0xc0000000, 0x3fe745a2, 0xc4121f7e, 0xbe52c40a, + 0x60000000, 0x3fe7386c, 0xd6852d72, 0xbe5c4e6b, 0xc0000000, + 0x3fe72b39, 0x91d690f7, 0xbe57f88f, 0xe0000000, 0x3fe71e0a, + 0x627a2159, 0xbe4425d5, 0xc0000000, 0x3fe710df, 0x50a54033, + 0x3e422b7e, 0x60000000, 0x3fe703b8, 0x3b0b5f91, 0x3e5d3857, + 0xe0000000, 0x3fe6f694, 0x84d628a2, 0xbe51f090, 0x00000000, + 0x3fe6e975, 0x306d8894, 0xbe414d83, 0xe0000000, 0x3fe6dc58, + 0x30bf24aa, 0xbe4650ca, 0x80000000, 0x3fe6cf40, 0xd4628d69, + 0xbe5db007, 0xc0000000, 0x3fe6c22b, 0xa2aae57b, 0xbe31d279, + 0xc0000000, 0x3fe6b51a, 0x860edf7e, 0xbe2d4c4a, 0x80000000, + 0x3fe6a80d, 0xf3559341, 0xbe5f7e98, 0xe0000000, 0x3fe69b03, + 0xa885899e, 0xbe5c2011, 0xe0000000, 0x3fe68dfd, 0x2bdc6d37, + 0x3e224a82, 0xa0000000, 0x3fe680fb, 0xc12ad1b9, 0xbe40cf56, + 0x00000000, 0x3fe673fd, 0x1bcdf659, 0xbdf52f2d, 0x00000000, + 0x3fe66702, 0x5df10408, 0x3e5663e0, 0xc0000000, 0x3fe65a0a, + 0xa4070568, 0xbe40b12f, 0x00000000, 0x3fe64d17, 0x71c54c47, + 0x3e5f5e8b, 0x00000000, 0x3fe64027, 0xbd4b7e83, 0x3e42ead6, + 0xa0000000, 0x3fe6333a, 0x61598bd2, 0xbe4c48d4, 0xc0000000, + 0x3fe62651, 0x6f538d61, 0x3e548401, 0xa0000000, 0x3fe6196c, + 0x14344120, 0xbe529af6, 0x00000000, 0x3fe60c8b, 0x5982c587, + 0xbe3e1e4f, 0x00000000, 0x3fe5ffad, 0xfe51d4ea, 0xbe4c897a, + 0x80000000, 0x3fe5f2d2, 0xfd46ebe1, 0x3e552e00, 0xa0000000, + 0x3fe5e5fb, 0xa4695699, 0x3e5ed471, 0x60000000, 0x3fe5d928, + 0x80d118ae, 0x3e456b61, 0xa0000000, 0x3fe5cc58, 0x304c330b, + 0x3e54dc29, 0x80000000, 0x3fe5bf8c, 0x0af2dedf, 0xbe3aa9bd, + 0xe0000000, 0x3fe5b2c3, 0x15fc9258, 0xbe479a37, 0xc0000000, + 0x3fe5a5fe, 0x9292c7ea, 0x3e188650, 0x20000000, 0x3fe5993d, + 0x33b4d380, 0x3e5d6d93, 0x20000000, 0x3fe58c7f, 0x02fd16c7, + 0x3e2fe961, 0xa0000000, 0x3fe57fc4, 0x4a05edb6, 0xbe4d55b4, + 0xa0000000, 0x3fe5730d, 0x3d443abb, 0xbe5e6954, 0x00000000, + 0x3fe5665a, 0x024acfea, 0x3e50e61b, 0x00000000, 0x3fe559aa, + 0xcc9edd09, 0xbe325403, 0x60000000, 0x3fe54cfd, 0x1fe26950, + 0x3e5d500e, 0x60000000, 0x3fe54054, 0x6c5ae164, 0xbe4a79b4, + 0xc0000000, 0x3fe533ae, 0x154b0287, 0xbe401571, 0xa0000000, + 0x3fe5270c, 0x0673f401, 0xbe56e56b, 0xe0000000, 0x3fe51a6d, + 0x751b639c, 0x3e235269, 0xa0000000, 0x3fe50dd2, 0x7c7b2bed, + 0x3ddec887, 0xc0000000, 0x3fe5013a, 0xafab4e17, 0x3e5e7575, + 0x60000000, 0x3fe4f4a6, 0x2e308668, 0x3e59aed6, 0x80000000, + 0x3fe4e815, 0xf33e2a76, 0xbe51f184, 0xe0000000, 0x3fe4db87, + 0x839f3e3e, 0x3e57db01, 0xc0000000, 0x3fe4cefd, 0xa9eda7bb, + 0x3e535e0f, 0x00000000, 0x3fe4c277, 0x2a8f66a5, 0x3e5ce451, + 0xc0000000, 0x3fe4b5f3, 0x05192456, 0xbe4e8518, 0xc0000000, + 0x3fe4a973, 0x4aa7cd1d, 0x3e46784a, 0x40000000, 0x3fe49cf7, + 0x8e23025e, 0xbe5749f2, 0x00000000, 0x3fe4907e, 0x18d30215, + 0x3e360f39, 0x20000000, 0x3fe48408, 0x63dcf2f3, 0x3e5e00fe, + 0xc0000000, 0x3fe47795, 0x46182d09, 0xbe5173d9, 0xa0000000, + 0x3fe46b26, 0x8f0e62aa, 0xbe48f281, 0xe0000000, 0x3fe45eba, + 0x5775c40c, 0xbe56aad4, 0x60000000, 0x3fe45252, 0x0fe25f69, + 0x3e48bd71, 0x40000000, 0x3fe445ed, 0xe9989ec5, 0x3e590d97, + 0x80000000, 0x3fe4398b, 0xb3d9ffe3, 0x3e479dbc, 0x20000000, + 0x3fe42d2d, 0x388e4d2e, 0xbe5eed80, 0xe0000000, 0x3fe420d1, + 0x6f797c18, 0x3e554b4c, 0x20000000, 0x3fe4147a, 0x31048bb4, + 0xbe5b1112, 0x80000000, 0x3fe40825, 0x2efba4f9, 0x3e48ebc7, + 0x40000000, 0x3fe3fbd4, 0x50201119, 0x3e40b701, 0x40000000, + 0x3fe3ef86, 0x0a4db32c, 0x3e551de8, 0xa0000000, 0x3fe3e33b, + 0x0c9c148b, 0xbe50c1f6, 0x20000000, 0x3fe3d6f4, 0xc9129447, + 0x3e533fa0, 0x00000000, 0x3fe3cab0, 0xaae5b5a0, 0xbe22b68e, + 0x20000000, 0x3fe3be6f, 0x02305e8a, 0xbe54fc08, 0x60000000, + 0x3fe3b231, 0x7f908258, 0x3e57dc05, 0x00000000, 0x3fe3a5f7, + 0x1a09af78, 0x3e08038b, 0xe0000000, 0x3fe399bf, 0x490643c1, + 0xbe5dbe42, 0xe0000000, 0x3fe38d8b, 0x5e8ad724, 0xbe3c2b72, + 0x20000000, 0x3fe3815b, 0xc67196b6, 0x3e1713cf, 0xa0000000, + 0x3fe3752d, 0x6182e429, 0xbe3ec14c, 0x40000000, 0x3fe36903, + 0xab6eb1ae, 0x3e5a2cc5, 0x40000000, 0x3fe35cdc, 0xfe5dc064, + 0xbe5c5878, 0x40000000, 0x3fe350b8, 0x0ba6b9e4, 0x3e51619b, + 0x80000000, 0x3fe34497, 0x857761aa, 0x3e5fff53, 0x00000000, + 0x3fe3387a, 0xf872d68c, 0x3e484f4d, 0xa0000000, 0x3fe32c5f, + 0x087e97c2, 0x3e52842e, 0x80000000, 0x3fe32048, 0x73d6d0c0, + 0xbe503edf, 0x80000000, 0x3fe31434, 0x0c1456a1, 0xbe5f72ad, + 0xa0000000, 0x3fe30823, 0x83a1a4d5, 0xbe5e65cc, 0xe0000000, + 0x3fe2fc15, 0x855a7390, 0xbe506438, 0x40000000, 0x3fe2f00b, + 0xa2898287, 0x3e3d22a2, 0xe0000000, 0x3fe2e403, 0x8b56f66f, + 0xbe5aa5fd, 0x80000000, 0x3fe2d7ff, 0x52db119a, 0x3e3a2e3d, + 0x60000000, 0x3fe2cbfe, 0xe2ddd4c0, 0xbe586469, 0x40000000, + 0x3fe2c000, 0x6b01bf10, 0x3e352b9d, 0x40000000, 0x3fe2b405, + 0xb07a1cdf, 0x3e5c5cda, 0x80000000, 0x3fe2a80d, 0xc7b5f868, + 0xbe5668b3, 0xc0000000, 0x3fe29c18, 0x185edf62, 0xbe563d66, + 0x00000000, 0x3fe29027, 0xf729e1cc, 0x3e59a9a0, 0x80000000, + 0x3fe28438, 0x6433c727, 0xbe43cc89, 0x00000000, 0x3fe2784d, + 0x41782631, 0xbe30750c, 0xa0000000, 0x3fe26c64, 0x914911b7, + 0xbe58290e, 0x40000000, 0x3fe2607f, 0x3dcc73e1, 0xbe4269cd, + 0x00000000, 0x3fe2549d, 0x2751bf70, 0xbe5a6998, 0xc0000000, + 0x3fe248bd, 0x4248b9fb, 0xbe4ddb00, 0x80000000, 0x3fe23ce1, + 0xf35cf82f, 0x3e561b71, 0x60000000, 0x3fe23108, 0x8e481a2d, + 0x3e518fb9, 0x60000000, 0x3fe22532, 0x5ab96edc, 0xbe5fafc5, + 0x40000000, 0x3fe2195f, 0x80943911, 0xbe07f819, 0x40000000, + 0x3fe20d8f, 0x386f2d6c, 0xbe54ba8b, 0x40000000, 0x3fe201c2, + 0xf29664ac, 0xbe5eb815, 0x20000000, 0x3fe1f5f8, 0x64f03390, + 0x3e5e320c, 0x20000000, 0x3fe1ea31, 0x747ff696, 0x3e5ef0a5, + 0x40000000, 0x3fe1de6d, 0x3e9ceb51, 0xbe5f8d27, 0x20000000, + 0x3fe1d2ac, 0x4ae0b55e, 0x3e5faa21, 0x20000000, 0x3fe1c6ee, + 0x28569a5e, 0x3e598a4f, 0x20000000, 0x3fe1bb33, 0x54b33e07, + 0x3e46130a, 0x20000000, 0x3fe1af7b, 0x024f1078, 0xbe4dbf93, + 0x00000000, 0x3fe1a3c6, 0xb0783bfa, 0x3e419248, 0xe0000000, + 0x3fe19813, 0x2f02b836, 0x3e4e02b7, 0xc0000000, 0x3fe18c64, + 0x28dec9d4, 0x3e09064f, 0x80000000, 0x3fe180b8, 0x45cbf406, + 0x3e5b1f46, 0x40000000, 0x3fe1750f, 0x03d9964c, 0x3e5b0a79, + 0x00000000, 0x3fe16969, 0x8b5b882b, 0xbe238086, 0xa0000000, + 0x3fe15dc5, 0x73bad6f8, 0xbdf1fca4, 0x20000000, 0x3fe15225, + 0x5385769c, 0x3e5e8d76, 0xa0000000, 0x3fe14687, 0x1676dc6b, + 0x3e571d08, 0x20000000, 0x3fe13aed, 0xa8c41c7f, 0xbe598a25, + 0x60000000, 0x3fe12f55, 0xc4e1aaf0, 0x3e435277, 0xa0000000, + 0x3fe123c0, 0x403638e1, 0xbe21aa7c, 0xc0000000, 0x3fe1182e, + 0x557a092b, 0xbdd0116b, 0xc0000000, 0x3fe10c9f, 0x7d779f66, + 0x3e4a61ba, 0xc0000000, 0x3fe10113, 0x2b09c645, 0xbe5d586e, + 0x20000000, 0x3fe0ea04, 0xea2cad46, 0x3e5aa97c, 0x20000000, + 0x3fe0d300, 0x23190e54, 0x3e50f1a7, 0xa0000000, 0x3fe0bc07, + 0x1379a5a6, 0xbe51619d, 0x60000000, 0x3fe0a51a, 0x926a3d4a, + 0x3e5cf019, 0xa0000000, 0x3fe08e38, 0xa8c24358, 0x3e35241e, + 0x20000000, 0x3fe07762, 0x24317e7a, 0x3e512cfa, 0x00000000, + 0x3fe06097, 0xfd9cf274, 0xbe55bef3, 0x00000000, 0x3fe049d7, + 0x3689b49d, 0xbe36d26d, 0x40000000, 0x3fe03322, 0xf72ef6c4, + 0xbe54cd08, 0xa0000000, 0x3fe01c78, 0x23702d2d, 0xbe5900bf, + 0x00000000, 0x3fe005da, 0x3f59c14c, 0x3e57d80b, 0x40000000, + 0x3fdfde8d, 0xad67766d, 0xbe57fad4, 0x40000000, 0x3fdfb17c, + 0x644f4ae7, 0x3e1ee43b, 0x40000000, 0x3fdf8481, 0x903234d2, + 0x3e501a86, 0x40000000, 0x3fdf579c, 0xafe9e509, 0xbe267c3e, + 0x00000000, 0x3fdf2acd, 0xb7dfda0b, 0xbe48149b, 0x40000000, + 0x3fdefe13, 0x3b94305e, 0x3e5f4ea7, 0x80000000, 0x3fded16f, + 0x5d95da61, 0xbe55c198, 0x00000000, 0x3fdea4e1, 0x406960c9, + 0xbdd99a19, 0x00000000, 0x3fde7868, 0xd22f3539, 0x3e470c78, + 0x80000000, 0x3fde4c04, 0x83eec535, 0xbe3e1232, 0x40000000, + 0x3fde1fb6, 0x3dfbffcb, 0xbe4b7d71, 0x40000000, 0x3fddf37d, + 0x7e1be4e0, 0xbe5b8f8f, 0x40000000, 0x3fddc759, 0x46dae887, + 0xbe350458, 0x80000000, 0x3fdd9b4a, 0xed6ecc49, 0xbe5f0045, + 0x80000000, 0x3fdd6f50, 0x2e9e883c, 0x3e2915da, 0x80000000, + 0x3fdd436b, 0xf0bccb32, 0x3e4a68c9, 0x80000000, 0x3fdd179b, + 0x9bbfc779, 0xbe54a26a, 0x00000000, 0x3fdcebe0, 0x7cea33ab, + 0x3e43c6b7, 0x40000000, 0x3fdcc039, 0xe740fd06, 0x3e5526c2, + 0x40000000, 0x3fdc94a7, 0x9eadeb1a, 0xbe396d8d, 0xc0000000, + 0x3fdc6929, 0xf0a8f95a, 0xbe5c0ab2, 0x80000000, 0x3fdc3dc0, + 0x6ee2693b, 0x3e0992e6, 0xc0000000, 0x3fdc126b, 0x5ac6b581, + 0xbe2834b6, 0x40000000, 0x3fdbe72b, 0x8cc226ff, 0x3e3596a6, + 0x00000000, 0x3fdbbbff, 0xf92a74bb, 0x3e3c5813, 0x00000000, + 0x3fdb90e7, 0x479664c0, 0xbe50d644, 0x00000000, 0x3fdb65e3, + 0x5004975b, 0xbe55258f, 0x00000000, 0x3fdb3af3, 0xe4b23194, + 0xbe588407, 0xc0000000, 0x3fdb1016, 0xe65d4d0a, 0x3e527c26, + 0x80000000, 0x3fdae54e, 0x814fddd6, 0x3e5962a2, 0x40000000, + 0x3fdaba9a, 0xe19d0913, 0xbe562f4e, 0x80000000, 0x3fda8ff9, + 0x43cfd006, 0xbe4cfdeb, 0x40000000, 0x3fda656c, 0x686f0a4e, + 0x3e5e47a8, 0xc0000000, 0x3fda3af2, 0x7200d410, 0x3e5e1199, + 0xc0000000, 0x3fda108c, 0xabd2266e, 0x3e5ee4d1, 0x40000000, + 0x3fd9e63a, 0x396f8f2c, 0x3e4dbffb, 0x00000000, 0x3fd9bbfb, + 0xe32b25dd, 0x3e5c3a54, 0x40000000, 0x3fd991cf, 0x431e4035, + 0xbe457925, 0x80000000, 0x3fd967b6, 0x7bed3dd3, 0x3e40c61d, + 0x00000000, 0x3fd93db1, 0xd7449365, 0x3e306419, 0x80000000, + 0x3fd913be, 0x1746e791, 0x3e56fcfc, 0x40000000, 0x3fd8e9df, + 0xf3a9028b, 0xbe5041b9, 0xc0000000, 0x3fd8c012, 0x56840c50, + 0xbe26e20a, 0x40000000, 0x3fd89659, 0x19763102, 0xbe51f466, + 0x80000000, 0x3fd86cb2, 0x7032de7c, 0xbe4d298a, 0x80000000, + 0x3fd8431e, 0xdeb39fab, 0xbe4361eb, 0x40000000, 0x3fd8199d, + 0x5d01cbe0, 0xbe5425b3, 0x80000000, 0x3fd7f02e, 0x3ce99aa9, + 0x3e146fa8, 0x80000000, 0x3fd7c6d2, 0xd1a262b9, 0xbe5a1a69, + 0xc0000000, 0x3fd79d88, 0x8606c236, 0x3e423a08, 0x80000000, + 0x3fd77451, 0x8fd1e1b7, 0x3e5a6a63, 0xc0000000, 0x3fd74b2c, + 0xe491456a, 0x3e42c1ca, 0x40000000, 0x3fd7221a, 0x4499a6d7, + 0x3e36a69a, 0x00000000, 0x3fd6f91a, 0x5237df94, 0xbe0f8f02, + 0x00000000, 0x3fd6d02c, 0xb6482c6e, 0xbe5abcf7, 0x00000000, + 0x3fd6a750, 0x1919fd61, 0xbe57ade2, 0x00000000, 0x3fd67e86, + 0xaa7a994d, 0xbe3f3fbd, 0x00000000, 0x3fd655ce, 0x67db014c, + 0x3e33c550, 0x00000000, 0x3fd62d28, 0xa82856b7, 0xbe1409d1, + 0xc0000000, 0x3fd60493, 0x1e6a300d, 0x3e55d899, 0x80000000, + 0x3fd5dc11, 0x1222bd5c, 0xbe35bfc0, 0xc0000000, 0x3fd5b3a0, + 0x6e8dc2d3, 0x3e5d4d79, 0x00000000, 0x3fd58b42, 0xe0e4ace6, + 0xbe517303, 0x80000000, 0x3fd562f4, 0xb306e0a8, 0x3e5edf0f, + 0xc0000000, 0x3fd53ab8, 0x6574bc54, 0x3e5ee859, 0x80000000, + 0x3fd5128e, 0xea902207, 0x3e5f6188, 0xc0000000, 0x3fd4ea75, + 0x9f911d79, 0x3e511735, 0x80000000, 0x3fd4c26e, 0xf9c77397, + 0xbe5b1643, 0x40000000, 0x3fd49a78, 0x15fc9258, 0x3e479a37, + 0x80000000, 0x3fd47293, 0xd5a04dd9, 0xbe426e56, 0xc0000000, + 0x3fd44abf, 0xe04042f5, 0x3e56f7c6, 0x40000000, 0x3fd422fd, + 0x1d8bf2c8, 0x3e5d8810, 0x00000000, 0x3fd3fb4c, 0x88a8ddee, + 0xbe311454, 0xc0000000, 0x3fd3d3ab, 0x3e3b5e47, 0xbe5d1b72, + 0x40000000, 0x3fd3ac1c, 0xc2ab5d59, 0x3e31b02b, 0xc0000000, + 0x3fd3849d, 0xd4e34b9e, 0x3e51cb2f, 0x40000000, 0x3fd35d30, + 0x177204fb, 0xbe2b8cd7, 0x80000000, 0x3fd335d3, 0xfcd38c82, + 0xbe4356e1, 0x80000000, 0x3fd30e87, 0x64f54acc, 0xbe4e6224, + 0x00000000, 0x3fd2e74c, 0xaa7975d9, 0x3e5dc0fe, 0x80000000, + 0x3fd2c021, 0x516dab3f, 0xbe50ffa3, 0x40000000, 0x3fd29907, + 0x2bfb7313, 0x3e5674a2, 0xc0000000, 0x3fd271fd, 0x0549fc99, + 0x3e385d29, 0xc0000000, 0x3fd24b04, 0x55b63073, 0xbe500c6d, + 0x00000000, 0x3fd2241c, 0x3f91953a, 0x3e389977, 0xc0000000, + 0x3fd1fd43, 0xa1543f71, 0xbe3487ab, 0xc0000000, 0x3fd1d67b, + 0x4ec8867c, 0x3df6a2dc, 0x00000000, 0x3fd1afc4, 0x4328e3bb, + 0x3e41d9c0, 0x80000000, 0x3fd1891c, 0x2e1cda84, 0x3e3bdd87, + 0x40000000, 0x3fd16285, 0x4b5331ae, 0xbe53128e, 0x00000000, + 0x3fd13bfe, 0xb9aec164, 0xbe52ac98, 0xc0000000, 0x3fd11586, + 0xd91e1316, 0xbe350630, 0x80000000, 0x3fd0ef1f, 0x7cacc12c, + 0x3e3f5219, 0x40000000, 0x3fd0c8c8, 0xbce277b7, 0x3e3d30c0, + 0x00000000, 0x3fd0a281, 0x2a63447d, 0xbe541377, 0x80000000, + 0x3fd07c49, 0xfac483b5, 0xbe5772ec, 0xc0000000, 0x3fd05621, + 0x36b8a570, 0xbe4fd4bd, 0xc0000000, 0x3fd03009, 0xbae505f7, + 0xbe450388, 0x80000000, 0x3fd00a01, 0x3e35aead, 0xbe5430fc, + 0x80000000, 0x3fcfc811, 0x707475ac, 0x3e38806e, 0x80000000, + 0x3fcf7c3f, 0xc91817fc, 0xbe40ccea, 0x80000000, 0x3fcf308c, + 0xae05d5e9, 0xbe4919b8, 0x80000000, 0x3fcee4f8, 0xae6cc9e6, + 0xbe530b94, 0x00000000, 0x3fce9983, 0x1efe3e8e, 0x3e57747e, + 0x00000000, 0x3fce4e2d, 0xda78d9bf, 0xbe59a608, 0x00000000, + 0x3fce02f5, 0x8abe2c2e, 0x3e4a35ad, 0x00000000, 0x3fcdb7dc, + 0x1495450d, 0xbe0872cc, 0x80000000, 0x3fcd6ce1, 0x86ee0ba0, + 0xbe4f59a0, 0x00000000, 0x3fcd2205, 0xe81ca888, 0x3e5402c3, + 0x00000000, 0x3fccd747, 0x3b4424b9, 0x3e5dfdc3, 0x80000000, + 0x3fcc8ca7, 0xd305b56c, 0x3e202da6, 0x00000000, 0x3fcc4226, + 0x399a6910, 0xbe482a1c, 0x80000000, 0x3fcbf7c2, 0x747f7938, + 0xbe587372, 0x80000000, 0x3fcbad7c, 0x6fc246a0, 0x3e50d83d, + 0x00000000, 0x3fcb6355, 0xee9e9be5, 0xbe5c35bd, 0x80000000, + 0x3fcb194a, 0x8416c0bc, 0x3e546d4f, 0x00000000, 0x3fcacf5e, + 0x49f7f08f, 0x3e56da76, 0x00000000, 0x3fca858f, 0x5dc30de2, + 0x3e5f390c, 0x00000000, 0x3fca3bde, 0x950583b6, 0xbe5e4169, + 0x80000000, 0x3fc9f249, 0x33631553, 0x3e52aeb1, 0x00000000, + 0x3fc9a8d3, 0xde8795a6, 0xbe59a504, 0x00000000, 0x3fc95f79, + 0x076bf41e, 0x3e5122fe, 0x80000000, 0x3fc9163c, 0x2914c8e7, + 0x3e3dd064, 0x00000000, 0x3fc8cd1d, 0x3a30eca3, 0xbe21b4aa, + 0x80000000, 0x3fc8841a, 0xb2a96650, 0xbe575444, 0x80000000, + 0x3fc83b34, 0x2376c0cb, 0xbe2a74c7, 0x80000000, 0x3fc7f26b, + 0xd8a0b653, 0xbe5181b6, 0x00000000, 0x3fc7a9bf, 0x32257882, + 0xbe4a78b4, 0x00000000, 0x3fc7612f, 0x1eee8bd9, 0xbe1bfe9d, + 0x80000000, 0x3fc718bb, 0x0c603cc4, 0x3e36fdc9, 0x80000000, + 0x3fc6d064, 0x3728b8cf, 0xbe1e542e, 0x80000000, 0x3fc68829, + 0xc79a4067, 0x3e5c380f, 0x00000000, 0x3fc6400b, 0xf69eac69, + 0x3e550a84, 0x80000000, 0x3fc5f808, 0xb7a780a4, 0x3e5d9224, + 0x80000000, 0x3fc5b022, 0xad9dfb1e, 0xbe55242f, 0x00000000, + 0x3fc56858, 0x659b18be, 0xbe4bfda3, 0x80000000, 0x3fc520a9, + 0x66ee3631, 0xbe57d769, 0x80000000, 0x3fc4d916, 0x1ec62819, + 0x3e2427f7, 0x80000000, 0x3fc4919f, 0xdec25369, 0xbe435431, + 0x00000000, 0x3fc44a44, 0xa8acfc4b, 0xbe3c62e8, 0x00000000, + 0x3fc40304, 0xcf1d3eab, 0xbdfba29f, 0x80000000, 0x3fc3bbdf, + 0x79aba3ea, 0xbdf1b7c8, 0x80000000, 0x3fc374d6, 0xb8d186da, + 0xbe5130cf, 0x80000000, 0x3fc32de8, 0x9d74f152, 0x3e2285b6, + 0x00000000, 0x3fc2e716, 0x50ae7ca9, 0xbe503920, 0x80000000, + 0x3fc2a05e, 0x6caed92e, 0xbe533924, 0x00000000, 0x3fc259c2, + 0x9cb5034e, 0xbe510e31, 0x80000000, 0x3fc21340, 0x12c4d378, + 0xbe540b43, 0x80000000, 0x3fc1ccd9, 0xcc418706, 0x3e59887a, + 0x00000000, 0x3fc1868e, 0x921f4106, 0xbe528e67, 0x80000000, + 0x3fc1405c, 0x3969441e, 0x3e5d8051, 0x00000000, 0x3fc0fa46, + 0xd941ef5b, 0x3e5f9079, 0x80000000, 0x3fc0b44a, 0x5a3e81b2, + 0xbe567691, 0x00000000, 0x3fc06e69, 0x9d66afe7, 0xbe4d43fb, + 0x00000000, 0x3fc028a2, 0x0a92a162, 0xbe52f394, 0x00000000, + 0x3fbfc5ea, 0x209897e5, 0x3e529e37, 0x00000000, 0x3fbf3ac5, + 0x8458bd7b, 0x3e582831, 0x00000000, 0x3fbeafd5, 0xb8d8b4b8, + 0xbe486b4a, 0x00000000, 0x3fbe2518, 0xe0a3b7b6, 0x3e5bafd2, + 0x00000000, 0x3fbd9a90, 0x2bf2710e, 0x3e383b2b, 0x00000000, + 0x3fbd103c, 0x73eb6ab7, 0xbe56d78d, 0x00000000, 0x3fbc861b, + 0x32ceaff5, 0xbe32dc5a, 0x00000000, 0x3fbbfc2e, 0xbee04cb7, + 0xbe4a71a4, 0x00000000, 0x3fbb7274, 0x35ae9577, 0x3e38142f, + 0x00000000, 0x3fbae8ee, 0xcbaddab4, 0xbe5490f0, 0x00000000, + 0x3fba5f9a, 0x95ce1114, 0x3e597c71, 0x00000000, 0x3fb9d67a, + 0x6d7c0f78, 0x3e3abc2d, 0x00000000, 0x3fb94d8d, 0x2841a782, + 0xbe566cbc, 0x00000000, 0x3fb8c4d2, 0x6ed429c6, 0xbe3cfff9, + 0x00000000, 0x3fb83c4a, 0xe4a49fbb, 0xbe552964, 0x00000000, + 0x3fb7b3f4, 0x2193d81e, 0xbe42fa72, 0x00000000, 0x3fb72bd0, + 0xdd70c122, 0x3e527a8c, 0x00000000, 0x3fb6a3df, 0x03108a54, + 0xbe450393, 0x00000000, 0x3fb61c1f, 0x30ff7954, 0x3e565840, + 0x00000000, 0x3fb59492, 0xdedd460c, 0xbe5422b5, 0x00000000, + 0x3fb50d36, 0x950f9f45, 0xbe5313f6, 0x00000000, 0x3fb4860b, + 0x582cdcb1, 0x3e506d39, 0x00000000, 0x3fb3ff12, 0x7216d3a6, + 0x3e4aa719, 0x00000000, 0x3fb3784a, 0x57a423fd, 0x3e5a9b9f, + 0x00000000, 0x3fb2f1b4, 0x7a138b41, 0xbe50b418, 0x00000000, + 0x3fb26b4e, 0x2fbfd7ea, 0x3e23a53e, 0x00000000, 0x3fb1e519, + 0x18913ccb, 0x3e465fc1, 0x00000000, 0x3fb15f15, 0x7ea24e21, + 0x3e042843, 0x00000000, 0x3fb0d941, 0x7c6d9c77, 0x3e59f61e, + 0x00000000, 0x3fb0539e, 0x114efd44, 0x3e4ccab7, 0x00000000, + 0x3faf9c56, 0x1777f657, 0x3e552f65, 0x00000000, 0x3fae91d2, + 0xc317b86a, 0xbe5a61e0, 0x00000000, 0x3fad87ac, 0xb7664efb, + 0xbe41f64e, 0x00000000, 0x3fac7de6, 0x5d3d03a9, 0x3e0807a0, + 0x00000000, 0x3fab7480, 0x743c38eb, 0xbe3726e1, 0x00000000, + 0x3faa6b78, 0x06a253f1, 0x3e5ad636, 0x00000000, 0x3fa962d0, + 0xa35f541b, 0x3e5a187a, 0x00000000, 0x3fa85a88, 0x4b86e446, + 0xbe508150, 0x00000000, 0x3fa7529c, 0x2589cacf, 0x3e52938a, + 0x00000000, 0x3fa64b10, 0xaf6b11f2, 0xbe3454cd, 0x00000000, + 0x3fa543e2, 0x97506fef, 0xbe5fdec5, 0x00000000, 0x3fa43d10, + 0xe75f7dd9, 0xbe388dd3, 0x00000000, 0x3fa3369c, 0xa4139632, + 0xbdea5177, 0x00000000, 0x3fa23086, 0x352d6f1e, 0xbe565ad6, + 0x00000000, 0x3fa12acc, 0x77449eb7, 0xbe50d5c7, 0x00000000, + 0x3fa0256e, 0x7478da78, 0x3e404724, 0x00000000, 0x3f9e40dc, + 0xf59cef7f, 0xbe539d0a, 0x00000000, 0x3f9c3790, 0x1511d43c, + 0x3e53c2c8, 0x00000000, 0x3f9a2f00, 0x9b8bff3c, 0xbe43b3e1, + 0x00000000, 0x3f982724, 0xad1e22a5, 0x3e46f0bd, 0x00000000, + 0x3f962000, 0x130d9356, 0x3e475ba0, 0x00000000, 0x3f941994, + 0x8f86f883, 0xbe513d0b, 0x00000000, 0x3f9213dc, 0x914d0dc8, + 0xbe534335, 0x00000000, 0x3f900ed8, 0x2d73e5e7, 0xbe22ba75, + 0x00000000, 0x3f8c1510, 0xc5b7d70e, 0x3e599c5d, 0x00000000, + 0x3f880de0, 0x8a27857e, 0xbe3d28c8, 0x00000000, 0x3f840810, + 0xda767328, 0x3e531b3d, 0x00000000, 0x3f8003b0, 0x77bacaf3, + 0xbe5f04e3, 0x00000000, 0x3f780150, 0xdf4b0720, 0x3e5a8bff, + 0x00000000, 0x3f6ffc40, 0x34c48e71, 0xbe3fcd99, 0x00000000, + 0x3f5ff6c0, 0x1ad218af, 0xbe4c78a7, 0x00000000, 0x00000000, + 0x00000000, 0x80000000 + }; + + private static int[] logTwoPow = { + 0xfefa39ef, 0x3fe62e42, 0xfefa39ef, 0xbfe62e42 + }; + + public void powIntrinsic(Register dest, Register value1, Register value2, CompilationResultBuilder crb, AMD64MacroAssembler masm) { + ArrayDataPointerConstant highSigMaskPtr = new ArrayDataPointerConstant(highSigMask, 16); + ArrayDataPointerConstant logTwoEPtr = new ArrayDataPointerConstant(logTwoE, 16); + ArrayDataPointerConstant highmaskYPtr = new ArrayDataPointerConstant(highmaskY, 16); + ArrayDataPointerConstant tExpPtr = new ArrayDataPointerConstant(tExp, 16); + ArrayDataPointerConstant eCoeffPtr = new ArrayDataPointerConstant(eCoeff, 16); + ArrayDataPointerConstant coeffHPtr = new ArrayDataPointerConstant(coeffH, 16); + ArrayDataPointerConstant highmaskLogXPtr = new ArrayDataPointerConstant(highmaskLogX, 16); + ArrayDataPointerConstant halfmaskPtr = new ArrayDataPointerConstant(halfmask, 8); + ArrayDataPointerConstant coeffPowPtr = new ArrayDataPointerConstant(coeffPow, 16); + ArrayDataPointerConstant lTblPowPtr = new ArrayDataPointerConstant(lTblPow, 16); + ArrayDataPointerConstant logTwoPowPtr = new ArrayDataPointerConstant(logTwoPow, 8); + + Label bb0 = new Label(); + Label bb1 = new Label(); + Label bb2 = new Label(); + Label bb3 = new Label(); + Label bb4 = new Label(); + Label bb5 = new Label(); + Label bb6 = new Label(); + Label bb7 = new Label(); + Label bb8 = new Label(); + Label bb9 = new Label(); + Label bb10 = new Label(); + Label bb11 = new Label(); + Label bb12 = new Label(); + Label bb13 = new Label(); + Label bb14 = new Label(); + Label bb15 = new Label(); + Label bb16 = new Label(); + Label bb18 = new Label(); + Label bb19 = new Label(); + Label bb20 = new Label(); + Label bb21 = new Label(); + Label bb22 = new Label(); + Label bb23 = new Label(); + Label bb24 = new Label(); + Label bb25 = new Label(); + Label bb26 = new Label(); + Label bb27 = new Label(); + Label bb28 = new Label(); + Label bb29 = new Label(); + Label bb30 = new Label(); + Label bb31 = new Label(); + Label bb32 = new Label(); + Label bb33 = new Label(); + Label bb34 = new Label(); + Label bb35 = new Label(); + Label bb36 = new Label(); + Label bb37 = new Label(); + Label bb38 = new Label(); + Label bb39 = new Label(); + Label bb40 = new Label(); + Label bb41 = new Label(); + Label bb42 = new Label(); + Label bb43 = new Label(); + Label bb44 = new Label(); + Label bb45 = new Label(); + Label bb46 = new Label(); + Label bb47 = new Label(); + Label bb48 = new Label(); + Label bb49 = new Label(); + Label bb50 = new Label(); + Label bb51 = new Label(); + Label bb53 = new Label(); + Label bb54 = new Label(); + Label bb55 = new Label(); + Label bb56 = new Label(); + + Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD); + Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD); + Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD); + Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD); + Register gpr5 = asRegister(gpr5Temp, AMD64Kind.QWORD); + Register gpr6 = asRegister(gpr6Temp, AMD64Kind.QWORD); + Register gpr7 = asRegister(gpr7Temp, AMD64Kind.QWORD); + Register gpr8 = asRegister(gpr8Temp, AMD64Kind.QWORD); + + Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE); + Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE); + Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE); + Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE); + Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE); + Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE); + Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE); + Register temp8 = asRegister(xmm8Temp, AMD64Kind.DOUBLE); + Register temp9 = asRegister(xmm9Temp, AMD64Kind.DOUBLE); + Register temp10 = asRegister(xmm10Temp, AMD64Kind.DOUBLE); + + setCrb(crb); + masm.movdqu(temp10, value1); + masm.movsd(temp8, value2); + if (dest.encoding != value1.encoding) { + masm.movdqu(dest, value1); + } + + masm.movq(temp9, externalAddress(logTwoEPtr)); // 0x00000000, + // 0x3ff72000 + masm.pextrw(gpr1, dest, 3); + masm.xorpd(temp2, temp2); + masm.movq(gpr2, 0x3ff0000000000000L); + masm.movdq(temp2, gpr2); + masm.movl(gpr5, 1069088768); + masm.movdq(temp7, gpr5); + masm.xorpd(temp1, temp1); + masm.movq(gpr6, 0x77f0000000000000L); + masm.movdq(temp1, gpr6); + masm.movdqu(temp3, dest); + masm.movl(gpr4, 32752); + masm.andl(gpr4, gpr1); + masm.subl(gpr4, 16368); + masm.movl(gpr3, gpr4); + masm.sarl(gpr4, 31); + masm.addl(gpr3, gpr4); + masm.xorl(gpr3, gpr4); + masm.por(dest, temp2); + masm.movdqu(temp6, externalAddress(highSigMaskPtr)); // 0x00000000, + // 0xfffff800, + // 0x00000000, + // 0xfffff800 + masm.psrlq(dest, 27); + masm.psrld(dest, 2); + masm.addl(gpr3, 16); + masm.bsrl(gpr3, gpr3); + masm.rcpps(dest, dest); + masm.psllq(temp3, 12); + masm.movl(gpr7, 8192); + masm.movdq(temp4, gpr7); + masm.psrlq(temp3, 12); + masm.subl(gpr1, 16); + masm.cmpl(gpr1, 32736); + masm.jcc(ConditionFlag.AboveEqual, bb0); + + masm.movl(gpr5, 0); + + masm.bind(bb1); + masm.mulss(dest, temp7); + masm.movl(gpr4, -1); + masm.subl(gpr3, 4); + masm.shll(gpr4); + masm.shlq(gpr4, 32); + masm.movdq(temp5, gpr4); + masm.por(temp3, temp1); + masm.subl(gpr1, 16351); + masm.cmpl(gpr1, 1); + masm.jcc(ConditionFlag.BelowEqual, bb2); + + masm.paddd(dest, temp4); + masm.pand(temp5, temp3); + masm.movdl(gpr4, dest); + masm.psllq(dest, 29); + + masm.bind(bb3); + masm.subsd(temp3, temp5); + masm.pand(dest, temp6); + masm.subl(gpr1, 1); + masm.sarl(gpr1, 4); + masm.cvtsi2sdl(temp7, gpr1); + masm.mulpd(temp5, dest); + + masm.bind(bb4); + masm.mulsd(temp3, dest); + masm.leaq(gpr8, externalAddress(coeffPowPtr)); + masm.movdqu(temp1, new AMD64Address(gpr8, 0)); // 0x6dc96112, + // 0xbf836578, + // 0xee241472, + // 0xbf9b0301 + masm.movdqu(temp4, new AMD64Address(gpr8, 16)); // 0x9f95985a, + // 0xbfb528db, + // 0xb3841d2a, + // 0xbfd619b6 + masm.movdqu(temp6, new AMD64Address(gpr8, 32)); // 0x518775e3, + // 0x3f9004f2, + // 0xac8349bb, + // 0x3fa76c9b + masm.movdqu(dest, new AMD64Address(gpr8, 48)); // 0x486ececc, + // 0x3fc4635e, + // 0x161bb241, + // 0xbf5dabe1 + masm.subsd(temp5, temp9); + masm.movl(gpr3, gpr1); + masm.sarl(gpr1, 31); + masm.addl(gpr3, gpr1); + masm.xorl(gpr1, gpr3); + masm.addl(gpr1, 1); + masm.bsrl(gpr1, gpr1); + masm.unpcklpd(temp5, temp3); + masm.addsd(temp3, temp5); + masm.leaq(gpr7, externalAddress(lTblPowPtr)); + masm.andl(gpr4, 16760832); + masm.shrl(gpr4, 10); + masm.addpd(temp5, new AMD64Address(gpr7, gpr4, Scale.Times1, -3648)); + masm.pshufd(temp2, temp3, 0x44); + masm.mulsd(temp3, temp3); + masm.mulpd(temp1, temp2); + masm.mulpd(temp4, temp2); + masm.addsd(temp5, temp7); + masm.mulsd(temp2, temp3); + masm.addpd(temp6, temp1); + masm.mulsd(temp3, temp3); + masm.addpd(dest, temp4); + masm.movdqu(temp1, temp8); + masm.pextrw(gpr3, temp8, 3); + masm.pshufd(temp7, temp5, 0xEE); + masm.movq(temp4, externalAddress(highmaskYPtr)); // 0x00000000, + // 0xfffffff8 + masm.mulpd(temp6, temp2); + masm.pshufd(temp3, temp3, 0x44); + masm.mulpd(dest, temp2); + masm.shll(gpr1, 4); + masm.subl(gpr1, 15872); + masm.andl(gpr3, 32752); + masm.addl(gpr1, gpr3); + masm.mulpd(temp3, temp6); + masm.cmpl(gpr1, 624); + masm.jcc(ConditionFlag.AboveEqual, bb5); + + masm.xorpd(temp6, temp6); + masm.movl(gpr4, 17080); + masm.pinsrw(temp6, gpr4, 3); + masm.movdqu(temp2, temp1); + masm.pand(temp4, temp1); + masm.subsd(temp1, temp4); + masm.mulsd(temp4, temp5); + masm.addsd(dest, temp7); + masm.mulsd(temp1, temp5); + masm.movdqu(temp7, temp6); + masm.addsd(temp6, temp4); + masm.leaq(gpr7, externalAddress(tExpPtr)); + masm.addpd(temp3, dest); + masm.movdl(gpr4, temp6); + masm.movl(gpr3, gpr4); + masm.andl(gpr4, 255); + masm.addl(gpr4, gpr4); + masm.movdqu(temp5, new AMD64Address(gpr7, gpr4, Scale.Times8, 0)); + masm.subsd(temp6, temp7); + masm.pshufd(dest, temp3, 0xEE); + masm.subsd(temp4, temp6); + masm.addsd(dest, temp3); + masm.addsd(temp4, temp1); + masm.mulsd(temp2, dest); + masm.leaq(gpr8, externalAddress(eCoeffPtr)); + masm.movdqu(temp7, new AMD64Address(gpr8, 0)); // 0xe78a6731, + // 0x3f55d87f, + // 0xd704a0c0, + // 0x3fac6b08 + masm.movdqu(temp3, new AMD64Address(gpr8, 16)); // 0x6fba4e77, + // 0x3f83b2ab, + // 0xff82c58f, + // 0x3fcebfbd + masm.shll(gpr3, 12); + masm.xorl(gpr3, gpr5); + masm.andl(gpr3, -1048576); + masm.movdq(temp6, gpr3); + masm.addsd(temp2, temp4); + masm.movq(gpr2, 0x3fe62e42fefa39efL); + masm.movdq(temp1, gpr2); + masm.pshufd(dest, temp2, 0x44); + masm.pshufd(temp4, temp2, 0x44); + masm.mulsd(temp1, temp2); + masm.pshufd(temp6, temp6, 0x11); + masm.mulpd(dest, dest); + masm.mulpd(temp7, temp4); + masm.paddd(temp5, temp6); + masm.mulsd(temp1, temp5); + masm.pshufd(temp6, temp5, 0xEE); + masm.mulsd(dest, dest); + masm.addpd(temp3, temp7); + masm.addsd(temp1, temp6); + masm.mulpd(dest, temp3); + masm.pshufd(temp3, dest, 0xEE); + masm.mulsd(dest, temp5); + masm.mulsd(temp3, temp5); + masm.addsd(dest, temp1); + masm.addsd(dest, temp3); + masm.addsd(dest, temp5); + masm.jmp(bb56); + + masm.bind(bb0); + masm.addl(gpr1, 16); + masm.movl(gpr4, 32752); + masm.andl(gpr4, gpr1); + masm.cmpl(gpr4, 32752); + masm.jcc(ConditionFlag.Equal, bb6); + + masm.testl(gpr1, 32768); + masm.jcc(ConditionFlag.NotEqual, bb7); + + masm.bind(bb8); + masm.movdqu(dest, temp10); + masm.movdqu(temp3, temp10); + masm.movdl(gpr4, temp3); + masm.psrlq(temp3, 32); + masm.movdl(gpr3, temp3); + masm.orl(gpr4, gpr3); + masm.cmpl(gpr4, 0); + masm.jcc(ConditionFlag.Equal, bb9); + + masm.xorpd(temp3, temp3); + masm.movl(gpr1, 18416); + masm.pinsrw(temp3, gpr1, 3); + masm.mulsd(dest, temp3); + masm.xorpd(temp2, temp2); + masm.movl(gpr1, 16368); + masm.pinsrw(temp2, gpr1, 3); + masm.movdqu(temp3, dest); + masm.pextrw(gpr1, dest, 3); + masm.por(dest, temp2); + masm.movl(gpr3, 18416); + masm.psrlq(dest, 27); + masm.psrld(dest, 2); + masm.rcpps(dest, dest); + masm.psllq(temp3, 12); + masm.movdqu(temp6, externalAddress(highSigMaskPtr)); // 0x00000000, + // 0xfffff800, + // 0x00000000, + // 0xfffff800 + masm.psrlq(temp3, 12); + masm.mulss(dest, temp7); + masm.movl(gpr4, -1024); + masm.movdl(temp5, gpr4); + masm.por(temp3, temp1); + masm.paddd(dest, temp4); + masm.psllq(temp5, 32); + masm.movdl(gpr4, dest); + masm.psllq(dest, 29); + masm.pand(temp5, temp3); + masm.movl(gpr5, 0); + masm.pand(dest, temp6); + masm.subsd(temp3, temp5); + masm.andl(gpr1, 32752); + masm.subl(gpr1, 18416); + masm.sarl(gpr1, 4); + masm.cvtsi2sdl(temp7, gpr1); + masm.mulpd(temp5, dest); + masm.jmp(bb4); + + masm.bind(bb10); + masm.movdqu(dest, temp10); + masm.movdqu(temp3, temp10); + masm.movdl(gpr4, temp3); + masm.psrlq(temp3, 32); + masm.movdl(gpr3, temp3); + masm.orl(gpr4, gpr3); + masm.cmpl(gpr4, 0); + masm.jcc(ConditionFlag.Equal, bb9); + + masm.xorpd(temp3, temp3); + masm.movl(gpr1, 18416); + masm.pinsrw(temp3, gpr1, 3); + masm.mulsd(dest, temp3); + masm.xorpd(temp2, temp2); + masm.movl(gpr1, 16368); + masm.pinsrw(temp2, gpr1, 3); + masm.movdqu(temp3, dest); + masm.pextrw(gpr1, dest, 3); + masm.por(dest, temp2); + masm.movl(gpr3, 18416); + masm.psrlq(dest, 27); + masm.psrld(dest, 2); + masm.rcpps(dest, dest); + masm.psllq(temp3, 12); + masm.movdqu(temp6, externalAddress(highSigMaskPtr)); // 0x00000000, + // 0xfffff800, + // 0x00000000, + // 0xfffff800 + masm.psrlq(temp3, 12); + masm.mulss(dest, temp7); + masm.movl(gpr4, -1024); + masm.movdl(temp5, gpr4); + masm.por(temp3, temp1); + masm.paddd(dest, temp4); + masm.psllq(temp5, 32); + masm.movdl(gpr4, dest); + masm.psllq(dest, 29); + masm.pand(temp5, temp3); + masm.movl(gpr5, Integer.MIN_VALUE); + masm.pand(dest, temp6); + masm.subsd(temp3, temp5); + masm.andl(gpr1, 32752); + masm.subl(gpr1, 18416); + masm.sarl(gpr1, 4); + masm.cvtsi2sdl(temp7, gpr1); + masm.mulpd(temp5, dest); + masm.jmp(bb4); + + masm.bind(bb5); + masm.cmpl(gpr1, 0); + masm.jcc(ConditionFlag.Less, bb11); + + masm.cmpl(gpr1, 752); + masm.jcc(ConditionFlag.AboveEqual, bb12); + + masm.addsd(dest, temp7); + masm.movq(temp4, externalAddress(halfmaskPtr)); // 0xf8000000, + // 0xffffffff + masm.addpd(temp3, dest); + masm.xorpd(temp6, temp6); + masm.movl(gpr1, 17080); + masm.pinsrw(temp6, gpr1, 3); + masm.pshufd(dest, temp3, 0xEE); + masm.addsd(dest, temp3); + masm.movdqu(temp3, temp5); + masm.addsd(temp5, dest); + masm.subsd(temp3, temp5); + masm.movdqu(temp7, temp5); + masm.pand(temp5, temp4); + masm.movdqu(temp2, temp1); + masm.pand(temp4, temp1); + masm.subsd(temp7, temp5); + masm.addsd(dest, temp3); + masm.subsd(temp1, temp4); + masm.mulsd(temp4, temp5); + masm.addsd(dest, temp7); + masm.mulsd(temp2, dest); + masm.movdqu(temp7, temp6); + masm.mulsd(temp1, temp5); + masm.addsd(temp6, temp4); + masm.movdl(gpr1, temp6); + masm.subsd(temp6, temp7); + masm.leaq(gpr7, externalAddress(tExpPtr)); + masm.movl(gpr3, gpr1); + masm.andl(gpr1, 255); + masm.addl(gpr1, gpr1); + masm.movdqu(temp5, new AMD64Address(gpr7, gpr1, Scale.Times8, 0)); + masm.addsd(temp2, temp1); + masm.leaq(gpr8, externalAddress(eCoeffPtr)); + masm.movdqu(temp7, new AMD64Address(gpr8, 0)); // 0xe78a6731, + // 0x3f55d87f, + // 0xd704a0c0, + // 0x3fac6b08 + masm.movdqu(temp3, new AMD64Address(gpr8, 16)); // 0x6fba4e77, + // 0x3f83b2ab, + // 0xff82c58f, + // 0x3fcebfbd + masm.subsd(temp4, temp6); + masm.pextrw(gpr4, temp6, 3); + masm.addsd(temp2, temp4); + masm.sarl(gpr3, 8); + masm.movl(gpr1, gpr3); + masm.sarl(gpr3, 1); + masm.subl(gpr1, gpr3); + masm.shll(gpr3, 20); + masm.xorl(gpr3, gpr5); + masm.movdl(temp6, gpr3); + masm.movq(temp1, new AMD64Address(gpr8, 32)); // 0xfefa39ef, + // 0x3fe62e42 + masm.andl(gpr4, 32767); + masm.cmpl(gpr4, 16529); + masm.jcc(ConditionFlag.Above, bb12); + + masm.pshufd(dest, temp2, 0x44); + masm.pshufd(temp4, temp2, 0x44); + masm.mulpd(dest, dest); + masm.mulpd(temp7, temp4); + masm.pshufd(temp6, temp6, 0x11); + masm.mulsd(temp1, temp2); + masm.mulsd(dest, dest); + masm.paddd(temp5, temp6); + masm.addpd(temp3, temp7); + masm.mulsd(temp1, temp5); + masm.pshufd(temp6, temp5, 0xEE); + masm.mulpd(dest, temp3); + masm.addsd(temp1, temp6); + masm.pshufd(temp3, dest, 0xEE); + masm.mulsd(dest, temp5); + masm.mulsd(temp3, temp5); + masm.shll(gpr1, 4); + masm.xorpd(temp4, temp4); + masm.addl(gpr1, 16368); + masm.pinsrw(temp4, gpr1, 3); + masm.addsd(dest, temp1); + masm.addsd(dest, temp3); + masm.movdqu(temp1, dest); + masm.addsd(dest, temp5); + masm.mulsd(dest, temp4); + masm.pextrw(gpr1, dest, 3); + masm.andl(gpr1, 32752); + masm.jcc(ConditionFlag.Equal, bb13); + + masm.cmpl(gpr1, 32752); + masm.jcc(ConditionFlag.Equal, bb14); + + masm.jmp(bb56); + + masm.bind(bb6); + masm.movdqu(temp1, temp8); + masm.movdqu(dest, temp10); + masm.movdqu(temp2, dest); + masm.movdl(gpr1, temp2); + masm.psrlq(temp2, 20); + masm.movdl(gpr4, temp2); + masm.orl(gpr1, gpr4); + masm.jcc(ConditionFlag.Equal, bb15); + + masm.movdl(gpr1, temp1); + masm.psrlq(temp1, 32); + masm.movdl(gpr4, temp1); + masm.movl(gpr3, gpr4); + masm.addl(gpr4, gpr4); + masm.orl(gpr1, gpr4); + masm.jcc(ConditionFlag.Equal, bb16); + + masm.addsd(dest, dest); + masm.jmp(bb56); + + masm.bind(bb16); + masm.xorpd(dest, dest); + masm.movl(gpr1, 16368); + masm.pinsrw(dest, gpr1, 3); + masm.jmp(bb56); + + masm.bind(bb18); + masm.addpd(dest, temp8); + masm.jmp(bb56); + + masm.bind(bb15); + masm.movdl(gpr1, temp1); + masm.movdqu(temp2, temp1); + masm.psrlq(temp1, 32); + masm.movdl(gpr4, temp1); + masm.movl(gpr3, gpr4); + masm.addl(gpr4, gpr4); + masm.orl(gpr1, gpr4); + masm.jcc(ConditionFlag.Equal, bb19); + + masm.pextrw(gpr1, temp2, 3); + masm.andl(gpr1, 32752); + masm.cmpl(gpr1, 32752); + masm.jcc(ConditionFlag.NotEqual, bb20); + + masm.movdl(gpr1, temp2); + masm.psrlq(temp2, 20); + masm.movdl(gpr4, temp2); + masm.orl(gpr1, gpr4); + masm.jcc(ConditionFlag.NotEqual, bb18); + + masm.bind(bb20); + masm.pextrw(gpr1, dest, 3); + masm.testl(gpr1, 32768); + masm.jcc(ConditionFlag.NotEqual, bb21); + + masm.testl(gpr3, Integer.MIN_VALUE); + masm.jcc(ConditionFlag.NotZero, bb22); + + masm.jmp(bb56); + + masm.bind(bb23); + masm.movdl(gpr1, temp8); + masm.testl(gpr1, 1); + masm.jcc(ConditionFlag.NotEqual, bb24); + + masm.testl(gpr1, 2); + masm.jcc(ConditionFlag.NotEqual, bb25); + + masm.jmp(bb24); + + masm.bind(bb21); + masm.shrl(gpr3, 20); + masm.andl(gpr3, 2047); + masm.cmpl(gpr3, 1075); + masm.jcc(ConditionFlag.Above, bb24); + + masm.jcc(ConditionFlag.Equal, bb26); + + masm.cmpl(gpr3, 1074); + masm.jcc(ConditionFlag.Above, bb23); + + masm.cmpl(gpr3, 1023); + masm.jcc(ConditionFlag.Below, bb24); + + masm.movdqu(temp1, temp8); + masm.movl(gpr1, 17208); + masm.xorpd(temp3, temp3); + masm.pinsrw(temp3, gpr1, 3); + masm.movdqu(temp4, temp3); + masm.addsd(temp3, temp1); + masm.subsd(temp4, temp3); + masm.addsd(temp1, temp4); + masm.pextrw(gpr1, temp1, 3); + masm.andl(gpr1, 32752); + masm.jcc(ConditionFlag.NotEqual, bb24); + + masm.movdl(gpr1, temp3); + masm.andl(gpr1, 1); + masm.jcc(ConditionFlag.Equal, bb24); + + masm.bind(bb25); + masm.pextrw(gpr1, temp8, 3); + masm.andl(gpr1, 32768); + masm.jcc(ConditionFlag.NotEqual, bb27); + + masm.jmp(bb56); + + masm.bind(bb27); + masm.xorpd(dest, dest); + masm.movl(gpr1, 32768); + masm.pinsrw(dest, gpr1, 3); + masm.jmp(bb56); + + masm.bind(bb24); + masm.pextrw(gpr1, temp8, 3); + masm.andl(gpr1, 32768); + masm.jcc(ConditionFlag.NotEqual, bb22); + + masm.xorpd(dest, dest); + masm.movl(gpr1, 32752); + masm.pinsrw(dest, gpr1, 3); + masm.jmp(bb56); + + masm.bind(bb26); + masm.movdl(gpr1, temp8); + masm.andl(gpr1, 1); + masm.jcc(ConditionFlag.Equal, bb24); + + masm.jmp(bb25); + + masm.bind(bb28); + masm.movdl(gpr1, temp1); + masm.psrlq(temp1, 20); + masm.movdl(gpr4, temp1); + masm.orl(gpr1, gpr4); + masm.jcc(ConditionFlag.Equal, bb29); + + masm.addsd(dest, temp8); + masm.jmp(bb56); + + masm.bind(bb29); + masm.movdqu(dest, temp10); + masm.pextrw(gpr1, dest, 3); + masm.cmpl(gpr1, 49136); + masm.jcc(ConditionFlag.NotEqual, bb30); + + masm.movdl(gpr3, dest); + masm.psrlq(dest, 20); + masm.movdl(gpr4, dest); + masm.orl(gpr3, gpr4); + masm.jcc(ConditionFlag.NotEqual, bb30); + + masm.xorpd(dest, dest); + masm.movl(gpr1, 32760); + masm.pinsrw(dest, gpr1, 3); + masm.jmp(bb56); + + masm.bind(bb30); + masm.andl(gpr1, 32752); + masm.subl(gpr1, 16368); + masm.pextrw(gpr4, temp8, 3); + masm.xorpd(dest, dest); + masm.xorl(gpr1, gpr4); + masm.andl(gpr1, 32768); + masm.jcc(ConditionFlag.Equal, bb31); + + masm.jmp(bb56); + + masm.bind(bb31); + masm.movl(gpr3, 32752); + masm.pinsrw(dest, gpr3, 3); + masm.jmp(bb56); + + masm.bind(bb32); + masm.movdl(gpr1, temp1); + masm.cmpl(gpr4, 17184); + masm.jcc(ConditionFlag.Above, bb33); + + masm.testl(gpr1, 1); + masm.jcc(ConditionFlag.NotEqual, bb34); + + masm.testl(gpr1, 2); + masm.jcc(ConditionFlag.Equal, bb35); + + masm.jmp(bb36); + + masm.bind(bb33); + masm.testl(gpr1, 1); + masm.jcc(ConditionFlag.Equal, bb35); + + masm.jmp(bb36); + + masm.bind(bb7); + masm.movdqu(temp2, temp10); + masm.movdl(gpr1, temp2); + masm.psrlq(temp2, 31); + masm.movdl(gpr3, temp2); + masm.orl(gpr1, gpr3); + masm.jcc(ConditionFlag.Equal, bb9); + + masm.pextrw(gpr4, temp8, 3); + masm.movdl(gpr1, temp8); + masm.movdqu(temp2, temp8); + masm.psrlq(temp2, 32); + masm.movdl(gpr3, temp2); + masm.addl(gpr3, gpr3); + masm.orl(gpr3, gpr1); + masm.jcc(ConditionFlag.Equal, bb37); + + masm.andl(gpr4, 32752); + masm.cmpl(gpr4, 32752); + masm.jcc(ConditionFlag.Equal, bb28); + + masm.cmpl(gpr4, 17200); + masm.jcc(ConditionFlag.Above, bb35); + + masm.cmpl(gpr4, 17184); + masm.jcc(ConditionFlag.AboveEqual, bb32); + + masm.cmpl(gpr4, 16368); + masm.jcc(ConditionFlag.Below, bb34); + + masm.movl(gpr1, 17208); + masm.xorpd(temp2, temp2); + masm.pinsrw(temp2, gpr1, 3); + masm.movdqu(temp4, temp2); + masm.addsd(temp2, temp1); + masm.subsd(temp4, temp2); + masm.addsd(temp1, temp4); + masm.pextrw(gpr1, temp1, 3); + masm.andl(gpr1, 32767); + masm.jcc(ConditionFlag.NotEqual, bb34); + + masm.movdl(gpr1, temp2); + masm.andl(gpr1, 1); + masm.jcc(ConditionFlag.Equal, bb35); + + masm.bind(bb36); + masm.xorpd(temp1, temp1); + masm.movl(gpr4, 30704); + masm.pinsrw(temp1, gpr4, 3); + masm.pextrw(gpr1, temp10, 3); + masm.movl(gpr4, 8192); + masm.movdl(temp4, gpr4); + masm.andl(gpr1, 32767); + masm.subl(gpr1, 16); + masm.jcc(ConditionFlag.Less, bb10); + + masm.movl(gpr4, gpr1); + masm.andl(gpr4, 32752); + masm.subl(gpr4, 16368); + masm.movl(gpr3, gpr4); + masm.sarl(gpr4, 31); + masm.addl(gpr3, gpr4); + masm.xorl(gpr3, gpr4); + masm.addl(gpr3, 16); + masm.bsrl(gpr3, gpr3); + masm.movl(gpr5, Integer.MIN_VALUE); + masm.jmp(bb1); + + masm.bind(bb34); + masm.xorpd(temp1, temp1); + masm.movl(gpr1, 32752); + masm.pinsrw(temp1, gpr1, 3); + masm.xorpd(dest, dest); + masm.mulsd(dest, temp1); + masm.jmp(bb56); + + masm.bind(bb35); + masm.xorpd(temp1, temp1); + masm.movl(gpr4, 30704); + masm.pinsrw(temp1, gpr4, 3); + masm.pextrw(gpr1, temp10, 3); + masm.movl(gpr4, 8192); + masm.movdl(temp4, gpr4); + masm.andl(gpr1, 32767); + masm.subl(gpr1, 16); + masm.jcc(ConditionFlag.Less, bb8); + + masm.movl(gpr4, gpr1); + masm.andl(gpr4, 32752); + masm.subl(gpr4, 16368); + masm.movl(gpr3, gpr4); + masm.sarl(gpr4, 31); + masm.addl(gpr3, gpr4); + masm.xorl(gpr3, gpr4); + masm.addl(gpr3, 16); + masm.bsrl(gpr3, gpr3); + masm.movl(gpr5, 0); + masm.jmp(bb1); + + masm.bind(bb19); + masm.xorpd(dest, dest); + masm.movl(gpr1, 16368); + masm.pinsrw(dest, gpr1, 3); + masm.jmp(bb56); + + masm.bind(bb22); + masm.xorpd(dest, dest); + masm.jmp(bb56); + + masm.bind(bb11); + masm.addl(gpr1, 384); + masm.cmpl(gpr1, 0); + masm.jcc(ConditionFlag.Less, bb38); + + masm.mulsd(temp5, temp1); + masm.addsd(dest, temp7); + masm.shrl(gpr5, 31); + masm.addpd(temp3, dest); + masm.pshufd(dest, temp3, 0xEE); + masm.addsd(temp3, dest); + masm.leaq(gpr7, externalAddress(logTwoPowPtr)); // 0xfefa39ef, + // 0x3fe62e42, + // 0xfefa39ef, + // 0xbfe62e42 + masm.movq(temp4, new AMD64Address(gpr7, gpr5, Scale.Times8, 0)); + masm.mulsd(temp1, temp3); + masm.xorpd(dest, dest); + masm.movl(gpr1, 16368); + masm.shll(gpr5, 15); + masm.orl(gpr1, gpr5); + masm.pinsrw(dest, gpr1, 3); + masm.addsd(temp5, temp1); + masm.mulsd(temp5, temp4); + masm.addsd(dest, temp5); + masm.jmp(bb56); + + masm.bind(bb38); + + masm.bind(bb37); + masm.xorpd(dest, dest); + masm.movl(gpr1, 16368); + masm.pinsrw(dest, gpr1, 3); + masm.jmp(bb56); + + masm.bind(bb39); + masm.xorpd(dest, dest); + masm.movl(gpr1, 16368); + masm.pinsrw(dest, gpr1, 3); + masm.jmp(bb56); + + masm.bind(bb9); + masm.movdqu(temp2, temp8); + masm.pextrw(gpr1, temp8, 3); + masm.andl(gpr1, 32752); + masm.cmpl(gpr1, 32752); + masm.jcc(ConditionFlag.NotEqual, bb40); + + masm.movdl(gpr1, temp2); + masm.psrlq(temp2, 20); + masm.movdl(gpr4, temp2); + masm.orl(gpr1, gpr4); + masm.jcc(ConditionFlag.NotEqual, bb18); + + masm.bind(bb40); + masm.movdl(gpr1, temp1); + masm.psrlq(temp1, 32); + masm.movdl(gpr4, temp1); + masm.movl(gpr3, gpr4); + masm.addl(gpr4, gpr4); + masm.orl(gpr1, gpr4); + masm.jcc(ConditionFlag.Equal, bb39); + + masm.shrl(gpr4, 21); + masm.cmpl(gpr4, 1075); + masm.jcc(ConditionFlag.Above, bb41); + + masm.jcc(ConditionFlag.Equal, bb42); + + masm.cmpl(gpr4, 1023); + masm.jcc(ConditionFlag.Below, bb41); + + masm.movdqu(temp1, temp8); + masm.movl(gpr1, 17208); + masm.xorpd(temp3, temp3); + masm.pinsrw(temp3, gpr1, 3); + masm.movdqu(temp4, temp3); + masm.addsd(temp3, temp1); + masm.subsd(temp4, temp3); + masm.addsd(temp1, temp4); + masm.pextrw(gpr1, temp1, 3); + masm.andl(gpr1, 32752); + masm.jcc(ConditionFlag.NotEqual, bb41); + + masm.movdl(gpr1, temp3); + masm.andl(gpr1, 1); + masm.jcc(ConditionFlag.Equal, bb41); + + masm.bind(bb43); + masm.movdqu(dest, temp10); + masm.testl(gpr3, Integer.MIN_VALUE); + masm.jcc(ConditionFlag.NotEqual, bb44); + + masm.jmp(bb56); + + masm.bind(bb42); + masm.movdl(gpr1, temp8); + masm.testl(gpr1, 1); + masm.jcc(ConditionFlag.NotEqual, bb43); + + masm.bind(bb41); + masm.testl(gpr3, Integer.MIN_VALUE); + masm.jcc(ConditionFlag.Equal, bb22); + + masm.xorpd(dest, dest); + + masm.bind(bb44); + masm.movl(gpr1, 16368); + masm.xorpd(temp1, temp1); + masm.pinsrw(temp1, gpr1, 3); + masm.divsd(temp1, dest); + masm.movdqu(dest, temp1); + masm.jmp(bb56); + + masm.bind(bb12); + masm.pextrw(gpr1, temp10, 3); + masm.pextrw(gpr4, temp8, 3); + masm.movl(gpr3, 32752); + masm.andl(gpr3, gpr4); + masm.cmpl(gpr3, 32752); + masm.jcc(ConditionFlag.Equal, bb45); + + masm.andl(gpr1, 32752); + masm.subl(gpr1, 16368); + masm.xorl(gpr4, gpr1); + masm.testl(gpr4, 32768); + masm.jcc(ConditionFlag.NotEqual, bb46); + + masm.bind(bb47); + masm.movl(gpr1, 32736); + masm.pinsrw(dest, gpr1, 3); + masm.shrl(gpr5, 16); + masm.orl(gpr1, gpr5); + masm.pinsrw(temp1, gpr1, 3); + masm.mulsd(dest, temp1); + + masm.bind(bb14); + masm.jmp(bb56); + + masm.bind(bb46); + masm.movl(gpr1, 16); + masm.pinsrw(dest, gpr1, 3); + masm.mulsd(dest, dest); + masm.testl(gpr3, Integer.MIN_VALUE); + masm.jcc(ConditionFlag.Equal, bb48); + + masm.movq(gpr2, 0x8000000000000000L); + masm.movdq(temp2, gpr2); + masm.xorpd(dest, temp2); + + masm.bind(bb48); + masm.jmp(bb56); + + masm.bind(bb13); + masm.pextrw(gpr3, temp5, 3); + masm.pextrw(gpr4, temp4, 3); + masm.movl(gpr1, -1); + masm.andl(gpr3, 32752); + masm.subl(gpr3, 16368); + masm.andl(gpr4, 32752); + masm.addl(gpr4, gpr3); + masm.movl(gpr3, -31); + masm.sarl(gpr4, 4); + masm.subl(gpr3, gpr4); + masm.jcc(ConditionFlag.LessEqual, bb49); + + masm.cmpl(gpr3, 20); + masm.jcc(ConditionFlag.Above, bb50); + + masm.shll(gpr1); + + masm.bind(bb49); + masm.movdl(dest, gpr1); + masm.psllq(dest, 32); + masm.pand(dest, temp5); + masm.subsd(temp5, dest); + masm.addsd(temp5, temp1); + masm.mulsd(dest, temp4); + masm.mulsd(temp5, temp4); + masm.addsd(dest, temp5); + + masm.bind(bb50); + masm.jmp(bb48); + + masm.bind(bb2); + masm.pextrw(gpr3, temp8, 3); + masm.movl(gpr4, Integer.MIN_VALUE); + masm.movdl(temp1, gpr4); + masm.xorpd(temp7, temp7); + masm.paddd(dest, temp4); + masm.movdl(gpr4, dest); + masm.psllq(dest, 29); + masm.paddq(temp1, temp3); + masm.pand(temp5, temp1); + masm.andl(gpr3, 32752); + masm.cmpl(gpr3, 16560); + masm.jcc(ConditionFlag.Less, bb3); + + masm.leaq(gpr7, externalAddress(lTblPowPtr)); + masm.leaq(gpr8, externalAddress(coeffHPtr)); + masm.movdqu(temp4, new AMD64Address(gpr8, 0)); // 0x00000000, + // 0xbfd61a00, + // 0x00000000, + // 0xbf5dabe1 + masm.pand(dest, temp6); + masm.subsd(temp3, temp5); + masm.addl(gpr1, 16351); + masm.shrl(gpr1, 4); + masm.subl(gpr1, 1022); + masm.cvtsi2sdl(temp7, gpr1); + masm.mulpd(temp5, dest); + masm.mulsd(temp3, dest); + masm.subsd(temp5, temp9); + masm.pshufd(temp1, temp4, 0xE); + masm.pshufd(temp2, temp3, 0x44); + masm.unpcklpd(temp5, temp3); + masm.addsd(temp3, temp5); + masm.andl(gpr4, 16760832); + masm.shrl(gpr4, 10); + masm.addpd(temp7, new AMD64Address(gpr7, gpr4, Scale.Times1, -3648)); + masm.movdqu(temp6, temp4); + masm.mulsd(temp4, temp5); + masm.movdqu(dest, temp1); + masm.mulsd(dest, temp5); + masm.mulsd(temp6, temp2); + masm.mulsd(temp1, temp2); + masm.movdqu(temp2, temp5); + masm.mulsd(temp4, temp5); + masm.addsd(temp5, dest); + masm.movdqu(dest, temp7); + masm.addsd(temp2, temp3); + masm.addsd(temp7, temp5); + masm.mulsd(temp6, temp2); + masm.subsd(dest, temp7); + masm.movdqu(temp2, temp7); + masm.addsd(temp7, temp4); + masm.addsd(dest, temp5); + masm.subsd(temp2, temp7); + masm.addsd(temp4, temp2); + masm.pshufd(temp2, temp5, 0xEE); + masm.movdqu(temp5, temp7); + masm.addsd(temp7, temp2); + masm.addsd(temp4, dest); + masm.leaq(gpr8, externalAddress(coeffPowPtr)); + masm.movdqu(dest, new AMD64Address(gpr8, 0)); // 0x6dc96112, + // 0xbf836578, + // 0xee241472, + // 0xbf9b0301 + masm.subsd(temp5, temp7); + masm.addsd(temp6, temp4); + masm.movdqu(temp4, temp7); + masm.addsd(temp5, temp2); + masm.addsd(temp7, temp1); + masm.movdqu(temp2, new AMD64Address(gpr8, 64)); // 0x486ececc, + // 0x3fc4635e, + // 0x161bb241, + // 0xbf5dabe1 + masm.subsd(temp4, temp7); + masm.addsd(temp6, temp5); + masm.addsd(temp4, temp1); + masm.pshufd(temp5, temp7, 0xEE); + masm.movapd(temp1, temp7); + masm.addsd(temp7, temp5); + masm.subsd(temp1, temp7); + masm.addsd(temp1, temp5); + masm.movdqu(temp5, new AMD64Address(gpr8, 80)); // 0x9f95985a, + // 0xbfb528db, + // 0xf8b5787d, + // 0x3ef2531e + masm.pshufd(temp3, temp3, 0x44); + masm.addsd(temp6, temp4); + masm.addsd(temp6, temp1); + masm.movdqu(temp1, new AMD64Address(gpr8, 32)); // 0x9f95985a, + // 0xbfb528db, + // 0xb3841d2a, + // 0xbfd619b6 + masm.mulpd(dest, temp3); + masm.mulpd(temp2, temp3); + masm.pshufd(temp4, temp3, 0x44); + masm.mulpd(temp3, temp3); + masm.addpd(dest, temp1); + masm.addpd(temp5, temp2); + masm.mulsd(temp4, temp3); + masm.movq(temp2, externalAddress(highmaskLogXPtr)); // 0xf8000000, + // 0xffffffff + masm.mulpd(temp3, temp3); + masm.movdqu(temp1, temp8); + masm.pextrw(gpr3, temp8, 3); + masm.mulpd(dest, temp4); + masm.pextrw(gpr1, temp7, 3); + masm.mulpd(temp5, temp4); + masm.mulpd(dest, temp3); + masm.leaq(gpr8, externalAddress(highmaskYPtr)); + masm.movq(temp4, new AMD64Address(gpr8, 8)); // 0x00000000, + // 0xffffffff + masm.pand(temp2, temp7); + masm.addsd(temp5, temp6); + masm.subsd(temp7, temp2); + masm.addpd(temp5, dest); + masm.andl(gpr1, 32752); + masm.subl(gpr1, 16368); + masm.andl(gpr3, 32752); + masm.cmpl(gpr3, 32752); + masm.jcc(ConditionFlag.Equal, bb45); + + masm.addl(gpr3, gpr1); + masm.cmpl(gpr3, 16576); + masm.jcc(ConditionFlag.AboveEqual, bb51); + + masm.pshufd(dest, temp5, 0xEE); + masm.pand(temp4, temp1); + masm.movdqu(temp3, temp1); + masm.addsd(temp5, dest); + masm.subsd(temp1, temp4); + masm.xorpd(temp6, temp6); + masm.movl(gpr4, 17080); + masm.pinsrw(temp6, gpr4, 3); + masm.addsd(temp7, temp5); + masm.mulsd(temp4, temp2); + masm.mulsd(temp1, temp2); + masm.movdqu(temp5, temp6); + masm.mulsd(temp3, temp7); + masm.addsd(temp6, temp4); + masm.addsd(temp1, temp3); + masm.leaq(gpr8, externalAddress(eCoeffPtr)); + masm.movdqu(temp7, new AMD64Address(gpr8, 0)); // 0xe78a6731, + // 0x3f55d87f, + // 0xd704a0c0, + // 0x3fac6b08 + masm.movdl(gpr4, temp6); + masm.subsd(temp6, temp5); + masm.leaq(gpr7, externalAddress(tExpPtr)); + masm.movl(gpr3, gpr4); + masm.andl(gpr4, 255); + masm.addl(gpr4, gpr4); + masm.movdqu(temp5, new AMD64Address(gpr7, gpr4, Scale.Times8, 0)); + masm.movdqu(temp3, new AMD64Address(gpr8, 16)); // 0x6fba4e77, + // 0x3f83b2ab, + // 0xff82c58f, + // 0x3fcebfbd + masm.movq(temp2, new AMD64Address(gpr8, 32)); // 0xfefa39ef, + // 0x3fe62e42 + masm.subsd(temp4, temp6); + masm.addsd(temp4, temp1); + masm.pextrw(gpr4, temp6, 3); + masm.shrl(gpr3, 8); + masm.movl(gpr1, gpr3); + masm.shrl(gpr3, 1); + masm.subl(gpr1, gpr3); + masm.shll(gpr3, 20); + masm.movdl(temp6, gpr3); + masm.pshufd(dest, temp4, 0x44); + masm.pshufd(temp1, temp4, 0x44); + masm.mulpd(dest, dest); + masm.mulpd(temp7, temp1); + masm.pshufd(temp6, temp6, 0x11); + masm.mulsd(temp2, temp4); + masm.andl(gpr4, 32767); + masm.cmpl(gpr4, 16529); + masm.jcc(ConditionFlag.Above, bb12); + + masm.mulsd(dest, dest); + masm.paddd(temp5, temp6); + masm.addpd(temp3, temp7); + masm.mulsd(temp2, temp5); + masm.pshufd(temp6, temp5, 0xEE); + masm.mulpd(dest, temp3); + masm.addsd(temp2, temp6); + masm.pshufd(temp3, dest, 0xEE); + masm.addl(gpr1, 1023); + masm.shll(gpr1, 20); + masm.orl(gpr1, gpr5); + masm.movdl(temp4, gpr1); + masm.mulsd(dest, temp5); + masm.mulsd(temp3, temp5); + masm.addsd(dest, temp2); + masm.psllq(temp4, 32); + masm.addsd(dest, temp3); + masm.movdqu(temp1, dest); + masm.addsd(dest, temp5); + masm.mulsd(dest, temp4); + masm.pextrw(gpr1, dest, 3); + masm.andl(gpr1, 32752); + masm.jcc(ConditionFlag.Equal, bb13); + + masm.cmpl(gpr1, 32752); + masm.jcc(ConditionFlag.Equal, bb14); + + masm.jmp(bb56); + + masm.bind(bb45); + masm.movdqu(dest, temp10); + masm.xorpd(temp2, temp2); + masm.movl(gpr1, 49136); + masm.pinsrw(temp2, gpr1, 3); + masm.addsd(temp2, dest); + masm.pextrw(gpr1, temp2, 3); + masm.cmpl(gpr1, 0); + masm.jcc(ConditionFlag.NotEqual, bb53); + + masm.xorpd(dest, dest); + masm.movl(gpr1, 32760); + masm.pinsrw(dest, gpr1, 3); + masm.jmp(bb56); + + masm.bind(bb53); + masm.movdqu(temp1, temp8); + masm.movdl(gpr4, temp1); + masm.movdqu(temp3, temp1); + masm.psrlq(temp3, 20); + masm.movdl(gpr3, temp3); + masm.orl(gpr3, gpr4); + masm.jcc(ConditionFlag.Equal, bb54); + + masm.addsd(temp1, temp1); + masm.movdqu(dest, temp1); + masm.jmp(bb56); + + masm.bind(bb51); + masm.pextrw(gpr1, temp1, 3); + masm.pextrw(gpr3, temp2, 3); + masm.xorl(gpr1, gpr3); + masm.testl(gpr1, 32768); + masm.jcc(ConditionFlag.Equal, bb47); + + masm.jmp(bb46); + + masm.bind(bb54); + masm.pextrw(gpr1, dest, 3); + masm.andl(gpr1, 32752); + masm.pextrw(gpr4, temp1, 3); + masm.xorpd(dest, dest); + masm.subl(gpr1, 16368); + masm.xorl(gpr1, gpr4); + masm.testl(gpr1, 32768); + masm.jcc(ConditionFlag.Equal, bb55); + + masm.jmp(bb56); + + masm.bind(bb55); + masm.movl(gpr4, 32752); + masm.pinsrw(dest, gpr4, 3); + masm.jmp(bb56); + + masm.bind(bb56); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathIntrinsicUnaryOp.java 2016-12-07 13:54:30.613681042 -0800 @@ -0,0 +1,3843 @@ +/* + * Copyright (c) 2011, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.ArrayDataPointerConstant; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; + +public final class AMD64MathIntrinsicUnaryOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64MathIntrinsicUnaryOp.class); + + public enum UnaryIntrinsicOpcode { + LOG, + LOG10, + SIN, + COS, + TAN, + EXP + } + + @Opcode private final UnaryIntrinsicOpcode opcode; + @Def protected Value result; + @Use protected Value input; + @Temp({REG, ILLEGAL}) protected Value xmm1Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm2Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm3Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm4Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm5Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm6Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm7Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm8Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm9Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value xmm10Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr1Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr2Temp = Value.ILLEGAL; + @Temp protected AllocatableValue rcxTemp; + @Temp({REG, ILLEGAL}) protected Value gpr4Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr5Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr6Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr7Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr8Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr9Temp = Value.ILLEGAL; + @Temp({REG, ILLEGAL}) protected Value gpr10Temp = Value.ILLEGAL; + @Temp({STACK, ILLEGAL}) protected Value stackTemp = Value.ILLEGAL; + + CompilationResultBuilder internalCrb; + + public AMD64MathIntrinsicUnaryOp(LIRGeneratorTool tool, UnaryIntrinsicOpcode opcode, Value result, Value input, Value stackTemp) { + super(TYPE); + this.opcode = opcode; + this.result = result; + this.input = input; + if (opcode == UnaryIntrinsicOpcode.LOG || opcode == UnaryIntrinsicOpcode.LOG10 || + opcode == UnaryIntrinsicOpcode.SIN || opcode == UnaryIntrinsicOpcode.COS || + opcode == UnaryIntrinsicOpcode.TAN || opcode == UnaryIntrinsicOpcode.EXP) { + this.gpr1Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr2Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.rcxTemp = AMD64.rcx.asValue(LIRKind.value(AMD64Kind.QWORD)); + this.gpr4Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.xmm1Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm2Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm3Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm4Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm5Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm6Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm7Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + + if (opcode == UnaryIntrinsicOpcode.EXP) { + this.gpr5Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.xmm8Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm9Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm10Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + } + + if (opcode == UnaryIntrinsicOpcode.TAN) { + this.gpr5Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr6Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr7Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr8Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr9Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr10Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + } + + if (opcode == UnaryIntrinsicOpcode.SIN || opcode == UnaryIntrinsicOpcode.COS) { + this.gpr5Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr6Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr7Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr8Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr9Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.gpr10Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD)); + this.xmm8Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.xmm9Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + } + + this.stackTemp = stackTemp; + } + } + + public AMD64MathIntrinsicUnaryOp(LIRGeneratorTool tool, UnaryIntrinsicOpcode opcode, Value result, Value input) { + this(tool, opcode, result, input, Value.ILLEGAL); + } + + private void setCrb(CompilationResultBuilder crb) { + internalCrb = crb; + } + + private AMD64Address externalAddress(ArrayDataPointerConstant curPtr) { + return (AMD64Address) internalCrb.recordDataReferenceInCode(curPtr); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + switch (opcode) { + case LOG: + logIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm); + break; + case LOG10: + log10Intrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm); + break; + case SIN: + sinIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm); + break; + case COS: + cosIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm); + break; + case TAN: + tanIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm); + break; + case EXP: + expIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + + private static int[] logTwoTable = { + 0xfefa3800, 0x3fe62e42, 0x93c76730, 0x3d2ef357, 0xaa241800, + 0x3fe5ee82, 0x0cda46be, 0x3d220238, 0x5c364800, 0x3fe5af40, + 0xac10c9fb, 0x3d2dfa63, 0x26bb8c00, 0x3fe5707a, 0xff3303dd, + 0x3d09980b, 0x26867800, 0x3fe5322e, 0x5d257531, 0x3d05ccc4, + 0x835a5000, 0x3fe4f45a, 0x6d93b8fb, 0xbd2e6c51, 0x6f970c00, + 0x3fe4b6fd, 0xed4c541c, 0x3cef7115, 0x27e8a400, 0x3fe47a15, + 0xf94d60aa, 0xbd22cb6a, 0xf2f92400, 0x3fe43d9f, 0x481051f7, + 0xbcfd984f, 0x2125cc00, 0x3fe4019c, 0x30f0c74c, 0xbd26ce79, + 0x0c36c000, 0x3fe3c608, 0x7cfe13c2, 0xbd02b736, 0x17197800, + 0x3fe38ae2, 0xbb5569a4, 0xbd218b7a, 0xad9d8c00, 0x3fe35028, + 0x9527e6ac, 0x3d10b83f, 0x44340800, 0x3fe315da, 0xc5a0ed9c, + 0xbd274e93, 0x57b0e000, 0x3fe2dbf5, 0x07b9dc11, 0xbd17a6e5, + 0x6d0ec000, 0x3fe2a278, 0xe797882d, 0x3d206d2b, 0x1134dc00, + 0x3fe26962, 0x05226250, 0xbd0b61f1, 0xd8bebc00, 0x3fe230b0, + 0x6e48667b, 0x3d12fc06, 0x5fc61800, 0x3fe1f863, 0xc9fe81d3, + 0xbd2a7242, 0x49ae6000, 0x3fe1c078, 0xed70e667, 0x3cccacde, + 0x40f23c00, 0x3fe188ee, 0xf8ab4650, 0x3d14cc4e, 0xf6f29800, + 0x3fe151c3, 0xa293ae49, 0xbd2edd97, 0x23c75c00, 0x3fe11af8, + 0xbb9ddcb2, 0xbd258647, 0x8611cc00, 0x3fe0e489, 0x07801742, + 0x3d1c2998, 0xe2d05400, 0x3fe0ae76, 0x887e7e27, 0x3d1f486b, + 0x0533c400, 0x3fe078bf, 0x41edf5fd, 0x3d268122, 0xbe760400, + 0x3fe04360, 0xe79539e0, 0xbd04c45f, 0xe5b20800, 0x3fe00e5a, + 0xb1727b1c, 0xbd053ba3, 0xaf7a4800, 0x3fdfb358, 0x3c164935, + 0x3d0085fa, 0xee031800, 0x3fdf4aa7, 0x6f014a8b, 0x3d12cde5, + 0x56b41000, 0x3fdee2a1, 0x5a470251, 0x3d2f27f4, 0xc3ddb000, + 0x3fde7b42, 0x5372bd08, 0xbd246550, 0x1a272800, 0x3fde148a, + 0x07322938, 0xbd1326b2, 0x484c9800, 0x3fddae75, 0x60dc616a, + 0xbd1ea42d, 0x46def800, 0x3fdd4902, 0xe9a767a8, 0x3d235baf, + 0x18064800, 0x3fdce42f, 0x3ec7a6b0, 0xbd0797c3, 0xc7455800, + 0x3fdc7ff9, 0xc15249ae, 0xbd29b6dd, 0x693fa000, 0x3fdc1c60, + 0x7fe8e180, 0x3d2cec80, 0x1b80e000, 0x3fdbb961, 0xf40a666d, + 0x3d27d85b, 0x04462800, 0x3fdb56fa, 0x2d841995, 0x3d109525, + 0x5248d000, 0x3fdaf529, 0x52774458, 0xbd217cc5, 0x3c8ad800, + 0x3fda93ed, 0xbea77a5d, 0x3d1e36f2, 0x0224f800, 0x3fda3344, + 0x7f9d79f5, 0x3d23c645, 0xea15f000, 0x3fd9d32b, 0x10d0c0b0, + 0xbd26279e, 0x43135800, 0x3fd973a3, 0xa502d9f0, 0xbd152313, + 0x635bf800, 0x3fd914a8, 0x2ee6307d, 0xbd1766b5, 0xa88b3000, + 0x3fd8b639, 0xe5e70470, 0xbd205ae1, 0x776dc800, 0x3fd85855, + 0x3333778a, 0x3d2fd56f, 0x3bd81800, 0x3fd7fafa, 0xc812566a, + 0xbd272090, 0x687cf800, 0x3fd79e26, 0x2efd1778, 0x3d29ec7d, + 0x76c67800, 0x3fd741d8, 0x49dc60b3, 0x3d2d8b09, 0xe6af1800, + 0x3fd6e60e, 0x7c222d87, 0x3d172165, 0x3e9c6800, 0x3fd68ac8, + 0x2756eba0, 0x3d20a0d3, 0x0b3ab000, 0x3fd63003, 0xe731ae00, + 0xbd2db623, 0xdf596000, 0x3fd5d5bd, 0x08a465dc, 0xbd0a0b2a, + 0x53c8d000, 0x3fd57bf7, 0xee5d40ef, 0x3d1faded, 0x0738a000, + 0x3fd522ae, 0x8164c759, 0x3d2ebe70, 0x9e173000, 0x3fd4c9e0, + 0x1b0ad8a4, 0xbd2e2089, 0xc271c800, 0x3fd4718d, 0x0967d675, + 0xbd2f27ce, 0x23d5e800, 0x3fd419b4, 0xec90e09d, 0x3d08e436, + 0x77333000, 0x3fd3c252, 0xb606bd5c, 0x3d183b54, 0x76be1000, + 0x3fd36b67, 0xb0f177c8, 0x3d116ecd, 0xe1d36000, 0x3fd314f1, + 0xd3213cb8, 0xbd28e27a, 0x7cdc9000, 0x3fd2bef0, 0x4a5004f4, + 0x3d2a9cfa, 0x1134d800, 0x3fd26962, 0xdf5bb3b6, 0x3d2c93c1, + 0x6d0eb800, 0x3fd21445, 0xba46baea, 0x3d0a87de, 0x635a6800, + 0x3fd1bf99, 0x5147bdb7, 0x3d2ca6ed, 0xcbacf800, 0x3fd16b5c, + 0xf7a51681, 0x3d2b9acd, 0x8227e800, 0x3fd1178e, 0x63a5f01c, + 0xbd2c210e, 0x67616000, 0x3fd0c42d, 0x163ceae9, 0x3d27188b, + 0x604d5800, 0x3fd07138, 0x16ed4e91, 0x3cf89cdb, 0x5626c800, + 0x3fd01eae, 0x1485e94a, 0xbd16f08c, 0x6cb3b000, 0x3fcf991c, + 0xca0cdf30, 0x3d1bcbec, 0xe4dd0000, 0x3fcef5ad, 0x65bb8e11, + 0xbcca2115, 0xffe71000, 0x3fce530e, 0x6041f430, 0x3cc21227, + 0xb0d49000, 0x3fcdb13d, 0xf715b035, 0xbd2aff2a, 0xf2656000, + 0x3fcd1037, 0x75b6f6e4, 0xbd084a7e, 0xc6f01000, 0x3fcc6ffb, + 0xc5962bd2, 0xbcf1ec72, 0x383be000, 0x3fcbd087, 0x595412b6, + 0xbd2d4bc4, 0x575bd000, 0x3fcb31d8, 0x4eace1aa, 0xbd0c358d, + 0x3c8ae000, 0x3fca93ed, 0x50562169, 0xbd287243, 0x07089000, + 0x3fc9f6c4, 0x6865817a, 0x3d29904d, 0xdcf70000, 0x3fc95a5a, + 0x58a0ff6f, 0x3d07f228, 0xeb390000, 0x3fc8beaf, 0xaae92cd1, + 0xbd073d54, 0x6551a000, 0x3fc823c1, 0x9a631e83, 0x3d1e0ddb, + 0x85445000, 0x3fc7898d, 0x70914305, 0xbd1c6610, 0x8b757000, + 0x3fc6f012, 0xe59c21e1, 0xbd25118d, 0xbe8c1000, 0x3fc6574e, + 0x2c3c2e78, 0x3d19cf8b, 0x6b544000, 0x3fc5bf40, 0xeb68981c, + 0xbd127023, 0xe4a1b000, 0x3fc527e5, 0xe5697dc7, 0x3d2633e8, + 0x8333b000, 0x3fc4913d, 0x54fdb678, 0x3d258379, 0xa5993000, + 0x3fc3fb45, 0x7e6a354d, 0xbd2cd1d8, 0xb0159000, 0x3fc365fc, + 0x234b7289, 0x3cc62fa8, 0x0c868000, 0x3fc2d161, 0xcb81b4a1, + 0x3d039d6c, 0x2a49c000, 0x3fc23d71, 0x8fd3df5c, 0x3d100d23, + 0x7e23f000, 0x3fc1aa2b, 0x44389934, 0x3d2ca78e, 0x8227e000, + 0x3fc1178e, 0xce2d07f2, 0x3d21ef78, 0xb59e4000, 0x3fc08598, + 0x7009902c, 0xbd27e5dd, 0x39dbe000, 0x3fbfe891, 0x4fa10afd, + 0xbd2534d6, 0x830a2000, 0x3fbec739, 0xafe645e0, 0xbd2dc068, + 0x63844000, 0x3fbda727, 0x1fa71733, 0x3d1a8940, 0x01bc4000, + 0x3fbc8858, 0xc65aacd3, 0x3d2646d1, 0x8dad6000, 0x3fbb6ac8, + 0x2bf768e5, 0xbd139080, 0x40b1c000, 0x3fba4e76, 0xb94407c8, + 0xbd0e42b6, 0x5d594000, 0x3fb9335e, 0x3abd47da, 0x3d23115c, + 0x2f40e000, 0x3fb8197e, 0xf96ffdf7, 0x3d0f80dc, 0x0aeac000, + 0x3fb700d3, 0xa99ded32, 0x3cec1e8d, 0x4d97a000, 0x3fb5e95a, + 0x3c5d1d1e, 0xbd2c6906, 0x5d208000, 0x3fb4d311, 0x82f4e1ef, + 0xbcf53a25, 0xa7d1e000, 0x3fb3bdf5, 0xa5db4ed7, 0x3d2cc85e, + 0xa4472000, 0x3fb2aa04, 0xae9c697d, 0xbd20b6e8, 0xd1466000, + 0x3fb1973b, 0x560d9e9b, 0xbd25325d, 0xb59e4000, 0x3fb08598, + 0x7009902c, 0xbd17e5dd, 0xc006c000, 0x3faeea31, 0x4fc93b7b, + 0xbd0e113e, 0xcdddc000, 0x3faccb73, 0x47d82807, 0xbd1a68f2, + 0xd0fb0000, 0x3faaaef2, 0x353bb42e, 0x3d20fc1a, 0x149fc000, + 0x3fa894aa, 0xd05a267d, 0xbd197995, 0xf2d4c000, 0x3fa67c94, + 0xec19afa2, 0xbd029efb, 0xd42e0000, 0x3fa466ae, 0x75bdfd28, + 0xbd2c1673, 0x2f8d0000, 0x3fa252f3, 0xe021b67b, 0x3d283e9a, + 0x89e74000, 0x3fa0415d, 0x5cf1d753, 0x3d0111c0, 0xec148000, + 0x3f9c63d2, 0x3f9eb2f3, 0x3d2578c6, 0x28c90000, 0x3f984925, + 0x325a0c34, 0xbd2aa0ba, 0x25980000, 0x3f9432a9, 0x928637fe, + 0x3d098139, 0x58938000, 0x3f902056, 0x06e2f7d2, 0xbd23dc5b, + 0xa3890000, 0x3f882448, 0xda74f640, 0xbd275577, 0x75890000, + 0x3f801015, 0x999d2be8, 0xbd10c76b, 0x59580000, 0x3f700805, + 0xcb31c67b, 0x3d2166af, 0x00000000, 0x00000000, 0x00000000, + 0x80000000 + }; + + private static int[] logTwoData = { + 0xfefa3800, 0x3fa62e42, 0x93c76730, 0x3ceef357 + }; + + private static int[] coeffLogTwoData = { + 0x92492492, 0x3fc24924, 0x00000000, 0xbfd00000, 0x3d6fb175, + 0xbfc5555e, 0x55555555, 0x3fd55555, 0x9999999a, 0x3fc99999, + 0x00000000, 0xbfe00000 + }; + + /* + * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM) + * Source Code + * + * ALGORITHM DESCRIPTION - LOG() --------------------- + * + * x=2^k * mx, mx in [1,2) + * + * Get B~1/mx based on the output of rcpps instruction (B0) B = int((B0*2^7+0.5))/2^7 + * + * Reduced argument: r=B*mx-1.0 (computed accurately in high and low parts) + * + * Result: k*log(2) - log(B) + p(r) if |x-1| >= small value (2^-6) and p(r) is a degree 7 + * polynomial -log(B) read from data table (high, low parts) Result is formed from high and low + * parts. + * + * Special cases: log(NaN) = quiet NaN, and raise invalid exception log(+INF) = that INF log(0) + * = -INF with divide-by-zero exception raised log(1) = +0 log(x) = NaN with invalid exception + * raised if x < -0, including -INF + * + */ + + public void logIntrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) { + ArrayDataPointerConstant logTwoTablePtr = new ArrayDataPointerConstant(logTwoTable, 16); + ArrayDataPointerConstant logTwoDataPtr = new ArrayDataPointerConstant(logTwoData, 16); + ArrayDataPointerConstant coeffLogTwoDataPtr = new ArrayDataPointerConstant(coeffLogTwoData, 16); + + Label bb0 = new Label(); + Label bb1 = new Label(); + Label bb2 = new Label(); + Label bb3 = new Label(); + Label bb4 = new Label(); + Label bb5 = new Label(); + Label bb6 = new Label(); + Label bb7 = new Label(); + Label bb8 = new Label(); + + Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD); + Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD); + Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD); + Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD); + + Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE); + Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE); + Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE); + Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE); + Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE); + Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE); + Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE); + + AMD64Address stackSlot = (AMD64Address) crb.asAddress(stackTemp); + + setCrb(crb); + masm.movdq(stackSlot, value); + if (dest.encoding != value.encoding) { + masm.movdqu(dest, value); + } + masm.movq(gpr1, 0x3ff0000000000000L); + masm.movdq(temp2, gpr1); + masm.movq(gpr3, 0x77f0000000000000L); + masm.movdq(temp3, gpr3); + masm.movl(gpr2, 32768); + masm.movdl(temp4, gpr2); + masm.movq(gpr2, 0xffffe00000000000L); + masm.movdq(temp5, gpr2); + masm.movdqu(temp1, value); + masm.pextrw(gpr1, dest, 3); + masm.por(dest, temp2); + masm.movl(gpr2, 16352); + masm.psrlq(dest, 27); + masm.leaq(gpr4, externalAddress(logTwoTablePtr)); + masm.psrld(dest, 2); + masm.rcpps(dest, dest); + masm.psllq(temp1, 12); + masm.pshufd(temp6, temp5, 0xE4); + masm.psrlq(temp1, 12); + masm.subl(gpr1, 16); + masm.cmpl(gpr1, 32736); + masm.jcc(ConditionFlag.AboveEqual, bb0); + + masm.bind(bb1); + masm.paddd(dest, temp4); + masm.por(temp1, temp3); + masm.movdl(gpr3, dest); + masm.psllq(dest, 29); + masm.pand(temp5, temp1); + masm.pand(dest, temp6); + masm.subsd(temp1, temp5); + masm.mulpd(temp5, dest); + masm.andl(gpr1, 32752); + masm.subl(gpr1, gpr2); + masm.cvtsi2sdl(temp7, gpr1); + masm.mulsd(temp1, dest); + masm.movdq(temp6, externalAddress(logTwoDataPtr)); // 0xfefa3800, + // 0x3fa62e42 + masm.movdqu(temp3, externalAddress(coeffLogTwoDataPtr)); // 0x92492492, + // 0x3fc24924, + // 0x00000000, + // 0xbfd00000 + masm.subsd(temp5, temp2); + masm.andl(gpr3, 16711680); + masm.shrl(gpr3, 12); + masm.movdqu(dest, new AMD64Address(gpr4, gpr3, Scale.Times1, 0)); + masm.leaq(gpr4, externalAddress(coeffLogTwoDataPtr)); + masm.movdqu(temp4, new AMD64Address(gpr4, 16)); // 0x3d6fb175, + // 0xbfc5555e, + // 0x55555555, + // 0x3fd55555 + masm.addsd(temp1, temp5); + masm.movdqu(temp2, new AMD64Address(gpr4, 32)); // 0x9999999a, + // 0x3fc99999, + // 0x00000000, + // 0xbfe00000 + masm.mulsd(temp6, temp7); + if (masm.supports(CPUFeature.SSE3)) { + masm.movddup(temp5, temp1); + } else { + masm.movdqu(temp5, temp1); + masm.movlhps(temp5, temp5); + } + masm.leaq(gpr4, externalAddress(logTwoDataPtr)); + masm.mulsd(temp7, new AMD64Address(gpr4, 8)); // 0x93c76730, + // 0x3ceef357 + masm.mulsd(temp3, temp1); + masm.addsd(dest, temp6); + masm.mulpd(temp4, temp5); + masm.mulpd(temp5, temp5); + if (masm.supports(CPUFeature.SSE3)) { + masm.movddup(temp6, dest); + } else { + masm.movdqu(temp6, dest); + masm.movlhps(temp6, temp6); + } + masm.addsd(dest, temp1); + masm.addpd(temp4, temp2); + masm.mulpd(temp3, temp5); + masm.subsd(temp6, dest); + masm.mulsd(temp4, temp1); + masm.pshufd(temp2, dest, 0xEE); + masm.addsd(temp1, temp6); + masm.mulsd(temp5, temp5); + masm.addsd(temp7, temp2); + masm.addpd(temp4, temp3); + masm.addsd(temp1, temp7); + masm.mulpd(temp4, temp5); + masm.addsd(temp1, temp4); + masm.pshufd(temp5, temp4, 0xEE); + masm.addsd(temp1, temp5); + masm.addsd(dest, temp1); + masm.jmp(bb8); + + masm.bind(bb0); + masm.movdq(dest, stackSlot); + masm.movdq(temp1, stackSlot); + masm.addl(gpr1, 16); + masm.cmpl(gpr1, 32768); + masm.jcc(ConditionFlag.AboveEqual, bb2); + + masm.cmpl(gpr1, 16); + masm.jcc(ConditionFlag.Below, bb3); + + masm.bind(bb4); + masm.addsd(dest, dest); + masm.jmp(bb8); + + masm.bind(bb5); + masm.jcc(ConditionFlag.Above, bb4); + + masm.cmpl(gpr3, 0); + masm.jcc(ConditionFlag.Above, bb4); + + masm.jmp(bb6); + + masm.bind(bb3); + masm.xorpd(temp1, temp1); + masm.addsd(temp1, dest); + masm.movdl(gpr3, temp1); + masm.psrlq(temp1, 32); + masm.movdl(gpr2, temp1); + masm.orl(gpr3, gpr2); + masm.cmpl(gpr3, 0); + masm.jcc(ConditionFlag.Equal, bb7); + + masm.xorpd(temp1, temp1); + masm.movl(gpr1, 18416); + masm.pinsrw(temp1, gpr1, 3); + masm.mulsd(dest, temp1); + masm.movdqu(temp1, dest); + masm.pextrw(gpr1, dest, 3); + masm.por(dest, temp2); + masm.psrlq(dest, 27); + masm.movl(gpr2, 18416); + masm.psrld(dest, 2); + masm.rcpps(dest, dest); + masm.psllq(temp1, 12); + masm.pshufd(temp6, temp5, 0xE4); + masm.psrlq(temp1, 12); + masm.jmp(bb1); + + masm.bind(bb2); + masm.movdl(gpr3, temp1); + masm.psrlq(temp1, 32); + masm.movdl(gpr2, temp1); + masm.addl(gpr2, gpr2); + masm.cmpl(gpr2, -2097152); + masm.jcc(ConditionFlag.AboveEqual, bb5); + + masm.orl(gpr3, gpr2); + masm.cmpl(gpr3, 0); + masm.jcc(ConditionFlag.Equal, bb7); + + masm.bind(bb6); + masm.xorpd(temp1, temp1); + masm.xorpd(dest, dest); + masm.movl(gpr1, 32752); + masm.pinsrw(temp1, gpr1, 3); + masm.mulsd(dest, temp1); + masm.jmp(bb8); + + masm.bind(bb7); + masm.xorpd(temp1, temp1); + masm.xorpd(dest, dest); + masm.movl(gpr1, 49136); + masm.pinsrw(dest, gpr1, 3); + masm.divsd(dest, temp1); + + masm.bind(bb8); + } + + private static int[] highmaskLogTen = { + 0xf8000000, 0xffffffff, 0x00000000, 0xffffe000 + }; + + private static int[] logTenE = { + 0x00000000, 0x3fdbc000, 0xbf2e4108, 0x3f5a7a6c + }; + + private static int[] logTenTable = { + 0x509f7800, 0x3fd34413, 0x1f12b358, 0x3d1fef31, 0x80333400, + 0x3fd32418, 0xc671d9d0, 0xbcf542bf, 0x51195000, 0x3fd30442, + 0x78a4b0c3, 0x3d18216a, 0x6fc79400, 0x3fd2e490, 0x80fa389d, + 0xbc902869, 0x89d04000, 0x3fd2c502, 0x75c2f564, 0x3d040754, + 0x4ddd1c00, 0x3fd2a598, 0xd219b2c3, 0xbcfa1d84, 0x6baa7c00, + 0x3fd28651, 0xfd9abec1, 0x3d1be6d3, 0x94028800, 0x3fd2672d, + 0xe289a455, 0xbd1ede5e, 0x78b86400, 0x3fd2482c, 0x6734d179, + 0x3d1fe79b, 0xcca3c800, 0x3fd2294d, 0x981a40b8, 0xbced34ea, + 0x439c5000, 0x3fd20a91, 0xcc392737, 0xbd1a9cc3, 0x92752c00, + 0x3fd1ebf6, 0x03c9afe7, 0x3d1e98f8, 0x6ef8dc00, 0x3fd1cd7d, + 0x71dae7f4, 0x3d08a86c, 0x8fe4dc00, 0x3fd1af25, 0xee9185a1, + 0xbcff3412, 0xace59400, 0x3fd190ee, 0xc2cab353, 0x3cf17ed9, + 0x7e925000, 0x3fd172d8, 0x6952c1b2, 0x3cf1521c, 0xbe694400, + 0x3fd154e2, 0xcacb79ca, 0xbd0bdc78, 0x26cbac00, 0x3fd1370d, + 0xf71f4de1, 0xbd01f8be, 0x72fa0800, 0x3fd11957, 0x55bf910b, + 0x3c946e2b, 0x5f106000, 0x3fd0fbc1, 0x39e639c1, 0x3d14a84b, + 0xa802a800, 0x3fd0de4a, 0xd3f31d5d, 0xbd178385, 0x0b992000, + 0x3fd0c0f3, 0x3843106f, 0xbd1f602f, 0x486ce800, 0x3fd0a3ba, + 0x8819497c, 0x3cef987a, 0x1de49400, 0x3fd086a0, 0x1caa0467, + 0x3d0faec7, 0x4c30cc00, 0x3fd069a4, 0xa4424372, 0xbd1618fc, + 0x94490000, 0x3fd04cc6, 0x946517d2, 0xbd18384b, 0xb7e84000, + 0x3fd03006, 0xe0109c37, 0xbd19a6ac, 0x798a0c00, 0x3fd01364, + 0x5121e864, 0xbd164cf7, 0x38ce8000, 0x3fcfedbf, 0x46214d1a, + 0xbcbbc402, 0xc8e62000, 0x3fcfb4ef, 0xdab93203, 0x3d1e0176, + 0x2cb02800, 0x3fcf7c5a, 0x2a2ea8e4, 0xbcfec86a, 0xeeeaa000, + 0x3fcf43fd, 0xc18e49a4, 0x3cf110a8, 0x9bb6e800, 0x3fcf0bda, + 0x923cc9c0, 0xbd15ce99, 0xc093f000, 0x3fced3ef, 0x4d4b51e9, + 0x3d1a04c7, 0xec58f800, 0x3fce9c3c, 0x163cad59, 0x3cac8260, + 0x9a907000, 0x3fce2d7d, 0x3fa93646, 0x3ce4a1c0, 0x37311000, + 0x3fcdbf99, 0x32abd1fd, 0x3d07ea9d, 0x6744b800, 0x3fcd528c, + 0x4dcbdfd4, 0xbd1b08e2, 0xe36de800, 0x3fcce653, 0x0b7b7f7f, + 0xbd1b8f03, 0x77506800, 0x3fcc7aec, 0xa821c9fb, 0x3d13c163, + 0x00ff8800, 0x3fcc1053, 0x536bca76, 0xbd074ee5, 0x70719800, + 0x3fcba684, 0xd7da9b6b, 0xbd1fbf16, 0xc6f8d800, 0x3fcb3d7d, + 0xe2220bb3, 0x3d1a295d, 0x16c15800, 0x3fcad53c, 0xe724911e, + 0xbcf55822, 0x82533800, 0x3fca6dbc, 0x6d982371, 0x3cac567c, + 0x3c19e800, 0x3fca06fc, 0x84d17d80, 0x3d1da204, 0x85ef8000, + 0x3fc9a0f8, 0x54466a6a, 0xbd002204, 0xb0ac2000, 0x3fc93bae, + 0xd601fd65, 0x3d18840c, 0x1bb9b000, 0x3fc8d71c, 0x7bf58766, + 0xbd14f897, 0x34aae800, 0x3fc8733e, 0x3af6ac24, 0xbd0f5c45, + 0x76d68000, 0x3fc81012, 0x4303e1a1, 0xbd1f9a80, 0x6af57800, + 0x3fc7ad96, 0x43fbcb46, 0x3cf4c33e, 0xa6c51000, 0x3fc74bc7, + 0x70f0eac5, 0xbd192e3b, 0xccab9800, 0x3fc6eaa3, 0xc0093dfe, + 0xbd0faf15, 0x8b60b800, 0x3fc68a28, 0xde78d5fd, 0xbc9ea4ee, + 0x9d987000, 0x3fc62a53, 0x962bea6e, 0xbd194084, 0xc9b0e800, + 0x3fc5cb22, 0x888dd999, 0x3d1fe201, 0xe1634800, 0x3fc56c93, + 0x16ada7ad, 0x3d1b1188, 0xc176c000, 0x3fc50ea4, 0x4159b5b5, + 0xbcf09c08, 0x51766000, 0x3fc4b153, 0x84393d23, 0xbcf6a89c, + 0x83695000, 0x3fc4549d, 0x9f0b8bbb, 0x3d1c4b8c, 0x538d5800, + 0x3fc3f881, 0xf49df747, 0x3cf89b99, 0xc8138000, 0x3fc39cfc, + 0xd503b834, 0xbd13b99f, 0xf0df0800, 0x3fc3420d, 0xf011b386, + 0xbd05d8be, 0xe7466800, 0x3fc2e7b2, 0xf39c7bc2, 0xbd1bb94e, + 0xcdd62800, 0x3fc28de9, 0x05e6d69b, 0xbd10ed05, 0xd015d800, + 0x3fc234b0, 0xe29b6c9d, 0xbd1ff967, 0x224ea800, 0x3fc1dc06, + 0x727711fc, 0xbcffb30d, 0x01540000, 0x3fc183e8, 0x39786c5a, + 0x3cc23f57, 0xb24d9800, 0x3fc12c54, 0xc905a342, 0x3d003a1d, + 0x82835800, 0x3fc0d54a, 0x9b9920c0, 0x3d03b25a, 0xc72ac000, + 0x3fc07ec7, 0x46f26a24, 0x3cf0fa41, 0xdd35d800, 0x3fc028ca, + 0x41d9d6dc, 0x3d034a65, 0x52474000, 0x3fbfa6a4, 0x44f66449, + 0x3d19cad3, 0x2da3d000, 0x3fbefcb8, 0x67832999, 0x3d18400f, + 0x32a10000, 0x3fbe53ce, 0x9c0e3b1a, 0xbcff62fd, 0x556b7000, + 0x3fbdabe3, 0x02976913, 0xbcf8243b, 0x97e88000, 0x3fbd04f4, + 0xec793797, 0x3d1c0578, 0x09647000, 0x3fbc5eff, 0x05fc0565, + 0xbd1d799e, 0xc6426000, 0x3fbbb9ff, 0x4625f5ed, 0x3d1f5723, + 0xf7afd000, 0x3fbb15f3, 0xdd5aae61, 0xbd1a7e1e, 0xd358b000, + 0x3fba72d8, 0x3314e4d3, 0x3d17bc91, 0x9b1f5000, 0x3fb9d0ab, + 0x9a4d514b, 0x3cf18c9b, 0x9cd4e000, 0x3fb92f69, 0x7e4496ab, + 0x3cf1f96d, 0x31f4f000, 0x3fb88f10, 0xf56479e7, 0x3d165818, + 0xbf628000, 0x3fb7ef9c, 0x26bf486d, 0xbd1113a6, 0xb526b000, + 0x3fb7510c, 0x1a1c3384, 0x3ca9898d, 0x8e31e000, 0x3fb6b35d, + 0xb3875361, 0xbd0661ac, 0xd01de000, 0x3fb6168c, 0x2a7cacfa, + 0xbd1bdf10, 0x0af23000, 0x3fb57a98, 0xff868816, 0x3cf046d0, + 0xd8ea0000, 0x3fb4df7c, 0x1515fbe7, 0xbd1fd529, 0xde3b2000, + 0x3fb44538, 0x6e59a132, 0x3d1faeee, 0xc8df9000, 0x3fb3abc9, + 0xf1322361, 0xbd198807, 0x505f1000, 0x3fb3132d, 0x0888e6ab, + 0x3d1e5380, 0x359bd000, 0x3fb27b61, 0xdfbcbb22, 0xbcfe2724, + 0x429ee000, 0x3fb1e463, 0x6eb4c58c, 0xbcfe4dd6, 0x4a673000, + 0x3fb14e31, 0x4ce1ac9b, 0x3d1ba691, 0x28b96000, 0x3fb0b8c9, + 0x8c7813b8, 0xbd0b3872, 0xc1f08000, 0x3fb02428, 0xc2bc8c2c, + 0x3cb5ea6b, 0x05a1a000, 0x3faf209c, 0x72e8f18e, 0xbce8df84, + 0xc0b5e000, 0x3fadfa6d, 0x9fdef436, 0x3d087364, 0xaf416000, + 0x3facd5c2, 0x1068c3a9, 0x3d0827e7, 0xdb356000, 0x3fabb296, + 0x120a34d3, 0x3d101a9f, 0x5dfea000, 0x3faa90e6, 0xdaded264, + 0xbd14c392, 0x6034c000, 0x3fa970ad, 0x1c9d06a9, 0xbd1b705e, + 0x194c6000, 0x3fa851e8, 0x83996ad9, 0xbd0117bc, 0xcf4ac000, + 0x3fa73492, 0xb1a94a62, 0xbca5ea42, 0xd67b4000, 0x3fa618a9, + 0x75aed8ca, 0xbd07119b, 0x9126c000, 0x3fa4fe29, 0x5291d533, + 0x3d12658f, 0x6f4d4000, 0x3fa3e50e, 0xcd2c5cd9, 0x3d1d5c70, + 0xee608000, 0x3fa2cd54, 0xd1008489, 0x3d1a4802, 0x9900e000, + 0x3fa1b6f9, 0x54fb5598, 0xbd16593f, 0x06bb6000, 0x3fa0a1f9, + 0x64ef57b4, 0xbd17636b, 0xb7940000, 0x3f9f1c9f, 0xee6a4737, + 0x3cb5d479, 0x91aa0000, 0x3f9cf7f5, 0x3a16373c, 0x3d087114, + 0x156b8000, 0x3f9ad5ed, 0x836c554a, 0x3c6900b0, 0xd4764000, + 0x3f98b67f, 0xed12f17b, 0xbcffc974, 0x77dec000, 0x3f9699a7, + 0x232ce7ea, 0x3d1e35bb, 0xbfbf4000, 0x3f947f5d, 0xd84ffa6e, + 0x3d0e0a49, 0x82c7c000, 0x3f92679c, 0x8d170e90, 0xbd14d9f2, + 0xadd20000, 0x3f90525d, 0x86d9f88e, 0x3cdeb986, 0x86f10000, + 0x3f8c7f36, 0xb9e0a517, 0x3ce29faa, 0xb75c8000, 0x3f885e9e, + 0x542568cb, 0xbd1f7bdb, 0x46b30000, 0x3f8442e8, 0xb954e7d9, + 0x3d1e5287, 0xb7e60000, 0x3f802c07, 0x22da0b17, 0xbd19fb27, + 0x6c8b0000, 0x3f7833e3, 0x821271ef, 0xbd190f96, 0x29910000, + 0x3f701936, 0xbc3491a5, 0xbd1bcf45, 0x354a0000, 0x3f600fe3, + 0xc0ff520a, 0xbd19d71c, 0x00000000, 0x00000000, 0x00000000, + 0x00000000 + }; + + private static int[] logTwoLogTenData = { + 0x509f7800, 0x3f934413, 0x1f12b358, 0x3cdfef31 + }; + + private static int[] coeffLogTenData = { + 0xc1a5f12e, 0x40358874, 0x64d4ef0d, 0xc0089309, 0x385593b1, + 0xc025c917, 0xdc963467, 0x3ffc6a02, 0x7f9d3aa1, 0x4016ab9f, + 0xdc77b115, 0xbff27af2 + }; + + /* + * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM) + * Source Code + * + * ALGORITHM DESCRIPTION - LOG10() --------------------- + * + * Let x=2^k * mx, mx in [1,2) + * + * Get B~1/mx based on the output of rcpss instruction (B0) B = int((B0*LH*2^7+0.5))/2^7 LH is a + * short approximation for log10(e) + * + * Reduced argument: r=B*mx-LH (computed accurately in high and low parts) + * + * Result: k*log10(2) - log(B) + p(r) p(r) is a degree 7 polynomial -log(B) read from data table + * (high, low parts) Result is formed from high and low parts + * + * Special cases: log10(0) = -INF with divide-by-zero exception raised log10(1) = +0 log10(x) = + * NaN with invalid exception raised if x < -0, including -INF log10(+INF) = +INF + * + */ + + public void log10Intrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) { + ArrayDataPointerConstant highmaskLogTenPtr = new ArrayDataPointerConstant(highmaskLogTen, 16); + ArrayDataPointerConstant logTenEPtr = new ArrayDataPointerConstant(logTenE, 16); + ArrayDataPointerConstant logTenTablePtr = new ArrayDataPointerConstant(logTenTable, 16); + ArrayDataPointerConstant logTwoLogTenDataPtr = new ArrayDataPointerConstant(logTwoLogTenData, 16); + ArrayDataPointerConstant coeffLogTenDataPtr = new ArrayDataPointerConstant(coeffLogTenData, 16); + + Label bb0 = new Label(); + Label bb1 = new Label(); + Label bb2 = new Label(); + Label bb3 = new Label(); + Label bb4 = new Label(); + Label bb5 = new Label(); + Label bb6 = new Label(); + Label bb7 = new Label(); + Label bb8 = new Label(); + + Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD); + Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD); + Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD); + Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD); + + Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE); + Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE); + Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE); + Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE); + Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE); + Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE); + Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE); + + AMD64Address stackSlot = (AMD64Address) crb.asAddress(stackTemp); + + setCrb(crb); + masm.movdq(stackSlot, value); + if (dest.encoding != value.encoding) { + masm.movdqu(dest, value); + } + masm.movdqu(temp5, externalAddress(highmaskLogTenPtr)); // 0xf8000000, + // 0xffffffff, + // 0x00000000, + // 0xffffe000 + masm.xorpd(temp2, temp2); + masm.movl(gpr1, 16368); + masm.pinsrw(temp2, gpr1, 3); + masm.movl(gpr2, 1054736384); + masm.movdl(temp7, gpr2); + masm.xorpd(temp3, temp3); + masm.movl(gpr3, 30704); + masm.pinsrw(temp3, gpr3, 3); + masm.movl(gpr3, 32768); + masm.movdl(temp4, gpr3); + masm.movdqu(temp1, value); + masm.pextrw(gpr1, dest, 3); + masm.por(dest, temp2); + masm.movl(gpr2, 16352); + masm.psrlq(dest, 27); + masm.movdqu(temp2, externalAddress(logTenEPtr)); // 0x00000000, + // 0x3fdbc000, + // 0xbf2e4108, + // 0x3f5a7a6c + masm.psrld(dest, 2); + masm.rcpps(dest, dest); + masm.psllq(temp1, 12); + masm.pshufd(temp6, temp5, 0x4E); + masm.psrlq(temp1, 12); + masm.subl(gpr1, 16); + masm.cmpl(gpr1, 32736); + masm.jcc(ConditionFlag.AboveEqual, bb0); + + masm.bind(bb1); + masm.mulss(dest, temp7); + masm.por(temp1, temp3); + masm.andpd(temp5, temp1); + masm.paddd(dest, temp4); + masm.movdqu(temp3, externalAddress(coeffLogTenDataPtr)); // 0xc1a5f12e, + // 0x40358874, + // 0x64d4ef0d, + // 0xc0089309 + masm.leaq(gpr4, externalAddress(coeffLogTenDataPtr)); + masm.movdqu(temp4, new AMD64Address(gpr4, 16)); // 0x385593b1, + // 0xc025c917, + // 0xdc963467, + // 0x3ffc6a02 + masm.subsd(temp1, temp5); + masm.movdl(gpr3, dest); + masm.psllq(dest, 29); + masm.andpd(dest, temp6); + masm.movdq(temp6, externalAddress(logTwoLogTenDataPtr)); // 0x509f7800, + // 0x3f934413 + masm.andl(gpr1, 32752); + masm.subl(gpr1, gpr2); + masm.cvtsi2sdl(temp7, gpr1); + masm.mulpd(temp5, dest); + masm.mulsd(temp1, dest); + masm.subsd(temp5, temp2); + masm.movdqu(temp2, new AMD64Address(gpr4, 32)); // 0x7f9d3aa1, + // 0x4016ab9f, + // 0xdc77b115, + // 0xbff27af2 + masm.leaq(gpr4, externalAddress(logTenTablePtr)); + masm.andl(gpr3, 16711680); + masm.shrl(gpr3, 12); + masm.movdqu(dest, new AMD64Address(gpr4, gpr3, Scale.Times1, -1504)); + masm.addsd(temp1, temp5); + masm.mulsd(temp6, temp7); + masm.pshufd(temp5, temp1, 0x44); + masm.leaq(gpr4, externalAddress(logTwoLogTenDataPtr)); + masm.mulsd(temp7, new AMD64Address(gpr4, 8)); // 0x1f12b358, + // 0x3cdfef31 + masm.mulsd(temp3, temp1); + masm.addsd(dest, temp6); + masm.mulpd(temp4, temp5); + masm.leaq(gpr4, externalAddress(logTenEPtr)); + masm.movdq(temp6, new AMD64Address(gpr4, 8)); // 0xbf2e4108, + // 0x3f5a7a6c + masm.mulpd(temp5, temp5); + masm.addpd(temp4, temp2); + masm.mulpd(temp3, temp5); + masm.pshufd(temp2, dest, 0xE4); + masm.addsd(dest, temp1); + masm.mulsd(temp4, temp1); + masm.subsd(temp2, dest); + masm.mulsd(temp6, temp1); + masm.addsd(temp1, temp2); + masm.pshufd(temp2, dest, 0xEE); + masm.mulsd(temp5, temp5); + masm.addsd(temp7, temp2); + masm.addsd(temp1, temp6); + masm.addpd(temp4, temp3); + masm.addsd(temp1, temp7); + masm.mulpd(temp4, temp5); + masm.addsd(temp1, temp4); + masm.pshufd(temp5, temp4, 0xEE); + masm.addsd(temp1, temp5); + masm.addsd(dest, temp1); + masm.jmp(bb8); + + masm.bind(bb0); + masm.movdq(dest, stackSlot); + masm.movdq(temp1, stackSlot); + masm.addl(gpr1, 16); + masm.cmpl(gpr1, 32768); + masm.jcc(ConditionFlag.AboveEqual, bb2); + + masm.cmpl(gpr1, 16); + masm.jcc(ConditionFlag.Below, bb3); + + masm.bind(bb4); + masm.addsd(dest, dest); + masm.jmp(bb8); + + masm.bind(bb5); + masm.jcc(ConditionFlag.Above, bb4); + + masm.cmpl(gpr3, 0); + masm.jcc(ConditionFlag.Above, bb4); + + masm.jmp(bb6); + + masm.bind(bb3); + masm.xorpd(temp1, temp1); + masm.addsd(temp1, dest); + masm.movdl(gpr3, temp1); + masm.psrlq(temp1, 32); + masm.movdl(gpr2, temp1); + masm.orl(gpr3, gpr2); + masm.cmpl(gpr3, 0); + masm.jcc(ConditionFlag.Equal, bb7); + + masm.xorpd(temp1, temp1); + masm.xorpd(temp2, temp2); + masm.movl(gpr1, 18416); + masm.pinsrw(temp1, gpr1, 3); + masm.mulsd(dest, temp1); + masm.movl(gpr1, 16368); + masm.pinsrw(temp2, gpr1, 3); + masm.movdqu(temp1, dest); + masm.pextrw(gpr1, dest, 3); + masm.por(dest, temp2); + masm.movl(gpr2, 18416); + masm.psrlq(dest, 27); + masm.movdqu(temp2, externalAddress(logTenEPtr)); // 0x00000000, + // 0x3fdbc000, + // 0xbf2e4108, + // 0x3f5a7a6c + masm.psrld(dest, 2); + masm.rcpps(dest, dest); + masm.psllq(temp1, 12); + masm.pshufd(temp6, temp5, 0x4E); + masm.psrlq(temp1, 12); + masm.jmp(bb1); + + masm.bind(bb2); + masm.movdl(gpr3, temp1); + masm.psrlq(temp1, 32); + masm.movdl(gpr2, temp1); + masm.addl(gpr2, gpr2); + masm.cmpl(gpr2, -2097152); + masm.jcc(ConditionFlag.AboveEqual, bb5); + + masm.orl(gpr3, gpr2); + masm.cmpl(gpr3, 0); + masm.jcc(ConditionFlag.Equal, bb7); + + masm.bind(bb6); + masm.xorpd(temp1, temp1); + masm.xorpd(dest, dest); + masm.movl(gpr1, 32752); + masm.pinsrw(temp1, gpr1, 3); + masm.mulsd(dest, temp1); + masm.jmp(bb8); + + masm.bind(bb7); + masm.xorpd(temp1, temp1); + masm.xorpd(dest, dest); + masm.movl(gpr1, 49136); + masm.pinsrw(dest, gpr1, 3); + masm.divsd(dest, temp1); + + masm.bind(bb8); + } + + /* + * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM) + * Source Code + * + * ALGORITHM DESCRIPTION - SIN() --------------------- + * + * 1. RANGE REDUCTION + * + * We perform an initial range reduction from X to r with + * + * X =~= N * pi/32 + r + * + * so that |r| <= pi/64 + epsilon. We restrict inputs to those where |N| <= 932560. Beyond this, + * the range reduction is insufficiently accurate. For extremely small inputs, denormalization + * can occur internally, impacting performance. This means that the main path is actually only + * taken for 2^-252 <= |X| < 90112. + * + * To avoid branches, we perform the range reduction to full accuracy each time. + * + * X - N * (P_1 + P_2 + P_3) + * + * where P_1 and P_2 are 32-bit numbers (so multiplication by N is exact) and P_3 is a 53-bit + * number. Together, these approximate pi well enough for all cases in the restricted range. + * + * The main reduction sequence is: + * + * y = 32/pi * x N = integer(y) (computed by adding and subtracting off SHIFTER) + * + * m_1 = N * P_1 m_2 = N * P_2 r_1 = x - m_1 r = r_1 - m_2 (this r can be used for most of the + * calculation) + * + * c_1 = r_1 - r m_3 = N * P_3 c_2 = c_1 - m_2 c = c_2 - m_3 + * + * 2. MAIN ALGORITHM + * + * The algorithm uses a table lookup based on B = M * pi / 32 where M = N mod 64. The stored + * values are: sigma closest power of 2 to cos(B) C_hl 53-bit cos(B) - sigma S_hi + S_lo 2 * + * 53-bit sin(B) + * + * The computation is organized as follows: + * + * sin(B + r + c) = [sin(B) + sigma * r] + r * (cos(B) - sigma) + sin(B) * [cos(r + c) - 1] + + * cos(B) * [sin(r + c) - r] + * + * which is approximately: + * + * [S_hi + sigma * r] + C_hl * r + S_lo + S_hi * [(cos(r) - 1) - r * c] + (C_hl + sigma) * + * [(sin(r) - r) + c] + * + * and this is what is actually computed. We separate this sum into four parts: + * + * hi + med + pols + corr + * + * where + * + * hi = S_hi + sigma r med = C_hl * r pols = S_hi * (cos(r) - 1) + (C_hl + sigma) * (sin(r) - r) + * corr = S_lo + c * ((C_hl + sigma) - S_hi * r) + * + * 3. POLYNOMIAL + * + * The polynomial S_hi * (cos(r) - 1) + (C_hl + sigma) * (sin(r) - r) can be rearranged freely, + * since it is quite small, so we exploit parallelism to the fullest. + * + * psc4 = SC_4 * r_1 msc4 = psc4 * r r2 = r * r msc2 = SC_2 * r2 r4 = r2 * r2 psc3 = SC_3 + msc4 + * psc1 = SC_1 + msc2 msc3 = r4 * psc3 sincospols = psc1 + msc3 pols = sincospols * + * + * 4. CORRECTION TERM + * + * This is where the "c" component of the range reduction is taken into account; recall that + * just "r" is used for most of the calculation. + * + * -c = m_3 - c_2 -d = S_hi * r - (C_hl + sigma) corr = -c * -d + S_lo + * + * 5. COMPENSATED SUMMATIONS + * + * The two successive compensated summations add up the high and medium parts, leaving just the + * low parts to add up at the end. + * + * rs = sigma * r res_int = S_hi + rs k_0 = S_hi - res_int k_2 = k_0 + rs med = C_hl * r res_hi + * = res_int + med k_1 = res_int - res_hi k_3 = k_1 + med + * + * 6. FINAL SUMMATION + * + * We now add up all the small parts: + * + * res_lo = pols(hi) + pols(lo) + corr + k_1 + k_3 + * + * Now the overall result is just: + * + * res_hi + res_lo + * + * 7. SMALL ARGUMENTS + * + * If |x| < SNN (SNN meaning the smallest normal number), we simply perform 0.1111111 cdots 1111 + * * x. For SNN <= |x|, we do 2^-55 * (2^55 * x - x). + * + * Special cases: sin(NaN) = quiet NaN, and raise invalid exception sin(INF) = NaN and raise + * invalid exception sin(+/-0) = +/-0 + * + */ + + public int[] oneHalf = { + 0x00000000, 0x3fe00000, 0x00000000, 0x3fe00000 + }; + + public int[] pTwo = { + 0x1a600000, 0x3d90b461, 0x1a600000, 0x3d90b461 + }; + + public int[] scFour = { + 0xa556c734, 0x3ec71de3, 0x1a01a01a, 0x3efa01a0 + }; + + public int[] cTable = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3ff00000, 0x176d6d31, 0xbf73b92e, + 0xbc29b42c, 0x3fb917a6, 0xe0000000, 0xbc3e2718, 0x00000000, + 0x3ff00000, 0x011469fb, 0xbf93ad06, 0x3c69a60b, 0x3fc8f8b8, + 0xc0000000, 0xbc626d19, 0x00000000, 0x3ff00000, 0x939d225a, + 0xbfa60bea, 0x2ed59f06, 0x3fd29406, 0xa0000000, 0xbc75d28d, + 0x00000000, 0x3ff00000, 0x866b95cf, 0xbfb37ca1, 0xa6aea963, + 0x3fd87de2, 0xe0000000, 0xbc672ced, 0x00000000, 0x3ff00000, + 0x73fa1279, 0xbfbe3a68, 0x3806f63b, 0x3fde2b5d, 0x20000000, + 0x3c5e0d89, 0x00000000, 0x3ff00000, 0x5bc57974, 0xbfc59267, + 0x39ae68c8, 0x3fe1c73b, 0x20000000, 0x3c8b25dd, 0x00000000, + 0x3ff00000, 0x53aba2fd, 0xbfcd0dfe, 0x25091dd6, 0x3fe44cf3, + 0x20000000, 0x3c68076a, 0x00000000, 0x3ff00000, 0x99fcef32, + 0x3fca8279, 0x667f3bcd, 0x3fe6a09e, 0x20000000, 0xbc8bdd34, + 0x00000000, 0x3fe00000, 0x94247758, 0x3fc133cc, 0x6b151741, + 0x3fe8bc80, 0x20000000, 0xbc82c5e1, 0x00000000, 0x3fe00000, + 0x9ae68c87, 0x3fac73b3, 0x290ea1a3, 0x3fea9b66, 0xe0000000, + 0x3c39f630, 0x00000000, 0x3fe00000, 0x7f909c4e, 0xbf9d4a2c, + 0xf180bdb1, 0x3fec38b2, 0x80000000, 0xbc76e0b1, 0x00000000, + 0x3fe00000, 0x65455a75, 0xbfbe0875, 0xcf328d46, 0x3fed906b, + 0x20000000, 0x3c7457e6, 0x00000000, 0x3fe00000, 0x76acf82d, + 0x3fa4a031, 0x56c62dda, 0x3fee9f41, 0xe0000000, 0x3c8760b1, + 0x00000000, 0x3fd00000, 0x0e5967d5, 0xbfac1d1f, 0xcff75cb0, + 0x3fef6297, 0x20000000, 0x3c756217, 0x00000000, 0x3fd00000, + 0x0f592f50, 0xbf9ba165, 0xa3d12526, 0x3fefd88d, 0x40000000, + 0xbc887df6, 0x00000000, 0x3fc00000, 0x00000000, 0x00000000, + 0x00000000, 0x3ff00000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x0f592f50, 0x3f9ba165, 0xa3d12526, 0x3fefd88d, + 0x40000000, 0xbc887df6, 0x00000000, 0xbfc00000, 0x0e5967d5, + 0x3fac1d1f, 0xcff75cb0, 0x3fef6297, 0x20000000, 0x3c756217, + 0x00000000, 0xbfd00000, 0x76acf82d, 0xbfa4a031, 0x56c62dda, + 0x3fee9f41, 0xe0000000, 0x3c8760b1, 0x00000000, 0xbfd00000, + 0x65455a75, 0x3fbe0875, 0xcf328d46, 0x3fed906b, 0x20000000, + 0x3c7457e6, 0x00000000, 0xbfe00000, 0x7f909c4e, 0x3f9d4a2c, + 0xf180bdb1, 0x3fec38b2, 0x80000000, 0xbc76e0b1, 0x00000000, + 0xbfe00000, 0x9ae68c87, 0xbfac73b3, 0x290ea1a3, 0x3fea9b66, + 0xe0000000, 0x3c39f630, 0x00000000, 0xbfe00000, 0x94247758, + 0xbfc133cc, 0x6b151741, 0x3fe8bc80, 0x20000000, 0xbc82c5e1, + 0x00000000, 0xbfe00000, 0x99fcef32, 0xbfca8279, 0x667f3bcd, + 0x3fe6a09e, 0x20000000, 0xbc8bdd34, 0x00000000, 0xbfe00000, + 0x53aba2fd, 0x3fcd0dfe, 0x25091dd6, 0x3fe44cf3, 0x20000000, + 0x3c68076a, 0x00000000, 0xbff00000, 0x5bc57974, 0x3fc59267, + 0x39ae68c8, 0x3fe1c73b, 0x20000000, 0x3c8b25dd, 0x00000000, + 0xbff00000, 0x73fa1279, 0x3fbe3a68, 0x3806f63b, 0x3fde2b5d, + 0x20000000, 0x3c5e0d89, 0x00000000, 0xbff00000, 0x866b95cf, + 0x3fb37ca1, 0xa6aea963, 0x3fd87de2, 0xe0000000, 0xbc672ced, + 0x00000000, 0xbff00000, 0x939d225a, 0x3fa60bea, 0x2ed59f06, + 0x3fd29406, 0xa0000000, 0xbc75d28d, 0x00000000, 0xbff00000, + 0x011469fb, 0x3f93ad06, 0x3c69a60b, 0x3fc8f8b8, 0xc0000000, + 0xbc626d19, 0x00000000, 0xbff00000, 0x176d6d31, 0x3f73b92e, + 0xbc29b42c, 0x3fb917a6, 0xe0000000, 0xbc3e2718, 0x00000000, + 0xbff00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xbff00000, 0x176d6d31, + 0x3f73b92e, 0xbc29b42c, 0xbfb917a6, 0xe0000000, 0x3c3e2718, + 0x00000000, 0xbff00000, 0x011469fb, 0x3f93ad06, 0x3c69a60b, + 0xbfc8f8b8, 0xc0000000, 0x3c626d19, 0x00000000, 0xbff00000, + 0x939d225a, 0x3fa60bea, 0x2ed59f06, 0xbfd29406, 0xa0000000, + 0x3c75d28d, 0x00000000, 0xbff00000, 0x866b95cf, 0x3fb37ca1, + 0xa6aea963, 0xbfd87de2, 0xe0000000, 0x3c672ced, 0x00000000, + 0xbff00000, 0x73fa1279, 0x3fbe3a68, 0x3806f63b, 0xbfde2b5d, + 0x20000000, 0xbc5e0d89, 0x00000000, 0xbff00000, 0x5bc57974, + 0x3fc59267, 0x39ae68c8, 0xbfe1c73b, 0x20000000, 0xbc8b25dd, + 0x00000000, 0xbff00000, 0x53aba2fd, 0x3fcd0dfe, 0x25091dd6, + 0xbfe44cf3, 0x20000000, 0xbc68076a, 0x00000000, 0xbff00000, + 0x99fcef32, 0xbfca8279, 0x667f3bcd, 0xbfe6a09e, 0x20000000, + 0x3c8bdd34, 0x00000000, 0xbfe00000, 0x94247758, 0xbfc133cc, + 0x6b151741, 0xbfe8bc80, 0x20000000, 0x3c82c5e1, 0x00000000, + 0xbfe00000, 0x9ae68c87, 0xbfac73b3, 0x290ea1a3, 0xbfea9b66, + 0xe0000000, 0xbc39f630, 0x00000000, 0xbfe00000, 0x7f909c4e, + 0x3f9d4a2c, 0xf180bdb1, 0xbfec38b2, 0x80000000, 0x3c76e0b1, + 0x00000000, 0xbfe00000, 0x65455a75, 0x3fbe0875, 0xcf328d46, + 0xbfed906b, 0x20000000, 0xbc7457e6, 0x00000000, 0xbfe00000, + 0x76acf82d, 0xbfa4a031, 0x56c62dda, 0xbfee9f41, 0xe0000000, + 0xbc8760b1, 0x00000000, 0xbfd00000, 0x0e5967d5, 0x3fac1d1f, + 0xcff75cb0, 0xbfef6297, 0x20000000, 0xbc756217, 0x00000000, + 0xbfd00000, 0x0f592f50, 0x3f9ba165, 0xa3d12526, 0xbfefd88d, + 0x40000000, 0x3c887df6, 0x00000000, 0xbfc00000, 0x00000000, + 0x00000000, 0x00000000, 0xbff00000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x0f592f50, 0xbf9ba165, 0xa3d12526, + 0xbfefd88d, 0x40000000, 0x3c887df6, 0x00000000, 0x3fc00000, + 0x0e5967d5, 0xbfac1d1f, 0xcff75cb0, 0xbfef6297, 0x20000000, + 0xbc756217, 0x00000000, 0x3fd00000, 0x76acf82d, 0x3fa4a031, + 0x56c62dda, 0xbfee9f41, 0xe0000000, 0xbc8760b1, 0x00000000, + 0x3fd00000, 0x65455a75, 0xbfbe0875, 0xcf328d46, 0xbfed906b, + 0x20000000, 0xbc7457e6, 0x00000000, 0x3fe00000, 0x7f909c4e, + 0xbf9d4a2c, 0xf180bdb1, 0xbfec38b2, 0x80000000, 0x3c76e0b1, + 0x00000000, 0x3fe00000, 0x9ae68c87, 0x3fac73b3, 0x290ea1a3, + 0xbfea9b66, 0xe0000000, 0xbc39f630, 0x00000000, 0x3fe00000, + 0x94247758, 0x3fc133cc, 0x6b151741, 0xbfe8bc80, 0x20000000, + 0x3c82c5e1, 0x00000000, 0x3fe00000, 0x99fcef32, 0x3fca8279, + 0x667f3bcd, 0xbfe6a09e, 0x20000000, 0x3c8bdd34, 0x00000000, + 0x3fe00000, 0x53aba2fd, 0xbfcd0dfe, 0x25091dd6, 0xbfe44cf3, + 0x20000000, 0xbc68076a, 0x00000000, 0x3ff00000, 0x5bc57974, + 0xbfc59267, 0x39ae68c8, 0xbfe1c73b, 0x20000000, 0xbc8b25dd, + 0x00000000, 0x3ff00000, 0x73fa1279, 0xbfbe3a68, 0x3806f63b, + 0xbfde2b5d, 0x20000000, 0xbc5e0d89, 0x00000000, 0x3ff00000, + 0x866b95cf, 0xbfb37ca1, 0xa6aea963, 0xbfd87de2, 0xe0000000, + 0x3c672ced, 0x00000000, 0x3ff00000, 0x939d225a, 0xbfa60bea, + 0x2ed59f06, 0xbfd29406, 0xa0000000, 0x3c75d28d, 0x00000000, + 0x3ff00000, 0x011469fb, 0xbf93ad06, 0x3c69a60b, 0xbfc8f8b8, + 0xc0000000, 0x3c626d19, 0x00000000, 0x3ff00000, 0x176d6d31, + 0xbf73b92e, 0xbc29b42c, 0xbfb917a6, 0xe0000000, 0x3c3e2718, + 0x00000000, 0x3ff00000 + }; + + public int[] scTwo = { + 0x11111111, 0x3f811111, 0x55555555, 0x3fa55555 + }; + + public int[] scThree = { + 0x1a01a01a, 0xbf2a01a0, 0x16c16c17, 0xbf56c16c + }; + + public int[] scOne = { + 0x55555555, 0xbfc55555, 0x00000000, 0xbfe00000 + }; + + public int[] piInvTable = { + 0x00000000, 0x00000000, 0xa2f9836e, 0x4e441529, 0xfc2757d1, + 0xf534ddc0, 0xdb629599, 0x3c439041, 0xfe5163ab, 0xdebbc561, + 0xb7246e3a, 0x424dd2e0, 0x06492eea, 0x09d1921c, 0xfe1deb1c, + 0xb129a73e, 0xe88235f5, 0x2ebb4484, 0xe99c7026, 0xb45f7e41, + 0x3991d639, 0x835339f4, 0x9c845f8b, 0xbdf9283b, 0x1ff897ff, + 0xde05980f, 0xef2f118b, 0x5a0a6d1f, 0x6d367ecf, 0x27cb09b7, + 0x4f463f66, 0x9e5fea2d, 0x7527bac7, 0xebe5f17b, 0x3d0739f7, + 0x8a5292ea, 0x6bfb5fb1, 0x1f8d5d08, 0x56033046, 0xfc7b6bab, + 0xf0cfbc21 + }; + + public int[] piFour = { + 0x40000000, 0x3fe921fb, 0x18469899, 0x3e64442d + }; + + public int[] piThirtyTwoInv = { + 0x6dc9c883, 0x40245f30 + }; + + public int[] shifter = { + 0x00000000, 0x43380000 + }; + + public int[] signMask = { + 0x00000000, 0x80000000 + }; + + public int[] pThree = { + 0x2e037073, 0x3b63198a + }; + + public int[] allOnes = { + 0xffffffff, 0x3fefffff + }; + + public int[] twoPowFiftyFive = { + 0x00000000, 0x43600000 + }; + + public int[] twoPowFiftyFiveM = { + 0x00000000, 0x3c800000 + }; + + public int[] pOne = { + 0x54400000, 0x3fb921fb + }; + + public void sinIntrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) { + ArrayDataPointerConstant oneHalfPtr = new ArrayDataPointerConstant(oneHalf, 16); + ArrayDataPointerConstant pTwoPtr = new ArrayDataPointerConstant(pTwo, 16); + ArrayDataPointerConstant scFourPtr = new ArrayDataPointerConstant(scFour, 16); + ArrayDataPointerConstant cTablePtr = new ArrayDataPointerConstant(cTable, 16); + ArrayDataPointerConstant scTwoPtr = new ArrayDataPointerConstant(scTwo, 16); + ArrayDataPointerConstant scThreePtr = new ArrayDataPointerConstant(scThree, 16); + ArrayDataPointerConstant scOnePtr = new ArrayDataPointerConstant(scOne, 16); + ArrayDataPointerConstant piInvTablePtr = new ArrayDataPointerConstant(piInvTable, 16); + ArrayDataPointerConstant piFourPtr = new ArrayDataPointerConstant(piFour, 16); + ArrayDataPointerConstant piThirtyTwoInvPtr = new ArrayDataPointerConstant(piThirtyTwoInv, 8); + ArrayDataPointerConstant shifterPtr = new ArrayDataPointerConstant(shifter, 8); + ArrayDataPointerConstant signMaskPtr = new ArrayDataPointerConstant(signMask, 8); + ArrayDataPointerConstant pThreePtr = new ArrayDataPointerConstant(pThree, 8); + ArrayDataPointerConstant allOnesPtr = new ArrayDataPointerConstant(allOnes, 8); + ArrayDataPointerConstant twoPowFiftyFivePtr = new ArrayDataPointerConstant(twoPowFiftyFive, 8); + ArrayDataPointerConstant twoPowFiftyFiveMPtr = new ArrayDataPointerConstant(twoPowFiftyFiveM, 8); + ArrayDataPointerConstant pOnePtr = new ArrayDataPointerConstant(pOne, 8); + + Label bb0 = new Label(); + Label bb1 = new Label(); + Label bb2 = new Label(); + Label bb4 = new Label(); + Label bb5 = new Label(); + Label bb6 = new Label(); + Label bb8 = new Label(); + Label bb9 = new Label(); + Label bb10 = new Label(); + Label bb11 = new Label(); + Label bb12 = new Label(); + Label bb13 = new Label(); + Label bb14 = new Label(); + Label bb15 = new Label(); + + Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD); + Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD); + Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD); + Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD); + Register gpr5 = asRegister(gpr5Temp, AMD64Kind.QWORD); + Register gpr6 = asRegister(gpr6Temp, AMD64Kind.QWORD); + Register gpr7 = asRegister(gpr7Temp, AMD64Kind.QWORD); + Register gpr8 = asRegister(gpr8Temp, AMD64Kind.QWORD); + Register gpr9 = asRegister(gpr9Temp, AMD64Kind.QWORD); + Register gpr10 = asRegister(gpr10Temp, AMD64Kind.QWORD); + + Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE); + Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE); + Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE); + Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE); + Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE); + Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE); + Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE); + Register temp8 = asRegister(xmm8Temp, AMD64Kind.DOUBLE); + Register temp9 = asRegister(xmm9Temp, AMD64Kind.DOUBLE); + + AMD64Address stackSlot = (AMD64Address) crb.asAddress(stackTemp); + + setCrb(crb); + masm.movsd(stackSlot, value); + if (dest.encoding != value.encoding) { + masm.movdqu(dest, value); + } + + masm.leaq(gpr1, stackSlot); + masm.movl(gpr1, new AMD64Address(gpr1, 4)); + masm.movdq(temp1, externalAddress(piThirtyTwoInvPtr)); // 0x6dc9c883, + // 0x40245f30 + masm.movdq(temp2, externalAddress(shifterPtr)); // 0x00000000, + // 0x43380000 + + masm.andl(gpr1, 2147418112); + masm.subl(gpr1, 808452096); + masm.cmpl(gpr1, 281346048); + masm.jcc(ConditionFlag.Above, bb0); + + masm.mulsd(temp1, dest); + masm.movdqu(temp5, externalAddress(oneHalfPtr)); // 0x00000000, + // 0x3fe00000, + // 0x00000000, + // 0x3fe00000 + masm.movdq(temp4, externalAddress(signMaskPtr)); // 0x00000000, + // 0x80000000 + masm.pand(temp4, dest); + masm.por(temp5, temp4); + masm.addpd(temp1, temp5); + masm.cvttsd2sil(gpr4, temp1); + masm.cvtsi2sdl(temp1, gpr4); + masm.movdqu(temp6, externalAddress(pTwoPtr)); // 0x1a600000, + // 0x3d90b461, + // 0x1a600000, + // 0x3d90b461 + masm.movq(gpr7, 0x3fb921fb54400000L); + masm.movdq(temp3, gpr7); + masm.movdqu(temp5, externalAddress(scFourPtr)); // 0xa556c734, + // 0x3ec71de3, + // 0x1a01a01a, + // 0x3efa01a0 + masm.pshufd(temp4, dest, 0x44); + masm.mulsd(temp3, temp1); + if (masm.supports(CPUFeature.SSE3)) { + masm.movddup(temp1, temp1); + } else { + masm.movlhps(temp1, temp1); + } + masm.andl(gpr4, 63); + masm.shll(gpr4, 5); + masm.leaq(gpr1, externalAddress(cTablePtr)); + masm.addq(gpr1, gpr4); + masm.movdqu(temp8, new AMD64Address(gpr1, 0)); + masm.mulpd(temp6, temp1); + masm.mulsd(temp1, externalAddress(pThreePtr)); // 0x2e037073, + // 0x3b63198a + masm.subsd(temp4, temp3); + masm.subsd(dest, temp3); + if (masm.supports(CPUFeature.SSE3)) { + masm.movddup(temp3, temp4); + } else { + masm.movdqu(temp3, temp4); + masm.movlhps(temp3, temp3); + } + masm.subsd(temp4, temp6); + masm.pshufd(dest, dest, 0x44); + masm.pshufd(temp7, temp8, 0xE); + masm.movdqu(temp2, temp8); + masm.movdqu(temp9, temp7); + masm.mulpd(temp5, dest); + masm.subpd(dest, temp6); + masm.mulsd(temp7, temp4); + masm.subsd(temp3, temp4); + masm.mulpd(temp5, dest); + masm.mulpd(dest, dest); + masm.subsd(temp3, temp6); + masm.movdqu(temp6, externalAddress(scTwoPtr)); // 0x11111111, + // 0x3f811111, + // 0x55555555, + // 0x3fa55555 + masm.subsd(temp1, temp3); + masm.movdq(temp3, new AMD64Address(gpr1, 24)); + masm.addsd(temp2, temp3); + masm.subsd(temp7, temp2); + masm.mulsd(temp2, temp4); + masm.mulpd(temp6, dest); + masm.mulsd(temp3, temp4); + masm.mulpd(temp2, dest); + masm.mulpd(dest, dest); + masm.addpd(temp5, externalAddress(scThreePtr)); // 0x1a01a01a, + // 0xbf2a01a0, + // 0x16c16c17, + // 0xbf56c16c + masm.mulsd(temp4, temp8); + masm.addpd(temp6, externalAddress(scOnePtr)); // 0x55555555, + // 0xbfc55555, + // 0x00000000, + // 0xbfe00000 + masm.mulpd(temp5, dest); + masm.movdqu(dest, temp3); + masm.addsd(temp3, temp9); + masm.mulpd(temp1, temp7); + masm.movdqu(temp7, temp4); + masm.addsd(temp4, temp3); + masm.addpd(temp6, temp5); + masm.subsd(temp9, temp3); + masm.subsd(temp3, temp4); + masm.addsd(temp1, new AMD64Address(gpr1, 16)); + masm.mulpd(temp6, temp2); + masm.addsd(temp9, dest); + masm.addsd(temp3, temp7); + masm.addsd(temp1, temp9); + masm.addsd(temp1, temp3); + masm.addsd(temp1, temp6); + masm.unpckhpd(temp6, temp6); + masm.movdqu(dest, temp4); + masm.addsd(temp1, temp6); + masm.addsd(dest, temp1); + masm.jmp(bb15); + + masm.bind(bb14); + masm.xorpd(temp1, temp1); + masm.xorpd(dest, dest); + masm.divsd(dest, temp1); + masm.jmp(bb15); + + masm.bind(bb0); + masm.jcc(ConditionFlag.Greater, bb1); + + masm.shrl(gpr1, 20); + masm.cmpl(gpr1, 3325); + masm.jcc(ConditionFlag.NotEqual, bb2); + + masm.mulsd(dest, externalAddress(allOnesPtr)); // 0xffffffff, + // 0x3fefffff + masm.jmp(bb15); + + masm.bind(bb2); + masm.movdq(temp3, externalAddress(twoPowFiftyFivePtr)); // 0x00000000, + // 0x43600000 + masm.mulsd(temp3, dest); + masm.subsd(temp3, dest); + masm.mulsd(temp3, externalAddress(twoPowFiftyFiveMPtr)); // 0x00000000, + // 0x3c800000 + masm.jmp(bb15); + + masm.bind(bb1); + masm.pextrw(gpr3, dest, 3); + masm.andl(gpr3, 32752); + masm.cmpl(gpr3, 32752); + masm.jcc(ConditionFlag.Equal, bb14); + + masm.subl(gpr3, 16224); + masm.shrl(gpr3, 7); + masm.andl(gpr3, 65532); + masm.leaq(gpr10, externalAddress(piInvTablePtr)); + masm.addq(gpr3, gpr10); + masm.movdq(gpr1, dest); + masm.movl(gpr9, new AMD64Address(gpr3, 20)); + masm.movl(gpr7, new AMD64Address(gpr3, 24)); + masm.movl(gpr4, gpr1); + masm.shrq(gpr1, 21); + masm.orl(gpr1, Integer.MIN_VALUE); + masm.shrl(gpr1, 11); + masm.movl(gpr8, gpr9); + masm.imulq(gpr9, gpr4); + masm.imulq(gpr8, gpr1); + masm.imulq(gpr7, gpr1); + masm.movl(gpr5, new AMD64Address(gpr3, 16)); + masm.movl(gpr6, new AMD64Address(gpr3, 12)); + masm.movl(gpr10, gpr9); + masm.shrq(gpr9, 32); + masm.addq(gpr8, gpr9); + masm.addq(gpr10, gpr7); + masm.movl(gpr7, gpr10); + masm.shrq(gpr10, 32); + masm.addq(gpr8, gpr10); + masm.movl(gpr9, gpr5); + masm.imulq(gpr5, gpr4); + masm.imulq(gpr9, gpr1); + masm.movl(gpr10, gpr6); + masm.imulq(gpr6, gpr4); + masm.movl(gpr2, gpr5); + masm.shrq(gpr5, 32); + masm.addq(gpr8, gpr2); + masm.movl(gpr2, gpr8); + masm.shrq(gpr8, 32); + masm.addq(gpr9, gpr5); + masm.addq(gpr9, gpr8); + masm.shlq(gpr2, 32); + masm.orq(gpr7, gpr2); + masm.imulq(gpr10, gpr1); + masm.movl(gpr8, new AMD64Address(gpr3, 8)); + masm.movl(gpr5, new AMD64Address(gpr3, 4)); + masm.movl(gpr2, gpr6); + masm.shrq(gpr6, 32); + masm.addq(gpr9, gpr2); + masm.movl(gpr2, gpr9); + masm.shrq(gpr9, 32); + masm.addq(gpr10, gpr6); + masm.addq(gpr10, gpr9); + masm.movq(gpr6, gpr8); + masm.imulq(gpr8, gpr4); + masm.imulq(gpr6, gpr1); + masm.movl(gpr9, gpr8); + masm.shrq(gpr8, 32); + masm.addq(gpr10, gpr9); + masm.movl(gpr9, gpr10); + masm.shrq(gpr10, 32); + masm.addq(gpr6, gpr8); + masm.addq(gpr6, gpr10); + masm.movq(gpr8, gpr5); + masm.imulq(gpr5, gpr4); + masm.imulq(gpr8, gpr1); + masm.shlq(gpr9, 32); + masm.orq(gpr9, gpr2); + masm.movl(gpr1, new AMD64Address(gpr3, 0)); + masm.movl(gpr10, gpr5); + masm.shrq(gpr5, 32); + masm.addq(gpr6, gpr10); + masm.movl(gpr10, gpr6); + masm.shrq(gpr6, 32); + masm.addq(gpr8, gpr5); + masm.addq(gpr8, gpr6); + masm.imulq(gpr4, gpr1); + masm.pextrw(gpr2, dest, 3); + masm.leaq(gpr6, externalAddress(piInvTablePtr)); + masm.subq(gpr3, gpr6); + masm.addl(gpr3, gpr3); + masm.addl(gpr3, gpr3); + masm.addl(gpr3, gpr3); + masm.addl(gpr3, 19); + masm.movl(gpr5, 32768); + masm.andl(gpr5, gpr2); + masm.shrl(gpr2, 4); + masm.andl(gpr2, 2047); + masm.subl(gpr2, 1023); + masm.subl(gpr3, gpr2); + masm.addq(gpr8, gpr4); + masm.movl(gpr4, gpr3); + masm.addl(gpr4, 32); + masm.cmpl(gpr3, 1); + masm.jcc(ConditionFlag.Less, bb4); + + masm.negl(gpr3); + masm.addl(gpr3, 29); + masm.shll(gpr8); + masm.movl(gpr6, gpr8); + masm.andl(gpr8, 536870911); + masm.testl(gpr8, 268435456); + masm.jcc(ConditionFlag.NotEqual, bb5); + + masm.shrl(gpr8); + masm.movl(gpr2, 0); + masm.shlq(gpr8, 32); + masm.orq(gpr8, gpr10); + + masm.bind(bb6); + + masm.cmpq(gpr8, 0); + masm.jcc(ConditionFlag.Equal, bb8); + + masm.bind(bb9); + masm.bsrq(gpr10, gpr8); + masm.movl(gpr3, 29); + masm.subl(gpr3, gpr10); + masm.jcc(ConditionFlag.LessEqual, bb10); + + masm.shlq(gpr8); + masm.movq(gpr1, gpr9); + masm.shlq(gpr9); + masm.addl(gpr4, gpr3); + masm.negl(gpr3); + masm.addl(gpr3, 64); + masm.shrq(gpr1); + masm.shrq(gpr7); + masm.orq(gpr8, gpr1); + masm.orq(gpr9, gpr7); + + masm.bind(bb11); + masm.cvtsi2sdq(dest, gpr8); + masm.shrq(gpr9, 1); + masm.cvtsi2sdq(temp3, gpr9); + masm.xorpd(temp4, temp4); + masm.shll(gpr4, 4); + masm.negl(gpr4); + masm.addl(gpr4, 16368); + masm.orl(gpr4, gpr5); + masm.xorl(gpr4, gpr2); + masm.pinsrw(temp4, gpr4, 3); + masm.leaq(gpr1, externalAddress(piFourPtr)); + masm.movdqu(temp2, new AMD64Address(gpr1, 0)); // 0x40000000, + // 0x3fe921fb, + // 0x18469899, + // 0x3e64442d + masm.xorpd(temp5, temp5); + masm.subl(gpr4, 1008); + masm.pinsrw(temp5, gpr4, 3); + masm.mulsd(dest, temp4); + masm.shll(gpr5, 16); + masm.sarl(gpr5, 31); + masm.mulsd(temp3, temp5); + masm.movdqu(temp1, dest); + masm.pshufd(temp6, temp2, 0xE); + masm.mulsd(dest, temp2); + masm.shrl(gpr6, 29); + masm.addsd(temp1, temp3); + masm.mulsd(temp3, temp2); + masm.addl(gpr6, gpr5); + masm.xorl(gpr6, gpr5); + masm.mulsd(temp6, temp1); + masm.movl(gpr1, gpr6); + masm.addsd(temp6, temp3); + masm.movdqu(temp2, dest); + masm.addsd(dest, temp6); + masm.subsd(temp2, dest); + masm.addsd(temp6, temp2); + + masm.bind(bb12); + masm.movdq(temp1, externalAddress(piThirtyTwoInvPtr)); // 0x6dc9c883, + // 0x40245f30 + masm.mulsd(temp1, dest); + masm.movdq(temp5, externalAddress(oneHalfPtr)); // 0x00000000, + // 0x3fe00000, + // 0x00000000, + // 0x3fe00000 + masm.movdq(temp4, externalAddress(signMaskPtr)); // 0x00000000, + // 0x80000000 + masm.pand(temp4, dest); + masm.por(temp5, temp4); + masm.addpd(temp1, temp5); + masm.cvttsd2sil(gpr4, temp1); + masm.cvtsi2sdl(temp1, gpr4); + masm.movdq(temp3, externalAddress(pOnePtr)); // 0x54400000, + // 0x3fb921fb + masm.movdqu(temp2, externalAddress(pTwoPtr)); // 0x1a600000, + // 0x3d90b461, + // 0x1a600000, + // 0x3d90b461 + masm.mulsd(temp3, temp1); + masm.unpcklpd(temp1, temp1); + masm.shll(gpr1, 3); + masm.addl(gpr4, 1865216); + masm.movdqu(temp4, dest); + masm.addl(gpr4, gpr1); + masm.andl(gpr4, 63); + masm.movdqu(temp5, externalAddress(scFourPtr)); // 0x54400000, + // 0x3fb921fb + masm.leaq(gpr1, externalAddress(cTablePtr)); + masm.shll(gpr4, 5); + masm.addq(gpr1, gpr4); + masm.movdqu(temp8, new AMD64Address(gpr1, 0)); + masm.mulpd(temp2, temp1); + masm.subsd(dest, temp3); + masm.mulsd(temp1, externalAddress(pThreePtr)); // 0x2e037073, + // 0x3b63198a + masm.subsd(temp4, temp3); + masm.unpcklpd(dest, dest); + masm.movdqu(temp3, temp4); + masm.subsd(temp4, temp2); + masm.mulpd(temp5, dest); + masm.subpd(dest, temp2); + masm.pshufd(temp7, temp8, 0xE); + masm.movdqu(temp9, temp7); + masm.mulsd(temp7, temp4); + masm.subsd(temp3, temp4); + masm.mulpd(temp5, dest); + masm.mulpd(dest, dest); + masm.subsd(temp3, temp2); + masm.movdqu(temp2, temp8); + masm.subsd(temp1, temp3); + masm.movdq(temp3, new AMD64Address(gpr1, 24)); + masm.addsd(temp2, temp3); + masm.subsd(temp7, temp2); + masm.subsd(temp1, temp6); + masm.movdqu(temp6, externalAddress(scTwoPtr)); // 0x11111111, + // 0x3f811111, + // 0x55555555, + // 0x3fa55555 + masm.mulsd(temp2, temp4); + masm.mulpd(temp6, dest); + masm.mulsd(temp3, temp4); + masm.mulpd(temp2, dest); + masm.mulpd(dest, dest); + masm.addpd(temp5, externalAddress(scThreePtr)); // 0x1a01a01a, + // 0xbf2a01a0, + // 0x16c16c17, + // 0xbf56c16c + masm.mulsd(temp4, temp8); + masm.addpd(temp6, externalAddress(scOnePtr)); // 0x55555555, + // 0xbfc55555, + // 0x00000000, + // 0xbfe00000 + masm.mulpd(temp5, dest); + masm.movdqu(dest, temp3); + masm.addsd(temp3, temp9); + masm.mulpd(temp1, temp7); + masm.movdqu(temp7, temp4); + masm.addsd(temp4, temp3); + masm.addpd(temp6, temp5); + masm.subsd(temp9, temp3); + masm.subsd(temp3, temp4); + masm.addsd(temp1, new AMD64Address(gpr1, 16)); + masm.mulpd(temp6, temp2); + masm.addsd(temp9, dest); + masm.addsd(temp3, temp7); + masm.addsd(temp1, temp9); + masm.addsd(temp1, temp3); + masm.addsd(temp1, temp6); + masm.unpckhpd(temp6, temp6); + masm.movdqu(dest, temp4); + masm.addsd(temp1, temp6); + masm.addsd(dest, temp1); + masm.jmp(bb15); + + masm.bind(bb8); + masm.addl(gpr4, 64); + masm.movq(gpr8, gpr9); + masm.movq(gpr9, gpr7); + masm.movl(gpr7, 0); + masm.cmpq(gpr8, 0); + masm.jcc(ConditionFlag.NotEqual, bb9); + + masm.addl(gpr4, 64); + masm.movq(gpr8, gpr9); + masm.movq(gpr9, gpr7); + masm.cmpq(gpr8, 0); + masm.jcc(ConditionFlag.NotEqual, bb9); + + masm.xorpd(dest, dest); + masm.xorpd(temp6, temp6); + masm.jmp(bb12); + + masm.bind(bb10); + masm.jcc(ConditionFlag.Equal, bb11); + + masm.negl(gpr3); + masm.shrq(gpr9); + masm.movq(gpr1, gpr8); + masm.shrq(gpr8); + masm.subl(gpr4, gpr3); + masm.negl(gpr3); + masm.addl(gpr3, 64); + masm.shlq(gpr1); + masm.orq(gpr9, gpr1); + masm.jmp(bb11); + + masm.bind(bb4); + masm.negl(gpr3); + masm.shlq(gpr8, 32); + masm.orq(gpr8, gpr10); + masm.shlq(gpr8); + masm.movq(gpr6, gpr8); + masm.testl(gpr8, Integer.MIN_VALUE); + masm.jcc(ConditionFlag.NotEqual, bb13); + + masm.shrl(gpr8); + masm.movl(gpr2, 0); + masm.shrq(gpr6, 3); + masm.jmp(bb6); + + masm.bind(bb5); + masm.shrl(gpr8); + masm.movl(gpr2, 536870912); + masm.shrl(gpr2); + masm.shlq(gpr8, 32); + masm.orq(gpr8, gpr10); + masm.shlq(gpr2, 32); + masm.addl(gpr6, 536870912); + masm.movl(gpr3, 0); + masm.movl(gpr10, 0); + masm.subq(gpr3, gpr7); + masm.sbbq(gpr10, gpr9); + masm.sbbq(gpr2, gpr8); + masm.movq(gpr7, gpr3); + masm.movq(gpr9, gpr10); + masm.movq(gpr8, gpr2); + masm.movl(gpr2, 32768); + masm.jmp(bb6); + + masm.bind(bb13); + masm.shrl(gpr8); + masm.movq(gpr2, 0x100000000L); + masm.shrq(gpr2); + masm.movl(gpr3, 0); + masm.movl(gpr10, 0); + masm.subq(gpr3, gpr7); + masm.sbbq(gpr10, gpr9); + masm.sbbq(gpr2, gpr8); + masm.movq(gpr7, gpr3); + masm.movq(gpr9, gpr10); + masm.movq(gpr8, gpr2); + masm.movl(gpr2, 32768); + masm.shrq(gpr6, 3); + masm.addl(gpr6, 536870912); + masm.jmp(bb6); + + masm.bind(bb15); + } + + /* + * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM) + * Source Code + * + * ALGORITHM DESCRIPTION - COS() --------------------- + * + * 1. RANGE REDUCTION + * + * We perform an initial range reduction from X to r with + * + * X =~= N * pi/32 + r + * + * so that |r| <= pi/64 + epsilon. We restrict inputs to those where |N| <= 932560. Beyond this, + * the range reduction is insufficiently accurate. For extremely small inputs, denormalization + * can occur internally, impacting performance. This means that the main path is actually only + * taken for 2^-252 <= |X| < 90112. + * + * To avoid branches, we perform the range reduction to full accuracy each time. + * + * X - N * (P_1 + P_2 + P_3) + * + * where P_1 and P_2 are 32-bit numbers (so multiplication by N is exact) and P_3 is a 53-bit + * number. Together, these approximate pi well enough for all cases in the restricted range. + * + * The main reduction sequence is: + * + * y = 32/pi * x N = integer(y) (computed by adding and subtracting off SHIFTER) + * + * m_1 = N * P_1 m_2 = N * P_2 r_1 = x - m_1 r = r_1 - m_2 (this r can be used for most of the + * calculation) + * + * c_1 = r_1 - r m_3 = N * P_3 c_2 = c_1 - m_2 c = c_2 - m_3 + * + * 2. MAIN ALGORITHM + * + * The algorithm uses a table lookup based on B = M * pi / 32 where M = N mod 64. The stored + * values are: sigma closest power of 2 to cos(B) C_hl 53-bit cos(B) - sigma S_hi + S_lo 2 * + * 53-bit sin(B) + * + * The computation is organized as follows: + * + * sin(B + r + c) = [sin(B) + sigma * r] + r * (cos(B) - sigma) + sin(B) * [cos(r + c) - 1] + + * cos(B) * [sin(r + c) - r] + * + * which is approximately: + * + * [S_hi + sigma * r] + C_hl * r + S_lo + S_hi * [(cos(r) - 1) - r * c] + (C_hl + sigma) * + * [(sin(r) - r) + c] + * + * and this is what is actually computed. We separate this sum into four parts: + * + * hi + med + pols + corr + * + * where + * + * hi = S_hi + sigma r med = C_hl * r pols = S_hi * (cos(r) - 1) + (C_hl + sigma) * (sin(r) - r) + * corr = S_lo + c * ((C_hl + sigma) - S_hi * r) + * + * 3. POLYNOMIAL + * + * The polynomial S_hi * (cos(r) - 1) + (C_hl + sigma) * (sin(r) - r) can be rearranged freely, + * since it is quite small, so we exploit parallelism to the fullest. + * + * psc4 = SC_4 * r_1 msc4 = psc4 * r r2 = r * r msc2 = SC_2 * r2 r4 = r2 * r2 psc3 = SC_3 + msc4 + * psc1 = SC_1 + msc2 msc3 = r4 * psc3 sincospols = psc1 + msc3 pols = sincospols * + * + * 4. CORRECTION TERM + * + * This is where the "c" component of the range reduction is taken into account; recall that + * just "r" is used for most of the calculation. + * + * -c = m_3 - c_2 -d = S_hi * r - (C_hl + sigma) corr = -c * -d + S_lo + * + * 5. COMPENSATED SUMMATIONS + * + * The two successive compensated summations add up the high and medium parts, leaving just the + * low parts to add up at the end. + * + * rs = sigma * r res_int = S_hi + rs k_0 = S_hi - res_int k_2 = k_0 + rs med = C_hl * r res_hi + * = res_int + med k_1 = res_int - res_hi k_3 = k_1 + med + * + * 6. FINAL SUMMATION + * + * We now add up all the small parts: + * + * res_lo = pols(hi) + pols(lo) + corr + k_1 + k_3 + * + * Now the overall result is just: + * + * res_hi + res_lo + * + * 7. SMALL ARGUMENTS + * + * Inputs with |X| < 2^-252 are treated specially as 1 - |x|. + * + * Special cases: cos(NaN) = quiet NaN, and raise invalid exception cos(INF) = NaN and raise + * invalid exception cos(0) = 1 + * + */ + + public int[] one = { + 0x00000000, 0x3ff00000 + }; + + public void cosIntrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) { + ArrayDataPointerConstant oneHalfPtr = new ArrayDataPointerConstant(oneHalf, 16); + ArrayDataPointerConstant pTwoPtr = new ArrayDataPointerConstant(pTwo, 16); + ArrayDataPointerConstant scFourPtr = new ArrayDataPointerConstant(scFour, 16); + ArrayDataPointerConstant cTablePtr = new ArrayDataPointerConstant(cTable, 16); + ArrayDataPointerConstant scTwoPtr = new ArrayDataPointerConstant(scTwo, 16); + ArrayDataPointerConstant scThreePtr = new ArrayDataPointerConstant(scThree, 16); + ArrayDataPointerConstant scOnePtr = new ArrayDataPointerConstant(scOne, 16); + ArrayDataPointerConstant piInvTablePtr = new ArrayDataPointerConstant(piInvTable, 16); + ArrayDataPointerConstant piFourPtr = new ArrayDataPointerConstant(piFour, 16); + ArrayDataPointerConstant piThirtyTwoInvPtr = new ArrayDataPointerConstant(piThirtyTwoInv, 8); + ArrayDataPointerConstant signMaskPtr = new ArrayDataPointerConstant(signMask, 8); + ArrayDataPointerConstant pThreePtr = new ArrayDataPointerConstant(pThree, 8); + ArrayDataPointerConstant pOnePtr = new ArrayDataPointerConstant(pOne, 8); + ArrayDataPointerConstant onePtr = new ArrayDataPointerConstant(one, 8); + + Label bb0 = new Label(); + Label bb1 = new Label(); + Label bb3 = new Label(); + Label bb4 = new Label(); + Label bb5 = new Label(); + Label bb6 = new Label(); + Label bb7 = new Label(); + Label bb8 = new Label(); + Label bb9 = new Label(); + Label bb10 = new Label(); + Label bb11 = new Label(); + Label bb12 = new Label(); + Label bb13 = new Label(); + Label bb14 = new Label(); + + Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD); + Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD); + Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD); + Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD); + Register gpr5 = asRegister(gpr5Temp, AMD64Kind.QWORD); + Register gpr6 = asRegister(gpr6Temp, AMD64Kind.QWORD); + Register gpr7 = asRegister(gpr7Temp, AMD64Kind.QWORD); + Register gpr8 = asRegister(gpr8Temp, AMD64Kind.QWORD); + Register gpr9 = asRegister(gpr9Temp, AMD64Kind.QWORD); + Register gpr10 = asRegister(gpr10Temp, AMD64Kind.QWORD); + + Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE); + Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE); + Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE); + Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE); + Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE); + Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE); + Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE); + Register temp8 = asRegister(xmm8Temp, AMD64Kind.DOUBLE); + Register temp9 = asRegister(xmm9Temp, AMD64Kind.DOUBLE); + + AMD64Address stackSlot = (AMD64Address) crb.asAddress(stackTemp); + + setCrb(crb); + masm.movdq(stackSlot, value); + if (dest.encoding != value.encoding) { + masm.movdqu(dest, value); + } + + masm.leaq(gpr1, stackSlot); + masm.movl(gpr1, new AMD64Address(gpr1, 4)); + masm.movdq(temp1, externalAddress(piThirtyTwoInvPtr)); // 0x6dc9c883, + // 0x40245f30 + + masm.andl(gpr1, 2147418112); + masm.subl(gpr1, 808452096); + masm.cmpl(gpr1, 281346048); + masm.jcc(ConditionFlag.Above, bb0); + + masm.mulsd(temp1, dest); + masm.movdqu(temp5, externalAddress(oneHalfPtr)); // 0x00000000, + // 0x3fe00000, + // 0x00000000, + // 0x3fe00000 + masm.movdq(temp4, externalAddress(signMaskPtr)); // 0x00000000, + // 0x80000000 + masm.pand(temp4, dest); + masm.por(temp5, temp4); + masm.addpd(temp1, temp5); + masm.cvttsd2sil(gpr4, temp1); + masm.cvtsi2sdl(temp1, gpr4); + masm.movdqu(temp2, externalAddress(pTwoPtr)); // 0x1a600000, + // 0x3d90b461, + // 0x1a600000, + // 0x3d90b461 + masm.movdq(temp3, externalAddress(pOnePtr)); // 0x54400000, + // 0x3fb921fb + masm.mulsd(temp3, temp1); + masm.unpcklpd(temp1, temp1); + masm.addq(gpr4, 1865232); + masm.movdqu(temp4, dest); + masm.andq(gpr4, 63); + masm.movdqu(temp5, externalAddress(scFourPtr)); // 0xa556c734, + // 0x3ec71de3, + // 0x1a01a01a, + // 0x3efa01a0 + masm.leaq(gpr1, externalAddress(cTablePtr)); + masm.shlq(gpr4, 5); + masm.addq(gpr1, gpr4); + masm.movdqu(temp8, new AMD64Address(gpr1, 0)); + masm.mulpd(temp2, temp1); + masm.subsd(dest, temp3); + masm.mulsd(temp1, externalAddress(pThreePtr)); // 0x2e037073, + // 0x3b63198a + masm.subsd(temp4, temp3); + masm.unpcklpd(dest, dest); + masm.movdqu(temp3, temp4); + masm.subsd(temp4, temp2); + masm.mulpd(temp5, dest); + masm.subpd(dest, temp2); + masm.pshufd(temp7, temp8, 0xE); + masm.movdqu(temp6, externalAddress(scTwoPtr)); // 0x11111111, + // 0x3f811111, + // 0x55555555, + // 0x3fa55555 + masm.mulsd(temp7, temp4); + masm.subsd(temp3, temp4); + masm.mulpd(temp5, dest); + masm.mulpd(dest, dest); + masm.subsd(temp3, temp2); + masm.movdqu(temp2, temp8); + masm.subsd(temp1, temp3); + masm.movdq(temp3, new AMD64Address(gpr1, 24)); + masm.addsd(temp2, temp3); + masm.subsd(temp7, temp2); + masm.mulsd(temp2, temp4); + masm.mulpd(temp6, dest); + masm.mulsd(temp3, temp4); + masm.mulpd(temp2, dest); + masm.mulpd(dest, dest); + masm.addpd(temp5, externalAddress(scThreePtr)); // 0x1a01a01a, + // 0xbf2a01a0, + // 0x16c16c17, + // 0xbf56c16c + masm.mulsd(temp4, temp8); + masm.pshufd(temp9, temp8, 0xE); + masm.addpd(temp6, externalAddress(scOnePtr)); // 0x55555555, + // 0xbfc55555, + // 0x00000000, + // 0xbfe00000 + masm.mulpd(temp5, dest); + masm.movdqu(dest, temp3); + masm.addsd(temp3, temp9); + masm.mulpd(temp1, temp7); + masm.movdqu(temp7, temp4); + masm.addsd(temp4, temp3); + masm.addpd(temp6, temp5); + masm.subsd(temp9, temp3); + masm.subsd(temp3, temp4); + masm.addsd(temp1, new AMD64Address(gpr1, 16)); + masm.mulpd(temp6, temp2); + masm.addsd(dest, temp9); + masm.addsd(temp3, temp7); + masm.addsd(dest, temp1); + masm.addsd(dest, temp3); + masm.addsd(dest, temp6); + masm.unpckhpd(temp6, temp6); + masm.addsd(dest, temp6); + masm.addsd(dest, temp4); + masm.jmp(bb13); + + masm.bind(bb14); + masm.xorpd(temp1, temp1); + masm.xorpd(dest, dest); + masm.divsd(dest, temp1); + masm.jmp(bb13); + + masm.bind(bb0); + masm.jcc(ConditionFlag.Greater, bb1); + + masm.pextrw(gpr1, dest, 3); + masm.andl(gpr1, 32767); + masm.pinsrw(dest, gpr1, 3); + masm.movdq(temp1, externalAddress(onePtr)); // 0x00000000, + // 0x3ff00000 + masm.subsd(temp1, dest); + masm.movdqu(dest, temp1); + masm.jmp(bb13); + + masm.bind(bb1); + masm.pextrw(gpr3, dest, 3); + masm.andl(gpr3, 32752); + masm.cmpl(gpr3, 32752); + masm.jcc(ConditionFlag.Equal, bb14); + + masm.subl(gpr3, 16224); + masm.shrl(gpr3, 7); + masm.andl(gpr3, 65532); + masm.leaq(gpr10, externalAddress(piInvTablePtr)); + masm.addq(gpr3, gpr10); + masm.movdq(gpr1, dest); + masm.movl(gpr9, new AMD64Address(gpr3, 20)); + masm.movl(gpr7, new AMD64Address(gpr3, 24)); + masm.movl(gpr4, gpr1); + masm.shrq(gpr1, 21); + masm.orl(gpr1, Integer.MIN_VALUE); + masm.shrl(gpr1, 11); + masm.movl(gpr8, gpr9); + masm.imulq(gpr9, gpr4); + masm.imulq(gpr8, gpr1); + masm.imulq(gpr7, gpr1); + masm.movl(gpr5, new AMD64Address(gpr3, 16)); + masm.movl(gpr6, new AMD64Address(gpr3, 12)); + masm.movl(gpr10, gpr9); + masm.shrq(gpr9, 32); + masm.addq(gpr8, gpr9); + masm.addq(gpr10, gpr7); + masm.movl(gpr7, gpr10); + masm.shrq(gpr10, 32); + masm.addq(gpr8, gpr10); + masm.movl(gpr9, gpr5); + masm.imulq(gpr5, gpr4); + masm.imulq(gpr9, gpr1); + masm.movl(gpr10, gpr6); + masm.imulq(gpr6, gpr4); + masm.movl(gpr2, gpr5); + masm.shrq(gpr5, 32); + masm.addq(gpr8, gpr2); + masm.movl(gpr2, gpr8); + masm.shrq(gpr8, 32); + masm.addq(gpr9, gpr5); + masm.addq(gpr9, gpr8); + masm.shlq(gpr2, 32); + masm.orq(gpr7, gpr2); + masm.imulq(gpr10, gpr1); + masm.movl(gpr8, new AMD64Address(gpr3, 8)); + masm.movl(gpr5, new AMD64Address(gpr3, 4)); + masm.movl(gpr2, gpr6); + masm.shrq(gpr6, 32); + masm.addq(gpr9, gpr2); + masm.movl(gpr2, gpr9); + masm.shrq(gpr9, 32); + masm.addq(gpr10, gpr6); + masm.addq(gpr10, gpr9); + masm.movq(gpr6, gpr8); + masm.imulq(gpr8, gpr4); + masm.imulq(gpr6, gpr1); + masm.movl(gpr9, gpr8); + masm.shrq(gpr8, 32); + masm.addq(gpr10, gpr9); + masm.movl(gpr9, gpr10); + masm.shrq(gpr10, 32); + masm.addq(gpr6, gpr8); + masm.addq(gpr6, gpr10); + masm.movq(gpr8, gpr5); + masm.imulq(gpr5, gpr4); + masm.imulq(gpr8, gpr1); + masm.shlq(gpr9, 32); + masm.orq(gpr9, gpr2); + masm.movl(gpr1, new AMD64Address(gpr3, 0)); + masm.movl(gpr10, gpr5); + masm.shrq(gpr5, 32); + masm.addq(gpr6, gpr10); + masm.movl(gpr10, gpr6); + masm.shrq(gpr6, 32); + masm.addq(gpr8, gpr5); + masm.addq(gpr8, gpr6); + masm.imulq(gpr4, gpr1); + masm.pextrw(gpr2, dest, 3); + masm.leaq(gpr6, externalAddress(piInvTablePtr)); + masm.subq(gpr3, gpr6); + masm.addl(gpr3, gpr3); + masm.addl(gpr3, gpr3); + masm.addl(gpr3, gpr3); + masm.addl(gpr3, 19); + masm.movl(gpr5, 32768); + masm.andl(gpr5, gpr2); + masm.shrl(gpr2, 4); + masm.andl(gpr2, 2047); + masm.subl(gpr2, 1023); + masm.subl(gpr3, gpr2); + masm.addq(gpr8, gpr4); + masm.movl(gpr4, gpr3); + masm.addl(gpr4, 32); + masm.cmpl(gpr3, 1); + masm.jcc(ConditionFlag.Less, bb3); + + masm.negl(gpr3); + masm.addl(gpr3, 29); + masm.shll(gpr8); + masm.movl(gpr6, gpr8); + masm.andl(gpr8, 536870911); + masm.testl(gpr8, 268435456); + masm.jcc(ConditionFlag.NotEqual, bb4); + + masm.shrl(gpr8); + masm.movl(gpr2, 0); + masm.shlq(gpr8, 32); + masm.orq(gpr8, gpr10); + + masm.bind(bb5); + + masm.bind(bb6); + masm.cmpq(gpr8, 0); + masm.jcc(ConditionFlag.Equal, bb7); + + masm.bind(bb8); + masm.bsrq(gpr10, gpr8); + masm.movl(gpr3, 29); + masm.subl(gpr3, gpr10); + masm.jcc(ConditionFlag.LessEqual, bb9); + + masm.shlq(gpr8); + masm.movq(gpr1, gpr9); + masm.shlq(gpr9); + masm.addl(gpr4, gpr3); + masm.negl(gpr3); + masm.addl(gpr3, 64); + masm.shrq(gpr1); + masm.shrq(gpr7); + masm.orq(gpr8, gpr1); + masm.orq(gpr9, gpr7); + + masm.bind(bb10); + masm.cvtsi2sdq(dest, gpr8); + masm.shrq(gpr9, 1); + masm.cvtsi2sdq(temp3, gpr9); + masm.xorpd(temp4, temp4); + masm.shll(gpr4, 4); + masm.negl(gpr4); + masm.addl(gpr4, 16368); + masm.orl(gpr4, gpr5); + masm.xorl(gpr4, gpr2); + masm.pinsrw(temp4, gpr4, 3); + masm.leaq(gpr2, externalAddress(piFourPtr)); + masm.movdqu(temp2, new AMD64Address(gpr2, 0)); // 0x40000000, + // 0x3fe921fb, + // 0x18469899, + // 0x3e64442d + masm.xorpd(temp5, temp5); + masm.subl(gpr4, 1008); + masm.pinsrw(temp5, gpr4, 3); + masm.mulsd(dest, temp4); + masm.shll(gpr5, 16); + masm.sarl(gpr5, 31); + masm.mulsd(temp3, temp5); + masm.movdqu(temp1, dest); + masm.mulsd(dest, temp2); + masm.pshufd(temp6, temp2, 0xE); + masm.shrl(gpr6, 29); + masm.addsd(temp1, temp3); + masm.mulsd(temp3, temp2); + masm.addl(gpr6, gpr5); + masm.xorl(gpr6, gpr5); + masm.mulsd(temp6, temp1); + masm.movl(gpr1, gpr6); + masm.addsd(temp6, temp3); + masm.movdqu(temp2, dest); + masm.addsd(dest, temp6); + masm.subsd(temp2, dest); + masm.addsd(temp6, temp2); + + masm.bind(bb11); + masm.movq(temp1, externalAddress(piThirtyTwoInvPtr)); // 0x6dc9c883, + // 0x40245f30 + masm.mulsd(temp1, dest); + masm.movdq(temp5, externalAddress(oneHalfPtr)); // 0x00000000, + // 0x3fe00000, + // 0x00000000, + // 0x3fe00000 + masm.movdq(temp4, externalAddress(signMaskPtr)); // 0x00000000, + // 0x80000000 + masm.pand(temp4, dest); + masm.por(temp5, temp4); + masm.addpd(temp1, temp5); + masm.cvttsd2siq(gpr4, temp1); + masm.cvtsi2sdq(temp1, gpr4); + masm.movdq(temp3, externalAddress(pOnePtr)); // 0x54400000, + // 0x3fb921fb + masm.movdqu(temp2, externalAddress(pTwoPtr)); // 0x1a600000, + // 0x3d90b461, + // 0x1a600000, + // 0x3d90b461 + masm.mulsd(temp3, temp1); + masm.unpcklpd(temp1, temp1); + masm.shll(gpr1, 3); + masm.addl(gpr4, 1865232); + masm.movdqu(temp4, dest); + masm.addl(gpr4, gpr1); + masm.andl(gpr4, 63); + masm.movdqu(temp5, externalAddress(scFourPtr)); // 0xa556c734, + // 0x3ec71de3, + // 0x1a01a01a, + // 0x3efa01a0 + masm.leaq(gpr1, externalAddress(cTablePtr)); + masm.shll(gpr4, 5); + masm.addq(gpr1, gpr4); + masm.movdqu(temp8, new AMD64Address(gpr1, 0)); + masm.mulpd(temp2, temp1); + masm.subsd(dest, temp3); + masm.mulsd(temp1, externalAddress(pThreePtr)); // 0x2e037073, + // 0x3b63198a + masm.subsd(temp4, temp3); + masm.unpcklpd(dest, dest); + masm.movdqu(temp3, temp4); + masm.subsd(temp4, temp2); + masm.mulpd(temp5, dest); + masm.pshufd(temp7, temp8, 0xE); + masm.movdqu(temp9, temp7); + masm.subpd(dest, temp2); + masm.mulsd(temp7, temp4); + masm.subsd(temp3, temp4); + masm.mulpd(temp5, dest); + masm.mulpd(dest, dest); + masm.subsd(temp3, temp2); + masm.movdqu(temp2, temp8); + masm.subsd(temp1, temp3); + masm.movdq(temp3, new AMD64Address(gpr1, 24)); + masm.addsd(temp2, temp3); + masm.subsd(temp7, temp2); + masm.subsd(temp1, temp6); + masm.movdqu(temp6, externalAddress(scTwoPtr)); // 0x11111111, + // 0x3f811111, + // 0x55555555, + // 0x3fa55555 + masm.mulsd(temp2, temp4); + masm.mulpd(temp6, dest); + masm.mulsd(temp3, temp4); + masm.mulpd(temp2, dest); + masm.mulpd(dest, dest); + masm.addpd(temp5, externalAddress(scThreePtr)); // 0x1a01a01a, + // 0xbf2a01a0, + // 0x16c16c17, + // 0xbf56c16c + masm.mulsd(temp4, temp8); + masm.addpd(temp6, externalAddress(scOnePtr)); // 0x55555555, + // 0xbfc55555, + // 0x00000000, + // 0xbfe00000 + masm.mulpd(temp5, dest); + masm.movdqu(dest, temp3); + masm.addsd(temp3, temp9); + masm.mulpd(temp1, temp7); + masm.movdqu(temp7, temp4); + masm.addsd(temp4, temp3); + masm.addpd(temp6, temp5); + masm.subsd(temp9, temp3); + masm.subsd(temp3, temp4); + masm.addsd(temp1, new AMD64Address(gpr1, 16)); + masm.mulpd(temp6, temp2); + masm.addsd(temp9, dest); + masm.addsd(temp3, temp7); + masm.addsd(temp1, temp9); + masm.addsd(temp1, temp3); + masm.addsd(temp1, temp6); + masm.unpckhpd(temp6, temp6); + masm.movdqu(dest, temp4); + masm.addsd(temp1, temp6); + masm.addsd(dest, temp1); + masm.jmp(bb13); + + masm.bind(bb7); + masm.addl(gpr4, 64); + masm.movq(gpr8, gpr9); + masm.movq(gpr9, gpr7); + masm.movl(gpr7, 0); + masm.cmpq(gpr8, 0); + masm.jcc(ConditionFlag.NotEqual, bb8); + + masm.addl(gpr4, 64); + masm.movq(gpr8, gpr9); + masm.movq(gpr9, gpr7); + masm.cmpq(gpr8, 0); + masm.jcc(ConditionFlag.NotEqual, bb8); + + masm.xorpd(dest, dest); + masm.xorpd(temp6, temp6); + masm.jmp(bb11); + + masm.bind(bb9); + masm.jcc(ConditionFlag.Equal, bb10); + + masm.negl(gpr3); + masm.shrq(gpr9); + masm.movq(gpr1, gpr8); + masm.shrq(gpr8); + masm.subl(gpr4, gpr3); + masm.negl(gpr3); + masm.addl(gpr3, 64); + masm.shlq(gpr1); + masm.orq(gpr9, gpr1); + masm.jmp(bb10); + + masm.bind(bb3); + masm.negl(gpr3); + masm.shlq(gpr8, 32); + masm.orq(gpr8, gpr10); + masm.shlq(gpr8); + masm.movq(gpr6, gpr8); + masm.testl(gpr8, Integer.MIN_VALUE); + masm.jcc(ConditionFlag.NotEqual, bb12); + + masm.shrl(gpr8); + masm.movl(gpr2, 0); + masm.shrq(gpr6, 3); + masm.jmp(bb6); + + masm.bind(bb4); + masm.shrl(gpr8); + masm.movl(gpr2, 536870912); + masm.shrl(gpr2); + masm.shlq(gpr8, 32); + masm.orq(gpr8, gpr10); + masm.shlq(gpr2, 32); + masm.addl(gpr6, 536870912); + masm.movl(gpr3, 0); + masm.movl(gpr10, 0); + masm.subq(gpr3, gpr7); + masm.sbbq(gpr10, gpr9); + masm.sbbq(gpr2, gpr8); + masm.movq(gpr7, gpr3); + masm.movq(gpr9, gpr10); + masm.movq(gpr8, gpr2); + masm.movl(gpr2, 32768); + masm.jmp(bb5); + + masm.bind(bb12); + masm.shrl(gpr8); + masm.movq(gpr2, 0x100000000L); + masm.shrq(gpr2); + masm.movl(gpr3, 0); + masm.movl(gpr10, 0); + masm.subq(gpr3, gpr7); + masm.sbbq(gpr10, gpr9); + masm.sbbq(gpr2, gpr8); + masm.movq(gpr7, gpr3); + masm.movq(gpr9, gpr10); + masm.movq(gpr8, gpr2); + masm.movl(gpr2, 32768); + masm.shrq(gpr6, 3); + masm.addl(gpr6, 536870912); + masm.jmp(bb6); + + masm.bind(bb13); + } + + /* + * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM) + * Source Code + * + * ALGORITHM DESCRIPTION - TAN() --------------------- + * + * Polynomials coefficients and other constants. + * + * Note that in this algorithm, there is a different polynomial for each breakpoint, so there + * are 32 sets of polynomial coefficients as well as 32 instances of the other constants. + * + * The polynomial coefficients and constants are offset from the start of the main block as + * follows: + * + * 0: c8 | c0 16: c9 | c1 32: c10 | c2 48: c11 | c3 64: c12 | c4 80: c13 | c5 96: c14 | c6 112: + * c15 | c7 128: T_hi 136: T_lo 144: Sigma 152: T_hl 160: Tau 168: Mask 176: (end of block) + * + * The total table size is therefore 5632 bytes. + * + * Note that c0 and c1 are always zero. We could try storing other constants here, and just + * loading the low part of the SIMD register in these cases, after ensuring the high part is + * zero. + * + * The higher terms of the polynomial are computed in the *low* part of the SIMD register. This + * is so we can overlap the multiplication by r^8 and the unpacking of the other part. + * + * The constants are: T_hi + T_lo = accurate constant term in power series Sigma + T_hl = + * accurate coefficient of r in power series (Sigma=1 bit) Tau = multiplier for the reciprocal, + * always -1 or 0 + * + * The basic reconstruction formula using these constants is: + * + * High = tau * recip_hi + t_hi Med = (sgn * r + t_hl * r)_hi Low = (sgn * r + t_hl * r)_lo + + * tau * recip_lo + T_lo + (T_hl + sigma) * c + pol + * + * where pol = c0 + c1 * r + c2 * r^2 + ... + c15 * r^15 + * + * (c0 = c1 = 0, but using them keeps SIMD regularity) + * + * We then do a compensated sum High + Med, add the low parts together and then do the final + * sum. + * + * Here recip_hi + recip_lo is an accurate reciprocal of the remainder modulo pi/2 + * + * Special cases: tan(NaN) = quiet NaN, and raise invalid exception tan(INF) = NaN and raise + * invalid exception tan(+/-0) = +/-0 + * + */ + + private static int[] oneHalfTan = { + 0x00000000, 0x3fe00000, 0x00000000, 0x3fe00000 + }; + + private static int[] mulSixteen = { + 0x00000000, 0x40300000, 0x00000000, 0x3ff00000 + }; + + private static int[] signMaskTan = { + 0x00000000, 0x80000000, 0x00000000, 0x80000000 + }; + + private static int[] piThirtyTwoInvTan = { + 0x6dc9c883, 0x3fe45f30, 0x6dc9c883, 0x40245f30 + }; + + private static int[] pOneTan = { + 0x54444000, 0x3fb921fb, 0x54440000, 0x3fb921fb + }; + + private static int[] pTwoTan = { + 0x67674000, 0xbd32e7b9, 0x4c4c0000, 0x3d468c23 + }; + + private static int[] pThreeTan = { + 0x3707344a, 0x3aa8a2e0, 0x03707345, 0x3ae98a2e + }; + + private static int[] cTableTan = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x882c10fa, + 0x3f9664f4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x55e6c23d, 0x3f8226e3, 0x55555555, + 0x3fd55555, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0e157de0, 0x3f6d6d3d, 0x11111111, 0x3fc11111, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x452b75e3, 0x3f57da36, + 0x1ba1ba1c, 0x3faba1ba, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3ff00000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x4e435f9b, + 0x3f953f83, 0x00000000, 0x00000000, 0x3c6e8e46, 0x3f9b74ea, + 0x00000000, 0x00000000, 0xda5b7511, 0x3f85ad63, 0xdc230b9b, + 0x3fb97558, 0x26cb3788, 0x3f881308, 0x76fc4985, 0x3fd62ac9, + 0x77bb08ba, 0x3f757c85, 0xb6247521, 0x3fb1381e, 0x5922170c, + 0x3f754e95, 0x8746482d, 0x3fc27f83, 0x11055b30, 0x3f64e391, + 0x3e666320, 0x3fa3e609, 0x0de9dae3, 0x3f6301df, 0x1f1dca06, + 0x3fafa8ae, 0x8c5b2da2, 0x3fb936bb, 0x4e88f7a5, 0x3c587d05, + 0x00000000, 0x3ff00000, 0xa8935dd9, 0x3f83dde2, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x5a279ea3, 0x3faa3407, + 0x00000000, 0x00000000, 0x432d65fa, 0x3fa70153, 0x00000000, + 0x00000000, 0x891a4602, 0x3f9d03ef, 0xd62ca5f8, 0x3fca77d9, + 0xb35f4628, 0x3f97a265, 0x433258fa, 0x3fd8cf51, 0xb58fd909, + 0x3f8f88e3, 0x01771cea, 0x3fc2b154, 0xf3562f8e, 0x3f888f57, + 0xc028a723, 0x3fc7370f, 0x20b7f9f0, 0x3f80f44c, 0x214368e9, + 0x3fb6dfaa, 0x28891863, 0x3f79b4b6, 0x172dbbf0, 0x3fb6cb8e, + 0xe0553158, 0x3fc975f5, 0x593fe814, 0x3c2ef5d3, 0x00000000, + 0x3ff00000, 0x03dec550, 0x3fa44203, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x9314533e, 0x3fbb8ec5, 0x00000000, + 0x00000000, 0x09aa36d0, 0x3fb6d3f4, 0x00000000, 0x00000000, + 0xdcb427fd, 0x3fb13950, 0xd87ab0bb, 0x3fd5335e, 0xce0ae8a5, + 0x3fabb382, 0x79143126, 0x3fddba41, 0x5f2b28d4, 0x3fa552f1, + 0x59f21a6d, 0x3fd015ab, 0x22c27d95, 0x3fa0e984, 0xe19fc6aa, + 0x3fd0576c, 0x8f2c2950, 0x3f9a4898, 0xc0b3f22c, 0x3fc59462, + 0x1883a4b8, 0x3f94b61c, 0x3f838640, 0x3fc30eb8, 0x355c63dc, + 0x3fd36a08, 0x1dce993d, 0xbc6d704d, 0x00000000, 0x3ff00000, + 0x2b82ab63, 0x3fb78e92, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x56f37042, 0x3fccfc56, 0x00000000, 0x00000000, + 0xaa563951, 0x3fc90125, 0x00000000, 0x00000000, 0x3d0e7c5d, + 0x3fc50533, 0x9bed9b2e, 0x3fdf0ed9, 0x5fe7c47c, 0x3fc1f250, + 0x96c125e5, 0x3fe2edd9, 0x5a02bbd8, 0x3fbe5c71, 0x86362c20, + 0x3fda08b7, 0x4b4435ed, 0x3fb9d342, 0x4b494091, 0x3fd911bd, + 0xb56658be, 0x3fb5e4c7, 0x93a2fd76, 0x3fd3c092, 0xda271794, + 0x3fb29910, 0x3303df2b, 0x3fd189be, 0x99fcef32, 0x3fda8279, + 0xb68c1467, 0x3c708b2f, 0x00000000, 0x3ff00000, 0x980c4337, + 0x3fc5f619, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xcc03e501, 0x3fdff10f, 0x00000000, 0x00000000, 0x44a4e845, + 0x3fddb63b, 0x00000000, 0x00000000, 0x3768ad9f, 0x3fdb72a4, + 0x3dd01cca, 0x3fe5fdb9, 0xa61d2811, 0x3fd972b2, 0x5645ad0b, + 0x3fe977f9, 0xd013b3ab, 0x3fd78ca3, 0xbf0bf914, 0x3fe4f192, + 0x4d53e730, 0x3fd5d060, 0x3f8b9000, 0x3fe49933, 0xe2b82f08, + 0x3fd4322a, 0x5936a835, 0x3fe27ae1, 0xb1c61c9b, 0x3fd2b3fb, + 0xef478605, 0x3fe1659e, 0x190834ec, 0x3fe11ab7, 0xcdb625ea, + 0xbc8e564b, 0x00000000, 0x3ff00000, 0xb07217e3, 0x3fd248f1, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2b2c49d0, + 0x3ff2de9c, 0x00000000, 0x00000000, 0x2655bc98, 0x3ff33e58, + 0x00000000, 0x00000000, 0xff691fa2, 0x3ff3972e, 0xe93463bd, + 0x3feeed87, 0x070e10a0, 0x3ff3f5b2, 0xf4d790a4, 0x3ff20c10, + 0xa04e8ea3, 0x3ff4541a, 0x386accd3, 0x3ff1369e, 0x222a66dd, + 0x3ff4b521, 0x22a9777e, 0x3ff20817, 0x52a04a6e, 0x3ff5178f, + 0xddaa0031, 0x3ff22137, 0x4447d47c, 0x3ff57c01, 0x1e9c7f1d, + 0x3ff29311, 0x2ab7f990, 0x3fe561b8, 0x209c7df1, 0x3c87a8c5, + 0x00000000, 0x3ff00000, 0x4170bcc6, 0x3fdc92d8, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xc7ab4d5a, 0x40085e24, + 0x00000000, 0x00000000, 0xe93ea75d, 0x400b963d, 0x00000000, + 0x00000000, 0x94a7f25a, 0x400f37e2, 0x4b6261cb, 0x3ff5f984, + 0x5a9dd812, 0x4011aab0, 0x74c30018, 0x3ffaf5a5, 0x7f2ce8e3, + 0x4013fe8b, 0xfe8e54fa, 0x3ffd7334, 0x670d618d, 0x4016a10c, + 0x4db97058, 0x4000e012, 0x24df44dd, 0x40199c5f, 0x697d6ece, + 0x4003006e, 0x83298b82, 0x401cfc4d, 0x19d490d6, 0x40058c19, + 0x2ae42850, 0x3fea4300, 0x118e20e6, 0xbc7a6db8, 0x00000000, + 0x40000000, 0xe33345b8, 0xbfd4e526, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x65965966, 0x40219659, 0x00000000, + 0x00000000, 0x882c10fa, 0x402664f4, 0x00000000, 0x00000000, + 0x83cd3723, 0x402c8342, 0x00000000, 0x40000000, 0x55e6c23d, + 0x403226e3, 0x55555555, 0x40055555, 0x34451939, 0x40371c96, + 0xaaaaaaab, 0x400aaaaa, 0x0e157de0, 0x403d6d3d, 0x11111111, + 0x40111111, 0xa738201f, 0x4042bbce, 0x05b05b06, 0x4015b05b, + 0x452b75e3, 0x4047da36, 0x1ba1ba1c, 0x401ba1ba, 0x00000000, + 0x3ff00000, 0x00000000, 0x00000000, 0x00000000, 0x40000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x4f48b8d3, 0xbf33eaf9, 0x00000000, 0x00000000, + 0x0cf7586f, 0x3f20b8ea, 0x00000000, 0x00000000, 0xd0258911, + 0xbf0abaf3, 0x23e49fe9, 0xbfab5a8c, 0x2d53222e, 0x3ef60d15, + 0x21169451, 0x3fa172b2, 0xbb254dbc, 0xbee1d3b5, 0xdbf93b8e, + 0xbf84c7db, 0x05b4630b, 0x3ecd3364, 0xee9aada7, 0x3f743924, + 0x794a8297, 0xbeb7b7b9, 0xe015f797, 0xbf5d41f5, 0xe41a4a56, + 0x3ea35dfb, 0xe4c2a251, 0x3f49a2ab, 0x5af9e000, 0xbfce49ce, + 0x8c743719, 0x3d1eb860, 0x00000000, 0x00000000, 0x1b4863cf, + 0x3fd78294, 0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8, + 0x535ad890, 0xbf2b9320, 0x00000000, 0x00000000, 0x018fdf1f, + 0x3f16d61d, 0x00000000, 0x00000000, 0x0359f1be, 0xbf0139e4, + 0xa4317c6d, 0xbfa67e17, 0x82672d0f, 0x3eebb405, 0x2f1b621e, + 0x3f9f455b, 0x51ccf238, 0xbed55317, 0xf437b9ac, 0xbf804bee, + 0xc791a2b5, 0x3ec0e993, 0x919a1db2, 0x3f7080c2, 0x336a5b0e, + 0xbeaa48a2, 0x0a268358, 0xbf55a443, 0xdfd978e4, 0x3e94b61f, + 0xd7767a58, 0x3f431806, 0x2aea0000, 0xbfc9bbe8, 0x7723ea61, + 0xbd3a2369, 0x00000000, 0x00000000, 0xdf7796ff, 0x3fd6e642, + 0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8, 0xb9ff07ce, + 0xbf231c78, 0x00000000, 0x00000000, 0xa5517182, 0x3f0ff0e0, + 0x00000000, 0x00000000, 0x790b4cbc, 0xbef66191, 0x848a46c6, + 0xbfa21ac0, 0xb16435fa, 0x3ee1d3ec, 0x2a1aa832, 0x3f9c71ea, + 0xfdd299ef, 0xbec9dd1a, 0x3f8dbaaf, 0xbf793363, 0x309fc6ea, + 0x3eb415d6, 0xbee60471, 0x3f6b83ba, 0x94a0a697, 0xbe9dae11, + 0x3e5c67b3, 0xbf4fd07b, 0x9a8f3e3e, 0x3e86bd75, 0xa4beb7a4, + 0x3f3d1eb1, 0x29cfc000, 0xbfc549ce, 0xbf159358, 0xbd397b33, + 0x00000000, 0x00000000, 0x871fee6c, 0x3fd666f0, 0x00000000, + 0x3ff00000, 0x00000000, 0xfffffff8, 0x7d98a556, 0xbf1a3958, + 0x00000000, 0x00000000, 0x9d88dc01, 0x3f0704c2, 0x00000000, + 0x00000000, 0x73742a2b, 0xbeed054a, 0x58844587, 0xbf9c2a13, + 0x55688a79, 0x3ed7a326, 0xee33f1d6, 0x3f9a48f4, 0xa8dc9888, + 0xbebf8939, 0xaad4b5b8, 0xbf72f746, 0x9102efa1, 0x3ea88f82, + 0xdabc29cf, 0x3f678228, 0x9289afb8, 0xbe90f456, 0x741fb4ed, + 0xbf46f3a3, 0xa97f6663, 0x3e79b4bf, 0xca89ff3f, 0x3f36db70, + 0xa8a2a000, 0xbfc0ee13, 0x3da24be1, 0xbd338b9f, 0x00000000, + 0x00000000, 0x11cd6c69, 0x3fd601fd, 0x00000000, 0x3ff00000, + 0x00000000, 0xfffffff8, 0x1a154b97, 0xbf116b01, 0x00000000, + 0x00000000, 0x2d427630, 0x3f0147bf, 0x00000000, 0x00000000, + 0xb93820c8, 0xbee264d4, 0xbb6cbb18, 0xbf94ab8c, 0x888d4d92, + 0x3ed0568b, 0x60730f7c, 0x3f98b19b, 0xe4b1fb11, 0xbeb2f950, + 0x22cf9f74, 0xbf6b21cd, 0x4a3ff0a6, 0x3e9f499e, 0xfd2b83ce, + 0x3f64aad7, 0x637b73af, 0xbe83487c, 0xe522591a, 0xbf3fc092, + 0xa158e8bc, 0x3e6e3aae, 0xe5e82ffa, 0x3f329d2f, 0xd636a000, + 0xbfb9477f, 0xc2c2d2bc, 0xbd135ef9, 0x00000000, 0x00000000, + 0xf2fdb123, 0x3fd5b566, 0x00000000, 0x3ff00000, 0x00000000, + 0xfffffff8, 0xc41acb64, 0xbf05448d, 0x00000000, 0x00000000, + 0xdbb03d6f, 0x3efb7ad2, 0x00000000, 0x00000000, 0x9e42962d, + 0xbed5aea5, 0x2579f8ef, 0xbf8b2398, 0x288a1ed9, 0x3ec81441, + 0xb0198dc5, 0x3f979a3a, 0x2fdfe253, 0xbea57cd3, 0x5766336f, + 0xbf617caa, 0x600944c3, 0x3e954ed6, 0xa4e0aaf8, 0x3f62c646, + 0x6b8fb29c, 0xbe74e3a3, 0xdc4c0409, 0xbf33f952, 0x9bffe365, + 0x3e6301ec, 0xb8869e44, 0x3f2fc566, 0xe1e04000, 0xbfb0cc62, + 0x016b907f, 0xbd119cbc, 0x00000000, 0x00000000, 0xe6b9d8fa, + 0x3fd57fb3, 0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8, + 0x5daf22a6, 0xbef429d7, 0x00000000, 0x00000000, 0x06bca545, + 0x3ef7a27d, 0x00000000, 0x00000000, 0x7211c19a, 0xbec41c3e, + 0x956ed53e, 0xbf7ae3f4, 0xee750e72, 0x3ec3901b, 0x91d443f5, + 0x3f96f713, 0x36661e6c, 0xbe936e09, 0x506f9381, 0xbf5122e8, + 0xcb6dd43f, 0x3e9041b9, 0x6698b2ff, 0x3f61b0c7, 0x576bf12b, + 0xbe625a8a, 0xe5a0e9dc, 0xbf23499d, 0x110384dd, 0x3e5b1c2c, + 0x68d43db6, 0x3f2cb899, 0x6ecac000, 0xbfa0c414, 0xcd7dd58c, + 0x3d13500f, 0x00000000, 0x00000000, 0x85a2c8fb, 0x3fd55fe0, + 0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x2bf70ebe, 0x3ef66a8f, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xd644267f, 0x3ec22805, 0x16c16c17, 0x3f96c16c, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xc4e09162, + 0x3e8d6db2, 0xbc011567, 0x3f61566a, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x1f79955c, 0x3e57da4e, 0x9334ef0b, + 0x3f2bbd77, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x55555555, 0x3fd55555, 0x00000000, + 0x3ff00000, 0x00000000, 0xfffffff8, 0x5daf22a6, 0x3ef429d7, + 0x00000000, 0x00000000, 0x06bca545, 0x3ef7a27d, 0x00000000, + 0x00000000, 0x7211c19a, 0x3ec41c3e, 0x956ed53e, 0x3f7ae3f4, + 0xee750e72, 0x3ec3901b, 0x91d443f5, 0x3f96f713, 0x36661e6c, + 0x3e936e09, 0x506f9381, 0x3f5122e8, 0xcb6dd43f, 0x3e9041b9, + 0x6698b2ff, 0x3f61b0c7, 0x576bf12b, 0x3e625a8a, 0xe5a0e9dc, + 0x3f23499d, 0x110384dd, 0x3e5b1c2c, 0x68d43db6, 0x3f2cb899, + 0x6ecac000, 0x3fa0c414, 0xcd7dd58c, 0xbd13500f, 0x00000000, + 0x00000000, 0x85a2c8fb, 0x3fd55fe0, 0x00000000, 0x3ff00000, + 0x00000000, 0xfffffff8, 0xc41acb64, 0x3f05448d, 0x00000000, + 0x00000000, 0xdbb03d6f, 0x3efb7ad2, 0x00000000, 0x00000000, + 0x9e42962d, 0x3ed5aea5, 0x2579f8ef, 0x3f8b2398, 0x288a1ed9, + 0x3ec81441, 0xb0198dc5, 0x3f979a3a, 0x2fdfe253, 0x3ea57cd3, + 0x5766336f, 0x3f617caa, 0x600944c3, 0x3e954ed6, 0xa4e0aaf8, + 0x3f62c646, 0x6b8fb29c, 0x3e74e3a3, 0xdc4c0409, 0x3f33f952, + 0x9bffe365, 0x3e6301ec, 0xb8869e44, 0x3f2fc566, 0xe1e04000, + 0x3fb0cc62, 0x016b907f, 0x3d119cbc, 0x00000000, 0x00000000, + 0xe6b9d8fa, 0x3fd57fb3, 0x00000000, 0x3ff00000, 0x00000000, + 0xfffffff8, 0x1a154b97, 0x3f116b01, 0x00000000, 0x00000000, + 0x2d427630, 0x3f0147bf, 0x00000000, 0x00000000, 0xb93820c8, + 0x3ee264d4, 0xbb6cbb18, 0x3f94ab8c, 0x888d4d92, 0x3ed0568b, + 0x60730f7c, 0x3f98b19b, 0xe4b1fb11, 0x3eb2f950, 0x22cf9f74, + 0x3f6b21cd, 0x4a3ff0a6, 0x3e9f499e, 0xfd2b83ce, 0x3f64aad7, + 0x637b73af, 0x3e83487c, 0xe522591a, 0x3f3fc092, 0xa158e8bc, + 0x3e6e3aae, 0xe5e82ffa, 0x3f329d2f, 0xd636a000, 0x3fb9477f, + 0xc2c2d2bc, 0x3d135ef9, 0x00000000, 0x00000000, 0xf2fdb123, + 0x3fd5b566, 0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8, + 0x7d98a556, 0x3f1a3958, 0x00000000, 0x00000000, 0x9d88dc01, + 0x3f0704c2, 0x00000000, 0x00000000, 0x73742a2b, 0x3eed054a, + 0x58844587, 0x3f9c2a13, 0x55688a79, 0x3ed7a326, 0xee33f1d6, + 0x3f9a48f4, 0xa8dc9888, 0x3ebf8939, 0xaad4b5b8, 0x3f72f746, + 0x9102efa1, 0x3ea88f82, 0xdabc29cf, 0x3f678228, 0x9289afb8, + 0x3e90f456, 0x741fb4ed, 0x3f46f3a3, 0xa97f6663, 0x3e79b4bf, + 0xca89ff3f, 0x3f36db70, 0xa8a2a000, 0x3fc0ee13, 0x3da24be1, + 0x3d338b9f, 0x00000000, 0x00000000, 0x11cd6c69, 0x3fd601fd, + 0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8, 0xb9ff07ce, + 0x3f231c78, 0x00000000, 0x00000000, 0xa5517182, 0x3f0ff0e0, + 0x00000000, 0x00000000, 0x790b4cbc, 0x3ef66191, 0x848a46c6, + 0x3fa21ac0, 0xb16435fa, 0x3ee1d3ec, 0x2a1aa832, 0x3f9c71ea, + 0xfdd299ef, 0x3ec9dd1a, 0x3f8dbaaf, 0x3f793363, 0x309fc6ea, + 0x3eb415d6, 0xbee60471, 0x3f6b83ba, 0x94a0a697, 0x3e9dae11, + 0x3e5c67b3, 0x3f4fd07b, 0x9a8f3e3e, 0x3e86bd75, 0xa4beb7a4, + 0x3f3d1eb1, 0x29cfc000, 0x3fc549ce, 0xbf159358, 0x3d397b33, + 0x00000000, 0x00000000, 0x871fee6c, 0x3fd666f0, 0x00000000, + 0x3ff00000, 0x00000000, 0xfffffff8, 0x535ad890, 0x3f2b9320, + 0x00000000, 0x00000000, 0x018fdf1f, 0x3f16d61d, 0x00000000, + 0x00000000, 0x0359f1be, 0x3f0139e4, 0xa4317c6d, 0x3fa67e17, + 0x82672d0f, 0x3eebb405, 0x2f1b621e, 0x3f9f455b, 0x51ccf238, + 0x3ed55317, 0xf437b9ac, 0x3f804bee, 0xc791a2b5, 0x3ec0e993, + 0x919a1db2, 0x3f7080c2, 0x336a5b0e, 0x3eaa48a2, 0x0a268358, + 0x3f55a443, 0xdfd978e4, 0x3e94b61f, 0xd7767a58, 0x3f431806, + 0x2aea0000, 0x3fc9bbe8, 0x7723ea61, 0x3d3a2369, 0x00000000, + 0x00000000, 0xdf7796ff, 0x3fd6e642, 0x00000000, 0x3ff00000, + 0x00000000, 0xfffffff8, 0x4f48b8d3, 0x3f33eaf9, 0x00000000, + 0x00000000, 0x0cf7586f, 0x3f20b8ea, 0x00000000, 0x00000000, + 0xd0258911, 0x3f0abaf3, 0x23e49fe9, 0x3fab5a8c, 0x2d53222e, + 0x3ef60d15, 0x21169451, 0x3fa172b2, 0xbb254dbc, 0x3ee1d3b5, + 0xdbf93b8e, 0x3f84c7db, 0x05b4630b, 0x3ecd3364, 0xee9aada7, + 0x3f743924, 0x794a8297, 0x3eb7b7b9, 0xe015f797, 0x3f5d41f5, + 0xe41a4a56, 0x3ea35dfb, 0xe4c2a251, 0x3f49a2ab, 0x5af9e000, + 0x3fce49ce, 0x8c743719, 0xbd1eb860, 0x00000000, 0x00000000, + 0x1b4863cf, 0x3fd78294, 0x00000000, 0x3ff00000, 0x00000000, + 0xfffffff8, 0x65965966, 0xc0219659, 0x00000000, 0x00000000, + 0x882c10fa, 0x402664f4, 0x00000000, 0x00000000, 0x83cd3723, + 0xc02c8342, 0x00000000, 0xc0000000, 0x55e6c23d, 0x403226e3, + 0x55555555, 0x40055555, 0x34451939, 0xc0371c96, 0xaaaaaaab, + 0xc00aaaaa, 0x0e157de0, 0x403d6d3d, 0x11111111, 0x40111111, + 0xa738201f, 0xc042bbce, 0x05b05b06, 0xc015b05b, 0x452b75e3, + 0x4047da36, 0x1ba1ba1c, 0x401ba1ba, 0x00000000, 0xbff00000, + 0x00000000, 0x00000000, 0x00000000, 0x40000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xc7ab4d5a, 0xc0085e24, 0x00000000, 0x00000000, 0xe93ea75d, + 0x400b963d, 0x00000000, 0x00000000, 0x94a7f25a, 0xc00f37e2, + 0x4b6261cb, 0xbff5f984, 0x5a9dd812, 0x4011aab0, 0x74c30018, + 0x3ffaf5a5, 0x7f2ce8e3, 0xc013fe8b, 0xfe8e54fa, 0xbffd7334, + 0x670d618d, 0x4016a10c, 0x4db97058, 0x4000e012, 0x24df44dd, + 0xc0199c5f, 0x697d6ece, 0xc003006e, 0x83298b82, 0x401cfc4d, + 0x19d490d6, 0x40058c19, 0x2ae42850, 0xbfea4300, 0x118e20e6, + 0x3c7a6db8, 0x00000000, 0x40000000, 0xe33345b8, 0xbfd4e526, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2b2c49d0, + 0xbff2de9c, 0x00000000, 0x00000000, 0x2655bc98, 0x3ff33e58, + 0x00000000, 0x00000000, 0xff691fa2, 0xbff3972e, 0xe93463bd, + 0xbfeeed87, 0x070e10a0, 0x3ff3f5b2, 0xf4d790a4, 0x3ff20c10, + 0xa04e8ea3, 0xbff4541a, 0x386accd3, 0xbff1369e, 0x222a66dd, + 0x3ff4b521, 0x22a9777e, 0x3ff20817, 0x52a04a6e, 0xbff5178f, + 0xddaa0031, 0xbff22137, 0x4447d47c, 0x3ff57c01, 0x1e9c7f1d, + 0x3ff29311, 0x2ab7f990, 0xbfe561b8, 0x209c7df1, 0xbc87a8c5, + 0x00000000, 0x3ff00000, 0x4170bcc6, 0x3fdc92d8, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xcc03e501, 0xbfdff10f, + 0x00000000, 0x00000000, 0x44a4e845, 0x3fddb63b, 0x00000000, + 0x00000000, 0x3768ad9f, 0xbfdb72a4, 0x3dd01cca, 0xbfe5fdb9, + 0xa61d2811, 0x3fd972b2, 0x5645ad0b, 0x3fe977f9, 0xd013b3ab, + 0xbfd78ca3, 0xbf0bf914, 0xbfe4f192, 0x4d53e730, 0x3fd5d060, + 0x3f8b9000, 0x3fe49933, 0xe2b82f08, 0xbfd4322a, 0x5936a835, + 0xbfe27ae1, 0xb1c61c9b, 0x3fd2b3fb, 0xef478605, 0x3fe1659e, + 0x190834ec, 0xbfe11ab7, 0xcdb625ea, 0x3c8e564b, 0x00000000, + 0x3ff00000, 0xb07217e3, 0x3fd248f1, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x56f37042, 0xbfccfc56, 0x00000000, + 0x00000000, 0xaa563951, 0x3fc90125, 0x00000000, 0x00000000, + 0x3d0e7c5d, 0xbfc50533, 0x9bed9b2e, 0xbfdf0ed9, 0x5fe7c47c, + 0x3fc1f250, 0x96c125e5, 0x3fe2edd9, 0x5a02bbd8, 0xbfbe5c71, + 0x86362c20, 0xbfda08b7, 0x4b4435ed, 0x3fb9d342, 0x4b494091, + 0x3fd911bd, 0xb56658be, 0xbfb5e4c7, 0x93a2fd76, 0xbfd3c092, + 0xda271794, 0x3fb29910, 0x3303df2b, 0x3fd189be, 0x99fcef32, + 0xbfda8279, 0xb68c1467, 0xbc708b2f, 0x00000000, 0x3ff00000, + 0x980c4337, 0x3fc5f619, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x9314533e, 0xbfbb8ec5, 0x00000000, 0x00000000, + 0x09aa36d0, 0x3fb6d3f4, 0x00000000, 0x00000000, 0xdcb427fd, + 0xbfb13950, 0xd87ab0bb, 0xbfd5335e, 0xce0ae8a5, 0x3fabb382, + 0x79143126, 0x3fddba41, 0x5f2b28d4, 0xbfa552f1, 0x59f21a6d, + 0xbfd015ab, 0x22c27d95, 0x3fa0e984, 0xe19fc6aa, 0x3fd0576c, + 0x8f2c2950, 0xbf9a4898, 0xc0b3f22c, 0xbfc59462, 0x1883a4b8, + 0x3f94b61c, 0x3f838640, 0x3fc30eb8, 0x355c63dc, 0xbfd36a08, + 0x1dce993d, 0x3c6d704d, 0x00000000, 0x3ff00000, 0x2b82ab63, + 0x3fb78e92, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x5a279ea3, 0xbfaa3407, 0x00000000, 0x00000000, 0x432d65fa, + 0x3fa70153, 0x00000000, 0x00000000, 0x891a4602, 0xbf9d03ef, + 0xd62ca5f8, 0xbfca77d9, 0xb35f4628, 0x3f97a265, 0x433258fa, + 0x3fd8cf51, 0xb58fd909, 0xbf8f88e3, 0x01771cea, 0xbfc2b154, + 0xf3562f8e, 0x3f888f57, 0xc028a723, 0x3fc7370f, 0x20b7f9f0, + 0xbf80f44c, 0x214368e9, 0xbfb6dfaa, 0x28891863, 0x3f79b4b6, + 0x172dbbf0, 0x3fb6cb8e, 0xe0553158, 0xbfc975f5, 0x593fe814, + 0xbc2ef5d3, 0x00000000, 0x3ff00000, 0x03dec550, 0x3fa44203, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x4e435f9b, + 0xbf953f83, 0x00000000, 0x00000000, 0x3c6e8e46, 0x3f9b74ea, + 0x00000000, 0x00000000, 0xda5b7511, 0xbf85ad63, 0xdc230b9b, + 0xbfb97558, 0x26cb3788, 0x3f881308, 0x76fc4985, 0x3fd62ac9, + 0x77bb08ba, 0xbf757c85, 0xb6247521, 0xbfb1381e, 0x5922170c, + 0x3f754e95, 0x8746482d, 0x3fc27f83, 0x11055b30, 0xbf64e391, + 0x3e666320, 0xbfa3e609, 0x0de9dae3, 0x3f6301df, 0x1f1dca06, + 0x3fafa8ae, 0x8c5b2da2, 0xbfb936bb, 0x4e88f7a5, 0xbc587d05, + 0x00000000, 0x3ff00000, 0xa8935dd9, 0x3f83dde2, 0x00000000, + 0x00000000, 0x00000000, 0x00000000 + }; + + private static int[] maskThirtyFiveTan = { + 0xfffc0000, 0xffffffff, 0x00000000, 0x00000000 + }; + + private static int[] qElevenTan = { + 0xb8fe4d77, 0x3f82609a + }; + + private static int[] qNineTan = { + 0xbf847a43, 0x3f9664a0 + }; + + private static int[] qSevenTan = { + 0x52c4c8ab, 0x3faba1ba + }; + + private static int[] qFiveTan = { + 0x11092746, 0x3fc11111 + }; + + private static int[] qThreeTan = { + 0x55555612, 0x3fd55555 + }; + + private static int[] piInvTableTan = { + 0x00000000, 0x00000000, 0xa2f9836e, 0x4e441529, 0xfc2757d1, + 0xf534ddc0, 0xdb629599, 0x3c439041, 0xfe5163ab, 0xdebbc561, + 0xb7246e3a, 0x424dd2e0, 0x06492eea, 0x09d1921c, 0xfe1deb1c, + 0xb129a73e, 0xe88235f5, 0x2ebb4484, 0xe99c7026, 0xb45f7e41, + 0x3991d639, 0x835339f4, 0x9c845f8b, 0xbdf9283b, 0x1ff897ff, + 0xde05980f, 0xef2f118b, 0x5a0a6d1f, 0x6d367ecf, 0x27cb09b7, + 0x4f463f66, 0x9e5fea2d, 0x7527bac7, 0xebe5f17b, 0x3d0739f7, + 0x8a5292ea, 0x6bfb5fb1, 0x1f8d5d08, 0x56033046, 0xfc7b6bab, + 0xf0cfbc21 + }; + + private static int[] piFourTan = { + 0x00000000, 0x3fe921fb, 0x4611a626, 0x3e85110b + }; + + private static int[] qqTwoTan = { + 0x676733af, 0x3d32e7b9 + }; + + private static int[] twoPowFiftyFiveTan = { + 0x00000000, 0x43600000 + }; + + private static int[] twoPowMFiftyFiveTan = { + 0x00000000, 0x3c800000 + }; + + public void tanIntrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) { + ArrayDataPointerConstant oneHalfTanPtr = new ArrayDataPointerConstant(oneHalfTan, 16); + ArrayDataPointerConstant mulSixteenPtr = new ArrayDataPointerConstant(mulSixteen, 16); + ArrayDataPointerConstant signMaskTanPtr = new ArrayDataPointerConstant(signMaskTan, 16); + ArrayDataPointerConstant piThirtyTwoInvTanPtr = new ArrayDataPointerConstant(piThirtyTwoInvTan, 16); + ArrayDataPointerConstant pOneTanPtr = new ArrayDataPointerConstant(pOneTan, 16); + ArrayDataPointerConstant pTwoTanPtr = new ArrayDataPointerConstant(pTwoTan, 16); + ArrayDataPointerConstant pThreeTanPtr = new ArrayDataPointerConstant(pThreeTan, 16); + ArrayDataPointerConstant cTableTanPtr = new ArrayDataPointerConstant(cTableTan, 16); + ArrayDataPointerConstant maskThirtyFiveTanPtr = new ArrayDataPointerConstant(maskThirtyFiveTan, 16); + ArrayDataPointerConstant qElevenTanPtr = new ArrayDataPointerConstant(qElevenTan, 16); + ArrayDataPointerConstant qNineTanPtr = new ArrayDataPointerConstant(qNineTan, 16); + ArrayDataPointerConstant qSevenTanPtr = new ArrayDataPointerConstant(qSevenTan, 8); + ArrayDataPointerConstant qFiveTanPtr = new ArrayDataPointerConstant(qFiveTan, 16); + ArrayDataPointerConstant qThreeTanPtr = new ArrayDataPointerConstant(qThreeTan, 16); + ArrayDataPointerConstant piInvTableTanPtr = new ArrayDataPointerConstant(piInvTableTan, 16); + ArrayDataPointerConstant piFourTanPtr = new ArrayDataPointerConstant(piFourTan, 8); + ArrayDataPointerConstant qqTwoTanPtr = new ArrayDataPointerConstant(qqTwoTan, 8); + ArrayDataPointerConstant onePtr = new ArrayDataPointerConstant(one, 8); + ArrayDataPointerConstant twoPowFiftyFiveTanPtr = new ArrayDataPointerConstant(twoPowFiftyFiveTan, 8); + ArrayDataPointerConstant twoPowMFiftyFiveTanPtr = new ArrayDataPointerConstant(twoPowMFiftyFiveTan, 8); + + Label bb0 = new Label(); + Label bb1 = new Label(); + Label bb2 = new Label(); + Label bb3 = new Label(); + Label bb5 = new Label(); + Label bb6 = new Label(); + Label bb8 = new Label(); + Label bb9 = new Label(); + Label bb10 = new Label(); + Label bb11 = new Label(); + Label bb12 = new Label(); + Label bb13 = new Label(); + Label bb14 = new Label(); + Label bb15 = new Label(); + + Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD); + Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD); + Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD); + Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD); + Register gpr5 = asRegister(gpr5Temp, AMD64Kind.QWORD); + Register gpr6 = asRegister(gpr6Temp, AMD64Kind.QWORD); + Register gpr7 = asRegister(gpr7Temp, AMD64Kind.QWORD); + Register gpr8 = asRegister(gpr8Temp, AMD64Kind.QWORD); + Register gpr9 = asRegister(gpr9Temp, AMD64Kind.QWORD); + Register gpr10 = asRegister(gpr10Temp, AMD64Kind.QWORD); + + Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE); + Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE); + Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE); + Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE); + Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE); + Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE); + Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE); + + setCrb(crb); + if (dest.encoding != value.encoding) { + masm.movdqu(dest, value); + } + + masm.pextrw(gpr1, dest, 3); + masm.andl(gpr1, 32767); + masm.subl(gpr1, 16314); + masm.cmpl(gpr1, 270); + masm.jcc(ConditionFlag.Above, bb0); + + masm.movdqu(temp5, externalAddress(oneHalfTanPtr)); // 0x00000000, + // 0x3fe00000, + // 0x00000000, + // 0x3fe00000 + masm.movdqu(temp6, externalAddress(mulSixteenPtr)); // 0x00000000, + // 0x40300000, + // 0x00000000, + // 0x3ff00000 + masm.unpcklpd(dest, dest); + masm.movdqu(temp4, externalAddress(signMaskTanPtr)); // 0x00000000, + // 0x80000000, + // 0x00000000, + // 0x80000000 + masm.andpd(temp4, dest); + masm.movdqu(temp1, externalAddress(piThirtyTwoInvTanPtr)); // 0x6dc9c883, + // 0x3fe45f30, + // 0x6dc9c883, + // 0x40245f30 + masm.mulpd(temp1, dest); + masm.por(temp5, temp4); + masm.addpd(temp1, temp5); + masm.movdqu(temp7, temp1); + masm.unpckhpd(temp7, temp7); + masm.cvttsd2sil(gpr4, temp7); + masm.cvttpd2dq(temp1, temp1); + masm.cvtdq2pd(temp1, temp1); + masm.mulpd(temp1, temp6); + masm.movdqu(temp3, externalAddress(pOneTanPtr)); // 0x54444000, + // 0x3fb921fb, + // 0x54440000, + // 0x3fb921fb + masm.movdq(temp5, externalAddress(qqTwoTanPtr)); // 0x676733af, + // 0x3d32e7b9 + masm.addq(gpr4, 469248); + masm.movdqu(temp4, externalAddress(pTwoTanPtr)); // 0x67674000, + // 0xbd32e7b9, + // 0x4c4c0000, + // 0x3d468c23 + masm.mulpd(temp3, temp1); + masm.andq(gpr4, 31); + masm.mulsd(temp5, temp1); + masm.movq(gpr3, gpr4); + masm.mulpd(temp4, temp1); + masm.shlq(gpr3, 1); + masm.subpd(dest, temp3); + masm.mulpd(temp1, externalAddress(pThreeTanPtr)); // 0x3707344a, + // 0x3aa8a2e0, + // 0x03707345, + // 0x3ae98a2e + masm.addq(gpr4, gpr3); + masm.shlq(gpr3, 2); + masm.addq(gpr4, gpr3); + masm.addsd(temp5, dest); + masm.movdqu(temp2, dest); + masm.subpd(dest, temp4); + masm.movdq(temp6, externalAddress(onePtr)); // 0x00000000, + // 0x3ff00000 + masm.shlq(gpr4, 4); + masm.leaq(gpr1, externalAddress(cTableTanPtr)); + masm.andpd(temp5, externalAddress(maskThirtyFiveTanPtr)); // 0xfffc0000, + // 0xffffffff, + // 0x00000000, + // 0x00000000 + masm.movdqu(temp3, dest); + masm.addq(gpr1, gpr4); + masm.subpd(temp2, dest); + masm.unpckhpd(dest, dest); + masm.divsd(temp6, temp5); + masm.subpd(temp2, temp4); + masm.movdqu(temp7, new AMD64Address(gpr1, 16)); + masm.subsd(temp3, temp5); + masm.mulpd(temp7, dest); + masm.subpd(temp2, temp1); + masm.movdqu(temp1, new AMD64Address(gpr1, 48)); + masm.mulpd(temp1, dest); + masm.movdqu(temp4, new AMD64Address(gpr1, 96)); + masm.mulpd(temp4, dest); + masm.addsd(temp2, temp3); + masm.movdqu(temp3, dest); + masm.mulpd(dest, dest); + masm.addpd(temp7, new AMD64Address(gpr1, 0)); + masm.addpd(temp1, new AMD64Address(gpr1, 32)); + masm.mulpd(temp1, dest); + masm.addpd(temp4, new AMD64Address(gpr1, 80)); + masm.addpd(temp7, temp1); + masm.movdqu(temp1, new AMD64Address(gpr1, 112)); + masm.mulpd(temp1, dest); + masm.mulpd(dest, dest); + masm.addpd(temp4, temp1); + masm.movdqu(temp1, new AMD64Address(gpr1, 64)); + masm.mulpd(temp1, dest); + masm.addpd(temp7, temp1); + masm.movdqu(temp1, temp3); + masm.mulpd(temp3, dest); + masm.mulsd(dest, dest); + masm.mulpd(temp1, new AMD64Address(gpr1, 144)); + masm.mulpd(temp4, temp3); + masm.movdqu(temp3, temp1); + masm.addpd(temp7, temp4); + masm.movdqu(temp4, temp1); + masm.mulsd(dest, temp7); + masm.unpckhpd(temp7, temp7); + masm.addsd(dest, temp7); + masm.unpckhpd(temp1, temp1); + masm.addsd(temp3, temp1); + masm.subsd(temp4, temp3); + masm.addsd(temp1, temp4); + masm.movdqu(temp4, temp2); + masm.movdq(temp7, new AMD64Address(gpr1, 144)); + masm.unpckhpd(temp2, temp2); + masm.addsd(temp7, new AMD64Address(gpr1, 152)); + masm.mulsd(temp7, temp2); + masm.addsd(temp7, new AMD64Address(gpr1, 136)); + masm.addsd(temp7, temp1); + masm.addsd(dest, temp7); + masm.movdq(temp7, externalAddress(onePtr)); // 0x00000000, + // 0x3ff00000 + masm.mulsd(temp4, temp6); + masm.movdq(temp2, new AMD64Address(gpr1, 168)); + masm.andpd(temp2, temp6); + masm.mulsd(temp5, temp2); + masm.mulsd(temp6, new AMD64Address(gpr1, 160)); + masm.subsd(temp7, temp5); + masm.subsd(temp2, new AMD64Address(gpr1, 128)); + masm.subsd(temp7, temp4); + masm.mulsd(temp7, temp6); + masm.movdqu(temp4, temp3); + masm.subsd(temp3, temp2); + masm.addsd(temp2, temp3); + masm.subsd(temp4, temp2); + masm.addsd(dest, temp4); + masm.subsd(dest, temp7); + masm.addsd(dest, temp3); + masm.jmp(bb15); + + masm.bind(bb0); + masm.jcc(ConditionFlag.Greater, bb1); + + masm.pextrw(gpr1, dest, 3); + masm.movl(gpr4, gpr1); + masm.andl(gpr1, 32752); + masm.jcc(ConditionFlag.Equal, bb2); + + masm.andl(gpr4, 32767); + masm.cmpl(gpr4, 15904); + masm.jcc(ConditionFlag.Below, bb3); + + masm.movdqu(temp2, dest); + masm.movdqu(temp3, dest); + masm.movdq(temp1, externalAddress(qElevenTanPtr)); // 0xb8fe4d77, + // 0x3f82609a + masm.mulsd(temp2, dest); + masm.mulsd(temp3, temp2); + masm.mulsd(temp1, temp2); + masm.addsd(temp1, externalAddress(qNineTanPtr)); // 0xbf847a43, + // 0x3f9664a0 + masm.mulsd(temp1, temp2); + masm.addsd(temp1, externalAddress(qSevenTanPtr)); // 0x52c4c8ab, + // 0x3faba1ba + masm.mulsd(temp1, temp2); + masm.addsd(temp1, externalAddress(qFiveTanPtr)); // 0x11092746, + // 0x3fc11111 + masm.mulsd(temp1, temp2); + masm.addsd(temp1, externalAddress(qThreeTanPtr)); // 0x55555612, + // 0x3fd55555 + masm.mulsd(temp1, temp3); + masm.addsd(dest, temp1); + masm.jmp(bb15); + + masm.bind(bb3); + masm.movdq(temp3, externalAddress(twoPowFiftyFiveTanPtr)); // 0x00000000, + // 0x43600000 + masm.mulsd(temp3, dest); + masm.addsd(dest, temp3); + masm.mulsd(dest, externalAddress(twoPowMFiftyFiveTanPtr)); // 0x00000000, + // 0x3c800000 + masm.jmp(bb15); + + masm.bind(bb14); + masm.xorpd(temp1, temp1); + masm.xorpd(dest, dest); + masm.divsd(dest, temp1); + masm.jmp(bb15); + + masm.bind(bb2); + masm.movdqu(temp1, dest); + masm.mulsd(temp1, temp1); + masm.jmp(bb15); + + masm.bind(bb1); + masm.pextrw(gpr3, dest, 3); + masm.andl(gpr3, 32752); + masm.cmpl(gpr3, 32752); + masm.jcc(ConditionFlag.Equal, bb14); + + masm.subl(gpr3, 16224); + masm.shrl(gpr3, 7); + masm.andl(gpr3, 65532); + masm.leaq(gpr10, externalAddress(piInvTableTanPtr)); + masm.addq(gpr3, gpr10); + masm.movdq(gpr1, dest); + masm.movl(gpr9, new AMD64Address(gpr3, 20)); + masm.movl(gpr7, new AMD64Address(gpr3, 24)); + masm.movl(gpr4, gpr1); + masm.shrq(gpr1, 21); + masm.orl(gpr1, Integer.MIN_VALUE); + masm.shrl(gpr1, 11); + masm.movl(gpr8, gpr9); + masm.imulq(gpr9, gpr4); + masm.imulq(gpr8, gpr1); + masm.imulq(gpr7, gpr1); + masm.movl(gpr5, new AMD64Address(gpr3, 16)); + masm.movl(gpr6, new AMD64Address(gpr3, 12)); + masm.movl(gpr10, gpr9); + masm.shrq(gpr9, 32); + masm.addq(gpr8, gpr9); + masm.addq(gpr10, gpr7); + masm.movl(gpr7, gpr10); + masm.shrq(gpr10, 32); + masm.addq(gpr8, gpr10); + masm.movl(gpr9, gpr5); + masm.imulq(gpr5, gpr4); + masm.imulq(gpr9, gpr1); + masm.movl(gpr10, gpr6); + masm.imulq(gpr6, gpr4); + masm.movl(gpr2, gpr5); + masm.shrq(gpr5, 32); + masm.addq(gpr8, gpr2); + masm.movl(gpr2, gpr8); + masm.shrq(gpr8, 32); + masm.addq(gpr9, gpr5); + masm.addq(gpr9, gpr8); + masm.shlq(gpr2, 32); + masm.orq(gpr7, gpr2); + masm.imulq(gpr10, gpr1); + masm.movl(gpr8, new AMD64Address(gpr3, 8)); + masm.movl(gpr5, new AMD64Address(gpr3, 4)); + masm.movl(gpr2, gpr6); + masm.shrq(gpr6, 32); + masm.addq(gpr9, gpr2); + masm.movl(gpr2, gpr9); + masm.shrq(gpr9, 32); + masm.addq(gpr10, gpr6); + masm.addq(gpr10, gpr9); + masm.movq(gpr6, gpr8); + masm.imulq(gpr8, gpr4); + masm.imulq(gpr6, gpr1); + masm.movl(gpr9, gpr8); + masm.shrq(gpr8, 32); + masm.addq(gpr10, gpr9); + masm.movl(gpr9, gpr10); + masm.shrq(gpr10, 32); + masm.addq(gpr6, gpr8); + masm.addq(gpr6, gpr10); + masm.movq(gpr8, gpr5); + masm.imulq(gpr5, gpr4); + masm.imulq(gpr8, gpr1); + masm.shlq(gpr9, 32); + masm.orq(gpr9, gpr2); + masm.movl(gpr1, new AMD64Address(gpr3, 0)); + masm.movl(gpr10, gpr5); + masm.shrq(gpr5, 32); + masm.addq(gpr6, gpr10); + masm.movl(gpr10, gpr6); + masm.shrq(gpr6, 32); + masm.addq(gpr8, gpr5); + masm.addq(gpr8, gpr6); + masm.imulq(gpr4, gpr1); + masm.pextrw(gpr2, dest, 3); + masm.leaq(gpr6, externalAddress(piInvTableTanPtr)); + masm.subq(gpr3, gpr6); + masm.addl(gpr3, gpr3); + masm.addl(gpr3, gpr3); + masm.addl(gpr3, gpr3); + masm.addl(gpr3, 19); + masm.movl(gpr5, 32768); + masm.andl(gpr5, gpr2); + masm.shrl(gpr2, 4); + masm.andl(gpr2, 2047); + masm.subl(gpr2, 1023); + masm.subl(gpr3, gpr2); + masm.addq(gpr8, gpr4); + masm.movl(gpr4, gpr3); + masm.addl(gpr4, 32); + masm.cmpl(gpr3, 0); + masm.jcc(ConditionFlag.Less, bb5); + + masm.negl(gpr3); + masm.addl(gpr3, 29); + masm.shll(gpr8); + masm.movl(gpr6, gpr8); + masm.andl(gpr8, 1073741823); + masm.testl(gpr8, 536870912); + masm.jcc(ConditionFlag.NotEqual, bb6); + + masm.shrl(gpr8); + masm.movl(gpr2, 0); + masm.shlq(gpr8, 32); + masm.orq(gpr8, gpr10); + + masm.bind(bb8); + masm.cmpq(gpr8, 0); + masm.jcc(ConditionFlag.Equal, bb9); + + masm.bind(bb10); + masm.bsrq(gpr10, gpr8); + masm.movl(gpr3, 29); + masm.subl(gpr3, gpr10); + masm.jcc(ConditionFlag.LessEqual, bb11); + + masm.shlq(gpr8); + masm.movq(gpr1, gpr9); + masm.shlq(gpr9); + masm.addl(gpr4, gpr3); + masm.negl(gpr3); + masm.addl(gpr3, 64); + masm.shrq(gpr1); + masm.shrq(gpr7); + masm.orq(gpr8, gpr1); + masm.orq(gpr9, gpr7); + + masm.bind(bb12); + masm.cvtsi2sdq(dest, gpr8); + masm.shrq(gpr9, 1); + masm.cvtsi2sdq(temp3, gpr9); + masm.xorpd(temp4, temp4); + masm.shll(gpr4, 4); + masm.negl(gpr4); + masm.addl(gpr4, 16368); + masm.orl(gpr4, gpr5); + masm.xorl(gpr4, gpr2); + masm.pinsrw(temp4, gpr4, 3); + masm.leaq(gpr1, externalAddress(piFourTanPtr)); + masm.movdq(temp2, new AMD64Address(gpr1, 0)); // 0x00000000, + // 0x3fe921fb, + masm.movdq(temp7, new AMD64Address(gpr1, 8)); // 0x4611a626, + // 0x3e85110b + masm.xorpd(temp5, temp5); + masm.subl(gpr4, 1008); + masm.pinsrw(temp5, gpr4, 3); + masm.mulsd(dest, temp4); + masm.shll(gpr5, 16); + masm.sarl(gpr5, 31); + masm.mulsd(temp3, temp5); + masm.movdqu(temp1, dest); + masm.mulsd(dest, temp2); + masm.shrl(gpr6, 30); + masm.addsd(temp1, temp3); + masm.mulsd(temp3, temp2); + masm.addl(gpr6, gpr5); + masm.xorl(gpr6, gpr5); + masm.mulsd(temp7, temp1); + masm.movl(gpr1, gpr6); + masm.addsd(temp7, temp3); + masm.movdqu(temp2, dest); + masm.addsd(dest, temp7); + masm.subsd(temp2, dest); + masm.addsd(temp7, temp2); + masm.movdqu(temp1, externalAddress(piThirtyTwoInvTanPtr)); // 0x6dc9c883, + // 0x3fe45f30, + // 0x6dc9c883, + // 0x40245f30 + if (masm.supports(CPUFeature.SSE3)) { + masm.movddup(dest, dest); + } else { + masm.movlhps(dest, dest); + } + masm.movdqu(temp4, externalAddress(signMaskTanPtr)); // 0x00000000, + // 0x80000000, + // 0x00000000, + // 0x80000000 + masm.andpd(temp4, dest); + masm.mulpd(temp1, dest); + if (masm.supports(CPUFeature.SSE3)) { + masm.movddup(temp7, temp7); + } else { + masm.movlhps(temp7, temp7); + } + masm.movdqu(temp5, externalAddress(oneHalfTanPtr)); // 0x00000000, + // 0x3fe00000, + // 0x00000000, + // 0x3fe00000 + masm.movdqu(temp6, externalAddress(mulSixteenPtr)); // 0x00000000, + // 0x40300000, + // 0x00000000, + // 0x3ff00000 + masm.por(temp5, temp4); + masm.addpd(temp1, temp5); + masm.movdqu(temp5, temp1); + masm.unpckhpd(temp5, temp5); + masm.cvttsd2sil(gpr4, temp5); + masm.cvttpd2dq(temp1, temp1); + masm.cvtdq2pd(temp1, temp1); + masm.mulpd(temp1, temp6); + masm.movdqu(temp3, externalAddress(pOneTanPtr)); // 0x54444000, + // 0x3fb921fb, + // 0x54440000, + // 0x3fb921fb + masm.movdq(temp5, externalAddress(qqTwoTanPtr)); // 0x676733af, + // 0x3d32e7b9 + masm.shll(gpr1, 4); + masm.addl(gpr4, 469248); + masm.movdqu(temp4, externalAddress(pTwoTanPtr)); // 0x67674000, + // 0xbd32e7b9, + // 0x4c4c0000, + // 0x3d468c23 + masm.mulpd(temp3, temp1); + masm.addl(gpr4, gpr1); + masm.andl(gpr4, 31); + masm.mulsd(temp5, temp1); + masm.movl(gpr3, gpr4); + masm.mulpd(temp4, temp1); + masm.shll(gpr3, 1); + masm.subpd(dest, temp3); + masm.mulpd(temp1, externalAddress(pThreeTanPtr)); // 0x3707344a, + // 0x3aa8a2e0, + // 0x03707345, + // 0x3ae98a2e + masm.addl(gpr4, gpr3); + masm.shll(gpr3, 2); + masm.addl(gpr4, gpr3); + masm.addsd(temp5, dest); + masm.movdqu(temp2, dest); + masm.subpd(dest, temp4); + masm.movdq(temp6, externalAddress(onePtr)); // 0x00000000, + // 0x3ff00000 + masm.shll(gpr4, 4); + masm.leaq(gpr1, externalAddress(cTableTanPtr)); + masm.andpd(temp5, externalAddress(maskThirtyFiveTanPtr)); // 0xfffc0000, + // 0xffffffff, + // 0x00000000, + // 0x00000000 + masm.movdqu(temp3, dest); + masm.addq(gpr1, gpr4); + masm.subpd(temp2, dest); + masm.unpckhpd(dest, dest); + masm.divsd(temp6, temp5); + masm.subpd(temp2, temp4); + masm.subsd(temp3, temp5); + masm.subpd(temp2, temp1); + masm.movdqu(temp1, new AMD64Address(gpr1, 48)); + masm.addpd(temp2, temp7); + masm.movdqu(temp7, new AMD64Address(gpr1, 16)); + masm.mulpd(temp7, dest); + masm.movdqu(temp4, new AMD64Address(gpr1, 96)); + masm.mulpd(temp1, dest); + masm.mulpd(temp4, dest); + masm.addsd(temp2, temp3); + masm.movdqu(temp3, dest); + masm.mulpd(dest, dest); + masm.addpd(temp7, new AMD64Address(gpr1, 0)); + masm.addpd(temp1, new AMD64Address(gpr1, 32)); + masm.mulpd(temp1, dest); + masm.addpd(temp4, new AMD64Address(gpr1, 80)); + masm.addpd(temp7, temp1); + masm.movdqu(temp1, new AMD64Address(gpr1, 112)); + masm.mulpd(temp1, dest); + masm.mulpd(dest, dest); + masm.addpd(temp4, temp1); + masm.movdqu(temp1, new AMD64Address(gpr1, 64)); + masm.mulpd(temp1, dest); + masm.addpd(temp7, temp1); + masm.movdqu(temp1, temp3); + masm.mulpd(temp3, dest); + masm.mulsd(dest, dest); + masm.mulpd(temp1, new AMD64Address(gpr1, 144)); + masm.mulpd(temp4, temp3); + masm.movdqu(temp3, temp1); + masm.addpd(temp7, temp4); + masm.movdqu(temp4, temp1); + masm.mulsd(dest, temp7); + masm.unpckhpd(temp7, temp7); + masm.addsd(dest, temp7); + masm.unpckhpd(temp1, temp1); + masm.addsd(temp3, temp1); + masm.subsd(temp4, temp3); + masm.addsd(temp1, temp4); + masm.movdqu(temp4, temp2); + masm.movdq(temp7, new AMD64Address(gpr1, 144)); + masm.unpckhpd(temp2, temp2); + masm.addsd(temp7, new AMD64Address(gpr1, 152)); + masm.mulsd(temp7, temp2); + masm.addsd(temp7, new AMD64Address(gpr1, 136)); + masm.addsd(temp7, temp1); + masm.addsd(dest, temp7); + masm.movdq(temp7, externalAddress(onePtr)); // 0x00000000, + // 0x3ff00000 + masm.mulsd(temp4, temp6); + masm.movdq(temp2, new AMD64Address(gpr1, 168)); + masm.andpd(temp2, temp6); + masm.mulsd(temp5, temp2); + masm.mulsd(temp6, new AMD64Address(gpr1, 160)); + masm.subsd(temp7, temp5); + masm.subsd(temp2, new AMD64Address(gpr1, 128)); + masm.subsd(temp7, temp4); + masm.mulsd(temp7, temp6); + masm.movdqu(temp4, temp3); + masm.subsd(temp3, temp2); + masm.addsd(temp2, temp3); + masm.subsd(temp4, temp2); + masm.addsd(dest, temp4); + masm.subsd(dest, temp7); + masm.addsd(dest, temp3); + masm.jmp(bb15); + + masm.bind(bb9); + masm.addl(gpr4, 64); + masm.movq(gpr8, gpr9); + masm.movq(gpr9, gpr7); + masm.movl(gpr7, 0); + masm.cmpq(gpr8, 0); + masm.jcc(ConditionFlag.NotEqual, bb10); + + masm.addl(gpr4, 64); + masm.movq(gpr8, gpr9); + masm.movq(gpr9, gpr7); + masm.cmpq(gpr8, 0); + masm.jcc(ConditionFlag.NotEqual, bb10); + + masm.jmp(bb12); + + masm.bind(bb11); + masm.jcc(ConditionFlag.Equal, bb12); + + masm.negl(gpr3); + masm.shrq(gpr9); + masm.movq(gpr1, gpr8); + masm.shrq(gpr8); + masm.subl(gpr4, gpr3); + masm.negl(gpr3); + masm.addl(gpr3, 64); + masm.shlq(gpr1); + masm.orq(gpr9, gpr1); + masm.jmp(bb12); + + masm.bind(bb5); + masm.notl(gpr3); + masm.shlq(gpr8, 32); + masm.orq(gpr8, gpr10); + masm.shlq(gpr8); + masm.movq(gpr6, gpr8); + masm.testl(gpr8, Integer.MIN_VALUE); + masm.jcc(ConditionFlag.NotEqual, bb13); + + masm.shrl(gpr8); + masm.movl(gpr2, 0); + masm.shrq(gpr6, 2); + masm.jmp(bb8); + + masm.bind(bb6); + masm.shrl(gpr8); + masm.movl(gpr2, 1073741824); + masm.shrl(gpr2); + masm.shlq(gpr8, 32); + masm.orq(gpr8, gpr10); + masm.shlq(gpr2, 32); + masm.addl(gpr6, 1073741824); + masm.movl(gpr3, 0); + masm.movl(gpr10, 0); + masm.subq(gpr3, gpr7); + masm.sbbq(gpr10, gpr9); + masm.sbbq(gpr2, gpr8); + masm.movq(gpr7, gpr3); + masm.movq(gpr9, gpr10); + masm.movq(gpr8, gpr2); + masm.movl(gpr2, 32768); + masm.jmp(bb8); + + masm.bind(bb13); + masm.shrl(gpr8); + masm.movq(gpr2, 0x100000000L); + masm.shrq(gpr2); + masm.movl(gpr3, 0); + masm.movl(gpr10, 0); + masm.subq(gpr3, gpr7); + masm.sbbq(gpr10, gpr9); + masm.sbbq(gpr2, gpr8); + masm.movq(gpr7, gpr3); + masm.movq(gpr9, gpr10); + masm.movq(gpr8, gpr2); + masm.movl(gpr2, 32768); + masm.shrq(gpr6, 2); + masm.addl(gpr6, 1073741824); + masm.jmp(bb8); + + masm.bind(bb15); + } + + /* + * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM) + * Source Code + * + * ALGORITHM DESCRIPTION - EXP() --------------------- + * + * Description: Let K = 64 (table size). x x/log(2) n e = 2 = 2 * T[j] * (1 + P(y)) where x = + * m*log(2)/K + y, y in [-log(2)/K..log(2)/K] m = n*K + j, m,n,j - signed integer, j in + * [-K/2..K/2] j/K values of 2 are tabulated as T[j] = T_hi[j] ( 1 + T_lo[j]). + * + * P(y) is a minimax polynomial approximation of exp(x)-1 on small interval + * [-log(2)/K..log(2)/K] (were calculated by Maple V). + * + * To avoid problems with arithmetic overflow and underflow, n n1 n2 value of 2 is safely + * computed as 2 * 2 where n1 in [-BIAS/2..BIAS/2] where BIAS is a value of exponent bias. + * + * Special cases: exp(NaN) = NaN exp(+INF) = +INF exp(-INF) = 0 exp(x) = 1 for subnormals for + * finite argument, only exp(0)=1 is exact For IEEE double if x > 709.782712893383973096 then + * exp(x) overflow if x < -745.133219101941108420 then exp(x) underflow + * + */ + + private static int[] cvExp = { + 0x652b82fe, 0x40571547, 0x652b82fe, 0x40571547, 0xfefa0000, + 0x3f862e42, 0xfefa0000, 0x3f862e42, 0xbc9e3b3a, 0x3d1cf79a, + 0xbc9e3b3a, 0x3d1cf79a, 0xfffffffe, 0x3fdfffff, 0xfffffffe, + 0x3fdfffff, 0xe3289860, 0x3f56c15c, 0x555b9e25, 0x3fa55555, + 0xc090cf0f, 0x3f811115, 0x55548ba1, 0x3fc55555 + }; + + private static int[] shifterExp = { + 0x00000000, 0x43380000, 0x00000000, 0x43380000 + }; + + private static int[] mMaskExp = { + 0xffffffc0, 0x00000000, 0xffffffc0, 0x00000000 + }; + + private static int[] biasExp = { + 0x0000ffc0, 0x00000000, 0x0000ffc0, 0x00000000 + }; + + private static int[] tblAddrExp = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0e03754d, + 0x3cad7bbf, 0x3e778060, 0x00002c9a, 0x3567f613, 0x3c8cd252, + 0xd3158574, 0x000059b0, 0x61e6c861, 0x3c60f74e, 0x18759bc8, + 0x00008745, 0x5d837b6c, 0x3c979aa6, 0x6cf9890f, 0x0000b558, + 0x702f9cd1, 0x3c3ebe3d, 0x32d3d1a2, 0x0000e3ec, 0x1e63bcd8, + 0x3ca3516e, 0xd0125b50, 0x00011301, 0x26f0387b, 0x3ca4c554, + 0xaea92ddf, 0x0001429a, 0x62523fb6, 0x3ca95153, 0x3c7d517a, + 0x000172b8, 0x3f1353bf, 0x3c8b898c, 0xeb6fcb75, 0x0001a35b, + 0x3e3a2f5f, 0x3c9aecf7, 0x3168b9aa, 0x0001d487, 0x44a6c38d, + 0x3c8a6f41, 0x88628cd6, 0x0002063b, 0xe3a8a894, 0x3c968efd, + 0x6e756238, 0x0002387a, 0x981fe7f2, 0x3c80472b, 0x65e27cdd, + 0x00026b45, 0x6d09ab31, 0x3c82f7e1, 0xf51fdee1, 0x00029e9d, + 0x720c0ab3, 0x3c8b3782, 0xa6e4030b, 0x0002d285, 0x4db0abb6, + 0x3c834d75, 0x0a31b715, 0x000306fe, 0x5dd3f84a, 0x3c8fdd39, + 0xb26416ff, 0x00033c08, 0xcc187d29, 0x3ca12f8c, 0x373aa9ca, + 0x000371a7, 0x738b5e8b, 0x3ca7d229, 0x34e59ff6, 0x0003a7db, + 0xa72a4c6d, 0x3c859f48, 0x4c123422, 0x0003dea6, 0x259d9205, + 0x3ca8b846, 0x21f72e29, 0x0004160a, 0x60c2ac12, 0x3c4363ed, + 0x6061892d, 0x00044e08, 0xdaa10379, 0x3c6ecce1, 0xb5c13cd0, + 0x000486a2, 0xbb7aafb0, 0x3c7690ce, 0xd5362a27, 0x0004bfda, + 0x9b282a09, 0x3ca083cc, 0x769d2ca6, 0x0004f9b2, 0xc1aae707, + 0x3ca509b0, 0x569d4f81, 0x0005342b, 0x18fdd78e, 0x3c933505, + 0x36b527da, 0x00056f47, 0xe21c5409, 0x3c9063e1, 0xdd485429, + 0x0005ab07, 0x2b64c035, 0x3c9432e6, 0x15ad2148, 0x0005e76f, + 0x99f08c0a, 0x3ca01284, 0xb03a5584, 0x0006247e, 0x0073dc06, + 0x3c99f087, 0x82552224, 0x00066238, 0x0da05571, 0x3c998d4d, + 0x667f3bcc, 0x0006a09e, 0x86ce4786, 0x3ca52bb9, 0x3c651a2e, + 0x0006dfb2, 0x206f0dab, 0x3ca32092, 0xe8ec5f73, 0x00071f75, + 0x8e17a7a6, 0x3ca06122, 0x564267c8, 0x00075feb, 0x461e9f86, + 0x3ca244ac, 0x73eb0186, 0x0007a114, 0xabd66c55, 0x3c65ebe1, + 0x36cf4e62, 0x0007e2f3, 0xbbff67d0, 0x3c96fe9f, 0x994cce12, + 0x00082589, 0x14c801df, 0x3c951f14, 0x9b4492ec, 0x000868d9, + 0xc1f0eab4, 0x3c8db72f, 0x422aa0db, 0x0008ace5, 0x59f35f44, + 0x3c7bf683, 0x99157736, 0x0008f1ae, 0x9c06283c, 0x3ca360ba, + 0xb0cdc5e4, 0x00093737, 0x20f962aa, 0x3c95e8d1, 0x9fde4e4f, + 0x00097d82, 0x2b91ce27, 0x3c71affc, 0x82a3f090, 0x0009c491, + 0x589a2ebd, 0x3c9b6d34, 0x7b5de564, 0x000a0c66, 0x9ab89880, + 0x3c95277c, 0xb23e255c, 0x000a5503, 0x6e735ab3, 0x3c846984, + 0x5579fdbf, 0x000a9e6b, 0x92cb3387, 0x3c8c1a77, 0x995ad3ad, + 0x000ae89f, 0xdc2d1d96, 0x3ca22466, 0xb84f15fa, 0x000b33a2, + 0xb19505ae, 0x3ca1112e, 0xf2fb5e46, 0x000b7f76, 0x0a5fddcd, + 0x3c74ffd7, 0x904bc1d2, 0x000bcc1e, 0x30af0cb3, 0x3c736eae, + 0xdd85529c, 0x000c199b, 0xd10959ac, 0x3c84e08f, 0x2e57d14b, + 0x000c67f1, 0x6c921968, 0x3c676b2c, 0xdcef9069, 0x000cb720, + 0x36df99b3, 0x3c937009, 0x4a07897b, 0x000d072d, 0xa63d07a7, + 0x3c74a385, 0xdcfba487, 0x000d5818, 0xd5c192ac, 0x3c8e5a50, + 0x03db3285, 0x000da9e6, 0x1c4a9792, 0x3c98bb73, 0x337b9b5e, + 0x000dfc97, 0x603a88d3, 0x3c74b604, 0xe78b3ff6, 0x000e502e, + 0x92094926, 0x3c916f27, 0xa2a490d9, 0x000ea4af, 0x41aa2008, + 0x3c8ec3bc, 0xee615a27, 0x000efa1b, 0x31d185ee, 0x3c8a64a9, + 0x5b6e4540, 0x000f5076, 0x4d91cd9d, 0x3c77893b, 0x819e90d8, + 0x000fa7c1 + }; + + private static int[] allOnesExp = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }; + + private static int[] expBias = { + 0x00000000, 0x3ff00000, 0x00000000, 0x3ff00000 + }; + + private static int[] xMaxExp = { + 0xffffffff, 0x7fefffff + }; + + private static int[] xMinExp = { + 0x00000000, 0x00100000 + }; + + private static int[] infExp = { + 0x00000000, 0x7ff00000 + }; + + private static int[] zeroExp = { + 0x00000000, 0x00000000 + }; + + public void expIntrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) { + ArrayDataPointerConstant onePtr = new ArrayDataPointerConstant(one, 16); + ArrayDataPointerConstant cvExpPtr = new ArrayDataPointerConstant(cvExp, 16); + ArrayDataPointerConstant shifterExpPtr = new ArrayDataPointerConstant(shifterExp, 8); + ArrayDataPointerConstant mMaskExpPtr = new ArrayDataPointerConstant(mMaskExp, 16); + ArrayDataPointerConstant biasExpPtr = new ArrayDataPointerConstant(biasExp, 16); + ArrayDataPointerConstant tblAddrExpPtr = new ArrayDataPointerConstant(tblAddrExp, 16); + ArrayDataPointerConstant expBiasPtr = new ArrayDataPointerConstant(expBias, 8); + ArrayDataPointerConstant xMaxExpPtr = new ArrayDataPointerConstant(xMaxExp, 8); + ArrayDataPointerConstant xMinExpPtr = new ArrayDataPointerConstant(xMinExp, 8); + ArrayDataPointerConstant infExpPtr = new ArrayDataPointerConstant(infExp, 8); + ArrayDataPointerConstant zeroExpPtr = new ArrayDataPointerConstant(zeroExp, 8); + ArrayDataPointerConstant allOnesExpPtr = new ArrayDataPointerConstant(allOnesExp, 8); + + Label bb0 = new Label(); + Label bb1 = new Label(); + Label bb2 = new Label(); + Label bb3 = new Label(); + Label bb4 = new Label(); + Label bb5 = new Label(); + Label bb7 = new Label(); + Label bb8 = new Label(); + Label bb9 = new Label(); + Label bb10 = new Label(); + Label bb11 = new Label(); + Label bb12 = new Label(); + Label bb14 = new Label(); + + Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD); + Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD); + Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD); + Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD); + Register gpr5 = asRegister(gpr5Temp, AMD64Kind.QWORD); + + Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE); + Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE); + Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE); + Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE); + Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE); + Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE); + Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE); + Register temp8 = asRegister(xmm8Temp, AMD64Kind.DOUBLE); + Register temp9 = asRegister(xmm9Temp, AMD64Kind.DOUBLE); + Register temp10 = asRegister(xmm10Temp, AMD64Kind.DOUBLE); + + AMD64Address stackSlot = (AMD64Address) crb.asAddress(stackTemp); + + setCrb(crb); + masm.movsd(stackSlot, value); + if (dest.encoding != value.encoding) { + masm.movdqu(dest, value); + } + + masm.movdqu(temp9, externalAddress(mMaskExpPtr)); // 0xffffffc0, + // 0x00000000, + // 0xffffffc0, + // 0x00000000 + masm.movdqu(temp10, externalAddress(biasExpPtr)); // 0x0000ffc0, + // 0x00000000, + // 0x0000ffc0, + // 0x00000000 + masm.unpcklpd(dest, dest); + masm.leaq(gpr5, stackSlot); + masm.leaq(gpr2, externalAddress(cvExpPtr)); + masm.movdqu(temp1, new AMD64Address(gpr2, 0)); // 0x652b82fe, + // 0x40571547, + // 0x652b82fe, + // 0x40571547 + masm.movdqu(temp6, externalAddress(shifterExpPtr)); // 0x00000000, + // 0x43380000, + // 0x00000000, + // 0x43380000 + masm.movdqu(temp2, new AMD64Address(gpr2, 16)); // 0xfefa0000, + // 0x3f862e42, + // 0xfefa0000, + // 0x3f862e42 + masm.movdqu(temp3, new AMD64Address(gpr2, 32)); // 0xbc9e3b3a, + // 0x3d1cf79a, + // 0xbc9e3b3a, + // 0x3d1cf79a + masm.pextrw(gpr1, dest, 3); + masm.andl(gpr1, 32767); + masm.movl(gpr4, 16527); + masm.subl(gpr4, gpr1); + masm.subl(gpr1, 15504); + masm.orl(gpr4, gpr1); + masm.cmpl(gpr4, Integer.MIN_VALUE); + masm.jcc(ConditionFlag.AboveEqual, bb0); + + masm.leaq(gpr4, externalAddress(tblAddrExpPtr)); + masm.movdqu(temp8, new AMD64Address(gpr2, 48)); // 0xfffffffe, + // 0x3fdfffff, + // 0xfffffffe, + // 0x3fdfffff + masm.movdqu(temp4, new AMD64Address(gpr2, 64)); // 0xe3289860, + // 0x3f56c15c, + // 0x555b9e25, + // 0x3fa55555 + masm.movdqu(temp5, new AMD64Address(gpr2, 80)); // 0xc090cf0f, + // 0x3f811115, + // 0x55548ba1, + // 0x3fc55555 + masm.mulpd(temp1, dest); + masm.addpd(temp1, temp6); + masm.movapd(temp7, temp1); + masm.movdl(gpr1, temp1); + masm.pand(temp7, temp9); + masm.subpd(temp1, temp6); + masm.mulpd(temp2, temp1); + masm.mulpd(temp3, temp1); + masm.paddq(temp7, temp10); + masm.subpd(dest, temp2); + masm.movl(gpr3, gpr1); + masm.andl(gpr3, 63); + masm.shll(gpr3, 4); + masm.movdqu(temp2, new AMD64Address(gpr3, gpr4, Scale.Times1, 0)); + masm.sarl(gpr1, 6); + masm.psllq(temp7, 46); + masm.subpd(dest, temp3); + masm.mulpd(temp4, dest); + masm.movl(gpr4, gpr1); + masm.movapd(temp6, dest); + masm.movapd(temp1, dest); + masm.mulpd(temp6, temp6); + masm.mulpd(dest, temp6); + masm.addpd(temp5, temp4); + masm.mulsd(dest, temp6); + masm.mulpd(temp6, temp8); + masm.addsd(temp1, temp2); + masm.unpckhpd(temp2, temp2); + masm.mulpd(dest, temp5); + masm.addsd(temp1, dest); + masm.por(temp2, temp7); + masm.unpckhpd(dest, dest); + masm.addsd(dest, temp1); + masm.addsd(dest, temp6); + masm.addl(gpr4, 894); + masm.cmpl(gpr4, 1916); + masm.jcc(ConditionFlag.Above, bb1); + + masm.mulsd(dest, temp2); + masm.addsd(dest, temp2); + masm.jmp(bb14); + + masm.bind(bb1); + masm.movdqu(temp6, externalAddress(expBiasPtr)); // 0x00000000, + // 0x3ff00000, + // 0x00000000, + // 0x3ff00000 + masm.xorpd(temp3, temp3); + masm.movdqu(temp4, externalAddress(allOnesExpPtr)); // 0xffffffff, + // 0xffffffff, + // 0xffffffff, + // 0xffffffff + masm.movl(gpr4, -1022); + masm.subl(gpr4, gpr1); + masm.movdl(temp5, gpr4); + masm.psllq(temp4, temp5); + masm.movl(gpr3, gpr1); + masm.sarl(gpr1, 1); + masm.pinsrw(temp3, gpr1, 3); + masm.psllq(temp3, 4); + masm.psubd(temp2, temp3); + masm.mulsd(dest, temp2); + masm.cmpl(gpr4, 52); + masm.jcc(ConditionFlag.Greater, bb2); + + masm.pand(temp4, temp2); + masm.paddd(temp3, temp6); + masm.subsd(temp2, temp4); + masm.addsd(dest, temp2); + masm.cmpl(gpr3, 1023); + masm.jcc(ConditionFlag.GreaterEqual, bb3); + + masm.pextrw(gpr3, dest, 3); + masm.andl(gpr3, 32768); + masm.orl(gpr4, gpr3); + masm.cmpl(gpr4, 0); + masm.jcc(ConditionFlag.Equal, bb4); + + masm.movapd(temp6, dest); + masm.addsd(dest, temp4); + masm.mulsd(dest, temp3); + masm.pextrw(gpr3, dest, 3); + masm.andl(gpr3, 32752); + masm.cmpl(gpr3, 0); + masm.jcc(ConditionFlag.Equal, bb5); + + masm.jmp(bb14); + + masm.bind(bb5); + masm.mulsd(temp6, temp3); + masm.mulsd(temp4, temp3); + masm.movdqu(dest, temp6); + masm.pxor(temp6, temp4); + masm.psrad(temp6, 31); + masm.pshufd(temp6, temp6, 85); + masm.psllq(dest, 1); + masm.psrlq(dest, 1); + masm.pxor(dest, temp6); + masm.psrlq(temp6, 63); + masm.paddq(dest, temp6); + masm.paddq(dest, temp4); + masm.jmp(bb14); + + masm.bind(bb4); + masm.addsd(dest, temp4); + masm.mulsd(dest, temp3); + masm.jmp(bb14); + + masm.bind(bb3); + masm.addsd(dest, temp4); + masm.mulsd(dest, temp3); + masm.pextrw(gpr3, dest, 3); + masm.andl(gpr3, 32752); + masm.cmpl(gpr3, 32752); + masm.jcc(ConditionFlag.AboveEqual, bb7); + + masm.jmp(bb14); + + masm.bind(bb2); + masm.paddd(temp3, temp6); + masm.addpd(dest, temp2); + masm.mulsd(dest, temp3); + masm.jmp(bb14); + + masm.bind(bb8); + masm.movsd(dest, externalAddress(xMaxExpPtr)); // 0xffffffff, + // 0x7fefffff + masm.movsd(temp8, externalAddress(xMinExpPtr)); // 0x00000000, + // 0x00100000 + masm.cmpl(gpr1, 2146435072); + masm.jcc(ConditionFlag.AboveEqual, bb9); + + masm.movl(gpr1, new AMD64Address(gpr5, 4)); + masm.cmpl(gpr1, Integer.MIN_VALUE); + masm.jcc(ConditionFlag.AboveEqual, bb10); + + masm.mulsd(dest, dest); + + masm.bind(bb7); + masm.jmp(bb14); + + masm.bind(bb10); + masm.mulsd(dest, temp8); + masm.jmp(bb14); + + masm.bind(bb9); + masm.movl(gpr4, stackSlot); + masm.cmpl(gpr1, 2146435072); + masm.jcc(ConditionFlag.Above, bb11); + + masm.cmpl(gpr4, 0); + masm.jcc(ConditionFlag.NotEqual, bb11); + + masm.movl(gpr1, new AMD64Address(gpr5, 4)); + masm.cmpl(gpr1, 2146435072); + masm.jcc(ConditionFlag.NotEqual, bb12); + + masm.movsd(dest, externalAddress(infExpPtr)); // 0x00000000, + // 0x7ff00000 + masm.jmp(bb14); + + masm.bind(bb12); + masm.movsd(dest, externalAddress(zeroExpPtr)); // 0x00000000, + // 0x00000000 + masm.jmp(bb14); + + masm.bind(bb11); + masm.movsd(dest, stackSlot); + masm.addsd(dest, dest); + masm.jmp(bb14); + + masm.bind(bb0); + masm.movl(gpr1, new AMD64Address(gpr5, 4)); + masm.andl(gpr1, 2147483647); + masm.cmpl(gpr1, 1083179008); + masm.jcc(ConditionFlag.AboveEqual, bb8); + + masm.addsd(dest, externalAddress(onePtr)); // 0x00000000, + // 0x3ff00000 + masm.bind(bb14); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java 2016-12-07 13:54:30.884692953 -0800 @@ -0,0 +1,721 @@ +/* + * Copyright (c) 2011, 2016, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED; +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static java.lang.Double.doubleToRawLongBits; +import static java.lang.Float.floatToRawIntBits; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.type.DataPointerConstant; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp.LoadConstantOp; +import org.graalvm.compiler.lir.StandardOp.NullCheck; +import org.graalvm.compiler.lir.StandardOp.ValueMoveOp; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.Value; + +public class AMD64Move { + + private abstract static class AbstractMoveOp extends AMD64LIRInstruction implements ValueMoveOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AbstractMoveOp.class); + + private AMD64Kind moveKind; + + protected AbstractMoveOp(LIRInstructionClass c, AMD64Kind moveKind) { + super(c); + this.moveKind = moveKind; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + move(moveKind, crb, masm, getResult(), getInput()); + } + } + + @Opcode("MOVE") + public static final class MoveToRegOp extends AbstractMoveOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MoveToRegOp.class); + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue input; + + public MoveToRegOp(AMD64Kind moveKind, AllocatableValue result, AllocatableValue input) { + super(TYPE, moveKind); + this.result = result; + this.input = input; + } + + @Override + public AllocatableValue getInput() { + return input; + } + + @Override + public AllocatableValue getResult() { + return result; + } + } + + @Opcode("MOVE") + public static final class MoveFromRegOp extends AbstractMoveOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MoveFromRegOp.class); + + @Def({REG, STACK}) protected AllocatableValue result; + @Use({REG, HINT}) protected AllocatableValue input; + + public MoveFromRegOp(AMD64Kind moveKind, AllocatableValue result, AllocatableValue input) { + super(TYPE, moveKind); + this.result = result; + this.input = input; + } + + @Override + public AllocatableValue getInput() { + return input; + } + + @Override + public AllocatableValue getResult() { + return result; + } + } + + @Opcode("MOVE") + public static class MoveFromConstOp extends AMD64LIRInstruction implements LoadConstantOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MoveFromConstOp.class); + + @Def({REG, STACK}) protected AllocatableValue result; + private final JavaConstant input; + + public MoveFromConstOp(AllocatableValue result, JavaConstant input) { + super(TYPE); + this.result = result; + this.input = input; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(result)) { + const2reg(crb, masm, asRegister(result), input); + } else { + assert isStackSlot(result); + const2stack(crb, masm, result, input); + } + } + + @Override + public Constant getConstant() { + return input; + } + + @Override + public AllocatableValue getResult() { + return result; + } + } + + @Opcode("STACKMOVE") + public static final class AMD64StackMove extends AMD64LIRInstruction implements ValueMoveOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64StackMove.class); + + @Def({STACK}) protected AllocatableValue result; + @Use({STACK, HINT}) protected AllocatableValue input; + @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private AllocatableValue backupSlot; + + private Register scratch; + + public AMD64StackMove(AllocatableValue result, AllocatableValue input, Register scratch, AllocatableValue backupSlot) { + super(TYPE); + this.result = result; + this.input = input; + this.backupSlot = backupSlot; + this.scratch = scratch; + } + + @Override + public AllocatableValue getInput() { + return input; + } + + @Override + public AllocatableValue getResult() { + return result; + } + + public Register getScratchRegister() { + return scratch; + } + + public AllocatableValue getBackupSlot() { + return backupSlot; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Kind backupKind = (AMD64Kind) backupSlot.getPlatformKind(); + if (backupKind.isXMM()) { + // graal doesn't use vector values, so it's safe to backup using DOUBLE + backupKind = AMD64Kind.DOUBLE; + } + + // backup scratch register + reg2stack(backupKind, crb, masm, backupSlot, scratch); + // move stack slot + stack2reg((AMD64Kind) getInput().getPlatformKind(), crb, masm, scratch, getInput()); + reg2stack((AMD64Kind) getResult().getPlatformKind(), crb, masm, getResult(), scratch); + // restore scratch register + stack2reg(backupKind, crb, masm, scratch, backupSlot); + } + } + + @Opcode("MULTISTACKMOVE") + public static final class AMD64MultiStackMove extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64MultiStackMove.class); + + @Def({STACK}) protected AllocatableValue[] results; + @Use({STACK}) protected Value[] inputs; + @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private AllocatableValue backupSlot; + + private Register scratch; + + public AMD64MultiStackMove(AllocatableValue[] results, Value[] inputs, Register scratch, AllocatableValue backupSlot) { + super(TYPE); + this.results = results; + this.inputs = inputs; + this.backupSlot = backupSlot; + this.scratch = scratch; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Kind backupKind = (AMD64Kind) backupSlot.getPlatformKind(); + if (backupKind.isXMM()) { + // graal doesn't use vector values, so it's safe to backup using DOUBLE + backupKind = AMD64Kind.DOUBLE; + } + + // backup scratch register + move(backupKind, crb, masm, backupSlot, scratch.asValue(backupSlot.getValueKind())); + for (int i = 0; i < results.length; i++) { + Value input = inputs[i]; + AllocatableValue result = results[i]; + // move stack slot + move((AMD64Kind) input.getPlatformKind(), crb, masm, scratch.asValue(input.getValueKind()), input); + move((AMD64Kind) result.getPlatformKind(), crb, masm, result, scratch.asValue(result.getValueKind())); + } + // restore scratch register + move(backupKind, crb, masm, scratch.asValue(backupSlot.getValueKind()), backupSlot); + } + } + + @Opcode("STACKMOVE") + public static final class AMD64PushPopStackMove extends AMD64LIRInstruction implements ValueMoveOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64PushPopStackMove.class); + + @Def({STACK}) protected AllocatableValue result; + @Use({STACK, HINT}) protected AllocatableValue input; + private final OperandSize size; + + public AMD64PushPopStackMove(OperandSize size, AllocatableValue result, AllocatableValue input) { + super(TYPE); + this.result = result; + this.input = input; + this.size = size; + } + + @Override + public AllocatableValue getInput() { + return input; + } + + @Override + public AllocatableValue getResult() { + return result; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64MOp.PUSH.emit(masm, size, (AMD64Address) crb.asAddress(input)); + AMD64MOp.POP.emit(masm, size, (AMD64Address) crb.asAddress(result)); + } + } + + public static final class LeaOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LeaOp.class); + + @Def({REG}) protected AllocatableValue result; + @Use({COMPOSITE, UNINITIALIZED}) protected AMD64AddressValue address; + + public LeaOp(AllocatableValue result, AMD64AddressValue address) { + super(TYPE); + this.result = result; + this.address = address; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + masm.leaq(asRegister(result, AMD64Kind.QWORD), address.toAddress()); + } + } + + public static final class LeaDataOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LeaDataOp.class); + + @Def({REG}) protected AllocatableValue result; + private final DataPointerConstant data; + + public LeaDataOp(AllocatableValue result, DataPointerConstant data) { + super(TYPE); + this.result = result; + this.data = data; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + masm.leaq(asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(data)); + } + } + + public static final class StackLeaOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StackLeaOp.class); + + @Def({REG}) protected AllocatableValue result; + @Use({STACK, UNINITIALIZED}) protected AllocatableValue slot; + + public StackLeaOp(AllocatableValue result, AllocatableValue slot) { + super(TYPE); + this.result = result; + this.slot = slot; + assert slot instanceof VirtualStackSlot || slot instanceof StackSlot; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + masm.leaq(asRegister(result, AMD64Kind.QWORD), (AMD64Address) crb.asAddress(slot)); + } + } + + public static final class MembarOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MembarOp.class); + + private final int barriers; + + public MembarOp(final int barriers) { + super(TYPE); + this.barriers = barriers; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + masm.membar(barriers); + } + } + + public static final class NullCheckOp extends AMD64LIRInstruction implements NullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(NullCheckOp.class); + + @Use({COMPOSITE}) protected AMD64AddressValue address; + @State protected LIRFrameState state; + + public NullCheckOp(AMD64AddressValue address, LIRFrameState state) { + super(TYPE); + this.address = address; + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + crb.recordImplicitException(masm.position(), state); + masm.nullCheck(address.toAddress()); + } + + @Override + public Value getCheckedValue() { + return address.base; + } + + @Override + public LIRFrameState getState() { + return state; + } + } + + @Opcode("CAS") + public static final class CompareAndSwapOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareAndSwapOp.class); + + private final AMD64Kind accessKind; + + @Def protected AllocatableValue result; + @Use({COMPOSITE}) protected AMD64AddressValue address; + @Use protected AllocatableValue cmpValue; + @Use protected AllocatableValue newValue; + + public CompareAndSwapOp(AMD64Kind accessKind, AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) { + super(TYPE); + this.accessKind = accessKind; + this.result = result; + this.address = address; + this.cmpValue = cmpValue; + this.newValue = newValue; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + assert asRegister(cmpValue).equals(AMD64.rax) && asRegister(result).equals(AMD64.rax); + + if (crb.target.isMP) { + masm.lock(); + } + switch (accessKind) { + case DWORD: + masm.cmpxchgl(asRegister(newValue), address.toAddress()); + break; + case QWORD: + masm.cmpxchgq(asRegister(newValue), address.toAddress()); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + } + + @Opcode("ATOMIC_READ_AND_ADD") + public static final class AtomicReadAndAddOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AtomicReadAndAddOp.class); + + private final AMD64Kind accessKind; + + @Def protected AllocatableValue result; + @Alive({COMPOSITE}) protected AMD64AddressValue address; + @Use protected AllocatableValue delta; + + public AtomicReadAndAddOp(AMD64Kind accessKind, AllocatableValue result, AMD64AddressValue address, AllocatableValue delta) { + super(TYPE); + this.accessKind = accessKind; + this.result = result; + this.address = address; + this.delta = delta; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + move(accessKind, crb, masm, result, delta); + if (crb.target.isMP) { + masm.lock(); + } + switch (accessKind) { + case DWORD: + masm.xaddl(address.toAddress(), asRegister(result)); + break; + case QWORD: + masm.xaddq(address.toAddress(), asRegister(result)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + } + + @Opcode("ATOMIC_READ_AND_WRITE") + public static final class AtomicReadAndWriteOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AtomicReadAndWriteOp.class); + + private final AMD64Kind accessKind; + + @Def protected AllocatableValue result; + @Alive({COMPOSITE}) protected AMD64AddressValue address; + @Use protected AllocatableValue newValue; + + public AtomicReadAndWriteOp(AMD64Kind accessKind, AllocatableValue result, AMD64AddressValue address, AllocatableValue newValue) { + super(TYPE); + this.accessKind = accessKind; + this.result = result; + this.address = address; + this.newValue = newValue; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + move(accessKind, crb, masm, result, newValue); + switch (accessKind) { + case DWORD: + masm.xchgl(asRegister(result), address.toAddress()); + break; + case QWORD: + masm.xchgq(asRegister(result), address.toAddress()); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + } + + public static void move(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, Value input) { + move((AMD64Kind) result.getPlatformKind(), crb, masm, result, input); + } + + public static void move(AMD64Kind moveKind, CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, Value input) { + if (isRegister(input)) { + if (isRegister(result)) { + reg2reg(moveKind, masm, result, input); + } else if (isStackSlot(result)) { + reg2stack(moveKind, crb, masm, result, asRegister(input)); + } else { + throw GraalError.shouldNotReachHere(); + } + } else if (isStackSlot(input)) { + if (isRegister(result)) { + stack2reg(moveKind, crb, masm, asRegister(result), input); + } else { + throw GraalError.shouldNotReachHere(); + } + } else if (isJavaConstant(input)) { + if (isRegister(result)) { + const2reg(crb, masm, asRegister(result), asJavaConstant(input)); + } else if (isStackSlot(result)) { + const2stack(crb, masm, result, asJavaConstant(input)); + } else { + throw GraalError.shouldNotReachHere(); + } + } else { + throw GraalError.shouldNotReachHere(); + } + } + + private static void reg2reg(AMD64Kind kind, AMD64MacroAssembler masm, Value result, Value input) { + if (asRegister(input).equals(asRegister(result))) { + return; + } + switch (kind) { + case BYTE: + case WORD: + case DWORD: + masm.movl(asRegister(result), asRegister(input)); + break; + case QWORD: + masm.movq(asRegister(result), asRegister(input)); + break; + case SINGLE: + masm.movflt(asRegister(result, AMD64Kind.SINGLE), asRegister(input, AMD64Kind.SINGLE)); + break; + case DOUBLE: + masm.movdbl(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE)); + break; + default: + throw GraalError.shouldNotReachHere("kind=" + kind); + } + } + + public static void reg2stack(AMD64Kind kind, CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, Register input) { + AMD64Address dest = (AMD64Address) crb.asAddress(result); + switch (kind) { + case BYTE: + masm.movb(dest, input); + break; + case WORD: + masm.movw(dest, input); + break; + case DWORD: + masm.movl(dest, input); + break; + case QWORD: + masm.movq(dest, input); + break; + case SINGLE: + masm.movflt(dest, input); + break; + case DOUBLE: + masm.movsd(dest, input); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + + public static void stack2reg(AMD64Kind kind, CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Value input) { + AMD64Address src = (AMD64Address) crb.asAddress(input); + switch (kind) { + case BYTE: + masm.movsbl(result, src); + break; + case WORD: + masm.movswl(result, src); + break; + case DWORD: + masm.movl(result, src); + break; + case QWORD: + masm.movq(result, src); + break; + case SINGLE: + masm.movflt(result, src); + break; + case DOUBLE: + masm.movdbl(result, src); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + + public static void const2reg(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, JavaConstant input) { + /* + * Note: we use the kind of the input operand (and not the kind of the result operand) + * because they don't match in all cases. For example, an object constant can be loaded to a + * long register when unsafe casts occurred (e.g., for a write barrier where arithmetic + * operations are then performed on the pointer). + */ + switch (input.getJavaKind().getStackKind()) { + case Int: + // Do not optimize with an XOR as this instruction may be between + // a CMP and a Jcc in which case the XOR will modify the condition + // flags and interfere with the Jcc. + masm.movl(result, input.asInt()); + + break; + case Long: + // Do not optimize with an XOR as this instruction may be between + // a CMP and a Jcc in which case the XOR will modify the condition + // flags and interfere with the Jcc. + if (input.asLong() == (int) input.asLong()) { + // Sign extended to long + masm.movslq(result, (int) input.asLong()); + } else if ((input.asLong() & 0xFFFFFFFFL) == input.asLong()) { + // Zero extended to long + masm.movl(result, (int) input.asLong()); + } else { + masm.movq(result, input.asLong()); + } + break; + case Float: + // This is *not* the same as 'constant == 0.0f' in the case where constant is -0.0f + if (Float.floatToRawIntBits(input.asFloat()) == Float.floatToRawIntBits(0.0f)) { + masm.xorps(result, result); + } else { + masm.movflt(result, (AMD64Address) crb.asFloatConstRef(input)); + } + break; + case Double: + // This is *not* the same as 'constant == 0.0d' in the case where constant is -0.0d + if (Double.doubleToRawLongBits(input.asDouble()) == Double.doubleToRawLongBits(0.0d)) { + masm.xorpd(result, result); + } else { + masm.movdbl(result, (AMD64Address) crb.asDoubleConstRef(input)); + } + break; + case Object: + // Do not optimize with an XOR as this instruction may be between + // a CMP and a Jcc in which case the XOR will modify the condition + // flags and interfere with the Jcc. + if (input.isNull()) { + masm.movq(result, 0x0L); + } else if (crb.target.inlineObjects) { + crb.recordInlineDataInCode(input); + masm.movq(result, 0xDEADDEADDEADDEADL); + } else { + masm.movq(result, (AMD64Address) crb.recordDataReferenceInCode(input, 0)); + } + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + + public static void const2stack(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, JavaConstant input) { + AMD64Address dest = (AMD64Address) crb.asAddress(result); + final long imm; + switch (input.getJavaKind().getStackKind()) { + case Int: + imm = input.asInt(); + break; + case Long: + imm = input.asLong(); + break; + case Float: + imm = floatToRawIntBits(input.asFloat()); + break; + case Double: + imm = doubleToRawLongBits(input.asDouble()); + break; + case Object: + if (input.isNull()) { + imm = 0; + } else { + throw GraalError.shouldNotReachHere("Non-null object constants must be in register"); + } + break; + default: + throw GraalError.shouldNotReachHere(); + } + + switch ((AMD64Kind) result.getPlatformKind()) { + case BYTE: + assert NumUtil.isByte(imm) : "Is not in byte range: " + imm; + AMD64MIOp.MOVB.emit(masm, OperandSize.BYTE, dest, (int) imm); + break; + case WORD: + assert NumUtil.isShort(imm) : "Is not in short range: " + imm; + AMD64MIOp.MOV.emit(masm, OperandSize.WORD, dest, (int) imm); + break; + case DWORD: + case SINGLE: + assert NumUtil.isInt(imm) : "Is not in int range: " + imm; + masm.movl(dest, (int) imm); + break; + case QWORD: + case DOUBLE: + masm.movlong(dest, imm); + break; + default: + throw GraalError.shouldNotReachHere("Unknown result Kind: " + result.getPlatformKind()); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MulDivOp.java 2016-12-07 13:54:31.148704556 -0800 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.DIV; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.IDIV; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.IMUL; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.MUL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isIllegal; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; + +/** + * AMD64 mul/div operation. This operation has a single operand for the second input. The first + * input must be in RAX for mul and in RDX:RAX for div. The result is in RDX:RAX. + */ +public class AMD64MulDivOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64MulDivOp.class); + + @Opcode private final AMD64MOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue highResult; + @Def({REG}) protected AllocatableValue lowResult; + + @Use({REG, ILLEGAL}) protected AllocatableValue highX; + @Use({REG}) protected AllocatableValue lowX; + + @Use({REG, STACK}) protected AllocatableValue y; + + @State protected LIRFrameState state; + + public AMD64MulDivOp(AMD64MOp opcode, OperandSize size, LIRKind resultKind, AllocatableValue x, AllocatableValue y) { + this(opcode, size, resultKind, Value.ILLEGAL, x, y, null); + } + + public AMD64MulDivOp(AMD64MOp opcode, OperandSize size, LIRKind resultKind, AllocatableValue highX, AllocatableValue lowX, AllocatableValue y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.highResult = AMD64.rdx.asValue(resultKind); + this.lowResult = AMD64.rax.asValue(resultKind); + + this.highX = highX; + this.lowX = lowX; + + this.y = y; + + this.state = state; + } + + public AllocatableValue getHighResult() { + return highResult; + } + + public AllocatableValue getLowResult() { + return lowResult; + } + + public AllocatableValue getQuotient() { + return lowResult; + } + + public AllocatableValue getRemainder() { + return highResult; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + if (isRegister(y)) { + opcode.emit(masm, size, asRegister(y)); + } else { + assert isStackSlot(y); + opcode.emit(masm, size, (AMD64Address) crb.asAddress(y)); + } + } + + @Override + public void verify() { + assert asRegister(highResult).equals(AMD64.rdx); + assert asRegister(lowResult).equals(AMD64.rax); + + assert asRegister(lowX).equals(AMD64.rax); + if (opcode == DIV || opcode == IDIV) { + assert asRegister(highX).equals(AMD64.rdx); + } else if (opcode == MUL || opcode == IMUL) { + assert isIllegal(highX); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64PauseOp.java 2016-12-07 13:54:31.414716247 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011, 2015, 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.lir.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +/** + * Emits a pause. + */ +@Opcode("PAUSE") +public final class AMD64PauseOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64PauseOp.class); + + public AMD64PauseOp() { + super(TYPE); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) { + asm.pause(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64PrefetchOp.java 2016-12-07 13:54:31.678727849 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +public final class AMD64PrefetchOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64PrefetchOp.class); + + private final int instr; // AllocatePrefetchInstr + @Alive({COMPOSITE}) protected AMD64AddressValue address; + + public AMD64PrefetchOp(AMD64AddressValue address, int instr) { + super(TYPE); + this.address = address; + this.instr = instr; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + switch (instr) { + case 0: + masm.prefetchnta(address.toAddress()); + break; + case 1: + masm.prefetcht0(address.toAddress()); + break; + case 2: + masm.prefetcht2(address.toAddress()); + break; + case 3: + masm.prefetchw(address.toAddress()); + break; + default: + throw GraalError.shouldNotReachHere("unspported prefetch op " + instr); + + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ReadTimestampCounter.java 2016-12-07 13:54:31.945739584 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.meta.AllocatableValue; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +/** + * AMD64 rdtsc operation. The result is in EDX:EAX. + */ +@Opcode("RDTSC") +public class AMD64ReadTimestampCounter extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ReadTimestampCounter.class); + + @Def({REG}) protected AllocatableValue highResult; + @Def({REG}) protected AllocatableValue lowResult; + + public AMD64ReadTimestampCounter() { + super(TYPE); + + this.highResult = AMD64.rdx.asValue(LIRKind.value(AMD64Kind.DWORD)); + this.lowResult = AMD64.rax.asValue(LIRKind.value(AMD64Kind.DWORD)); + } + + public AllocatableValue getHighResult() { + return highResult; + } + + public AllocatableValue getLowResult() { + return lowResult; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + masm.rdtsc(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64RestoreRegistersOp.java 2016-12-07 13:54:32.209751187 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asStackSlot; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import java.util.Arrays; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.LIRValueUtil; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Restores registers from stack slots. + */ +@Opcode("RESTORE_REGISTER") +public class AMD64RestoreRegistersOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64RestoreRegistersOp.class); + + /** + * The slots from which the registers are restored. + */ + @Use(STACK) protected final AllocatableValue[] slots; + + /** + * The operation that saved the registers restored by this operation. + */ + private final AMD64SaveRegistersOp save; + + public AMD64RestoreRegistersOp(AllocatableValue[] values, AMD64SaveRegistersOp save) { + this(TYPE, values, save); + } + + protected AMD64RestoreRegistersOp(LIRInstructionClass c, AllocatableValue[] values, AMD64SaveRegistersOp save) { + super(c); + assert Arrays.asList(values).stream().allMatch(LIRValueUtil::isVirtualStackSlot); + this.slots = values; + this.save = save; + } + + protected Register[] getSavedRegisters() { + return save.savedRegisters; + } + + protected void restoreRegister(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, StackSlot input) { + AMD64Move.stack2reg((AMD64Kind) input.getPlatformKind(), crb, masm, result, input); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Register[] savedRegisters = getSavedRegisters(); + for (int i = 0; i < savedRegisters.length; i++) { + if (savedRegisters[i] != null) { + assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i]; + restoreRegister(crb, masm, savedRegisters[i], asStackSlot(slots[i])); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java 2016-12-07 13:54:32.471762702 -0800 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asStackSlot; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import java.util.Arrays; +import java.util.Set; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.LIRValueUtil; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.framemap.FrameMap; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterSaveLayout; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * Saves registers to stack slots. + */ +@Opcode("SAVE_REGISTER") +public class AMD64SaveRegistersOp extends AMD64LIRInstruction implements SaveRegistersOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64SaveRegistersOp.class); + + /** + * The registers (potentially) saved by this operation. + */ + protected final Register[] savedRegisters; + + /** + * The slots to which the registers are saved. + */ + @Def(STACK) protected final AllocatableValue[] slots; + + /** + * Specifies if {@link #remove(Set)} should have an effect. + */ + protected final boolean supportsRemove; + + /** + * + * @param savedRegisters the registers saved by this operation which may be subject to + * {@linkplain #remove(Set) pruning} + * @param savedRegisterLocations the slots to which the registers are saved + * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned} + */ + public AMD64SaveRegistersOp(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) { + this(TYPE, savedRegisters, savedRegisterLocations, supportsRemove); + } + + public AMD64SaveRegistersOp(LIRInstructionClass c, Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) { + super(c); + assert Arrays.asList(savedRegisterLocations).stream().allMatch(LIRValueUtil::isVirtualStackSlot); + this.savedRegisters = savedRegisters; + this.slots = savedRegisterLocations; + this.supportsRemove = supportsRemove; + } + + protected void saveRegister(CompilationResultBuilder crb, AMD64MacroAssembler masm, StackSlot result, Register input) { + AMD64Move.reg2stack((AMD64Kind) result.getPlatformKind(), crb, masm, result, input); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + for (int i = 0; i < savedRegisters.length; i++) { + if (savedRegisters[i] != null) { + assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i]; + saveRegister(crb, masm, asStackSlot(slots[i]), savedRegisters[i]); + } + } + } + + public AllocatableValue[] getSlots() { + return slots; + } + + @Override + public boolean supportsRemove() { + return supportsRemove; + } + + @Override + public int remove(Set doNotSave) { + if (!supportsRemove) { + throw new UnsupportedOperationException(); + } + return prune(doNotSave, savedRegisters); + } + + static int prune(Set toRemove, Register[] registers) { + int pruned = 0; + for (int i = 0; i < registers.length; i++) { + if (registers[i] != null) { + if (toRemove.contains(registers[i])) { + registers[i] = null; + pruned++; + } + } + } + return pruned; + } + + @Override + public RegisterSaveLayout getMap(FrameMap frameMap) { + int total = 0; + for (int i = 0; i < savedRegisters.length; i++) { + if (savedRegisters[i] != null) { + total++; + } + } + Register[] keys = new Register[total]; + int[] values = new int[total]; + if (total != 0) { + int mapIndex = 0; + for (int i = 0; i < savedRegisters.length; i++) { + if (savedRegisters[i] != null) { + keys[mapIndex] = savedRegisters[i]; + assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i]; + StackSlot slot = asStackSlot(slots[i]); + values[mapIndex] = indexForStackSlot(frameMap, slot); + mapIndex++; + } + } + assert mapIndex == total; + } + return new RegisterSaveLayout(keys, values); + } + + /** + * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack + * slots in the reference map. + * + * @param slot a stack slot + * @return the index of the stack slot + */ + private static int indexForStackSlot(FrameMap frameMap, StackSlot slot) { + assert frameMap.offsetForStackSlot(slot) % frameMap.getTarget().wordSize == 0; + int value = frameMap.offsetForStackSlot(slot) / frameMap.getTarget().wordSize; + return value; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ShiftOp.java 2016-12-07 13:54:32.736774349 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.meta.AllocatableValue; + +/** + * AMD64 shift/rotate operation. This operation has a single operand for the first input and output. + * The second input must be in the RCX register. + */ +public class AMD64ShiftOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ShiftOp.class); + + @Opcode private final AMD64MOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Alive({REG}) protected AllocatableValue y; + + public AMD64ShiftOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + opcode.emit(masm, size, asRegister(result)); + } + + @Override + public void verify() { + assert asRegister(y).equals(AMD64.rcx); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SignExtendOp.java 2016-12-07 13:54:33.000785952 -0800 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.meta.AllocatableValue; + +@Opcode("CDQ") +public class AMD64SignExtendOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64SignExtendOp.class); + + private final OperandSize size; + + @Def({REG}) protected AllocatableValue highResult; + @Def({REG}) protected AllocatableValue lowResult; + + @Use({REG}) protected AllocatableValue input; + + public AMD64SignExtendOp(OperandSize size, LIRKind resultKind, AllocatableValue input) { + super(TYPE); + this.size = size; + + this.highResult = AMD64.rdx.asValue(resultKind); + this.lowResult = AMD64.rax.asValue(resultKind); + this.input = input; + } + + public AllocatableValue getHighResult() { + return highResult; + } + + public AllocatableValue getLowResult() { + return lowResult; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (size == DWORD) { + masm.cdql(); + } else { + assert size == QWORD; + masm.cdqq(); + } + } + + @Override + public void verify() { + assert asRegister(highResult).equals(AMD64.rdx); + assert asRegister(lowResult).equals(AMD64.rax); + assert asRegister(input).equals(AMD64.rax); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Unary.java 2016-12-07 13:54:33.264797554 -0800 @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MROp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; + +/** + * AMD64 LIR instructions that have one input and one output. + */ +public class AMD64Unary { + + /** + * Instruction with a single operand that is both input and output. + */ + public static class MOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MOp.class); + + @Opcode private final AMD64MOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue value; + + public MOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.value = value; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, value); + opcode.emit(masm, size, asRegister(result)); + } + } + + /** + * Instruction with separate input and output operands, and an operand encoding of RM. + */ + public static class RMOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(RMOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue value; + + public RMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.value = value; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(value)) { + opcode.emit(masm, size, asRegister(result), asRegister(value)); + } else { + assert isStackSlot(value); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(value)); + } + } + } + + /** + * Instruction with separate input and output operands, and an operand encoding of MR. + */ + public static class MROp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MROp.class); + + @Opcode private final AMD64MROp opcode; + private final OperandSize size; + + @Def({REG, STACK}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue value; + + public MROp(AMD64MROp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.value = value; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(result)) { + opcode.emit(masm, size, asRegister(result), asRegister(value)); + } else { + assert isStackSlot(result); + opcode.emit(masm, size, (AMD64Address) crb.asAddress(result), asRegister(value)); + } + } + } + + /** + * Instruction with a {@link AMD64AddressValue memory} operand. + */ + public static class MemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({COMPOSITE}) protected AMD64AddressValue input; + + @State protected LIRFrameState state; + + public MemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AMD64AddressValue input, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.input = input; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, asRegister(result), input.toAddress()); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && input.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64VZeroUpper.java 2016-12-07 13:54:33.529809201 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016, 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.lir.amd64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; + +import java.util.BitSet; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.meta.Value; + +public class AMD64VZeroUpper extends AMD64LIRInstruction { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64VZeroUpper.class); + + @Temp protected final RegisterValue[] xmmRegisters; + + public AMD64VZeroUpper(Value[] exclude) { + super(TYPE); + xmmRegisters = initRegisterValues(exclude); + } + + private static RegisterValue[] initRegisterValues(Value[] exclude) { + BitSet skippedRegs = new BitSet(); + int numSkipped = 0; + if (exclude != null) { + for (Value value : exclude) { + if (isRegister(value) && asRegister(value).getRegisterCategory().equals(AMD64.XMM)) { + skippedRegs.set(asRegister(value).number); + numSkipped++; + } + } + } + RegisterValue[] regs = new RegisterValue[AMD64.xmmRegistersAVX512.length - numSkipped]; + for (int i = 0, j = 0; i < AMD64.xmmRegistersAVX512.length; i++) { + Register reg = AMD64.xmmRegistersAVX512[i]; + if (!skippedRegs.get(reg.number)) { + regs[j++] = reg.asValue(); + } + } + return regs; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) { + asm.vzeroupper(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java 2016-12-07 13:54:33.794820848 -0800 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.amd64; + +import static org.graalvm.compiler.lir.amd64.AMD64SaveRegistersOp.prune; + +import java.util.Set; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.framemap.FrameMap; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterSaveLayout; +import jdk.vm.ci.meta.JavaConstant; + +/** + * Writes well known garbage values to registers. + */ +@Opcode("ZAP_REGISTER") +public final class AMD64ZapRegistersOp extends AMD64LIRInstruction implements SaveRegistersOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ZapRegistersOp.class); + + /** + * The registers that are zapped. + */ + protected final Register[] zappedRegisters; + + /** + * The garbage values that are written to the registers. + */ + protected final JavaConstant[] zapValues; + + public AMD64ZapRegistersOp(Register[] zappedRegisters, JavaConstant[] zapValues) { + super(TYPE); + this.zappedRegisters = zappedRegisters; + this.zapValues = zapValues; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + for (int i = 0; i < zappedRegisters.length; i++) { + Register reg = zappedRegisters[i]; + if (reg != null) { + AMD64Move.const2reg(crb, masm, reg, zapValues[i]); + } + } + } + + @Override + public boolean supportsRemove() { + return true; + } + + @Override + public int remove(Set doNotSave) { + return prune(doNotSave, zappedRegisters); + } + + @Override + public RegisterSaveLayout getMap(FrameMap frameMap) { + return new RegisterSaveLayout(new Register[0], new int[0]); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapStackOp.java 2016-12-07 13:54:34.058832451 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016, 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.lir.amd64; + +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.meta.JavaConstant; + +/** + * Writes well known garbage values to stack slots. + */ +@Opcode("ZAP_STACK") +public final class AMD64ZapStackOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ZapStackOp.class); + + /** + * The stack slots that are zapped. + */ + @Def(OperandFlag.STACK) protected final StackSlot[] zappedStack; + + /** + * The garbage values that are written to the stack. + */ + protected final JavaConstant[] zapValues; + + public AMD64ZapStackOp(StackSlot[] zappedStack, JavaConstant[] zapValues) { + super(TYPE); + this.zappedStack = zappedStack; + this.zapValues = zapValues; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + for (int i = 0; i < zappedStack.length; i++) { + StackSlot slot = zappedStack[i]; + if (slot != null) { + AMD64Move.const2stack(crb, masm, slot, zapValues[i]); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/phases/StackMoveOptimizationPhase.java 2016-12-07 13:54:34.324844142 -0800 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.amd64.phases; + +import static org.graalvm.compiler.lir.phases.LIRPhase.Options.LIROptimization; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.RedundantMoveElimination; +import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64MultiStackMove; +import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64StackMove; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase; +import org.graalvm.compiler.options.NestedBooleanOptionValue; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; + +/** + * Replaces sequential {@link AMD64StackMove}s of the same type with a single + * {@link AMD64MultiStackMove} to avoid storing/restoring the scratch register multiple times. + * + * Note: this phase must be inserted after {@link RedundantMoveElimination} phase because + * {@link AMD64MultiStackMove} are not probably detected. + */ +public class StackMoveOptimizationPhase extends PostAllocationOptimizationPhase { + public static class Options { + // @formatter:off + @Option(help = "", type = OptionType.Debug) + public static final NestedBooleanOptionValue LIROptStackMoveOptimizer = new NestedBooleanOptionValue(LIROptimization, true); + // @formatter:on + } + + private static final DebugCounter eliminatedBackup = Debug.counter("StackMoveOptimizer[EliminatedScratchBackupRestore]"); + + @Override + protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) { + LIR lir = lirGenRes.getLIR(); + for (AbstractBlockBase block : lir.getControlFlowGraph().getBlocks()) { + List instructions = lir.getLIRforBlock(block); + new Closure().process(instructions); + } + } + + private static class Closure { + private static final int NONE = -1; + + private int begin = NONE; + private Register reg = null; + private List dst; + private List src; + private AllocatableValue slot; + private boolean removed = false; + + public void process(List instructions) { + for (int i = 0; i < instructions.size(); i++) { + LIRInstruction inst = instructions.get(i); + + if (isStackMove(inst)) { + AMD64StackMove move = asStackMove(inst); + + if (reg != null && !reg.equals(move.getScratchRegister())) { + // end of trace & start of new + replaceStackMoves(instructions); + } + + // lazy initialize + if (dst == null) { + assert src == null; + dst = new ArrayList<>(); + src = new ArrayList<>(); + } + + dst.add(move.getResult()); + src.add(move.getInput()); + + if (begin == NONE) { + // trace begin + begin = i; + reg = move.getScratchRegister(); + slot = move.getBackupSlot(); + } + + } else if (begin != NONE) { + // end of trace + replaceStackMoves(instructions); + } + } + // remove instructions + if (removed) { + instructions.removeAll(Collections.singleton(null)); + } + + } + + private void replaceStackMoves(List instructions) { + int size = dst.size(); + if (size > 1) { + AMD64MultiStackMove multiMove = new AMD64MultiStackMove(dst.toArray(new AllocatableValue[size]), src.toArray(new AllocatableValue[size]), reg, slot); + // replace first instruction + instructions.set(begin, multiMove); + // and null out others + Collections.fill(instructions.subList(begin + 1, begin + size), null); + // removed + removed = true; + eliminatedBackup.add(size - 1); + } + // reset + dst.clear(); + src.clear(); + begin = NONE; + reg = null; + slot = null; + } + } + + private static AMD64StackMove asStackMove(LIRInstruction inst) { + assert isStackMove(inst); + return (AMD64StackMove) inst; + } + + private static boolean isStackMove(LIRInstruction inst) { + return inst instanceof AMD64StackMove; + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/ConstantStackCastTest.java 2016-12-07 13:54:34.589855789 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.jtt; + +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.ConstantValue; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +/** + * Tests move from a constant to a wider stack slot (e.g. byte constant to integer stack slot). + */ +public class ConstantStackCastTest extends LIRTest { + private static PlatformKind byteKind; + private static final LoadConstantStackSpec stackCopyByte = new LoadConstantStackSpec(); + + @Before + public void setup() { + // Necessary to get the PlatformKind on which we're currently running on + byteKind = getBackend().getTarget().arch.getPlatformKind(JavaKind.Byte); + stackCopyByte.dstKind = LIRKind.fromJavaKind(getBackend().getTarget().arch, JavaKind.Int); + stackCopyByte.srcKind = LIRKind.fromJavaKind(getBackend().getTarget().arch, JavaKind.Byte); + } + + private static class LoadConstantStackSpec extends LIRTestSpecification { + LIRKind dstKind; + LIRKind srcKind; + + @Override + public void generate(LIRGeneratorTool gen, Value value) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + // create slots + VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(dstKind); + // move stuff around + Value srcValue; + if (isJavaConstant(value)) { + srcValue = getConstant(srcKind, asJavaConstant(value)); + } else { + srcValue = value; + } + gen.emitMove(s1, srcValue); + gen.emitBlackhole(s1); + setResult(gen.emitMove(s1)); + } + + private static ConstantValue getConstant(LIRKind srcKind, JavaConstant c) { + if (srcKind.getPlatformKind() == byteKind) { + JavaConstant byteConst = JavaConstant.forByte((byte) c.asInt()); + return new ConstantValue(srcKind, byteConst); + } else { + throw GraalError.shouldNotReachHere("Kind not supported: " + srcKind); + } + } + + } + + @LIRIntrinsic + public static byte testCopyByte(@SuppressWarnings("unused") LoadConstantStackSpec spec, byte value) { + return value; + } + + public byte testByte(byte value) { + return testCopyByte(stackCopyByte, value); + } + + @Test + public void runByte() throws Throwable { + runTest("testByte", (byte) 0); + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTest.java 2016-12-07 13:54:34.853867391 -0800 @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2015, 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.lir.jtt; + +import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; + +import java.lang.annotation.ElementType; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.stream.Stream; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.jtt.JTTTest; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +/** + * Base class for LIR tests. + *

    + * It provides facilities to replace methods with {@link LIRTestSpecification arbitrary LIR + * instructions}. + */ +public abstract class LIRTest extends JTTTest { + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + private static final class LIRTestNode extends FixedWithNextNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(LIRTestNode.class); + @Input protected ValueNode opsNode; + @Input protected NodeInputList values; + public final SnippetReflectionProvider snippetReflection; + + protected LIRTestNode(SnippetReflectionProvider snippetReflection, JavaKind kind, ValueNode opsNode, ValueNode[] values) { + super(TYPE, StampFactory.forKind(kind)); + this.opsNode = opsNode; + this.values = new NodeInputList<>(this, values); + this.snippetReflection = snippetReflection; + } + + public NodeInputList values() { + return values; + } + + public ValueNode getLIROpsNode() { + return opsNode; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + LIRTestSpecification ops = getLIROperations(); + Stream v = values().stream().map(node -> gen.operand(node)); + + ops.generate(gen.getLIRGeneratorTool(), v.toArray(size -> new Value[size])); + Value result = ops.getResult(); + if (result != null) { + gen.setResult(this, result); + } + } + + public LIRTestSpecification getLIROperations() { + assert getLIROpsNode().isConstant(); + LIRTestSpecification spec = snippetReflection.asObject(LIRTestSpecification.class, getLIROpsNode().asJavaConstant()); + return spec; + } + } + + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + private static final class LIRValueNode extends FixedWithNextNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(LIRValueNode.class); + @Input protected ValueNode opsNode; + @Input protected ValueNode name; + public final SnippetReflectionProvider snippetReflection; + + protected LIRValueNode(SnippetReflectionProvider snippetReflection, JavaKind kind, ValueNode opsNode, ValueNode name) { + super(TYPE, StampFactory.forKind(kind)); + this.opsNode = opsNode; + this.name = name; + this.snippetReflection = snippetReflection; + } + + public ValueNode getLIROpsNode() { + return opsNode; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + LIRTestSpecification spec = getLIROperations(); + Value output = spec.getOutput(getName()); + gen.setResult(this, isVariable(output) ? output : gen.getLIRGeneratorTool().emitMove(output)); + } + + private String getName() { + assert name.isConstant(); + return snippetReflection.asObject(String.class, name.asJavaConstant()); + } + + private LIRTestSpecification getLIROperations() { + assert getLIROpsNode().isConstant(); + return snippetReflection.asObject(LIRTestSpecification.class, getLIROpsNode().asJavaConstant()); + } + + } + + private InvocationPlugin lirTestPlugin = new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec) { + JavaKind returnKind = targetMethod.getSignature().getReturnKind(); + LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{}); + addNode(b, returnKind, node); + return true; + } + + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0) { + JavaKind returnKind = targetMethod.getSignature().getReturnKind(); + LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0}); + addNode(b, returnKind, node); + return true; + } + + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1) { + JavaKind returnKind = targetMethod.getSignature().getReturnKind(); + LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1}); + addNode(b, returnKind, node); + return true; + } + + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1, ValueNode arg2) { + JavaKind returnKind = targetMethod.getSignature().getReturnKind(); + LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1, arg2}); + addNode(b, returnKind, node); + return true; + } + + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1, ValueNode arg2, ValueNode arg3) { + JavaKind returnKind = targetMethod.getSignature().getReturnKind(); + LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1, arg2, arg3}); + addNode(b, returnKind, node); + return true; + } + + private void addNode(GraphBuilderContext b, JavaKind returnKind, LIRTestNode node) { + if (returnKind.equals(JavaKind.Void)) { + b.add(node); + } else { + b.addPush(returnKind, node); + } + } + + }; + + @Override + protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) { + InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins(); + + Class c = getClass(); + for (Method m : c.getMethods()) { + if (m.getAnnotation(LIRIntrinsic.class) != null) { + assert Modifier.isStatic(m.getModifiers()); + Class[] p = m.getParameterTypes(); + assert p.length > 0; + assert LIRTestSpecification.class.isAssignableFrom(p[0]); + + invocationPlugins.register(lirTestPlugin, c, m.getName(), p); + } + } + InvocationPlugin outputPlugin = new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode name, ValueNode expected) { + JavaKind returnKind = targetMethod.getSignature().getReturnKind(); + b.addPush(returnKind, new LIRValueNode(getSnippetReflection(), returnKind, spec, name)); + return true; + } + }; + invocationPlugins.register(outputPlugin, LIRTest.class, "getOutput", new Class[]{LIRTestSpecification.class, String.class, Object.class}); + invocationPlugins.register(outputPlugin, LIRTest.class, "getOutput", new Class[]{LIRTestSpecification.class, String.class, int.class}); + return super.editGraphBuilderConfiguration(conf); + } + + @SuppressWarnings("unused") + public static byte getOutput(LIRTestSpecification spec, String name, byte expected) { + return expected; + } + + @SuppressWarnings("unused") + public static short getOutput(LIRTestSpecification spec, String name, short expected) { + return expected; + } + + @SuppressWarnings("unused") + public static int getOutput(LIRTestSpecification spec, String name, int expected) { + return expected; + } + + @SuppressWarnings("unused") + public static long getOutput(LIRTestSpecification spec, String name, long expected) { + return expected; + } + + @SuppressWarnings("unused") + public static float getOutput(LIRTestSpecification spec, String name, float expected) { + return expected; + } + + @SuppressWarnings("unused") + public static double getOutput(LIRTestSpecification spec, String name, double expected) { + return expected; + } + + @SuppressWarnings("unused") + public static Object getOutput(LIRTestSpecification spec, String name, Object expected) { + return expected; + } + + @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) + @java.lang.annotation.Target(ElementType.METHOD) + public static @interface LIRIntrinsic { + } + +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTestSpecification.java 2016-12-07 13:54:35.119879082 -0800 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.jtt; + +import java.util.HashMap; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.meta.Value; + +public abstract class LIRTestSpecification { + private Value result; + private final HashMap output = new HashMap<>(); + + public void generate(LIRGeneratorTool gen) { + defaultHandler(gen); + } + + public void generate(LIRGeneratorTool gen, Value arg0) { + defaultHandler(gen, arg0); + } + + public void generate(LIRGeneratorTool gen, Value arg0, Value arg1) { + defaultHandler(gen, arg0, arg1); + } + + public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2) { + defaultHandler(gen, arg0, arg1, arg2); + } + + public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3) { + defaultHandler(gen, arg0, arg1, arg2, arg3); + } + + public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3, Value arg4) { + defaultHandler(gen, arg0, arg1, arg2, arg3, arg4); + } + + private static void defaultHandler(@SuppressWarnings("unused") LIRGeneratorTool gen, Value... args) { + throw new GraalError("LIRTestSpecification cannot handle generate() with %d arguments", args.length); + } + + void generate(LIRGeneratorTool gen, Value[] values) { + if (values.length == 0) { + generate(gen); + } else if (values.length == 1) { + generate(gen, values[0]); + } else if (values.length == 2) { + generate(gen, values[0], values[1]); + } else if (values.length == 3) { + generate(gen, values[0], values[1], values[2]); + } else if (values.length == 4) { + generate(gen, values[0], values[1], values[2], values[3]); + } else if (values.length == 5) { + generate(gen, values[0], values[1], values[2], values[3], values[4]); + } else { + GraalError.unimplemented(); + } + + } + + public void setOutput(String name, Value value) { + output.put(name, value); + } + + public Value getOutput(String name) { + return output.get(name); + } + + public void setResult(Value value) { + result = value; + } + + public Value getResult() { + return result; + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTestTest.java 2016-12-07 13:54:35.384890729 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.jtt; + +import org.junit.Test; + +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.meta.Value; + +public class LIRTestTest extends LIRTest { + private static final LIRTestSpecification stackCopy = new LIRTestSpecification() { + @Override + public void generate(LIRGeneratorTool gen, Value a, Value b) { + setOutput("a", a); + setOutput("b", b); + setResult(a); + } + }; + + @SuppressWarnings("unused") + @LIRIntrinsic + public static int copyInt(LIRTestSpecification spec, int a, int b) { + return a; + } + + public static int[] testGetOutput(int a, int b, int[] out) { + out[0] = copyInt(stackCopy, a, b); + out[1] = getOutput(stackCopy, "a", a); + out[2] = getOutput(stackCopy, "b", b); + return out; + } + + @Test + public void runInt() throws Throwable { + runTest("testGetOutput", Integer.MIN_VALUE, 0, supply(() -> new int[3])); + runTest("testGetOutput", -1, Integer.MAX_VALUE, supply(() -> new int[3])); + runTest("testGetOutput", 0, 42, supply(() -> new int[3])); + runTest("testGetOutput", 1, -0xFFAA44, supply(() -> new int[3])); + runTest("testGetOutput", Integer.MAX_VALUE, -42, supply(() -> new int[3])); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/SPARCBranchBailoutTest.java 2016-12-07 13:54:35.648902332 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016, 2016, 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.lir.jtt; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.common.PermanentBailoutException; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.sparc.SPARC; + +/** + * Tests the {@link BailoutException} thrown, when trying to compile huge methods, which have branch + * displacements which does not fit into 19 bit signed. + */ +public class SPARCBranchBailoutTest extends LIRTest { + private static class BranchSpec extends LIRTestSpecification { + private final int n; + + BranchSpec(int n) { + super(); + this.n = n; + } + + @Override + public void generate(LIRGeneratorTool gen, Value a) { + gen.append(new LargeOp(n)); + setResult(a); + } + } + + private static final BranchSpec spec = new BranchSpec(1 << 20); + + @LIRIntrinsic + public static int branch(@SuppressWarnings("unused") BranchSpec s, int a) { + return a; + } + + public static int testBranch(int length) { + int res = 1; + if (length > 0) { + res = branch(spec, 1); + } else { + res = branch(spec, 2); + } + return GraalDirectives.opaque(res); + } + + @Test + public void testBailoutOnBranchOverflow() throws Throwable { + Assume.assumeTrue(getBackend().getTarget().arch instanceof SPARC); + ResolvedJavaMethod m = getResolvedJavaMethod("testBranch"); + try { + compile(m, null); + } catch (GraalError e) { + Assert.assertEquals(PermanentBailoutException.class, e.getCause().getClass()); + } + } + + public static class LargeOp extends LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(LargeOp.class); + private final int n; + + public LargeOp(int n) { + super(TYPE); + this.n = n; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + for (int i = 0; i < n; i++) { + crb.asm.emitInt(0); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/StackMoveTest.java 2016-12-07 13:54:35.913913979 -0800 @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.jtt; + +import org.junit.Before; +import org.junit.Test; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.VirtualStackSlot; +import org.graalvm.compiler.lir.framemap.FrameMapBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; + +public class StackMoveTest extends LIRTest { + private static PlatformKind byteKind; + private static PlatformKind shortKind; + + @Before + public void setUp() { + byteKind = getBackend().getTarget().arch.getPlatformKind(JavaKind.Byte); + shortKind = getBackend().getTarget().arch.getPlatformKind(JavaKind.Short); + } + + private static class StackCopySpec extends LIRTestSpecification { + @Override + public void generate(LIRGeneratorTool gen, Value a) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + ValueKind valueKind = getValueKind(a); + + // create slots + VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(valueKind); + VirtualStackSlot s2 = frameMapBuilder.allocateSpillSlot(valueKind); + + // start emit + gen.emitMove(s1, a); + Value copy1 = gen.emitMove(s1); + gen.append(gen.getSpillMoveFactory().createStackMove(s2, s1)); + Variable result = gen.emitMove(s2); + // end emit + + // set output and result + setResult(result); + setOutput("slotcopy", copy1); + setOutput("slot1", s1); + setOutput("slot2", s2); + } + + protected ValueKind getValueKind(Value value) { + return value.getValueKind(); + } + } + + private static final LIRTestSpecification stackCopy = new StackCopySpec(); + + /* + * int + */ + + @SuppressWarnings("unused") + @LIRIntrinsic + public static int copyInt(LIRTestSpecification spec, int a) { + return a; + } + + public int[] testInt(int a, int[] out) { + out[0] = copyInt(stackCopy, a); + out[1] = getOutput(stackCopy, "slotcopy", a); + out[2] = getOutput(stackCopy, "slot1", a); + out[3] = getOutput(stackCopy, "slot2", a); + return out; + } + + @Test + public void runInt() throws Throwable { + runTest("testInt", Integer.MIN_VALUE, supply(() -> new int[4])); + runTest("testInt", -1, supply(() -> new int[4])); + runTest("testInt", 0, supply(() -> new int[4])); + runTest("testInt", 1, supply(() -> new int[4])); + runTest("testInt", Integer.MAX_VALUE, supply(() -> new int[4])); + } + + /* + * long + */ + + @SuppressWarnings("unused") + @LIRIntrinsic + public static long copyLong(LIRTestSpecification spec, long a) { + return a; + } + + public long[] testLong(long a, long[] out) { + out[0] = copyLong(stackCopy, a); + out[1] = getOutput(stackCopy, "slotcopy", a); + out[2] = getOutput(stackCopy, "slot1", a); + out[3] = getOutput(stackCopy, "slot2", a); + return out; + } + + @Test + public void runLong() throws Throwable { + runTest("testLong", Long.MIN_VALUE, supply(() -> new long[3])); + runTest("testLong", -1L, supply(() -> new long[3])); + runTest("testLong", 0L, supply(() -> new long[3])); + runTest("testLong", 1L, supply(() -> new long[3])); + runTest("testLong", Long.MAX_VALUE, supply(() -> new long[3])); + } + + /* + * float + */ + + @SuppressWarnings("unused") + @LIRIntrinsic + public static float copyFloat(LIRTestSpecification spec, float a) { + return a; + } + + public float[] testFloat(float a, float[] out) { + out[0] = copyFloat(stackCopy, a); + out[1] = getOutput(stackCopy, "slotcopy", a); + out[2] = getOutput(stackCopy, "slot1", a); + out[3] = getOutput(stackCopy, "slot2", a); + return out; + } + + @Test + public void runFloat() throws Throwable { + runTest("testFloat", Float.MIN_VALUE, supply(() -> new float[3])); + runTest("testFloat", -1f, supply(() -> new float[3])); + runTest("testFloat", -0.1f, supply(() -> new float[3])); + runTest("testFloat", 0f, supply(() -> new float[3])); + runTest("testFloat", 0.1f, supply(() -> new float[3])); + runTest("testFloat", 1f, supply(() -> new float[3])); + runTest("testFloat", Float.MAX_VALUE, supply(() -> new float[3])); + } + + /* + * double + */ + + @SuppressWarnings("unused") + @LIRIntrinsic + public static double copyDouble(LIRTestSpecification spec, double a) { + return a; + } + + public double[] testDouble(double a, double[] out) { + out[0] = copyDouble(stackCopy, a); + out[1] = getOutput(stackCopy, "slotcopy", a); + out[2] = getOutput(stackCopy, "slot1", a); + out[3] = getOutput(stackCopy, "slot2", a); + return out; + } + + @Test + public void runDouble() throws Throwable { + runTest("testDouble", Double.MIN_VALUE, supply(() -> new double[3])); + runTest("testDouble", -1., supply(() -> new double[3])); + runTest("testDouble", -0.1, supply(() -> new double[3])); + runTest("testDouble", 0., supply(() -> new double[3])); + runTest("testDouble", 0.1, supply(() -> new double[3])); + runTest("testDouble", 1., supply(() -> new double[3])); + runTest("testDouble", Double.MAX_VALUE, supply(() -> new double[3])); + } + + /* + * short + */ + + private static final LIRTestSpecification shortStackCopy = new StackCopySpec() { + @Override + protected ValueKind getValueKind(Value value) { + return LIRKind.value(shortKind); + } + }; + + @SuppressWarnings("unused") + @LIRIntrinsic + public static short copyShort(LIRTestSpecification spec, short a) { + return a; + } + + public short[] testShort(short a, short[] out) { + out[0] = copyShort(shortStackCopy, a); + out[1] = getOutput(shortStackCopy, "slotcopy", a); + out[2] = getOutput(shortStackCopy, "slot1", a); + out[3] = getOutput(shortStackCopy, "slot2", a); + return out; + } + + @Test + public void runShort() throws Throwable { + runTest("testShort", Short.MIN_VALUE, supply(() -> new short[3])); + runTest("testShort", (short) -1, supply(() -> new short[3])); + runTest("testShort", (short) 0, supply(() -> new short[3])); + runTest("testShort", (short) 1, supply(() -> new short[3])); + runTest("testShort", Short.MAX_VALUE, supply(() -> new short[3])); + } + + /* + * byte + */ + + private static final LIRTestSpecification byteStackCopy = new StackCopySpec() { + @Override + protected ValueKind getValueKind(Value value) { + return LIRKind.value(byteKind); + } + }; + + @SuppressWarnings("unused") + @LIRIntrinsic + public static byte copyByte(LIRTestSpecification spec, byte a) { + return a; + } + + public byte[] testByte(byte a, byte[] out) { + out[0] = copyByte(byteStackCopy, a); + out[1] = getOutput(byteStackCopy, "slotcopy", a); + out[2] = getOutput(byteStackCopy, "slot1", a); + out[3] = getOutput(byteStackCopy, "slot2", a); + return out; + } + + @Test + public void runByte() throws Throwable { + runTest("testByte", Byte.MIN_VALUE, supply(() -> new byte[3])); + runTest("testByte", (byte) -1, supply(() -> new byte[3])); + runTest("testByte", (byte) 0, supply(() -> new byte[3])); + runTest("testByte", (byte) 1, supply(() -> new byte[3])); + runTest("testByte", Byte.MAX_VALUE, supply(() -> new byte[3])); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCAddressValue.java 2016-12-07 13:54:36.176925538 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.sparc; + +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.lir.CompositeValue; + +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; + +public abstract class SPARCAddressValue extends CompositeValue { + + public SPARCAddressValue(ValueKind kind) { + super(kind); + } + + public abstract SPARCAddress toAddress(); + + public abstract boolean isValidImplicitNullCheckFor(Value value, int implicitNullCheckLimit); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArithmetic.java 2016-12-07 13:54:36.441937184 -0800 @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2013, 2016, 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.lir.sparc; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_V_SHIFT; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_XCC_SHIFT; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Ordered; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARCKind.DOUBLE; +import static jdk.vm.ci.sparc.SPARCKind.SINGLE; +import static jdk.vm.ci.sparc.SPARCKind.WORD; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.sparc.SPARC; + +public class SPARCArithmetic { + public static final class FloatConvertOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(FloatConvertOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(5); + + @Opcode private final FloatConvert opcode; + @Def({REG, HINT}) protected Value result; + @Use({REG}) protected Value x; + + public enum FloatConvert { + F2I, + D2I, + F2L, + D2L + } + + public FloatConvertOp(FloatConvert opcode, Value x, Value result) { + super(TYPE, SIZE); + this.opcode = opcode; + this.x = x; + this.result = result; + } + + @Override + protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Label notOrdered = new Label(); + switch (opcode) { + case F2L: + masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE)); + FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); + masm.fstox(asRegister(x, SINGLE), asRegister(result, DOUBLE)); + masm.fxtod(asRegister(result), asRegister(result)); + masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE)); + masm.bind(notOrdered); + break; + case F2I: + masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE)); + FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); + masm.fstoi(asRegister(x, SINGLE), asRegister(result, SINGLE)); + masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE)); + masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE)); + masm.bind(notOrdered); + break; + case D2L: + masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE)); + FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); + masm.fdtox(asRegister(x, DOUBLE), asRegister(result, DOUBLE)); + masm.fxtod(asRegister(result, DOUBLE), asRegister(result, DOUBLE)); + masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE)); + masm.bind(notOrdered); + break; + case D2I: + masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE)); + FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); + masm.fdtoi(asRegister(x, DOUBLE), asRegister(result, SINGLE)); + masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE)); + masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE)); + masm.bind(notOrdered); + break; + default: + throw GraalError.shouldNotReachHere("missing: " + opcode); + } + } + } + + /** + * Special LIR instruction as it requires a bunch of scratch registers. + */ + public static final class RemOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(RemOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(4); + + @Opcode private final Rem opcode; + @Def({REG}) protected Value result; + @Alive({REG, CONST}) protected Value x; + @Alive({REG, CONST}) protected Value y; + @Temp({REG}) protected Value scratch1; + @Temp({REG}) protected Value scratch2; + @State protected LIRFrameState state; + + public enum Rem { + IUREM, + LUREM + } + + public RemOp(Rem opcode, Value result, Value x, Value y, Value scratch1, Value scratch2, LIRFrameState state) { + super(TYPE, SIZE); + this.opcode = opcode; + this.result = result; + this.x = x; + this.y = y; + this.scratch1 = scratch1; + this.scratch2 = scratch2; + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + if (!isJavaConstant(x) && isJavaConstant(y)) { + assert isSimm13(crb.asIntConst(y)); + assert !x.equals(scratch1); + assert !x.equals(scratch2); + assert !y.equals(scratch1); + switch (opcode) { + case LUREM: + crb.recordImplicitException(masm.position(), state); + masm.udivx(asRegister(x, XWORD), crb.asIntConst(y), asRegister(scratch1, XWORD)); + masm.mulx(asRegister(scratch1, XWORD), crb.asIntConst(y), asRegister(scratch2, XWORD)); + getDelayedControlTransfer().emitControlTransfer(crb, masm); + masm.sub(asRegister(x, XWORD), asRegister(scratch2, XWORD), asRegister(result, XWORD)); + break; + case IUREM: + GraalError.unimplemented(); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } else if (isRegister(x) && isRegister(y)) { + Value xLeft = x; + switch (opcode) { + case LUREM: + if (isJavaConstant(x)) { + masm.setx(crb.asLongConst(x), asRegister(scratch2, XWORD), false); + xLeft = scratch2; + } + assert !asRegister(xLeft, XWORD).equals(asRegister(scratch1, XWORD)); + assert !asRegister(y, XWORD).equals(asRegister(scratch1, XWORD)); + crb.recordImplicitException(masm.position(), state); + masm.udivx(asRegister(xLeft, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); + masm.mulx(asRegister(scratch1, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); + getDelayedControlTransfer().emitControlTransfer(crb, masm); + masm.sub(asRegister(xLeft, XWORD), asRegister(scratch1, XWORD), asRegister(result, XWORD)); + break; + case IUREM: + assert !asRegister(result, WORD).equals(asRegister(scratch1, WORD)); + assert !asRegister(result, WORD).equals(asRegister(scratch2, WORD)); + masm.srl(asRegister(x, WORD), 0, asRegister(scratch1, WORD)); + masm.srl(asRegister(y, WORD), 0, asRegister(result, WORD)); + crb.recordImplicitException(masm.position(), state); + masm.udivx(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(scratch2, WORD)); + masm.mulx(asRegister(scratch2, WORD), asRegister(result, WORD), asRegister(result, WORD)); + getDelayedControlTransfer().emitControlTransfer(crb, masm); + masm.sub(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(result, WORD)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } else { + throw GraalError.shouldNotReachHere(); + } + } + } + + public static final class SPARCIMulccOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCIMulccOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(10); + @Def({REG}) protected Value result; + @Alive({REG}) protected Value x; + @Alive({REG}) protected Value y; + + public SPARCIMulccOp(Value result, Value x, Value y) { + super(TYPE, SIZE); + this.result = result; + this.x = x; + this.y = y; + } + + @Override + protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + try (ScratchRegister tmpScratch = masm.getScratchRegister()) { + Register tmp = tmpScratch.getRegister(); + Register resultRegister = asRegister(result, WORD); + Register xRegister = asRegister(x, WORD); + Register yRegister = asRegister(y, WORD); + masm.sra(xRegister, 0, xRegister); + masm.sra(yRegister, 0, yRegister); + masm.mulx(xRegister, yRegister, resultRegister); + Label noOverflow = new Label(); + masm.sra(resultRegister, 0, tmp); + masm.compareBranch(tmp, resultRegister, Equal, Xcc, noOverflow, PREDICT_TAKEN, null); + masm.wrccr(SPARC.g0, 1 << (SPARCAssembler.CCR_ICC_SHIFT + SPARCAssembler.CCR_V_SHIFT)); + masm.bind(noOverflow); + } + } + } + + /** + * Calculates the product and condition code for long multiplication of long values. + */ + public static final class SPARCLMulccOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCLMulccOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(13); + + @Def({REG}) protected Value result; + @Alive({REG}) protected Value x; + @Alive({REG}) protected Value y; + @Temp({REG}) protected Value scratch1; + @Temp({REG}) protected Value scratch2; + + public SPARCLMulccOp(Value result, Value x, Value y, LIRGeneratorTool gen) { + super(TYPE, SIZE); + this.result = result; + this.x = x; + this.y = y; + this.scratch1 = gen.newVariable(LIRKind.combine(x, y)); + this.scratch2 = gen.newVariable(LIRKind.combine(x, y)); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Label noOverflow = new Label(); + masm.mulx(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD)); + + // Calculate the upper 64 bit signed := (umulxhi product - (x{63}&y + y{63}&x)) + masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); + masm.srax(asRegister(x, XWORD), 63, asRegister(scratch2, XWORD)); + masm.and(asRegister(scratch2, XWORD), asRegister(y, XWORD), asRegister(scratch2, XWORD)); + masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD)); + + masm.srax(asRegister(y, XWORD), 63, asRegister(scratch2, XWORD)); + masm.and(asRegister(scratch2, XWORD), asRegister(x, XWORD), asRegister(scratch2, XWORD)); + masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD)); + + // Now construct the lower half and compare + masm.srax(asRegister(result, XWORD), 63, asRegister(scratch2, XWORD)); + masm.cmp(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD)); + BPCC.emit(masm, Xcc, Equal, NOT_ANNUL, PREDICT_TAKEN, noOverflow); + masm.nop(); + masm.wrccr(g0, 1 << (CCR_XCC_SHIFT + CCR_V_SHIFT)); + masm.bind(noOverflow); + } + } + + public static final class MulHighOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MulHighOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(4); + + @Opcode private final MulHigh opcode; + @Def({REG}) public AllocatableValue result; + @Alive({REG}) public AllocatableValue x; + @Alive({REG}) public AllocatableValue y; + @Temp({REG}) public AllocatableValue scratch; + + public enum MulHigh { + IMUL, + LMUL + } + + public MulHighOp(MulHigh opcode, AllocatableValue x, AllocatableValue y, AllocatableValue result, AllocatableValue scratch) { + super(TYPE, SIZE); + this.opcode = opcode; + this.x = x; + this.y = y; + this.scratch = scratch; + this.result = result; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + assert isRegister(x) && isRegister(y) && isRegister(result) && isRegister(scratch); + switch (opcode) { + case IMUL: + masm.sra(asRegister(x), 0, asRegister(x)); + masm.sra(asRegister(y), 0, asRegister(y)); + masm.mulx(asRegister(x, WORD), asRegister(y, WORD), asRegister(result, WORD)); + masm.srax(asRegister(result, WORD), 32, asRegister(result, WORD)); + break; + case LMUL: + assert !asRegister(scratch, XWORD).equals(asRegister(result, XWORD)); + masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD)); + + masm.srlx(asRegister(x, XWORD), 63, asRegister(scratch, XWORD)); + masm.mulx(asRegister(scratch, XWORD), asRegister(y, XWORD), asRegister(scratch, XWORD)); + masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD)); + + masm.srlx(asRegister(y, XWORD), 63, asRegister(scratch, XWORD)); + masm.mulx(asRegister(scratch, XWORD), asRegister(x, XWORD), asRegister(scratch, XWORD)); + masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java 2016-12-07 13:54:36.708948919 -0800 @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2013, 2016, 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.lir.sparc; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Less; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARCKind.WORD; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.sparc.SPARCKind; +import sun.misc.Unsafe; + +/** + * Emits code which compares two arrays of the same length. + */ +@Opcode("ARRAY_EQUALS") +public final class SPARCArrayEqualsOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCArrayEqualsOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(32); + + private final JavaKind kind; + private final int arrayBaseOffset; + private final int arrayIndexScale; + + @Def({REG}) protected Value resultValue; + @Alive({REG}) protected Value array1Value; + @Alive({REG}) protected Value array2Value; + @Alive({REG}) protected Value lengthValue; + @Temp({REG}) protected Value temp1; + @Temp({REG}) protected Value temp2; + @Temp({REG}) protected Value temp3; + @Temp({REG}) protected Value temp4; + @Temp({REG}) protected Value temp5; + + public SPARCArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, Value result, Value array1, Value array2, Value length) { + super(TYPE, SIZE); + this.kind = kind; + + Class arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass(); + this.arrayBaseOffset = UNSAFE.arrayBaseOffset(arrayClass); + this.arrayIndexScale = UNSAFE.arrayIndexScale(arrayClass); + + this.resultValue = result; + this.array1Value = array1; + this.array2Value = array2; + this.lengthValue = length; + + // Allocate some temporaries. + this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + this.temp3 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); + this.temp4 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); + this.temp5 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Register result = asRegister(resultValue); + Register array1 = asRegister(temp1); + Register array2 = asRegister(temp2); + Register length = asRegister(temp3); + + Label trueLabel = new Label(); + Label falseLabel = new Label(); + Label done = new Label(); + + // Load array base addresses. + masm.add(asRegister(array1Value), arrayBaseOffset, array1); + masm.add(asRegister(array2Value), arrayBaseOffset, array2); + + // Get array length in bytes. + masm.mulx(asRegister(lengthValue, WORD), arrayIndexScale, length); + masm.mov(length, result); // copy + + emit8ByteCompare(masm, result, array1, array2, length, trueLabel, falseLabel); + emitTailCompares(masm, result, array1, array2, trueLabel, falseLabel); + + // Return true + masm.bind(trueLabel); + masm.mov(1, result); + masm.jmp(done); + + // Return false + masm.bind(falseLabel); + masm.mov(g0, result); + + // That's it + masm.bind(done); + } + + /** + * Vector size used in {@link #emit8ByteCompare}. + */ + private static final int VECTOR_SIZE = 8; + + /** + * Emits code that uses 8-byte vector compares. + */ + private void emit8ByteCompare(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + assert lengthValue.getPlatformKind().equals(SPARCKind.WORD); + Label loop = new Label(); + Label compareTail = new Label(); + Label compareTailCorrectVectorEnd = new Label(); + + Register tempReg1 = asRegister(temp4); + Register tempReg2 = asRegister(temp5); + + masm.sra(length, 0, length); + masm.and(result, VECTOR_SIZE - 1, result); // tail count (in bytes) + masm.andcc(length, ~(VECTOR_SIZE - 1), length); // vector count (in bytes) + BPCC.emit(masm, Xcc, Equal, NOT_ANNUL, PREDICT_NOT_TAKEN, compareTail); + + masm.sub(length, VECTOR_SIZE, length); // Delay slot + masm.add(array1, length, array1); + masm.add(array2, length, array2); + masm.sub(g0, length, length); + + // Compare the last element first + masm.ldx(new SPARCAddress(array1, 0), tempReg1); + masm.ldx(new SPARCAddress(array2, 0), tempReg2); + masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_NOT_TAKEN, null); + masm.compareBranch(length, 0, Equal, Xcc, compareTailCorrectVectorEnd, PREDICT_NOT_TAKEN, null); + + // Load the first value from array 1 (Later done in back branch delay-slot) + masm.ldx(new SPARCAddress(array1, length), tempReg1); + masm.bind(loop); + masm.ldx(new SPARCAddress(array2, length), tempReg2); + masm.cmp(tempReg1, tempReg2); + + BPCC.emit(masm, Xcc, NotEqual, NOT_ANNUL, PREDICT_NOT_TAKEN, falseLabel); + // Delay slot, not annul, add for next iteration + masm.addcc(length, VECTOR_SIZE, length); + // Annul, to prevent access past the array + BPCC.emit(masm, Xcc, NotEqual, ANNUL, PREDICT_TAKEN, loop); + masm.ldx(new SPARCAddress(array1, length), tempReg1); // Load in delay slot + + // Tail count zero, therefore we can go to the end + masm.compareBranch(result, 0, Equal, Xcc, trueLabel, PREDICT_TAKEN, null); + + masm.bind(compareTailCorrectVectorEnd); + // Correct the array pointers + masm.add(array1, VECTOR_SIZE, array1); + masm.add(array2, VECTOR_SIZE, array2); + + masm.bind(compareTail); + } + + /** + * Emits code to compare the remaining 1 to 4 bytes. + */ + private void emitTailCompares(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Label trueLabel, Label falseLabel) { + Label compare2Bytes = new Label(); + Label compare1Byte = new Label(); + + Register tempReg1 = asRegister(temp3); + Register tempReg2 = asRegister(temp4); + + if (kind.getByteCount() <= 4) { + // Compare trailing 4 bytes, if any. + masm.compareBranch(result, 4, Less, Xcc, compare2Bytes, PREDICT_NOT_TAKEN, null); + + masm.lduw(new SPARCAddress(array1, 0), tempReg1); + masm.lduw(new SPARCAddress(array2, 0), tempReg2); + masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_NOT_TAKEN, null); + + if (kind.getByteCount() <= 2) { + // Move array pointers forward. + masm.add(array1, 4, array1); + masm.add(array2, 4, array2); + masm.sub(result, 4, result); + + // Compare trailing 2 bytes, if any. + masm.bind(compare2Bytes); + + masm.compareBranch(result, 2, Less, Xcc, compare1Byte, PREDICT_TAKEN, null); + + masm.lduh(new SPARCAddress(array1, 0), tempReg1); + masm.lduh(new SPARCAddress(array2, 0), tempReg2); + + masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_TAKEN, null); + + // The one-byte tail compare is only required for boolean and byte arrays. + if (kind.getByteCount() <= 1) { + // Move array pointers forward before we compare the last trailing byte. + masm.add(array1, 2, array1); + masm.add(array2, 2, array2); + masm.sub(result, 2, result); + + // Compare trailing byte, if any. + masm.bind(compare1Byte); + masm.compareBranch(result, 1, NotEqual, Xcc, trueLabel, PREDICT_TAKEN, null); + + masm.ldub(new SPARCAddress(array1, 0), tempReg1); + masm.ldub(new SPARCAddress(array2, 0), tempReg2); + masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_TAKEN, null); + } else { + masm.bind(compare1Byte); + } + } else { + masm.bind(compare2Bytes); + } + } + } + + private static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBitManipulationOp.java 2016-12-07 13:54:36.973960566 -0800 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2012, 2015, 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.lir.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARCKind.WORD; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +public final class SPARCBitManipulationOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCBitManipulationOp.class); + + public enum IntrinsicOpcode { + IBSR(SizeEstimate.create(13)), + LBSR(SizeEstimate.create(14)), + BSF(SizeEstimate.create(4)); + + final SizeEstimate size; + + IntrinsicOpcode(SizeEstimate size) { + this.size = size; + } + } + + @Opcode private final IntrinsicOpcode opcode; + @Def protected AllocatableValue result; + @Alive({REG}) protected AllocatableValue input; + @Temp({REG}) protected Value scratch; + + public SPARCBitManipulationOp(IntrinsicOpcode opcode, AllocatableValue result, AllocatableValue input, LIRGeneratorTool gen) { + super(TYPE, opcode.size); + this.opcode = opcode; + this.result = result; + this.input = input; + scratch = gen.newVariable(LIRKind.combine(input)); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Register dst = asRegister(result, WORD); + if (isRegister(input)) { + Register src = asRegister(input); + switch (opcode) { + case BSF: + PlatformKind tkind = input.getPlatformKind(); + if (tkind == WORD) { + masm.sub(src, 1, dst); + masm.andn(dst, src, dst); + masm.srl(dst, g0, dst); + masm.popc(dst, dst); + } else if (tkind == XWORD) { + masm.sub(src, 1, dst); + masm.andn(dst, src, dst); + masm.popc(dst, dst); + } else { + throw GraalError.shouldNotReachHere("missing: " + tkind); + } + break; + case IBSR: { + PlatformKind ikind = input.getPlatformKind(); + assert ikind == WORD; + Register tmp = asRegister(scratch); + assert !tmp.equals(dst); + masm.srl(src, 1, tmp); + masm.srl(src, 0, dst); + masm.or(dst, tmp, dst); + masm.srl(dst, 2, tmp); + masm.or(dst, tmp, dst); + masm.srl(dst, 4, tmp); + masm.or(dst, tmp, dst); + masm.srl(dst, 8, tmp); + masm.or(dst, tmp, dst); + masm.srl(dst, 16, tmp); + masm.or(dst, tmp, dst); + masm.popc(dst, dst); + masm.sub(dst, 1, dst); + break; + } + case LBSR: { + PlatformKind lkind = input.getPlatformKind(); + assert lkind == XWORD; + Register tmp = asRegister(scratch); + assert !tmp.equals(dst); + masm.srlx(src, 1, tmp); + masm.or(src, tmp, dst); + masm.srlx(dst, 2, tmp); + masm.or(dst, tmp, dst); + masm.srlx(dst, 4, tmp); + masm.or(dst, tmp, dst); + masm.srlx(dst, 8, tmp); + masm.or(dst, tmp, dst); + masm.srlx(dst, 16, tmp); + masm.or(dst, tmp, dst); + masm.srlx(dst, 32, tmp); + masm.or(dst, tmp, dst); + masm.popc(dst, dst); + masm.sub(dst, 1, dst); // This is required to fit the given structure. + break; + } + default: + throw GraalError.shouldNotReachHere(); + + } + } else { + throw GraalError.shouldNotReachHere(); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBlockEndOp.java 2016-12-07 13:54:37.235972080 -0800 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.sparc; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.StandardOp.AbstractBlockEndOp; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +public abstract class SPARCBlockEndOp extends AbstractBlockEndOp implements SPARCLIRInstructionMixin { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCBlockEndOp.class); + private final SPARCLIRInstructionMixinStore store; + + protected SPARCBlockEndOp(LIRInstructionClass c) { + this(c, null); + } + + protected SPARCBlockEndOp(LIRInstructionClass c, SizeEstimate sizeEstimate) { + super(c); + store = new SPARCLIRInstructionMixinStore(sizeEstimate); + } + + @Override + public SPARCLIRInstructionMixinStore getSPARCLIRInstructionStore() { + return store; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + emitCode(crb, (SPARCMacroAssembler) crb.asm); + } + + protected abstract void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm); +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBreakpointOp.java 2016-12-07 13:54:37.501983772 -0800 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2012, 2015, 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.lir.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; + +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.meta.Value; + +/** + * Emits a breakpoint. + */ +@Opcode("BREAKPOINT") +public final class SPARCBreakpointOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCBreakpointOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(1); + + // historical - from hotspot src/cpu/sparc/vm + // promises that the system will not use traps 16-31 + // We want to use ST_BREAKPOINT here, but the debugger is confused by it. + public static final int ST_RESERVED_FOR_USER_0 = 0x10; + + /** + * A set of values loaded into the Java ABI parameter locations (for inspection by a debugger). + */ + @Use({REG, STACK}) protected Value[] parameters; + + public SPARCBreakpointOp(Value[] parameters) { + super(TYPE, SIZE); + this.parameters = parameters; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + masm.ta(ST_RESERVED_FOR_USER_0); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCByteSwapOp.java 2016-12-07 13:54:37.784996210 -0800 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARCKind.WORD; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; + +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.Asi; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.ValueUtil; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.sparc.SPARCKind; + +@Opcode("BSWAP") +public final class SPARCByteSwapOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCByteSwapOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(3); + @Def({REG, HINT}) protected Value result; + @Use({REG}) protected Value input; + @Temp({REG}) protected Value tempIndex; + @Use({STACK, UNINITIALIZED}) protected AllocatableValue tmpSlot; + + public SPARCByteSwapOp(LIRGeneratorTool tool, Value result, Value input) { + super(TYPE, SIZE); + this.result = result; + this.input = input; + this.tmpSlot = tool.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(XWORD)); + this.tempIndex = tool.newVariable(LIRKind.value(XWORD)); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + SPARCAddress addr = (SPARCAddress) crb.asAddress(tmpSlot); + SPARCMove.emitStore(input, addr, result.getPlatformKind(), SPARCDelayedControlTransfer.DUMMY, null, crb, masm); + if (addr.getIndex().equals(Register.None)) { + Register tempReg = ValueUtil.asRegister(tempIndex, XWORD); + masm.setx(addr.getDisplacement(), tempReg, false); + addr = new SPARCAddress(addr.getBase(), tempReg); + } + getDelayedControlTransfer().emitControlTransfer(crb, masm); + switch ((SPARCKind) input.getPlatformKind()) { + case WORD: + masm.lduwa(addr.getBase(), addr.getIndex(), asRegister(result, WORD), Asi.ASI_PRIMARY_LITTLE); + break; + case XWORD: + masm.ldxa(addr.getBase(), addr.getIndex(), asRegister(result, XWORD), Asi.ASI_PRIMARY_LITTLE); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCCall.java 2016-12-07 13:54:38.049007813 -0800 @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2013, 2015, 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.lir.sparc; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.sparc.SPARC.o7; + +import org.graalvm.compiler.asm.sparc.SPARCAddress; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.InvokeTarget; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Value; + +public class SPARCCall { + + public abstract static class CallOp extends SPARCLIRInstruction { + @Def({REG, ILLEGAL}) protected Value result; + @Use({REG, STACK}) protected Value[] parameters; + @Temp({REG, STACK}) protected Value[] temps; + @State protected LIRFrameState state; + + protected CallOp(LIRInstructionClass c, SizeEstimate size, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(c, size); + this.result = result; + this.parameters = parameters; + this.state = state; + this.temps = addStackSlotsToTemporaries(parameters, temps); + assert temps != null; + } + + @Override + public boolean destroysCallerSavedRegisters() { + return true; + } + } + + public abstract static class MethodCallOp extends CallOp { + + protected final ResolvedJavaMethod callTarget; + + protected MethodCallOp(LIRInstructionClass c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(c, size, result, parameters, temps, state); + this.callTarget = callTarget; + } + + } + + @Opcode("CALL_DIRECT") + public abstract static class DirectCallOp extends MethodCallOp { + private boolean emitted = false; + private int before = -1; + + public DirectCallOp(LIRInstructionClass c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(c, size, callTarget, result, parameters, temps, state); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + if (!emitted) { + emitCallPrefixCode(crb, masm); + directCall(crb, masm, callTarget, null, state); + } else { + int after = masm.position(); + if (after - before == 4) { + masm.nop(); + } else if (after - before == 8) { + // everything is fine; + } else { + GraalError.shouldNotReachHere("" + (after - before)); + } + after = masm.position(); + crb.recordDirectCall(before, after, callTarget, state); + crb.recordExceptionHandlers(after, state); + masm.ensureUniquePC(); + } + } + + @SuppressWarnings("unused") + public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + // + } + + public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + assert !emitted; + emitCallPrefixCode(crb, masm); + before = masm.call(0); + emitted = true; + } + + public void resetState() { + emitted = false; + before = -1; + } + } + + @Opcode("CALL_INDIRECT") + public abstract static class IndirectCallOp extends MethodCallOp { + @Use({REG}) protected Value targetAddress; + + protected IndirectCallOp(LIRInstructionClass c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, + Value targetAddress, LIRFrameState state) { + super(c, size, callTarget, result, parameters, temps, state); + this.targetAddress = targetAddress; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + indirectCall(crb, masm, asRegister(targetAddress), callTarget, state); + } + + @Override + public void verify() { + super.verify(); + assert isRegister(targetAddress) : "The current register allocator cannot handle variables to be used at call sites, it must be in a fixed register for now"; + } + } + + public abstract static class ForeignCallOp extends CallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ForeignCallOp.class); + + protected final ForeignCallLinkage callTarget; + + public ForeignCallOp(LIRInstructionClass c, SizeEstimate size, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(c, size, result, parameters, temps, state); + this.callTarget = callTarget; + } + + @Override + public boolean destroysCallerSavedRegisters() { + return callTarget.destroysRegisters(); + } + } + + @Opcode("NEAR_FOREIGN_CALL") + public static final class DirectNearForeignCallOp extends ForeignCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(1); + + public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(TYPE, SIZE, linkage, result, parameters, temps, state); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + directCall(crb, masm, callTarget, null, state); + } + } + + @Opcode("FAR_FOREIGN_CALL") + public static final class DirectFarForeignCallOp extends ForeignCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(1); + + public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(TYPE, SIZE, callTarget, result, parameters, temps, state); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + try (ScratchRegister scratch = masm.getScratchRegister()) { + directCall(crb, masm, callTarget, scratch.getRegister(), state); + } + } + } + + public static void directCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info) { + int before; + if (scratch != null) { + // offset might not fit a 30-bit displacement, generate an + // indirect call with a 64-bit immediate + before = masm.position(); + masm.sethix(0L, scratch, true); + masm.jmpl(scratch, 0, o7); + } else { + before = masm.call(0); + } + masm.nop(); // delay slot + int after = masm.position(); + crb.recordDirectCall(before, after, callTarget, info); + crb.recordExceptionHandlers(after, info); + masm.ensureUniquePC(); + } + + public static void indirectJmp(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget target) { + int before = masm.position(); + masm.sethix(0L, dst, true); + masm.jmp(new SPARCAddress(dst, 0)); + masm.nop(); // delay slot + int after = masm.position(); + crb.recordIndirectCall(before, after, target, null); + masm.ensureUniquePC(); + } + + public static void indirectCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { + int before = masm.jmpl(dst, 0, o7); + masm.nop(); // delay slot + int after = masm.position(); + crb.recordIndirectCall(before, after, callTarget, info); + crb.recordExceptionHandlers(after, info); + masm.ensureUniquePC(); + } +} --- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java 2016-12-07 13:54:38.313019415 -0800 @@ -0,0 +1,754 @@ +/* + * Copyright (c) 2013, 2016, 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.lir.sparc; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.INSTRUCTION_SIZE; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm10; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm11; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm5; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Icc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Always; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Equal; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Greater; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_GreaterOrEqual; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Less; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_LessOrEqual; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedGreaterOrEqual; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrEqual; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrGreater; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrLess; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrLessOrEqual; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Greater; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.GreaterEqual; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.GreaterEqualUnsigned; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.GreaterUnsigned; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Less; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.LessEqual; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.LessEqualUnsigned; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.LessUnsigned; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static org.graalvm.compiler.lir.sparc.SPARCMove.const2reg; +import static org.graalvm.compiler.lir.sparc.SPARCOP3Op.emitOp3; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.CPU; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARCKind.WORD; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.graalvm.compiler.asm.Assembler; +import org.graalvm.compiler.asm.Assembler.LabelHint; +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.NumUtil; +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.CMOV; +import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.LabelRef; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.StandardOp; +import org.graalvm.compiler.lir.SwitchStrategy; +import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure; +import org.graalvm.compiler.lir.Variable; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.sparc.SPARC.CPUFeature; +import jdk.vm.ci.sparc.SPARCKind; + +public class SPARCControlFlow { + // This describes the maximum offset between the first emitted (load constant in to scratch, + // if does not fit into simm5 of cbcond) instruction and the final branch instruction + private static final int maximumSelfOffsetInstructions = 2; + + public static final class ReturnOp extends SPARCBlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ReturnOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(2); + + @Use({REG, ILLEGAL}) protected Value x; + + public ReturnOp(Value x) { + super(TYPE, SIZE); + this.x = x; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + emitCodeHelper(crb, masm); + } + + public static void emitCodeHelper(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + masm.ret(); + // On SPARC we always leave the frame (in the delay slot). + crb.frameContext.leave(crb); + } + } + + public static final class CompareBranchOp extends SPARCBlockEndOp implements SPARCDelayedControlTransfer { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareBranchOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(3); + static final EnumSet SUPPORTED_KINDS = EnumSet.of(XWORD, WORD); + + @Use({REG}) protected Value x; + @Use({REG, CONST}) protected Value y; + private ConditionFlag conditionFlag; + protected final LabelRef trueDestination; + protected LabelHint trueDestinationHint; + protected final LabelRef falseDestination; + protected LabelHint falseDestinationHint; + protected final SPARCKind kind; + protected final boolean unorderedIsTrue; + private boolean emitted = false; + private int delaySlotPosition = -1; + private double trueDestinationProbability; + + public CompareBranchOp(Value x, Value y, Condition condition, LabelRef trueDestination, LabelRef falseDestination, SPARCKind kind, boolean unorderedIsTrue, double trueDestinationProbability) { + super(TYPE, SIZE); + this.x = x; + this.y = y; + this.trueDestination = trueDestination; + this.falseDestination = falseDestination; + this.kind = kind; + this.unorderedIsTrue = unorderedIsTrue; + this.trueDestinationProbability = trueDestinationProbability; + conditionFlag = fromCondition(kind.isInteger(), condition, unorderedIsTrue); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + if (emitted) { // Only if delayed control transfer is used we must check this + assert masm.position() - delaySlotPosition == 4 : "Only one instruction can be stuffed into the delay slot"; + } + if (!emitted) { + requestHints(masm); + int targetPosition = getTargetPosition(masm); + if (canUseShortBranch(crb, masm, targetPosition)) { + emitted = emitShortCompareBranch(crb, masm); + } + if (!emitted) { // No short compare/branch was used, so we go into fallback + emitted = emitLongCompareBranch(crb, masm, true); + emitted = true; + } + } + assert emitted; + } + + private boolean emitLongCompareBranch(CompilationResultBuilder crb, SPARCMacroAssembler masm, boolean withDelayedNop) { + emitOp3(masm, Subcc, x, y); + return emitBranch(crb, masm, kind, conditionFlag, trueDestination, falseDestination, withDelayedNop, trueDestinationProbability); + } + + private static int getTargetPosition(Assembler asm) { + return asm.position() + maximumSelfOffsetInstructions * asm.target.wordSize; + } + + @Override + public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + requestHints(masm); + // When we use short branches, no delay slot is available + int targetPosition = getTargetPosition(masm); + if (!canUseShortBranch(crb, masm, targetPosition)) { + emitted = emitLongCompareBranch(crb, masm, false); + if (emitted) { + delaySlotPosition = masm.position(); + } + } + } + + private void requestHints(SPARCMacroAssembler masm) { + if (trueDestinationHint == null) { + this.trueDestinationHint = masm.requestLabelHint(trueDestination.label()); + } + if (falseDestinationHint == null) { + this.falseDestinationHint = masm.requestLabelHint(falseDestination.label()); + } + } + + /** + * Tries to use the emit the compare/branch instruction. + *

    + * CBcond has follwing limitations + *

      + *
    • Immediate field is only 5 bit and is on the right + *
    • Jump offset is maximum of -+512 instruction + * + *

      + * We get from outside + *

        + *
      • at least one of trueDestination falseDestination is within reach of +-512 + * instructions + *
      • two registers OR one register and a constant which fits simm13 + * + *

        + * We do: + *

          + *
        • find out which target needs to be branched conditionally + *
        • find out if fall-through is possible, if not, a unconditional branch is needed after + * cbcond (needJump=true) + *
        • if no fall through: we need to put the closer jump into the cbcond branch and the + * farther into the jmp (unconditional branch) + *
        • if constant on the left side, mirror to be on the right + *
        • if constant on right does not fit into simm5, put it into a scratch register + * + * @param crb + * @param masm + * @return true if the branch could be emitted + */ + private boolean emitShortCompareBranch(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + ConditionFlag actualConditionFlag = conditionFlag; + Label actualTrueTarget = trueDestination.label(); + Label actualFalseTarget = falseDestination.label(); + Label tmpTarget; + boolean needJump; + if (crb.isSuccessorEdge(trueDestination)) { + actualConditionFlag = conditionFlag.negate(); + tmpTarget = actualTrueTarget; + actualTrueTarget = actualFalseTarget; + actualFalseTarget = tmpTarget; + needJump = false; + } else { + needJump = !crb.isSuccessorEdge(falseDestination); + int targetPosition = getTargetPosition(masm); + if (needJump && !isShortBranch(masm, targetPosition, trueDestinationHint, actualTrueTarget)) { + // we have to jump in either way, so we must put the shorter + // branch into the actualTarget as only one of the two jump targets + // is guaranteed to be simm10 + actualConditionFlag = actualConditionFlag.negate(); + tmpTarget = actualTrueTarget; + actualTrueTarget = actualFalseTarget; + actualFalseTarget = tmpTarget; + } + } + emitCBCond(masm, x, y, actualTrueTarget, actualConditionFlag); + if (needJump) { + masm.jmp(actualFalseTarget); + masm.nop(); + } + return true; + } + + private void emitCBCond(SPARCMacroAssembler masm, Value actualX, Value actualY, Label actualTrueTarget, ConditionFlag cFlag) { + PlatformKind xKind = actualX.getPlatformKind(); + boolean isLong = kind == SPARCKind.XWORD; + if (isJavaConstant(actualY)) { + JavaConstant c = asJavaConstant(actualY); + long constantY = c.isNull() ? 0 : c.asLong(); + assert NumUtil.isInt(constantY); + CBCOND.emit(masm, cFlag, isLong, asRegister(actualX, xKind), (int) constantY, actualTrueTarget); + } else { + CBCOND.emit(masm, cFlag, isLong, asRegister(actualX, xKind), asRegister(actualY, xKind), actualTrueTarget); + } + } + + private boolean canUseShortBranch(CompilationResultBuilder crb, SPARCAssembler asm, int position) { + if (!asm.hasFeature(CPUFeature.CBCOND)) { + return false; + } + if (!((SPARCKind) x.getPlatformKind()).isInteger()) { + return false; + } + // Do not use short branch, if the y value is a constant and does not fit into simm5 but + // fits into simm13; this means the code with CBcond would be longer as the code without + // CBcond. + if (isJavaConstant(y) && !isSimm5(asJavaConstant(y)) && isSimm13(asJavaConstant(y))) { + return false; + } + boolean hasShortJumpTarget = false; + if (!crb.isSuccessorEdge(trueDestination)) { + hasShortJumpTarget |= isShortBranch(asm, position, trueDestinationHint, trueDestination.label()); + } + if (!crb.isSuccessorEdge(falseDestination)) { + hasShortJumpTarget |= isShortBranch(asm, position, falseDestinationHint, falseDestination.label()); + } + return hasShortJumpTarget; + } + + @Override + public void resetState() { + emitted = false; + delaySlotPosition = -1; + } + + @Override + public void verify() { + super.verify(); + assert SUPPORTED_KINDS.contains(kind) : kind; + assert !isConstantValue(x); + assert x.getPlatformKind().equals(kind) && (isConstantValue(y) || y.getPlatformKind().equals(kind)) : x + " " + y; + } + } + + public static boolean isShortBranch(SPARCAssembler asm, int position, LabelHint hint, Label label) { + int disp = 0; + boolean dispValid = true; + if (label.isBound()) { + disp = label.position() - position; + } else if (hint != null && hint.isValid()) { + disp = hint.getTarget() - hint.getPosition(); + } else { + dispValid = false; + } + if (dispValid) { + if (disp < 0) { + disp -= maximumSelfOffsetInstructions * asm.target.wordSize; + } else { + disp += maximumSelfOffsetInstructions * asm.target.wordSize; + } + return isSimm10(disp >> 2); + } else if (hint == null) { + asm.requestLabelHint(label); + } + return false; + } + + public static final class BranchOp extends SPARCBlockEndOp implements StandardOp.BranchOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BranchOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(2); + protected final ConditionFlag conditionFlag; + protected final LabelRef trueDestination; + protected final LabelRef falseDestination; + protected final SPARCKind kind; + protected final double trueDestinationProbability; + + public BranchOp(ConditionFlag conditionFlag, LabelRef trueDestination, LabelRef falseDestination, SPARCKind kind, double trueDestinationProbability) { + super(TYPE, SIZE); + this.trueDestination = trueDestination; + this.falseDestination = falseDestination; + this.kind = kind; + this.conditionFlag = conditionFlag; + this.trueDestinationProbability = trueDestinationProbability; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + emitBranch(crb, masm, kind, conditionFlag, trueDestination, falseDestination, true, trueDestinationProbability); + } + } + + private static boolean emitBranch(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCKind kind, ConditionFlag conditionFlag, LabelRef trueDestination, LabelRef falseDestination, + boolean withDelayedNop, double trueDestinationProbability) { + Label actualTarget; + ConditionFlag actualConditionFlag; + boolean needJump; + BranchPredict predictTaken; + if (falseDestination != null && crb.isSuccessorEdge(trueDestination)) { + actualConditionFlag = conditionFlag != null ? conditionFlag.negate() : null; + actualTarget = falseDestination.label(); + needJump = false; + predictTaken = trueDestinationProbability < .5d ? PREDICT_TAKEN : PREDICT_NOT_TAKEN; + } else { + actualConditionFlag = conditionFlag; + actualTarget = trueDestination.label(); + needJump = falseDestination != null && !crb.isSuccessorEdge(falseDestination); + predictTaken = trueDestinationProbability > .5d ? PREDICT_TAKEN : PREDICT_NOT_TAKEN; + } + if (!withDelayedNop && needJump) { + // We cannot make use of the delay slot when we jump in true-case and false-case + return false; + } + if (kind.isFloat()) { + FBPCC.emit(masm, Fcc0, actualConditionFlag, NOT_ANNUL, predictTaken, actualTarget); + } else { + assert kind.isInteger(); + CC cc = kind.equals(WORD) ? Icc : Xcc; + BPCC.emit(masm, cc, actualConditionFlag, NOT_ANNUL, predictTaken, actualTarget); + } + if (withDelayedNop) { + masm.nop(); // delay slot + } + if (needJump) { + masm.jmp(falseDestination.label()); + } + return true; + } + + public static class StrategySwitchOp extends SPARCBlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StrategySwitchOp.class); + protected Constant[] keyConstants; + private final LabelRef[] keyTargets; + private LabelRef defaultTarget; + @Alive({REG}) protected Value key; + @Alive({REG, ILLEGAL}) protected Value constantTableBase; + @Temp({REG}) protected Value scratch; + protected final SwitchStrategy strategy; + private final Map labelHints; + private final List