Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion substratevm/mx.substratevm/suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,8 @@
],
"jdk.internal.vm.ci" : [
"jdk.vm.ci.code",
"jdk.vm.ci.meta"
"jdk.vm.ci.meta",
"jdk.vm.ci.amd64",
],
},
"javaCompliance" : "22+",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -24,14 +24,29 @@
*/
package com.oracle.svm.core.foreign;

import java.lang.foreign.MemorySegment;
import java.lang.foreign.SymbolLookup;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;

import org.graalvm.nativeimage.Platform.WINDOWS;
import org.graalvm.nativeimage.Platforms;
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.word.Pointer;

import com.oracle.svm.core.OS;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.util.BasedOnJDKClass;

import jdk.graal.compiler.word.Word;
import jdk.internal.foreign.Utils;

/**
* Separated from {@link Target_jdk_internal_foreign_SystemLookup} to allow (forced) runtime
* initialization.
Expand All @@ -56,7 +71,28 @@ public static SymbolLookup makeSystemLookup() {
Path msvcrt = system32.resolve("msvcrt.dll");
boolean useUCRT = Files.exists(ucrtbase);
Path stdLib = useUCRT ? ucrtbase : msvcrt;
return Util_java_lang_foreign_SymbolLookup.libraryLookup(LookupNativeLibraries::loadLibraryPlatformSpecific, List.of(stdLib));

SymbolLookup lookup = Util_java_lang_foreign_SymbolLookup.libraryLookup(LookupNativeLibraries::loadLibraryPlatformSpecific, List.of(stdLib));
if (useUCRT) {
// use a fallback lookup to look up inline functions
Function<String, Optional<MemorySegment>> fallbackLookup = name -> {
Pointer ptr = getWindowsFallbackSymbol(name);
if (ptr.isNonNull()) {
return Optional.of(MemorySegment.ofAddress(ptr.rawValue()));
}
return Optional.empty();
};
final SymbolLookup finalLookup = lookup;
lookup = name -> {
Objects.requireNonNull(name);
if (Utils.containsNullChars(name)) {
return Optional.empty();
}
return finalLookup.find(name).or(() -> fallbackLookup.apply(name));
};
}

return lookup;
} else {
/*
* This list of libraries was obtained by examining the dependencies of libsystemlookup,
Expand All @@ -65,4 +101,27 @@ public static SymbolLookup makeSystemLookup() {
return Util_java_lang_foreign_SymbolLookup.libraryLookup(LookupNativeLibraries::loadLibraryPlatformSpecific, List.of("libc.so.6", "libm.so.6", "libdl.so.2"));
}
}

/**
* Returns the function pointer of the requested symbol specified with
* {@link Target_jdk_internal_foreign_SystemLookup_WindowsFallbackSymbols}. See also file
* 'com.oracle.svm.native.libchelper/src/syslookup.c'.
*/
@Platforms(WINDOWS.class)
@CLibrary(value = "libchelper", requireStatic = true)
@CFunction(value = "__svm_get_syslookup_func", transition = Transition.NO_TRANSITION)
public static native Pointer getSyslookupFunc(int i, int nExpected);

