Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
*/
public final class VMInterface {

private static final MethodInvoker FALLBACK_INVOKER = new InterpretedInvoker();
private static final int MAX_INSNS = 1024;
private final InstructionProcessor[] processors = new InstructionProcessor[MAX_INSNS];
private final Map<JavaMethod, MethodInvoker> invokerMap = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* @author xDark
*/
public final class InterpretedInvoker implements MethodInvoker {
public static final InterpretedInvoker INSTANCE = new InterpretedInvoker();

@Override
public Result intercept(ExecutionContext<?> ctx) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
*/
public class SimpleExecutionEngine implements ExecutionEngine {

private static final MethodInvoker FALLBACK = new InterpretedInvoker();
private final VirtualMachine vm;

public SimpleExecutionEngine(VirtualMachine vm) {
Expand Down Expand Up @@ -52,7 +51,7 @@ public <R extends ValueSink> ExecutionContext<R> execute(ExecutionRequest<R> req
try {
MethodInvoker invoker = vmi.getInvoker(jm);
if (invoker == null) {
invoker = FALLBACK;
invoker = InterpretedInvoker.INSTANCE;
}
Result result = invoker.intercept(ctx);
if (result == Result.ABORT) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
*/
public abstract class BasicZipFile implements ZipFile {

private final int rawHandle;
private final long rawHandle;
private final Map<ZipEntry, byte[]> contents = new HashMap<>();
private final Map<Handle, ZipEntry> handles = new HashMap<>();
private Map<String, ZipEntry> names;

/**
* @param rawHandle Raw zip handle.
*/
protected BasicZipFile(int rawHandle) {
protected BasicZipFile(long rawHandle) {
this.rawHandle = rawHandle;
}

Expand Down Expand Up @@ -98,19 +98,17 @@ public synchronized long makeHandle(ZipEntry entry) {
handle.set(value);
} while (handles.containsKey(handle));
handles.put(handle.copy(), entry);
return (long) value << 32L | rawHandle & 0xffffffffL;
return (rawHandle & 0xFFFFFFFF00000000L) | value;
}

@Override
public synchronized ZipEntry getEntry(long handle) {
handle >>= 32;
return handles.get(Handle.threadLocal((int) handle));
return handles.get(Handle.threadLocal(handle));
}

@Override
public synchronized boolean freeHandle(long handle) {
handle >>= 32;
return handles.remove(Handle.threadLocal((int) handle)) != null;
return handles.remove(Handle.threadLocal(handle)) != null;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,14 @@ public interface FileManager {
*/
long openZipFile(String path, int mode) throws IOException;

/**
* Transfers a handle from {@link #open(String, int)} to being a treated as if it were opened with {@link #openZipFile(String, int)}.
* @param handle Handle to migrate.
* @param mode The mode in which the file is to be opened.
* @throws IOException If any I/O error occurs.
*/
void transferInputToZip(long handle, int mode) throws IOException;

/**
* @param handle Zip file handle.
* @return zip file by it's handle or {@code null},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/
public class HostFileManager implements FileManager {

protected final Map<Handle, String> inputPaths = new HashMap<>();
protected final Map<Handle, InputStream> inputs = new HashMap<>();
protected final Map<Handle, OutputStream> outputs = new HashMap<>();
protected final Map<Handle, ZipFile> zipFiles = new HashMap<>();
Expand Down Expand Up @@ -91,6 +92,7 @@ public synchronized long getRealHandle(long handle) {
@Override
public synchronized boolean close(long handle) throws IOException {
Handle h = Handle.threadLocal(handle);
inputPaths.remove(h);
InputStream in = inputs.remove(h);
if (in != null) {
in.close();
Expand Down Expand Up @@ -155,6 +157,7 @@ public synchronized long open(String path, int mode) throws IOException {
InputStream in = new BufferedInputStream(new FileInputStream(path));
in.mark(Integer.MAX_VALUE);
Handle h = Handle.of(fd);
inputPaths.put(h, path);
inputs.put(h, in);
return fd;
}
Expand Down Expand Up @@ -259,20 +262,30 @@ public synchronized long openZipFile(String path, int mode) throws IOException {
return fd;
}

@Override
public void transferInputToZip(long handle, int mode) throws IOException {
Handle h = Handle.of(handle);
if (inputs.remove(h) == null) throw new IOException("Cannot transfer, handle was not open prior");
String path = inputPaths.get(h);
if (path == null) throw new IOException("Cannot transfer, handle was not associated with a file path prior");
ZipFile zf = new SimpleZipFile((int) handle, new java.util.zip.ZipFile(new File(path), mode));
zipFiles.put(h, zf);
}

@Override
public synchronized ZipFile getZipFile(long handle) {
return zipFiles.get(Handle.threadLocal((int) handle));
return zipFiles.get(Handle.threadLocal(handle));
}

@Override
public synchronized ZipEntry getZipEntry(long handle) {
ZipFile zf = zipFiles.get(Handle.threadLocal((int) handle));
ZipFile zf = zipFiles.get(Handle.threadLocal(handle));
return zf == null ? null : zf.getEntry(handle);
}

@Override
public synchronized boolean freeZipEntry(long handle) {
ZipFile zf = zipFiles.get(Handle.threadLocal((int) handle));
ZipFile zf = zipFiles.get(Handle.threadLocal(handle));
return zf != null && zf.freeHandle(handle);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ public long openZipFile(String path, int mode) throws IOException {
return 0L;
}

@Override
public void transferInputToZip(long handle, int mode) throws IOException {}

@Override
public ZipFile getZipFile(long handle) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class SimpleZipFile extends BasicZipFile {
* @param rawHandle Raw zip handle.
* @param handle Zip file.
*/
public SimpleZipFile(int rawHandle, ZipFile handle) {
public SimpleZipFile(long rawHandle, ZipFile handle) {
super(rawHandle);
this.handle = handle;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@
import dev.xdark.ssvm.execution.Locals;
import dev.xdark.ssvm.execution.Result;
import dev.xdark.ssvm.filesystem.FileManager;
import dev.xdark.ssvm.mirror.member.JavaField;
import dev.xdark.ssvm.mirror.member.JavaMethod;
import dev.xdark.ssvm.mirror.member.area.ClassArea;
import dev.xdark.ssvm.mirror.type.InstanceClass;
import dev.xdark.ssvm.operation.VMOperations;
import dev.xdark.ssvm.value.ArrayValue;
import dev.xdark.ssvm.value.InstanceValue;
import dev.xdark.ssvm.value.ObjectValue;
import lombok.experimental.UtilityClass;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.attribute.BasicFileAttributes;

/**
* Initializes sun/nio/fs/WindowsNativeDispatcher.
Expand All @@ -26,40 +33,126 @@ public class FileSystemNativeDispatcherNatives {
* @param fileManager File manager.
*/
public void init(VirtualMachine vm, FileManager fileManager) {
VMInterface vmi = vm.getInterface();
InstanceClass windowsDispatcher = (InstanceClass) vm.findBootstrapClass("sun/nio/fs/WindowsNativeDispatcher");
if (windowsDispatcher == null) {
InstanceClass unixDispatcher = (InstanceClass) vm.findBootstrapClass("sun/nio/fs/UnixNativeDispatcher");
vmi.setInvoker(unixDispatcher, "getcwd", "()[B", ctx -> {
byte[] cwd = fileManager.getCurrentWorkingDirectory().getBytes(StandardCharsets.UTF_8);
ctx.setResult(vm.getOperations().toVMBytes(cwd));
return Result.ABORT;
});
vmi.setInvoker(unixDispatcher, "init", "()V", MethodInvoker.noop());
vmi.setInvoker(unixDispatcher, "init", "()I", ctx -> {
ctx.setResult(0);
return Result.ABORT;
});
InstanceClass linuxDispatcher = (InstanceClass) vm.findBootstrapClass("sun/nio/fs/LinuxNativeDispatcher");
if (linuxDispatcher != null) {
vmi.setInvoker(linuxDispatcher, "init", "()V", MethodInvoker.noop());
} else {
InstanceClass bsdDispatcher = (InstanceClass) vm.findBootstrapClass("sun/nio/fs/BsdNativeDispatcher");
vmi.setInvoker(bsdDispatcher, "initIDs", "()V", MethodInvoker.noop());
InstanceClass macDispatcher = (InstanceClass) vm.findBootstrapClass("sun/nui/fs/MacOSXNativeDispatcher");
if (macDispatcher != null) {
vmi.setInvoker(macDispatcher, "normalizepath", "([CI)[C", ctx -> {
Locals locals = ctx.getLocals();
VMOperations ops = vm.getOperations();
ArrayValue path = ops.checkNotNull(locals.loadReference(0));
// int form = locals.load(1).asInt();
ctx.setResult(path);
return Result.ABORT;
});
if (windowsDispatcher != null) {
initWindows(vm, fileManager, windowsDispatcher);
return;
}

InstanceClass unixDispatcher = (InstanceClass) vm.findBootstrapClass("sun/nio/fs/UnixNativeDispatcher");
if (unixDispatcher != null) {
initUnix(vm, fileManager, unixDispatcher);
return;
}

InstanceClass linuxDispatcher = (InstanceClass) vm.findBootstrapClass("sun/nio/fs/LinuxNativeDispatcher");
if (linuxDispatcher != null) {
initLinux(vm, fileManager, linuxDispatcher);
return;
}

InstanceClass bsdDispatcher = (InstanceClass) vm.findBootstrapClass("sun/nio/fs/BsdNativeDispatcher");
if (bsdDispatcher != null) {
initBsd(vm, fileManager, bsdDispatcher);
return;
}

InstanceClass macDispatcher = (InstanceClass) vm.findBootstrapClass("sun/nui/fs/MacOSXNativeDispatcher");
if (macDispatcher != null) {
initMac(vm, fileManager, macDispatcher);
}
}

private static void initMac(VirtualMachine vm, FileManager fileManager, InstanceClass macDispatcher) {
VMInterface vmi = vm.getInterface();
vmi.setInvoker(macDispatcher, "normalizepath", "([CI)[C", ctx -> {
Locals locals = ctx.getLocals();
VMOperations ops = vm.getOperations();
ArrayValue path = ops.checkNotNull(locals.loadReference(0));
// int form = locals.load(1).asInt();
ctx.setResult(path);
return Result.ABORT;
});
}

private static void initBsd(VirtualMachine vm, FileManager fileManager, InstanceClass bsdDispatcher) {
VMInterface vmi = vm.getInterface();
vmi.setInvoker(bsdDispatcher, "initIDs", "()V", MethodInvoker.noop());
}

private static void initLinux(VirtualMachine vm, FileManager fileManager, InstanceClass linuxDispatcher) {
VMInterface vmi = vm.getInterface();
vmi.setInvoker(linuxDispatcher, "init", "()V", MethodInvoker.noop());
}

private static void initUnix(VirtualMachine vm, FileManager fileManager, InstanceClass unixDispatcher) {
VMInterface vmi = vm.getInterface();
vmi.setInvoker(unixDispatcher, "getcwd", "()[B", ctx -> {
byte[] cwd = fileManager.getCurrentWorkingDirectory().getBytes(StandardCharsets.UTF_8);
ctx.setResult(vm.getOperations().toVMBytes(cwd));
return Result.ABORT;
});
vmi.setInvoker(unixDispatcher, "init", "()V", MethodInvoker.noop());
vmi.setInvoker(unixDispatcher, "init", "()I", ctx -> {
ctx.setResult(0);
return Result.ABORT;
});
}

private static void initWindows(VirtualMachine vm, FileManager fileManager, InstanceClass windowsDispatcher) {
VMOperations ops = vm.getOperations();
VMInterface vmi = vm.getInterface();
vmi.setInvoker(windowsDispatcher, "initIDs", "()V", MethodInvoker.noop());
vmi.setInvoker(windowsDispatcher, "CreateFile0", "(JIIJII)J", ctx -> {
// TODO: How to get string from NativeBuffer at address 'lpFileName'?
// LPCWSTR lpFileName = jlong_to_ptr(lpFileName);
return Result.ABORT;
});
/*
private static native long CreateFile0(long lpFileName,
int dwDesiredAccess,
int dwShareMode,
long lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes)
*/

InstanceClass winPath = (InstanceClass) vm.findBootstrapClass("sun/nio/fs/WindowsPath");
JavaField winPathString = winPath.getField("path", "Ljava/lang/String;");

InstanceClass winAttrs = (InstanceClass) vm.findBootstrapClass("sun/nio/fs/WindowsFileAttributes");
JavaMethod winAttrsCtor = winAttrs.getMethod("<init>", "(IJJJJIIII)V");
vmi.setInvoker(winAttrs, "get", "(Lsun/nio/fs/WindowsPath;Z)Lsun/nio/fs/WindowsFileAttributes;", ctx -> {
ObjectValue pathParam = ctx.getLocals().loadReference(0);
String pathLiteral = ops.toString(vm.getMemoryManager().readReference(pathParam, winPathString.getOffset()));
try {
InstanceValue attrsInstance = vm.getMemoryManager().newInstance(winAttrs);
BasicFileAttributes attrs = fileManager.getAttributes(pathLiteral, BasicFileAttributes.class);
if (attrs != null) {
Locals newLocals = vm.getThreadStorage().newLocals(winAttrsCtor);
long creationTime = attrs.creationTime().toMillis();
long lastAccessTime = attrs.lastAccessTime().toMillis();
long lastWriteTime = attrs.lastModifiedTime().toMillis();
long size = attrs.size();
newLocals.setReference(0, attrsInstance);
newLocals.setInt(1, 32); // fileAttrs
newLocals.setLong(2, creationTime);
newLocals.setLong(4, lastAccessTime);
newLocals.setLong(6, lastWriteTime);
newLocals.setLong(8, size);
newLocals.setInt(10, 0); // reparseTag
newLocals.setInt(11, 0); // volSerialNumber
newLocals.setInt(12, 0); // fileIndexHigh
newLocals.setInt(13, 0); // fileIndexLow
ops.invokeReference(winAttrsCtor, newLocals);
ctx.setResult(attrsInstance);
} else {
ops.throwException(vm.getSymbols().java_io_FileNotFoundException(), pathLiteral);
}
} catch (IOException ex) {
ops.throwException(vm.getSymbols().java_io_IOException(), ex.getMessage());
}
} else {
vmi.setInvoker(windowsDispatcher, "initIDs", "()V", MethodInvoker.noop());
}
return Result.ABORT;
});
}
}
Loading