From 34a8671fdc185288fd326ec1a234e8d221e924e5 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Thu, 28 Jul 2022 09:12:52 +0200 Subject: [PATCH 1/2] Add RISC-V LLVM backend for Native Image --- compiler/mx.compiler/mx_compiler.py | 3 +- compiler/mx.compiler/suite.py | 43 +++ .../riscv64/RISCV64LoweringProviderMixin.java | 68 ++++ .../core/riscv64/RISCV64NodeMatchRules.java | 35 +++ .../core/riscv64/RISCV64ReflectionUtil.java | 87 ++++++ .../core/riscv64/ShadowedRISCV64.java | 110 +++++++ .../riscv64/RISCV64HotSpotBackendFactory.java | 193 ++++++++++++ .../RISCV64HotSpotForeignCallsProvider.java | 81 +++++ .../RISCV64HotSpotLoweringProvider.java | 67 ++++ .../hotspot/GraalHotSpotVMConfigAccess.java | 4 +- sdk/mx.sdk/mx_sdk_vm_impl.py | 1 + sdk/mx.sdk/suite.py | 3 + .../org.graalvm.nativeimage/snapshot.sigtest | 14 + .../services/org.graalvm.nativeimage.Platform | 1 + .../src/org/graalvm/nativeimage/Platform.java | 34 ++ substratevm/CHANGELOG.md | 1 + substratevm/mx.substratevm/suite.py | 31 ++ .../com/oracle/objectfile/elf/ELFMachine.java | 126 +++++++- .../oracle/objectfile/elf/ELFObjectFile.java | 14 +- .../svm/core/graal/llvm/LLVMGenerator.java | 6 +- .../core/graal/llvm/util/LLVMIRBuilder.java | 23 +- .../graal/llvm/util/LLVMObjectFileReader.java | 20 +- .../graal/llvm/util/LLVMStackMapInfo.java | 10 +- .../graal/llvm/util/LLVMTargetSpecific.java | 149 +++++++++ .../riscv64/RISCV64ReservedRegisters.java | 51 +++ .../riscv64/SubstrateRISCV64Feature.java | 63 ++++ .../SubstrateRISCV64RegisterConfig.java | 295 ++++++++++++++++++ .../oracle/svm/core/posix/headers/Signal.java | 15 + ...V64LinuxUContextRegisterDumperFeature.java | 121 +++++++ .../RuntimeCPUFeatureCheckImpl.java | 11 +- .../svm/core/graal/GraalConfiguration.java | 4 + .../graal/nodes/VaListInitializationNode.java | 63 ++++ .../aarch64/PosixAArch64VaListSnippets.java | 20 ++ .../amd64/PosixAMD64VaListSnippets.java | 20 ++ .../riscv64/PosixRISCV64VaListSnippets.java | 183 +++++++++++ .../riscv64/RISCV64ArithmeticSnippets.java | 46 +++ .../riscv64/RISCV64NonSnippetLowerings.java | 52 +++ .../riscv64/RISCV64SnippetsFeature.java | 62 ++++ .../core/graal/stackvalue/StackValueNode.java | 16 +- .../core/riscv64/RISCV64CPUFeatureAccess.java | 115 +++++++ .../svm/core/riscv64/RISCV64FrameAccess.java | 72 +++++ .../svm/core/riscv64/RISCV64LibCHelper.java | 86 +++++ .../riscv64/RISCV64LibCHelperDirectives.java | 40 +++ .../hotspot/libgraal/LibGraalFeature.java | 2 +- .../svm/hosted/NativeImageGenerator.java | 25 ++ .../hosted/NativeImageGeneratorRunner.java | 5 +- .../RISCV64CPUFeatureAccessFeature.java | 64 ++++ .../hosted/c/codegen/CCompilerInvoker.java | 3 + .../svm/hosted/image/CCLinkerInvocation.java | 5 + .../jni/JNIJavaCallVariantWrapperMethod.java | 17 +- .../include/riscv64cpufeatures.h | 34 ++ .../src/cpuid.c | 55 +++- .../com/oracle/svm/util/ReflectionUtil.java | 8 + tools/mx.tools/suite.py | 5 +- 54 files changed, 2643 insertions(+), 39 deletions(-) create mode 100644 compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64LoweringProviderMixin.java create mode 100644 compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64NodeMatchRules.java create mode 100644 compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64ReflectionUtil.java create mode 100644 compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/ShadowedRISCV64.java create mode 100644 compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotBackendFactory.java create mode 100644 compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotForeignCallsProvider.java create mode 100644 compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotLoweringProvider.java create mode 100644 substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/RISCV64ReservedRegisters.java create mode 100644 substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64Feature.java create mode 100644 substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64RegisterConfig.java create mode 100644 substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/riscv64/RISCV64LinuxUContextRegisterDumperFeature.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/VaListInitializationNode.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/PosixRISCV64VaListSnippets.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64ArithmeticSnippets.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64NonSnippetLowerings.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64SnippetsFeature.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64CPUFeatureAccess.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64FrameAccess.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64LibCHelper.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64LibCHelperDirectives.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/RISCV64CPUFeatureAccessFeature.java create mode 100644 substratevm/src/com.oracle.svm.native.libchelper/include/riscv64cpufeatures.h diff --git a/compiler/mx.compiler/mx_compiler.py b/compiler/mx.compiler/mx_compiler.py index ad7209fc29ab..8263c99c9d62 100644 --- a/compiler/mx.compiler/mx_compiler.py +++ b/compiler/mx.compiler/mx_compiler.py @@ -620,7 +620,8 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix=''): _registers = { 'amd64': 'rbx,r11,r10,r14,xmm3,xmm2,xmm11,xmm14,k1?', - 'aarch64': 'r0,r1,r2,r3,r4,v0,v1,v2,v3' + 'aarch64': 'r0,r1,r2,r3,r4,v0,v1,v2,v3', + 'riscv64': 'x10,x11,x12,x13,x14,v10,v11,v12,v13' } if mx.get_arch() not in _registers: mx.warn('No registers for register pressure tests are defined for architecture ' + mx.get_arch()) diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index 6b8816f043d9..093ecbf8124d 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -167,6 +167,9 @@ "digest" : "sha512:422e1078fe5d9e2f71c04ca2bbefef4e09cf9675d132c7531f1fb17330e2b1f9441470541b66c8db2f3d8e105d167e25a78dc11aada524ed623b1ae9a4cfdeeb", "urls" : ["{urlbase}/hsdis-aarch64-linux-fcc9b70ac91c00db8a50b0d4345490a68e3743e1.tar.gz"], }, + "riscv64" : { + "optional" : True, + } }, "darwin" : { "amd64" : { @@ -681,6 +684,27 @@ "workingSets" : "Graal,HotSpot,AMD64", }, + "org.graalvm.compiler.hotspot.riscv64" : { + "subDir" : "src", + "sourceDirs" : ["src"], + "dependencies" : [ + "org.graalvm.compiler.core.riscv64", + "org.graalvm.compiler.hotspot", + ], + "requiresConcealed" : { + "jdk.internal.vm.ci" : [ + "jdk.vm.ci.meta", + "jdk.vm.ci.code", + ], + }, + "checkstyle" : "org.graalvm.compiler.graph", + "annotationProcessors" : [ + "GRAAL_PROCESSOR" + ], + "javaCompliance" : "11+", + "workingSets" : "Graal,HotSpot,RISCV64", + }, + "org.graalvm.compiler.hotspot.test" : { "subDir" : "src", "sourceDirs" : ["src"], @@ -1389,6 +1413,20 @@ "workingSets" : "Graal,AMD64,Test", }, + "org.graalvm.compiler.core.riscv64" : { + "subDir" : "src", + "sourceDirs" : ["src"], + "dependencies" : [ + "org.graalvm.compiler.core", + ], + "checkstyle" : "org.graalvm.compiler.graph", + "annotationProcessors" : [ + "GRAAL_PROCESSOR", + ], + "javaCompliance" : "11+", + "workingSets" : "Graal,RISCV64", + }, + "org.graalvm.compiler.runtime" : { "subDir" : "src", "sourceDirs" : ["src"], @@ -2110,8 +2148,10 @@ "org.graalvm.compiler.replacements.aarch64", "org.graalvm.compiler.core.amd64", "org.graalvm.compiler.replacements.amd64", + "org.graalvm.compiler.core.riscv64", "org.graalvm.compiler.hotspot.aarch64", "org.graalvm.compiler.hotspot.amd64", + "org.graalvm.compiler.hotspot.riscv64", "org.graalvm.compiler.hotspot", "org.graalvm.compiler.lir.aarch64", "org.graalvm.compiler.truffle.runtime.serviceprovider", @@ -2187,6 +2227,9 @@ "description" : "Disassembler support distribution for the GraalVM", "os_arch" : { "linux" : { + "riscv64" : { + "optional" : True, + }, "" : { "layout" : { "hsdis-.so" : "file:/*", diff --git a/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64LoweringProviderMixin.java b/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64LoweringProviderMixin.java new file mode 100644 index 000000000000..98d104ae70f2 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64LoweringProviderMixin.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +package org.graalvm.compiler.core.riscv64; + +import org.graalvm.compiler.core.common.memory.MemoryExtendKind; +import org.graalvm.compiler.nodes.memory.ExtendableMemoryAccess; +import org.graalvm.compiler.nodes.spi.LoweringProvider; + +public interface RISCV64LoweringProviderMixin extends LoweringProvider { + + @Override + default boolean divisionOverflowIsJVMSCompliant() { + return true; + } + + @Override + default Integer smallestCompareWidth() { + return 32; + } + + @Override + default boolean supportsBulkZeroing() { + return false; + } + + @Override + default boolean supportsRounding() { + return false; + } + + @Override + default boolean writesStronglyOrdered() { + return false; + } + + @Override + default boolean narrowsUseCastValue() { + return false; + } + + @Override + default boolean supportsFoldingExtendIntoAccess(ExtendableMemoryAccess access, MemoryExtendKind extendKind) { + return false; + } +} diff --git a/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64NodeMatchRules.java b/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64NodeMatchRules.java new file mode 100644 index 000000000000..775f2c6ae647 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64NodeMatchRules.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +package org.graalvm.compiler.core.riscv64; + +import org.graalvm.compiler.core.gen.NodeMatchRules; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +public class RISCV64NodeMatchRules extends NodeMatchRules { + public RISCV64NodeMatchRules(LIRGeneratorTool gen) { + super(gen); + } +} diff --git a/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64ReflectionUtil.java b/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64ReflectionUtil.java new file mode 100644 index 000000000000..abca576bb0a4 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/RISCV64ReflectionUtil.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +package org.graalvm.compiler.core.riscv64; + +import java.lang.reflect.Method; + +/** + * This class contains utility methods for accessing RISC-V JVMCI classes and fields using + * reflection. This is needed as all JDK versions used by Graal currently do not implement JVMCI for + * RISC-V, which causes unwanted build errors. + */ +public class RISCV64ReflectionUtil { + public static final String archClass = "jdk.vm.ci.riscv64.RISCV64"; + public static final String featureClass = archClass + "$CPUFeature"; + public static final String flagClass = archClass + "$Flag"; + public static final String hotSpotClass = "jdk.vm.ci.hotspot.riscv64.RISCV64HotSpotRegisterConfig"; + + public static Class lookupClass(boolean optional, String className) { + try { + return Class.forName(className); + } catch (ClassNotFoundException ex) { + if (optional) { + return null; + } + throw new ReflectionUtilError(ex); + } + } + + public static Class getArch(boolean optional) { + return lookupClass(optional, archClass); + } + + @SuppressWarnings("unchecked") + public static T readStaticField(Class declaringClass, String fieldName) { + try { + return (T) declaringClass.getField(fieldName).get(null); + } catch (ReflectiveOperationException ex) { + throw new ReflectionUtilError(ex); + } + } + + @SuppressWarnings("serial") + public static final class ReflectionUtilError extends Error { + private ReflectionUtilError(Throwable cause) { + super(cause); + } + } + + public static Method lookupMethod(Class declaringClass, String methodName, Class... parameterTypes) { + try { + return declaringClass.getDeclaredMethod(methodName, parameterTypes); + } catch (ReflectiveOperationException ex) { + throw new ReflectionUtilError(ex); + } + } + + public static Object invokeMethod(Method method, Object obj, Object... args) { + try { + return method.invoke(obj, args); + } catch (ReflectiveOperationException ex) { + throw new ReflectionUtilError(ex); + } + } +} diff --git a/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/ShadowedRISCV64.java b/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/ShadowedRISCV64.java new file mode 100644 index 000000000000..e7a3fb0798eb --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.riscv64/src/org/graalvm/compiler/core/riscv64/ShadowedRISCV64.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +package org.graalvm.compiler.core.riscv64; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterArray; + +public class ShadowedRISCV64 { + public static final Class riscv64OrNull = RISCV64ReflectionUtil.getArch(true); + + public static final Register x0 = getRegister("x0"); + public static final Register x1 = getRegister("x1"); + public static final Register x2 = getRegister("x2"); + public static final Register x3 = getRegister("x3"); + public static final Register x4 = getRegister("x4"); + public static final Register x5 = getRegister("x5"); + public static final Register x6 = getRegister("x6"); + public static final Register x7 = getRegister("x7"); + public static final Register x8 = getRegister("x8"); + public static final Register x9 = getRegister("x9"); + public static final Register x10 = getRegister("x10"); + public static final Register x11 = getRegister("x11"); + public static final Register x12 = getRegister("x12"); + public static final Register x13 = getRegister("x13"); + public static final Register x14 = getRegister("x14"); + public static final Register x15 = getRegister("x15"); + public static final Register x16 = getRegister("x16"); + public static final Register x17 = getRegister("x17"); + public static final Register x18 = getRegister("x18"); + public static final Register x19 = getRegister("x19"); + public static final Register x20 = getRegister("x20"); + public static final Register x21 = getRegister("x21"); + public static final Register x22 = getRegister("x22"); + public static final Register x23 = getRegister("x23"); + public static final Register x24 = getRegister("x24"); + public static final Register x25 = getRegister("x25"); + public static final Register x26 = getRegister("x26"); + public static final Register x27 = getRegister("x27"); + public static final Register x28 = getRegister("x28"); + public static final Register x29 = getRegister("x29"); + public static final Register x30 = getRegister("x30"); + public static final Register x31 = getRegister("x31"); + + public static final Register f0 = getRegister("f0"); + public static final Register f1 = getRegister("f1"); + public static final Register f2 = getRegister("f2"); + public static final Register f3 = getRegister("f3"); + public static final Register f4 = getRegister("f4"); + public static final Register f5 = getRegister("f5"); + public static final Register f6 = getRegister("f6"); + public static final Register f7 = getRegister("f7"); + public static final Register f8 = getRegister("f8"); + public static final Register f9 = getRegister("f9"); + public static final Register f10 = getRegister("f10"); + public static final Register f11 = getRegister("f11"); + public static final Register f12 = getRegister("f12"); + public static final Register f13 = getRegister("f13"); + public static final Register f14 = getRegister("f14"); + public static final Register f15 = getRegister("f15"); + public static final Register f16 = getRegister("f16"); + public static final Register f17 = getRegister("f17"); + public static final Register f18 = getRegister("f18"); + public static final Register f19 = getRegister("f19"); + public static final Register f20 = getRegister("f20"); + public static final Register f21 = getRegister("f21"); + public static final Register f22 = getRegister("f22"); + public static final Register f23 = getRegister("f23"); + public static final Register f24 = getRegister("f24"); + public static final Register f25 = getRegister("f25"); + public static final Register f26 = getRegister("f26"); + public static final Register f27 = getRegister("f27"); + public static final Register f28 = getRegister("f28"); + public static final Register f29 = getRegister("f29"); + public static final Register f30 = getRegister("f30"); + public static final Register f31 = getRegister("f31"); + + public static final RegisterArray allRegisters = riscv64OrNull == null ? null : RISCV64ReflectionUtil.readStaticField(riscv64OrNull, "allRegisters"); + + public static boolean instanceOf(Architecture arch) { + return ShadowedRISCV64.riscv64OrNull != null && ShadowedRISCV64.riscv64OrNull.isInstance(arch); + } + + private static Register getRegister(String register) { + return riscv64OrNull == null ? null : RISCV64ReflectionUtil.readStaticField(riscv64OrNull, register); + } +} diff --git a/compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotBackendFactory.java b/compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotBackendFactory.java new file mode 100644 index 000000000000..533d3c1d8048 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotBackendFactory.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package org.graalvm.compiler.hotspot.riscv64; + +import java.util.ArrayList; +import java.util.List; + +import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; +import org.graalvm.compiler.core.riscv64.RISCV64ReflectionUtil; +import org.graalvm.compiler.core.riscv64.ShadowedRISCV64; +import org.graalvm.compiler.debug.GraalError; +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.AddressLoweringHotSpotSuitesProvider; +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.HotSpotMetaAccessExtensionProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotPlatformConfigurationProvider; +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.HotSpotSuitesProvider; +import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; +import org.graalvm.compiler.java.DefaultSuitesCreator; +import org.graalvm.compiler.lir.framemap.ReferenceMapBuilder; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.spi.CoreProviders; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.common.AddressLoweringPhase; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +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.HotSpotJVMCIRuntime; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.Value; + +@ServiceProvider(HotSpotBackendFactory.class) +public class RISCV64HotSpotBackendFactory extends HotSpotBackendFactory { + @Override + public String getName() { + return "community"; + } + + @Override + public Class getArchitecture() { + if (ShadowedRISCV64.riscv64OrNull != null) { + return ShadowedRISCV64.riscv64OrNull.asSubclass(Architecture.class); + } else { + return null; + } + } + + @Override + protected Plugins createGraphBuilderPlugins(HotSpotGraalRuntimeProvider graalRuntime, CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, TargetDescription target, + HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls, MetaAccessProvider metaAccess, + HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, OptionValues options) { + Plugins plugins = HotSpotGraphBuilderPlugins.create(graalRuntime, + compilerConfiguration, + config, + wordTypes, + metaAccess, + constantReflection, + snippetReflection, + foreignCalls, + replacements, + options, + target); + return plugins; + } + + @Override + protected HotSpotBackend createBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { + return new HotSpotBackend(runtime, providers) { + @Override + public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) { + throw GraalError.unimplemented(); + } + + @Override + public ReferenceMapBuilder newReferenceMapBuilder(int totalFrameSize) { + throw GraalError.unimplemented(); + } + }; + } + + @Override + protected HotSpotRegistersProvider createRegisters() { + Class riscv64HotSpotRegisterConfig = RISCV64ReflectionUtil.lookupClass(false, RISCV64ReflectionUtil.hotSpotClass); + Register tp = RISCV64ReflectionUtil.readStaticField(riscv64HotSpotRegisterConfig, "tp"); + Register x27 = ShadowedRISCV64.x27; + Register sp = RISCV64ReflectionUtil.readStaticField(riscv64HotSpotRegisterConfig, "sp"); + return new HotSpotRegisters(tp, x27, sp); + } + + @Override + protected HotSpotHostForeignCallsProvider createForeignCalls(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider graalRuntime, MetaAccessProvider metaAccess, + HotSpotCodeCacheProvider codeCache, HotSpotWordTypes wordTypes, Value[] nativeABICallerSaveRegisters) { + return new RISCV64HotSpotForeignCallsProvider(jvmciRuntime, graalRuntime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters); + } + + @Override + protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins, + HotSpotRegistersProvider registers, HotSpotReplacementsImpl replacements, OptionValues options) { + DefaultSuitesCreator suitesCreator = new DefaultSuitesCreator(compilerConfiguration, plugins); + BasePhase addressLoweringPhase = new AddressLoweringPhase(null); + return new AddressLoweringHotSpotSuitesProvider(suitesCreator, config, runtime, addressLoweringPhase); + } + + @Override + protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider graalRuntime, MetaAccessProvider metaAccess, HotSpotHostForeignCallsProvider foreignCalls, + HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, HotSpotPlatformConfigurationProvider platformConfig, + HotSpotMetaAccessExtensionProvider metaAccessExtensionProvider, TargetDescription target) { + return new RISCV64HotSpotLoweringProvider(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, platformConfig, metaAccessExtensionProvider, target); + } + + @Override + protected Value[] createNativeABICallerSaveRegisters(@SuppressWarnings("unused") GraalHotSpotVMConfig config, RegisterConfig regConfig) { + List callerSave = new ArrayList<>(regConfig.getAllocatableRegisters().asList()); + // Removing callee-saved registers. + /* General Purpose Registers. */ + callerSave.remove(ShadowedRISCV64.x2); + callerSave.remove(ShadowedRISCV64.x8); + callerSave.remove(ShadowedRISCV64.x9); + callerSave.remove(ShadowedRISCV64.x18); + callerSave.remove(ShadowedRISCV64.x19); + callerSave.remove(ShadowedRISCV64.x20); + callerSave.remove(ShadowedRISCV64.x21); + callerSave.remove(ShadowedRISCV64.x22); + callerSave.remove(ShadowedRISCV64.x23); + callerSave.remove(ShadowedRISCV64.x24); + callerSave.remove(ShadowedRISCV64.x25); + callerSave.remove(ShadowedRISCV64.x26); + callerSave.remove(ShadowedRISCV64.x27); + /* Floating-Point Registers. */ + callerSave.remove(ShadowedRISCV64.f8); + callerSave.remove(ShadowedRISCV64.f9); + callerSave.remove(ShadowedRISCV64.f18); + callerSave.remove(ShadowedRISCV64.f19); + callerSave.remove(ShadowedRISCV64.f20); + callerSave.remove(ShadowedRISCV64.f21); + callerSave.remove(ShadowedRISCV64.f22); + callerSave.remove(ShadowedRISCV64.f23); + callerSave.remove(ShadowedRISCV64.f24); + callerSave.remove(ShadowedRISCV64.f25); + callerSave.remove(ShadowedRISCV64.f26); + callerSave.remove(ShadowedRISCV64.f27); + + 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 "RISCV64"; + } +} diff --git a/compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotForeignCallsProvider.java b/compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotForeignCallsProvider.java new file mode 100644 index 000000000000..672a70b698d8 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotForeignCallsProvider.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package org.graalvm.compiler.hotspot.riscv64; + +import static jdk.vm.ci.meta.Value.ILLEGAL; +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.HotSpotForeignCallLinkage.JUMP_ADDRESS; +import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_ALL_CALLER_SAVE_REGISTERS; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.riscv64.ShadowedRISCV64; +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.hotspot.word.HotSpotWordTypes; +import org.graalvm.compiler.options.OptionValues; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +public class RISCV64HotSpotForeignCallsProvider extends HotSpotHostForeignCallsProvider { + + private final Value[] nativeABICallerSaveRegisters; + + public RISCV64HotSpotForeignCallsProvider(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider graalRuntime, MetaAccessProvider metaAccess, + HotSpotCodeCacheProvider codeCache, HotSpotWordTypes wordTypes, Value[] nativeABICallerSaveRegisters) { + super(jvmciRuntime, graalRuntime, metaAccess, codeCache, wordTypes); + this.nativeABICallerSaveRegisters = nativeABICallerSaveRegisters; + } + + @Override + public void initialize(HotSpotProviders providers, OptionValues options) { + 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 = ShadowedRISCV64.x10.asValue(LIRKind.reference(word)); + RegisterValue exceptionPc = ShadowedRISCV64.x13.asValue(LIRKind.value(word)); + CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc); + register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, DESTROYS_ALL_CALLER_SAVE_REGISTERS, exceptionCc, null)); + register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, DESTROYS_ALL_CALLER_SAVE_REGISTERS, exceptionCc, null)); + + super.initialize(providers, options); + } + + @Override + public Value[] getNativeABICallerSaveRegisters() { + return nativeABICallerSaveRegisters; + } +} diff --git a/compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotLoweringProvider.java b/compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotLoweringProvider.java new file mode 100644 index 000000000000..3a2d9d98d24d --- /dev/null +++ b/compiler/src/org.graalvm.compiler.hotspot.riscv64/src/org/graalvm/compiler/hotspot/riscv64/RISCV64HotSpotLoweringProvider.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package org.graalvm.compiler.hotspot.riscv64; + +import org.graalvm.compiler.core.riscv64.RISCV64LoweringProviderMixin; +import org.graalvm.compiler.debug.DebugHandlersFactory; +import org.graalvm.compiler.debug.GraalError; +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.HotSpotHostForeignCallsProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotMetaAccessExtensionProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotPlatformConfigurationProvider; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.hotspot.replacements.HotSpotAllocationSnippets; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.options.OptionValues; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; + +public class RISCV64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider implements RISCV64LoweringProviderMixin { + + public RISCV64HotSpotLoweringProvider(HotSpotGraalRuntimeProvider graalRuntime, MetaAccessProvider metaAccess, HotSpotHostForeignCallsProvider foreignCalls, + HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, HotSpotPlatformConfigurationProvider platformConfig, + HotSpotMetaAccessExtensionProvider metaAccessExtensionProvider, TargetDescription target) { + super(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, platformConfig, metaAccessExtensionProvider, target); + } + + @Override + public void initialize(OptionValues options, Iterable factories, HotSpotProviders providers, GraalHotSpotVMConfig config, + HotSpotAllocationSnippets.Templates allocationSnippetTemplates) { + + super.initialize(options, factories, providers, config, allocationSnippetTemplates); + } + + @Override + public void lower(Node n, LoweringTool tool) { + throw GraalError.unimplemented(); + } + +} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigAccess.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigAccess.java index 8310ff097d45..9791ea11ab0c 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigAccess.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,7 +110,7 @@ protected static String getProperty(String name) { return getProperty(name, null); } - public static final Set KNOWN_ARCHITECTURES = new HashSet<>(Arrays.asList("amd64", "aarch64")); + public static final Set KNOWN_ARCHITECTURES = new HashSet<>(Arrays.asList("amd64", "aarch64", "riscv64")); public static final Set KNOWN_OS_NAMES = new HashSet<>(Arrays.asList("windows", "linux", "darwin")); /** diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index 88d530ac414b..389d096d8bda 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -3555,6 +3555,7 @@ def graalvm_vendor_version(graalvm_dist): mx.add_argument('--no-licenses', action='store_true', help='Do not add license files in the archives.') mx.add_argument('--base-jdk-info', action='store', help='Colon-separated tuple of base JDK `NAME:VERSION`, to be added on deployment to the \'basejdk\' attribute of the \'suite-revisions.xml\' file on maven-deployment.') mx.add_argument('--graalvm-skip-archive', action='store_true', help='Do not archive GraalVM distributions.') +mx.add_argument('--svmtest-target-arch', action='store', dest='svmtest_target_arch', help='specify targeted arch for GraalVM output', default=mx.get_arch()) def _parse_cmd_arg(arg_name, env_var_name=None, separator=',', parse_bool=True, default_value=None): diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index 452d24fe638e..b672c3671184 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -107,6 +107,9 @@ "aarch64" : { "digest" : "sha512:75d9c41cc3861a021a38f78992c018713c3a06adaa2b343a62fb048596f080d26e4583cafc95cbf3747f9637b22c8156353a6557c6738cf0e68f671b549f31e3", "urls": ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/upx/upx-3.96-arm64_linux.tar.gz"], + }, + "" : { + "optional": True, } }, "windows" : { diff --git a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest index ab4d849c3711..dffd346fcb74 100644 --- a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest +++ b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest @@ -245,12 +245,14 @@ innr public abstract interface static LINUX innr public abstract interface static LINUX_AARCH64_BASE innr public abstract interface static LINUX_AMD64_BASE innr public abstract interface static MACOS +innr public abstract interface static RISCV64 innr public abstract interface static WINDOWS innr public final static ANDROID_AARCH64 innr public final static HOSTED_ONLY innr public final static IOS_AARCH64 innr public final static IOS_AMD64 innr public final static LINUX_AARCH64 +innr public final static LINUX_RISCV64 innr public final static MACOS_AARCH64 innr public final static MACOS_AMD64 innr public final static WINDOWS_AARCH64 @@ -353,6 +355,13 @@ CLSS public abstract interface static org.graalvm.nativeimage.Platform$LINUX_AMD intf org.graalvm.nativeimage.Platform$AMD64 intf org.graalvm.nativeimage.Platform$LINUX +CLSS public final static org.graalvm.nativeimage.Platform$LINUX_RISCV64 + outer org.graalvm.nativeimage.Platform +cons public init() +intf org.graalvm.nativeimage.Platform$LINUX +intf org.graalvm.nativeimage.Platform$RISCV64 +supr java.lang.Object + CLSS public abstract interface static org.graalvm.nativeimage.Platform$MACOS outer org.graalvm.nativeimage.Platform intf org.graalvm.nativeimage.Platform$DARWIN @@ -372,6 +381,11 @@ intf org.graalvm.nativeimage.Platform$DARWIN_AMD64 intf org.graalvm.nativeimage.Platform$MACOS supr java.lang.Object +CLSS public abstract interface static org.graalvm.nativeimage.Platform$RISCV64 + outer org.graalvm.nativeimage.Platform +intf org.graalvm.nativeimage.Platform +meth public java.lang.String getArchitecture() + CLSS public abstract interface static org.graalvm.nativeimage.Platform$WINDOWS outer org.graalvm.nativeimage.Platform intf org.graalvm.nativeimage.impl.InternalPlatform$NATIVE_ONLY diff --git a/sdk/src/org.graalvm.nativeimage/src/META-INF/services/org.graalvm.nativeimage.Platform b/sdk/src/org.graalvm.nativeimage/src/META-INF/services/org.graalvm.nativeimage.Platform index 31f89e6b5f11..91aca6bc88ef 100644 --- a/sdk/src/org.graalvm.nativeimage/src/META-INF/services/org.graalvm.nativeimage.Platform +++ b/sdk/src/org.graalvm.nativeimage/src/META-INF/services/org.graalvm.nativeimage.Platform @@ -1,5 +1,6 @@ org.graalvm.nativeimage.Platform$LINUX_AMD64 org.graalvm.nativeimage.Platform$LINUX_AARCH64 +org.graalvm.nativeimage.Platform$LINUX_RISCV64 org.graalvm.nativeimage.Platform$ANDROID_AARCH64 org.graalvm.nativeimage.Platform$IOS_AMD64 org.graalvm.nativeimage.Platform$IOS_AARCH64 diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/Platform.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/Platform.java index 098ed211296c..77cda7dcd848 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/Platform.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/Platform.java @@ -146,6 +146,23 @@ default String getArchitecture() { } } + /** + * Supported architecture: RISC-V 64-bit. + * + * @since 22.2 + */ + interface RISCV64 extends Platform { + + /** + * Returns string representing RISCV64 architecture. + * + * @since 22.2 + */ + default String getArchitecture() { + return "riscv64"; + } + } + /* * The standard operating systems that are supported. */ @@ -311,6 +328,23 @@ public LINUX_AARCH64() { } + /** + * Supported leaf platform: Linux on RISC-V 64-bit. + * + * @since 22.2 + */ + final class LINUX_RISCV64 implements LINUX, RISCV64 { + + /** + * Instantiates a marker instance of this platform. + * + * @since 22.2 + */ + public LINUX_RISCV64() { + } + + } + /** * Supported leaf platform: Android on AArch64 64-bit. * diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 0af3681b309e..14b2e87f6cf2 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -13,6 +13,7 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-34179) Improved debugging support on Windows: Debug information now includes information about Java types (contributed by Red Hat). * (GR-41096) Support services loaded through the `java.util.ServiceLoader.ModuleServicesLookupIterator`. An example of such service is the `com.sun.jndi.rmi.registry.RegistryContextFactory`. * (GR-41912) The builder now generated reports for internal errors, which users can share when creating issues. By default, error reports follow the `svm_err_b__pid.md` pattern and are created in the working directory. Use `-H:ErrorFile` to adjust the path or filename. +* (GR-36951) Add [RISC-V support](https://medium.com/p/899be38eddd9) for Native Image through the LLVM backend. ## Version 22.3.0 * (GR-35721) Remove old build output style and the `-H:±BuildOutputUseNewStyle` option. diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 45f24bb3817e..e14c599c5d93 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -108,6 +108,11 @@ "urls": ["{urlbase}/llvm-shadowed-13.0.1-1.5.7_1-linux-arm64.jar"], "moduleName" : "com.oracle.svm.shadowed.org.bytedeco.llvm.linux.arm64" }, + "riscv64": { + "sha1": "51762767783b9997474397cfac1e5d1a0ad59e2f", + "urls": ["{urlbase}/llvm-shadowed-13.0.1-1.5.7-linux-riscv64.jar"], + "moduleName" : "com.oracle.svm.shadowed.org.bytedeco.llvm.linux.riscv64" + }, "": { "optional": True, }, @@ -144,6 +149,11 @@ "urls": ["{urlbase}/javacpp-shadowed-1.5.7_1-linux-arm64.jar"], "moduleName" : "com.oracle.svm.shadowed.org.bytedeco.javacpp.linux.arm64" }, + "riscv64": { + "sha1": "b00dee62b202898ec899cb7bc03604247d648ceb", + "urls": ["{urlbase}/javacpp-shadowed-1.5.7-linux-riscv64.jar"], + "moduleName" : "com.oracle.svm.shadowed.org.bytedeco.javacpp.linux.riscv64" + }, "": { "optional": True, }, @@ -416,6 +426,25 @@ "workingSets": "SVM", "jacoco" : "exclude", }, + "com.oracle.svm.core.graal.riscv64": { + "subDir": "src", + "sourceDirs": ["src"], + "dependencies": [ + "com.oracle.svm.core", + ], + "requiresConcealed" : { + "jdk.internal.vm.ci" : [ + "jdk.vm.ci.code.site", + ], + }, + "checkstyle": "com.oracle.svm.core", + "javaCompliance": "11+", + "annotationProcessors": [ + "compiler:GRAAL_PROCESSOR", + "SVM_PROCESSOR", + ], + "workingSets": "SVM", + }, "com.oracle.svm.core.graal.llvm": { "subDir": "src", "sourceDirs": ["src"], @@ -441,6 +470,7 @@ "dependencies": [ "com.oracle.svm.core.graal.amd64", "com.oracle.svm.core.graal.aarch64", + "com.oracle.svm.core.graal.riscv64", ], "requiresConcealed" : { "java.base" : [ @@ -1275,6 +1305,7 @@ "com.oracle.svm.core.jdk17", "com.oracle.svm.core.graal.amd64", "com.oracle.svm.core.graal.aarch64", + "com.oracle.svm.core.graal.riscv64", "com.oracle.svm.core.posix", "com.oracle.svm.core.windows", "com.oracle.svm.core.genscavenge", diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFMachine.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFMachine.java index 4e1aa9456449..02d3f892fec1 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFMachine.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFMachine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,16 +38,52 @@ public enum ELFMachine/* implements Integral */ { Class> relocationTypes() { return ELFX86_64Relocation.class; } + + @Override + int flags() { + /* + * e_flags are always 0 for X86 + */ + return NO_FLAGS; + } }, AArch64 { @Override Class> relocationTypes() { return ELFAArch64Relocation.class; } + + @Override + int flags() { + /* + * e_flags are always 0 for AArch64 + */ + return NO_FLAGS; + } + }, + RISCV64 { + @Override + Class> relocationTypes() { + return ELFRISCV64Relocation.class; + } + + @Override + int flags() { + /* + * Since we use the most powerful rv64gc model variant, we need to set e_flags to 5, + * which are RVC and double-float ABI. + */ + return RVC_DOUBLE_FLOAT_ABI; + } }; + private static final int NO_FLAGS = 0; + private static final int RVC_DOUBLE_FLOAT_ABI = 5; + abstract Class> relocationTypes(); + abstract int flags(); + public static ELFMachine from(String s) { switch (s.toLowerCase()) { case "amd64": @@ -56,6 +92,8 @@ public static ELFMachine from(String s) { case "arm64": case "aarch64": return AArch64; + case "riscv64": + return RISCV64; } throw new IllegalStateException("unknown CPU type: " + s); } @@ -129,6 +167,14 @@ public static ELFRelocationMethod getRelocation(ELFMachine m, RelocationKind k) throw new IllegalArgumentException("cannot map unknown relocation kind to an ELF aarch64 relocation type: " + k); } + case RISCV64: + switch (k) { + case DIRECT_8: + return ELFRISCV64Relocation.R_RISCV_64; + default: + case UNKNOWN: + throw new IllegalArgumentException("cannot map unknown relocation kind to an ELF riscv64 relocation type: " + k); + } default: throw new IllegalStateException("unknown ELF machine type"); } @@ -141,6 +187,8 @@ public static ELFMachine from(int m) { return X86_64; case 0xB7: return AArch64; + case 0xF3: + return RISCV64; default: throw new IllegalStateException("unknown ELF machine type"); } @@ -151,6 +199,8 @@ public short toShort() { return 0xB7; } else if (this == X86_64) { return 0x3E; + } else if (this == RISCV64) { + return 0xF3; } else { throw new IllegalStateException("should not reach here"); } @@ -159,6 +209,8 @@ public short toShort() { public static ELFMachine getSystemNativeValue() { if (System.getProperty("os.arch").equals("aarch64")) { return AArch64; + } else if (System.getProperty("os.arch").equals("riscv64")) { + return RISCV64; } else { return X86_64; } @@ -360,3 +412,75 @@ public long toLong() { return code; } } + +/** + * Reference: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc. + */ +enum ELFRISCV64Relocation implements ELFRelocationMethod { + R_RISCV_NONE(0), + R_RISCV_32(1), + R_RISCV_64(2), + R_RISCV_RELATIVE(3), + R_RISCV_COPY(4), + R_RISCV_JUMP_SLOT(5), + R_RISCV_TLS_DTPMOD32(6), + R_RISCV_TLS_DTPMOD64(7), + R_RISCV_TLS_DTPREL32(8), + R_RISCV_TLS_DTPREL64(9), + R_RISCV_TLS_TPREL32(10), + R_RISCV_TLS_TPREL64(11), + R_RISCV_BRANCH(16), + R_RISCV_JAL(17), + R_RISCV_CALL(18), + R_RISCV_CALL_PLT(19), + R_RISCV_GOT_HI20(20), + R_RISCV_TLS_GOT_HI20(21), + R_RISCV_TLS_GD_HI20(22), + R_RISCV_PCREL_HI20(23), + R_RISCV_PCREL_LO12_I(24), + R_RISCV_PCREL_LO12_S(25), + R_RISCV_HI20(26), + R_RISCV_LO12_I(27), + R_RISCV_LO12_S(28), + R_RISCV_TPREL_HI20(29), + R_RISCV_TPREL_LO12_I(30), + R_RISCV_TPREL_LO12_S(31), + R_RISCV_TPREL_ADD(32), + R_RISCV_ADD8(33), + R_RISCV_ADD16(34), + R_RISCV_ADD32(35), + R_RISCV_ADD64(36), + R_RISCV_SUB8(37), + R_RISCV_SUB16(38), + R_RISCV_SUB32(39), + R_RISCV_SUB64(40), + R_RISCV_GNU_VTINHERIT(41), + R_RISCV_GNU_VTENTRY(42), + R_RISCV_ALIGN(43), + R_RISCV_RVC_BRANCH(44), + R_RISCV_RVC_JUMP(45), + R_RISCV_RVC_LUI(46), + R_RISCV_GPREL_I(47), + R_RISCV_GPREL_S(48), + R_RISCV_TPREL_I(49), + R_RISCV_TPREL_S(50), + R_RISCV_RELAX(51), + R_RISCV_SUB6(52), + R_RISCV_SET6(53), + R_RISCV_SET8(54), + R_RISCV_SET16(55), + R_RISCV_SET32(56), + R_RISCV_32_PCREL(57), + R_RISCV_IRELATIVE(58); + + private final long code; + + ELFRISCV64Relocation(long code) { + this.code = code; + } + + @Override + public long toLong() { + return code; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index 1227f287ef0b..68dcf5a4125a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,7 +81,7 @@ public class ELFObjectFile extends ObjectFile { private char abiVersion; private ELFClass fileClass = ELFClass.getSystemNativeValue(); private ELFMachine machine; - private long processorSpecificFlags; // FIXME: to encapsulate (EF_* in elf.h) + private long processorFlags; // FIXME: to encapsulate (EF_* in elf.h) private final boolean runtimeDebugInfoGeneration; private ELFObjectFile(int pageSize, ELFMachine machine, boolean runtimeDebugInfoGeneration) { @@ -89,7 +89,7 @@ private ELFObjectFile(int pageSize, ELFMachine machine, boolean runtimeDebugInfo this.runtimeDebugInfoGeneration = runtimeDebugInfoGeneration; // Create the elements of an empty ELF file: // 1. create header - header = new ELFHeader("ELFHeader"); + header = new ELFHeader("ELFHeader", machine.flags()); this.machine = machine; // 2. create shstrtab shstrtab = new SectionHeaderStrtab(); @@ -584,9 +584,13 @@ public int getWrittenSize() { } public ELFHeader(String name) { // create an "empty" default ELF header + this(name, 0); + } + + public ELFHeader(String name, int processorFlags) { // create an "empty" default ELF header super(name); ELFObjectFile.this.version = 1; - ELFObjectFile.this.processorSpecificFlags = 0; + ELFObjectFile.this.processorFlags = processorFlags; } @Override @@ -1129,7 +1133,7 @@ public void setMachine(ELFMachine machine) { } public long getFlags() { - return processorSpecificFlags; + return processorFlags; } @SuppressWarnings("unused") diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java index ae091260825d..00d6c6466718 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java @@ -845,7 +845,7 @@ public Variable emitAddress(AllocatableValue stackslot) { @Override public Value emitReadCallerStackPointer(Stamp wordStamp) { LLVMValueRef basePointer = builder.buildFrameAddress(builder.constantInt(0)); - LLVMValueRef callerSP = builder.buildAdd(builder.buildPtrToInt(basePointer), builder.constantLong(16)); + LLVMValueRef callerSP = builder.buildAdd(builder.buildPtrToInt(basePointer), builder.constantLong(LLVMTargetSpecific.get().getCallerSPOffset())); return new LLVMVariable(callerSP); } @@ -1759,7 +1759,7 @@ public Value emitMathCopySign(Value a, Value b) { public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state, MemoryOrderMode memoryOrder, MemoryExtendKind extendKind) { assert extendKind.isNotExtended(); assert memoryOrder != MemoryOrderMode.RELEASE && memoryOrder != MemoryOrderMode.RELEASE_ACQUIRE; - LLVMValueRef load = builder.buildLoad(getVal(address), getType(kind)); + LLVMValueRef load = builder.buildAlignedLoad(getVal(address), getType(kind), kind.getPlatformKind().getSizeInBytes()); if (memoryOrder == MemoryOrderMode.ACQUIRE || memoryOrder == MemoryOrderMode.VOLATILE) { /* * Ensure subsequent memory operations cannot execute before this load. Additional @@ -1787,7 +1787,7 @@ public void emitStore(ValueKind kind, Value addr, Value input, LIRFrameState castedValue = builder.buildAddrSpaceCast(value, builder.rawPointerType()); } LLVMValueRef castedAddress = builder.buildBitcast(address, builder.pointerType(valueType, LLVMIRBuilder.isObjectType(addressType), false)); - builder.buildStore(castedValue, castedAddress); + builder.buildAlignedStore(castedValue, castedAddress, input.getValueKind().getPlatformKind().getSizeInBytes()); if (memoryOrder == MemoryOrderMode.VOLATILE) { // Guarantee subsequent volatile loads cannot be executed before this diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMIRBuilder.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMIRBuilder.java index 7c7380894035..c164ffd3ce50 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMIRBuilder.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMIRBuilder.java @@ -1176,24 +1176,43 @@ public LLVMValueRef buildGEP(LLVMValueRef base, LLVMValueRef... indices) { return LLVM.LLVMBuildGEP(builder, base, new PointerPointer<>(indices), indices.length, DEFAULT_INSTR_NAME); } - public LLVMValueRef buildLoad(LLVMValueRef address, LLVMTypeRef type) { + private LLVMValueRef buildLoadHelper(LLVMValueRef address, LLVMTypeRef type, int alignment) { LLVMTypeRef addressType = LLVM.LLVMTypeOf(address); if (isObjectType(type) && !isObjectType(addressType)) { boolean compressed = isCompressedPointerType(type); return buildCall(helpers.getLoadObjectFromUntrackedPointerFunction(compressed), address); } LLVMValueRef castedAddress = buildBitcast(address, pointerType(type, isObjectType(addressType), false)); - return buildLoad(castedAddress); + return alignment > 0 ? buildAlignedLoad(castedAddress, alignment) : buildLoad(castedAddress); + } + + public LLVMValueRef buildLoad(LLVMValueRef address, LLVMTypeRef type) { + return buildLoadHelper(address, type, 0); + } + + public LLVMValueRef buildAlignedLoad(LLVMValueRef address, LLVMTypeRef type, int alignment) { + return buildLoadHelper(address, type, alignment); } public LLVMValueRef buildLoad(LLVMValueRef address) { return LLVM.LLVMBuildLoad(builder, address, DEFAULT_INSTR_NAME); } + public LLVMValueRef buildAlignedLoad(LLVMValueRef address, int alignment) { + LLVMValueRef load = LLVM.LLVMBuildLoad(builder, address, DEFAULT_INSTR_NAME); + LLVM.LLVMSetAlignment(load, alignment); + return load; + } + public void buildStore(LLVMValueRef value, LLVMValueRef address) { LLVM.LLVMBuildStore(builder, value, address); } + public void buildAlignedStore(LLVMValueRef value, LLVMValueRef address, int alignment) { + LLVMValueRef store = LLVM.LLVMBuildStore(builder, value, address); + LLVM.LLVMSetAlignment(store, alignment); + } + public void buildVolatileStore(LLVMValueRef value, LLVMValueRef address, int alignment) { LLVMValueRef store = LLVM.LLVMBuildStore(builder, value, address); LLVM.LLVMSetOrdering(store, LLVM.LLVMAtomicOrderingRelease); diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMObjectFileReader.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMObjectFileReader.java index 9a39cbd2b136..49807adabaa9 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMObjectFileReader.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMObjectFileReader.java @@ -72,7 +72,7 @@ public LLVMObjectFileReader(StackMapDumper stackMapDumper) { @FunctionalInterface private interface SectionReader { - Result apply(LLVMSectionIteratorRef sectionIterator); + Result apply(LLVMSectionIteratorRef sectionIterator, LLVMSectionIteratorRef relocationsSectionIterator); } @FunctionalInterface @@ -98,12 +98,13 @@ private static LLVMSectionInfo result = new LLVMSectionInfo<>(); for (sectionIterator = LLVM.LLVMGetSections(objectFile); LLVM.LLVMIsSectionIteratorAtEnd(objectFile, sectionIterator) == FALSE; LLVM.LLVMMoveToNextSection(sectionIterator)) { BytePointer sectionNamePointer = LLVM.LLVMGetSectionName(sectionIterator); String currentSectionName = (sectionNamePointer != null) ? sectionNamePointer.getString() : ""; if (currentSectionName.startsWith(sectionName.getFormatDependentName(ObjectFile.getNativeFormat()))) { - result.sectionInfo = sectionReader.apply(sectionIterator); + result.sectionInfo = sectionReader.apply(sectionIterator, relocationsSectionIterator); if (symbolReader != null) { LLVMSymbolIteratorRef symbolIterator; @@ -116,9 +117,11 @@ private static LLVMSectionInfo sectionInfo) { this.codeSize = sectionInfo.sectionInfo; for (SymbolOffset symbolOffset : sectionInfo.symbolInfo) { - offsetToSymbol.put(symbolOffset.offset, symbolOffset.symbol); - symbolToOffset.put(symbolOffset.symbol, symbolOffset.offset); + if (LLVMTargetSpecific.get().isSymbolValid(symbolOffset.symbol)) { + offsetToSymbol.put(symbolOffset.offset, symbolOffset.symbol); + symbolToOffset.put(symbolOffset.symbol, symbolOffset.offset); + } } this.sortedMethodOffsets = computeSortedMethodOffsets(); } diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMStackMapInfo.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMStackMapInfo.java index 5abcdc1d904a..522c6afc1617 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMStackMapInfo.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMStackMapInfo.java @@ -36,6 +36,9 @@ import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMRelocationIteratorRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMSectionIteratorRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.global.LLVM; public class LLVMStackMapInfo { public static final long DEFAULT_PATCHPOINT_ID = 0xABCDEF00L; @@ -99,7 +102,8 @@ static class LiveOut { * Stack map format specification available at * https://llvm.org/docs/StackMaps.html#stack-map-format */ - LLVMStackMapInfo(ByteBuffer buffer) { + LLVMStackMapInfo(ByteBuffer buffer, LLVMSectionIteratorRef relocationsSectionIteratorRef) { + LLVMRelocationIteratorRef relocationIteratorRef = LLVM.LLVMGetRelocations(relocationsSectionIteratorRef); StackMap stackMap = new StackMap(); int offset = 0; @@ -158,7 +162,7 @@ static class LiveOut { record.patchpointID = buffer.getLong(offset); offset += Long.BYTES; - record.instructionOffset = buffer.getInt(offset); + record.instructionOffset = LLVMTargetSpecific.get().getInstructionOffset(buffer, offset, relocationsSectionIteratorRef, relocationIteratorRef); offset += Integer.BYTES; record.flags = buffer.getShort(offset); @@ -218,6 +222,8 @@ static class LiveOut { patchpointToFunction.put(record.patchpointID, function); patchpointsByID.computeIfAbsent(record.patchpointID, v -> new HashSet<>()).add(record); } + + LLVM.LLVMDisposeRelocationIterator(relocationIteratorRef); } private Map patchpointToFunction = new HashMap<>(); diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMTargetSpecific.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMTargetSpecific.java index 6321b4a9fee1..c15dfd6c9d4c 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMTargetSpecific.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMTargetSpecific.java @@ -24,6 +24,10 @@ */ package com.oracle.svm.core.graal.llvm.util; +import static com.oracle.svm.core.graal.llvm.util.LLVMUtils.FALSE; +import static com.oracle.svm.core.util.VMError.shouldNotReachHere; + +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -36,6 +40,10 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMRelocationIteratorRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMSectionIteratorRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMSymbolIteratorRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.global.LLVM; /** * LLVM target-specific inline assembly snippets and information. @@ -87,6 +95,11 @@ static LLVMTargetSpecific get() { */ int getFramePointerDwarfRegNum(); + /** + * Offset between the stack pointer of the caller and the frame pointer of the callee. + */ + long getCallerSPOffset(); + /** * Additional target-specific options to be passed to the LLVM compiler. */ @@ -106,6 +119,21 @@ default String getLLVMRegisterName(String register) { * A scratch register of the architecture. */ String getScratchRegister(); + + /** + * Condition for adding section in sections info to avoid duplicates. + */ + default boolean isSymbolValid(@SuppressWarnings("unused") String symbol) { + return true; + } + + /** + * Extracts the instruction offset from the Stack Map section. + */ + default int getInstructionOffset(ByteBuffer buffer, int offset, @SuppressWarnings("unused") LLVMSectionIteratorRef relocationsSectionIteratorRef, + @SuppressWarnings("unused") LLVMRelocationIteratorRef relocationIteratorRef) { + return buffer.getInt(offset); + } } @AutomaticallyRegisteredFeature @@ -162,6 +190,11 @@ public int getFramePointerOffset() { return -FrameAccess.wordSize(); } + @Override + public long getCallerSPOffset() { + return 2L * FrameAccess.wordSize(); + } + @Override public int getStackPointerDwarfRegNum() { return AMD64_RSP_IDX; @@ -242,6 +275,11 @@ public int getFramePointerOffset() { return -2 * FrameAccess.wordSize(); } + @Override + public long getCallerSPOffset() { + return 2L * FrameAccess.wordSize(); + } + @Override public int getStackPointerDwarfRegNum() { return AARCH64_SP_IDX; @@ -275,3 +313,114 @@ public String getScratchRegister() { }); } } + +@AutomaticallyRegisteredFeature +@Platforms(Platform.RISCV64.class) +class LLVMRISCV64TargetSpecificFeature implements InternalFeature { + private static final int RISCV64_FP_IDX = 8; + private static final int RISCV64_SP_IDX = 2; + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return SubstrateOptions.useLLVMBackend(); + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + ImageSingletons.add(LLVMTargetSpecific.class, new LLVMTargetSpecific() { + @Override + public String getJumpInlineAsm() { + return "jr $0"; + } + + @Override + public String getLoadInlineAsm(String inputRegister, int offset) { + return "ld $0, " + offset + "(" + getLLVMRegisterName(inputRegister) + ")"; + } + + @Override + public String getAddInlineAssembly(String outputRegister, String inputRegister) { + return "add $0, " + getLLVMRegisterName(outputRegister) + ", " + getLLVMRegisterName(inputRegister); + } + + @Override + public String getLLVMArchName() { + return "riscv64"; + } + + /* + * All data push on the stack is in the call frame + */ + @Override + public int getCallFrameSeparation() { + return 0; + } + + /* + * The frame pointer is stored below the saved value for the return register. + */ + @Override + public int getFramePointerOffset() { + return 0; + } + + @Override + public long getCallerSPOffset() { + return 0; + } + + @Override + public int getStackPointerDwarfRegNum() { + return RISCV64_SP_IDX; + } + + @Override + public int getFramePointerDwarfRegNum() { + return RISCV64_FP_IDX; + } + + @Override + public List getLLCAdditionalOptions() { + List list = new ArrayList<>(); + list.add("--frame-pointer=all"); + list.add("-mattr=+c,+d"); + list.add("-target-abi=lp64d"); + return list; + } + + @Override + public String getScratchRegister() { + return "x5"; + } + + /* + * When compiling for RISC-V, llc produces labels in the intermediate files, which we + * must remove when we parse the code at the linking step. + */ + @Override + public boolean isSymbolValid(String section) { + return !section.isEmpty() && !section.startsWith(".LBB"); + } + + /* + * We have the use the relocations to parse the instruction offset in RISC-V, as the + * offset is 0 otherwise, due to RISC-V specific relocations. + */ + @Override + public int getInstructionOffset(ByteBuffer buffer, int offset, LLVMSectionIteratorRef relocationsSectionIteratorRef, LLVMRelocationIteratorRef relocationIteratorRef) { + while (LLVM.LLVMIsRelocationIteratorAtEnd(relocationsSectionIteratorRef, relocationIteratorRef) == FALSE && offset != LLVM.LLVMGetRelocationOffset(relocationIteratorRef)) { + LLVM.LLVMMoveToNextRelocation(relocationIteratorRef); + } + if (offset == LLVM.LLVMGetRelocationOffset(relocationIteratorRef)) { + LLVMSymbolIteratorRef firstSymbol = LLVM.LLVMGetRelocationSymbol(relocationIteratorRef); + LLVM.LLVMMoveToNextRelocation(relocationIteratorRef); + assert offset == LLVM.LLVMGetRelocationOffset(relocationIteratorRef); + LLVMSymbolIteratorRef secondSymbol = LLVM.LLVMGetRelocationSymbol(relocationIteratorRef); + return (int) (LLVM.LLVMGetSymbolAddress(firstSymbol) - LLVM.LLVMGetSymbolAddress(secondSymbol)); + } else { + throw shouldNotReachHere("Stack map has no relocation for offset " + offset); + } + } + }); + } +} diff --git a/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/RISCV64ReservedRegisters.java b/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/RISCV64ReservedRegisters.java new file mode 100644 index 000000000000..658c2270bb68 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/RISCV64ReservedRegisters.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.graal.riscv64; + +import org.graalvm.compiler.core.riscv64.ShadowedRISCV64; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.ReservedRegisters; + +import jdk.vm.ci.code.Register; + +public final class RISCV64ReservedRegisters extends ReservedRegisters { + + public static Register threadRegisterCandidate; + public static Register heapBaseRegisterCandidate; + public static Register stackBaseRegisterCandidate; + + static { + stackBaseRegisterCandidate = ShadowedRISCV64.x2; + threadRegisterCandidate = ShadowedRISCV64.x23; + heapBaseRegisterCandidate = ShadowedRISCV64.x27; + } + + @Platforms(Platform.HOSTED_ONLY.class) + RISCV64ReservedRegisters() { + super(stackBaseRegisterCandidate, threadRegisterCandidate, heapBaseRegisterCandidate); + } +} diff --git a/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64Feature.java b/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64Feature.java new file mode 100644 index 000000000000..2bf0c18dcd35 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64Feature.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.graal.riscv64; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.ReservedRegisters; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.graal.code.SubstrateRegisterConfigFactory; +import com.oracle.svm.core.graal.meta.SubstrateRegisterConfig.ConfigKind; + +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.MetaAccessProvider; + +@AutomaticallyRegisteredFeature +@Platforms(Platform.RISCV64.class) +class SubstrateRISCV64Feature implements InternalFeature { + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + + ImageSingletons.add(SubstrateRegisterConfigFactory.class, new SubstrateRegisterConfigFactory() { + @Override + public RegisterConfig newRegisterFactory(ConfigKind config, MetaAccessProvider metaAccess, TargetDescription target, Boolean preserveFramePointer) { + return new SubstrateRISCV64RegisterConfig(config, metaAccess, target, preserveFramePointer); + } + }); + + ImageSingletons.add(ReservedRegisters.class, new RISCV64ReservedRegisters()); + + if (!SubstrateOptions.useLLVMBackend()) { + throw GraalError.unimplemented("The RISC-V native backend is currently unimplemented. Use the LLVM backend."); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64RegisterConfig.java b/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64RegisterConfig.java new file mode 100644 index 000000000000..7a443a32ca01 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64RegisterConfig.java @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.graal.riscv64; + +import static com.oracle.svm.core.util.VMError.shouldNotReachHere; +import static com.oracle.svm.core.util.VMError.unimplemented; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.allRegisters; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f10; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f11; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f12; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f13; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f14; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f15; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f16; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f17; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f18; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f19; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f20; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f21; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f22; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f23; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f24; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f25; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f26; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f27; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f8; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.f9; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x0; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x1; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x10; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x11; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x12; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x13; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x14; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x15; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x16; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x17; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x18; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x19; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x2; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x20; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x21; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x22; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x23; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x24; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x25; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x26; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x27; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x3; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x8; +import static org.graalvm.compiler.core.riscv64.ShadowedRISCV64.x9; + +import java.util.ArrayList; + +import org.graalvm.nativeimage.Platform; + +import com.oracle.svm.core.ReservedRegisters; +import com.oracle.svm.core.config.ObjectLayout; +import com.oracle.svm.core.graal.code.SubstrateCallingConvention; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionType; +import com.oracle.svm.core.graal.meta.SubstrateRegisterConfig; +import com.oracle.svm.core.util.VMError; + +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.CallingConvention.Type; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterAttributes; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.code.ValueKindFactory; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.meta.ValueKind; + +public class SubstrateRISCV64RegisterConfig implements SubstrateRegisterConfig { + + private final TargetDescription target; + private final int nativeParamsStackOffset; + private final RegisterArray generalParameterRegs; + private final RegisterArray fpParameterRegs; + private final RegisterArray allocatableRegs; + private final RegisterArray calleeSaveRegisters; + private final RegisterAttributes[] attributesMap; + private final MetaAccessProvider metaAccess; + + public SubstrateRISCV64RegisterConfig(ConfigKind config, MetaAccessProvider metaAccess, TargetDescription target, boolean preserveFramePointer) { + this.target = target; + this.metaAccess = metaAccess; + + generalParameterRegs = new RegisterArray(x10, x11, x12, x13, x14, x15, x16, x17); + fpParameterRegs = new RegisterArray(f10, f11, f12, f13, f14, f15, f16, f17); + + nativeParamsStackOffset = 0; + + ArrayList regs = new ArrayList<>(allRegisters.asList()); + regs.remove(x2); // sp + regs.remove(x0); // zero + if (preserveFramePointer) { + regs.remove(x8); + } + /* + * If enabled, the heapBaseRegister and threadRegister are x27 and x23, respectively. See + * RISCV64ReservedRegisters and ReservedRegisters for more information. + */ + regs.remove(ReservedRegisters.singleton().getHeapBaseRegister()); + regs.remove(ReservedRegisters.singleton().getThreadRegister()); + regs.remove(x1); // ra + regs.remove(x3); // gp + allocatableRegs = new RegisterArray(regs); + + switch (config) { + case NORMAL: + calleeSaveRegisters = new RegisterArray(); + break; + + case NATIVE_TO_JAVA: + calleeSaveRegisters = new RegisterArray(x2, x8, x9, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, + f8, f9, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27); + break; + + default: + throw shouldNotReachHere(); + + } + + attributesMap = RegisterAttributes.createMap(this, allRegisters); + } + + @Override + public Register getReturnRegister(JavaKind kind) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + case Object: + return x10; + case Float: + case Double: + return f10; + case Void: + return null; + default: + throw VMError.shouldNotReachHere(); + } + } + + @Override + public RegisterArray getAllocatableRegisters() { + return allocatableRegs; + } + + @Override + public RegisterArray getCalleeSaveRegisters() { + return calleeSaveRegisters; + } + + @Override + public RegisterArray getCallerSaveRegisters() { + return getAllocatableRegisters(); + } + + @Override + public boolean areAllAllocatableRegistersCallerSaved() { + return true; + } + + @Override + public RegisterAttributes[] getAttributesMap() { + return attributesMap; + } + + @Override + public RegisterArray getCallingConventionRegisters(Type t, JavaKind kind) { + throw VMError.unimplemented(); + } + + private int javaStackParameterAssignment(ValueKindFactory valueKindFactory, AllocatableValue[] locations, int index, JavaKind kind, int currentStackOffset, boolean isOutgoing) { + /* All parameters within Java are assigned slots of at least 8 bytes */ + ValueKind valueKind = valueKindFactory.getValueKind(kind.getStackKind()); + int alignment = Math.max(valueKind.getPlatformKind().getSizeInBytes(), target.wordSize); + locations[index] = StackSlot.get(valueKind, currentStackOffset, !isOutgoing); + return currentStackOffset + alignment; + } + + @Override + public CallingConvention getCallingConvention(Type t, JavaType returnType, JavaType[] parameterTypes, ValueKindFactory valueKindFactory) { + SubstrateCallingConventionType type = (SubstrateCallingConventionType) t; + boolean isEntryPoint = type.nativeABI() && !type.outgoing; + + AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; + + int currentGeneral = 0; + int currentFP = 0; + + /* + * We have to reserve a slot between return address and outgoing parameters for the deopt + * frame handle. Exception: calls to native methods. + */ + int currentStackOffset = (type.nativeABI() ? nativeParamsStackOffset : target.wordSize); + + JavaKind[] kinds = new JavaKind[locations.length]; + for (int i = 0; i < parameterTypes.length; i++) { + JavaKind kind = ObjectLayout.getCallSignatureKind(isEntryPoint, (ResolvedJavaType) parameterTypes[i], metaAccess, target); + kinds[i] = kind; + + Register register = null; + if (type.kind == SubstrateCallingConventionKind.ForwardReturnValue) { + VMError.guarantee(i == 0, "Method with calling convention ForwardReturnValue cannot have more than one parameter"); + register = getReturnRegister(kind); + } else { + switch (kind) { + case Byte: + case Boolean: + case Short: + case Char: + case Int: + case Long: + case Object: + if (currentGeneral < generalParameterRegs.size()) { + register = generalParameterRegs.get(currentGeneral++); + } + break; + case Float: + case Double: + if (currentFP < fpParameterRegs.size()) { + register = fpParameterRegs.get(currentFP++); + } + break; + default: + throw shouldNotReachHere(); + } + + } + if (register != null) { + boolean useJavaKind = isEntryPoint && Platform.includedIn(Platform.LINUX.class); + locations[i] = register.asValue(valueKindFactory.getValueKind(useJavaKind ? kind : kind.getStackKind())); + } else { + if (type.nativeABI()) { + if (Platform.includedIn(Platform.LINUX.class)) { + ValueKind valueKind = valueKindFactory.getValueKind(type.outgoing ? kind.getStackKind() : kind); + int alignment = Math.max(kind.getByteCount(), target.wordSize); + locations[i] = StackSlot.get(valueKind, currentStackOffset, !type.outgoing); + currentStackOffset = currentStackOffset + alignment; + } else { + throw VMError.shouldNotReachHere(); + } + } else { + currentStackOffset = javaStackParameterAssignment(valueKindFactory, locations, i, kind, currentStackOffset, type.outgoing); + } + } + } + + JavaKind returnKind = returnType == null ? JavaKind.Void : ObjectLayout.getCallSignatureKind(isEntryPoint, (ResolvedJavaType) returnType, metaAccess, target); + AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(valueKindFactory.getValueKind(returnKind.getStackKind())); + return new SubstrateCallingConvention(type, kinds, currentStackOffset, returnLocation, locations); + } + + @Override + public RegisterArray filterAllocatableRegisters(PlatformKind kind, RegisterArray registers) { + throw unimplemented(); + } + +} diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java index 93e7d0d66161..f94d14ba9375 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java @@ -126,6 +126,10 @@ public interface ucontext_t extends RegisterDumper.Context { @Platforms({Platform.LINUX_AARCH64_BASE.class}) mcontext_linux_aarch64_t uc_mcontext_linux_aarch64(); + @CFieldAddress("uc_mcontext") + @Platforms({Platform.LINUX_RISCV64.class}) + mcontext_linux_riscv64_t uc_mcontext_linux_riscv64(); + @CField("uc_mcontext") @Platforms({Platform.DARWIN_AMD64.class}) AMD64DarwinMContext64 uc_mcontext_darwin_amd64(); @@ -340,6 +344,17 @@ public interface mcontext_linux_aarch64_t extends PointerBase { long pstate(); } + /** + * Information about Linux's RISCV64 struct sigcontext uc_mcontext can be found at + * https://github.com/torvalds/linux/blob/9e1ff307c779ce1f0f810c7ecce3d95bbae40896/arch/riscv/include/uapi/asm/sigcontext.h#L17 + */ + @CStruct(value = "mcontext_t") + @Platforms({Platform.LINUX_RISCV64.class}) + public interface mcontext_linux_riscv64_t extends PointerBase { + @CFieldAddress(value = "__gregs") + GregsPointer gregs(); + } + /** * Information about Darwin's AMD64 mcontext64 can be found at * https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/i386/_mcontext.h#L147 diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/riscv64/RISCV64LinuxUContextRegisterDumperFeature.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/riscv64/RISCV64LinuxUContextRegisterDumperFeature.java new file mode 100644 index 000000000000..eb587ad6070e --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/riscv64/RISCV64LinuxUContextRegisterDumperFeature.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.posix.riscv64; + +import static com.oracle.svm.core.RegisterDumper.dumpReg; + +import org.graalvm.compiler.core.riscv64.ShadowedRISCV64; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.word.PointerBase; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.RegisterDumper; +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.graal.riscv64.RISCV64ReservedRegisters; +import com.oracle.svm.core.log.Log; +import com.oracle.svm.core.posix.UContextRegisterDumper; +import com.oracle.svm.core.posix.headers.Signal; +import com.oracle.svm.core.posix.headers.Signal.GregsPointer; +import com.oracle.svm.core.posix.headers.Signal.mcontext_linux_riscv64_t; +import com.oracle.svm.core.posix.headers.Signal.ucontext_t; +import com.oracle.svm.core.util.VMError; + +@AutomaticallyRegisteredImageSingleton(RegisterDumper.class) +@Platforms(Platform.LINUX_RISCV64.class) +class RISCV64LinuxUContextRegisterDumper implements UContextRegisterDumper { + RISCV64LinuxUContextRegisterDumper() { + VMError.guarantee(ShadowedRISCV64.x27.equals(RISCV64ReservedRegisters.heapBaseRegisterCandidate)); + VMError.guarantee(ShadowedRISCV64.x23.equals(RISCV64ReservedRegisters.threadRegisterCandidate)); + } + + @Override + public void dumpRegisters(Log log, Signal.ucontext_t uContext, boolean printLocationInfo, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { + mcontext_linux_riscv64_t sigcontext = uContext.uc_mcontext_linux_riscv64(); + GregsPointer gregs = sigcontext.gregs(); + dumpReg(log, "PC ", gregs.read(0), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X1 ", gregs.read(1), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X2 ", gregs.read(2), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X3 ", gregs.read(3), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X4 ", gregs.read(4), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X5 ", gregs.read(5), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X6 ", gregs.read(6), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X7 ", gregs.read(7), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X8 ", gregs.read(8), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X9 ", gregs.read(9), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X10 ", gregs.read(10), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X11 ", gregs.read(11), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X12 ", gregs.read(12), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X13 ", gregs.read(13), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X14 ", gregs.read(14), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X15 ", gregs.read(15), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X16 ", gregs.read(16), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X17 ", gregs.read(17), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X18 ", gregs.read(18), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X19 ", gregs.read(19), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X20 ", gregs.read(20), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X21 ", gregs.read(21), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X22 ", gregs.read(22), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X23 ", gregs.read(23), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X24 ", gregs.read(24), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X25 ", gregs.read(25), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X26 ", gregs.read(26), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X27 ", gregs.read(27), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X28 ", gregs.read(28), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X29 ", gregs.read(29), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X30 ", gregs.read(30), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "X31 ", gregs.read(31), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true) + public PointerBase getHeapBase(ucontext_t uContext) { + GregsPointer regs = uContext.uc_mcontext_linux_riscv64().gregs(); + return WordFactory.pointer(regs.read(27)); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true) + public PointerBase getThreadPointer(ucontext_t uContext) { + GregsPointer regs = uContext.uc_mcontext_linux_riscv64().gregs(); + return WordFactory.pointer(regs.read(23)); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public PointerBase getSP(ucontext_t uContext) { + GregsPointer regs = uContext.uc_mcontext_linux_riscv64().gregs(); + return WordFactory.pointer(regs.read(2)); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public PointerBase getIP(ucontext_t uContext) { + // gregs[0] holds the program counter. + GregsPointer regs = uContext.uc_mcontext_linux_riscv64().gregs(); + return WordFactory.pointer(regs.read(0)); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/cpufeature/RuntimeCPUFeatureCheckImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/cpufeature/RuntimeCPUFeatureCheckImpl.java index 12c16244b781..5e158f20e78a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/cpufeature/RuntimeCPUFeatureCheckImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/cpufeature/RuntimeCPUFeatureCheckImpl.java @@ -26,6 +26,7 @@ import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.EnumMap; import java.util.EnumSet; @@ -34,6 +35,8 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.NumUtil; +import org.graalvm.compiler.core.riscv64.RISCV64ReflectionUtil; +import org.graalvm.compiler.core.riscv64.ShadowedRISCV64; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node.InjectedNodeParameter; import org.graalvm.compiler.graph.Node.NodeIntrinsicFactory; @@ -55,10 +58,10 @@ import com.oracle.svm.core.SubstrateTargetDescription; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.jdk.RuntimeSupport; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.jdk.RuntimeSupport; import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.aarch64.AArch64; @@ -364,6 +367,10 @@ static EnumSet getStaticFeatures() { return ((AMD64) arch).getFeatures(); } else if (arch instanceof AArch64) { return ((AArch64) arch).getFeatures(); + } else if (ShadowedRISCV64.instanceOf(arch)) { + Method getFeatures = RISCV64ReflectionUtil.lookupMethod(ShadowedRISCV64.riscv64OrNull, "getFeatures"); + getFeatures.setAccessible(true); + return (EnumSet) RISCV64ReflectionUtil.invokeMethod(getFeatures, arch); } else { throw GraalError.shouldNotReachHere("unsupported architecture"); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/GraalConfiguration.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/GraalConfiguration.java index e027af4f5b56..7e53a68ac84a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/GraalConfiguration.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/GraalConfiguration.java @@ -36,6 +36,8 @@ import org.graalvm.compiler.core.gen.NodeMatchRules; import org.graalvm.compiler.core.match.MatchRuleRegistry; import org.graalvm.compiler.core.match.MatchStatement; +import org.graalvm.compiler.core.riscv64.RISCV64NodeMatchRules; +import org.graalvm.compiler.core.riscv64.RISCV64ReflectionUtil; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.hotspot.CommunityCompilerConfigurationFactory; import org.graalvm.compiler.lir.phases.LIRSuites; @@ -137,6 +139,8 @@ public void populateMatchRuleRegistry(HashMap, E matchRuleClass = AMD64NodeMatchRules.class; } else if (hostedArchitecture instanceof AArch64) { matchRuleClass = AArch64NodeMatchRules.class; + } else if (RISCV64ReflectionUtil.getArch(false).isInstance(hostedArchitecture)) { + matchRuleClass = RISCV64NodeMatchRules.class; } else { throw VMError.shouldNotReachHere("Can not instantiate NodeMatchRules for architecture " + hostedArchitecture.getName()); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/VaListInitializationNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/VaListInitializationNode.java new file mode 100644 index 000000000000..a16810a2fc35 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/VaListInitializationNode.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.graal.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; + +import org.graalvm.compiler.graph.IterableNodeType; +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.memory.SingleMemoryKill; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.word.LocationIdentity; + +import com.oracle.svm.core.FrameAccess; + +/** + * Puts the VaList in a StackValue, used as a layer to access and modify it. + */ +@NodeInfo(size = SIZE_8, cycles = CYCLES_4) +public final class VaListInitializationNode extends FixedWithNextNode implements SingleMemoryKill, Lowerable, IterableNodeType { + public static final NodeClass TYPE = NodeClass.create(VaListInitializationNode.class); + + @Input protected ValueNode vaList; + + public VaListInitializationNode(ValueNode vaList) { + super(TYPE, FrameAccess.getWordStamp()); + this.vaList = vaList; + } + + public ValueNode getVaList() { + return vaList; + } + + @Override + public LocationIdentity getKilledLocationIdentity() { + return LocationIdentity.any(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/aarch64/PosixAArch64VaListSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/aarch64/PosixAArch64VaListSnippets.java index 6edf5d392549..9ebbd9fd9fe0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/aarch64/PosixAArch64VaListSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/aarch64/PosixAArch64VaListSnippets.java @@ -37,6 +37,7 @@ import org.graalvm.compiler.replacements.Snippets; import org.graalvm.word.Pointer; +import com.oracle.svm.core.graal.nodes.VaListInitializationNode; import com.oracle.svm.core.graal.nodes.VaListNextArgNode; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; import com.oracle.svm.core.graal.snippets.SubstrateTemplates; @@ -99,6 +100,11 @@ final class PosixAArch64VaListSnippets extends SubstrateTemplates implements Sni private static final int GP_TOP_LOCATION = 8; private static final int FP_TOP_LOCATION = 16; + @Snippet + protected static Pointer vaListInitializationSnippet(Pointer vaList) { + return vaList; + } + @Snippet(allowMissingProbabilities = true) protected static double vaArgDoubleSnippet(Pointer vaList) { int fpOffset = vaList.readInt(FP_OFFSET_LOCATION); @@ -147,6 +153,8 @@ public static void registerLowerings(OptionValues options, Providers providers, new PosixAArch64VaListSnippets(options, providers, lowerings); } + private final SnippetInfo vaListInitialization; + private final SnippetInfo vaArgDouble; private final SnippetInfo vaArgFloat; private final SnippetInfo vaArgLong; @@ -154,14 +162,26 @@ public static void registerLowerings(OptionValues options, Providers providers, private PosixAArch64VaListSnippets(OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings) { super(options, providers); + lowerings.put(VaListInitializationNode.class, new VaListInitializationSnippetsLowering()); lowerings.put(VaListNextArgNode.class, new VaListSnippetsLowering()); + this.vaListInitialization = snippet(providers, PosixAArch64VaListSnippets.class, "vaListInitializationSnippet"); + this.vaArgDouble = snippet(providers, PosixAArch64VaListSnippets.class, "vaArgDoubleSnippet"); this.vaArgFloat = snippet(providers, PosixAArch64VaListSnippets.class, "vaArgFloatSnippet"); this.vaArgLong = snippet(providers, PosixAArch64VaListSnippets.class, "vaArgLongSnippet"); this.vaArgInt = snippet(providers, PosixAArch64VaListSnippets.class, "vaArgIntSnippet"); } + protected class VaListInitializationSnippetsLowering implements NodeLoweringProvider { + @Override + public void lower(VaListInitializationNode node, LoweringTool tool) { + Arguments args = new Arguments(vaListInitialization, node.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("vaList", node.getVaList()); + template(tool, node, args).instantiate(tool.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args); + } + } + protected class VaListSnippetsLowering implements NodeLoweringProvider { @Override public void lower(VaListNextArgNode node, LoweringTool tool) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/amd64/PosixAMD64VaListSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/amd64/PosixAMD64VaListSnippets.java index 8f8f47c3f20d..97e88307f287 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/amd64/PosixAMD64VaListSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/amd64/PosixAMD64VaListSnippets.java @@ -37,6 +37,7 @@ import org.graalvm.compiler.replacements.Snippets; import org.graalvm.word.Pointer; +import com.oracle.svm.core.graal.nodes.VaListInitializationNode; import com.oracle.svm.core.graal.nodes.VaListNextArgNode; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; import com.oracle.svm.core.graal.snippets.SubstrateTemplates; @@ -102,6 +103,11 @@ final class PosixAMD64VaListSnippets extends SubstrateTemplates implements Snipp private static final int OVERFLOW_ARG_AREA_ALIGNMENT = 8; private static final int REG_SAVE_AREA_LOCATION = 16; + @Snippet + protected static Pointer vaListInitializationSnippet(Pointer vaList) { + return vaList; + } + @Snippet(allowMissingProbabilities = true) protected static double vaArgDoubleSnippet(Pointer vaList) { int fpOffset = vaList.readInt(FP_OFFSET_LOCATION); @@ -150,6 +156,8 @@ public static void registerLowerings(OptionValues options, Providers providers, new PosixAMD64VaListSnippets(options, providers, lowerings); } + private final SnippetInfo vaListInitialization; + private final SnippetInfo vaArgDouble; private final SnippetInfo vaArgFloat; private final SnippetInfo vaArgLong; @@ -157,15 +165,27 @@ public static void registerLowerings(OptionValues options, Providers providers, private PosixAMD64VaListSnippets(OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings) { super(options, providers); + this.vaListInitialization = snippet(providers, PosixAMD64VaListSnippets.class, "vaListInitializationSnippet"); this.vaArgDouble = snippet(providers, PosixAMD64VaListSnippets.class, "vaArgDoubleSnippet"); this.vaArgFloat = snippet(providers, PosixAMD64VaListSnippets.class, "vaArgFloatSnippet"); this.vaArgLong = snippet(providers, PosixAMD64VaListSnippets.class, "vaArgLongSnippet"); this.vaArgInt = snippet(providers, PosixAMD64VaListSnippets.class, "vaArgIntSnippet"); + lowerings.put(VaListInitializationNode.class, new VaListInitializationSnippetsLowering()); lowerings.put(VaListNextArgNode.class, new VaListSnippetsLowering()); } + protected class VaListInitializationSnippetsLowering implements NodeLoweringProvider { + + @Override + public void lower(VaListInitializationNode node, LoweringTool tool) { + Arguments args = new Arguments(vaListInitialization, node.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("vaList", node.getVaList()); + template(tool, node, args).instantiate(tool.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args); + } + } + protected class VaListSnippetsLowering implements NodeLoweringProvider { @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/PosixRISCV64VaListSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/PosixRISCV64VaListSnippets.java new file mode 100644 index 000000000000..b255ea041c41 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/PosixRISCV64VaListSnippets.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.graal.snippets.riscv64; + +import java.util.Map; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.core.common.memory.MemoryOrderMode; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.memory.OnHeapMemoryAccess.BarrierType; +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.options.OptionValues; +import org.graalvm.compiler.phases.util.Providers; +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.word.LocationIdentity; +import org.graalvm.word.Pointer; + +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.graal.nodes.VaListInitializationNode; +import com.oracle.svm.core.graal.nodes.VaListNextArgNode; +import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; +import com.oracle.svm.core.graal.snippets.SubstrateTemplates; +import com.oracle.svm.core.graal.stackvalue.StackValueNode; +import com.oracle.svm.core.graal.stackvalue.StackValueNode.StackSlotIdentity; +import com.oracle.svm.core.util.VMError; + +import jdk.vm.ci.code.BytecodeFrame; + +/** + * Implementation of C {@code va_list} handling for System V systems on RISCV64 (Linux). A + * {@code va_list} is used for passing the arguments of a C varargs function ({@code ...} in the + * argument list) to another function. Varargs functions use the same calling convention as other + * functions, which entails passing the first few arguments in registers and the remaining arguments + * (if any) on the stack. The {@code va_list} type is void*. + *

+ * Reading a {@code va_list} requires knowing the types of the arguments. General-purpose values + * (integers and pointers) are passed in the eight 64-bit registers {@code x10} to {@code x17}. + * Floating-point values are passed in the eight 64-bit registers {@code f10} through {@code f17}. + * The callee is responsible for copying the contents of the registers used to pass variadic + * arguments to the {@code vararg} save area, which must be contiguous with the arguments passed on + * the stack. + *

+ * Reading an argument from the {@code va_list} only necessitates to read the value pointed by + * {@code va_list} and then increment the pointer using the size of the value read. + *

+ * References:
+ * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc
+ */ +final class PosixRISCV64VaListSnippets extends SubstrateTemplates implements Snippets { + + private static final int STACK_AREA_GP_ALIGNMENT = 8; + private static final int STACK_AREA_FP_ALIGNMENT = 8; + + private static final StackSlotIdentity vaListIdentity = new StackSlotIdentity("PosixRISCV64VaListSnippets.vaListSlotIdentifier", false); + + @Snippet + protected static double vaArgDoubleSnippet(Pointer vaListPointer) { + Pointer vaList = vaListPointer.readWord(0); + vaListPointer.writeWord(0, vaList.add(STACK_AREA_FP_ALIGNMENT)); + return vaList.readDouble(0); + } + + @Snippet + protected static float vaArgFloatSnippet(Pointer vaListPointer) { + // float is always promoted to double when passed in varargs + return (float) vaArgDoubleSnippet(vaListPointer); + } + + @Snippet + protected static long vaArgLongSnippet(Pointer vaListPointer) { + Pointer vaList = vaListPointer.readWord(0); + vaListPointer.writeWord(0, vaList.add(STACK_AREA_GP_ALIGNMENT)); + return vaList.readLong(0); + } + + @Snippet + protected static int vaArgIntSnippet(Pointer vaListPointer) { + return (int) vaArgLongSnippet(vaListPointer); + } + + @SuppressWarnings("unused") + public static void registerLowerings(OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings) { + new PosixRISCV64VaListSnippets(options, providers, lowerings); + } + + private final SnippetInfo vaArgDouble; + private final SnippetInfo vaArgFloat; + private final SnippetInfo vaArgLong; + private final SnippetInfo vaArgInt; + + private PosixRISCV64VaListSnippets(OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings) { + super(options, providers); + + this.vaArgDouble = snippet(providers, PosixRISCV64VaListSnippets.class, "vaArgDoubleSnippet"); + this.vaArgFloat = snippet(providers, PosixRISCV64VaListSnippets.class, "vaArgFloatSnippet"); + this.vaArgLong = snippet(providers, PosixRISCV64VaListSnippets.class, "vaArgLongSnippet"); + this.vaArgInt = snippet(providers, PosixRISCV64VaListSnippets.class, "vaArgIntSnippet"); + + lowerings.put(VaListInitializationNode.class, new VaListInitializationSnippetsLowering()); + lowerings.put(VaListNextArgNode.class, new VaListSnippetsLowering()); + } + + protected class VaListInitializationSnippetsLowering implements NodeLoweringProvider { + @Override + public void lower(VaListInitializationNode node, LoweringTool tool) { + StructuredGraph graph = node.graph(); + + StackValueNode stackValueNode = graph.add(StackValueNode.create(FrameAccess.wordSize(), vaListIdentity, true)); + FrameState frameState = new FrameState(BytecodeFrame.UNKNOWN_BCI); + frameState.invalidateForDeoptimization(); + stackValueNode.setStateAfter(graph.add(frameState)); + + OffsetAddressNode address = graph.unique(new OffsetAddressNode(stackValueNode, graph.unique(ConstantNode.forLong(0)))); + WriteNode writeNode = graph.add(new WriteNode(address, LocationIdentity.any(), node.getVaList(), BarrierType.NONE, MemoryOrderMode.PLAIN)); + + FixedNode successor = node.next(); + node.replaceAndDelete(stackValueNode); + stackValueNode.setNext(successor); + + graph.addAfterFixed(stackValueNode, writeNode); + stackValueNode.lower(tool); + } + } + + protected class VaListSnippetsLowering implements NodeLoweringProvider { + @Override + public void lower(VaListNextArgNode node, LoweringTool tool) { + SnippetInfo snippet; + switch (node.getStackKind()) { + case Double: + snippet = vaArgDouble; + break; + case Float: + snippet = vaArgFloat; + break; + case Long: + snippet = vaArgLong; + break; + case Int: + // everything narrower than int is promoted to int when passed in varargs + snippet = vaArgInt; + break; + default: + // getStackKind() should be at least int + throw VMError.shouldNotReachHere(); + } + Arguments args = new Arguments(snippet, node.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("vaListPointer", node.getVaList()); + template(tool, node, args).instantiate(tool.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64ArithmeticSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64ArithmeticSnippets.java new file mode 100644 index 000000000000..801b7452748a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64ArithmeticSnippets.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.graal.snippets.riscv64; + +import java.util.Map; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.util.Providers; + +import com.oracle.svm.core.graal.snippets.ArithmeticSnippets; +import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; + +final class RISCV64ArithmeticSnippets extends ArithmeticSnippets { + + @SuppressWarnings("unused") + public static void registerLowerings(OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings) { + new RISCV64ArithmeticSnippets(options, providers, lowerings); + } + + private RISCV64ArithmeticSnippets(OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings) { + super(options, providers, lowerings, true); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64NonSnippetLowerings.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64NonSnippetLowerings.java new file mode 100644 index 000000000000..d5312d13acff --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64NonSnippetLowerings.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.graal.snippets.riscv64; + +import java.util.Map; +import java.util.function.Predicate; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.util.Providers; + +import com.oracle.svm.core.graal.meta.RuntimeConfiguration; +import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; +import com.oracle.svm.core.graal.snippets.NonSnippetLowerings; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +final class RISCV64NonSnippetLowerings extends NonSnippetLowerings { + + @SuppressWarnings("unused") + public static void registerLowerings(RuntimeConfiguration runtimeConfig, Predicate mustNotAllocatePredicate, OptionValues options, + Providers providers, Map, NodeLoweringProvider> lowerings, boolean hosted) { + new RISCV64NonSnippetLowerings(runtimeConfig, mustNotAllocatePredicate, options, providers, lowerings, hosted); + } + + private RISCV64NonSnippetLowerings(RuntimeConfiguration runtimeConfig, Predicate mustNotAllocatePredicate, OptionValues options, + Providers providers, Map, NodeLoweringProvider> lowerings, boolean hosted) { + super(runtimeConfig, mustNotAllocatePredicate, options, providers, lowerings, hosted); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64SnippetsFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64SnippetsFeature.java new file mode 100644 index 000000000000..05b5dbab4bf6 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/riscv64/RISCV64SnippetsFeature.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.graal.snippets.riscv64; + +import java.util.Map; +import java.util.function.Predicate; + +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.graal.meta.RuntimeConfiguration; +import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; +import com.oracle.svm.core.heap.RestrictHeapAccessCallees; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@AutomaticallyRegisteredFeature +@Platforms(Platform.RISCV64.class) +class RISCV64SnippetsFeature implements InternalFeature { + + @Override + public void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues options, Providers providers, + Map, NodeLoweringProvider> lowerings, boolean hosted) { + + Predicate mustNotAllocatePredicate = null; + if (hosted) { + mustNotAllocatePredicate = method -> ImageSingletons.lookup(RestrictHeapAccessCallees.class).mustNotAllocate(method); + } + + RISCV64ArithmeticSnippets.registerLowerings(options, providers, lowerings); + RISCV64NonSnippetLowerings.registerLowerings(runtimeConfig, mustNotAllocatePredicate, options, providers, lowerings, hosted); + PosixRISCV64VaListSnippets.registerLowerings(options, providers, lowerings); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/StackValueNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/StackValueNode.java index 3e55032421aa..5d7bcf2ba523 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/StackValueNode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/StackValueNode.java @@ -145,12 +145,6 @@ public static ValueNode create(long numElements, long elementSize, GraphBuilderC public static StackValueNode create(int sizeInBytes, ResolvedJavaMethod method, int bci, boolean disallowVirtualThread) { String name = method.asStackTraceElement(bci).toString(); - if (UnsignedMath.aboveOrEqual(sizeInBytes, MAX_SIZE)) { - throw new PermanentBailoutException("stack value has illegal size " + sizeInBytes + ": " + name); - } - - /* Alignment is specified by StackValue API methods as "alignment used for stack frames". */ - int alignmentInBytes = ConfigurationValues.getTarget().stackAlignment; StackSlotIdentity slotIdentity = new StackSlotIdentity(name, false); /* @@ -160,6 +154,16 @@ public static StackValueNode create(int sizeInBytes, ResolvedJavaMethod method, * callees. */ boolean checkVirtualThread = disallowVirtualThread && VirtualThreads.isSupported() && !Uninterruptible.Utils.isUninterruptible(method); + return create(sizeInBytes, slotIdentity, checkVirtualThread); + } + + public static StackValueNode create(int sizeInBytes, StackSlotIdentity slotIdentity, boolean checkVirtualThread) { + if (UnsignedMath.aboveOrEqual(sizeInBytes, MAX_SIZE)) { + throw new PermanentBailoutException("stack value has illegal size " + sizeInBytes + ": " + slotIdentity.name); + } + + /* Alignment is specified by StackValue API methods as "alignment used for stack frames". */ + int alignmentInBytes = ConfigurationValues.getTarget().stackAlignment; return new StackValueNode(sizeInBytes, alignmentInBytes, slotIdentity, checkVirtualThread); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64CPUFeatureAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64CPUFeatureAccess.java new file mode 100644 index 000000000000..3cb7b3b265b7 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64CPUFeatureAccess.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.riscv64; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.AbstractCollection; +import java.util.ArrayList; +import java.util.EnumSet; + +import org.graalvm.compiler.core.riscv64.RISCV64ReflectionUtil; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.StackValue; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.word.Pointer; + +import com.oracle.svm.core.CPUFeatureAccessImpl; +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.UnmanagedMemoryUtil; +import com.oracle.svm.core.util.VMError; + +import jdk.vm.ci.code.Architecture; + +public class RISCV64CPUFeatureAccess extends CPUFeatureAccessImpl { + + @Platforms(Platform.HOSTED_ONLY.class) + public RISCV64CPUFeatureAccess(EnumSet buildtimeCPUFeatures, int[] offsets, byte[] errorMessageBytes, byte[] buildtimeFeatureMaskBytes) { + super(buildtimeCPUFeatures, offsets, errorMessageBytes, buildtimeFeatureMaskBytes); + } + + /** + * We include all flags which currently impact RISCV64 performance. + */ + @Platforms(Platform.HOSTED_ONLY.class) + public static EnumSet enabledRISCV64Flags() { + Class riscv64Flag = RISCV64ReflectionUtil.lookupClass(false, RISCV64ReflectionUtil.flagClass); + Method of = RISCV64ReflectionUtil.lookupMethod(EnumSet.class, "of", Enum.class, Enum.class); + return (EnumSet) RISCV64ReflectionUtil.invokeMethod(of, null, RISCV64ReflectionUtil.readStaticField(riscv64Flag, "UseConservativeFence"), + RISCV64ReflectionUtil.readStaticField(riscv64Flag, "AvoidUnalignedAccesses")); + } + + @Override + @Platforms(Platform.RISCV64.class) + public EnumSet determineHostCPUFeatures() { + Class riscv64CPUFeature = RISCV64ReflectionUtil.lookupClass(false, RISCV64ReflectionUtil.featureClass); + Method noneOf = RISCV64ReflectionUtil.lookupMethod(EnumSet.class, "noneOf", Class.class); + EnumSet features = (EnumSet) RISCV64ReflectionUtil.invokeMethod(noneOf, null, riscv64CPUFeature); + + RISCV64LibCHelper.CPUFeatures cpuFeatures = StackValue.get(RISCV64LibCHelper.CPUFeatures.class); + + UnmanagedMemoryUtil.fill((Pointer) cpuFeatures, SizeOf.unsigned(RISCV64LibCHelper.CPUFeatures.class), (byte) 0); + + RISCV64LibCHelper.determineCPUFeatures(cpuFeatures); + + ArrayList unknownFeatures = new ArrayList<>(); + for (Object feature : riscv64CPUFeature.getEnumConstants()) { + if (isFeaturePresent((Enum) feature, (Pointer) cpuFeatures, unknownFeatures)) { + Method add = RISCV64ReflectionUtil.lookupMethod(AbstractCollection.class, "add", Object.class); + RISCV64ReflectionUtil.invokeMethod(add, features, feature); + } + } + if (!unknownFeatures.isEmpty()) { + throw VMError.shouldNotReachHere("Native image does not support the following JVMCI CPU features: " + unknownFeatures); + } + + return features; + } + + @Uninterruptible(reason = "Thread state not set up yet.") + @Override + public int verifyHostSupportsArchitectureEarly() { + return RISCV64LibCHelper.checkCPUFeatures(BUILDTIME_CPU_FEATURE_MASK.get()); + } + + @Uninterruptible(reason = "Thread state not set up yet.") + @Override + public void verifyHostSupportsArchitectureEarlyOrExit() { + RISCV64LibCHelper.checkCPUFeaturesOrExit(BUILDTIME_CPU_FEATURE_MASK.get(), IMAGE_CPU_FEATURE_ERROR_MSG.get()); + } + + @Override + public void enableFeatures(Architecture runtimeArchitecture) { + EnumSet features = determineHostCPUFeatures(); + Method addAll = RISCV64ReflectionUtil.lookupMethod(AbstractCollection.class, "addAll", Object.class); + Method getFeatures = RISCV64ReflectionUtil.lookupMethod(Architecture.class, "getFeatures"); + try { + addAll.invoke(getFeatures.invoke(runtimeArchitecture), features); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64FrameAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64FrameAccess.java new file mode 100644 index 000000000000..6fc8f6c9e83d --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64FrameAccess.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.riscv64; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.function.CodePointer; +import org.graalvm.word.Pointer; + +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; + +@AutomaticallyRegisteredImageSingleton(FrameAccess.class) +@Platforms(Platform.RISCV64.class) +public class RISCV64FrameAccess extends FrameAccess { + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public CodePointer readReturnAddress(Pointer sourceSp) { + /* Read the return address, which is stored immediately below the stack pointer */ + return sourceSp.readWord(-returnAddressSize()); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public void writeReturnAddress(Pointer sourceSp, CodePointer newReturnAddress) { + sourceSp.writeWord(-returnAddressSize(), newReturnAddress); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public Pointer getReturnAddressLocation(Pointer sourceSp) { + return sourceSp.subtract(returnAddressSize()); + } + + @Fold + @Override + public int savedBasePointerSize() { + // The base pointer is always pushed on the stack on method entry + return wordSize(); + } + + @Override + @Fold + public int stackPointerAdjustmentOnCall() { + // A call on RISCV64 does not touch the SP. + return 0; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64LibCHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64LibCHelper.java new file mode 100644 index 000000000000..5ca52abdd0b1 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64LibCHelper.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.riscv64; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.function.CFunction; +import org.graalvm.nativeimage.c.function.CFunction.Transition; +import org.graalvm.nativeimage.c.function.CLibrary; +import org.graalvm.nativeimage.c.struct.AllowNarrowingCast; +import org.graalvm.nativeimage.c.struct.CField; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.word.PointerBase; + +@CLibrary(value = "libchelper", requireStatic = true) +public class RISCV64LibCHelper { + + @Platforms(Platform.RISCV64.class) + @CFunction(transition = Transition.NO_TRANSITION) + public static native void determineCPUFeatures(CPUFeatures features); + + @Platforms(Platform.RISCV64.class) + @CFunction(transition = Transition.NO_TRANSITION) + public static native int checkCPUFeatures(CCharPointer cCharPointer); + + @Platforms(Platform.RISCV64.class) + @CFunction(transition = Transition.NO_TRANSITION) + public static native int checkCPUFeaturesOrExit(CCharPointer buildtimeCPUFeatureMask, CCharPointer errorMessage); + + // Checkstyle: stop + @CStruct + @CContext(RISCV64LibCHelperDirectives.class) + public interface CPUFeatures extends PointerBase { + @AllowNarrowingCast + @CField + boolean fI(); + + @AllowNarrowingCast + @CField + boolean fM(); + + @AllowNarrowingCast + @CField + boolean fA(); + + @AllowNarrowingCast + @CField + boolean fF(); + + @AllowNarrowingCast + @CField + boolean fD(); + + @AllowNarrowingCast + @CField + boolean fC(); + + @AllowNarrowingCast + @CField + boolean fV(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64LibCHelperDirectives.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64LibCHelperDirectives.java new file mode 100644 index 000000000000..258543c51d25 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/riscv64/RISCV64LibCHelperDirectives.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.core.riscv64; + +import java.util.Collections; +import java.util.List; + +import org.graalvm.nativeimage.c.CContext; + +import com.oracle.svm.core.c.ProjectHeaderFile; + +public class RISCV64LibCHelperDirectives implements CContext.Directives { + + @Override + public List getHeaderFiles() { + return Collections.singletonList(ProjectHeaderFile.resolve("com.oracle.svm.native.libchelper", "include/riscv64cpufeatures.h")); + } +} diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java index 440a81c71a5d..d1ea5f1b4240 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java @@ -516,7 +516,7 @@ private static void filterArchitectureServices(String archPackage, Map, for (List list : services.values()) { list.removeIf(o -> { String name = o.getClass().getName(); - if (name.contains(".aarch64.") || name.contains(".amd64.")) { + if (name.contains(".aarch64.") || name.contains(".amd64.") || name.contains(".riscv64.")) { return !name.contains(archPackage); } return false; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 64e9b3e6ac73..8f5377833984 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -39,6 +39,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -67,6 +68,7 @@ import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.core.common.spi.MetaAccessExtensionProvider; +import org.graalvm.compiler.core.riscv64.RISCV64ReflectionUtil; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext.Builder; @@ -223,6 +225,7 @@ import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.option.RuntimeOptionValues; import com.oracle.svm.core.option.SubstrateOptionsParser; +import com.oracle.svm.core.riscv64.RISCV64CPUFeatureAccess; import com.oracle.svm.core.snippets.SnippetRuntime; import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.UserError; @@ -497,6 +500,28 @@ public static SubstrateTargetDescription createTarget(Platform platform) { EnumSet runtimeCheckedFeatures = ((AArch64) architecture).getFeatures().clone(); int deoptScratchSpace = 2 * 8; // Space for two 64-bit registers: r0 and v0. return new SubstrateTargetDescription(architecture, true, 16, 0, deoptScratchSpace, runtimeCheckedFeatures); + } else if (includedIn(platform, Platform.RISCV64.class)) { + Class riscv64CPUFeature = RISCV64ReflectionUtil.lookupClass(false, RISCV64ReflectionUtil.featureClass); + Architecture architecture; + if (NativeImageOptions.NativeArchitecture.getValue()) { + architecture = GraalAccess.getOriginalTarget().arch; + } else { + Method noneOf = RISCV64ReflectionUtil.lookupMethod(EnumSet.class, "noneOf", Class.class); + EnumSet features = (EnumSet) RISCV64ReflectionUtil.invokeMethod(noneOf, null, riscv64CPUFeature); + Method parseCSVtoEnum = RISCV64ReflectionUtil.lookupMethod(NativeImageGenerator.class, "parseCSVtoEnum", Class.class, List.class, Enum[].class); + parseCSVtoEnum.setAccessible(true); + Method addAll = RISCV64ReflectionUtil.lookupMethod(AbstractCollection.class, "addAll", Collection.class); + + RISCV64ReflectionUtil.invokeMethod(addAll, features, + RISCV64ReflectionUtil.invokeMethod(parseCSVtoEnum, null, riscv64CPUFeature, NativeImageOptions.CPUFeatures.getValue().values(), riscv64CPUFeature.getEnumConstants())); + + architecture = (Architecture) ReflectionUtil.newInstance(ReflectionUtil.lookupConstructor(RISCV64ReflectionUtil.getArch(false), EnumSet.class, EnumSet.class), features, + RISCV64CPUFeatureAccess.enabledRISCV64Flags()); + } + Method getFeatures = RISCV64ReflectionUtil.lookupMethod(Architecture.class, "getFeatures"); + EnumSet runtimeCheckedFeatures = ((EnumSet) RISCV64ReflectionUtil.invokeMethod(getFeatures, architecture)).clone(); + int deoptScratchSpace = 2 * 8; + return new SubstrateTargetDescription(architecture, true, 16, 0, deoptScratchSpace, runtimeCheckedFeatures); } else { throw UserError.abort("Architecture specified by platform is not supported: %s", platform.getClass().getTypeName()); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index dd4f9dbf36cb..18583cd18499 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -43,6 +43,7 @@ import java.util.stream.Collectors; import org.graalvm.collections.Pair; +import org.graalvm.compiler.core.riscv64.ShadowedRISCV64; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.printer.GraalDebugHandlersFactory; @@ -258,7 +259,7 @@ private static void reportToolUserError(String msg) { private static boolean isValidArchitecture() { final Architecture originalTargetArch = GraalAccess.getOriginalTarget().arch; - return originalTargetArch instanceof AMD64 || originalTargetArch instanceof AArch64; + return originalTargetArch instanceof AMD64 || originalTargetArch instanceof AArch64 || ShadowedRISCV64.instanceOf(originalTargetArch); } private static boolean isValidOperatingSystem() { @@ -498,7 +499,7 @@ protected void verifyMainEntryPoint(Method mainEntryPoint) { public static boolean verifyValidJavaVersionAndPlatform() { if (!isValidArchitecture()) { - reportToolUserError("runs on AMD64 and AArch64 only. Detected architecture: " + ClassUtil.getUnqualifiedName(GraalAccess.getOriginalTarget().arch.getClass())); + reportToolUserError("runs on AMD64, AArch64 and RISCV64 only. Detected architecture: " + ClassUtil.getUnqualifiedName(GraalAccess.getOriginalTarget().arch.getClass())); } if (!isValidOperatingSystem()) { reportToolUserError("runs on Linux, Mac OS X and Windows only. Detected OS: " + System.getProperty("os.name")); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/RISCV64CPUFeatureAccessFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/RISCV64CPUFeatureAccessFeature.java new file mode 100644 index 000000000000..b08b713712cd --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/RISCV64CPUFeatureAccessFeature.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ +package com.oracle.svm.hosted; + +import java.lang.reflect.Method; +import java.util.EnumSet; + +import org.graalvm.compiler.core.riscv64.RISCV64ReflectionUtil; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.SubstrateTargetDescription; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.riscv64.RISCV64CPUFeatureAccess; +import com.oracle.svm.core.riscv64.RISCV64LibCHelper; +import com.oracle.svm.util.ReflectionUtil; + +import jdk.vm.ci.code.Architecture; + +@AutomaticallyRegisteredFeature +@Platforms(Platform.RISCV64.class) +class RISCV64CPUFeatureAccessFeature extends CPUFeatureAccessFeatureBase implements InternalFeature { + + @Override + public void beforeAnalysis(BeforeAnalysisAccess arg) { + var targetDescription = ImageSingletons.lookup(SubstrateTargetDescription.class); + Method getFeatures = ReflectionUtil.lookupMethod(Architecture.class, "getFeatures"); + var buildtimeCPUFeatures = RISCV64ReflectionUtil.invokeMethod(getFeatures, targetDescription.arch); + Class riscv64CPUFeature = RISCV64ReflectionUtil.lookupClass(false, RISCV64ReflectionUtil.featureClass); + Method values = ReflectionUtil.lookupMethod(riscv64CPUFeature, "values"); + Method initializeCPUFeatureAccessData = ReflectionUtil.lookupMethod(CPUFeatureAccessFeatureBase.class, + "initializeCPUFeatureAccessData", Enum[].class, EnumSet.class, Class.class, FeatureImpl.BeforeAnalysisAccessImpl.class); + RISCV64ReflectionUtil.invokeMethod(initializeCPUFeatureAccessData, this, RISCV64ReflectionUtil.invokeMethod(values, null), buildtimeCPUFeatures, RISCV64LibCHelper.CPUFeatures.class, arg); + } + + @Override + protected RISCV64CPUFeatureAccess createCPUFeatureAccessSingleton(EnumSet buildtimeCPUFeatures, int[] offsets, byte[] errorMessageBytes, byte[] buildtimeFeatureMaskBytes) { + return new RISCV64CPUFeatureAccess(buildtimeCPUFeatures, offsets, errorMessageBytes, buildtimeFeatureMaskBytes); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java index 155e1f3295ea..adbdff26ba03 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java @@ -40,6 +40,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; +import org.graalvm.compiler.core.riscv64.RISCV64ReflectionUtil; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; @@ -438,6 +439,8 @@ protected static Class guessArchitecture(String archStr) case "aarch64": case "arm64": /* Darwin notation */ return AArch64.class; + case "riscv64": + return (Class) RISCV64ReflectionUtil.getArch(false); case "i686": case "80x86": /* Windows notation */ case "x86": diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java index 362b8ab0898b..ce5e951fc4ee 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java @@ -214,6 +214,11 @@ public List getCommand() { cmd.addAll(getNativeLinkerOptions()); + /* RISC-V always needs the -latomic option */ + if (Platform.includedIn(Platform.RISCV64.class)) { + cmd.add("-latomic"); + } + return cmd; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallVariantWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallVariantWrapperMethod.java index 6c7cebe2d3fa..d4a6e45abfbd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallVariantWrapperMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallVariantWrapperMethod.java @@ -37,6 +37,7 @@ import org.graalvm.compiler.nodes.CallTargetNode; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.IndirectCallTargetNode; import org.graalvm.compiler.nodes.InvokeWithExceptionNode; import org.graalvm.compiler.nodes.NodeView; @@ -44,6 +45,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.ValuePhiNode; import org.graalvm.compiler.nodes.calc.FloatConvertNode; +import org.graalvm.compiler.nodes.calc.ReinterpretNode; import org.graalvm.compiler.nodes.memory.OnHeapMemoryAccess.BarrierType; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; import org.graalvm.compiler.word.WordTypes; @@ -60,6 +62,7 @@ import com.oracle.svm.core.graal.nodes.CEntryPointLeaveNode; import com.oracle.svm.core.graal.nodes.CInterfaceReadNode; import com.oracle.svm.core.graal.nodes.ReadCallerStackPointerNode; +import com.oracle.svm.core.graal.nodes.VaListInitializationNode; import com.oracle.svm.core.graal.nodes.VaListNextArgNode; import com.oracle.svm.core.jni.CallVariant; import com.oracle.svm.core.jni.JNIJavaCallVariantWrapperHolder; @@ -114,6 +117,8 @@ private static Signature createSignature(Signature callWrapperSignature, CallVar JavaKind kind = callWrapperSignature.getParameterKind(i); if (kind.isObject()) { args.add(wordKind); // handle + } else if (Platform.includedIn(Platform.RISCV64.class) && (kind == JavaKind.Float || kind == JavaKind.Double)) { + args.add(JavaKind.Long); } else if (kind == JavaKind.Float) { // C varargs promote float to double (C99, 6.5.2.2-6) args.add(JavaKind.Double); @@ -256,10 +261,15 @@ private List loadArguments(JNIGraphKit kit, HostedProviders providers JavaKind kind = invokeSignature.getParameterKind(i); assert kind == kind.getStackKind() : "sub-int conversions and bit masking must happen in JNIJavaCallWrapperMethod"; JavaKind loadKind = kind; - if (loadKind == JavaKind.Float) { + if (Platform.includedIn(Platform.RISCV64.class) && (kind == JavaKind.Double || kind == JavaKind.Float)) { + loadKind = JavaKind.Long; + } else if (loadKind == JavaKind.Float) { loadKind = JavaKind.Double; // C varargs promote float to double (C99 6.5.2.2-6) } ValueNode value = kit.loadLocal(slotIndex, loadKind); + if (Platform.includedIn(Platform.RISCV64.class) && (kind == JavaKind.Double || kind == JavaKind.Float)) { + value = kit.unique(new ReinterpretNode(JavaKind.Double, value)); + } if (kind == JavaKind.Float) { value = kit.unique(new FloatConvertNode(FloatConvert.D2F, value)); } @@ -267,14 +277,15 @@ private List loadArguments(JNIGraphKit kit, HostedProviders providers slotIndex += loadKind.getSlotCount(); } } else if (callVariant == CallVariant.VA_LIST) { - ValueNode valist = kit.loadLocal(slotIndex, wordKind); + ValueNode vaList = kit.loadLocal(slotIndex, wordKind); + FixedWithNextNode vaListInitialized = kit.append(new VaListInitializationNode(vaList)); for (int i = firstParamIndex; i < count; i++) { JavaKind kind = invokeSignature.getParameterKind(i); if (kind.isObject()) { kind = wordKind; } assert kind == kind.getStackKind() : "sub-int conversions and bit masking must happen in JNIJavaCallWrapperMethod"; - ValueNode value = kit.append(new VaListNextArgNode(kind, valist)); + ValueNode value = kit.append(new VaListNextArgNode(kind, vaListInitialized)); args.add(value); } } else { diff --git a/substratevm/src/com.oracle.svm.native.libchelper/include/riscv64cpufeatures.h b/substratevm/src/com.oracle.svm.native.libchelper/include/riscv64cpufeatures.h new file mode 100644 index 000000000000..9a9060b5de4a --- /dev/null +++ b/substratevm/src/com.oracle.svm.native.libchelper/include/riscv64cpufeatures.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +typedef struct { + char fI; + char fM; + char fA; + char fF; + char fD; + char fC; + char fV; +} CPUFeatures; diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c b/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c index 96cd2a199d6f..08127b9c890a 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c +++ b/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c @@ -781,9 +781,62 @@ void determineCPUFeatures(CPUFeatures* features) { } #endif +#elif defined(__riscv) +/* + * The corresponding HotSpot code can be found in vm_version_riscv and + * vm_version_linux_riscv. + */ + +#include +#include +#include "riscv64cpufeatures.h" + +#ifndef HWCAP_ISA_I +#define HWCAP_ISA_I (1 << ('I' - 'A')) +#endif + +#ifndef HWCAP_ISA_M +#define HWCAP_ISA_M (1 << ('M' - 'A')) +#endif + +#ifndef HWCAP_ISA_A +#define HWCAP_ISA_A (1 << ('A' - 'A')) +#endif + +#ifndef HWCAP_ISA_F +#define HWCAP_ISA_F (1 << ('F' - 'A')) +#endif + +#ifndef HWCAP_ISA_D +#define HWCAP_ISA_D (1 << ('D' - 'A')) +#endif + +#ifndef HWCAP_ISA_C +#define HWCAP_ISA_C (1 << ('C' - 'A')) +#endif + +#ifndef HWCAP_ISA_V +#define HWCAP_ISA_V (1 << ('V' - 'A')) +#endif + +/* + * Extracts the CPU features by reading the hwcaps + */ +void determineCPUFeatures(CPUFeatures* features) { + + unsigned long auxv = getauxval(AT_HWCAP); + features->fI = !!(auxv & HWCAP_ISA_I); + features->fM = !!(auxv & HWCAP_ISA_M); + features->fA = !!(auxv & HWCAP_ISA_A); + features->fF = !!(auxv & HWCAP_ISA_F); + features->fD = !!(auxv & HWCAP_ISA_D); + features->fC = !!(auxv & HWCAP_ISA_C); + features->fV = !!(auxv & HWCAP_ISA_V); +} + #else /* - * Dummy for non AMD64 and non AArch64 + * Dummy for non AMD64, non AArch64 and non RISCV64 */ void determineCPUFeatures(void* features) { } diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java index 5761b8f0855a..0986d6366939 100644 --- a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java @@ -109,6 +109,14 @@ public static T newInstance(Class declaringClass) { } } + public static T newInstance(Constructor constructor, Object... initArgs) { + try { + return constructor.newInstance(initArgs); + } catch (ReflectiveOperationException ex) { + throw new ReflectionUtilError(ex); + } + } + public static Field lookupField(Class declaringClass, String fieldName) { return lookupField(false, declaringClass, fieldName); } diff --git a/tools/mx.tools/suite.py b/tools/mx.tools/suite.py index 634705ebb174..e728ecfc964e 100644 --- a/tools/mx.tools/suite.py +++ b/tools/mx.tools/suite.py @@ -336,7 +336,10 @@ "aarch64" : { "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/visualvm/visualvm-1089-linux-aarch64.tar.gz"], "digest" : "sha512:8987f5c0f3922df71dbc33249a15c5840b3e2164a6ace1dd14730542e9536ab11dd332ceff41b6b16900f9bfca9bc779f83e06bec30ec28c1915d1b8830e00ea", - } + }, + "": { + "optional": True, + }, }, "darwin" : { "amd64" : { From 6317c96a5257be2b1e6fc410f533dece451f0f55 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Thu, 28 Jul 2022 09:17:28 +0200 Subject: [PATCH 2/2] Allow to use CLibraryPath to load Java static libraries --- .../src/com/oracle/svm/hosted/c/NativeLibraries.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java index 2ce976b55f91..1377a46b600b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java @@ -326,6 +326,17 @@ private static LinkedHashSet initCLibraryPath() { String libraryLocationHint = System.lineSeparator() + "(search path: " + jdkLibDir + ")"; hint = defaultBuiltInLibraries.stream().filter(hasStaticLibrary.negate()).collect(Collectors.joining(", ", "Missing libraries: ", libraryLocationHint)); } + + /* Probe for static JDK libraries in user-specified CLibraryPath directory */ + if (staticLibsDir == null) { + for (String clibPathComponent : SubstrateOptions.CLibraryPath.getValue().values()) { + Path path = Paths.get(clibPathComponent); + Predicate hasStaticLibraryCLibraryPath = s -> Files.isRegularFile(path.resolve(getStaticLibraryName(s))); + if (defaultBuiltInLibraries.stream().allMatch(hasStaticLibraryCLibraryPath)) { + return libraryPaths; + } + } + } } catch (IOException e) { /* Fallthrough to next strategy */ hint = e.getMessage();