Skip to content
Open
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
Expand Up @@ -43,11 +43,15 @@
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.StackValue;
import org.graalvm.nativeimage.VMRuntime;
import org.graalvm.nativeimage.c.CContext;
import org.graalvm.nativeimage.c.function.CEntryPoint;
import org.graalvm.nativeimage.c.function.CFunction;
import org.graalvm.nativeimage.c.function.CFunctionPointer;
import org.graalvm.nativeimage.c.struct.CPointerTo;
import org.graalvm.nativeimage.c.struct.SizeOf;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.CCharPointerPointer;
import org.graalvm.nativeimage.c.type.CIntPointer;
import org.graalvm.nativeimage.c.type.CTypeConversion;
import org.graalvm.nativeimage.c.type.CTypeConversion.CCharPointerHolder;
import org.graalvm.nativeimage.c.type.WordPointer;
Expand Down Expand Up @@ -272,7 +276,11 @@ private static int runCore0() {
* exceptions in a InvocationTargetException.
*/
JavaMainSupport mainSupport = ImageSingletons.lookup(JavaMainSupport.class);
invokeMain(mainSupport.mainArgs);
String[] args = mainSupport.mainArgs;
if (Platform.includedIn(Platform.WINDOWS.class)) {
args = WindowsArguments.alterArgs(args);
}
invokeMain(args);

return 0;
} catch (Throwable ex) {
Expand All @@ -287,6 +295,88 @@ private static int runCore0() {
}
}

@CContext(WindowsArguments.Directives.class)
final class WindowsArguments {

private WindowsArguments() {
}

public static String[] alterArgs(String[] originalArgs) {
return readCommandLineArgs();
}

private static final int WCHAR_SIZE = 2;

private static String[] readCommandLineArgs() {
var cmd = GetCommandLineW();

CIntPointer numOfArgs = StackValue.get(Long.BYTES);

WCharPointerPointer args = CommandLineToArgvW(cmd, numOfArgs);
try {
var numArgs = numOfArgs.read();

var results = new String[numArgs - 1];
for (var i = 0; i < results.length; i++) {
var arg = args.read(i + 1);
results[i] = toJavaString(arg);
}

return results;
} finally {
LocalFree(args);
}
}

private static String toJavaString(WCharPointer arg) {
return CTypeConversion.asByteBuffer(arg, wcslen(arg) * WCHAR_SIZE)
.order(java.nio.ByteOrder.LITTLE_ENDIAN)
.asCharBuffer()
.toString();
}

@CPointerTo(nameOfCType = "wchar_t")
private interface WCharPointer extends PointerBase {
}

@CPointerTo(WCharPointer.class)
private interface WCharPointerPointer extends PointerBase {

WCharPointer read(int index);
}

@CFunction
private static native WCharPointer GetCommandLineW();

@CFunction
private static native WCharPointerPointer CommandLineToArgvW(
WCharPointer cmdLine, CIntPointer numArgsOut);

@CFunction
private static native int wcslen(WCharPointer str);

@CFunction
private static native void LocalFree(PointerBase p);

static final class Directives implements CContext.Directives {

@Override
public boolean isInConfiguration() {
return Platform.includedIn(Platform.WINDOWS.class);
}

@Override
public List<String> getHeaderFiles() {
return List.of("<windows.h>", "<wchar.h>");
}

@Override
public List<String> getLibraries() {
return List.of("Kernel32", "Shell32");
}
}
}

@Uninterruptible(reason = "The caller initialized the thread state, so the callees do not need to be uninterruptible.", calleeMustBe = false)
private static void runShutdown() {
RecurringCallbackSupport.suspendCallbackTimer("Recurring callbacks can't be executed during shutdown.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,23 @@

import java.io.IOException;
import java.lang.module.Configuration;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Scanner;
import java.util.Set;
import java.util.stream.Collectors;

import jdk.dynalink.StandardOperation;

public class Main {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
public static void main(String[] args) throws Exception {
if (args.length > 0 && "print".equals(args[0])) {
List<String> toPrint = Arrays.asList(args).subList(1, args.length);
System.out.println(toPrint);
System.exit(0);
}
failIfAssertionsAreDisabled();

Module helloAppModule = Main.class.getModule();
Expand All @@ -62,6 +68,8 @@ public static void main(String[] args) throws NoSuchMethodException, InvocationT

/* Use classes from Java module jdk.dynalink (which the builder does NOT depend on) */
System.out.println("jdk.dynalink.StandardOperation enum values: " + String.join(" ", Arrays.stream(StandardOperation.values()).map(StandardOperation::toString).collect(Collectors.joining(" "))));

testPassingArguments();
}

private static void failIfAssertionsAreDisabled() {
Expand Down Expand Up @@ -156,4 +164,23 @@ private static void testResourceAccess(Module helloAppModule, Module helloLibMod
assert helloLibModuleResourceContents.equals(s.nextLine()) : "Class.getResourceAsStream(String) result differs from Module.getResourceAsStream(String) result";
}
}

private static void testPassingArguments() throws Exception {
Optional<String> cmd = ProcessHandle.current().info().command();
if (cmd.isEmpty() || cmd.get().endsWith("java") || cmd.get().endsWith("java.exe")) {
return;
}
System.err.println("Now testing passing arguments to " + cmd);
String t1 = "使";
String t2 = "用";
String t3 = "者";
Process proc = new ProcessBuilder(cmd.get(), "print", t1, t2, t3).start();
int exitCode = proc.waitFor();
assert exitCode == 0 : "Can't invoke " + cmd.get();

List<String> lines = proc.inputReader().lines().toList();
assert lines.size() == 1 : "Assuming one line " + lines;
// System.err.println("got: " + lines.get(0));
assert lines.get(0).equals("[" + t1 + ", " + t2 + ", " + t3 + "]");
}
}