private static Pointer getWindowsFallbackSymbol(String name) {
try {
assert Target_jdk_internal_foreign_SystemLookup_WindowsFallbackSymbols.class.isEnum();
@SuppressWarnings({"unchecked", "rawtypes"})
Enum value = Enum.valueOf(SubstrateUtil.cast(Target_jdk_internal_foreign_SystemLookup_WindowsFallbackSymbols.class, Class.class), name);
Pointer func = getSyslookupFunc(value.ordinal(), Target_jdk_internal_foreign_SystemLookup_WindowsFallbackSymbols.class.getEnumConstants().length);
assert func.isNonNull() : "Function pointer for " + value.name() + " is NULL but shouldn't.";
return func;
} catch (IllegalArgumentException e) {
return Word.nullPointer();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import java.lang.foreign.MemorySegment;
import java.util.Optional;

import com.oracle.svm.core.annotate.Delete;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;

Expand All @@ -44,7 +43,11 @@ public Optional<MemorySegment> find(String name) {
}
}

/*
* IMPORTANT: If the substitution target (i.e. enum
* 'jdk.internal.foreign.SystemLookup$WindowsFallbackSymbols') changes, ensure that the enum values
* are still in sync with 'com.oracle.svm.native.libchelper/src/syslookup.c'.
*/
@TargetClass(className = "jdk.internal.foreign.SystemLookup", innerClass = "WindowsFallbackSymbols", onlyWith = ForeignFunctionsEnabled.class)
@Delete
final class Target_jdk_internal_foreign_SystemLookup_WindowsFallbackSymbols {
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import jdk.graal.compiler.nodes.java.NewArrayNode;
import jdk.graal.compiler.replacements.nodes.ReadRegisterNode;
import jdk.graal.compiler.replacements.nodes.WriteRegisterNode;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.MetaAccessProvider;
Expand Down Expand Up @@ -125,9 +126,14 @@ public ValueNode bindRegister(Register register, JavaKind kind) {
return append(new ReadRegisterNode(register, kind, false, false));
}

private JavaKind getRegisterKind(Register register) {
// GR-62468: possible incorrect backup/restore of XMM register (Windows only)
return AMD64.XMM.equals(register.getRegisterCategory()) ? JavaKind.Double : getWordTypes().getWordKind();
}

public Map<Register, ValueNode> saveRegisters(Iterable<Register> registers) {
return StreamSupport.stream(registers.spliterator(), false)
.collect(Collectors.toMap(reg -> reg, register -> bindRegister(register, getWordTypes().getWordKind())));
.collect(Collectors.toMap(reg -> reg, register -> bindRegister(register, getRegisterKind(register))));
}

public void restoreRegisters(Map<Register, ValueNode> save) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,11 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos
List<ValueNode> arguments = new ArrayList<>(kit.getInitialArguments());

/*
* Prologue: save function-preserved registers, allocate return space if needed, transition
* from native to Java.
* Prologue: save callee-save registers, allocate return space if needed, transition from
* native to Java.
*
* Saving the callee-save registers is necessary because the invocation of the high-level
* stub uses the Java calling convention which may interfere with those registers.
*/
assert !savedRegisters.asList().contains(registers.methodHandle());
assert !savedRegisters.asList().contains(registers.isolate());
Expand All @@ -213,11 +216,11 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos
FrameState frameState = new FrameState(BytecodeFrame.UNKNOWN_BCI);
frameState.invalidateForDeoptimization();
returnBuffer.setStateAfter(kit.getGraph().add(frameState));
arguments.add(0, returnBuffer);
arguments.addFirst(returnBuffer);
}

/* Transfers to the Java-side stub; note that exceptions should be handled there. */
arguments.add(0, mh);
arguments.addFirst(mh);
InvokeWithExceptionNode returnValue = kit.createJavaCallWithException(CallTargetNode.InvokeKind.Static, highLevelStub, arguments.toArray(ValueNode.EMPTY_ARRAY));
kit.exceptionPart();
kit.append(new DeadEndNode());
Expand All @@ -232,6 +235,7 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos
long offset = 0;
for (AssignedLocation loc : AbiUtils.create().toMemoryAssignment(jep.returnAssignment(), true)) {
assert loc.assignsToRegister();
// an output location must not be a callee-save register
assert !save.containsKey(loc.register());

AddressNode address = new OffsetAddressNode(returnBuffer, ConstantNode.forLong(offset, kit.getGraph()));
Expand Down Expand Up @@ -307,7 +311,7 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos

List<ValueNode> allArguments = new ArrayList<>(kit.getInitialArguments());

ValueNode mh = allArguments.remove(0);
ValueNode mh = allArguments.removeFirst();
/* If adaptations are ever needed for upcalls, they should most likely be applied here */
allArguments = kit.boxArguments(allArguments, jep.handleType());
ValueNode arguments = kit.packArguments(allArguments);
Expand Down
100 changes: 100 additions & 0 deletions substratevm/src/com.oracle.svm.native.libchelper/src/syslookup.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute 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.
*/

#ifdef _WIN64

#include <stdio.h>
#include <stdint.h>
#include <time.h>

// Forces generation of code on Windows for functions that are not available as regular symbols
static void* _syslookup_funcs[] = {
// stdio.h
&fprintf,
&fprintf_s,
&fscanf,
&fscanf_s,
&fwprintf,
&fwprintf_s,
&fwscanf,
&fwscanf_s,
&printf,
&printf_s,
&scanf,
&scanf_s,
&snprintf,
&sprintf,
&sprintf_s,
&sscanf,
&sscanf_s,
&swprintf,
&swprintf_s,
&swscanf,
&swscanf_s,
&vfprintf,
&vfprintf_s,
&vfscanf,
&vfscanf_s,
&vfwprintf,
&vfwprintf_s,
&vfwscanf,
&vfwscanf_s,
&vprintf,
&vprintf_s,
&vscanf,
&vscanf_s,
&vsnprintf,
&vsnprintf_s,
&vsprintf,
&vsprintf_s,
&vsscanf,
&vsscanf_s,
&vswprintf,
&vswprintf_s,
&vswscanf,
&vswscanf_s,
&vwprintf,
&vwprintf_s,
&vwscanf,
&vwscanf_s,
&wprintf,
&wprintf_s,
&wscanf,
&wscanf_s,

// time.h
&gmtime
};

#define N_SYSLOOKUP_FUNCS (sizeof(_syslookup_funcs) / sizeof(void*))

void* __svm_get_syslookup_func(int32_t i, int32_t n_expected) {
if (n_expected != N_SYSLOOKUP_FUNCS || i < 0 || i >= N_SYSLOOKUP_FUNCS) {
return NULL;
}
return _syslookup_funcs[i];
}

#endif
Loading