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
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2025, 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.
*/
package com.oracle.svm.core.windows;

import static com.oracle.svm.core.windows.headers.StringAPISet.CP_ACP;
import static com.oracle.svm.core.windows.headers.StringAPISet.MultiByteToWideChar;

import org.graalvm.nativeimage.c.type.CCharPointer;

import com.oracle.svm.core.JavaMainWrapper;
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
import com.oracle.svm.core.handles.PrimitiveArrayView;
import com.oracle.svm.core.log.StringBuilderLog;
import com.oracle.svm.core.util.UnsignedUtils;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.core.windows.headers.WinBase;
import com.oracle.svm.core.windows.headers.WindowsLibC;

import jdk.graal.compiler.word.Word;

@AutomaticallyRegisteredImageSingleton
class WindowsJavaMainWrapperArgsSupport extends JavaMainWrapper.ArgsSupport {
@Override
protected String toJavaArg(CCharPointer rawArg) {
/*
* On Windows, wide-character strings are UTF-16LE, matching Java char[]. So we convert ANSI
* bytes directly into a Java char[] (excluding the trailing NUL) and construct the String.
*/
int rawLen = UnsignedUtils.safeToInt(WindowsLibC.strlen(rawArg)); // excludes trailing NUL
if (rawLen == 0) {
return ""; // MultiByteToWideChar would fail here
}
int wcLen = checkResult(MultiByteToWideChar(CP_ACP(), 0, rawArg, rawLen, Word.nullPointer(), 0));
char[] wcArg = new char[wcLen];
try (var wcBuf = PrimitiveArrayView.createForReadingAndWriting(wcArg)) {
checkResult(MultiByteToWideChar(CP_ACP(), 0, rawArg, rawLen, wcBuf.addressOfArrayElement(0), wcLen));
}
return new String(wcArg);
}

private static int checkResult(int result) {
if (result == 0) {
var log = new StringBuilderLog();
log.string("MultiByteToWideChar failed with error ").hex(WinBase.GetLastError());
throw VMError.shouldNotReachHere(log.getResult());
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2025, 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.
*/
package com.oracle.svm.core.windows.headers;

import org.graalvm.nativeimage.c.CContext;
import org.graalvm.nativeimage.c.constant.CConstant;
import org.graalvm.nativeimage.c.function.CFunction;
import org.graalvm.nativeimage.c.type.CCharPointer;

import com.oracle.svm.core.windows.headers.WindowsLibC.WCharPointer;

// Checkstyle: stop

/**
* Definitions for Windows stringapiset.h
*/
@CContext(WindowsDirectives.class)
public class StringAPISet {

/** The system-wide Windows ANSI code page. */
@CConstant
public static native int CP_ACP();

/** Maps a character string to a UTF-16 (wide character) string. */
@CFunction(transition = CFunction.Transition.NO_TRANSITION)
public static native int MultiByteToWideChar(int CodePage, int dwFlags, CCharPointer lpMultiByteStr, int cbMultiByte, WCharPointer lpWideCharStr, int cchWideChar);
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import com.oracle.svm.core.c.function.CEntryPointOptions.NoEpilogue;
import com.oracle.svm.core.c.function.CEntryPointOptions.NoPrologue;
import com.oracle.svm.core.c.function.CEntryPointSetup;
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
import com.oracle.svm.core.graal.snippets.CEntryPointSnippets;
import com.oracle.svm.core.jdk.InternalVMMethod;
import com.oracle.svm.core.jdk.RuntimeSupport;
Expand Down Expand Up @@ -150,7 +151,7 @@ public String getJavaCommand() {
public List<String> getInputArguments() {
CEntryPointCreateIsolateParameters args = MAIN_ISOLATE_PARAMETERS.get();
if (args.getArgv().isNonNull() && args.getArgc() > 0) {
String[] unmodifiedArgs = SubstrateUtil.convertCToJavaArgs(args.getArgc(), args.getArgv());
String[] unmodifiedArgs = ArgsSupport.convertCToJavaArgs(args.getArgc(), args.getArgv());
List<String> inputArgs = new ArrayList<>(Arrays.asList(unmodifiedArgs));

if (mainArgs != null) {
Expand Down Expand Up @@ -479,4 +480,34 @@ static void enter(Isolate isolate) {
}
}
}

/** Support for platform-specific conversion of the command line to Java main arguments. */
@AutomaticallyRegisteredImageSingleton(ArgsSupport.class)
public static class ArgsSupport {
private static ArgsSupport singleton() {
return ImageSingletons.lookup(ArgsSupport.class);
}

/**
* Convert C-style to Java-style command line arguments. The first C-style argument, which
* is always the executable file name, is ignored.
*
* @param argc the number of arguments in the {@code argv} array.
* @param argv a C {@code char**}.
*
* @return the command line argument strings in a Java string array.
*/
public static String[] convertCToJavaArgs(int argc, CCharPointerPointer argv) {
String[] args = new String[argc - 1];
for (int i = 1; i < argc; ++i) {
args[i - 1] = singleton().toJavaArg(argv.read(i));
}
return args;
}

/** Converts a single argv element to a Java string. */
protected String toJavaArg(CCharPointer rawArg) {
return CTypeConversion.toJavaString(rawArg);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.CCharPointerPointer;
import org.graalvm.nativeimage.c.type.CTypeConversion;
import org.graalvm.word.Pointer;
import org.graalvm.word.UnsignedWord;

Expand Down Expand Up @@ -152,23 +150,6 @@ public static FileDescriptor getFileDescriptor(FileOutputStream out) {
return SubstrateUtil.cast(out, Target_java_io_FileOutputStream.class).fd;
}

/**
* Convert C-style to Java-style command line arguments. The first C-style argument, which is
* always the executable file name, is ignored.
*
* @param argc the number of arguments in the {@code argv} array.
* @param argv a C {@code char**}.
*
* @return the command line argument strings in a Java string array.
*/
public static String[] convertCToJavaArgs(int argc, CCharPointerPointer argv) {
String[] args = new String[argc - 1];
for (int i = 1; i < argc; ++i) {
args[i - 1] = CTypeConversion.toJavaString(argv.read(i));
}
return args;
}

/**
* Returns the length of a C {@code char*} string.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import java.util.Map;

import com.oracle.svm.core.JavaMainWrapper;
import org.graalvm.nativeimage.CurrentIsolate;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Isolate;
Expand All @@ -60,7 +61,6 @@
import com.oracle.svm.core.RuntimeAssertionsSupport;
import com.oracle.svm.core.SubstrateDiagnostics;
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.Uninterruptible;
import com.oracle.svm.core.UnmanagedMemoryUtil;
import com.oracle.svm.core.c.CGlobalData;
Expand Down Expand Up @@ -452,7 +452,7 @@ private static int initializeIsolateInterruptibly1(CEntryPointCreateIsolateParam
exitWhenArgumentParsingFails = parameters.getExitWhenArgumentParsingFails();
}

String[] args = SubstrateUtil.convertCToJavaArgs(parameters.getArgc(), parameters.getArgv());
String[] args = JavaMainWrapper.ArgsSupport.convertCToJavaArgs(parameters.getArgc(), parameters.getArgv());
try {
args = RuntimeOptionParser.parseAndConsumeAllOptions(args, ignoreUnrecognized);
} catch (IllegalArgumentException e) {
Expand Down