diff --git a/ci/common.jsonnet b/ci/common.jsonnet
index 4272ca2d1516..1b553d098b01 100644
--- a/ci/common.jsonnet
+++ b/ci/common.jsonnet
@@ -239,6 +239,14 @@ local common_json = import "../common.json";
} else {},
},
+ espresso:: {
+ downloads+: {
+ EXTRA_JAVA_HOMES+: {
+ pathlist+: [jdks_data["oraclejdk21"], jdks_data["oraclejdk25"]],
+ }
+ }
+ },
+
sulong:: self.cmake + {
packages+: if self.os == "windows" then {
msvc_source: "==14.0",
diff --git a/common.json b/common.json
index fea05a770214..efc4ce54e798 100644
--- a/common.json
+++ b/common.json
@@ -4,7 +4,7 @@
"Jsonnet files should not include this file directly but use ci/common.jsonnet instead."
],
- "mx_version": "7.58.9",
+ "mx_version": "7.59.0",
"COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet",
"jdks": {
diff --git a/espresso-shared/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java b/espresso-shared/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java
index 0e30149ecea2..2722980ad66b 100644
--- a/espresso-shared/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java
+++ b/espresso-shared/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java
@@ -111,6 +111,10 @@ public static JavaVersion forVersion(String version) {
}
}
+ public Runtime.Version toRunTimeVersion() {
+ return Runtime.Version.parse(toString());
+ }
+
private static JavaVersion forVersion(Runtime.Version version) {
return forVersion(version.feature());
}
diff --git a/espresso/ci/ci_common/common.jsonnet b/espresso/ci/ci_common/common.jsonnet
index 5e7387231ba6..c9a11eb234aa 100644
--- a/espresso/ci/ci_common/common.jsonnet
+++ b/espresso/ci/ci_common/common.jsonnet
@@ -15,7 +15,7 @@ local benchmark_suites = ['dacapo', 'renaissance', 'scala-dacapo'];
local that = self,
// platform-specific snippets
- common: graal_common.deps.sulong + {
+ common: graal_common.deps.sulong + graal_common.deps.espresso + {
python_version: '3',
environment+: {
GRAALVM_CHECK_EXPERIMENTAL_OPTIONS: "true",
diff --git a/espresso/mx.espresso/suite.py b/espresso/mx.espresso/suite.py
index 81ce67168a52..a6ac976af285 100644
--- a/espresso/mx.espresso/suite.py
+++ b/espresso/mx.espresso/suite.py
@@ -101,7 +101,41 @@
"sourceDirs": ["src"],
# Contains classes in sun.nio.* that only compile with javac.
"forceJavac": "true",
- "javaCompliance": "8+",
+ "javaCompliance": "21+",
+ "patchModule": "java.base",
+ "checkPackagePrefix": False, # Contains classes in java.io and sun.nio.
+ "checkstyle": "com.oracle.truffle.espresso",
+ },
+
+ "com.oracle.truffle.espresso.io.jdk21": {
+ "subDir": "src",
+ "sourceDirs": ["src"],
+ "dependencies": [
+ "com.oracle.truffle.espresso.io",
+ ],
+ # Contains classes in sun.nio.* that only compile with javac.
+ "overlayTarget": "com.oracle.truffle.espresso.io",
+ "forceJavac": "true",
+ "multiReleaseJarVersion": "21",
+ "patchModule": "java.base",
+ "javaCompliance": "21",
+ "checkPackagePrefix": False, # Contains classes in java.io and sun.nio.
+ "checkstyle": "com.oracle.truffle.espresso",
+ },
+
+ "com.oracle.truffle.espresso.io.jdk25": {
+ "subDir": "src",
+ "sourceDirs": ["src"],
+ "dependencies": [
+ "com.oracle.truffle.espresso.io",
+ ],
+ # Contains classes in sun.nio.* that only compile with javac.
+ "spotbugs": "false", # inorder to pass the gate
+ "overlayTarget": "com.oracle.truffle.espresso.io",
+ "forceJavac": "true",
+ "multiReleaseJarVersion": "25",
+ "patchModule": "java.base",
+ "javaCompliance": "25",
"checkPackagePrefix": False, # Contains classes in java.io and sun.nio.
"checkstyle": "com.oracle.truffle.espresso",
},
diff --git a/espresso/src/com.oracle.truffle.espresso.io.jdk21/src/sun/nio/ch/DefaultPollerProvider.java b/espresso/src/com.oracle.truffle.espresso.io.jdk21/src/sun/nio/ch/DefaultPollerProvider.java
new file mode 100644
index 000000000000..5e6065e56054
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io.jdk21/src/sun/nio/ch/DefaultPollerProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+import java.io.IOException;
+
+public class DefaultPollerProvider extends PollerProvider {
+
+ @Override
+ Poller readPoller() throws IOException {
+ return new TrufflePoller(true);
+ }
+
+ @Override
+ Poller writePoller() throws IOException {
+ return new TrufflePoller(false);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io.jdk21/src/sun/nio/ch/TrufflePoller.java b/espresso/src/com.oracle.truffle.espresso.io.jdk21/src/sun/nio/ch/TrufflePoller.java
new file mode 100644
index 000000000000..654643742c8c
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io.jdk21/src/sun/nio/ch/TrufflePoller.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+
+public class TrufflePoller extends Poller {
+ private final int id;
+ private final int event;
+
+ TrufflePoller(boolean read) {
+ super(read);
+ this.event = (read) ? SelectionKey.OP_READ : SelectionKey.OP_WRITE;
+ id = init();
+ }
+
+ @Override
+ void implRegister(int fdVal) throws IOException {
+ register(id, fdVal, event);
+ }
+
+ @Override
+ void implDeregister(int fdVal) {
+ deregister(id, fdVal);
+ }
+
+ @Override
+ int poll(int timeout) throws IOException {
+ doSelect(id, timeout);
+ int[] fds = getReadyFds(id);
+ for (int i = 0; i < fds.length; i++) {
+ polled(fds[i]);
+ }
+ return fds.length;
+ }
+
+ static native int init();
+
+ static native void deregister(int id, int fd);
+
+ static native void register(int id, int fd, int newEvents);
+
+ static native int doSelect(int id, long timeout);
+
+ static native int[] getReadyFds(int id);
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io.jdk21/src/sun/nio/fs/NewFileChannelHelper.java b/espresso/src/com.oracle.truffle.espresso.io.jdk21/src/sun/nio/fs/NewFileChannelHelper.java
new file mode 100644
index 000000000000..fce795b8acb0
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io.jdk21/src/sun/nio/fs/NewFileChannelHelper.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.fs;
+
+import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.nio.channels.FileChannel;
+
+import sun.nio.ch.FileChannelImpl;
+
+public class NewFileChannelHelper {
+ public static FileChannel open(FileDescriptor fd, String path,
+ boolean readable, boolean writable,
+ boolean sync, boolean direct, Closeable parent) {
+ return FileChannelImpl.open(fd, path, readable, writable, direct, parent);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io.jdk25/src/sun/nio/ch/DefaultPollerProvider.java b/espresso/src/com.oracle.truffle.espresso.io.jdk25/src/sun/nio/ch/DefaultPollerProvider.java
new file mode 100644
index 000000000000..55eeb53dc85e
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io.jdk25/src/sun/nio/ch/DefaultPollerProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+import java.io.IOException;
+
+public class DefaultPollerProvider extends PollerProvider {
+ @Override
+ Poller readPoller(boolean subPoller) throws IOException {
+ if (subPoller) {
+ // the concept of subPoller relies on virtual threads which are not supported thus we
+ // should not reach here.
+ throw new IllegalStateException("should not reach here");
+ }
+ return new TrufflePoller(true);
+ }
+
+ @Override
+ Poller writePoller(boolean subPoller) throws IOException {
+ if (subPoller) {
+ // same reasoning as above
+ throw new IllegalStateException("should not reach here");
+ }
+ return new TrufflePoller(false);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io.jdk25/src/sun/nio/ch/TrufflePoller.java b/espresso/src/com.oracle.truffle.espresso.io.jdk25/src/sun/nio/ch/TrufflePoller.java
new file mode 100644
index 000000000000..488409ae59e6
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io.jdk25/src/sun/nio/ch/TrufflePoller.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+
+public class TrufflePoller extends Poller {
+ private final int id;
+ private final int event;
+
+ TrufflePoller(boolean read) {
+ super();
+ this.event = (read) ? SelectionKey.OP_READ : SelectionKey.OP_WRITE;
+ id = init();
+ }
+
+ @Override
+ void implRegister(int fdVal) throws IOException {
+ // this registeration must be one shot now
+ register(id, fdVal, event);
+ }
+
+ @Override
+ void implDeregister(int fdVal, boolean polled) {
+ if (!polled) {
+ deregister(id, fdVal);
+ }
+ }
+
+ @Override
+ int poll(int timeout) throws IOException {
+ doSelect(id, timeout);
+ int[] fds = getReadyFds(id);
+ for (int i = 0; i < fds.length; i++) {
+ polled(fds[i]);
+ }
+ return fds.length;
+ }
+
+ static native int init();
+
+ static native void deregister(int id, int fd);
+
+ static native void register(int id, int fd, int newEvents);
+
+ static native int doSelect(int id, long timeout);
+
+ static native int[] getReadyFds(int id);
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io.jdk25/src/sun/nio/fs/NewFileChannelHelper.java b/espresso/src/com.oracle.truffle.espresso.io.jdk25/src/sun/nio/fs/NewFileChannelHelper.java
new file mode 100644
index 000000000000..5a497dfc140d
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io.jdk25/src/sun/nio/fs/NewFileChannelHelper.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.fs;
+
+import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.nio.channels.FileChannel;
+
+import sun.nio.ch.FileChannelImpl;
+
+public class NewFileChannelHelper {
+ public static FileChannel open(FileDescriptor fd, String path,
+ boolean readable, boolean writable,
+ boolean sync, boolean direct, Closeable parent) {
+ return FileChannelImpl.open(fd, path, readable, writable, sync, direct, parent);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/java/io/TruffleFileSystem.java b/espresso/src/com.oracle.truffle.espresso.io/src/java/io/TruffleFileSystem.java
index 15c20c810abf..66017229dede 100644
--- a/espresso/src/com.oracle.truffle.espresso.io/src/java/io/TruffleFileSystem.java
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/java/io/TruffleFileSystem.java
@@ -27,9 +27,7 @@
*
* Its native methods are provided by Espresso's custom {@code libjava} implementation.
*
- * This file must be compatible with all Java versions supported by Espresso, strict Java 8
- * compatibility is required.
- *
+ * This file must be compatible with 21+.
*/
final class TruffleFileSystem extends FileSystem {
@@ -73,7 +71,13 @@ public String getDefaultParent() {
@Override
public String fromURIPath(String path) {
- return fromURIPath0(path);
+ // copy pasted from UnixFileSystem
+ String p = path;
+ if (p.endsWith("/") && (p.length() > 1)) {
+ // "/foo/" --> "/foo", but "/" --> "/"
+ p = p.substring(0, p.length() - 1);
+ }
+ return p;
}
@Override
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DefaultAsynchronousChannelProvider.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DefaultAsynchronousChannelProvider.java
new file mode 100644
index 000000000000..4c7739a1c1b7
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DefaultAsynchronousChannelProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+
+public final class DefaultAsynchronousChannelProvider {
+
+ /**
+ * Prevent instantiation.
+ */
+ private DefaultAsynchronousChannelProvider() {
+ }
+
+ /**
+ * Returns the default AsynchronousChannelProvider.
+ */
+ public static AsynchronousChannelProvider create() {
+ return new DummyAsynchronousChannelProvider();
+ }
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DefaultPollerProvider.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DefaultPollerProvider.java
new file mode 100644
index 000000000000..0bfc3b5778e1
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DefaultPollerProvider.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+import java.io.IOException;
+
+public class DefaultPollerProvider extends PollerProvider {
+ // needs to compile with 21+. Thus include all abstract methods of PollerProvider from 21+
+ Poller readPoller(boolean subPoller) throws IOException {
+ return null;
+ }
+
+ Poller writePoller(boolean subPoller) throws IOException {
+ return null;
+ }
+
+ Poller readPoller() throws IOException {
+ return null;
+ }
+
+ Poller writePoller() throws IOException {
+ return null;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DefaultSelectorProvider.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DefaultSelectorProvider.java
new file mode 100644
index 000000000000..915f876182f7
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DefaultSelectorProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+public class DefaultSelectorProvider {
+ public static SelectorProviderImpl get() {
+ return new TruffleSelectorProvider();
+ }
+}
+
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DummyAsynchronousChannelProvider.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DummyAsynchronousChannelProvider.java
new file mode 100644
index 000000000000..06bccb319c22
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/DummyAsynchronousChannelProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.AsynchronousChannelGroup;
+import java.nio.channels.AsynchronousServerSocketChannel;
+import java.nio.channels.AsynchronousSocketChannel;
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+
+public class DummyAsynchronousChannelProvider extends AsynchronousChannelProvider {
+ @Override
+ public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory threadFactory) throws IOException {
+ return null;
+ }
+
+ @Override
+ public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize) throws IOException {
+ return null;
+ }
+
+ @Override
+ public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group) throws IOException {
+ return null;
+ }
+
+ @Override
+ public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group) throws IOException {
+ return null;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/FileDispatcherImpl.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/FileDispatcherImpl.java
index 36aa9f507c06..d0f08888f67c 100644
--- a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/FileDispatcherImpl.java
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/FileDispatcherImpl.java
@@ -34,11 +34,11 @@
* descriptors used this class are purely virtual and should not be passed down to native code.
*
*
- * This file must be compatible with all Java versions supported by Espresso, strict Java 8
- * compatibility is required.
+ * This file must be compatible with 21+
*/
final class FileDispatcherImpl extends sun.nio.ch.FileDispatcher {
-
+ // to avoid code duplication of NativeDispatcher operations
+ private final TruffleDispatcher truffleDispatcher = new TruffleDispatcher();
static {
sun.nio.ch.IOUtil.load();
}
@@ -106,27 +106,27 @@ int setDirectIO(FileDescriptor fd, String path) {
@Override
int read(FileDescriptor fd, long address, int len) throws IOException {
- return read0(fd, address, len);
+ return truffleDispatcher.read(fd, address, len);
}
@Override
long readv(FileDescriptor fd, long address, int len) throws IOException {
- return readv0(fd, address, len);
+ return truffleDispatcher.readv(fd, address, len);
}
@Override
int write(FileDescriptor fd, long address, int len) throws IOException {
- return write0(fd, address, len);
+ return truffleDispatcher.write(fd, address, len);
}
@Override
long writev(FileDescriptor fd, long address, int len) throws IOException {
- return writev0(fd, address, len);
+ return truffleDispatcher.writev(fd, address, len);
}
@Override
void close(FileDescriptor fd) throws IOException {
- close0(fd);
+ truffleDispatcher.close(fd);
}
@Override
@@ -213,16 +213,6 @@ boolean isOther(FileDescriptor fd) throws IOException {
private static native long size0(FileDescriptor fd) throws IOException;
- private static native int read0(FileDescriptor fd, long address, int len) throws IOException;
-
- private static native int readv0(FileDescriptor fd, long address, int len) throws IOException;
-
- private static native int write0(FileDescriptor fd, long address, int len) throws IOException;
-
- private static native int writev0(FileDescriptor fd, long address, int len) throws IOException;
-
- private static native void close0(FileDescriptor fd) throws IOException;
-
private static native int pread0(FileDescriptor fd, long address, int len, long position) throws IOException;
private static native int pwrite0(FileDescriptor fd, long address, int len, long position) throws IOException;
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/SocketDispatcher.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/SocketDispatcher.java
new file mode 100644
index 000000000000..6bdb55c2f040
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/SocketDispatcher.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+class SocketDispatcher extends TruffleDispatcher {
+ @Override
+ int read(FileDescriptor fd, long address, int len) throws IOException {
+ int read = super.read(fd, address, len);
+ if (read == 0 && !isBlocking(fd)) {
+ return -2;
+ }
+ return read;
+ }
+
+ private static native boolean isBlocking(FileDescriptor fd);
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/TruffleDispatcher.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/TruffleDispatcher.java
new file mode 100644
index 000000000000..2193704c4944
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/TruffleDispatcher.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+class TruffleDispatcher extends NativeDispatcher {
+ @Override
+ int read(FileDescriptor fd, long address, int len) throws IOException {
+ return read0(fd, address, len);
+ }
+
+ @Override
+ long readv(FileDescriptor fd, long address, int len) throws IOException {
+ return readv0(fd, address, len);
+ }
+
+ @Override
+ int write(FileDescriptor fd, long address, int len) throws IOException {
+ return write0(fd, address, len);
+ }
+
+ @Override
+ long writev(FileDescriptor fd, long address, int len) throws IOException {
+ return writev0(fd, address, len);
+ }
+
+ @Override
+ void close(FileDescriptor fd) throws IOException {
+ close0(fd);
+ }
+
+ private static native int read0(FileDescriptor fd, long address, int len) throws IOException;
+
+ private static native int readv0(FileDescriptor fd, long address, int len) throws IOException;
+
+ private static native int write0(FileDescriptor fd, long address, int len) throws IOException;
+
+ private static native int writev0(FileDescriptor fd, long address, int len) throws IOException;
+
+ private static native void close0(FileDescriptor fd) throws IOException;
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/TruffleSelector.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/TruffleSelector.java
new file mode 100644
index 000000000000..6b3166891ecf
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/TruffleSelector.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+
+public class TruffleSelector extends SelectorImpl {
+ private final int id;
+ private final Object updateLock = new Object();
+ private final ConcurrentHashMap fdToKey = new ConcurrentHashMap<>();
+
+ protected TruffleSelector(SelectorProvider sp) {
+ super(sp);
+ id = init();
+ }
+
+ private void ensureOpen() {
+ if (!isOpen()) {
+ throw new ClosedSelectorException();
+ }
+ }
+
+ @Override
+ protected int doSelect(Consumer action, long timeout) throws IOException {
+ assert Thread.holdsLock(this);
+ boolean blocking = timeout != 0;
+
+ processDeregisterQueue();
+
+ begin(blocking);
+ try {
+ doSelect(id, timeout);
+ } finally {
+ end(blocking);
+ }
+
+ processDeregisterQueue();
+ return processEvents(action);
+ }
+
+ private int processEvents(Consumer action) {
+ assert Thread.holdsLock(this);
+ int numKeysUpdated = 0;
+ long[] fdAndOps = processEvents(id);
+ for (int i = 0; i < fdAndOps.length; i++) {
+ long fdAndOp = fdAndOps[i];
+ int fd = (int) (fdAndOp & 0xFFFFFFFFL);
+ int rOps = (int) (fdAndOp >>> 32);
+ SelectionKeyImpl ski = fdToKey.get(fd);
+ if (ski != null) {
+ // the processReadyEvents expects the rOps to be in native form;
+ // There is no unified way of doing the Translation
+ // eg. OP_CONNECT gets translated to either PollIn and PollConn depending on the
+ // channel
+ // This should work since the underlying channel of ski is a SelChImpl
+ int rOpsNative = ((SelChImpl) ski.channel()).translateInterestOps(rOps);
+ numKeysUpdated += processReadyEvents(rOpsNative, ski, action);
+ }
+ }
+ return numKeysUpdated;
+ }
+
+ private int translateOps(int rOps) {
+ short nativeOps = 0;
+
+ if ((rOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0) {
+ nativeOps |= Net.pollinValue(); // You need to pass the correct InformationLeak instance
+ }
+ if ((rOps & SelectionKey.OP_WRITE) != 0) {
+ nativeOps |= Net.polloutValue(); // You need to pass the correct InformationLeak
+ // instance
+ }
+ if ((rOps & SelectionKey.OP_CONNECT) != 0) {
+ nativeOps |= Net.pollconnValue(); // You need to pass the correct InformationLeak
+ // instance
+ }
+
+ // You might want to handle other conditions like error or hangup
+ // nativeOps |= pollerrValue(null); // You need to pass the correct InformationLeak instance
+ // nativeOps |= pollhupValue(null); // You need to pass the correct InformationLeak instance
+
+ return nativeOps;
+ }
+
+ @Override
+ public Selector wakeup() {
+ wakeup(id);
+ return this;
+ }
+
+ @Override
+ protected void implClose() throws IOException {
+ assert Thread.holdsLock(this);
+ close(id);
+ }
+
+ @Override
+ protected void implDereg(SelectionKeyImpl ski) throws IOException {
+ // nop
+ // Normally, the channel remains registered with the Selector until the next selection,
+ // at which point ImplDereg is called. However, this can cause issues in our implementation:
+ // if configureBlocking(true) is called on a "canceled" channel before the next selection,
+ // the channel is still internally linked to the selector. This will cause
+ // configureBlocking(true) to throw an IllegalBlockingModeException, since a channel with
+ // selection keys cannot be configured to blocking mode. To avoid this, we deregister the
+ // channel internally as soon as its key is canceled.
+
+ }
+
+ @Override
+ public void cancel(SelectionKeyImpl ski) {
+ super.cancel(ski);
+ // Immediately deregister the channel from the selector internally
+ assert !ski.isValid();
+ int fd = ski.getFDVal();
+ // In EPollSelectorImpl all accesses to sun.nio.ch.EPoll.ctl are synchronized thus we should
+ // do the same.
+ synchronized (updateLock) {
+ if (fdToKey.remove(fd) != null) {
+ deregister(id, fd);
+ } else {
+ assert ski.registeredEvents() == 0;
+ }
+ }
+
+ }
+
+ @Override
+ protected void setEventOps(SelectionKeyImpl ski) {
+ int fd = ski.getFDVal();
+ SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski);
+ assert (previous == null) || (previous == ski);
+ int newEvents = ski.interestOps();
+ int registeredEvents = ski.registeredEvents();
+ // Synchronization to native selector operations as in EPollSelectorImpl
+ synchronized (updateLock) {
+ if (newEvents != registeredEvents && ski.isValid()) {
+ // if (newEvents == 0) {
+ // deregister(id, fd);
+ // }
+ // We previously encountered unhandled CancelledKeyExceptions from io.register. The
+ // issue arose because our code canceled the HostSelectionKey internally, while the
+ // GuestSelectionKey remained valid. This allowed the Channel, Selector pair to be
+ // registered again, resulting in CancelledKeyExceptions. To fix this, we now update
+ // the interestOps of the HostSelectionKey when newEvents == 0, preventing it from
+ // being canceled. If the Channel, Selector pair is registered again,
+ // TruffleIO.register returns the same valid HostSelectionKey since it wasn't
+ // deregistered. The HostSelectionKey is now only invalidated when the
+ // GuestSelectionKey is canceled, which also invalidates the GuestSelectionKey
+ // itself.
+ if (registeredEvents == 0) {
+ // add to epoll
+ register(id, fd, newEvents);
+ } else {
+ // modify events
+ changeEvents(id, fd, newEvents);
+ }
+ ski.registeredEvents(newEvents);
+ }
+ }
+ }
+
+ static native int init();
+
+ static native int doSelect(int id, long timeout);
+
+ static native void deregister(int id, int fd);
+
+ static native void register(int id, int fd, int newEvents);
+
+ static native void wakeup(int id);
+
+ static native void close(int id);
+
+ static native void changeEvents(int id, int fd, int newEvents);
+
+ static native long[] processEvents(int id);
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/TruffleSelectorProvider.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/TruffleSelectorProvider.java
new file mode 100644
index 000000000000..1890eefaa4dc
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/ch/TruffleSelectorProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.spi.AbstractSelector;
+
+public class TruffleSelectorProvider extends SelectorProviderImpl {
+ @Override
+ public AbstractSelector openSelector() throws IOException {
+ return new TruffleSelector(this);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/DefaultFileSystemProvider.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/DefaultFileSystemProvider.java
index d763f7a49bcf..5fb6ec957166 100644
--- a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/DefaultFileSystemProvider.java
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/DefaultFileSystemProvider.java
@@ -28,8 +28,7 @@
* Replaces JDK's own {@link DefaultFileSystemProvider} to link to a Truffle-based
* {@code FileSystem}.
*
- * This file must be compatible with all Java versions supported by Espresso, strict Java 8
- * compatibility is required.
+ * This file must be compatible with 21+.
*/
public final class DefaultFileSystemProvider {
private static final TruffleFileSystemProvider INSTANCE = new TruffleFileSystemProvider();
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/DummyWatchService.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/DummyWatchService.java
new file mode 100644
index 000000000000..03c9aa17f939
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/DummyWatchService.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.fs;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+
+class DummyWatchService extends AbstractWatchService {
+ @Override
+ WatchKey register(Path path, WatchEvent.Kind>[] events, WatchEvent.Modifier... modifiers) throws IOException {
+ return null;
+ }
+
+ @Override
+ void implClose() throws IOException {
+
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/FileAttributeParser.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/FileAttributeParser.java
new file mode 100644
index 000000000000..14006c934da4
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/FileAttributeParser.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.fs;
+
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Arrays;
+import java.util.Set;
+
+class FileAttributeParser {
+ static final int OWNER_READ_VALUE = 256;
+ static final int OWNER_WRITE_VALUE = 128;
+ static final int OWNER_EXECUTE_VALUE = 64;
+ static final int GROUP_READ_VALUE = 32;
+ static final int GROUP_WRITE_VALUE = 16;
+ static final int GROUP_EXECUTE_VALUE = 8;
+ static final int OTHERS_READ_VALUE = 4;
+ static final int OTHERS_WRITE_VALUE = 2;
+ static final int OTHERS_EXECUTE_VALUE = 1;
+
+ static int parse(FileAttribute>... attrs) {
+ if (attrs != null) {
+ for (FileAttribute> attr : attrs) {
+ if (attr.name().equals("posix:permissions")) {
+ @SuppressWarnings("unchecked")
+ Set perms = (Set) attr.value();
+ return getMaskfromPosix(perms);
+ } else {
+ throw new UnsupportedOperationException("file attributes: " + Arrays.toString(attrs));
+ }
+ }
+ }
+ return 0;
+ }
+
+ private static int getMaskfromPosix(Set perms) {
+ int mask = 0;
+ for (PosixFilePermission perm : perms) {
+ switch (perm) {
+ case OWNER_READ:
+ mask |= OWNER_READ_VALUE;
+ break;
+ case OWNER_WRITE:
+ mask |= OWNER_WRITE_VALUE;
+ break;
+ case OWNER_EXECUTE:
+ mask |= OWNER_EXECUTE_VALUE;
+ break;
+ case GROUP_READ:
+ mask |= GROUP_READ_VALUE;
+ break;
+ case GROUP_WRITE:
+ mask |= GROUP_WRITE_VALUE;
+ break;
+ case GROUP_EXECUTE:
+ mask |= GROUP_EXECUTE_VALUE;
+ break;
+ case OTHERS_READ:
+ mask |= OTHERS_READ_VALUE;
+ break;
+ case OTHERS_WRITE:
+ mask |= OTHERS_WRITE_VALUE;
+ break;
+ case OTHERS_EXECUTE:
+ mask |= OTHERS_EXECUTE_VALUE;
+ break;
+ }
+ }
+ return mask;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/MapFilterIterator.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/MapFilterIterator.java
index baf66ec50217..d15cadcd451d 100644
--- a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/MapFilterIterator.java
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/MapFilterIterator.java
@@ -32,8 +32,7 @@
* Small utility to apply map + filter operations, in that order, to a base iterator.
*
*
- * This file must be compatible with all Java versions supported by Espresso, strict Java 8
- * compatibility is required.
+ * This file must be compatible with 21+.
*/
final class MapFilterIterator implements Iterator {
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/NewFileChannelHelper.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/NewFileChannelHelper.java
new file mode 100644
index 000000000000..b37a4841dd11
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/NewFileChannelHelper.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 sun.nio.fs;
+
+import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.nio.channels.FileChannel;
+import java.nio.file.OpenOption;
+import java.util.Set;
+
+public class NewFileChannelHelper {
+ public static FileChannel open(FileDescriptor fd, String path,
+ boolean readable, boolean writable,
+ boolean sync, boolean direct, Closeable parent) {
+ // should be implemented in the overlay project since its version specific.
+ throw new IllegalStateException("Should not reach here!");
+ }
+
+ public static boolean getDirectOption(Set extends OpenOption> options) {
+ // should be implemented in the overlay project since its version specific.
+ throw new IllegalStateException("Should not reach here!");
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleBasicFileAttributeView.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleBasicFileAttributeView.java
index a1c5c7fd82d2..0ce1b960983c 100644
--- a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleBasicFileAttributeView.java
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleBasicFileAttributeView.java
@@ -32,8 +32,7 @@
import java.util.Objects;
/**
- * This file must be compatible with all Java versions supported by Espresso, strict Java 8
- * compatibility is required.
+ * This file must be compatible with 21+.
*/
final class TruffleBasicFileAttributeView implements BasicFileAttributeView {
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleBasicFileAttributes.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleBasicFileAttributes.java
index 94b8ab4737a2..ba5d18977ed8 100644
--- a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleBasicFileAttributes.java
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleBasicFileAttributes.java
@@ -31,8 +31,7 @@
* attributes are serialized as a lon (milliseconds from the epoch).
*
*
- * This file must be compatible with all Java versions supported by Espresso, strict Java 8
- * compatibility is required.
+ * This file must be compatible with 21+.
*/
final class TruffleBasicFileAttributes implements BasicFileAttributes {
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFileSystem.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFileSystem.java
index 9de76f11bf89..195f0ca68b70 100644
--- a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFileSystem.java
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFileSystem.java
@@ -53,8 +53,7 @@
* native code.
*
*
- * This file must be compatible with all Java versions supported by Espresso, strict Java 8
- * compatibility is required.
+ * This file must be compatible with 21+.
*/
final class TruffleFileSystem extends FileSystem {
private static final Set SUPPORTED_ATTRIBUTES = Collections.singleton("basic");
@@ -184,8 +183,12 @@ public UserPrincipalLookupService getUserPrincipalLookupService() {
throw new UnsupportedOperationException();
}
+ /**
+ * We cannot just throw {@link UnsupportedOperationException} since we implement the Default
+ * filesystem.
+ */
@Override
public WatchService newWatchService() throws IOException {
- throw new UnsupportedOperationException();
+ return new DummyWatchService();
}
}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFileSystemProvider.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFileSystemProvider.java
index 1ce296576c97..d091756d77fa 100644
--- a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFileSystemProvider.java
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFileSystemProvider.java
@@ -43,7 +43,6 @@
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.FileAttributeView;
import java.nio.file.spi.FileSystemProvider;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -51,10 +50,10 @@
import java.util.Set;
/**
- * This file must be compatible with all Java versions supported by Espresso, strict Java 8
- * compatibility is required.
+ * This file must be compatible with 21+.
*/
class TruffleFileSystemProvider extends FileSystemProvider {
+ public static final int DEFAULT_FILE_PERMISSIONS_MASK = 511;
static {
// ensure 'nio' is loaded. Also loads 'net' as a side-effect.
@@ -116,7 +115,7 @@ public FileSystem getFileSystem(URI uri) {
@Override
public Path getPath(URI uri) {
- throw new UnsupportedOperationException();
+ return new TrufflePath(theFileSystem(), uri.getPath());
}
@Override
@@ -126,19 +125,49 @@ public SeekableByteChannel newByteChannel(Path path, Set extends OpenOption> o
@Override
public FileChannel newFileChannel(Path path, Set extends OpenOption> options, FileAttribute>... attrs) throws IOException {
- if (attrs == null || attrs.length > 0) {
- throw new UnsupportedOperationException("file attributes: " + Arrays.toString(attrs));
- }
+ int fileAttributeMask = FileAttributeParser.parse(attrs);
int openOptionsMask = openOptionsToMask(options);
- return newFileChannel0(TrufflePath.toTrufflePath(path), new FileDescriptor(), openOptionsMask);
+ boolean readable = options.contains(StandardOpenOption.READ);
+ boolean sync = options.contains(StandardOpenOption.SYNC);
+ boolean writable = options.contains(StandardOpenOption.WRITE);
+ boolean append = options.contains(StandardOpenOption.APPEND);
+
+ // default is reading; append => writing
+ if (!readable && !writable) {
+ if (append) {
+ writable = true;
+ } else {
+ readable = true;
+ }
+ }
+
+ // set direct option
+ boolean direct = false;
+ for (OpenOption option : options) {
+ if (ExtendedOptions.DIRECT.matches(option)) {
+ direct = true;
+ break;
+ }
+ }
+ // check for Exceptions
+ if (readable && append) {
+ throw new IllegalArgumentException("READ + APPEND not allowed");
+ }
+ if (append && options.contains(StandardOpenOption.TRUNCATE_EXISTING)) {
+ throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
+ }
+
+ FileDescriptor fd = new FileDescriptor();
+ // populates fd via HostCode which opens the file and checks the permissions
+ newFileChannel0(TrufflePath.toTrufflePath(path), fd, openOptionsMask, fileAttributeMask);
+ return NewFileChannelHelper.open(fd, path.toString(), readable, writable, sync, direct, null);
}
@Override
+ @SuppressWarnings("unchecked")
public void createDirectory(Path dir, FileAttribute>... attrs) throws IOException {
- if (attrs == null || attrs.length > 0) {
- throw new UnsupportedOperationException("file attributes: " + Arrays.toString(attrs));
- }
- createDirectory0(TrufflePath.toTrufflePath(dir));
+ int fileAttributeMask = FileAttributeParser.parse(attrs);
+ createDirectory0(TrufflePath.toTrufflePath(dir), fileAttributeMask);
}
@Override
@@ -156,7 +185,7 @@ public void delete(Path path) throws IOException {
// TODO(peterssen): Add NO_FOLLOW_LINKS?
// Keep in sync with Target_*_TruffleFileSystemProvider#SUPPORTED_OPEN_OPTIONS.
- private static final List SUPPORTED_OPEN_OPTIONS = Collections.unmodifiableList(Arrays.asList(
+ private static final List SUPPORTED_OPEN_OPTIONS = Collections.unmodifiableList(List.of(
StandardOpenOption.READ,
StandardOpenOption.WRITE,
StandardOpenOption.APPEND,
@@ -170,7 +199,7 @@ public void delete(Path path) throws IOException {
// TODO(peterssen): Add NO_FOLLOW_LINKS?
// Keep in sync with Target_*_TruffleFileSystemProvider#SUPPORTED_COPY_OPTIONS.
- private static final List SUPPORTED_COPY_OPTIONS = Collections.unmodifiableList(Arrays.asList(
+ private static final List SUPPORTED_COPY_OPTIONS = Collections.unmodifiableList(List.of(
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.COPY_ATTRIBUTES,
StandardCopyOption.ATOMIC_MOVE));
@@ -235,11 +264,11 @@ public boolean isHidden(Path path) throws IOException {
@Override
public FileStore getFileStore(Path path) throws IOException {
- throw new UnsupportedOperationException();
+ return null;
}
// Keep in sync with Target_*_TruffleFileSystemProvider#SUPPORTED_ACCESS_MODES.
- private static final List SUPPORTED_ACCESS_MODES = Collections.unmodifiableList(Arrays.asList(
+ private static final List SUPPORTED_ACCESS_MODES = Collections.unmodifiableList(List.of(
AccessMode.READ,
AccessMode.WRITE,
AccessMode.EXECUTE));
@@ -321,10 +350,8 @@ public void setAttribute(Path path, String attribute, Object value, LinkOption..
@Override
public void createSymbolicLink(Path link, Path target, FileAttribute>... attrs) throws IOException {
- if (attrs == null || attrs.length > 0) {
- throw new UnsupportedOperationException("file attributes: " + Arrays.toString(attrs));
- }
- createSymbolicLink0(TrufflePath.toTrufflePath(link), TrufflePath.toTrufflePath(target));
+ int fileAttributeMask = FileAttributeParser.parse(attrs);
+ createSymbolicLink0(TrufflePath.toTrufflePath(link), TrufflePath.toTrufflePath(target), fileAttributeMask);
}
@Override
@@ -342,9 +369,9 @@ public Path readSymbolicLink(Path link) throws IOException {
private static native String getSeparator0();
- private static native FileChannel newFileChannel0(TrufflePath path, FileDescriptor fileDescriptor, int openOptionsMask) throws IOException;
+ private static native void newFileChannel0(TrufflePath path, FileDescriptor fileDescriptor, int openOptionsMask, int fileAttributeMask) throws IOException;
- private static native void createDirectory0(TrufflePath path) throws IOException;
+ private static native void createDirectory0(TrufflePath path, int fileAttributeMask) throws IOException;
private static native void delete0(TrufflePath path) throws IOException;
@@ -356,7 +383,7 @@ public Path readSymbolicLink(Path link) throws IOException {
private static native void checkAccess0(TrufflePath path, int accessModesMask) throws IOException;
- private static native void createSymbolicLink0(TrufflePath link, TrufflePath target) throws IOException;
+ private static native void createSymbolicLink0(TrufflePath link, TrufflePath target, int fileAttributeMask) throws IOException;
private static native void createLink0(TrufflePath link, TrufflePath existing) throws IOException;
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFilteredDirectoryStream.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFilteredDirectoryStream.java
index ebb46d071693..521e5ad0c5b9 100644
--- a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFilteredDirectoryStream.java
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFilteredDirectoryStream.java
@@ -31,18 +31,19 @@
import java.util.Objects;
/**
- * This file must be compatible with all Java versions supported by Espresso, strict Java 8
- * compatibility is required.
+ * DirectoryStream implementation by setting a host iterator and stream as hidden host reference
+ * then proxying all methods to the native world where we retrieve the host object and do the
+ * semantics of the function. Note this file must be compatible with 21+.
*/
final class TruffleFilteredDirectoryStream implements DirectoryStream {
private final TrufflePath truffleDir;
- private final DirectoryStream stream;
+ private final DirectoryStream stream;
private final DirectoryStream.Filter super Path> filter;
/**
- * Thin wrapper for a foreign (host) {@code Iterator}, cannot have any fields.
+ * Thin wrapper for a foreign (host) {@code Iterator}, cannot have any fields.
*/
- private static final class ForeignIterator implements Iterator {
+ private static final class ForeignIterator implements Iterator {
private ForeignIterator() {
// only foreign wrappers allowed
@@ -54,7 +55,7 @@ public boolean hasNext() {
}
@Override
- public Object next() {
+ public String next() {
return next0(this);
}
}
@@ -62,7 +63,7 @@ public Object next() {
/**
* Thin wrapper for a foreign (host) DirectoryStream, cannot have any fields.
*/
- private static final class ForeignDirectoryStream implements DirectoryStream {
+ private static final class ForeignDirectoryStream implements DirectoryStream {
private ForeignDirectoryStream() {
// only foreign wrappers
@@ -74,7 +75,7 @@ public void close() throws IOException {
}
@Override
- public Iterator iterator() {
+ public Iterator iterator() {
return iterator0(this, ForeignIterator.class);
}
}
@@ -86,7 +87,7 @@ static DirectoryStream create(TrufflePath truffleDir, Filter super Path>
return new TruffleFilteredDirectoryStream(truffleDir, directoryStream0(truffleDir, ForeignDirectoryStream.class), filter);
}
- private TruffleFilteredDirectoryStream(TrufflePath dir, DirectoryStream stream, Filter super Path> filter) {
+ private TruffleFilteredDirectoryStream(TrufflePath dir, DirectoryStream stream, Filter super Path> filter) {
this.truffleDir = Objects.requireNonNull(dir);
this.filter = Objects.requireNonNull(filter);
this.stream = Objects.requireNonNull(stream);
@@ -95,7 +96,7 @@ private TruffleFilteredDirectoryStream(TrufflePath dir, DirectoryStream
@Override
public Iterator iterator() {
- return MapFilterIterator.mapThenFilter(stream.iterator(), tf -> toTrufflePath0(tf, truffleDir.getTruffleFileSystem()),
+ return MapFilterIterator.mapThenFilter(stream.iterator(), tf -> new TrufflePath((TruffleFileSystem) truffleDir.getFileSystem(), truffleDir.resolve(tf).toString()),
path -> {
try {
return filter.accept(path);
@@ -117,17 +118,15 @@ private static RuntimeException sneakyThrow(Throwable ex)
// region native methods
- private static native DirectoryStream directoryStream0(TrufflePath dir, Class directoryStreamClass) throws IOException;
+ private static native DirectoryStream directoryStream0(TrufflePath dir, Class directoryStreamClass) throws IOException;
- private static native boolean hasNext0(Iterator iterator);
+ private static native boolean hasNext0(Iterator iterator);
- private static native Object next0(Iterator iterator);
+ private static native String next0(Iterator iterator);
- private static native void close0(DirectoryStream directoryStream) throws IOException;
+ private static native void close0(DirectoryStream directoryStream) throws IOException;
- private static native Iterator iterator0(DirectoryStream directoryStream, Class iteratorClass);
-
- private static native TrufflePath toTrufflePath0(Object truffleFile, TruffleFileSystem truffleFileSystem);
+ private static native Iterator iterator0(DirectoryStream directoryStream, Class iteratorClass);
// endregion native methods
}
diff --git a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TrufflePath.java b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TrufflePath.java
index 6db963b8119e..e265d0bd3804 100644
--- a/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TrufflePath.java
+++ b/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TrufflePath.java
@@ -43,8 +43,7 @@
* Truffle VFS implementation of {@link java.nio.file.Path}.
*
*
- * This file must be compatible with all Java versions supported by Espresso, strict Java 8
- * compatibility is required.
+ * This file must be compatible with 21+.
*/
final class TrufflePath implements Path {
@@ -265,7 +264,7 @@ public WatchKey register(WatchService watcher, WatchEvent.Kind>... events) thr
@Override
public Iterator iterator() {
- List components = Arrays.asList(getPathComponents());
+ List components = List.of(getPathComponents());
return MapFilterIterator.map(components.iterator(), s -> new TrufflePath(getTruffleFileSystem(), s));
}
diff --git a/espresso/src/com.oracle.truffle.espresso.memory/src/com/oracle/truffle/espresso/memory/MemorySegmentChunkedMemoryImpl.java b/espresso/src/com.oracle.truffle.espresso.memory/src/com/oracle/truffle/espresso/memory/MemorySegmentChunkedMemoryImpl.java
new file mode 100644
index 000000000000..7d095be14ea4
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.memory/src/com/oracle/truffle/espresso/memory/MemorySegmentChunkedMemoryImpl.java
@@ -0,0 +1,243 @@
+package com.oracle.truffle.espresso.memory;
+
+import java.lang.foreign.Arena;
+import java.lang.foreign.MemorySegment;
+import java.lang.foreign.ValueLayout;
+import java.lang.invoke.VarHandle;
+
+public class MemorySegmentChunkedMemoryImpl implements ChunkedNativeMemory {
+
+ private static final VarHandle VH_JAVA_BOOLEAN = ValueLayout.JAVA_BOOLEAN.varHandle();
+ private static final VarHandle VH_JAVA_BYTE = ValueLayout.JAVA_BYTE.varHandle();
+ private static final VarHandle VH_JAVA_CHAR = ValueLayout.JAVA_CHAR.varHandle();
+ private static final VarHandle VH_JAVA_SHORT = ValueLayout.JAVA_SHORT.varHandle();
+ private static final VarHandle VH_JAVA_INT = ValueLayout.JAVA_INT.varHandle();
+ private static final VarHandle VH_JAVA_FLOAT = ValueLayout.JAVA_FLOAT.varHandle();
+ private static final VarHandle VH_JAVA_DOUBLE = ValueLayout.JAVA_DOUBLE.varHandle();
+ private static final VarHandle VH_JAVA_LONG = ValueLayout.JAVA_LONG.varHandle();
+
+ protected final Arena arena;
+
+ public Arena getArena() {
+ return arena;
+ }
+
+ protected MemorySegmentChunkedMemoryImpl(Arena arena) {
+ this.arena = arena;
+ }
+
+ @Override
+ public void setMemory(long address, long bytes, byte value) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ chunk.asSlice(chunkOffset, bytes).fill(value);
+ }
+
+ @Override
+ public void putBoolean(long address, boolean value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> VH_JAVA_BOOLEAN.set(chunk, chunkOffset, value);
+ case MemoryAccessMode.OPAQUE -> VH_JAVA_BOOLEAN.setOpaque(chunk, chunkOffset, value);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> VH_JAVA_BOOLEAN.setRelease(chunk, chunkOffset, value);
+ case MemoryAccessMode.VOLATILE -> VH_JAVA_BOOLEAN.setVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putByte(long address, byte value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> VH_JAVA_BYTE.set(chunk, chunkOffset, value);
+ case MemoryAccessMode.OPAQUE -> VH_JAVA_BYTE.setOpaque(chunk, chunkOffset, value);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> VH_JAVA_BYTE.setRelease(chunk, chunkOffset, value);
+ case MemoryAccessMode.VOLATILE -> VH_JAVA_BYTE.setVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putChar(long address, char value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> VH_JAVA_CHAR.set(chunk, chunkOffset, value);
+ case MemoryAccessMode.OPAQUE -> VH_JAVA_CHAR.setOpaque(chunk, chunkOffset, value);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> VH_JAVA_CHAR.setRelease(chunk, chunkOffset, value);
+ case MemoryAccessMode.VOLATILE -> VH_JAVA_CHAR.setVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putShort(long address, short value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> VH_JAVA_SHORT.set(chunk, chunkOffset, value);
+ case MemoryAccessMode.OPAQUE -> VH_JAVA_SHORT.setOpaque(chunk, chunkOffset, value);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> VH_JAVA_SHORT.setRelease(chunk, chunkOffset, value);
+ case MemoryAccessMode.VOLATILE -> VH_JAVA_SHORT.setVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putInt(long address, int value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> VH_JAVA_INT.set(chunk, chunkOffset, value);
+ case MemoryAccessMode.OPAQUE -> VH_JAVA_INT.setOpaque(chunk, chunkOffset, value);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> VH_JAVA_INT.setRelease(chunk, chunkOffset, value);
+ case MemoryAccessMode.VOLATILE -> VH_JAVA_INT.setVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putFloat(long address, float value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> VH_JAVA_FLOAT.set(chunk, chunkOffset, value);
+ case MemoryAccessMode.OPAQUE -> VH_JAVA_FLOAT.setOpaque(chunk, chunkOffset, value);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> VH_JAVA_FLOAT.setRelease(chunk, chunkOffset, value);
+ case MemoryAccessMode.VOLATILE -> VH_JAVA_FLOAT.setVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putDouble(long address, double value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> VH_JAVA_DOUBLE.set(chunk, chunkOffset, value);
+ case MemoryAccessMode.OPAQUE -> VH_JAVA_DOUBLE.setOpaque(chunk, chunkOffset, value);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> VH_JAVA_DOUBLE.setRelease(chunk, chunkOffset, value);
+ case MemoryAccessMode.VOLATILE -> VH_JAVA_DOUBLE.setVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putLong(long address, long value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> VH_JAVA_LONG.set(chunk, chunkOffset, value);
+ case MemoryAccessMode.OPAQUE -> VH_JAVA_LONG.setOpaque(chunk, chunkOffset, value);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> VH_JAVA_LONG.setRelease(chunk, chunkOffset, value);
+ case MemoryAccessMode.VOLATILE -> VH_JAVA_LONG.setVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public boolean getBoolean(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ return switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> (boolean) VH_JAVA_BOOLEAN.get(chunk, chunkOffset);
+ case MemoryAccessMode.OPAQUE -> (boolean) VH_JAVA_BOOLEAN.getOpaque(chunk, chunkOffset);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> (boolean) VH_JAVA_BOOLEAN.getAcquire(chunk, chunkOffset);
+ case MemoryAccessMode.VOLATILE -> (boolean) VH_JAVA_BOOLEAN.getVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ public byte getByte(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ return switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> (byte) VH_JAVA_BYTE.get(chunk, chunkOffset);
+ case MemoryAccessMode.OPAQUE -> (byte) VH_JAVA_BYTE.getOpaque(chunk, chunkOffset);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> (byte) VH_JAVA_BYTE.getAcquire(chunk, chunkOffset);
+ case MemoryAccessMode.VOLATILE -> (byte) VH_JAVA_BYTE.getVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ public char getChar(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ return switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> (char) VH_JAVA_CHAR.get(chunk, chunkOffset);
+ case MemoryAccessMode.OPAQUE -> (char) VH_JAVA_CHAR.getOpaque(chunk, chunkOffset);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> (char) VH_JAVA_CHAR.getAcquire(chunk, chunkOffset);
+ case MemoryAccessMode.VOLATILE -> (char) VH_JAVA_CHAR.getVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ public short getShort(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ return switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> (short) VH_JAVA_SHORT.get(chunk, chunkOffset);
+ case MemoryAccessMode.OPAQUE -> (short) VH_JAVA_SHORT.getOpaque(chunk, chunkOffset);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> (short) VH_JAVA_SHORT.getAcquire(chunk, chunkOffset);
+ case MemoryAccessMode.VOLATILE -> (short) VH_JAVA_SHORT.getVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ public int getInt(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ return switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> (int) VH_JAVA_INT.get(chunk, chunkOffset);
+ case MemoryAccessMode.OPAQUE -> (int) VH_JAVA_INT.getOpaque(chunk, chunkOffset);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> (int) VH_JAVA_INT.getAcquire(chunk, chunkOffset);
+ case MemoryAccessMode.VOLATILE -> (int) VH_JAVA_INT.getVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ public float getFloat(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ return switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> (float) VH_JAVA_FLOAT.get(chunk, chunkOffset);
+ case MemoryAccessMode.OPAQUE -> (float) VH_JAVA_FLOAT.getOpaque(chunk, chunkOffset);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> (float) VH_JAVA_FLOAT.getAcquire(chunk, chunkOffset);
+ case MemoryAccessMode.VOLATILE -> (float) VH_JAVA_FLOAT.getVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ public double getDouble(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ return switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> (double) VH_JAVA_DOUBLE.get(chunk, chunkOffset);
+ case MemoryAccessMode.OPAQUE -> (double) VH_JAVA_DOUBLE.getOpaque(chunk, chunkOffset);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> (double) VH_JAVA_DOUBLE.getAcquire(chunk, chunkOffset);
+ case MemoryAccessMode.VOLATILE -> (double) VH_JAVA_DOUBLE.getVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ public long getLong(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ MemorySegment chunk = getChunk(address);
+ return switch (accessMode) {
+ case MemoryAccessMode.PLAIN -> (long) VH_JAVA_LONG.get(chunk, chunkOffset);
+ case MemoryAccessMode.OPAQUE -> (long) VH_JAVA_LONG.getOpaque(chunk, chunkOffset);
+ case MemoryAccessMode.RELEASE_ACQUIRE -> (long) VH_JAVA_LONG.getAcquire(chunk, chunkOffset);
+ case MemoryAccessMode.VOLATILE -> (long) VH_JAVA_LONG.getVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ protected MemorySegment allocateChunk(long bytes) {
+ // At least 8 bytes to ensure aligned accesses work.
+ return arena.allocate(bytes, Long.BYTES);
+ }
+
+ @Override
+ protected long getChunkSize(long address) {
+ return getChunk(address).byteSize();
+ }
+
+ @Override
+ protected void copyBytes(long fromAddress, long toAddress, long byteSize) {
+ MemorySegment.copy(getChunk(fromAddress), getChunkOffset(fromAddress), getChunk(toAddress), getChunkOffset(toAddress), byteSize);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.memory/src/com/oracle/truffle/espresso/memory/SafeMemoryAccess.java b/espresso/src/com.oracle.truffle.espresso.memory/src/com/oracle/truffle/espresso/memory/SafeMemoryAccess.java
new file mode 100644
index 000000000000..7acc82d2dc62
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.memory/src/com/oracle/truffle/espresso/memory/SafeMemoryAccess.java
@@ -0,0 +1,79 @@
+package com.oracle.truffle.espresso.memory;
+
+import java.lang.foreign.Arena;
+import java.lang.foreign.MemorySegment;
+import java.util.ArrayList;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+final class SafeMemoryAccess extends ChunkedNativeMemory {
+
+ private static final int OFFSET_BITS = 38; // 256GB max buffer size
+ private static final int CHUNK_BITS = Long.SIZE - OFFSET_BITS; // 64M chunks
+ private static final long OFFSET_MASK = (1L << OFFSET_BITS) - 1;
+
+ private static int getChunkIndex(long address) {
+ return (int) (address >>> OFFSET_BITS);
+ }
+
+ private final ArrayList chunks = new ArrayList<>();
+ private final ConcurrentLinkedQueue freeList = new ConcurrentLinkedQueue<>();
+
+ public SafeMemoryAccess() {
+ chunks.add(MemorySegment.NULL); // NULL sentinel
+ }
+
+ @Override
+ public long reallocateMemory(long address, long bytes) {
+ int oldChunkIndex = getChunkIndex(address);
+ long newAddress = allocateMemory(bytes);
+ int newChunkIndex = getChunkIndex(newAddress);
+ MemorySegment oldChunk = chunks.get(oldChunkIndex);
+ MemorySegment newChunk = chunks.get(newChunkIndex);
+ MemorySegment.copy(oldChunk, 0, newChunk, 0, Math.min(oldChunk.byteSize(), newChunk.byteSize()));
+ freeMemory(address);
+ return newAddress;
+ }
+
+ @Override
+ public long allocateMemory(long bytes) {
+ Integer chunkIndex = null;
+ while ((chunkIndex = freeList.poll()) == null) {
+ synchronized (chunks) {
+ chunks.add(null);
+ freeList.add(chunks.size() - 1);
+ }
+ }
+ MemorySegment chunk = allocateChunk(bytes);
+ chunks.set(chunkIndex, chunk);
+ return encodeAddress(chunkIndex, 0);
+ }
+
+ private static MemorySegment allocateChunk(long bytes) {
+ return Arena.ofAuto().allocate(bytes);
+ }
+
+ @Override
+ public void freeMemory(long address) {
+ assert getChunkOffset(address) == 0 : "invalid address";
+ int chunkIndex = getChunkIndex(address);
+ chunks.set(chunkIndex, null);
+ freeList.add(chunkIndex);
+ }
+
+ @Override
+ protected MemorySegment getChunk(long address) {
+ int chunkIndex = getChunkIndex(address);
+ return chunks.get(chunkIndex);
+ }
+
+ @Override
+ protected long getChunkOffset(long address) {
+ return address & OFFSET_MASK;
+ }
+
+ private long encodeAddress(int chunkIndex, long chunkOffset) {
+ assert Long.compareUnsigned(chunkIndex, chunks.size()) <= 0;
+ assert Long.compareUnsigned(chunkOffset, OFFSET_MASK) <= 0;
+ return (((long) chunkIndex) << OFFSET_BITS) | chunkOffset;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.memory/src/com/oracle/truffle/espresso/memory/UnsafeMemoryImpl.java b/espresso/src/com.oracle.truffle.espresso.memory/src/com/oracle/truffle/espresso/memory/UnsafeMemoryImpl.java
new file mode 100644
index 000000000000..b9fb6d795b17
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso.memory/src/com/oracle/truffle/espresso/memory/UnsafeMemoryImpl.java
@@ -0,0 +1,52 @@
+package com.oracle.truffle.espresso.memory;
+
+import com.oracle.truffle.espresso.vm.UnsafeAccess;
+import sun.misc.Unsafe;
+
+import java.lang.foreign.Arena;
+import java.lang.foreign.MemorySegment;
+
+public class UnsafeMemoryImpl extends MemorySegmentChunkedMemoryImpl {
+
+ private static final MemorySegment ALL = MemorySegment.ofAddress(0).reinterpret(Long.MAX_VALUE);
+ private static final Unsafe UNSAFE = UnsafeAccess.get();
+
+ protected UnsafeMemoryImpl(Arena arena) {
+ super(arena);
+ }
+
+ @Override
+ public long reallocateMemory(long address, long bytes) {
+ return UNSAFE.reallocateMemory(address, bytes);
+ }
+
+ @Override
+ public long allocateMemory(long bytes) {
+ return UNSAFE.allocateMemory(bytes);
+ }
+
+ @Override
+ public void freeMemory(long address) {
+ UNSAFE.freeMemory(address);
+ }
+
+ @Override
+ protected MemorySegment getChunk(long address) {
+ return ALL;
+ }
+
+ @Override
+ protected long getChunkOffset(long address) {
+ return address;
+ }
+
+ @Override
+ protected MemorySegment allocateChunk(long bytes) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void copyBytes(long fromAddress, long toAddress, long byteSize) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionFlag.java b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionFlag.java
index f4fd19dee84b..60d953fc4415 100644
--- a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionFlag.java
+++ b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionFlag.java
@@ -53,6 +53,18 @@ public final class SubstitutionFlag {
*/
public static final byte InlineInBytecode = 0b00000010;
+ /**
+ * Whether the given library entry implementation needs to have its method signature mangled for
+ * registration. This can happen if a class has overloaded native methods.
+ */
+ public static final byte needsSignatureMangle = 0b00000100;
+
+ /**
+ * Whether to relax type checks in the substitution processor. Used for substitutions in
+ * libnespresso.
+ */
+ public static final byte relaxTypeChecks = 0b00001000;
+
private SubstitutionFlag() {
}
}
diff --git a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java
index c0bf4918f5be..b6befc7306f7 100644
--- a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java
+++ b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java
@@ -313,9 +313,16 @@ void processSubstitution(Element element, String className, TypeMirror defaultNa
// Find the methods annotated with @Substitution.
AnnotationMirror subst = getAnnotation(element, substitutionAnnotation);
if (subst != null) {
+ List flagsList = getAnnotationValueList(subst, "flags", Byte.class);
+ byte flags = 0;
+ for (Byte flag : flagsList) {
+ flags |= flag;
+ }
- // Sanity check.
- checkSubstitutionElement(element);
+ if (!isFlag(flags, SubstitutionFlag.relaxTypeChecks)) {
+ // Sanity check.
+ checkSubstitutionElement(element);
+ }
// Obtain the name of the element to be substituted in.
String targetMethodName = getSubstutitutedMethodName(element);
@@ -347,12 +354,6 @@ void processSubstitution(Element element, String className, TypeMirror defaultNa
TypeMirror languageFilter = getLanguageFilter(subst);
- List flagsList = getAnnotationValueList(subst, "flags", Byte.class);
- byte flags = 0;
- for (Byte flag : flagsList) {
- flags |= flag;
- }
-
TypeMirror encodedInlineGuard = getInlineValue(classWideInline, element);
boolean inlineInBytecode = encodedInlineGuard != null ||
// Implicit inlining of trivial substitutions.
@@ -626,6 +627,9 @@ List expectedImports(String className, String targetMethodName, List imp
@CompilationFinal private boolean eagerFrameAnalysis;
@CompilationFinal private boolean internalJvmciEnabled;
@CompilationFinal private boolean useEspressoLibs;
+ @CompilationFinal private boolean enableNetworking;
@CompilationFinal private boolean continuum;
+ @CompilationFinal private String nativeBackendId;
@CompilationFinal private boolean useTRegex;
@CompilationFinal private int maxStackTraceDepth;
// endregion Options
@@ -261,6 +267,12 @@ private void initializeOptions(final TruffleLanguage.Env env) {
case graal -> new GraalGuestFieldOffsetStrategy();
};
this.useEspressoLibs = env.getOptions().get(EspressoOptions.UseEspressoLibs);
+ boolean userEnableNetworking = env.getOptions().get((EspressoOptions.enableNetworking));
+ if (userEnableNetworking && !env.isSocketIOAllowed()) {
+ throw EspressoError.shouldNotReachHere("Socket IO is not allowed, but Espresso networking is enabled.");
+ }
+ this.enableNetworking = userEnableNetworking;
+ this.nativeBackendId = setNativeBackendId(env);
assert guestFieldOffsetStrategy.name().equals(strategy.name());
}
@@ -321,6 +333,33 @@ private void extractDataFrom(EspressoLanguage other) {
languageCache.importFrom(other.getLanguageCache());
}
+ private static String setNativeBackendId(final TruffleLanguage.Env env) {
+ boolean isAllowed = env.isNativeAccessAllowed();
+ // if the Env allows, this might be overwritten.
+ String nativeBackend = NoNativeAccess.Provider.ID;
+ if (env.getOptions().hasBeenSet(EspressoOptions.NativeBackend)) {
+ String userNativeBackend = env.getOptions().get(EspressoOptions.NativeBackend);
+ if (!isAllowed && !userNativeBackend.equals(nativeBackend)) {
+ throw EspressoError.fatal("trying to set NativeBackend even though NativeAccess is disabled");
+ }
+ return userNativeBackend;
+
+ } else if (isAllowed) {
+ // Pick a sane "default" native backend depending on the platform.
+ boolean isInPreInit = (boolean) env.getConfig().getOrDefault("preinit", false);
+ if (isInPreInit || !EspressoOptions.RUNNING_ON_SVM) {
+ if (OS.getCurrent() == OS.Linux) {
+ nativeBackend = NFIIsolatedNativeAccess.Provider.ID;
+ } else {
+ nativeBackend = NFISulongNativeAccess.Provider.ID;
+ }
+ } else {
+ nativeBackend = NFINativeAccess.Provider.ID;
+ }
+ }
+ return nativeBackend;
+ }
+
@Override
protected boolean patchContext(EspressoContext context, Env newEnv) {
// This check has to be done manually as long as language uses exclusive context sharing
@@ -354,6 +393,7 @@ protected boolean areOptionsCompatible(OptionValues oldOptions, OptionValues new
isOptionCompatible(newOptions, oldOptions, EspressoOptions.UseTRegex) &&
isOptionCompatible(newOptions, oldOptions, EspressoOptions.GuestFieldOffsetStrategy) &&
isOptionCompatible(newOptions, oldOptions, EspressoOptions.UseEspressoLibs) &&
+ isOptionCompatible(newOptions, oldOptions, EspressoOptions.NativeBackend) &&
isOptionCompatible(newOptions, oldOptions, EspressoOptions.MaxJavaStackTraceDepth);
}
@@ -600,6 +640,14 @@ public boolean useEspressoLibs() {
return useEspressoLibs;
}
+ public String nativeBackendId() {
+ return nativeBackendId;
+ }
+
+ public boolean enableNetworking() {
+ return enableNetworking;
+ }
+
public boolean isContinuumEnabled() {
return continuum;
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java
index 22cc6fc3b32e..c43d62e3f95e 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java
@@ -633,6 +633,12 @@ public Long apply(String size) {
usageSyntax = "true|false") //
public static final OptionKey UseEspressoLibs = new OptionKey<>(false);
+ @Option(help = "Enables/Disables the use of Networking until Truffle implements something (GR-23755)", //
+ category = OptionCategory.EXPERT, //
+ stability = OptionStability.EXPERIMENTAL, //
+ usageSyntax = "true|false") //
+ public static final OptionKey enableNetworking = new OptionKey<>(true);
+
@Option(help = "Enables the signal API (sun.misc.Signal or jdk.internal.misc.Signal).", //
category = OptionCategory.EXPERT, //
stability = OptionStability.EXPERIMENTAL, //
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java
index c6e59f2f6cfc..e5fe8f9ff599 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java
@@ -109,6 +109,9 @@ public static void ensureInitialized() {
public static final Symbol java_io_IOException = SYMBOLS.putType("Ljava/io/IOException;");
public static final Symbol java_io_File = SYMBOLS.putType("Ljava/io/File;");
public static final Symbol java_io_FileNotFoundException = SYMBOLS.putType("Ljava/io/FileNotFoundException;");
+ public static final Symbol java_nio_channels_ClosedByInterruptException = SYMBOLS.putType("Ljava/nio/channels/ClosedByInterruptException;");
+ public static final Symbol java_nio_channels_AsynchronousCloseException = SYMBOLS.putType("Ljava/nio/channels/AsynchronousCloseException;");
+ public static final Symbol java_nio_channels_ClosedChannelException = SYMBOLS.putType("Ljava/nio/channels/ClosedChannelException;");
public static final Symbol java_io_FileDescriptor = SYMBOLS.putType("Ljava/io/FileDescriptor;");
public static final Symbol java_io_FileInputStream = SYMBOLS.putType("Ljava/io/FileInputStream;");
public static final Symbol java_io_FileOutputStream = SYMBOLS.putType("Ljava/io/FileOutputStream;");
@@ -128,6 +131,7 @@ public static void ensureInitialized() {
public static final Symbol java_nio_file_AtomicMoveNotSupportedException = SYMBOLS.putType("Ljava/nio/file/AtomicMoveNotSupportedException;");
public static final Symbol java_nio_file_AccessDeniedException = SYMBOLS.putType("Ljava/nio/file/AccessDeniedException;");
public static final Symbol java_nio_file_NoSuchFileException = SYMBOLS.putType("Ljava/nio/file/NoSuchFileException;");
+ public static final Symbol java_net_SocketException = SYMBOLS.putType("Ljava/net/SocketException;");
public static final Symbol java_nio_file_InvalidPathException = SYMBOLS.putType("Ljava/nio/file/InvalidPathException;");
public static final Symbol java_nio_file_NotDirectoryException = SYMBOLS.putType("Ljava/nio/file/NotDirectoryException;");
@@ -140,8 +144,8 @@ public static void ensureInitialized() {
public static final Symbol sun_nio_fs_TruffleFileSystem = SYMBOLS.putType("Lsun/nio/fs/TruffleFileSystem;");
public static final Symbol sun_nio_fs_TruffleFileSystemProvider = SYMBOLS.putType("Lsun/nio/fs/TruffleFileSystemProvider;");
+ public static final Symbol sun_nio_fs_FileAttributeParser = SYMBOLS.putType("Lsun/nio/fs/FileAttributeParser;");
public static final Symbol sun_nio_fs_DefaultFileSystemProvider = SYMBOLS.putType("Lsun/nio/fs/DefaultFileSystemProvider;");
- public static final Symbol sun_nio_ch_FileChannelImpl = SYMBOLS.putType("Lsun/nio/ch/FileChannelImpl;");
public static final Symbol sun_nio_ch_NativeThread = SYMBOLS.putType("Lsun/nio/ch/NativeThread;");
public static final Symbol jdk_internal_loader_ClassLoaders = SYMBOLS.putType("Ljdk/internal/loader/ClassLoaders;");
@@ -159,10 +163,34 @@ public static void ensureInitialized() {
public static final Symbol java_lang_module_ModuleDescriptor = SYMBOLS.putType("Ljava/lang/module/ModuleDescriptor;");
// Espresso Libs
+ // libzip
public static final Symbol java_util_zip_CRC32 = SYMBOLS.putType("Ljava/util/zip/CRC32;");
public static final Symbol java_util_zip_Inflater = SYMBOLS.putType("Ljava/util/zip/Inflater;");
public static final Symbol java_util_zip_DataFormatException = SYMBOLS.putType("Ljava/util/zip/DataFormatException;");
-
+ // libnet
+ public static final Symbol java_net_NetworkInterface = SYMBOLS.putType("Ljava/net/NetworkInterface;");
+ public static final Symbol java_net_NetworkInterface_array = SYMBOLS.putType("[Ljava/net/NetworkInterface;");
+ public static final Symbol java_net_InetSocketAddress = SYMBOLS.putType("Ljava/net/InetSocketAddress;");
+ public static final Symbol java_net_InetAddress = SYMBOLS.putType("Ljava/net/InetAddress;");
+ public static final Symbol java_net_InetAddress$InetAddressHolder = SYMBOLS.putType("Ljava/net/InetAddress$InetAddressHolder;");
+ public static final Symbol java_net_InterfaceAddress = SYMBOLS.putType("Ljava/net/InterfaceAddress;");
+ public static final Symbol java_net_InterfaceAddress_array = SYMBOLS.putType("[Ljava/net/InterfaceAddress;");
+ public static final Symbol java_net_Inet4Address = SYMBOLS.putType("Ljava/net/Inet4Address;");
+ public static final Symbol java_net_Inet6Address = SYMBOLS.putType("Ljava/net/Inet6Address;");
+ public static final Symbol java_net_Inet6Address$Inet6AddressHolder = SYMBOLS.putType("Ljava/net/Inet6Address$Inet6AddressHolder;");
+ public static final Symbol java_net_InetAddress_array = SYMBOLS.putType("[Ljava/net/InetAddress;");
+ public static final Symbol sun_net_ConnectionResetException = SYMBOLS.putType("Lsun/net/ConnectionResetException;");
+ public static final Symbol java_net_UnknownHostException = SYMBOLS.putType("Ljava/net/UnknownHostException;");
+ public static final Symbol sun_nio_ch_IOStatus = SYMBOLS.putType("Lsun/nio/ch/IOStatus;");
+ // libjava
+ public static final Symbol java_lang_ProcessHandleImpl$Info = SYMBOLS.putType("Ljava/lang/ProcessHandleImpl$Info;");
+ // libnio
+ public static final Symbol sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream = SYMBOLS.putType("Lsun/nio/fs/TruffleFilteredDirectoryStream$ForeignDirectoryStream;");
+ public static final Symbol sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator = SYMBOLS.putType("Lsun/nio/fs/TruffleFilteredDirectoryStream$ForeignIterator;");
+ // libextnet
+ public static final Symbol jdk_net_ExtendedSocketOptions$PlatformSocketOptions = SYMBOLS.putType("Ljdk/net/ExtendedSocketOptions$PlatformSocketOptions;");
+ // libmanagement
+ public static final Symbol sun_management_VMManagementImpl = SYMBOLS.putType("Lsun/management/VMManagementImpl;");
// URL class loader
public static final Symbol java_net_URLClassLoader = SYMBOLS.putType("Ljava/net/URLClassLoader;");
public static final Symbol java_net_URL = SYMBOLS.putType("Ljava/net/URL;");
@@ -756,15 +784,54 @@ public static class Names {
// sun.nio.fs.TrufflePath
public static final Symbol HIDDEN_TRUFFLE_FILE = SYMBOLS.putName("0HIDDEN_TRUFFLE_FILE");
public static final Symbol instance = SYMBOLS.putName("instance");
+ // sun.nio.fs.TruffleFileSystemProvider
+ public static final Symbol OWNER_READ_VALUE = SYMBOLS.putName("OWNER_READ_VALUE");
+ public static final Symbol OWNER_WRITE_VALUE = SYMBOLS.putName("OWNER_WRITE_VALUE");
+ public static final Symbol OWNER_EXECUTE_VALUE = SYMBOLS.putName("OWNER_EXECUTE_VALUE");
+ public static final Symbol GROUP_READ_VALUE = SYMBOLS.putName("GROUP_READ_VALUE");
+ public static final Symbol GROUP_WRITE_VALUE = SYMBOLS.putName("GROUP_WRITE_VALUE");
+ public static final Symbol GROUP_EXECUTE_VALUE = SYMBOLS.putName("GROUP_EXECUTE_VALUE");
+ public static final Symbol OTHERS_READ_VALUE = SYMBOLS.putName("OTHERS_READ_VALUE");
+ public static final Symbol OTHERS_WRITE_VALUE = SYMBOLS.putName("OTHERS_WRITE_VALUE");
+ public static final Symbol OTHERS_EXECUTE_VALUE = SYMBOLS.putName("OTHERS_EXECUTE_VALUE");
// java.util.zip
public static final Symbol HIDDEN_CRC32 = SYMBOLS.putName("0HIDDEN_CRC32");
public static final Symbol inputConsumed = SYMBOLS.putName("inputConsumed");
public static final Symbol outputConsumed = SYMBOLS.putName("outputConsumed");
- public static final Symbol len = SYMBOLS.putName("len");
- public static final Symbol off = SYMBOLS.putName("off");
- public static final Symbol needDict = SYMBOLS.putName("needDict");
- public static final Symbol finished = SYMBOLS.putName("finished");
- public static final Symbol buf = SYMBOLS.putName("buf");
+ // java.net
+ public static final Symbol displayName = SYMBOLS.putName("displayName");
+ public static final Symbol virtual = SYMBOLS.putName("virtual");
+ public static final Symbol bindings = SYMBOLS.putName("bindings");
+ public static final Symbol childs = SYMBOLS.putName("childs");
+ public static final Symbol scope_ifname = SYMBOLS.putName("scope_ifname");
+ public static final Symbol holder6 = SYMBOLS.putName("holder6");
+ public static final Symbol ipaddress = SYMBOLS.putName("ipaddress");
+ public static final Symbol maskLength = SYMBOLS.putName("maskLength");
+ public static final Symbol broadcast = SYMBOLS.putName("broadcast");
+ // sun.nio.ch.IOStatus
+ public static final Symbol EOF = SYMBOLS.putName("EOF");
+ public static final Symbol UNAVAILABLE = SYMBOLS.putName("UNAVAILABLE");
+ public static final Symbol INTERRUPTED = SYMBOLS.putName("INTERRUPTED");
+ public static final Symbol UNSUPPORTED = SYMBOLS.putName("UNSUPPORTED");
+ public static final Symbol THROWN = SYMBOLS.putName("THROWN");
+ public static final Symbol UNSUPPORTED_CASE = SYMBOLS.putName("UNSUPPORTED_CASE");
+ // java.lang.ProcessHandleImpl$Info
+ public static final Symbol command = SYMBOLS.putName("command");
+ public static final Symbol commandLine = SYMBOLS.putName("commandLine");
+ public static final Symbol arguments = SYMBOLS.putName("arguments");
+ public static final Symbol startTime = SYMBOLS.putName("startTime");
+ public static final Symbol totalTime = SYMBOLS.putName("totalTime");
+ public static final Symbol user = SYMBOLS.putName("user");
+ public static final Symbol initialized = SYMBOLS.putName("initialized");
+ // java.management
+ public static final Symbol compTimeMonitoringSupport = SYMBOLS.putName("compTimeMonitoringSupport");
+ public static final Symbol threadContentionMonitoringSupport = SYMBOLS.putName("threadContentionMonitoringSupport");
+ public static final Symbol currentThreadCpuTimeSupport = SYMBOLS.putName("currentThreadCpuTimeSupport");
+ public static final Symbol otherThreadCpuTimeSupport = SYMBOLS.putName("otherThreadCpuTimeSupport");
+ public static final Symbol threadAllocatedMemorySupport = SYMBOLS.putName("threadAllocatedMemorySupport");
+ public static final Symbol remoteDiagnosticCommandsSupport = SYMBOLS.putName("remoteDiagnosticCommandsSupport");
+ public static final Symbol objectMonitorUsageSupport = SYMBOLS.putName("objectMonitorUsageSupport");
+ public static final Symbol synchronizerUsageSupport = SYMBOLS.putName("synchronizerUsageSupport");
// java.lang.invoke.*
// CallSite
public static final Symbol target = SYMBOLS.putName("target");
@@ -1445,6 +1512,24 @@ public static class Signatures {
Types._int,
Types.java_lang_Object);
+ public static final Symbol java_net_NetworkInterface_init_signature = SYMBOLS.putSignature(Types._void,
+ /* name */ Types.java_lang_String,
+ /* index */ Types._int,
+ /* addrs */ Types.java_net_InetAddress_array);
+
+ public static final Symbol java_net_Inet4Address_init_signature = SYMBOLS.putSignature(Types._void,
+ /* hostName */ Types.java_lang_String,
+ /* address */ Types._byte_array);
+
+ public static final Symbol java_net_Inet6Address_init_signature = SYMBOLS.putSignature(Types._void,
+ /* hostName */ Types.java_lang_String,
+ /* address */ Types._byte_array,
+ /* scopeId */ Types._int);
+
+ public static final Symbol java_net_InetSocketAddress_init_signature = SYMBOLS.putSignature(Types._void,
+ /* addr */ Types.java_net_InetAddress,
+ /* port */ Types._int);
+
public static void ensureInitialized() {
assert _void == ParserSymbols.ParserSignatures._void;
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/EspressoLibsNativeAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/EspressoLibsNativeAccess.java
index 118c8a094124..55418359b770 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/EspressoLibsNativeAccess.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/EspressoLibsNativeAccess.java
@@ -23,7 +23,9 @@
package com.oracle.truffle.espresso.ffi;
import java.nio.file.Path;
+import java.util.Arrays;
+import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleLogger;
import com.oracle.truffle.api.interop.ArityException;
@@ -31,6 +33,8 @@
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.espresso.EspressoLanguage;
+import com.oracle.truffle.espresso.ffi.memory.NativeMemory;
+import com.oracle.truffle.espresso.ffi.memory.ProtoChunkedMemoryImpl;
import com.oracle.truffle.espresso.impl.ContextAccessImpl;
import com.oracle.truffle.espresso.libs.Lib;
import com.oracle.truffle.espresso.libs.Libs;
@@ -48,6 +52,7 @@
* @see com.oracle.truffle.espresso.libs.Libs
*/
public class EspressoLibsNativeAccess extends ContextAccessImpl implements NativeAccess {
+ @CompilerDirectives.CompilationFinal protected NativeMemory nativeMemory = new ProtoChunkedMemoryImpl();
private static final TruffleLogger logger = TruffleLogger.getLogger(EspressoLanguage.ID, EspressoLibsNativeAccess.class);
@@ -61,20 +66,24 @@ private static TruffleLogger getLogger() {
public EspressoLibsNativeAccess(EspressoContext ctx, NativeAccess delegate) {
super(ctx);
this.delegate = delegate;
- this.libs = new Libs();
+ this.libs = new Libs(ctx.getLanguage());
}
@Override
public @Pointer TruffleObject loadLibrary(Path libraryPath) {
Path libname = libraryPath.getFileName();
- if (libs.isKnown(libraryPath.toString())) {
+ if (libname != null && libs.isKnown(libraryPath.toString())) {
getLogger().fine(() -> "Loading espresso lib: " + libname);
+ // this
return libs.loadLibrary(getContext(), libname.toString());
}
// Failed to find library in known libs:
// try to find an actual library (can be null)
- getLogger().fine(() -> "Could not find espresso lib '" + libname + "', trying delegate Native Access...");
+ String[] knownLibs = {"libnespresso.so", "libjvm.so", "libverify.so", "libjimage.so"};
+ if (!Arrays.asList(knownLibs).contains(libname.toString())) {
+ getLogger().warning(() -> "Could not find espresso lib '" + libname + "', trying delegate Native Access...");
+ }
return delegate.loadLibrary(libraryPath);
}
@@ -114,8 +123,11 @@ public void unloadLibrary(@Pointer TruffleObject library) {
getLogger().fine(() -> "Failed to locate symbol '" + symbolName + "' in espresso lib " + lib.name());
} else {
// Delegate library
- getLogger().fine(() -> "Espresso libs delegating for: " + symbolName);
- return delegate.lookupSymbol(library, symbolName);
+ TruffleObject ret = delegate.lookupSymbol(library, symbolName);
+ if (ret != null) {
+ getLogger().fine(() -> "Found: " + symbolName + " through delegate library");
+ }
+ return ret;
}
return null;
}
@@ -140,6 +152,9 @@ public boolean hasFallbackSymbols() {
@Override
public boolean isFallbackSymbol(TruffleObject symbol) {
+ if (symbol instanceof SubstitutionFactoryWrapper) {
+ return false;
+ }
return delegate.isFallbackSymbol(symbol);
}
@@ -158,21 +173,6 @@ public SignatureCallNode createSignatureCall(NativeSignature nativeSignature) {
return delegate.createSignatureCall(nativeSignature);
}
- @Override
- public @Buffer TruffleObject allocateMemory(long size) {
- return delegate.allocateMemory(size);
- }
-
- @Override
- public @Buffer TruffleObject reallocateMemory(@Pointer TruffleObject buffer, long newSize) {
- return delegate.reallocateMemory(buffer, newSize);
- }
-
- @Override
- public void freeMemory(@Pointer TruffleObject buffer) {
- delegate.freeMemory(buffer);
- }
-
@Override
public @Pointer TruffleObject createNativeClosure(TruffleObject executable, NativeSignature nativeSignature) {
return delegate.createNativeClosure(executable, nativeSignature);
@@ -183,6 +183,11 @@ public void prepareThread() {
delegate.prepareThread();
}
+ @Override
+ public NativeMemory nativeMemory() {
+ return nativeMemory;
+ }
+
@TruffleBoundary
public boolean isKnownBootLibrary(String path) {
Path p = Path.of(path);
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NativeAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NativeAccess.java
index b3d7e3104fe7..eb7096b8bbcb 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NativeAccess.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NativeAccess.java
@@ -38,6 +38,7 @@
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.espresso.EspressoOptions;
import com.oracle.truffle.espresso.classfile.JavaKind;
+import com.oracle.truffle.espresso.ffi.memory.NativeMemory;
import com.oracle.truffle.espresso.meta.EspressoError;
import com.oracle.truffle.espresso.runtime.EspressoProperties;
@@ -219,23 +220,47 @@ default boolean isBuiltIn(@SuppressWarnings("unused") String libname) {
* {@link InteropLibrary#hasBufferElements(Object) buffer}.
* @throws IllegalArgumentException if the size is negative
*/
- @Buffer
- TruffleObject allocateMemory(long size);
+ default @Buffer TruffleObject allocateMemory(long size) {
+ long address = nativeMemory().allocateMemory(size);
+ if (address == 0) {
+ return null;
+ }
+ return RawPointer.create(address);
+ }
/**
* Similar to realloc. The result of allocating a 0-sized buffer is an implementation detail.
- *
+ *
* @return null
if the memory cannot be re-allocated. Otherwise, a
* {@link InteropLibrary#hasBufferElements(Object) buffer}.
* @throws IllegalArgumentException if the size is negative
*/
- @Buffer
- TruffleObject reallocateMemory(@Pointer TruffleObject buffer, long newSize);
+ default @Buffer TruffleObject reallocateMemory(@Pointer TruffleObject buffer, long newSize) {
+ long address = 0;
+ try {
+ address = InteropLibrary.getUncached().asPointer(buffer);
+ } catch (UnsupportedMessageException e) {
+ throw EspressoError.shouldNotReachHere(e);
+ }
+ long rawPointer = nativeMemory().reallocateMemory(address, newSize);
+ if (rawPointer == 0) {
+ return null;
+ }
+ return RawPointer.create(rawPointer);
+ }
/**
* Similar to free. Accessing the buffer after free may cause explosive undefined behavior.
*/
- void freeMemory(@Pointer TruffleObject buffer);
+ default void freeMemory(@Pointer TruffleObject buffer) {
+ long address = 0;
+ try {
+ address = InteropLibrary.getUncached().asPointer(buffer);
+ } catch (UnsupportedMessageException e) {
+ throw EspressoError.shouldNotReachHere(e);
+ }
+ nativeMemory().freeMemory(address);
+ }
/**
* Sinking, make a Java method accessible to the native world. Returns an
@@ -292,4 +317,6 @@ interface Provider {
NativeAccess create(TruffleLanguage.Env env);
}
+
+ NativeMemory nativeMemory();
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NoNativeAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NoNativeAccess.java
index 5bf7a62ec206..cf0f9eea547d 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NoNativeAccess.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NoNativeAccess.java
@@ -32,10 +32,12 @@
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.espresso.EspressoLanguage;
+import com.oracle.truffle.espresso.ffi.memory.NativeMemory;
import com.oracle.truffle.espresso.meta.EspressoError;
import com.oracle.truffle.espresso.substitutions.Collect;
public class NoNativeAccess implements NativeAccess {
+
private static final TruffleLogger logger = TruffleLogger.getLogger(EspressoLanguage.ID, NoNativeAccess.class);
@Override
@@ -127,6 +129,11 @@ public void freeMemory(@Pointer TruffleObject buffer) {
public void prepareThread() {
}
+ @Override
+ public NativeMemory nativeMemory() {
+ return null;
+ }
+
private static TruffleLogger getLogger() {
return logger;
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/ByteArrayChunkedMemoryImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/ByteArrayChunkedMemoryImpl.java
new file mode 100644
index 000000000000..e90d86a9a33a
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/ByteArrayChunkedMemoryImpl.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2018, 2020, 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.
+ *
+ * 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.truffle.espresso.ffi.memory;
+
+import java.util.Arrays;
+
+import com.oracle.truffle.espresso.vm.UnsafeAccess;
+
+import sun.misc.Unsafe;
+
+public class ByteArrayChunkedMemoryImpl extends ChunkedNativeMemory {
+
+ private static final Unsafe UNSAFE = UnsafeAccess.get();
+
+ private static void validateAccess(int length, int byteIndex, int accessByteSize) {
+ if (byteIndex < 0 || byteIndex > length - accessByteSize) {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ @Override
+ public void setMemory(long address, long bytes, byte value) {
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(bytes), 0);
+ Arrays.fill(chunk, 0, Math.toIntExact(bytes), value);
+ }
+
+ @Override
+ public void putByte(long address, byte value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Byte.BYTES);
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putByte(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE ->
+ UNSAFE.putByteVolatile(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putShort(long address, short value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Short.BYTES);
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putShort(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE ->
+ UNSAFE.putShortVolatile(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putInt(long address, int value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Integer.BYTES);
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putInt(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE ->
+ UNSAFE.putIntVolatile(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset, value);
+ }
+ }
+
+ @Override
+ public byte getByte(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Byte.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getByte(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE ->
+ UNSAFE.getByteVolatile(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset);
+ };
+ }
+
+ @Override
+ public short getShort(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Short.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getShort(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE ->
+ UNSAFE.getShortVolatile(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset);
+ };
+ }
+
+ @Override
+ public int getInt(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Integer.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getInt(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE ->
+ UNSAFE.getIntVolatile(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset);
+ };
+ }
+
+ @Override
+ public void putLong(long address, long value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Long.BYTES);
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putLong(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE ->
+ UNSAFE.putLongVolatile(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset, value);
+ }
+ }
+
+ @Override
+ public double getDouble(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Double.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getDouble(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE ->
+ UNSAFE.getDoubleVolatile(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset);
+ };
+ }
+
+ @Override
+ public boolean compareAndSetLong(long address, long expected, long newValue) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ return UNSAFE.compareAndSwapLong(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset, expected, newValue);
+ }
+
+ @Override
+ public boolean compareAndSetInt(long address, int expected, int newValue) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ return UNSAFE.compareAndSwapInt(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset, expected, newValue);
+ }
+
+ @Override
+ public long getLong(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Long.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getLong(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE ->
+ UNSAFE.getLongVolatile(chunk, Unsafe.ARRAY_BYTE_BASE_OFFSET + chunkOffset);
+ };
+ }
+
+ @Override
+ protected byte[] allocateChunk(long bytes) {
+ return new byte[Math.toIntExact(bytes)];
+ }
+
+ @Override
+ protected long getChunkSize(long address) {
+ return getChunk(address).length;
+ }
+
+ @Override
+ protected void copyBytes(long fromAddress, long toAddress, long byteSize) {
+ int intByteSize = Math.toIntExact(byteSize);
+
+ byte[] fromChunk = getChunk(fromAddress);
+ int fromOffset = Math.toIntExact(getChunkOffset(fromAddress));
+ validateAccess(fromChunk.length, fromOffset, intByteSize);
+
+ byte[] toChunk = getChunk(toAddress);
+ int toOffset = Math.toIntExact(getChunkOffset(fromAddress));
+ validateAccess(toChunk.length, toOffset, intByteSize);
+
+ System.arraycopy(fromChunk, fromOffset, toChunk, toOffset, intByteSize);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/ChunkedNativeMemory.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/ChunkedNativeMemory.java
new file mode 100644
index 000000000000..1378a561a530
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/ChunkedNativeMemory.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018, 2020, 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.
+ *
+ * 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.truffle.espresso.ffi.memory;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Queue;
+
+abstract class ChunkedNativeMemory implements NativeMemory {
+
+ protected static final int OFFSET_BITS = 38; // 256GB max buffer size
+ protected static final int CHUNK_BITS = Long.SIZE - OFFSET_BITS; // 64M chunks
+ protected static final long OFFSET_MASK = (1L << OFFSET_BITS) - 1;
+
+ protected final List chunks = new ArrayList<>();
+ protected final Queue freeList = new ArrayDeque<>();
+
+ protected abstract T allocateChunk(long bytes);
+
+ protected ChunkedNativeMemory() {
+ allocateMemory(0); // Sentinel block, cannot be freed.
+ }
+
+ protected static int getChunkIndex(long address) {
+ return (int) (address >>> OFFSET_BITS);
+ }
+
+ protected T getChunk(long address) {
+ int chunkIndex = getChunkIndex(address);
+ return chunks.get(chunkIndex);
+ }
+
+ protected long getChunkOffset(long address) {
+ return address & OFFSET_MASK;
+ }
+
+ protected long encodeAddress(int chunkIndex, long chunkOffset) {
+ if (!(Long.compareUnsigned(chunkIndex, chunks.size()) < 0)) {
+ throw new IllegalStateException("invalid chunk index");
+ }
+ if (!(Long.compareUnsigned(chunkOffset, OFFSET_MASK) <= 0)) {
+ throw new IllegalStateException("invalid chunk offset");
+ }
+ return (((long) chunkIndex) << OFFSET_BITS) | chunkOffset;
+ }
+
+ @Override
+ public synchronized long allocateMemory(long bytes) {
+ Integer chunkIndex = freeList.poll();
+ if (chunkIndex == null) {
+ if (chunks.size() == 1 << CHUNK_BITS) {
+ throw new OutOfMemoryError("cannot allocate chunk");
+ }
+ chunks.add(null);
+ chunkIndex = chunks.size() - 1;
+ }
+ T chunk = allocateChunk(bytes);
+ chunks.set(chunkIndex, chunk);
+ return encodeAddress(chunkIndex, 0);
+ }
+
+ @Override
+ public synchronized void freeMemory(long address) {
+ if (getChunkOffset(address) != 0) {
+ throw new IllegalStateException("invalid address");
+ }
+ int chunkIndex = getChunkIndex(address);
+ chunks.set(chunkIndex, null);
+ freeList.add(chunkIndex);
+ }
+
+ public long reallocateMemory(long address, long bytes) {
+ if (getChunkOffset(address) != 0) {
+ throw new IllegalStateException("invalid address");
+ }
+ int oldChunkIndex = getChunkIndex(address);
+ if (oldChunkIndex == 0) {
+ throw new IllegalStateException("realloc NULL");
+ }
+
+ if (getChunkSize(address) == bytes) {
+ return address; // no change
+ }
+
+ long newAddress = allocateMemory(bytes);
+ copyBytes(address, newAddress, Math.min(getChunkSize(address), getChunkSize(newAddress)));
+ freeMemory(address);
+ return newAddress;
+ }
+
+ protected abstract long getChunkSize(long address);
+
+ protected abstract void copyBytes(long fromAddress, long toAddress, long byteSize);
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/NativeMemory.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/NativeMemory.java
new file mode 100644
index 000000000000..285fb4a5b5c1
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/NativeMemory.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018, 2020, 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.
+ *
+ * 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.truffle.espresso.ffi.memory;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The native memory abstraction layer for Espresso. It is assumed when you call
+ * {@link #allocateMemory(long)} it reserves a continuous block of memory of the specified size. Any
+ * location within the allocated block should be accessible by adding an offset (between 0 and size)
+ * to the base address.
+ */
+public interface NativeMemory {
+ long reallocateMemory(long address, long bytes);
+
+ long allocateMemory(long bytes);
+
+ void freeMemory(long bytes);
+
+ void setMemory(long address, long bytes, byte value);
+
+ enum MemoryAccessMode {
+ PLAIN,
+ OPAQUE,
+ RELEASE_ACQUIRE,
+ VOLATILE
+ }
+
+ void putByte(long address, byte value, MemoryAccessMode accessMode);
+
+ void putShort(long address, short value, MemoryAccessMode accessMode);
+
+ void putInt(long address, int value, MemoryAccessMode accessMode);
+
+ void putLong(long address, long value, MemoryAccessMode accessMode);
+
+ default void putBoolean(long address, boolean value, MemoryAccessMode accessMode) {
+ putByte(address, value ? (byte) 1 : (byte) 0, accessMode);
+ }
+
+ default void putChar(long address, char value, MemoryAccessMode accessMode) {
+ putShort(address, (short) value, accessMode);
+ }
+
+ default void putFloat(long address, float value, MemoryAccessMode accessMode) {
+ putInt(address, Float.floatToRawIntBits(value), accessMode);
+ }
+
+ default void putDouble(long address, double value, MemoryAccessMode accessMode) {
+ putLong(address, Double.doubleToRawLongBits(value), accessMode);
+ }
+
+ byte getByte(long address, MemoryAccessMode accessMode);
+
+ short getShort(long address, MemoryAccessMode accessMode);
+
+ int getInt(long address, MemoryAccessMode accessMode);
+
+ long getLong(long address, MemoryAccessMode accessMode);
+
+ default boolean getBoolean(long address, MemoryAccessMode accessMode) {
+ return getByte(address, accessMode) != 0;
+ }
+
+ default char getChar(long address, MemoryAccessMode accessMode) {
+ return (char) getShort(address, accessMode);
+ }
+
+ default float getFloat(long address, MemoryAccessMode accessMode) {
+ return Float.intBitsToFloat(getInt(address, accessMode));
+ }
+
+ default double getDouble(long address, MemoryAccessMode accessMode) {
+ return Double.longBitsToDouble(getLong(address, accessMode));
+ }
+
+ boolean compareAndSetLong(long address, long expected, long newValue);
+
+ boolean compareAndSetInt(long address, int expected, int newValue);
+
+ default long compareAndExchangeLong(long address, long expected, long newValue) {
+ long previous;
+ do {
+ previous = getLong(address, MemoryAccessMode.VOLATILE);
+ if (previous != expected) {
+ return previous;
+ }
+ } while (!compareAndSetLong(address, expected, newValue));
+ return previous;
+ }
+
+ default int compareAndExchangeInt(long address, int expected, int newValue) {
+ int previous;
+ do {
+ previous = getInt(address, MemoryAccessMode.VOLATILE);
+ if (previous != expected) {
+ return previous;
+ }
+ } while (!compareAndSetInt(address, expected, newValue));
+ return previous;
+ }
+
+ default void copyMemory(long srcBase,
+ long destBase,
+ long bytes, MemoryAccessMode accessMode) {
+ for (int offset = 0; offset < bytes; offset++) {
+ putByte(destBase + offset, getByte(srcBase + offset, accessMode), accessMode);
+ }
+ }
+
+ default void readMemory(long addr, long bytes, ByteBuffer buf) {
+ for (long offset = 0; offset < bytes; offset++) {
+ buf.put(getByte(addr + offset, MemoryAccessMode.PLAIN));
+ }
+ }
+
+ default void readMemory(long addr, long bytes, byte[] buf) {
+ readMemory(addr, bytes, ByteBuffer.wrap(buf));
+ }
+
+ default void writeMemory(long addr, long bytes, ByteBuffer buf) {
+ for (long offset = 0; offset < bytes; offset++) {
+ putByte(addr + offset, buf.get(), MemoryAccessMode.PLAIN);
+ }
+ }
+
+ default void writeMemory(long addr, long bytes, byte[] buf) {
+ writeMemory(addr, bytes, ByteBuffer.wrap(buf));
+ }
+
+ /*
+ * Should be overwritten if a direct way to access Memory can be provided which does not involve
+ * copying.
+ */
+ default ByteBuffer getDirectBuffer(long address, long bytes) {
+ throw new UnsupportedOperationException("DirectMemory Access is not supported");
+ }
+
+ default boolean isDirectBufferSupported() {
+ return false;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/ProtoChunkedMemoryImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/ProtoChunkedMemoryImpl.java
new file mode 100644
index 000000000000..f9e0fd18d416
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/ProtoChunkedMemoryImpl.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2018, 2020, 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.
+ *
+ * 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.truffle.espresso.ffi.memory;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+import com.oracle.truffle.api.memory.ByteArraySupport;
+
+public class ProtoChunkedMemoryImpl extends ChunkedNativeMemory {
+
+ private static final ByteArraySupport BYTES = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN
+ ? ByteArraySupport.littleEndian()
+ : ByteArraySupport.bigEndian();
+
+ private static void validateAccess(int length, int byteIndex, int accessByteSize) {
+ if (byteIndex < 0 || byteIndex > length - accessByteSize) {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ @Override
+ public void copyMemory(long srcBase,
+ long destBase,
+ long bytes, MemoryAccessMode accessMode) {
+ copyBytes(srcBase, destBase, bytes);
+ }
+
+ @Override
+ public void setMemory(long address, long bytes, byte value) {
+ byte[] chunk = getChunk(address);
+ // I think the accessByteSize should be 0 instead of 1 as we access exactly bytes many bytes
+ // in chunk
+ validateAccess(chunk.length, Math.toIntExact(bytes), 0);
+ Arrays.fill(chunk, 0, Math.toIntExact(bytes), value);
+ }
+
+ @Override
+ public void putBoolean(long address, boolean value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ switch (accessMode) {
+ case PLAIN -> BYTES.putByte(chunk, chunkOffset, value ? (byte) 1 : (byte) 0);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE ->
+ BYTES.putByteVolatile(chunk, chunkOffset, value ? (byte) 1 : (byte) 0);
+ }
+ }
+
+ @Override
+ public void putByte(long address, byte value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Byte.BYTES);
+ switch (accessMode) {
+ case PLAIN -> BYTES.putByte(chunk, chunkOffset, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.putByteVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putChar(long address, char value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Character.BYTES);
+ switch (accessMode) {
+ case PLAIN -> BYTES.putShort(chunk, chunkOffset, (short) value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.putShortVolatile(chunk, chunkOffset, (short) value);
+ }
+ }
+
+ @Override
+ public void putShort(long address, short value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Short.BYTES);
+ switch (accessMode) {
+ case PLAIN -> BYTES.putShort(chunk, chunkOffset, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.putShortVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putInt(long address, int value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Integer.BYTES);
+ switch (accessMode) {
+ case PLAIN -> BYTES.putInt(chunk, chunkOffset, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.putIntVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public void putFloat(long address, float value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Float.BYTES);
+ switch (accessMode) {
+ case PLAIN -> BYTES.putFloat(chunk, chunkOffset, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.putIntVolatile(chunk, chunkOffset, Float.floatToRawIntBits(value));
+ }
+ }
+
+ @Override
+ public void putDouble(long address, double value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Double.BYTES);
+ switch (accessMode) {
+ case PLAIN -> BYTES.putDouble(chunk, chunkOffset, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.putLongVolatile(chunk, chunkOffset, Double.doubleToRawLongBits(value));
+ }
+ }
+
+ @Override
+ public void putLong(long address, long value, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Long.BYTES);
+ switch (accessMode) {
+ case PLAIN -> BYTES.putLong(chunk, chunkOffset, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.putLongVolatile(chunk, chunkOffset, value);
+ }
+ }
+
+ @Override
+ public boolean getBoolean(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Byte.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> BYTES.getByte(chunk, chunkOffset) != 0;
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.getByteVolatile(chunk, chunkOffset) != 0;
+ };
+ }
+
+ @Override
+ public byte getByte(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Byte.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> BYTES.getByte(chunk, chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.getByteVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ public char getChar(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Character.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> (char) BYTES.getShort(chunk, chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> (char) BYTES.getShortVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ public short getShort(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Short.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> BYTES.getShort(chunk, chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.getShortVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ public int getInt(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Integer.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> BYTES.getInt(chunk, chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.getIntVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ public float getFloat(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Float.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> BYTES.getFloat(chunk, chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> Float.intBitsToFloat(BYTES.getIntVolatile(chunk, chunkOffset));
+ };
+ }
+
+ @Override
+ public double getDouble(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Double.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> BYTES.getDouble(chunk, chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> Double.longBitsToDouble(BYTES.getLongVolatile(chunk, chunkOffset));
+ };
+ }
+
+ @Override
+ public boolean compareAndSetLong(long address, long expected, long newValue) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ return BYTES.compareAndExchangeLong(chunk, chunkOffset, expected, newValue) == expected;
+ }
+
+ @Override
+ public boolean compareAndSetInt(long address, int expected, int newValue) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ return BYTES.compareAndExchangeInt(chunk, chunkOffset, expected, newValue) == expected;
+ }
+
+ @Override
+ public long getLong(long address, MemoryAccessMode accessMode) {
+ long chunkOffset = getChunkOffset(address);
+ byte[] chunk = getChunk(address);
+ validateAccess(chunk.length, Math.toIntExact(chunkOffset), Long.BYTES);
+ return switch (accessMode) {
+ case PLAIN -> BYTES.getLong(chunk, chunkOffset);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> BYTES.getLongVolatile(chunk, chunkOffset);
+ };
+ }
+
+ @Override
+ protected byte[] allocateChunk(long bytes) {
+ return new byte[Math.toIntExact(bytes)];
+ }
+
+ @Override
+ protected long getChunkSize(long address) {
+ return getChunk(address).length;
+ }
+
+ @Override
+ public ByteBuffer getDirectBuffer(long address, long bytes) {
+ int intByteSize = Math.toIntExact(bytes);
+ byte[] fromChunk = getChunk(address);
+ int fromOffset = Math.toIntExact(getChunkOffset(address));
+ validateAccess(fromChunk.length, fromOffset, intByteSize);
+ return ByteBuffer.wrap(fromChunk, fromOffset, intByteSize);
+ }
+
+ @Override
+ public void writeMemory(long address, long bytes, ByteBuffer buf) {
+ int intByteSize = Math.toIntExact(bytes);
+ int fromOffset = Math.toIntExact(getChunkOffset(address));
+ byte[] fromChunk = getChunk(address);
+ validateAccess(fromChunk.length, fromOffset, intByteSize);
+ buf.get(fromChunk, fromOffset, intByteSize);
+ }
+
+ @Override
+ public void readMemory(long address, long bytes, ByteBuffer buf) {
+ int intByteSize = Math.toIntExact(bytes);
+ int fromOffset = Math.toIntExact(getChunkOffset(address));
+ byte[] fromChunk = getChunk(address);
+ validateAccess(fromChunk.length, fromOffset, intByteSize);
+ buf.put(fromChunk, fromOffset, intByteSize);
+ }
+
+ @Override
+ protected void copyBytes(long fromAddress, long toAddress, long byteSize) {
+ int intByteSize = Math.toIntExact(byteSize);
+
+ byte[] fromChunk = getChunk(fromAddress);
+ int fromOffset = Math.toIntExact(getChunkOffset(fromAddress));
+ validateAccess(fromChunk.length, fromOffset, intByteSize);
+
+ byte[] toChunk = getChunk(toAddress);
+ int toOffset = Math.toIntExact(getChunkOffset(fromAddress));
+ validateAccess(toChunk.length, toOffset, intByteSize);
+
+ System.arraycopy(fromChunk, fromOffset, toChunk, toOffset, intByteSize);
+ }
+
+ @Override
+ public boolean isDirectBufferSupported() {
+ return true;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/UnsafeNativeMemory.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/UnsafeNativeMemory.java
new file mode 100644
index 000000000000..7074cc9a7e5c
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/memory/UnsafeNativeMemory.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2018, 2020, 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.
+ *
+ * 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.truffle.espresso.ffi.memory;
+
+import com.oracle.truffle.espresso.vm.UnsafeAccess;
+
+import sun.misc.Unsafe;
+
+public class UnsafeNativeMemory implements NativeMemory {
+
+ private static final Unsafe UNSAFE = UnsafeAccess.get();
+
+ @Override
+ public long reallocateMemory(long address, long bytes) {
+ return UNSAFE.reallocateMemory(address, bytes);
+ }
+
+ @Override
+ public long allocateMemory(long bytes) {
+ return UNSAFE.allocateMemory(bytes);
+ }
+
+ @Override
+ public void freeMemory(long address) {
+ UNSAFE.freeMemory(address);
+ }
+
+ @Override
+ public void setMemory(long address, long bytes, byte value) {
+ UNSAFE.setMemory(address, bytes, value);
+ }
+
+ @Override
+ public void putBoolean(long address, boolean value, MemoryAccessMode accessMode) {
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putBoolean(null, address, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.putBooleanVolatile(null, address, value);
+ }
+ }
+
+ @Override
+ public void putByte(long address, byte value, MemoryAccessMode accessMode) {
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putByte(null, address, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.putByteVolatile(null, address, value);
+ }
+ }
+
+ @Override
+ public void putChar(long address, char value, MemoryAccessMode accessMode) {
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putChar(null, address, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.putCharVolatile(null, address, value);
+ }
+ }
+
+ @Override
+ public void putShort(long address, short value, MemoryAccessMode accessMode) {
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putShort(null, address, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.putShortVolatile(null, address, value);
+ }
+ }
+
+ @Override
+ public void putInt(long address, int value, MemoryAccessMode accessMode) {
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putInt(null, address, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.putIntVolatile(null, address, value);
+ }
+ }
+
+ @Override
+ public void putFloat(long address, float value, MemoryAccessMode accessMode) {
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putFloat(null, address, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.putFloatVolatile(null, address, value);
+ }
+ }
+
+ @Override
+ public void putDouble(long address, double value, MemoryAccessMode accessMode) {
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putDouble(null, address, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.putDoubleVolatile(null, address, value);
+ }
+ }
+
+ @Override
+ public void putLong(long address, long value, MemoryAccessMode accessMode) {
+ switch (accessMode) {
+ case PLAIN -> UNSAFE.putLong(null, address, value);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.putLongVolatile(null, address, value);
+ }
+ }
+
+ @Override
+ public boolean getBoolean(long address, MemoryAccessMode accessMode) {
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getBoolean(null, address);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.getBooleanVolatile(null, address);
+ };
+ }
+
+ @Override
+ public byte getByte(long address, MemoryAccessMode accessMode) {
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getByte(null, address);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.getByteVolatile(null, address);
+ };
+ }
+
+ @Override
+ public char getChar(long address, MemoryAccessMode accessMode) {
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getChar(null, address);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.getCharVolatile(null, address);
+ };
+ }
+
+ @Override
+ public short getShort(long address, MemoryAccessMode accessMode) {
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getShort(null, address);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.getShortVolatile(null, address);
+ };
+ }
+
+ @Override
+ public int getInt(long address, MemoryAccessMode accessMode) {
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getInt(null, address);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.getIntVolatile(null, address);
+ };
+ }
+
+ @Override
+ public float getFloat(long address, MemoryAccessMode accessMode) {
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getFloat(null, address);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.getFloatVolatile(null, address);
+ };
+ }
+
+ @Override
+ public double getDouble(long address, MemoryAccessMode accessMode) {
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getDouble(null, address);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.getDoubleVolatile(null, address);
+ };
+ }
+
+ @Override
+ public long getLong(long address, MemoryAccessMode accessMode) {
+ return switch (accessMode) {
+ case PLAIN -> UNSAFE.getLong(null, address);
+ case OPAQUE, RELEASE_ACQUIRE, VOLATILE -> UNSAFE.getLongVolatile(null, address);
+ };
+ }
+
+ @Override
+ public boolean compareAndSetInt(long address, int expected, int newValue) {
+ return UNSAFE.compareAndSwapInt(null, address, expected, newValue);
+ }
+
+ @Override
+ public boolean compareAndSetLong(long address, long expected, long newValue) {
+ return UNSAFE.compareAndSwapLong(null, address, expected, newValue);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFIIsolatedNativeAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFIIsolatedNativeAccess.java
index 0fc2560fb303..8ee8e5ba839e 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFIIsolatedNativeAccess.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFIIsolatedNativeAccess.java
@@ -40,12 +40,13 @@
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.espresso.EspressoLanguage;
-import com.oracle.truffle.espresso.ffi.Buffer;
import com.oracle.truffle.espresso.ffi.NativeAccess;
import com.oracle.truffle.espresso.ffi.NativeSignature;
import com.oracle.truffle.espresso.ffi.NativeType;
import com.oracle.truffle.espresso.ffi.Pointer;
+import com.oracle.truffle.espresso.ffi.RawPointer;
import com.oracle.truffle.espresso.ffi.TruffleByteBuffer;
+import com.oracle.truffle.espresso.ffi.memory.UnsafeNativeMemory;
import com.oracle.truffle.espresso.impl.EmptyKeysArray;
import com.oracle.truffle.espresso.meta.EspressoError;
import com.oracle.truffle.espresso.substitutions.Collect;
@@ -78,7 +79,7 @@ public final class NFIIsolatedNativeAccess extends NFINativeAccess {
private final DefaultLibrary defaultLibrary;
NFIIsolatedNativeAccess(TruffleLanguage.Env env) {
- super(env);
+ super(env, null);
// libeden.so must be the first library loaded in the isolated namespace.
Path espressoLibraryPath = EspressoLanguage.getEspressoLibs(env);
this.edenLibrary = loadLibrary(Collections.singletonList(espressoLibraryPath), "eden", true);
@@ -93,13 +94,57 @@ public final class NFIIsolatedNativeAccess extends NFINativeAccess {
* loaded inside the isolated namespace provides a dlsym shim inside the namespace.
*/
this.defaultLibrary = new DefaultLibrary(this.dlsym, rtldDefault());
+
+ this.nativeMemory = new UnsafeNativeMemory() {
+ @Override
+ public long allocateMemory(long bytes) {
+ try {
+ @Pointer
+ TruffleObject address = (TruffleObject) UNCACHED_INTEROP.execute(malloc, bytes);
+ if (UNCACHED_INTEROP.isNull(address)) {
+ // malloc returned NULL
+ return 0L;
+ }
+ return UNCACHED_INTEROP.asPointer(address);
+ } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
+ CompilerDirectives.transferToInterpreterAndInvalidate();
+ throw EspressoError.shouldNotReachHere(e);
+ }
+ }
+
+ @Override
+ public void freeMemory(long address) {
+ try {
+ UNCACHED_INTEROP.execute(free, RawPointer.create(address));
+ } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
+ CompilerDirectives.transferToInterpreterAndInvalidate();
+ throw EspressoError.shouldNotReachHere(e);
+ }
+ }
+
+ @Override
+ public long reallocateMemory(long address, long newSize) {
+ try {
+ @Pointer
+ TruffleObject newAddress = (TruffleObject) UNCACHED_INTEROP.execute(realloc, address, newSize);
+ if (UNCACHED_INTEROP.isNull(address)) {
+ // realloc returned NULL
+ return 0L;
+ }
+ return UNCACHED_INTEROP.asPointer(newAddress);
+ } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
+ CompilerDirectives.transferToInterpreterAndInvalidate();
+ throw EspressoError.shouldNotReachHere(e);
+ }
+ }
+ };
}
private TruffleObject rtldDefault() {
TruffleObject edenRtldDefault = lookupAndBindSymbol(edenLibrary, "eden_RTLD_DEFAULT", NativeSignature.create(NativeType.POINTER));
try {
- TruffleObject result = (TruffleObject) InteropLibrary.getUncached().execute(edenRtldDefault);
- assert InteropLibrary.getUncached().isPointer(result);
+ TruffleObject result = (TruffleObject) UNCACHED_INTEROP.execute(edenRtldDefault);
+ assert UNCACHED_INTEROP.isPointer(result);
return result;
} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -169,56 +214,6 @@ Object toDisplayString(boolean allowSideEffects) {
}
}
- @Override
- public @Buffer TruffleObject allocateMemory(long size) {
- if (size < 0) {
- throw new IllegalArgumentException("negative buffer length: " + size);
- }
- try {
- @Pointer
- TruffleObject address = (TruffleObject) UNCACHED_INTEROP.execute(malloc, size);
- if (InteropLibrary.getUncached().isNull(address)) {
- // malloc returned NULL
- return null;
- }
- return TruffleByteBuffer.wrap(address, Math.toIntExact(size));
- } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
- CompilerDirectives.transferToInterpreterAndInvalidate();
- throw EspressoError.shouldNotReachHere(e);
- }
- }
-
- @Override
- public void freeMemory(@Pointer TruffleObject buffer) {
- assert InteropLibrary.getUncached().isPointer(buffer);
- try {
- UNCACHED_INTEROP.execute(free, buffer);
- } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
- CompilerDirectives.transferToInterpreterAndInvalidate();
- throw EspressoError.shouldNotReachHere(e);
- }
- }
-
- @Override
- public @Buffer TruffleObject reallocateMemory(@Pointer TruffleObject buffer, long newSize) {
- if (newSize < 0) {
- throw new IllegalArgumentException("negative buffer length: " + newSize);
- }
- assert InteropLibrary.getUncached().isPointer(buffer);
- try {
- @Pointer
- TruffleObject address = (TruffleObject) UNCACHED_INTEROP.execute(realloc, buffer, newSize);
- if (InteropLibrary.getUncached().isNull(address)) {
- // realloc returned NULL
- return null;
- }
- return TruffleByteBuffer.wrap(address, Math.toIntExact(newSize));
- } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
- CompilerDirectives.transferToInterpreterAndInvalidate();
- throw EspressoError.shouldNotReachHere(e);
- }
- }
-
@Override
public void prepareThread() {
try {
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java
index ef882dc0f10b..51214ac578ab 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java
@@ -31,6 +31,7 @@
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.TruffleLogger;
@@ -59,6 +60,8 @@
import com.oracle.truffle.espresso.ffi.RawPointer;
import com.oracle.truffle.espresso.ffi.SignatureCallNode;
import com.oracle.truffle.espresso.ffi.TruffleByteBuffer;
+import com.oracle.truffle.espresso.ffi.memory.NativeMemory;
+import com.oracle.truffle.espresso.ffi.memory.UnsafeNativeMemory;
import com.oracle.truffle.espresso.meta.EspressoError;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
import com.oracle.truffle.espresso.substitutions.Collect;
@@ -82,6 +85,8 @@ public class NFINativeAccess implements NativeAccess {
private final Map signatureCache;
protected final TruffleLanguage.Env env;
+ @CompilationFinal protected NativeMemory nativeMemory;
+
protected static String nfiType(NativeType nativeType) {
// @formatter:off
switch (nativeType) {
@@ -147,7 +152,12 @@ protected final Object getOrCreateNFISignature(NativeSignature nativeSignature,
}
NFINativeAccess(TruffleLanguage.Env env) {
+ this(env, new UnsafeNativeMemory());
+ }
+
+ NFINativeAccess(TruffleLanguage.Env env, NativeMemory nativeMemory) {
this.env = env;
+ this.nativeMemory = nativeMemory;
signatureCache = CACHE_SIGNATURES
? new ConcurrentHashMap<>()
: null;
@@ -526,4 +536,8 @@ public NativeAccess create(TruffleLanguage.Env env) {
}
}
+ @Override
+ public NativeMemory nativeMemory() {
+ return nativeMemory;
+ }
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java
index 3ddde3b652e3..fad920f5368b 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java
@@ -278,6 +278,12 @@ private static class HiddenField {
entry(Types.sun_nio_fs_TrufflePath, new HiddenField[]{
new HiddenField(Names.HIDDEN_TRUFFLE_FILE, Types.java_lang_Object, EspressoLanguage::useEspressoLibs, ACC_FINAL)
}),
+ entry(Types.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream, new HiddenField[]{
+ new HiddenField(Names.HIDDEN_HOST_REFERENCE, Types.java_lang_Object, EspressoLanguage::useEspressoLibs, ACC_FINAL)
+ }),
+ entry(Types.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator, new HiddenField[]{
+ new HiddenField(Names.HIDDEN_HOST_REFERENCE, Types.java_lang_Object, EspressoLanguage::useEspressoLibs, ACC_FINAL)
+ }),
entry(Types.java_util_zip_CRC32, new HiddenField[]{
new HiddenField(Names.HIDDEN_CRC32, Types.java_lang_Object, EspressoLanguage::useEspressoLibs, ACC_FINAL)
})
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/FDAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/FDAccess.java
index 76e770dcab06..fcefe3123798 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/FDAccess.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/FDAccess.java
@@ -22,25 +22,59 @@
*/
package com.oracle.truffle.espresso.io;
-import static com.oracle.truffle.espresso.io.Checks.nullCheck;
-
import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.RandomAccessFile;
-import com.oracle.truffle.espresso.descriptors.EspressoSymbols.Names;
-import com.oracle.truffle.espresso.descriptors.EspressoSymbols.Types;
-import com.oracle.truffle.espresso.impl.Field;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
import com.oracle.truffle.espresso.substitutions.JavaType;
public abstract class FDAccess {
- public static FDAccess GENERIC = new FDAccess() {
+
+ private static final FDAccess FILE_DESCRIPTOR = new FDAccess() {
@Override
public @JavaType(FileDescriptor.class) StaticObject get(@JavaType(Object.class) StaticObject objectWithFD, TruffleIO io) {
- nullCheck(objectWithFD, io);
- Field f = objectWithFD.getKlass().lookupField(Names.fd, Types.java_io_FileDescriptor);
- return f.getObject(objectWithFD);
+ return objectWithFD;
+ }
+ };
+
+ private static final FDAccess FILE_INPUT_STREAM = new FDAccess() {
+ @Override
+ public @JavaType(FileInputStream.class) StaticObject get(@JavaType(Object.class) StaticObject objectWithFD, TruffleIO io) {
+ return io.java_io_FileInputStream_fd.getObject(objectWithFD);
+ }
+ };
+
+ private static final FDAccess FILE_OUTPUT_STREAM = new FDAccess() {
+ @Override
+ public @JavaType(FileDescriptor.class) StaticObject get(@JavaType(Object.class) StaticObject objectWithFD, TruffleIO io) {
+ return io.java_io_FileOutputStream_fd.getObject(objectWithFD);
+ }
+ };
+
+ private static final FDAccess RANDOM_ACCESS_FILE = new FDAccess() {
+ @Override
+ public @JavaType(FileDescriptor.class) StaticObject get(@JavaType(RandomAccessFile.class) StaticObject objectWithFD, TruffleIO io) {
+ Checks.nullCheck(objectWithFD, io);
+ return io.java_io_RandomAccessFile_fd.getObject(objectWithFD);
}
};
public abstract @JavaType(FileDescriptor.class) StaticObject get(@JavaType(Object.class) StaticObject objectWithFD, TruffleIO io);
+
+ public static FDAccess forFileDescriptor() {
+ return FILE_DESCRIPTOR;
+ }
+
+ public static FDAccess forFileOutputStream() {
+ return FILE_OUTPUT_STREAM;
+ }
+
+ public static FDAccess forFileInputStream() {
+ return FILE_INPUT_STREAM;
+ }
+
+ public static FDAccess forRandomAccessFile() {
+ return RANDOM_ACCESS_FILE;
+ }
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/Throw.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/Throw.java
index d0a4cf66566c..1cf8aca93d6e 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/Throw.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/Throw.java
@@ -23,8 +23,18 @@
package com.oracle.truffle.espresso.io;
import java.io.IOException;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.ClosedByInterruptException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.file.AccessDeniedException;
+import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.NotDirectoryException;
+import java.nio.file.NotLinkException;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.espresso.meta.Meta;
@@ -48,15 +58,97 @@ public static EspressoException throwFileNotFoundException(String message, Espre
throw context.getMeta().throwExceptionWithMessage(context.getTruffleIO().java_io_FileNotFoundException, message);
}
+ public static EspressoException throwIllegalArgumentException(String message, EspressoContext context) {
+ throw context.getMeta().throwExceptionWithMessage(context.getMeta().java_lang_IllegalArgumentException, message);
+ }
+
public static EspressoException throwIOException(String message, EspressoContext context) {
throw context.getMeta().throwExceptionWithMessage(context.getTruffleIO().java_io_IOException, message);
}
+ public static EspressoException throwSocketException(String message, EspressoContext context) {
+ throw context.getMeta().throwExceptionWithMessage(context.getTruffleIO().java_net_SocketException, message);
+ }
+
+ public static EspressoException throwSocketException(SocketException e, EspressoContext context) {
+ throw throwSocketException(getMessageBoundary(e), context);
+ }
+
public static EspressoException throwIOException(IOException e, EspressoContext context) {
- if (e.getClass() != IOException.class) {
- context.getLogger().warning(() -> "Not exact translation of IOException: " + e.getClass());
+ Class> exceptionClass = e.getClass();
+ String message = getMessageBoundary(e);
+ if (exceptionClass == ClosedByInterruptException.class) {
+ throw throwClosedByInterruptException(message, context);
+ }
+
+ if (exceptionClass == AsynchronousCloseException.class) {
+ throw throwAsynchronousCloseException(message, context);
+ }
+
+ if (exceptionClass == ClosedChannelException.class) {
+ throw throwClosedChannelException(message, context);
+ }
+
+ if (exceptionClass == FileAlreadyExistsException.class) {
+ throw throwFileAlreadyExistsException(message, context);
+ }
+
+ if (exceptionClass == NoSuchFileException.class) {
+ throw throwNoSuchFileException(message, context);
+ }
+
+ if (exceptionClass == DirectoryNotEmptyException.class) {
+ throw throwDirectoryNotEmptyException(message, context);
+ }
+
+ if (exceptionClass == AtomicMoveNotSupportedException.class) {
+ throw throwAtomicMoveNotSupportedException(message, context);
+ }
+
+ if (exceptionClass == NotLinkException.class) {
+ throw throwNotLinkException(message, context);
+ }
+
+ if (exceptionClass == AccessDeniedException.class) {
+ throw throwAccessDeniedException(message, context);
+ }
+
+ if (exceptionClass == NotDirectoryException.class) {
+ throw throwNotDirectoryException(message, context);
+ }
+
+ if (exceptionClass == UnknownHostException.class) {
+ throw throwUnknownHostException(message, context);
+ }
+
+ if (exceptionClass == SocketException.class) {
+ throw throwSocketException(message, context);
+ }
+
+ if (isConnectionResetException(e)) {
+ throw throwConnectionResetException(message, context);
+ }
+
+ if (exceptionClass != IOException.class) {
+ context.getLogger().warning(() -> "Not exact translation of IOException: " + exceptionClass);
}
- throw throwIOException(getMessageBoundary(e), context);
+ throw throwIOException(message, context);
+ }
+
+ public static EspressoException throwClosedByInterruptException(String message, EspressoContext context) {
+ throw context.getMeta().throwExceptionWithMessage(context.getTruffleIO().java_nio_channels_ClosedByInterruptException, message);
+ }
+
+ public static EspressoException throwAsynchronousCloseException(String message, EspressoContext context) {
+ throw context.getMeta().throwExceptionWithMessage(context.getTruffleIO().java_nio_channels_AsynchronousCloseException, message);
+ }
+
+ public static EspressoException throwClosedChannelException(String message, EspressoContext context) {
+ throw context.getMeta().throwExceptionWithMessage(context.getTruffleIO().java_nio_channels_ClosedChannelException, message);
+ }
+
+ private static boolean isConnectionResetException(IOException e) {
+ return e.getClass() == SocketException.class && (getMessageBoundary(e).equals("Connection reset"));
}
public static EspressoException throwNonReadable(EspressoContext context) {
@@ -85,43 +177,53 @@ public static EspressoException throwSecurityException(SecurityException e, Espr
throw throwSecurityException(getMessageBoundary(e), context);
}
- public static EspressoException throwFileAlreadyExists(FileAlreadyExistsException e, EspressoContext context) {
+ public static EspressoException throwFileAlreadyExistsException(String message, EspressoContext context) {
Meta meta = context.getMeta();
- throw meta.throwExceptionWithMessage(meta.java_nio_file_FileAlreadyExistsException, getMessageBoundary(e));
+ throw meta.throwExceptionWithMessage(meta.java_nio_file_FileAlreadyExistsException, message);
}
- public static EspressoException throwDirectoryNotEmpty(DirectoryNotEmptyException e, EspressoContext context) {
+ public static EspressoException throwDirectoryNotEmptyException(String message, EspressoContext context) {
Meta meta = context.getMeta();
- throw meta.throwExceptionWithMessage(meta.java_nio_file_DirectoryNotEmptyException, getMessageBoundary(e));
+ throw meta.throwExceptionWithMessage(meta.java_nio_file_DirectoryNotEmptyException, message);
}
- public static EspressoException throwAtomicMoveNotSupported(EspressoContext context) {
+ public static EspressoException throwAtomicMoveNotSupportedException(String message, EspressoContext context) {
Meta meta = context.getMeta();
- throw meta.throwException(meta.java_nio_file_AtomicMoveNotSupportedException);
+ throw meta.throwExceptionWithMessage(meta.java_nio_file_AtomicMoveNotSupportedException, message);
}
- public static EspressoException throwAccessDenied(EspressoContext context) {
+ public static EspressoException throwAccessDeniedException(String message, EspressoContext context) {
Meta meta = context.getMeta();
- throw meta.throwException(meta.java_nio_file_AccessDeniedException);
+ throw meta.throwExceptionWithMessage(meta.java_nio_file_AccessDeniedException, message);
}
- public static EspressoException throwNoSuchFile(String filePath, EspressoContext context) {
+ public static EspressoException throwNoSuchFileException(String filePath, EspressoContext context) {
Meta meta = context.getMeta();
throw meta.throwExceptionWithMessage(meta.java_nio_file_NoSuchFileException, filePath);
}
- public static EspressoException throwNotDirectory(String message, EspressoContext context) {
+ public static EspressoException throwNotDirectoryException(String message, EspressoContext context) {
Meta meta = context.getMeta();
throw meta.throwExceptionWithMessage(meta.java_nio_file_NotDirectoryException, message);
}
- public static EspressoException throwIllegalState(String message, EspressoContext context) {
+ public static EspressoException throwIllegalStateException(String message, EspressoContext context) {
Meta meta = context.getMeta();
throw meta.throwExceptionWithMessage(meta.java_lang_IllegalStateException, message);
}
- public static EspressoException throwNotLink(String file, EspressoContext context) {
+ public static EspressoException throwNotLinkException(String message, EspressoContext context) {
+ Meta meta = context.getMeta();
+ throw meta.throwExceptionWithMessage(meta.java_nio_file_NotLinkException, message);
+ }
+
+ public static EspressoException throwConnectionResetException(String message, EspressoContext context) {
+ Meta meta = context.getMeta();
+ return meta.throwExceptionWithMessage(context.getTruffleIO().sun_net_ConnectionResetException, message);
+ }
+
+ public static EspressoException throwUnknownHostException(String message, EspressoContext context) {
Meta meta = context.getMeta();
- throw meta.throwExceptionWithMessage(meta.java_nio_file_NotLinkException, file);
+ return meta.throwExceptionWithMessage(context.getTruffleIO().java_net_UnknownHostException, message);
}
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/TruffleIO.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/TruffleIO.java
index d9d09c5de7f7..7b6a921c9142 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/TruffleIO.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/io/TruffleIO.java
@@ -23,6 +23,7 @@
package com.oracle.truffle.espresso.io;
import static com.oracle.truffle.espresso.libs.libnio.impl.Target_sun_nio_ch_IOUtil.FD_LIMIT;
+import static com.oracle.truffle.espresso.substitutions.standard.Target_sun_misc_Unsafe.ADDRESS_SIZE;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -30,17 +31,38 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.SocketOption;
+import java.net.StandardProtocolFamily;
+import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.Channel;
import java.nio.channels.Channels;
+import java.nio.channels.ClosedByInterruptException;
+import java.nio.channels.DatagramChannel;
+import java.nio.channels.GatheringByteChannel;
+import java.nio.channels.NetworkChannel;
import java.nio.channels.NonReadableChannelException;
import java.nio.channels.NonWritableChannelException;
+import java.nio.channels.Pipe;
import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.ScatteringByteChannel;
import java.nio.channels.SeekableByteChannel;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
+import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.file.OpenOption;
import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.FileAttribute;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@@ -53,18 +75,22 @@
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.espresso.classfile.descriptors.Name;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
+import com.oracle.truffle.espresso.descriptors.EspressoSymbols;
import com.oracle.truffle.espresso.descriptors.EspressoSymbols.Names;
import com.oracle.truffle.espresso.descriptors.EspressoSymbols.Signatures;
import com.oracle.truffle.espresso.descriptors.EspressoSymbols.Types;
+import com.oracle.truffle.espresso.ffi.memory.NativeMemory;
import com.oracle.truffle.espresso.impl.ContextAccess;
import com.oracle.truffle.espresso.impl.Field;
import com.oracle.truffle.espresso.impl.Method;
import com.oracle.truffle.espresso.impl.ObjectKlass;
+import com.oracle.truffle.espresso.libs.LibsState;
import com.oracle.truffle.espresso.meta.EspressoError;
import com.oracle.truffle.espresso.meta.Meta;
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.OS;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
import com.oracle.truffle.espresso.substitutions.JavaType;
/**
@@ -85,7 +111,14 @@ public final class TruffleIO implements ContextAccess {
// Checkstyle: stop field name check
public final ObjectKlass java_io_IOException;
+ public final ObjectKlass java_nio_file_NoSuchFileException;
+ public final ObjectKlass java_net_SocketException;
public final ObjectKlass java_io_FileNotFoundException;
+ public final ObjectKlass java_nio_channels_ClosedByInterruptException;
+ public final ObjectKlass java_nio_channels_AsynchronousCloseException;
+ public final ObjectKlass java_nio_channels_ClosedChannelException;
+ public final ObjectKlass sun_net_ConnectionResetException;
+ public final ObjectKlass java_net_UnknownHostException;
public final ObjectKlass java_io_FileDescriptor;
public final Field java_io_FileDescriptor_fd;
public final Field java_io_FileDescriptor_append;
@@ -113,6 +146,12 @@ public final class TruffleIO implements ContextAccess {
public final ObjectKlass sun_nio_fs_DefaultFileSystemProvider;
public final Method sun_nio_fs_DefaultFileSystemProvider_instance;
+ public final ObjectKlass sun_nio_fs_FileAttributeParser;
+ @CompilationFinal public FileAttributeParser_Sync fileAttributeParserSync;
+
+ public final ObjectKlass sun_nio_ch_IOStatus;
+ public final IOStatus_Sync ioStatusSync;
+
public final ObjectKlass java_io_FileSystem;
public final FileSystem_Sync fileSystemSync;
// Checkstyle: resume field name check
@@ -183,6 +222,398 @@ public TruffleFile getPublicTruffleFileSafe(String path) {
}
}
+ /**
+ * Opens a file and associates it with the given file descriptor holder.
+ *
+ * @param self A file descriptor holder.
+ * @param fdAccess How to get the file descriptor from the holder.
+ * @param path The location where the file is opened.
+ * @param openOptions Options to open the file.
+ * @param attributes The file attributes atomically set when opening the file.
+ * @return The file descriptor associated with the file.
+ */
+ @TruffleBoundary
+ public int open(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess,
+ TruffleFile path,
+ Set extends OpenOption> openOptions,
+ FileAttribute>... attributes) {
+ StaticObject fileDesc = getFileDesc(self, fdAccess);
+ int fd = open(path, openOptions, attributes);
+ boolean append = openOptions.contains(StandardOpenOption.APPEND);
+ updateFD(fileDesc, fd, append);
+ return fd;
+ }
+
+ /**
+ * Temporary Method to open a Socket with the given parameter and associate it with a generated
+ * fd. It will be replaced with a TruffleAPI as soon as one exists.
+ *
+ * @param preferIPv6 whether to prefer IPv6 over IPv4
+ * @param stream TCP or UDP
+ * @param reuse allows binding to an address even if in TIME_WAIT state
+ *
+ * @return The file descriptor associated with the file.
+ */
+ @TruffleBoundary
+ public int openSocket(boolean preferIPv6, boolean stream, boolean reuse) {
+ context.getInformationLeak().checkNetworkEnabled();
+ // opening the channel
+ java.net.ProtocolFamily family = preferIPv6 ? StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
+ ChannelWrapper channelWrapper;
+ try {
+ if (stream && !reuse) {
+ // this implies that we are opening a TCP Client Channel
+ // according to sun.nio.ch.Net.socket(java.net.ProtocolFamily,boolean)
+ SocketChannel channel = SocketChannel.open(family);
+ channel.setOption(StandardSocketOptions.SO_REUSEADDR, reuse);
+ channelWrapper = new ChannelWrapper(channel, 1);
+ } else if (stream) {
+ // opens a TCP Server Channel
+ ServerSocketChannel channel = ServerSocketChannel.open(family);
+ channel.setOption(StandardSocketOptions.SO_REUSEADDR, reuse);
+ channelWrapper = new TCPChannelWrapper(channel, 1);
+ } else {
+ // opens a UDP Channel
+ DatagramChannel channel = DatagramChannel.open(StandardProtocolFamily.INET);
+ channel.setOption(StandardSocketOptions.SO_REUSEADDR, reuse);
+ channelWrapper = new ChannelWrapper(channel, 1);
+ }
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ return createFDforChannel(channelWrapper);
+ }
+
+ /**
+ * Temporary Method to open a pipe (since we return a HostPipe here).
+ *
+ * @param blocking the blocking mode of the created pipe.
+ * @return Returns two file descriptors for a pipe encoded in a long. The read end of the pipe
+ * is returned in the high 32 bits, while the write end is returned in the low 32 bits.
+ */
+ @TruffleBoundary
+ public long openPipe(boolean blocking) {
+ // opening the channel
+ try {
+ Pipe pipe = Pipe.open();
+ Pipe.SinkChannel sink = pipe.sink();
+ Pipe.SourceChannel source = pipe.source();
+ sink.configureBlocking(blocking);
+ source.configureBlocking(blocking);
+ ChannelWrapper channelWrapperSink = new ChannelWrapper(sink, 1);
+ ChannelWrapper channelWrapperSource = new ChannelWrapper(source, 1);
+ int sourceFd = createFDforChannel(channelWrapperSource); // fd[0]
+ int sinkFd = createFDforChannel(channelWrapperSink); // fd[1]
+ return ((long) sourceFd << 32) | (sinkFd & 0xFFFFFFFFL);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ @TruffleBoundary
+ public void configureBlocking(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, boolean blocking) {
+ Channel channel = Checks.ensureOpen(getChannel(getFD(self, fdAccess)), getContext());
+ if (channel instanceof AbstractSelectableChannel selectableChannel) {
+ try {
+ selectableChannel.configureBlocking(blocking);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+ }
+
+ @TruffleBoundary
+ public int available(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess) {
+ try {
+ return Channels.newInputStream(getReadableChannel(self, fdAccess)).available();
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ @TruffleBoundary
+ public void bind(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, boolean preferIPv6, boolean useExclBind, @JavaType(InetAddress.class) StaticObject addr,
+ int port, LibsState libsState) {
+ ChannelWrapper channelWrapper = files.getOrDefault(getFD(self, fdAccess), null);
+ Objects.requireNonNull(channelWrapper);
+ Channel channel = channelWrapper.channel;
+
+ InetAddress inetAddress = libsState.net.fromGuestInetAddress(addr);
+
+ if (channel instanceof DatagramChannel datagramChannel) {
+ this.bindUDP(datagramChannel, inetAddress, preferIPv6, useExclBind, port);
+ } else if (channelWrapper instanceof TCPChannelWrapper tcpChannelWrapper) {
+ /*
+ * We shouldn't call bind directly on the ServerSocketChannel since we lack the backlog.
+ * parameter which will be provided by the listen method. Thus, we cache the arguments
+ * but wait with the bind.
+ */
+ tcpChannelWrapper.setTCPBindInformation(inetAddress, preferIPv6, useExclBind, port);
+ } else {
+ // the Server-fd isn't associated with a TCP-Channel for a TCP protocol method!
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ }
+
+ @TruffleBoundary
+ public void bindUDP(DatagramChannel datagramChannel, InetAddress inetAddress, boolean preferIPv6, boolean useExclBind, int port) {
+ this.initSocketOptions(datagramChannel, preferIPv6, useExclBind);
+ try {
+ datagramChannel.bind(new InetSocketAddress(inetAddress, port));
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ @TruffleBoundary
+ public int accept(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, @JavaType(FileDescriptor.class) StaticObject newfd, SocketAddress[] ret,
+ LibsState libsState) {
+ Channel channel = Checks.ensureOpen(getChannel(getFD(self, fdAccess)), getContext());
+ if (channel instanceof ServerSocketChannel serverSocketChannel) {
+ try {
+ // accept the connection
+ SocketChannel clientSocket = serverSocketChannel.accept();
+ if (clientSocket == null) {
+ return this.ioStatusSync.UNAVAILABLE;
+ }
+ // register the channel with a fd
+ int newfdVal = createFDforChannel(new ChannelWrapper(clientSocket, 1));
+ // set the value of the fd
+ libsState.net.setFDVal(newfd, newfdVal);
+ // return the remoteAddress
+ ret[0] = clientSocket.getRemoteAddress();
+ return 1;
+ } catch (AsynchronousCloseException e) {
+ return ioStatusSync.UNAVAILABLE;
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ } else {
+ // the Server-fd isn't associated with a TCP-Channel for a TCP protocol method!
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ }
+
+ /**
+ * Calls finishConnect on the underlying SocketChannel.
+ */
+ @TruffleBoundary
+ public boolean finishConnect(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess) {
+ try {
+ return getSocketChannel(self, fdAccess).finishConnect();
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ public void setSocketOption(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, SocketOption name, T value) {
+ try {
+ getNetworkChannel(self, fdAccess).setOption(name, value);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ public boolean connect(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, SocketAddress remote) {
+ try {
+ return getSocketChannel(self, fdAccess).connect(remote);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ public void shutdownSocketChannel(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, int how) {
+ try {
+ SocketChannel socketChannel = getSocketChannel(self, fdAccess);
+ if (how == 2 || how == 0) {
+ socketChannel.shutdownInput();
+ }
+ if (how == 1 || how == 2) {
+ socketChannel.shutdownOutput();
+ }
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ public T getSocketOption(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, SocketOption name) {
+ try {
+ return getNetworkChannel(self, fdAccess).getOption(name);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ private int createFDforChannel(ChannelWrapper channel) {
+ synchronized (files) {
+ int fd = nextFreeFd();
+ if (fd < 0) {
+ throw Throw.throwFileNotFoundException("Opened file limit reached.", context);
+ }
+ files.put(fd, channel);
+ return fd;
+ }
+ }
+
+ @TruffleBoundary
+ public void listenTCP(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, int backlog) {
+ int fd = getFD(getFileDesc(self, fdAccess));
+ ChannelWrapper channelWrapper = files.getOrDefault(fd, null);
+ Objects.requireNonNull(channelWrapper);
+ if (channelWrapper instanceof TCPChannelWrapper tcpWrapper) {
+ ServerSocketChannel channel = (ServerSocketChannel) channelWrapper.channel;
+ initSocketOptions(channel, tcpWrapper.preferIPv6, tcpWrapper.useExclBind);
+ try {
+ channel.bind(new InetSocketAddress(tcpWrapper.inetAddress, tcpWrapper.port), backlog);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ } else {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ }
+
+ @TruffleBoundary
+ public @JavaType StaticObject getLocalAddress(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess) {
+
+ try {
+ int fd = getFD(self, fdAccess);
+ NetworkChannel networkChannel = getNetworkChannel(fd);
+ InetSocketAddress socketAddress = (InetSocketAddress) networkChannel.getLocalAddress();
+ InetAddress inetAddress = null;
+ if (socketAddress != null) {
+ inetAddress = socketAddress.getAddress();
+ } else {
+ /*
+ * The host socket is bound once listen is called. On the other hand, the guest
+ * socket is bound by the call to bind (which proceeds the listen call. Thus, we
+ * need to check if we have cached the bind information.
+ */
+ TCPChannelWrapper tcpSocket = socketIsBound(fd);
+ if (tcpSocket != null) {
+ inetAddress = tcpSocket.inetAddress;
+ } else {
+ throw Throw.throwIOException("Unbound Socket", context);
+ }
+ }
+ return context.getLibsState().net.convertInetAddr(inetAddress);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ @TruffleBoundary
+ public int getPort(@JavaType(Object.class) StaticObject self, FDAccess fdAccess) {
+ try {
+ int fd = getFD(self, fdAccess);
+ InetSocketAddress socketAddress = (InetSocketAddress) getNetworkChannel(fd).getLocalAddress();
+ if (socketAddress != null) {
+ return socketAddress.getPort();
+ }
+ /*
+ * The host socket is bound once listen is called. On the other hand, the guest socket
+ * is bound by the call to bind (which proceeds the listen call. Thus, we need to check
+ * if we have cached the bind information.
+ */
+ TCPChannelWrapper tcpSocket = socketIsBound(fd);
+ if (tcpSocket != null) {
+ return tcpSocket.port;
+ }
+ throw Throw.throwIOException("Unbound Socket", context);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ private TCPChannelWrapper socketIsBound(int fd) {
+ if (files.getOrDefault(fd, null) instanceof TCPChannelWrapper tcpChannelWrapper) {
+ if (tcpChannelWrapper.inetAddress != null) {
+ return tcpChannelWrapper;
+ }
+ }
+ return null;
+ }
+
+ private void initSocketOptions(NetworkChannel networkChannel, boolean preferIPv6, boolean useExclBind) {
+ try {
+ if (preferIPv6) {
+ // might be overkill. We could just let the system figure out what it wants to use.
+ System.setProperty("java.net.preferIPv6Addresses", "true");
+ System.setProperty("java.net.preferIPv6Addresses", "false");
+ } else {
+ System.setProperty("java.net.preferIPv6Addresses", "false");
+ System.setProperty("java.net.preferIPv6Addresses", "true");
+ }
+ } catch (SecurityException e) {
+ // ignore preferIPv6
+ }
+ try {
+ networkChannel.setOption(StandardSocketOptions.SO_REUSEADDR, !useExclBind);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ /**
+ * Works as specified by {@link TruffleIO#register(StaticObject, FDAccess, Selector, int)} but
+ * with the raw int fd.
+ */
+ @TruffleBoundary
+ public SelectionKey register(int fd, Selector selector, int ops) {
+ Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
+ if (channel instanceof AbstractSelectableChannel selectableChannel) {
+ try {
+ // selectableChannel.configureBlocking(false);
+ if (selectableChannel.isBlocking()) {
+ throw Throw.throwIOException("Channel is blocking and thus can't be registered to a Selector", context);
+ }
+ context.getLibsState().net.checkValidOps(selectableChannel, ops);
+ return selectableChannel.register(selector, ops);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ } catch (RuntimeException e) {
+ // the method shouldn't throw anything but an IOException
+ throw Throw.throwIOException("In a native method the following exception occurred: " + e.getClass().toString() + ": " + e.getMessage(), context);
+ }
+ } else {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ }
+
+ /**
+ * Registers a file descriptor with a selector for the specified operations.
+ *
+ *
+ *
+ * The file descriptor {@code fd} is associated with a channel, which must be an instance of
+ * {@link SelectableChannel}. If the channel is not selectable, an {@link IOException} is
+ * thrown.
+ *
+ *
+ * @param self A file descriptor holder
+ * @param fdAccess How to get the file descriptor from the holder
+ * @param selector The selector to register with
+ * @param ops the operations to monitor (e.g., {@link SelectionKey#OP_READ},
+ * {@link SelectionKey#OP_WRITE})
+ */
+ public SelectionKey register(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, Selector selector, int ops) {
+ int fd = getFD(getFileDesc(self, fdAccess));
+ return register(fd, selector, ops);
+ }
+
/**
* Opens a file and associates it with the given file descriptor holder.
*
@@ -198,8 +629,8 @@ public int open(@JavaType(Object.class) StaticObject self,
String name,
Set extends OpenOption> openOptions) {
StaticObject fileDesc = getFileDesc(self, fdAccess);
- boolean append = openOptions.contains(StandardOpenOption.APPEND);
int fd = open(name, openOptions);
+ boolean append = openOptions.contains(StandardOpenOption.APPEND);
updateFD(fileDesc, fd, append);
return fd;
}
@@ -227,14 +658,13 @@ public boolean close(@JavaType(Object.class) StaticObject self,
/**
* Obtains the length of the file associated with the given file descriptor holder.
- *
+ *
* @see RandomAccessFile#length()
*/
@TruffleBoundary
public long length(@JavaType(Object.class) StaticObject self,
FDAccess fdAccess) {
- StaticObject fileDesc = getFileDesc(self, fdAccess);
- return length(getFD(fileDesc));
+ return length(getFD(self, fdAccess));
}
/**
@@ -242,11 +672,56 @@ public long length(@JavaType(Object.class) StaticObject self,
*/
@TruffleBoundary
public long length(int fd) {
- Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
- if (channel instanceof SeekableByteChannel seekableChannel) {
- return sizeImpl(seekableChannel, context);
+ return sizeImpl(getSeekableChannel(fd), context);
+ }
+
+ /**
+ * Writes buffered bytes to the file associated with the given file descriptor holder.
+ *
+ * @param self The file descriptor holder.
+ * @param fdAccess How to get the file descriptor from the holder.
+ * @param bytes The byte buffer containing the bytes to write.
+ * @return The number of bytes written, possibly zero.
+ * @see java.io.FileOutputStream#write(byte[])
+ */
+ @TruffleBoundary
+ public int writeBytes(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess,
+ ByteBuffer bytes) {
+ try {
+ return getWritableChannel(self, fdAccess).write(bytes);
+ } catch (ClosedByInterruptException e) {
+ return ioStatusSync.UNAVAILABLE;
+ } catch (NonWritableChannelException e) {
+ throw Throw.throwNonWritable(context);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ /**
+ * Writes bytes from the address specified to the file associated with the given file descriptor
+ * holder.
+ *
+ * @param self The file descriptor holder.
+ * @param fdAccess How to get the file descriptor from the holder.
+ * @param address The address containing the bytes to write.
+ * @param length the number of bytes to write.
+ * @return The number of bytes written, possibly zero.
+ * @see java.io.FileOutputStream#write(byte[])
+ */
+ @TruffleBoundary
+ public int writeAddress(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess,
+ long address, int length) {
+ NativeMemory nativeMemory = context.getNativeAccess().nativeMemory();
+ if (nativeMemory.isDirectBufferSupported()) {
+ return writeBytes(self, fdAccess, nativeMemory.getDirectBuffer(address, length));
+ } else {
+ byte[] buf = new byte[length];
+ nativeMemory.readMemory(address, length, buf);
+ return writeBytes(self, fdAccess, buf, 0, length);
}
- return 0; // unknown
}
/**
@@ -254,9 +729,7 @@ public long length(int fd) {
*
* @param self The file descriptor holder.
* @param fdAccess How to get the file descriptor from the holder.
- * @param bytes The byte array containing the bytes to write.
- * @param off The start of the byte sequence to write from {@code bytes}.
- * @param len The length of the byte sequence to write.
+ * @param bytes The ByteBuffer containing the bytes to write.
* @return The number of bytes written, possibly zero.
* @see java.io.FileOutputStream#write(byte[], int, int)
*/
@@ -265,8 +738,7 @@ public int writeBytes(@JavaType(Object.class) StaticObject self,
FDAccess fdAccess,
byte[] bytes,
int off, int len) {
- StaticObject fileDesc = getFileDesc(self, fdAccess);
- return writeBytes(getFD(fileDesc), bytes, off, len);
+ return writeBytes(getFD(self, fdAccess), bytes, off, len);
}
/**
@@ -278,12 +750,69 @@ public int writeBytes(@JavaType(Object.class) StaticObject self,
public int writeBytes(int fd,
byte[] bytes,
int off, int len) {
- Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
- if (channel instanceof WritableByteChannel) {
- return writeBytesImpl((WritableByteChannel) channel, bytes, off, len, context);
- } else {
- throw Throw.throwNonWritable(context);
+ return writeBytesImpl(getWritableChannel(fd), bytes, off, len, context);
+ }
+
+ /**
+ * Writes the content of the underlying "native" ByteBuffers to the file associated with the
+ * given file descriptor holder in the exact order of the ByteBuffers array.
+ *
+ * @param self The file descriptor holder.
+ * @param fdAccess How to get the file descriptor from the holder.
+ * @param address The base address of the continuous memory region, which contains addresses and
+ * lengths for the ByteBuffers we write from.
+ * @param length the number of ByteBuffers to extract from address.
+ * @return The number of bytes written, possibly zero.
+ * @see java.nio.channels.GatheringByteChannel#write(ByteBuffer[])
+ */
+ @TruffleBoundary
+ public long writev(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess,
+ long address, int length) {
+ if (context.getNativeAccess().nativeMemory().isDirectBufferSupported()) {
+ // Extracting all the buffers comes at a cost. In my opinions it is only worth it if we
+ // have direct memory access. Otherwise, we need to copy alot between buffers and memory
+ StaticObject fileDesc = getFileDesc(self, fdAccess);
+ Channel channel = Checks.ensureOpen(getChannel(getFD(fileDesc)), getContext());
+ if (channel instanceof GatheringByteChannel gatheringByteChannel) {
+ try {
+ return gatheringByteChannel.write(getByteBuffersFromIOVec(address, length, context.getNativeAccess().nativeMemory()));
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+ }
+ return sequentialWritev(self, fdAccess, address, length);
+ }
+
+ /**
+ * Reads the content of the file associated with the given file descriptor into the underlying
+ * "native" ByteBuffers.
+ *
+ * @param self The file descriptor holder.
+ * @param fdAccess How to get the file descriptor from the holder.
+ * @param address The base address of the continuous memory region, which contains addresses and
+ * lengths for the ByteBuffers we read into.
+ * @param length the number of ByteBuffers to extract from address.
+ * @return The number of bytes written, possibly zero.
+ * @see java.nio.channels.ScatteringByteChannel#read(ByteBuffer)
+ */
+ @TruffleBoundary
+ public long readv(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess,
+ long address, int length) {
+ if (context.getNativeAccess().nativeMemory().isDirectBufferSupported()) {
+ StaticObject fileDesc = getFileDesc(self, fdAccess);
+ Channel channel = Checks.ensureOpen(getChannel(getFD(fileDesc)), getContext());
+ if (channel instanceof ScatteringByteChannel scatteringByteChannel) {
+ try {
+ return scatteringByteChannel.read(getByteBuffersFromIOVec(address, length, context.getNativeAccess().nativeMemory()));
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
}
+ return sequentialReadv(self, fdAccess, address, length);
}
/**
@@ -297,8 +826,7 @@ public int writeBytes(int fd,
@TruffleBoundary
public int readSingle(@JavaType(Object.class) StaticObject self,
FDAccess fdAccess) {
- StaticObject fileDesc = getFileDesc(self, fdAccess);
- return readSingle(getFD(fileDesc));
+ return readSingle(getFD(self, fdAccess));
}
/**
@@ -308,12 +836,7 @@ public int readSingle(@JavaType(Object.class) StaticObject self,
*/
@TruffleBoundary
public int readSingle(int fd) {
- Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
- if (channel instanceof ReadableByteChannel readableByteChannel) {
- return readSingleImpl(readableByteChannel, context);
- } else {
- throw Throw.throwNonReadable(context);
- }
+ return readSingleImpl(getReadableChannel(fd), context);
}
/**
@@ -333,8 +856,47 @@ public int readBytes(@JavaType(Object.class) StaticObject self,
FDAccess fdAccess,
byte[] bytes,
int off, int len) {
- StaticObject fileDesc = getFileDesc(self, fdAccess);
- return readBytes(getFD(fileDesc), bytes, off, len);
+ return readBytes(getFD(self, fdAccess), bytes, off, len);
+ }
+
+ /**
+ * Reads a byte sequence from the file associated with the given file descriptor holder.
+ *
+ * @param self The file descriptor holder.
+ * @param fdAccess How to get the file descriptor from the holder.
+ * @param buffer The ByteBuffer that will contain the bytes read.
+ * @return The number of bytes read, possibly zero, or -1 if the channel has reached
+ * end-of-stream
+ * @see java.io.FileInputStream#read(byte[], int, int)
+ */
+ @TruffleBoundary
+ public int readBytes(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess,
+ ByteBuffer buffer) {
+ try {
+ return getReadableChannel(self, fdAccess).read(buffer);
+ } catch (ClosedByInterruptException e) {
+ return ioStatusSync.UNAVAILABLE;
+ } catch (NonReadableChannelException e) {
+ throw Throw.throwNonReadable(context);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ /**
+ * @return whether the channel associated with the fd is in blocking mode.
+ */
+ @TruffleBoundary
+ public boolean isBlocking(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess) {
+ Channel channel = Checks.ensureOpen(getChannel(getFD(self, fdAccess)), getContext());
+ if (channel instanceof AbstractSelectableChannel selectableChannel) {
+ return selectableChannel.isBlocking();
+ } else {
+ // the fd isn't an AbstractSelectableChannel
+ throw JavaSubstitution.shouldNotReachHere();
+ }
}
/**
@@ -346,11 +908,28 @@ public int readBytes(@JavaType(Object.class) StaticObject self,
public int readBytes(int fd,
byte[] bytes,
int off, int len) {
- Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
- if (channel instanceof ReadableByteChannel readableByteChannel) {
- return readBytesImpl(readableByteChannel, bytes, off, len, context);
+ return readBytesImpl(getReadableChannel(fd), bytes, off, len, context);
+ }
+
+ /**
+ * Reads a byte sequence from the file associated with the given file descriptor.
+ *
+ * @param addr the address to read into
+ * @param length how many bytes to read
+ * @see #readBytes(StaticObject, FDAccess, byte[], int, int)
+ */
+ @TruffleBoundary
+ public int readAddress(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, long addr,
+ int length) {
+ NativeMemory nativeMemory = context.getNativeAccess().nativeMemory();
+ if (nativeMemory.isDirectBufferSupported()) {
+ return readBytes(self, fdAccess, nativeMemory.getDirectBuffer(addr, length));
} else {
- throw Throw.throwNonReadable(context);
+ byte[] buf = new byte[length];
+ int ret = readBytes(self, fdAccess, buf, 0, length);
+ nativeMemory.writeMemory(addr, length, buf);
+ return ret;
}
}
@@ -365,8 +944,7 @@ public int readBytes(int fd,
@TruffleBoundary
public boolean drain(@JavaType(Object.class) StaticObject self,
FDAccess fdAccess) {
- StaticObject fileDesc = getFileDesc(self, fdAccess);
- return drain(getFD(fileDesc));
+ return drain(getFD(self, fdAccess));
}
/**
@@ -377,22 +955,18 @@ public boolean drain(@JavaType(Object.class) StaticObject self,
*/
@TruffleBoundary
public boolean drain(int fd) {
- Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
- if (channel instanceof ReadableByteChannel readableByteChannel) {
- try {
- ByteBuffer bytes = ByteBuffer.wrap(new byte[DRAIN_SEGMENT_COUNT]);
- boolean discarded = false;
- while ((readableByteChannel.read(bytes)) > 0) {
- discarded = true;
- }
- return discarded;
- } catch (NonReadableChannelException e) {
- throw Throw.throwNonReadable(context);
- } catch (IOException e) {
- throw Throw.throwIOException(e, context);
+ try {
+ ByteBuffer bytes = ByteBuffer.wrap(new byte[DRAIN_SEGMENT_COUNT]);
+ boolean discarded = false;
+ ReadableByteChannel readableByteChannel = getReadableChannel(fd);
+ while ((readableByteChannel.read(bytes)) > 0) {
+ discarded = true;
}
- } else {
+ return discarded;
+ } catch (NonReadableChannelException e) {
throw Throw.throwNonReadable(context);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
}
}
@@ -407,8 +981,7 @@ public boolean drain(int fd) {
@TruffleBoundary
public long position(@JavaType(Object.class) StaticObject self,
FDAccess fdAccess) {
- StaticObject fileDesc = getFileDesc(self, fdAccess);
- return position(getFD(fileDesc));
+ return position(getFD(self, fdAccess));
}
/**
@@ -419,15 +992,11 @@ public long position(@JavaType(Object.class) StaticObject self,
*/
@TruffleBoundary
public long position(int fd) {
- Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
- if (channel instanceof SeekableByteChannel seekableChannel) {
- try {
- return seekableChannel.position();
- } catch (IOException e) {
- throw Throw.throwIOException(e, context);
- }
- } else {
- return 0; // unknown
+ SeekableByteChannel seekableChannel = getSeekableChannel(fd);
+ try {
+ return seekableChannel.position();
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
}
}
@@ -444,8 +1013,7 @@ public long position(int fd) {
public void seek(@JavaType(Object.class) StaticObject self,
FDAccess fdAccess,
long pos) {
- StaticObject fileDesc = getFileDesc(self, fdAccess);
- seek(getFD(fileDesc), pos);
+ seek(getFD(self, fdAccess), pos);
}
/**
@@ -457,15 +1025,11 @@ public void seek(@JavaType(Object.class) StaticObject self,
@TruffleBoundary
public void seek(int fd,
long pos) {
- Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
- if (channel instanceof SeekableByteChannel seekableChannel) {
- try {
- seekableChannel.position(pos);
- } catch (IOException e) {
- throw Throw.throwIOException(e, context);
- }
- } else {
- Throw.throwNonSeekable(context);
+ SeekableByteChannel seekableChannel = getSeekableChannel(fd);
+ try {
+ seekableChannel.position(pos);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
}
}
@@ -496,6 +1060,10 @@ private Channel getChannel(int fd) {
return getFileChannel(fd);
}
+ private int getFD(StaticObject self, FDAccess fdAccess) {
+ return getFD(getFileDesc(self, fdAccess));
+ }
+
private int getFD(@JavaType(FileDescriptor.class) StaticObject fileDescriptor) {
assert !StaticObject.isNull(fileDescriptor);
return java_io_FileDescriptor_fd.getInt(fileDescriptor);
@@ -559,6 +1127,24 @@ void withPath(String newPath) {
}
}
+ private static class TCPChannelWrapper extends ChannelWrapper {
+ InetAddress inetAddress;
+ boolean preferIPv6;
+ boolean useExclBind;
+ int port;
+
+ TCPChannelWrapper(Channel channel, int cnt) {
+ super(channel, cnt, null);
+ }
+
+ void setTCPBindInformation(InetAddress inetAddress, boolean preferIPv6, boolean useExclBind, int port) {
+ this.inetAddress = inetAddress;
+ this.preferIPv6 = preferIPv6;
+ this.useExclBind = useExclBind;
+ this.port = port;
+ }
+ }
+
public TruffleIO(EspressoContext context) {
this.context = context;
@@ -596,8 +1182,16 @@ public TruffleIO(EspressoContext context) {
java_io_RandomAccessFile_fd = java_io_RandomAccessFile.requireDeclaredField(Names.fd, Types.java_io_FileDescriptor);
rafSync = new RAF_Sync(this);
+ // IOExceptions
java_io_IOException = meta.knownKlass(Types.java_io_IOException);
- java_io_FileNotFoundException = meta.knownKlass(Types.java_io_IOException);
+ java_io_FileNotFoundException = meta.knownKlass(Types.java_io_FileNotFoundException);
+ java_nio_channels_ClosedByInterruptException = meta.knownKlass(Types.java_nio_channels_ClosedByInterruptException);
+ java_nio_channels_AsynchronousCloseException = meta.knownKlass(Types.java_nio_channels_AsynchronousCloseException);
+ java_nio_channels_ClosedChannelException = meta.knownKlass(Types.java_nio_channels_ClosedChannelException);
+ java_nio_file_NoSuchFileException = meta.knownKlass(Types.java_nio_file_NoSuchFileException);
+ java_net_SocketException = meta.knownKlass(Types.java_net_SocketException);
+ sun_net_ConnectionResetException = meta.knownKlass(EspressoSymbols.Types.sun_net_ConnectionResetException);
+ java_net_UnknownHostException = meta.knownKlass(EspressoSymbols.Types.java_net_UnknownHostException);
java_io_File = meta.knownKlass(Types.java_io_File);
java_io_File_path = java_io_File.requireDeclaredField(Names.path, Types.java_lang_String);
@@ -611,6 +1205,11 @@ public TruffleIO(EspressoContext context) {
sun_nio_fs_DefaultFileSystemProvider = meta.knownKlass(Types.sun_nio_fs_DefaultFileSystemProvider);
sun_nio_fs_DefaultFileSystemProvider_instance = sun_nio_fs_DefaultFileSystemProvider.requireDeclaredMethod(Names.instance, Signatures.sun_nio_fs_TruffleFileSystemProvider);
+ sun_nio_fs_FileAttributeParser = meta.knownKlass(EspressoSymbols.Types.sun_nio_fs_FileAttributeParser);
+
+ sun_nio_ch_IOStatus = meta.knownKlass(EspressoSymbols.Types.sun_nio_ch_IOStatus);
+ ioStatusSync = new IOStatus_Sync(this);
+
sun_nio_fs_TrufflePath = meta.knownKlass(Types.sun_nio_fs_TrufflePath);
sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE = sun_nio_fs_TrufflePath.requireHiddenField(Names.HIDDEN_TRUFFLE_FILE);
@@ -620,6 +1219,13 @@ public TruffleIO(EspressoContext context) {
setEnv(context.getEnv());
}
+ /**
+ * See {@link Meta#postSystemInit()}.
+ */
+ public void postSystemInit() {
+ this.fileAttributeParserSync = new FileAttributeParser_Sync(this);
+ }
+
private void setEnv(TruffleLanguage.Env env) {
synchronized (files) {
files.get(FD_STDIN).setNewChannel(new DetachOnCloseInputStream(env.in()));
@@ -677,9 +1283,9 @@ private int open(TruffleFile path, Channel fc) {
}
}
- private int open(TruffleFile path, Set extends OpenOption> options) {
+ private int open(TruffleFile path, Set extends OpenOption> options, FileAttribute>... attributes) {
try {
- Channel channel = path.newByteChannel(options);
+ Channel channel = path.newByteChannel(options, attributes);
return open(path, channel);
} catch (IOException | UnsupportedOperationException | IllegalArgumentException | SecurityException e) {
// Guest code only ever expects FileNotFoundException.
@@ -715,7 +1321,7 @@ private static int readSingleImpl(ReadableByteChannel readableChannel, EspressoC
if (bytesRead == 1) {
return b[0] & 0xFF;
} else {
- return -1; // EOF
+ return context.getTruffleIO().ioStatusSync.EOF; // EOF
}
} catch (NonReadableChannelException e) {
throw Throw.throwNonReadable(context);
@@ -740,6 +1346,131 @@ private static int readBytesImpl(ReadableByteChannel readableChannel, byte[] b,
}
}
+ private long sequentialWritev(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, long address, int len) {
+ // constants
+ int lenOffset = ADDRESS_SIZE;
+ int sizeOfIOVec = (short) (ADDRESS_SIZE * 2);
+ long curIOVecAddr = address;
+ long nextAddr;
+ long nextLen;
+ long ret = 0;
+ NativeMemory nativeMemory = context.getNativeAccess().nativeMemory();
+ for (int i = 0; i < len; i++) {
+ if (ADDRESS_SIZE == 4) {
+ nextAddr = nativeMemory.getInt(curIOVecAddr, NativeMemory.MemoryAccessMode.PLAIN);
+ nextLen = nativeMemory.getInt(curIOVecAddr + lenOffset, NativeMemory.MemoryAccessMode.PLAIN);
+ } else {
+ nextAddr = nativeMemory.getLong(curIOVecAddr, NativeMemory.MemoryAccessMode.PLAIN);
+ nextLen = nativeMemory.getLong(curIOVecAddr + lenOffset, NativeMemory.MemoryAccessMode.PLAIN);
+ }
+ ret += writeAddress(self, fdAccess, nextAddr, Math.toIntExact(nextLen));
+ curIOVecAddr += sizeOfIOVec;
+ }
+ return ret;
+ }
+
+ @TruffleBoundary
+ private static ByteBuffer[] getByteBuffersFromIOVec(long address, int len, NativeMemory nativeMemory) {
+ // constants
+ int lenOffset = ADDRESS_SIZE;
+ int sizeOfIOVec = (short) (ADDRESS_SIZE * 2);
+ long curIOVecAddr = address;
+ long nextAddr;
+ long nextLen;
+ ByteBuffer[] buffs = new ByteBuffer[len];
+ for (int i = 0; i < len; i++) {
+ if (ADDRESS_SIZE == 4) {
+ nextAddr = nativeMemory.getInt(curIOVecAddr, NativeMemory.MemoryAccessMode.PLAIN);
+ nextLen = nativeMemory.getInt(curIOVecAddr + lenOffset, NativeMemory.MemoryAccessMode.PLAIN);
+ } else {
+ nextAddr = nativeMemory.getLong(curIOVecAddr, NativeMemory.MemoryAccessMode.PLAIN);
+ nextLen = nativeMemory.getLong(curIOVecAddr + lenOffset, NativeMemory.MemoryAccessMode.PLAIN);
+ }
+ buffs[i] = nativeMemory.getDirectBuffer(nextAddr, nextLen);
+ curIOVecAddr += sizeOfIOVec;
+ }
+ return buffs;
+ }
+
+ private long sequentialReadv(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess, long address, int length) {
+ // constants
+ int lenOffset = ADDRESS_SIZE;
+ int sizeOfIOVec = (short) (ADDRESS_SIZE * 2);
+ long curIOVecAddr = address;
+ long nextAddr;
+ long nextLen;
+ long ret = 0;
+ NativeMemory nativeMemory = context.getNativeAccess().nativeMemory();
+ for (int i = 0; i < length; i++) {
+ if (ADDRESS_SIZE == 4) {
+ nextAddr = nativeMemory.getInt(curIOVecAddr, NativeMemory.MemoryAccessMode.PLAIN);
+ nextLen = nativeMemory.getInt(curIOVecAddr + lenOffset, NativeMemory.MemoryAccessMode.PLAIN);
+ } else {
+ nextAddr = nativeMemory.getLong(curIOVecAddr, NativeMemory.MemoryAccessMode.PLAIN);
+ nextLen = nativeMemory.getLong(curIOVecAddr + lenOffset, NativeMemory.MemoryAccessMode.PLAIN);
+ }
+ ret += readAddress(self, fdAccess, nextAddr, Math.toIntExact(nextLen));
+ curIOVecAddr += sizeOfIOVec;
+ }
+ return ret;
+ }
+
+ private ReadableByteChannel getReadableChannel(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess) {
+ return getReadableChannel(getFD(getFileDesc(self, fdAccess)));
+ }
+
+ private ReadableByteChannel getReadableChannel(int fd) {
+ Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
+ if (channel instanceof ReadableByteChannel readableByteChannel) {
+ return readableByteChannel;
+ }
+ throw Throw.throwNonReadable(context);
+ }
+
+ private SocketChannel getSocketChannel(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess) {
+ return getSocketChannel(getFD(getFileDesc(self, fdAccess)));
+ }
+
+ private SocketChannel getSocketChannel(int fd) {
+ Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
+ if (channel instanceof SocketChannel socketChannel) {
+ return socketChannel;
+ }
+ // SocketChannels are backed by the host, thus it would be very suspicious if we reach here.
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+
+ private NetworkChannel getNetworkChannel(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess) {
+ return getNetworkChannel(getFD(getFileDesc(self, fdAccess)));
+ }
+
+ private NetworkChannel getNetworkChannel(int fd) {
+ Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
+ if (channel instanceof NetworkChannel networkChannel) {
+ return networkChannel;
+ }
+ // NetworkChannel are backed by the host, thus it would be very suspicious if we reach here.
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+
+ private WritableByteChannel getWritableChannel(@JavaType(Object.class) StaticObject self,
+ FDAccess fdAccess) {
+ return getWritableChannel(getFD(getFileDesc(self, fdAccess)));
+ }
+
+ private WritableByteChannel getWritableChannel(int fd) {
+ Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
+ if (channel instanceof WritableByteChannel writableByteChannel) {
+ return writableByteChannel;
+ }
+ throw Throw.throwNonWritable(context);
+ }
+
private static int writeBytesImpl(WritableByteChannel writableChannel, byte[] b, int off, int len,
EspressoContext context) {
try {
@@ -762,6 +1493,14 @@ private static long sizeImpl(SeekableByteChannel seekableChannel, EspressoContex
}
}
+ private SeekableByteChannel getSeekableChannel(int fd) {
+ Channel channel = Checks.ensureOpen(getChannel(fd), getContext());
+ if (channel instanceof SeekableByteChannel seekableChannel) {
+ return seekableChannel;
+ }
+ throw Throw.throwNonSeekable(context);
+ }
+
private static int lookupSyncedValue(ObjectKlass klass, Symbol constant) {
Field f = klass.lookupDeclaredField(constant, Types._int);
EspressoError.guarantee(f != null, "Failed to sync " + klass.getExternalName() + " constants");
@@ -806,5 +1545,47 @@ public FileSystem_Sync(TruffleIO io) {
this.ACCESS_EXECUTE = lookupSyncedValue(io.java_io_FileSystem, Names.ACCESS_EXECUTE);
}
}
+
+ public static final class FileAttributeParser_Sync {
+ public final int OWNER_READ_VALUE;
+ public final int OWNER_WRITE_VALUE;
+ public final int OWNER_EXECUTE_VALUE;
+ public final int GROUP_READ_VALUE;
+ public final int GROUP_WRITE_VALUE;
+ public final int GROUP_EXECUTE_VALUE;
+ public final int OTHERS_READ_VALUE;
+ public final int OTHERS_WRITE_VALUE;
+ public final int OTHERS_EXECUTE_VALUE;
+
+ public FileAttributeParser_Sync(TruffleIO io) {
+ this.OWNER_READ_VALUE = lookupSyncedValue(io.sun_nio_fs_FileAttributeParser, Names.OWNER_READ_VALUE);
+ this.OWNER_WRITE_VALUE = lookupSyncedValue(io.sun_nio_fs_FileAttributeParser, Names.OWNER_WRITE_VALUE);
+ this.OWNER_EXECUTE_VALUE = lookupSyncedValue(io.sun_nio_fs_FileAttributeParser, Names.OWNER_EXECUTE_VALUE);
+ this.GROUP_READ_VALUE = lookupSyncedValue(io.sun_nio_fs_FileAttributeParser, Names.GROUP_READ_VALUE);
+ this.GROUP_WRITE_VALUE = lookupSyncedValue(io.sun_nio_fs_FileAttributeParser, Names.GROUP_WRITE_VALUE);
+ this.GROUP_EXECUTE_VALUE = lookupSyncedValue(io.sun_nio_fs_FileAttributeParser, Names.GROUP_EXECUTE_VALUE);
+ this.OTHERS_READ_VALUE = lookupSyncedValue(io.sun_nio_fs_FileAttributeParser, Names.OTHERS_READ_VALUE);
+ this.OTHERS_WRITE_VALUE = lookupSyncedValue(io.sun_nio_fs_FileAttributeParser, Names.OTHERS_WRITE_VALUE);
+ this.OTHERS_EXECUTE_VALUE = lookupSyncedValue(io.sun_nio_fs_FileAttributeParser, Names.OTHERS_EXECUTE_VALUE);
+ }
+ }
+
+ public static final class IOStatus_Sync {
+ public final int EOF;
+ public final int UNAVAILABLE;
+ public final int INTERRUPTED;
+ public final int UNSUPPORTED;
+ public final int THROWN;
+ public final int UNSUPPORTED_CASE;
+
+ public IOStatus_Sync(TruffleIO io) {
+ this.EOF = lookupSyncedValue(io.sun_nio_ch_IOStatus, Names.EOF);
+ this.UNAVAILABLE = lookupSyncedValue(io.sun_nio_ch_IOStatus, Names.UNAVAILABLE);
+ this.INTERRUPTED = lookupSyncedValue(io.sun_nio_ch_IOStatus, Names.INTERRUPTED);
+ this.UNSUPPORTED = lookupSyncedValue(io.sun_nio_ch_IOStatus, Names.UNSUPPORTED);
+ this.THROWN = lookupSyncedValue(io.sun_nio_ch_IOStatus, Names.THROWN);
+ this.UNSUPPORTED_CASE = lookupSyncedValue(io.sun_nio_ch_IOStatus, Names.UNSUPPORTED_CASE);
+ }
+ }
// Checkstyle: resume field name check
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/InformationLeak.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/InformationLeak.java
new file mode 100644
index 000000000000..148bc3a34f9f
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/InformationLeak.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs;
+
+import java.io.IOException;
+import java.net.BindException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.StandardSocketOptions;
+import java.nio.channels.ServerSocketChannel;
+import java.util.Optional;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.io.Throw;
+import com.oracle.truffle.espresso.meta.EspressoError;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.vm.Management;
+
+/**
+ * In the context of the EspressoLibs project, this class is designed to aggregate methods and
+ * fields that potentially leak information about the host system. Depending on the context, leaking
+ * such information might not be preferable due to security or privacy concerns.
+ */
+public class InformationLeak {
+ private final EspressoContext context;
+
+ public InformationLeak(EspressoContext ctx) {
+ this.context = ctx;
+ }
+
+ public long getPid() {
+ return ProcessHandle.current().pid();
+ }
+
+ @TruffleBoundary
+ public ProcessHandle.Info getProcessHandleInfo(long pid) {
+ Optional processHandle = ProcessHandle.of(pid);
+ return processHandle.map(ProcessHandle::info).orElse(null);
+ }
+
+ public void checkNetworkEnabled() {
+ if (!context.getLanguage().enableNetworking()) {
+ throw Throw.throwIllegalStateException("You are accessing deep LibNet classes even though networking is disabled", context);
+ }
+ }
+
+ public boolean isIPv6Available0() {
+ this.checkNetworkEnabled();
+ try (Socket s = new Socket()) {
+ s.bind(new InetSocketAddress(Inet6Address.getByName("::"), 0));
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ public boolean isIPv4Available() {
+ this.checkNetworkEnabled();
+ try (Socket s = new Socket()) {
+ s.bind(new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0));
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ @TruffleBoundary
+ public boolean isReusePortAvailable0() {
+ this.checkNetworkEnabled();
+ try (ServerSocketChannel channel = ServerSocketChannel.open()) {
+ return channel.supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ public boolean istty() {
+ return context.getEnv().in() == System.in && context.getEnv().out() == System.out;
+ }
+
+ @TruffleBoundary
+ public int isExclusvieBindAvailable() {
+ try (ServerSocket socket1 = new ServerSocket()) {
+ socket1.setReuseAddress(false);
+ socket1.bind(new InetSocketAddress(8080));
+
+ try (ServerSocket socket2 = new ServerSocket()) {
+ socket2.setReuseAddress(false);
+ socket2.bind(new InetSocketAddress(8080)); // Should fail if exclusive bind works
+ return -1;
+ } catch (BindException e) {
+ return 1;
+ }
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ public byte[] getMacAddress(NetworkInterface netIF) {
+ try {
+ return netIF.getHardwareAddress();
+ } catch (SocketException e) {
+ throw Throw.throwSocketException(e, context);
+ }
+ }
+
+ @TruffleBoundary
+ public Management checkAndGetManagement(EspressoContext context) {
+ if (!context.getEspressoEnv().EnableManagement) {
+ throw Throw.throwIllegalStateException("You are accessing LibManagement classes even though management is disabled", context);
+ }
+ Management management = context.getVM().getManagement();
+ if (management == null) {
+ // management is only null if Management is disabled
+ throw EspressoError.shouldNotReachHere();
+ }
+ return management;
+ }
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/JNU.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/JNU.java
new file mode 100644
index 000000000000..6c9734502903
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/JNU.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs;
+
+import java.nio.charset.Charset;
+
+public class JNU {
+ private final String strEncoding = java.lang.System.getProperty("sun.jnu.encoding");
+ private final Charset charSet = Charset.forName(strEncoding);
+
+ public Charset getCharSet() {
+ return charSet;
+ }
+
+ public String getString(byte[] arr, int index, int length) {
+ return new String(arr, index, length, charSet);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/Lib.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/Lib.java
index 3bf795c88322..6303d1d89be6 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/Lib.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/Lib.java
@@ -28,6 +28,7 @@
import java.util.TreeMap;
import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.espresso.EspressoLanguage;
import com.oracle.truffle.espresso.classfile.descriptors.Name;
import com.oracle.truffle.espresso.classfile.descriptors.Signature;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
@@ -57,23 +58,38 @@ public interface Factory {
String name();
Lib create(EspressoContext ctx);
+
+ default boolean isValidfor(EspressoLanguage language) {
+ return true;
+ }
}
private final String name;
public Lib(EspressoContext context, List collector, String name) {
+ this(context, collector, name, true);
+ }
+
+ public Lib(EspressoContext context, List collector, String name, boolean mangle) {
this.name = name;
for (JavaSubstitution.Factory factory : collector) {
if (factory.isValidFor(context.getLanguage())) {
List refs = getRefs(context, factory);
for (MethodKey ref : refs) {
- String key = Mangle.mangleMethod(
- ref.getHolderType(),
- ref.getName().toString(),
- factory.needsSignatureMangle()
- ? ref.getSignature()
- : null,
- false);
+ String key;
+
+ if (mangle) {
+ key = Mangle.mangleMethod(
+ ref.getHolderType(),
+ ref.getName().toString(),
+ factory.needsSignatureMangle()
+ ? ref.getSignature()
+ : null,
+ false);
+ } else {
+ key = ref.getName().toString();
+ }
+
assert !bindings.containsKey(key);
context.getLogger().finer(() -> "Registering " + name() + " library entry: " + key);
bindings.put(key, factory);
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/Libs.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/Libs.java
index a42e51efb6cf..bfaf8819ef2a 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/Libs.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/Libs.java
@@ -24,6 +24,7 @@
import org.graalvm.collections.EconomicMap;
+import com.oracle.truffle.espresso.EspressoLanguage;
import com.oracle.truffle.espresso.runtime.EspressoContext;
/**
@@ -40,9 +41,11 @@ public final class Libs {
private final EconomicMap knownLibs = EconomicMap.create();
- public Libs() {
+ public Libs(EspressoLanguage lang) {
for (Lib.Factory lib : LibsCollector.getInstances(Lib.Factory.class)) {
- knownLibs.put(lib.name(), lib);
+ if (lib.isValidfor(lang)) {
+ knownLibs.put(lib.name(), lib);
+ }
}
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/LibsMeta.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/LibsMeta.java
new file mode 100644
index 000000000000..910dd25a2eb1
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/LibsMeta.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.truffle.espresso.libs;
+
+import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.ALL;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
+import com.oracle.truffle.espresso.classfile.descriptors.Type;
+import com.oracle.truffle.espresso.descriptors.EspressoSymbols;
+import com.oracle.truffle.espresso.impl.ContextAccess;
+import com.oracle.truffle.espresso.impl.Field;
+import com.oracle.truffle.espresso.impl.Method;
+import com.oracle.truffle.espresso.impl.ObjectKlass;
+import com.oracle.truffle.espresso.meta.DiffVersionLoadHelper;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+
+public final class LibsMeta implements ContextAccess {
+ private final EspressoContext context;
+ private final Meta meta;
+
+ // Checkstyle: stop field name check
+ // libnio
+ public final ObjectKlass sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream;
+ public final Field sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream_HIDDEN_HOST_REFERENCE;
+ public final Method sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream_init;
+ public final ObjectKlass sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator;
+ public final Field sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator_HIDDEN_HOST_REFERENCE;
+ public final Method sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator_init;
+ // libzip
+ public final ObjectKlass java_util_zip_CRC32;
+ public final Field HIDDEN_CRC32;
+ public final ObjectKlass java_util_zip_Inflater;
+ public final Field java_util_zip_Inflater_inputConsumed;
+ public final Field java_util_zip_Inflater_outputConsumed;
+ public final ObjectKlass java_util_zip_DataFormatException;
+
+ // libjava
+ public final ObjectKlass java_lang_ProcessHandleImpl$Info;
+ public final Field java_lang_ProcessHandleImpl$Info_command;
+ public final Field java_lang_ProcessHandleImpl$Info_commandLine;
+ public final Field java_lang_ProcessHandleImpl$Info_arguments;
+ public final Field java_lang_ProcessHandleImpl$Info_startTime;
+ public final Field java_lang_ProcessHandleImpl$Info_totalTime;
+ public final Field java_lang_ProcessHandleImpl$Info_user;
+ public final ObjectKlass java_lang_SecurityManager;
+ public final Field java_lang_SecurityManager_initialized;
+
+ // libnet
+ public final ObjectKlass java_net_NetworkInterface;
+ public final LibNetMeta net;
+
+ // libextnet
+ @CompilerDirectives.CompilationFinal public ObjectKlass jdk_net_ExtendedSocketOptions$PlatformSocketOptions;
+ @CompilerDirectives.CompilationFinal public Method jdk_net_ExtendedSocketOptions$PlatformSocketOptions_init;
+
+ // libmanagement
+ public final LibManagementMeta management;
+ // Checkstyle: resume field name check
+
+ @Override
+ public EspressoContext getContext() {
+ return context;
+ }
+
+ public Meta getMeta() {
+ return meta;
+ }
+
+ public LibsMeta(EspressoContext ctx) {
+ this.context = ctx;
+ this.meta = context.getMeta();
+
+ // libnio
+ sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream = knownKlass(EspressoSymbols.Types.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream);
+ sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream_init = sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream.lookupDeclaredMethod(EspressoSymbols.Names._init_,
+ EspressoSymbols.Signatures._void);
+ sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator = knownKlass(EspressoSymbols.Types.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator);
+ sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator_init = sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator.lookupDeclaredMethod(EspressoSymbols.Names._init_,
+ EspressoSymbols.Signatures._void);
+ sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream_HIDDEN_HOST_REFERENCE = sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream.requireHiddenField(
+ EspressoSymbols.Names.HIDDEN_HOST_REFERENCE);
+ sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator_HIDDEN_HOST_REFERENCE = sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator.requireHiddenField(
+ EspressoSymbols.Names.HIDDEN_HOST_REFERENCE);
+ // libzip
+ java_util_zip_CRC32 = knownKlass(EspressoSymbols.Types.java_util_zip_CRC32);
+ HIDDEN_CRC32 = diff().field(ALL, EspressoSymbols.Names.HIDDEN_CRC32, EspressoSymbols.Types._int).maybeHiddenfield(java_util_zip_CRC32);
+ java_util_zip_Inflater = knownKlass(EspressoSymbols.Types.java_util_zip_Inflater);
+ java_util_zip_DataFormatException = knownKlass(EspressoSymbols.Types.java_util_zip_DataFormatException);
+ java_util_zip_Inflater_inputConsumed = java_util_zip_Inflater.requireDeclaredField(EspressoSymbols.Names.inputConsumed, EspressoSymbols.Types._int);
+ java_util_zip_Inflater_outputConsumed = java_util_zip_Inflater.requireDeclaredField(EspressoSymbols.Names.outputConsumed, EspressoSymbols.Types._int);
+
+ // libjava
+ java_lang_ProcessHandleImpl$Info = knownKlass(EspressoSymbols.Types.java_lang_ProcessHandleImpl$Info);
+ java_lang_ProcessHandleImpl$Info_command = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.command, EspressoSymbols.Types.java_lang_String);
+ java_lang_ProcessHandleImpl$Info_commandLine = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.commandLine, EspressoSymbols.Types.java_lang_String);
+ java_lang_ProcessHandleImpl$Info_arguments = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.arguments, EspressoSymbols.Types.java_lang_String_array);
+ java_lang_ProcessHandleImpl$Info_startTime = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.startTime, EspressoSymbols.Types._long);
+ java_lang_ProcessHandleImpl$Info_totalTime = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.totalTime, EspressoSymbols.Types._long);
+ java_lang_ProcessHandleImpl$Info_user = java_lang_ProcessHandleImpl$Info.requireDeclaredField(EspressoSymbols.Names.user, EspressoSymbols.Types.java_lang_String);
+ java_lang_SecurityManager = knownKlass(EspressoSymbols.Types.java_lang_SecurityManager);
+ if (context.getJavaVersion().java25OrLater()) {
+ java_lang_SecurityManager_initialized = null;
+ } else {
+ java_lang_SecurityManager_initialized = java_lang_SecurityManager.requireDeclaredField(EspressoSymbols.Names.initialized, EspressoSymbols.Types._boolean);
+ }
+
+ // libnet
+ java_net_NetworkInterface = knownKlass(EspressoSymbols.Types.java_net_NetworkInterface);
+ this.net = context.getLanguage().enableNetworking() ? new LibNetMeta() : null;
+
+ // libmanagement
+ this.management = context.getEspressoEnv().EnableManagement ? new LibManagementMeta() : null;
+ }
+
+ /**
+ * same idea as {@link Meta#postSystemInit()}.
+ */
+ public void postSystemInit() {
+ // libextnet
+ jdk_net_ExtendedSocketOptions$PlatformSocketOptions = knownKlass(EspressoSymbols.Types.jdk_net_ExtendedSocketOptions$PlatformSocketOptions);
+ jdk_net_ExtendedSocketOptions$PlatformSocketOptions_init = jdk_net_ExtendedSocketOptions$PlatformSocketOptions.lookupDeclaredMethod(EspressoSymbols.Names._init_,
+ EspressoSymbols.Signatures._void);
+ if (management != null) {
+ management.postSystemInit();
+ }
+ }
+
+ public ObjectKlass knownKlass(Symbol type) {
+ return meta.knownKlass(type);
+ }
+
+ private DiffVersionLoadHelper diff() {
+ return new DiffVersionLoadHelper(meta);
+ }
+
+ public final class LibNetMeta {
+ // Checkstyle: stop field name check
+ public final ObjectKlass java_net_InetAddress;
+ public final Field java_net_InetAddress_holder;
+ public final ObjectKlass java_net_InetAddress$InetAddressHolder;
+ public final Field java_net_InetAddress$InetAddressHolder_address;
+
+ public final ObjectKlass java_net_InterfaceAddress;
+ public final Method java_net_InterfaceAddress_init;
+ public final Field java_net_InterfaceAddress_address;
+ public final Field java_net_InterfaceAddress_broadcast;
+ public final Field java_net_InterfaceAddress_maskLength;
+
+ public final ObjectKlass java_net_Inet4Address;
+ public final Method java_net_Inet4Address_init;
+
+ public final ObjectKlass java_net_Inet6Address;
+ public final Method java_net_Inet6Address_init;
+ public final Field java_net_Inet6Address_holder6;
+
+ public final ObjectKlass java_net_Inet6Address$Inet6AddressHolder;
+ public final Field java_net_Inet6Address$Inet6AddressHolder_scope_ifname;
+ public final Field java_net_Inet6Address$Inet6AddressHolder_ipaddress;
+
+ public final Method java_net_NetworkInterface_init;
+ public final Field java_net_NetworkInterface_displayName;
+ public final Field java_net_NetworkInterface_virtual;
+ public final Field java_net_NetworkInterface_bindings;
+ public final Field java_net_NetworkInterface_parent;
+ public final Field java_net_NetworkInterface_childs;
+
+ public final ObjectKlass java_net_InetSocketAddress;
+ public final Method java_net_InetSocketAddress_init;
+
+ // Checkstyle: resume field name check
+
+ private LibNetMeta() {
+ java_net_InetAddress = knownKlass(EspressoSymbols.Types.java_net_InetAddress);
+ java_net_InetAddress_holder = java_net_InetAddress.requireDeclaredField(EspressoSymbols.Names.holder, EspressoSymbols.Types.java_net_InetAddress$InetAddressHolder);
+ java_net_InetAddress$InetAddressHolder = knownKlass(EspressoSymbols.Types.java_net_InetAddress$InetAddressHolder);
+ java_net_InetAddress$InetAddressHolder_address = java_net_InetAddress$InetAddressHolder.requireDeclaredField(EspressoSymbols.Names.address, EspressoSymbols.Types._int);
+
+ java_net_Inet4Address = knownKlass(EspressoSymbols.Types.java_net_Inet4Address);
+ java_net_Inet4Address_init = java_net_Inet4Address.lookupDeclaredMethod(EspressoSymbols.Names._init_, EspressoSymbols.Signatures.java_net_Inet4Address_init_signature);
+
+ java_net_Inet6Address = knownKlass(EspressoSymbols.Types.java_net_Inet6Address);
+ java_net_Inet6Address_init = java_net_Inet6Address.lookupDeclaredMethod(EspressoSymbols.Names._init_, EspressoSymbols.Signatures.java_net_Inet6Address_init_signature);
+ java_net_Inet6Address_holder6 = java_net_Inet6Address.requireDeclaredField(EspressoSymbols.Names.holder6, EspressoSymbols.Types.java_net_Inet6Address$Inet6AddressHolder);
+ java_net_Inet6Address$Inet6AddressHolder = knownKlass(EspressoSymbols.Types.java_net_Inet6Address$Inet6AddressHolder);
+ java_net_Inet6Address$Inet6AddressHolder_scope_ifname = java_net_Inet6Address$Inet6AddressHolder.requireDeclaredField(EspressoSymbols.Names.scope_ifname,
+ EspressoSymbols.Types.java_net_NetworkInterface);
+ java_net_Inet6Address$Inet6AddressHolder_ipaddress = java_net_Inet6Address$Inet6AddressHolder.requireDeclaredField(EspressoSymbols.Names.ipaddress, EspressoSymbols.Types._byte_array);
+
+ java_net_InterfaceAddress = knownKlass(EspressoSymbols.Types.java_net_InterfaceAddress);
+ java_net_InterfaceAddress_init = java_net_InterfaceAddress.lookupDeclaredMethod(EspressoSymbols.Names._init_, EspressoSymbols.Signatures._void);
+ java_net_InterfaceAddress_address = java_net_InterfaceAddress.requireDeclaredField(EspressoSymbols.Names.address, EspressoSymbols.Types.java_net_InetAddress);
+ java_net_InterfaceAddress_broadcast = java_net_InterfaceAddress.requireDeclaredField(EspressoSymbols.Names.broadcast, EspressoSymbols.Types.java_net_Inet4Address);
+ java_net_InterfaceAddress_maskLength = java_net_InterfaceAddress.requireDeclaredField(EspressoSymbols.Names.maskLength, EspressoSymbols.Types._short);
+
+ java_net_NetworkInterface_init = java_net_NetworkInterface.lookupDeclaredMethod(EspressoSymbols.Names._init_, EspressoSymbols.Signatures.java_net_NetworkInterface_init_signature);
+ java_net_NetworkInterface_displayName = java_net_NetworkInterface.requireDeclaredField(EspressoSymbols.Names.displayName, EspressoSymbols.Types.java_lang_String);
+ java_net_NetworkInterface_virtual = java_net_NetworkInterface.requireDeclaredField(EspressoSymbols.Names.virtual, EspressoSymbols.Types._boolean);
+ java_net_NetworkInterface_bindings = java_net_NetworkInterface.requireDeclaredField(EspressoSymbols.Names.bindings, EspressoSymbols.Types.java_net_InterfaceAddress_array);
+ java_net_NetworkInterface_parent = java_net_NetworkInterface.requireDeclaredField(EspressoSymbols.Names.parent, EspressoSymbols.Types.java_net_NetworkInterface);
+ java_net_NetworkInterface_childs = java_net_NetworkInterface.requireDeclaredField(EspressoSymbols.Names.childs, EspressoSymbols.Types.java_net_NetworkInterface_array);
+
+ java_net_InetSocketAddress = knownKlass(EspressoSymbols.Types.java_net_InetSocketAddress);
+ java_net_InetSocketAddress_init = java_net_InetSocketAddress.lookupDeclaredMethod(EspressoSymbols.Names._init_, EspressoSymbols.Signatures.java_net_InetSocketAddress_init_signature);
+ }
+
+ }
+
+ public final class LibManagementMeta {
+ // Checkstyle: stop field name check
+ @CompilerDirectives.CompilationFinal public ObjectKlass sun_management_VMManagementImpl;
+ @CompilerDirectives.CompilationFinal public Field sun_management_VMManagementImpl_compTimeMonitoringSupport;
+ @CompilerDirectives.CompilationFinal public Field sun_management_VMManagementImpl_threadContentionMonitoringSupport;
+ @CompilerDirectives.CompilationFinal public Field sun_management_VMManagementImpl_currentThreadCpuTimeSupport;
+ @CompilerDirectives.CompilationFinal public Field sun_management_VMManagementImpl_otherThreadCpuTimeSupport;
+ @CompilerDirectives.CompilationFinal public Field sun_management_VMManagementImpl_threadAllocatedMemorySupport;
+ @CompilerDirectives.CompilationFinal public Field sun_management_VMManagementImpl_remoteDiagnosticCommandsSupport;
+ @CompilerDirectives.CompilationFinal public Field sun_management_VMManagementImpl_objectMonitorUsageSupport;
+ @CompilerDirectives.CompilationFinal public Field sun_management_VMManagementImpl_synchronizerUsageSupport;
+ // Checkstyle: resume field name check
+
+ public void postSystemInit() {
+ sun_management_VMManagementImpl = knownKlass(EspressoSymbols.Types.sun_management_VMManagementImpl);
+ sun_management_VMManagementImpl_compTimeMonitoringSupport = sun_management_VMManagementImpl.requireDeclaredField(EspressoSymbols.Names.compTimeMonitoringSupport,
+ EspressoSymbols.Types._boolean);
+ sun_management_VMManagementImpl_threadContentionMonitoringSupport = sun_management_VMManagementImpl.requireDeclaredField(EspressoSymbols.Names.threadContentionMonitoringSupport,
+ EspressoSymbols.Types._boolean);
+ sun_management_VMManagementImpl_currentThreadCpuTimeSupport = sun_management_VMManagementImpl.requireDeclaredField(EspressoSymbols.Names.currentThreadCpuTimeSupport,
+ EspressoSymbols.Types._boolean);
+ sun_management_VMManagementImpl_otherThreadCpuTimeSupport = sun_management_VMManagementImpl.requireDeclaredField(EspressoSymbols.Names.otherThreadCpuTimeSupport,
+ EspressoSymbols.Types._boolean);
+ sun_management_VMManagementImpl_threadAllocatedMemorySupport = sun_management_VMManagementImpl.requireDeclaredField(EspressoSymbols.Names.threadAllocatedMemorySupport,
+ EspressoSymbols.Types._boolean);
+ sun_management_VMManagementImpl_remoteDiagnosticCommandsSupport = sun_management_VMManagementImpl.requireDeclaredField(EspressoSymbols.Names.remoteDiagnosticCommandsSupport,
+ EspressoSymbols.Types._boolean);
+ sun_management_VMManagementImpl_objectMonitorUsageSupport = sun_management_VMManagementImpl.requireDeclaredField(EspressoSymbols.Names.objectMonitorUsageSupport,
+ EspressoSymbols.Types._boolean);
+ sun_management_VMManagementImpl_synchronizerUsageSupport = sun_management_VMManagementImpl.requireDeclaredField(EspressoSymbols.Names.synchronizerUsageSupport,
+ EspressoSymbols.Types._boolean);
+
+ }
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/LibsState.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/LibsState.java
index 98f486ec9e3f..cca1518f616a 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/LibsState.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/LibsState.java
@@ -22,17 +22,48 @@
*/
package com.oracle.truffle.espresso.libs;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.Inflater;
-import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.TruffleLogger;
+import com.oracle.truffle.espresso.EspressoLanguage;
+import com.oracle.truffle.espresso.io.Throw;
+import com.oracle.truffle.espresso.io.TruffleIO;
import com.oracle.truffle.espresso.jni.StrongHandles;
import com.oracle.truffle.espresso.meta.Meta;
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.EspressoException;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.vm.InterpreterToVM;
public class LibsState {
+ private static final TruffleLogger logger = TruffleLogger.getLogger(EspressoLanguage.ID, LibsState.class);
+
private final StrongHandles handle2Inflater = new StrongHandles<>();
+ public final LibsStateNet net;
+
+ public LibsState(EspressoContext context, LibsMeta lMeta) {
+ this.net = (context.getLanguage().enableNetworking()) ? new LibsStateNet(context, lMeta) : null;
+ }
+
+ public TruffleLogger getLogger() {
+ return logger;
+ }
+
public long handlifyInflater(Inflater i) {
return handle2Inflater.handlify(i);
}
@@ -49,10 +80,202 @@ public Inflater getInflater(long handle) {
return inflater;
}
- @CompilerDirectives.TruffleBoundary
+ @TruffleBoundary
private static EspressoException throwInternalError() {
Meta meta = EspressoContext.get(null).getMeta();
return meta.throwExceptionWithMessage(meta.java_lang_InternalError, "the provided handle doesn't correspond to an Inflater");
}
+ public final class LibsStateNet {
+ private final EspressoContext context;
+ private final LibsMeta lMeta;
+ // used for guestHandle to hostSelector
+ private final StrongHandles handle2Selector = new StrongHandles<>();
+ // mapping from guestHandle and channelFD to SelectionKey and the reversed one
+ private final ConcurrentHashMap hostSelectionKeys = new ConcurrentHashMap<>();
+ private final ConcurrentHashMap selectionKeysToFd = new ConcurrentHashMap<>();
+
+ public LibsStateNet(EspressoContext context, LibsMeta lMeta) {
+ this.context = context;
+ this.lMeta = lMeta;
+ }
+
+ public @JavaType StaticObject convertInetAddr(InetAddress inetAddr) {
+ return convertInetAddr(inetAddr, StaticObject.NULL);
+ }
+
+ public @JavaType StaticObject convertInetAddr(InetAddress inetAddr,
+ @JavaType(NetworkInterface.class) StaticObject netIF) {
+ @JavaType(InetAddress.class)
+ StaticObject guestInetAddr = null;
+ if (inetAddr instanceof Inet4Address ipv4Addr) {
+ // IPv4 address
+ guestInetAddr = convertIpv4Addr(ipv4Addr);
+ } else if (inetAddr instanceof Inet6Address ipv6Addr) {
+ // IPv6 address
+ guestInetAddr = convertIpv6Addr(ipv6Addr, netIF);
+ }
+ Objects.requireNonNull(guestInetAddr);
+ return guestInetAddr;
+ }
+
+ /**
+ * Converts a Guest InetAddress given as a StaticObject to a Host InetAddress.
+ *
+ * @param addr the Guest InetAddress
+ * @return The Host InetAddress
+ */
+ public InetAddress fromGuestInetAddress(@JavaType(InetAddress.class) StaticObject addr) {
+ InetAddress inetAddress = null;
+ try {
+ if (InterpreterToVM.instanceOf(addr, lMeta.net.java_net_Inet4Address)) {
+ // ipv4 case retrieve int address, convert to bytes and use getByAddress
+ @JavaType(internalName = "Ljava/net/InetAddress$InetAddressHolder;")
+ StaticObject ipaHolder = lMeta.net.java_net_InetAddress_holder.getObject(addr);
+ int address = lMeta.net.java_net_InetAddress$InetAddressHolder_address.getInt(ipaHolder);
+ byte[] byteAddress = new byte[]{
+ (byte) ((address >> 24) & 0xFF),
+ (byte) ((address >> 16) & 0xFF),
+ (byte) ((address >> 8) & 0xFF),
+ (byte) (address & 0xFF)
+ };
+ inetAddress = InetAddress.getByAddress(byteAddress);
+
+ } else if (InterpreterToVM.instanceOf(addr, lMeta.net.java_net_Inet6Address)) {
+ // ipv6 --> get the ip6 holder to retrieve the Ip6Address and use getByAddress
+ @JavaType(internalName = "Ljava/net/Inet6Address$Inet6AddressHolder;")
+ StaticObject ipv6Holder = lMeta.net.java_net_Inet6Address_holder6.getObject(addr);
+ @JavaType(byte[].class)
+ StaticObject ip6Addr = lMeta.net.java_net_Inet6Address$Inet6AddressHolder_ipaddress.getObject(ipv6Holder);
+ inetAddress = InetAddress.getByAddress(ip6Addr.unwrap(context.getLanguage()));
+ } else {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ return inetAddress;
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ private @JavaType StaticObject convertIpv4Addr(Inet4Address ipv4Addr) {
+ // in the original Native code the call the void constructor and set the address. To me
+ // providing full Information (Address and HostName) is the better approach.
+ @JavaType(Inet4Address.class)
+ StaticObject guestInetAddr = lMeta.net.java_net_Inet4Address.allocateInstance(context);
+ @JavaType(String.class)
+ StaticObject hostName = lMeta.getMeta().toGuestString(ipv4Addr.getHostName());
+ @JavaType(byte[].class)
+ StaticObject addr = context.getAllocator().wrapArrayAs(lMeta.getMeta()._byte_array, ipv4Addr.getAddress());
+
+ lMeta.net.java_net_Inet4Address_init.invokeDirectSpecial(
+ /* this */ guestInetAddr,
+ /* hostName */ hostName,
+ /* address */ addr);
+
+ return guestInetAddr;
+ }
+
+ private @JavaType StaticObject convertIpv6Addr(Inet6Address ipv6Addr,
+ @JavaType(NetworkInterface.class) StaticObject netIF) {
+ // in the original Native code the call the void constructor and set the address. To me
+ // providing more Information is the better approach.
+ @JavaType(Inet6Address.class)
+ StaticObject guestInetAddr = lMeta.net.java_net_Inet6Address.allocateInstance(context);
+ @JavaType(String.class)
+ StaticObject hostName = lMeta.getMeta().toGuestString(ipv6Addr.getHostName());
+ byte[] hostByteAddress = ipv6Addr.getAddress();
+ @JavaType(byte[].class)
+ StaticObject addr = context.getAllocator().wrapArrayAs(lMeta.getMeta()._byte_array, hostByteAddress);
+
+ lMeta.net.java_net_Inet6Address_init.invokeDirectSpecial(
+ /* this */ guestInetAddr,
+ /* hostName */ hostName,
+ /* address */ addr,
+ /* scopeId */ ipv6Addr.getScopeId());
+
+ // we also need to set the scope_ifName as in the native code (if applicable)
+ if (ipv6Addr.getScopeId() != 0 && netIF != StaticObject.NULL) {
+ @JavaType(internalName = "Ljava/net/Inet6Address$Inet6AddressHolder;")
+ StaticObject ipv6Holder = lMeta.net.java_net_Inet6Address_holder6.getObject(guestInetAddr);
+ lMeta.net.java_net_Inet6Address$Inet6AddressHolder_scope_ifname.setObject(ipv6Holder, netIF);
+ }
+ return guestInetAddr;
+ }
+
+ public void setFDVal(@JavaType(FileDescriptor.class) StaticObject fd, int fdVal) {
+ context.getTruffleIO().java_io_FileDescriptor_fd.setInt(fd, fdVal);
+ }
+
+ public void checkValidOps(SelectableChannel selectableChannel, int ops) {
+ if ((~selectableChannel.validOps() & ops) != 0) {
+ throw Throw.throwIOException("operations associated with SelectionKey are not valid", context);
+ }
+ }
+
+ @TruffleBoundary
+ public void putSelectionKey(int id, int fd, SelectionKey selKey) {
+ long key = ((long) id << 32) | (fd & 0xFFFFFFFFL);
+ SelectionKey previousSelKey = hostSelectionKeys.put(key, selKey);
+ Integer previousFd = selectionKeysToFd.put(selKey, fd);
+ // sanity check: SelectionKey <==> (SelectorId,ChannelFD)
+ assert previousSelKey == null || previousSelKey == selKey;
+ assert previousFd == null || previousFd == fd;
+ }
+
+ @TruffleBoundary
+ public SelectionKey getSelectionKey(int id, int fd) {
+ long key = ((long) id << 32) | (fd & 0xFFFFFFFFL);
+ return hostSelectionKeys.get(key);
+ }
+
+ @TruffleBoundary
+ public int getFdOfSelectionKey(SelectionKey key) {
+ return selectionKeysToFd.get(key);
+ }
+
+ @TruffleBoundary
+ public void removeSelectionKey(int id, int fd) {
+ long key = ((long) id << 32) | (fd & 0xFFFFFFFFL);
+ SelectionKey selKey = hostSelectionKeys.remove(key);
+ selectionKeysToFd.remove(selKey);
+ }
+
+ public long handlifySelector() {
+ try {
+ return handle2Selector.handlify(Selector.open());
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
+ }
+
+ public Selector getSelector(int selectorId) {
+ Selector selector = handle2Selector.getObject(selectorId);
+ if (selector == null) {
+ // Breaks the invariant that all ids are associated with a selector.
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ return selector;
+ }
+
+ /**
+ * If the fd is already registered with the selector it updates the interestOps and
+ * otherwise registers the fd with the selector.
+ */
+ public SelectionKey setInterestOpsOrRegister(int selectorId, int fd, int ops, TruffleIO io) {
+ Selector selector = getSelector(selectorId);
+ SelectionKey key = getSelectionKey(selectorId, fd);
+ if (key != null) {
+ checkValidOps(key.channel(), ops);
+ key.interestOps(ops);
+ } else {
+ key = io.register(fd, selector, ops);
+ putSelectionKey(selectorId, fd, key);
+ }
+ return key;
+ }
+
+ public void freeSelector(int selectorId) {
+ handle2Selector.freeHandle(selectorId);
+ }
+ }
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/SubstitutionFactoryWrapper.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/SubstitutionFactoryWrapper.java
index bf4d93e28581..e2013ca3ea51 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/SubstitutionFactoryWrapper.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/SubstitutionFactoryWrapper.java
@@ -22,7 +22,13 @@
*/
package com.oracle.truffle.espresso.libs;
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.interop.ArityException;
+import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnsupportedTypeException;
+import com.oracle.truffle.api.library.ExportLibrary;
+import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
/**
@@ -31,6 +37,7 @@
* substitutions to be used as the result of a call to
* {@link com.oracle.truffle.espresso.ffi.NativeAccess#lookupSymbol(TruffleObject, String)}.
*/
+@ExportLibrary(InteropLibrary.class)
public final class SubstitutionFactoryWrapper implements TruffleObject {
private final JavaSubstitution.Factory subst;
@@ -41,4 +48,16 @@ public final class SubstitutionFactoryWrapper implements TruffleObject {
public JavaSubstitution.Factory getSubstitution() {
return subst;
}
+
+ @ExportMessage
+ @SuppressWarnings("static-method")
+ public boolean isExecutable() {
+ return true;
+ }
+
+ @ExportMessage
+ @CompilerDirectives.TruffleBoundary
+ public Object execute(Object[] args) throws ArityException, UnsupportedTypeException {
+ return getSubstitution().create().invoke(args);
+ }
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/LibAwt.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/LibAwt.java
new file mode 100644
index 000000000000..47e4c5ef74ff
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/LibAwt.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libawt;
+
+import com.oracle.truffle.espresso.libs.Lib;
+import com.oracle.truffle.espresso.libs.Libs;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.substitutions.Collect;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+
+@Collect(Libs.class)
+public final class LibAwt implements Lib.Factory {
+ @Override
+ public String name() {
+ return "awt";
+ }
+
+ @Override
+ public Lib create(EspressoContext ctx) {
+ // return new Lib(ctx, List.of(), name());
+ return new Lib(ctx, LibAwtCollector.getInstances(JavaSubstitution.Factory.class),
+ name());
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_Rectangle.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_Rectangle.java
new file mode 100644
index 000000000000..20face14978c
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_Rectangle.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libawt.impl;
+
+public class Target_java_awt_Rectangle {
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_Toolkit.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_Toolkit.java
new file mode 100644
index 000000000000..f7b8571ff26b
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_Toolkit.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libawt.impl;
+
+import com.oracle.truffle.espresso.libs.libawt.LibAwt;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Ljava/awt/Toolkit;", group = LibAwt.class)
+public final class Target_java_awt_Toolkit {
+ @Substitution
+ public static void initIDs() {
+ // nop
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_image_ColorModel.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_image_ColorModel.java
new file mode 100644
index 000000000000..1230d4620530
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_image_ColorModel.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libawt.impl;
+
+import com.oracle.truffle.espresso.libs.libawt.LibAwt;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Ljava/awt/image/ColorModel;", group = LibAwt.class)
+public final class Target_java_awt_image_ColorModel {
+ @Substitution
+ public static void initIDs() {
+ // nop
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_image_Raster.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_image_Raster.java
new file mode 100644
index 000000000000..76ca0b58615f
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_image_Raster.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libawt.impl;
+
+import com.oracle.truffle.espresso.libs.libawt.LibAwt;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Ljava/awt/image/Raster;", group = LibAwt.class)
+public final class Target_java_awt_image_Raster {
+ @Substitution
+ public static void initIDs() {
+ // nop
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_image_SampleModel.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_image_SampleModel.java
new file mode 100644
index 000000000000..e8dce3c92c9c
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libawt/impl/Target_java_awt_image_SampleModel.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libawt.impl;
+
+import com.oracle.truffle.espresso.libs.libawt.LibAwt;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Ljava/awt/image/SampleModel;", group = LibAwt.class)
+public final class Target_java_awt_image_SampleModel {
+ @Substitution
+ public static void initIDs() {
+ // nop
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_Console.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_Console.java
new file mode 100644
index 000000000000..4659f02a976e
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_Console.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import java.io.Console;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.libs.InformationLeak;
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(value = Console.class, group = LibJava.class)
+public final class Target_java_io_Console {
+ @Substitution
+ @TruffleBoundary
+ public static boolean istty(@Inject InformationLeak iL) {
+ return iL.istty();
+ }
+
+ @Substitution
+ public static @JavaType(String.class) StaticObject encoding() {
+ return StaticObject.NULL;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileDescriptor.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileDescriptor.java
index 6c290fcf7f1f..35f9389cc0e4 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileDescriptor.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileDescriptor.java
@@ -37,12 +37,6 @@
@EspressoSubstitutions(value = FileDescriptor.class, group = LibJava.class)
public final class Target_java_io_FileDescriptor {
- private static final FDAccess FD = new FDAccess() {
- @Override
- public @JavaType(FileDescriptor.class) StaticObject get(@JavaType(Object.class) StaticObject objectWithFD, TruffleIO io) {
- return objectWithFD;
- }
- };
@Substitution
public static void initIDs() {
@@ -65,6 +59,6 @@ public static boolean getAppend(@SuppressWarnings("unused") int fd) {
@Throws(IOException.class)
public static void close0(@JavaType(FileDescriptor.class) StaticObject self,
@Inject TruffleIO io) {
- io.close(self, FD);
+ io.close(self, FDAccess.forFileDescriptor());
}
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileInputStream.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileInputStream.java
index 3f01fca03aa8..1e5e0b8f9a33 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileInputStream.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileInputStream.java
@@ -43,12 +43,6 @@
@EspressoSubstitutions(value = FileInputStream.class, group = LibJava.class)
public final class Target_java_io_FileInputStream {
- private static final FDAccess FD = new FDAccess() {
- @Override
- public @JavaType(FileInputStream.class) StaticObject get(@JavaType(Object.class) StaticObject objectWithFD, TruffleIO io) {
- return io.java_io_FileInputStream_fd.getObject(objectWithFD);
- }
- };
private static final EnumSet READ_ONLY_OPTION_SET = EnumSet.of(StandardOpenOption.READ);
@@ -63,14 +57,14 @@ public static void open0(@JavaType(FileInputStream.class) StaticObject self,
@JavaType(String.class) StaticObject name,
@Inject Meta meta, @Inject TruffleIO io) {
Checks.nullCheck(name, meta);
- io.open(self, FD, meta.toHostString(name), READ_ONLY_OPTION_SET);
+ io.open(self, FDAccess.forFileInputStream(), meta.toHostString(name), READ_ONLY_OPTION_SET);
}
@Substitution(hasReceiver = true)
@Throws(IOException.class)
public static int read0(@JavaType(FileInputStream.class) StaticObject self,
@Inject TruffleIO io) {
- return io.readSingle(self, FD);
+ return io.readSingle(self, FDAccess.forFileInputStream());
}
@Substitution(hasReceiver = true)
@@ -78,19 +72,19 @@ public static int read0(@JavaType(FileInputStream.class) StaticObject self,
public static int readBytes(@JavaType(FileInputStream.class) StaticObject self, @JavaType(byte[].class) StaticObject b, int off, int len,
@Inject TruffleIO io) {
Checks.nullCheck(b, io);
- return io.readBytes(self, FD, b.unwrap(io.getLanguage()), off, len);
+ return io.readBytes(self, FDAccess.forFileInputStream(), b.unwrap(io.getLanguage()), off, len);
}
@Substitution(hasReceiver = true)
@Throws(IOException.class)
public static long length0(@JavaType(FileInputStream.class) StaticObject self, @Inject TruffleIO io) {
- return io.length(self, FD);
+ return io.length(self, FDAccess.forFileInputStream());
}
@Substitution(hasReceiver = true)
@Throws(IOException.class)
public static long position0(@JavaType(FileInputStream.class) StaticObject self, @Inject TruffleIO io) {
- return io.position(self, FD);
+ return io.position(self, FDAccess.forFileInputStream());
}
@Substitution(hasReceiver = true)
@@ -102,8 +96,13 @@ public static long skip0(@JavaType(FileInputStream.class) StaticObject self, lon
@Substitution(hasReceiver = true)
@Throws(IOException.class)
- @SuppressWarnings("unused")
- public static int available0(@JavaType(FileInputStream.class) StaticObject self) {
- throw JavaSubstitution.unimplemented();
+ public static int available0(@JavaType(FileInputStream.class) StaticObject self,
+ @Inject TruffleIO io) {
+ long size = io.length(self, FDAccess.forFileInputStream());
+ long pos = io.position(self, FDAccess.forFileInputStream());
+ if (size <= pos) {
+ return 0;
+ }
+ return Math.toIntExact(size - pos);
}
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileOutputStream.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileOutputStream.java
index 53bb1d0ef126..c513e6698265 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileOutputStream.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_FileOutputStream.java
@@ -22,9 +22,10 @@
*/
package com.oracle.truffle.espresso.libs.libjava.impl;
-import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.nio.file.StandardOpenOption;
+import java.util.EnumSet;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.espresso.EspressoLanguage;
@@ -32,6 +33,7 @@
import com.oracle.truffle.espresso.io.FDAccess;
import com.oracle.truffle.espresso.io.TruffleIO;
import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.meta.Meta;
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
@@ -42,18 +44,22 @@
@EspressoSubstitutions(value = FileOutputStream.class, group = LibJava.class)
public final class Target_java_io_FileOutputStream {
- private static final FDAccess FD = new FDAccess() {
- @Override
- public @JavaType(FileDescriptor.class) StaticObject get(@JavaType(Object.class) StaticObject objectWithFD, TruffleIO io) {
- return io.java_io_FileOutputStream_fd.getObject(objectWithFD);
- }
- };
@Substitution
public static void initIDs() {
// Do nothing.
}
+ @Substitution(hasReceiver = true)
+ @TruffleBoundary
+ public static void open0(@JavaType(FileOutputStream.class) StaticObject self, @JavaType(String.class) StaticObject path, boolean append, @Inject TruffleIO io, @Inject Meta meta) {
+ EnumSet options = EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE);
+ if (append) {
+ options.add(StandardOpenOption.APPEND);
+ }
+ io.open(self, FDAccess.forFileOutputStream(), meta.toHostString(path), options);
+ }
+
@Substitution(hasReceiver = true)
@Throws(IOException.class)
@TruffleBoundary
@@ -61,6 +67,6 @@ static void writeBytes(@JavaType(FileOutputStream.class) StaticObject self, @Jav
@Inject EspressoLanguage lang, @Inject TruffleIO io, @Inject EspressoContext ctx) {
Checks.nullCheck(b, ctx);
Checks.requireNonForeign(b, ctx);
- io.writeBytes(self, FD, b.unwrap(lang), off, len);
+ io.writeBytes(self, FDAccess.forFileOutputStream(), b.unwrap(lang), off, len);
}
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_RandomAccessFile.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_RandomAccessFile.java
index 48492ae96da5..257119396560 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_RandomAccessFile.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_RandomAccessFile.java
@@ -22,7 +22,6 @@
*/
package com.oracle.truffle.espresso.libs.libjava.impl;
-import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
@@ -49,13 +48,6 @@
@EspressoSubstitutions(value = RandomAccessFile.class, group = LibJava.class)
public final class Target_java_io_RandomAccessFile {
- private static final FDAccess FD = new FDAccess() {
- @Override
- public @JavaType(FileDescriptor.class) StaticObject get(@JavaType(RandomAccessFile.class) StaticObject objectWithFD, TruffleIO io) {
- Checks.nullCheck(objectWithFD, io);
- return io.java_io_RandomAccessFile_fd.getObject(objectWithFD);
- }
- };
@Substitution
public static void initIDs() {
@@ -66,7 +58,7 @@ public static void initIDs() {
@Throws(IOException.class)
static long length0(@JavaType(RandomAccessFile.class) StaticObject self,
@Inject TruffleIO io) {
- return io.length(self, FD);
+ return io.length(self, FDAccess.forRandomAccessFile());
}
@Substitution(hasReceiver = true)
@@ -76,7 +68,7 @@ public static void open0(@JavaType(RandomAccessFile.class) StaticObject self, @J
Checks.nullCheck(name, context);
String hostName = context.getMeta().toHostString(name);
Set openOptions = getOpenOptions(mode, context, io);
- io.open(self, FD, hostName, openOptions);
+ io.open(self, FDAccess.forRandomAccessFile(), hostName, openOptions);
}
@Substitution(hasReceiver = true, nameProvider = Append0.class)
@@ -85,7 +77,7 @@ static int readBytes(@JavaType(RandomAccessFile.class) StaticObject self, @JavaT
@Inject EspressoContext context, @Inject TruffleIO io) {
Checks.nullCheck(b, context);
Checks.requireNonForeign(b, context);
- return io.readBytes(self, FD, b.unwrap(context.getLanguage()), off, len);
+ return io.readBytes(self, FDAccess.forRandomAccessFile(), b.unwrap(context.getLanguage()), off, len);
}
@Substitution(hasReceiver = true)
@@ -94,7 +86,7 @@ static void seek0(@JavaType(RandomAccessFile.class) StaticObject self, long pos,
@Inject EspressoContext context, @Inject TruffleIO io) {
assert pos >= 0;
Checks.nullCheck(self, context);
- io.seek(self, FD, pos);
+ io.seek(self, FDAccess.forRandomAccessFile(), pos);
}
@TruffleBoundary
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_TruffleFileSystem.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_TruffleFileSystem.java
index 8e0d96451d50..1275308a9d39 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_TruffleFileSystem.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_io_TruffleFileSystem.java
@@ -27,11 +27,15 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Collection;
+import java.util.Set;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleFile;
import com.oracle.truffle.espresso.io.Throw;
import com.oracle.truffle.espresso.io.TruffleIO;
+import com.oracle.truffle.espresso.libs.LibsState;
import com.oracle.truffle.espresso.libs.libjava.LibJava;
import com.oracle.truffle.espresso.meta.Meta;
import com.oracle.truffle.espresso.runtime.EspressoContext;
@@ -122,12 +126,29 @@ static boolean isInvalid0(@JavaType(File.class) StaticObject f, @Inject TruffleI
}
@Substitution
+ @TruffleBoundary
@Throws(IOException.class)
static @JavaType(String.class) StaticObject canonicalize0(@JavaType(String.class) StaticObject path, @Inject TruffleIO io, @Inject EspressoContext ctx) {
+ // Work around until canonicalize of TruffleFile works for non-existent paths (GR-29215).
nullCheck(path, ctx);
Meta meta = ctx.getMeta();
+ TruffleFile tf = io.getPublicTruffleFileSafe(meta.toHostString(path));
+ return meta.toGuestString(recursiveCanonicalize(tf, ctx).getPath());
+
+ }
+
+ private static TruffleFile recursiveCanonicalize(TruffleFile tf, EspressoContext ctx) {
try {
- return meta.toGuestString(io.getPublicTruffleFileSafe(meta.toHostString(path)).getCanonicalFile().getPath());
+ if (tf.exists()) {
+ return tf.getCanonicalFile();
+ }
+ TruffleFile parent = tf.getParent();
+ if (parent != null) {
+ TruffleFile partialPath = recursiveCanonicalize(parent, ctx);
+ return partialPath.resolve(tf.getName());
+ } else {
+ throw Throw.throwIOException("Canonicalize failed for path: " + tf.getPath(), ctx);
+ }
} catch (IOException e) {
throw Throw.throwIOException(e, ctx);
} catch (SecurityException e) {
@@ -198,9 +219,58 @@ static long getLength0(@JavaType(File.class) StaticObject f,
@Substitution
@SuppressWarnings("unused")
+ @TruffleBoundary
static boolean setPermission0(@JavaType(File.class) StaticObject f, int access, boolean enable, boolean owneronly,
@Inject TruffleIO io, @Inject EspressoContext ctx) {
- throw JavaSubstitution.unimplemented();
+ String path = getPathFromFile(f, io, ctx);
+ TruffleFile tf = io.getPublicTruffleFileSafe(path);
+ try {
+ Set perms = getPosixPermissions(tf, access, enable, owneronly);
+ if (perms == null) {
+ return false;
+ }
+ tf.setPosixPermissions(perms);
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ private static Set getPosixPermissions(TruffleFile tf, int access, boolean enable, boolean owneronly) {
+ try {
+ Set perms = tf.getPosixPermissions();
+ PosixFilePermission ownerPerm = getPermissionForAccess(access, PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE);
+ PosixFilePermission groupPerm = getPermissionForAccess(access, PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_WRITE, PosixFilePermission.GROUP_EXECUTE);
+ PosixFilePermission othersPerm = getPermissionForAccess(access, PosixFilePermission.OTHERS_READ, PosixFilePermission.OTHERS_WRITE, PosixFilePermission.OTHERS_EXECUTE);
+ if (enable) {
+ perms.add(ownerPerm);
+ if (!owneronly) {
+ perms.add(groupPerm);
+ perms.add(othersPerm);
+ }
+ } else {
+ perms.remove(ownerPerm);
+ if (!owneronly) {
+ perms.remove(groupPerm);
+ perms.remove(othersPerm);
+ }
+ }
+ return perms;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ private static PosixFilePermission getPermissionForAccess(int access, PosixFilePermission read, PosixFilePermission write, PosixFilePermission execute) {
+ return switch (access) {
+ case 4 -> // FileSystem.ACCESS_READ
+ read;
+ case 2 -> // FileSystem.ACCESS_WRITE
+ write;
+ case 1 -> // FileSystem.ACCESS_EXECUTE
+ execute;
+ default -> throw new UnsupportedOperationException("Unsupported access type");
+ };
}
@Substitution
@@ -222,21 +292,51 @@ static boolean createFileExclusively0(@JavaType(String.class) StaticObject pathn
@SuppressWarnings("unused")
static boolean delete0(@JavaType(File.class) StaticObject path,
@Inject TruffleIO io, @Inject EspressoContext ctx) {
- throw JavaSubstitution.unimplemented();
+ String strPath = getPathFromFile(path, io, ctx);
+ TruffleFile tf = io.getPublicTruffleFileSafe(strPath);
+ try {
+ tf.delete();
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
}
@Substitution
@SuppressWarnings("unused")
static @JavaType(String[].class) StaticObject list0(@JavaType(File.class) StaticObject path,
@Inject TruffleIO io, @Inject EspressoContext ctx) {
- throw JavaSubstitution.unimplemented();
+ String strPath = getPathFromFile(path, io, ctx);
+ TruffleFile tf = io.getPublicTruffleFileSafe(strPath);
+ try {
+ Collection ls = tf.list();
+ StaticObject[] ret = new StaticObject[ls.size()];
+ int i = 0;
+ for (TruffleFile file : ls) {
+ String name = file.getName();
+ if (name != null) {
+ ret[i++] = ctx.getMeta().toGuestString(name);
+ }
+ }
+ return ctx.getAllocator().wrapArrayAs(ctx.getMeta().java_lang_String_array, ret);
+ } catch (IOException e) {
+ return StaticObject.NULL;
+ }
}
@Substitution
@SuppressWarnings("unused")
static boolean createDirectory0(@JavaType(File.class) StaticObject f,
- @Inject TruffleIO io, @Inject EspressoContext ctx) {
- throw JavaSubstitution.unimplemented();
+ @Inject TruffleIO io, @Inject EspressoContext ctx, @Inject LibsState libsState) {
+ String path = getPathFromFile(f, io, ctx);
+ TruffleFile tf = io.getPublicTruffleFileSafe(path);
+ try {
+ tf.createDirectory();
+ return true;
+ } catch (IOException e) {
+ libsState.getLogger().fine(() -> "In TruffleFileSystem.createDirectory0 the following exception was ignored: class = " + e.getClass().toString() + ", message = " + e.getMessage());
+ return false;
+ }
}
@Substitution
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ClassLoader.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ClassLoader.java
index 3f3d50b256f9..db0e1ef0560b 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ClassLoader.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ClassLoader.java
@@ -22,12 +22,16 @@
*/
package com.oracle.truffle.espresso.libs.libjava.impl;
+import java.nio.ByteBuffer;
import java.security.ProtectionDomain;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.espresso.EspressoLanguage;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
import com.oracle.truffle.espresso.classfile.descriptors.Type;
+import com.oracle.truffle.espresso.ffi.Pointer;
+import com.oracle.truffle.espresso.ffi.nfi.NativeUtils;
import com.oracle.truffle.espresso.libs.libjava.LibJava;
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
@@ -135,6 +139,40 @@ public static void registerNatives() {
return ctx.getVM().defineClass(type, loader, pd, buf);
}
+ @Substitution
+ @TruffleBoundary
+ public static @JavaType(Class.class) StaticObject defineClass2(@JavaType(ClassLoader.class) StaticObject loader, @JavaType(String.class) StaticObject name,
+ @JavaType(ByteBuffer.class) StaticObject data, int off, int len,
+ @JavaType(ProtectionDomain.class) StaticObject pd,
+ // TODO: source unused
+ @SuppressWarnings("unused") @JavaType(String.class) StaticObject source,
+ @Inject EspressoContext ctx) {
+ if (StaticObject.isNull(data)) {
+ throw ctx.getMeta().throwNullPointerException();
+ }
+ if (len < 0) {
+ throw ctx.getMeta().throwArrayIndexOutOfBounds(len);
+ }
+ if (off < 0) {
+ throw ctx.getMeta().throwArrayIndexOutOfBounds(off);
+ }
+ // retrieve the GuestBuffer as Array
+ @Pointer
+ TruffleObject dataAddrPointer = ctx.getJNI().GetDirectBufferAddress(data);
+ long rawDataPtr = NativeUtils.interopAsPointer(dataAddrPointer);
+ byte[] buf = new byte[len];
+ // reads the memory in the buffer
+ ctx.getNativeAccess().nativeMemory().readMemory(rawDataPtr + off, len, buf);
+
+ Symbol type = null;
+ if (StaticObject.notNull(name)) {
+ type = ctx.getVM().nameToInternal(toSlashName(ctx.getMeta().toHostString(name)));
+ }
+
+ return ctx.getVM().defineClass(type, loader, pd, buf);
+
+ }
+
private static String toSlashName(String name) {
return name.replace('.', '/');
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_PhantomReference.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_PhantomReference.java
new file mode 100644
index 000000000000..eea67a50280e
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_PhantomReference.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.Reference;
+
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.SubstitutionProfiler;
+import com.oracle.truffle.espresso.substitutions.VersionFilter;
+import com.oracle.truffle.espresso.vm.VM;
+
+@EspressoSubstitutions(value = PhantomReference.class, group = LibJava.class)
+public final class Target_java_lang_PhantomReference {
+ @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java25OrLater.class)
+ public static void clear0(@JavaType(Reference.class) StaticObject ref,
+ @Inject SubstitutionProfiler profiler, @Inject VM vm) {
+ vm.JVM_ReferenceClear(ref, profiler);
+
+ }
+
+ @Substitution(hasReceiver = true)
+ public static boolean refersTo0(@JavaType(Reference.class) StaticObject ref, @JavaType(Object.class) StaticObject object,
+ @Inject SubstitutionProfiler profiler, @Inject VM vm) {
+ return vm.JVM_PhantomReferenceRefersTo(ref, object, profiler);
+ }
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessEnvironment.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessEnvironment.java
new file mode 100644
index 000000000000..85646841b28b
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessEnvironment.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import java.nio.charset.Charset;
+import java.util.Map;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.libs.JNU;
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Ljava/lang/ProcessEnvironment;", group = LibJava.class)
+public final class Target_java_lang_ProcessEnvironment {
+ @Substitution
+ @TruffleBoundary
+ public static @JavaType(byte[][].class) StaticObject environ(@Inject EspressoContext ctx, @Inject JNU jnu) {
+ Charset charSet = jnu.getCharSet();
+ Map truffleEnvironment = ctx.getEnv().getEnvironment();
+ int size = truffleEnvironment.size();
+ StaticObject[] environ = new StaticObject[size * 2];
+
+ int i = 0;
+ for (Map.Entry entry : truffleEnvironment.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ byte[] keyBytes = key.getBytes(charSet);
+ byte[] valueBytes = value.getBytes(charSet);
+ environ[i * 2] = ctx.getAllocator().wrapArrayAs(ctx.getMeta()._byte_array, keyBytes);
+ environ[i * 2 + 1] = ctx.getAllocator().wrapArrayAs(ctx.getMeta()._byte_array, valueBytes);
+ i++;
+ }
+
+ return ctx.getAllocator().wrapArrayAs(ctx.getMeta()._byte_array.array(), environ);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessHandleImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessHandleImpl.java
new file mode 100644
index 000000000000..e61708214703
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessHandleImpl.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import java.time.Instant;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.libs.InformationLeak;
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Ljava/lang/ProcessHandleImpl;", group = LibJava.class)
+public final class Target_java_lang_ProcessHandleImpl {
+ @Substitution
+ public static void initNative() {
+ // nop
+ }
+
+ @Substitution
+ public static long getCurrentPid0(@Inject EspressoContext ctx) {
+ return ctx.getInformationLeak().getPid();
+ }
+
+ @Substitution
+ @TruffleBoundary
+ public static long isAlive0(long pid, @Inject InformationLeak iL) {
+ ProcessHandle.Info info = iL.getProcessHandleInfo(pid);
+ if (info != null) {
+ return info.startInstant().map(Instant::toEpochMilli).orElse(-1L);
+ } else {
+ return -1;
+ }
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessHandleImpl_Info.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessHandleImpl_Info.java
new file mode 100644
index 000000000000..557b8f904847
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessHandleImpl_Info.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import java.time.Duration;
+import java.time.Instant;
+
+import com.oracle.truffle.espresso.libs.InformationLeak;
+import com.oracle.truffle.espresso.libs.LibsMeta;
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Ljava/lang/ProcessHandleImpl$Info;", group = LibJava.class)
+public final class Target_java_lang_ProcessHandleImpl_Info {
+ @Substitution
+ public static void initIDs() {
+ // nop
+ }
+
+ @Substitution(hasReceiver = true)
+ public static void info0(@JavaType(internalName = "Ljava/lang/ProcessHandleImpl$Info;") StaticObject self, long pid, @Inject InformationLeak iL, @Inject LibsMeta libsMeta) {
+ ProcessHandle.Info info = iL.getProcessHandleInfo(pid);
+ if (info != null) {
+ Meta meta = libsMeta.getMeta();
+ String command = info.command().orElse("");
+ libsMeta.java_lang_ProcessHandleImpl$Info_command.setObject(self, meta.toGuestString(command));
+
+ String commandLine = info.commandLine().orElse("");
+ libsMeta.java_lang_ProcessHandleImpl$Info_commandLine.setObject(self, meta.toGuestString(commandLine));
+
+ String[] arguments = info.arguments().orElse(new String[0]);
+ StaticObject[] arr = new StaticObject[arguments.length];
+ for (int i = 0; i < arguments.length; i++) {
+ arr[i] = meta.toGuestString(arguments[i]);
+ }
+ libsMeta.java_lang_ProcessHandleImpl$Info_arguments.setObject(self, libsMeta.getContext().getAllocator().wrapArrayAs(meta.java_lang_String_array, arr));
+
+ long startTime = info.startInstant().orElse(Instant.EPOCH).toEpochMilli();
+ libsMeta.java_lang_ProcessHandleImpl$Info_startTime.setLong(self, startTime);
+
+ long totalTime = info.totalCpuDuration().orElse(Duration.ZERO).toMillis();
+ libsMeta.java_lang_ProcessHandleImpl$Info_totalTime.setLong(self, totalTime);
+
+ String user = info.user().orElse("");
+ libsMeta.java_lang_ProcessHandleImpl$Info_user.setObject(self, meta.toGuestString(user));
+ }
+ }
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessImpl.java
new file mode 100644
index 000000000000..1e8d842ea5e1
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_ProcessImpl.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.graalvm.polyglot.io.ProcessHandler;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.TruffleFile;
+import com.oracle.truffle.api.io.TruffleProcessBuilder;
+import com.oracle.truffle.espresso.EspressoLanguage;
+import com.oracle.truffle.espresso.io.Throw;
+import com.oracle.truffle.espresso.io.TruffleIO;
+import com.oracle.truffle.espresso.libs.JNU;
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.Throws;
+
+@EspressoSubstitutions(type = "Ljava/lang/ProcessImpl;", group = LibJava.class)
+public final class Target_java_lang_ProcessImpl {
+ @Substitution(hasReceiver = true)
+ @TruffleBoundary
+ @Throws(IOException.class)
+ @SuppressWarnings("unused")
+ public static int forkAndExec(int mode, @JavaType(byte[].class) StaticObject helperpath,
+ @JavaType(byte[].class) StaticObject prog,
+ @JavaType(byte[].class) StaticObject argBlock, int argc,
+ @JavaType(byte[].class) StaticObject envBlock, int envc,
+ @JavaType(byte[].class) StaticObject dir,
+ @JavaType(int[].class) StaticObject fds,
+ boolean redirectErrorStream,
+ @Inject EspressoContext ctx,
+ @Inject EspressoLanguage lang,
+ @Inject TruffleIO io,
+ @Inject JNU jnu) {
+ /*
+ * In the end the fds array should hold the FileDescriptor to channels with which the parent
+ * can access the input, output and error stream of the newly created process. In some cases
+ * the parent already provides the fds.
+ */
+
+ // unwrap everything
+ @SuppressWarnings("unused")
+ byte[] helperpathArr = helperpath.unwrap(lang);
+ byte[] progArr = prog.unwrap(lang);
+ byte[] argBlockArr = argBlock.unwrap(lang);
+ byte[] envBlockArr = envBlock.unwrap(lang);
+ byte[] dirArr = dir.unwrap(lang);
+ byte[] fdsArr = fds.unwrap(lang);
+ String[] command = new String[argc + 1];
+
+ // set the command string array
+ command[0] = jnu.getString(progArr, 0, progArr.length - 1);
+ decodeCmdarray(argBlockArr, argc, command, jnu);
+ TruffleProcessBuilder builder = ctx.getEnv().newProcessBuilder(command);
+
+ // set environment
+ Map environment = decodeEnv(envBlockArr, envc, ctx, jnu);
+ builder.environment(environment);
+
+ // set directory
+ String dirString = jnu.getString(dirArr, 0, dirArr.length - 1);
+ TruffleFile dirTF = io.getPublicTruffleFileSafe(dirString);
+ builder.directory(dirTF);
+
+ // set fds
+ if (fdsArr[0] == 0) {
+ // we trust truffle to do the correct redirection from the parent to the child
+ builder.redirectInput(ProcessHandler.Redirect.INHERIT);
+ fdsArr[0] = -1;
+ } else if (fdsArr[0] == -1) {
+ /*
+ * Here we would need to create a new stream and set it as standardInput with
+ * builder.redirectInput. This is left unimplemented for the moment since it was not
+ * used.
+ */
+ throw JavaSubstitution.unimplemented();
+
+ } else {
+ /*
+ * In this case, we need to retrieve the channel associated with the fd. Then we need to
+ * cast it somehow to an OutputStream and use createRedirectToStream. This is left
+ * unimplemented for the moment since it was not used.
+ */
+ throw JavaSubstitution.unimplemented();
+ }
+
+ if (fdsArr[1] == 1) {
+ builder.redirectOutput(ProcessHandler.Redirect.INHERIT);
+ fdsArr[1] = -1;
+ } else {
+ throw JavaSubstitution.unimplemented();
+ }
+ builder.redirectErrorStream(redirectErrorStream);
+ if (fdsArr[2] == 2) {
+ builder.redirectError(ProcessHandler.Redirect.INHERIT);
+ fdsArr[2] = -1;
+ } else {
+ throw JavaSubstitution.unimplemented();
+ }
+ Process p;
+ try {
+ p = builder.start();
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
+ return Math.toIntExact(p.pid());
+ }
+
+ @Substitution
+ public static void init() {
+ // nop
+ }
+
+ private static void decodeCmdarray(byte[] argBlock, int argc, String[] command, JNU jnu) {
+ int i = 0;
+ int argIndex = 0;
+ while (i < argBlock.length && argIndex < argc) {
+ int start = i;
+
+ while (i < argBlock.length && argBlock[i] != 0) {
+ i++;
+ }
+
+ if (start < i) {
+ String arg = jnu.getString(argBlock, start, i - start);
+ command[argIndex + 1] = arg; // +1 because args[0] is the program path
+ argIndex++;
+ }
+ i++; // skip the null-terminator
+ }
+ }
+
+ private static Map decodeEnv(byte[] envBlockArr, int envc, EspressoContext ctx, JNU jnu) {
+ Map envMap = new HashMap<>();
+ int i = 0;
+ for (int j = 0; j < envc; j++) {
+ int start = i;
+
+ while (i < envBlockArr.length && envBlockArr[i] != 0) {
+ i++;
+ }
+
+ String envStr = jnu.getString(envBlockArr, start, i - start);
+ int equalsIndex = envStr.indexOf('=');
+ if (equalsIndex != -1) {
+ String key = envStr.substring(0, equalsIndex);
+ String value = envStr.substring(equalsIndex + 1);
+ envMap.put(key, value);
+ } else {
+ throw Throw.throwIOException("The byte array encoding for the Enviornment Map Entry didnt include =", ctx);
+ }
+ i++; // skip the null-terminator
+ }
+ return envMap;
+ }
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_Reference.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_Reference.java
index 8500907ead88..fbeadfa0cd3e 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_Reference.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_Reference.java
@@ -53,4 +53,9 @@ public static boolean refersTo0(@JavaType(Reference.class) StaticObject self, @J
public static @JavaType(Reference.class) StaticObject getAndClearReferencePendingList(@Inject EspressoContext ctx) {
return ctx.getVM().JVM_GetAndClearReferencePendingList();
}
+
+ @Substitution(hasReceiver = true)
+ public static void clear0(@JavaType(Reference.class) StaticObject self, @Inject VM vm, @Inject SubstitutionProfiler profiler) {
+ vm.JVM_ReferenceClear(self, profiler);
+ }
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_SecurityManager.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_SecurityManager.java
new file mode 100644
index 000000000000..f637f17781f9
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_SecurityManager.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.io.Throw;
+import com.oracle.truffle.espresso.libs.LibsMeta;
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.VersionFilter;
+import com.oracle.truffle.espresso.vm.VM;
+
+@SuppressWarnings("deprecated")
+@EspressoSubstitutions(value = SecurityManager.class, group = LibJava.class)
+public final class Target_java_lang_SecurityManager {
+
+ @TruffleBoundary
+ @SuppressWarnings("deprecated")
+ @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java21.class)
+ public static @JavaType(Class[].class) StaticObject getClassContext(@JavaType(SecurityManager.class) StaticObject self, @Inject VM vm, @Inject LibsMeta libsMeta, @Inject EspressoContext context) {
+ if (!libsMeta.java_lang_SecurityManager_initialized.getBoolean(self)) {
+ throw Throw.throwSecurityException("security manager not initialized", context);
+ }
+ return vm.JVM_GetClassContext();
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_StackFrameInfo.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_StackFrameInfo.java
new file mode 100644
index 000000000000..4c22c5d439bd
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_StackFrameInfo.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.VersionFilter;
+import com.oracle.truffle.espresso.vm.VM;
+
+@EspressoSubstitutions(type = "Ljava/lang/StackFrameInfo;", group = LibJava.class)
+public final class Target_java_lang_StackFrameInfo {
+ @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java25OrLater.class)
+ public static void expandStackFrameInfo(@JavaType(internalName = "Ljava/lang/StackFrameInfo;") StaticObject obj, @Inject Meta meta) {
+ VM.JVM_ExpandStackFrameInfo(obj, meta);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_StackStreamFactory.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_StackStreamFactory.java
new file mode 100644
index 000000000000..3b7d53270774
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_StackStreamFactory.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023, 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.vm.StackWalk;
+
+@EspressoSubstitutions(type = "Ljava/lang/StackStreamFactory;")
+public final class Target_java_lang_StackStreamFactory {
+ @Substitution
+ public static boolean checkStackWalkModes(@Inject Meta meta) {
+ return StackWalk.synchronizedConstants(meta);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_System.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_System.java
index 39ea2333f624..913161bccb01 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_System.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_System.java
@@ -29,6 +29,8 @@
import com.oracle.truffle.espresso.EspressoLanguage;
import com.oracle.truffle.espresso.descriptors.EspressoSymbols.Types;
import com.oracle.truffle.espresso.impl.ObjectKlass;
+import com.oracle.truffle.espresso.io.TruffleIO;
+import com.oracle.truffle.espresso.libs.JNU;
import com.oracle.truffle.espresso.libs.libjava.LibJava;
import com.oracle.truffle.espresso.meta.Meta;
import com.oracle.truffle.espresso.runtime.EspressoContext;
@@ -77,7 +79,7 @@ public static final class Raw {
@Substitution
@TruffleBoundary
- public static @JavaType(String[].class) StaticObject platformProperties(@Inject EspressoContext ctx) {
+ public static @JavaType(String[].class) StaticObject platformProperties(@Inject EspressoContext ctx, @Inject TruffleIO io, @Inject JNU jnu) {
// Import properties from host.
Props props = new Props(ctx);
String[] known = new String[props.fixedLength];
@@ -85,9 +87,13 @@ public static final class Raw {
known[props.userDirNdx] = java.lang.System.getProperty("user.dir");
known[props.userNameNdx] = java.lang.System.getProperty("user.name");
- known[props.sunJnuEncodingNdx] = java.lang.System.getProperty("sun.jnu.encoding");
- known[props.fileEncodingNdx] = java.lang.System.getProperty("file.encoding");
-
+ known[props.sunJnuEncodingNdx] = jnu.getCharSet().toString();
+ if (ctx.getJavaVersion().java21OrEarlier()) {
+ known[props.fileEncodingNdx] = java.lang.System.getProperty("file.encoding");
+ }
+ if (ctx.getJavaVersion().java25OrLater()) {
+ known[props.nativeEncodingNDX] = java.lang.System.getProperty("native.encoding");
+ }
known[props.stdoutEncodingNdx] = java.lang.System.getProperty("stdout.encoding");
known[props.stderrEncodingNdx] = java.lang.System.getProperty("stderr.encoding");
@@ -95,8 +101,8 @@ public static final class Raw {
known[props.osArchNdx] = java.lang.System.getProperty("os.arch");
known[props.osVersionNdx] = java.lang.System.getProperty("os.version");
known[props.lineSeparatorNdx] = java.lang.System.getProperty("line.separator");
- known[props.fileSeparatorNdx] = java.lang.System.getProperty("file.separator");
- known[props.pathSeparatorNdx] = java.lang.System.getProperty("path.separator");
+ known[props.fileSeparatorNdx] = String.valueOf(io.getFileSeparator());
+ known[props.pathSeparatorNdx] = String.valueOf(io.getPathSeparator());
known[props.javaIoTmpdirNdx] = java.lang.System.getProperty("java.io.tmpdir");
known[props.httpProxyHostNdx] = java.lang.System.getProperty("http.proxyHost");
@@ -143,6 +149,7 @@ private static final class Props {
private final int displayLanguageNdx;
private final int displayScriptNdx;
private final int displayVariantNdx;
+ // only in 21-
private final int fileEncodingNdx;
private final int fileSeparatorNdx;
private final int formatCountryNdx;
@@ -163,6 +170,8 @@ private static final class Props {
private final int osNameNdx;
private final int osVersionNdx;
private final int pathSeparatorNdx;
+ // only in 25+
+ private final int nativeEncodingNDX;
private final int socksNonProxyHostsNdx;
private final int socksProxyHostNdx;
private final int socksProxyPortNdx;
@@ -186,7 +195,16 @@ private Props(EspressoContext ctx) {
displayLanguageNdx = guestRaw.lookupDeclaredField(ctx.getNames().getOrCreate("_display_language_NDX"), Types._int).getInt(guestRaw.tryInitializeAndGetStatics());
displayScriptNdx = guestRaw.lookupDeclaredField(ctx.getNames().getOrCreate("_display_script_NDX"), Types._int).getInt(guestRaw.tryInitializeAndGetStatics());
displayVariantNdx = guestRaw.lookupDeclaredField(ctx.getNames().getOrCreate("_display_variant_NDX"), Types._int).getInt(guestRaw.tryInitializeAndGetStatics());
- fileEncodingNdx = guestRaw.lookupDeclaredField(ctx.getNames().getOrCreate("_file_encoding_NDX"), Types._int).getInt(guestRaw.tryInitializeAndGetStatics());
+ if (ctx.getJavaVersion().java21OrEarlier()) {
+ fileEncodingNdx = guestRaw.lookupDeclaredField(ctx.getNames().getOrCreate("_file_encoding_NDX"), Types._int).getInt(guestRaw.tryInitializeAndGetStatics());
+ } else {
+ fileEncodingNdx = -1;
+ }
+ if (ctx.getJavaVersion().java25OrLater()) {
+ nativeEncodingNDX = guestRaw.lookupDeclaredField(ctx.getNames().getOrCreate("_native_encoding_NDX"), Types._int).getInt(guestRaw.tryInitializeAndGetStatics());
+ } else {
+ nativeEncodingNDX = -1;
+ }
fileSeparatorNdx = guestRaw.lookupDeclaredField(ctx.getNames().getOrCreate("_file_separator_NDX"), Types._int).getInt(guestRaw.tryInitializeAndGetStatics());
formatCountryNdx = guestRaw.lookupDeclaredField(ctx.getNames().getOrCreate("_format_country_NDX"), Types._int).getInt(guestRaw.tryInitializeAndGetStatics());
formatLanguageNdx = guestRaw.lookupDeclaredField(ctx.getNames().getOrCreate("_format_language_NDX"), Types._int).getInt(guestRaw.tryInitializeAndGetStatics());
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_reflect_Executable.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_reflect_Executable.java
new file mode 100644
index 000000000000..a566e2ef8206
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_reflect_Executable.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import java.lang.reflect.Executable;
+import java.lang.reflect.Parameter;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.EspressoLanguage;
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.SubstitutionProfiler;
+import com.oracle.truffle.espresso.vm.VM;
+
+@EspressoSubstitutions(value = Executable.class, group = LibJava.class)
+public final class Target_java_lang_reflect_Executable {
+ @Substitution(hasReceiver = true)
+ public static @JavaType(Parameter[].class) StaticObject getParameters0(@JavaType(Executable.class) StaticObject self,
+ @Inject VM vm, @Inject EspressoLanguage language,
+ @Inject Meta meta,
+ @Inject SubstitutionProfiler profiler) {
+ return vm.JVM_GetMethodParameters(self, language, meta, profiler);
+ }
+
+ @TruffleBoundary
+ @Substitution(hasReceiver = true)
+ public static @JavaType(byte[].class) StaticObject getTypeAnnotationBytes0(@JavaType(Executable.class) StaticObject self, @Inject VM vm) {
+ return vm.JVM_GetMethodTypeAnnotations(self);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_reflect_Field.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_reflect_Field.java
new file mode 100644
index 000000000000..68d96f5a5da6
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_lang_reflect_Field.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import java.lang.reflect.Field;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.vm.VM;
+
+@EspressoSubstitutions(value = Field.class, group = LibJava.class)
+public final class Target_java_lang_reflect_Field {
+ @TruffleBoundary
+ @Substitution(hasReceiver = true)
+ public static @JavaType(byte[].class) StaticObject getTypeAnnotationBytes0(@JavaType(Field.class) StaticObject self, @Inject VM vm) {
+ return vm.JVM_GetFieldTypeAnnotations(self);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_util_TimeZone.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_util_TimeZone.java
new file mode 100644
index 000000000000..2dfdf5557afa
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_java_util_TimeZone.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.util.TimeZone;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(value = TimeZone.class, group = LibJava.class)
+public final class Target_java_util_TimeZone {
+ @Substitution
+ @TruffleBoundary
+ @SuppressWarnings("unused")
+ public static @JavaType(String.class) StaticObject getSystemTimeZoneID(@JavaType(String.class) StaticObject javaHome, @Inject Meta meta, @Inject EspressoContext context) {
+ return meta.toGuestString(context.getEnv().getTimeZone().getId());
+ }
+
+ @Substitution
+ @TruffleBoundary
+ public static @JavaType(String.class) StaticObject getSystemGMTOffsetID(@Inject Meta meta, @Inject EspressoContext context) {
+ ZoneId zone = context.getEnv().getTimeZone();
+ String offsetId;
+ if (zone instanceof ZoneOffset) {
+ offsetId = zone.getId();
+ } else {
+ ZoneOffset offset = zone.getRules().getOffset(Instant.now());
+ offsetId = offset.getId();
+ }
+ return meta.toGuestString(offsetId);
+
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_loader_BootLoader.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_loader_BootLoader.java
index 1fe799e04227..3eef64f43ec4 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_loader_BootLoader.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_loader_BootLoader.java
@@ -23,12 +23,14 @@
package com.oracle.truffle.espresso.libs.libjava.impl;
import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.meta.Meta;
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
import com.oracle.truffle.espresso.substitutions.Inject;
import com.oracle.truffle.espresso.substitutions.JavaType;
import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.vm.VM;
@EspressoSubstitutions(type = "Ljdk/internal/loader/BootLoader;", group = LibJava.class)
public final class Target_jdk_internal_loader_BootLoader {
@@ -36,4 +38,21 @@ public final class Target_jdk_internal_loader_BootLoader {
public static void setBootLoaderUnnamedModule0(@JavaType(Module.class) StaticObject module, @Inject EspressoContext ctx) {
ctx.getVM().JVM_SetBootLoaderUnnamedModule(module);
}
+ @Substitution
+ public static @JavaType(String[].class) StaticObject getSystemPackageNames(@Inject VM vm, @Inject Meta meta) {
+ return vm.JVM_GetSystemPackages(meta);
+ }
+
+ /**
+ * Returns the location of the package of the given name, if
+ * defined by the boot loader; otherwise {@code null} is returned.
+ *
+ * The location may be a module from the runtime image or exploded image,
+ * or from the boot class append path (i.e. -Xbootclasspath/a or
+ * BOOT-CLASS-PATH attribute specified in java agent).
+ */
+ @Substitution
+ public static @JavaType(String.class) StaticObject getSystemPackageLocation(@JavaType(String[].class) StaticObject name, @Inject VM vm, @Inject Meta meta) {
+ return vm.JVM_GetSystemPackage(name, meta);
+ }
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_platform_CgroupMetrics.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_platform_CgroupMetrics.java
new file mode 100644
index 000000000000..43afbe7e3332
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_platform_CgroupMetrics.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Ljdk/internal/platform/CgroupMetrics;", group = LibJava.class)
+public final class Target_jdk_internal_platform_CgroupMetrics {
+
+ @Substitution
+ public static boolean isUseContainerSupport() {
+ return false;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_reflect_ConstantPool.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_reflect_ConstantPool.java
new file mode 100644
index 000000000000..676de96822f0
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_reflect_ConstantPool.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.SubstitutionProfiler;
+import com.oracle.truffle.espresso.vm.VM;
+
+@EspressoSubstitutions(type = "Ljdk/internal/reflect/ConstantPool;", group = LibJava.class)
+public final class Target_jdk_internal_reflect_ConstantPool {
+ @Substitution(hasReceiver = true)
+ public static int getSize0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, @Inject VM vm) {
+ return vm.JVM_ConstantPoolGetSize(unused, jcpool);
+ }
+
+ @Substitution(hasReceiver = true)
+ public static @JavaType(Class.class) StaticObject getClassAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index,
+ @Inject VM vm,
+ @Inject Meta meta,
+ @Inject SubstitutionProfiler profiler) {
+ return vm.JVM_ConstantPoolGetClassAt(unused, jcpool, index, meta, profiler);
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static @JavaType(Class.class) StaticObject getClassAtIfLoaded0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index) {
+ throw JavaSubstitution.unimplemented();
+
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static int getClassRefIndexAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index) {
+ throw JavaSubstitution.unimplemented();
+
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static @JavaType(Member.class) StaticObject getMethodAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index) {
+ throw JavaSubstitution.unimplemented();
+
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static @JavaType(Member.class) StaticObject getMethodAtIfLoaded0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index) {
+ throw JavaSubstitution.unimplemented();
+
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static @JavaType(Field.class) StaticObject getFieldAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index) {
+ throw JavaSubstitution.unimplemented();
+
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static @JavaType(Field.class) StaticObject getFieldAtIfLoaded0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index) {
+ throw JavaSubstitution.unimplemented();
+
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static @JavaType(String[].class) StaticObject getMemberRefInfoAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index) {
+ throw JavaSubstitution.unimplemented();
+
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static int getNameAndTypeRefIndexAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index) {
+ throw JavaSubstitution.unimplemented();
+
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static @JavaType(String[].class) StaticObject getNameAndTypeRefInfoAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index) {
+ throw JavaSubstitution.unimplemented();
+
+ }
+
+ @Substitution(hasReceiver = true)
+ public static int getIntAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index,
+ @Inject VM vm,
+ @Inject Meta meta,
+ @Inject SubstitutionProfiler profiler) {
+ return vm.JVM_ConstantPoolGetIntAt(unused, jcpool, index, meta, profiler);
+ }
+
+ @Substitution(hasReceiver = true)
+ public static long getLongAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index,
+ @Inject VM vm,
+ @Inject Meta meta,
+ @Inject SubstitutionProfiler profiler) {
+ return vm.JVM_ConstantPoolGetLongAt(unused, jcpool, index, meta, profiler);
+ }
+
+ @Substitution(hasReceiver = true)
+ public static float getFloatAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index,
+ @Inject VM vm,
+ @Inject Meta meta,
+ @Inject SubstitutionProfiler profiler) {
+ return vm.JVM_ConstantPoolGetFloatAt(unused, jcpool, index, meta, profiler);
+ }
+
+ @Substitution(hasReceiver = true)
+ public static double getDoubleAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index,
+ @Inject VM vm,
+ @Inject Meta meta,
+ @Inject SubstitutionProfiler profiler) {
+ return vm.JVM_ConstantPoolGetDoubleAt(unused, jcpool, index, meta, profiler);
+ }
+
+ @Substitution(hasReceiver = true)
+ public static @JavaType(String.class) StaticObject getStringAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index,
+ @Inject VM vm,
+ @Inject Meta meta,
+ @Inject SubstitutionProfiler profiler) {
+ return vm.JVM_ConstantPoolGetStringAt(unused, jcpool, index, meta, profiler);
+ }
+
+ @Substitution(hasReceiver = true)
+ public static @JavaType(String.class) StaticObject getUTF8At0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index,
+ @Inject VM vm,
+ @Inject Meta meta,
+ @Inject SubstitutionProfiler profiler) {
+ return vm.JVM_ConstantPoolGetUTF8At(unused, jcpool, index, meta, profiler);
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static byte getTagAt0(@JavaType(Object.class) StaticObject unused, @JavaType(Object.class) StaticObject jcpool, int index) {
+ throw JavaSubstitution.unimplemented();
+
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_vm_ContinuationSupport.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_vm_ContinuationSupport.java
new file mode 100644
index 000000000000..7b2a7d18af09
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjava/impl/Target_jdk_internal_vm_ContinuationSupport.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjava.impl;
+
+import com.oracle.truffle.espresso.libs.libjava.LibJava;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Ljdk/internal/vm/ContinuationSupport;", group = LibJava.class)
+public final class Target_jdk_internal_vm_ContinuationSupport {
+ @Substitution
+ public static boolean isSupported0() {
+ return false;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjimage/LibJimage.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjimage/LibJimage.java
new file mode 100644
index 000000000000..f1d3cb903184
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjimage/LibJimage.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjimage;
+
+import com.oracle.truffle.espresso.EspressoLanguage;
+import com.oracle.truffle.espresso.ffi.NoNativeAccess;
+import com.oracle.truffle.espresso.libs.Lib;
+import com.oracle.truffle.espresso.libs.Libs;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.substitutions.Collect;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+
+@Collect(Libs.class)
+public final class LibJimage implements Lib.Factory {
+ @Override
+ public String name() {
+ return "jimage";
+ }
+
+ @Override
+ public Lib create(EspressoContext ctx) {
+ return new Lib(ctx, LibJimageCollector.getInstances(JavaSubstitution.Factory.class),
+ name());
+ }
+
+ @Override
+ public boolean isValidfor(EspressoLanguage language) {
+ return language.useEspressoLibs() && language.nativeBackendId().equals(NoNativeAccess.Provider.ID);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjimage/impl/Target_jdk_internal_jimage_NativeImageBuffer.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjimage/impl/Target_jdk_internal_jimage_NativeImageBuffer.java
new file mode 100644
index 000000000000..fdcfaf897c3d
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjimage/impl/Target_jdk_internal_jimage_NativeImageBuffer.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjimage.impl;
+
+import java.nio.ByteBuffer;
+
+import com.oracle.truffle.espresso.libs.libjimage.LibJimage;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Ljdk/internal/jimage/NativeImageBuffer;", group = LibJimage.class)
+public final class Target_jdk_internal_jimage_NativeImageBuffer {
+ @Substitution
+ @SuppressWarnings("unused")
+ public static @JavaType(ByteBuffer.class) StaticObject getNativeMap(@JavaType(String.class) StaticObject imagePath, @Inject Meta meta) {
+ return StaticObject.NULL;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjvm/LibJVM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjvm/LibJVM.java
new file mode 100644
index 000000000000..f57d6b69e863
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjvm/LibJVM.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjvm;
+
+import com.oracle.truffle.espresso.EspressoLanguage;
+import com.oracle.truffle.espresso.ffi.NoNativeAccess;
+import com.oracle.truffle.espresso.libs.Lib;
+import com.oracle.truffle.espresso.libs.Libs;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.substitutions.Collect;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+
+@Collect(Libs.class)
+public final class LibJVM implements Lib.Factory {
+ @Override
+ public String name() {
+ return "jvm";
+ }
+
+ @Override
+ public Lib create(EspressoContext ctx) {
+ return new Lib(ctx, LibJVMCollector.getInstances(JavaSubstitution.Factory.class),
+ name(), false);
+ }
+
+ @Override
+ public boolean isValidfor(EspressoLanguage language) {
+ return language.useEspressoLibs() && language.nativeBackendId().equals(NoNativeAccess.Provider.ID);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjvm/impl/LibJVMSubstitutions.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjvm/impl/LibJVMSubstitutions.java
new file mode 100644
index 000000000000..a4c1d15a5877
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libjvm/impl/LibJVMSubstitutions.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libjvm.impl;
+
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.espresso.ffi.Pointer;
+import com.oracle.truffle.espresso.ffi.RawPointer;
+import com.oracle.truffle.espresso.libs.libjvm.LibJVM;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.SubstitutionFlag;
+
+@EspressoSubstitutions(type = "", group = LibJVM.class)
+public final class LibJVMSubstitutions {
+ private static final @Pointer TruffleObject sentinelPointer = new RawPointer(-1);
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static @Pointer TruffleObject initializeMokapotContext(@Pointer TruffleObject unused1, @Pointer TruffleObject unused2) {
+ // nop
+ return null;
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static void disposeMokapotContext(@Pointer TruffleObject unused1, @Pointer TruffleObject unused2) {
+ // nop
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static @Pointer TruffleObject initializeManagementContext(@Pointer TruffleObject unused1, int unused2) {
+ return null;
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static void disposeManagementContext(@Pointer TruffleObject unused1, int unused2, @Pointer TruffleObject unused3) {
+ // nop
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static void initializeStructs(@Pointer TruffleObject unused) {
+ // nop
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static long lookupMemberOffset(@Pointer TruffleObject unused1, @Pointer TruffleObject unused2) {
+ return -1;
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static @Pointer TruffleObject initializeJvmtiContext(@Pointer TruffleObject unused1, int unused2) {
+ return null;
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static void disposeJvmtiContext(@Pointer TruffleObject unused1, int unused2, @Pointer TruffleObject unused3) {
+ // nop
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static @Pointer TruffleObject getJavaVM(@Pointer TruffleObject unused) {
+ return null;
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static void mokapotAttachThread(@Pointer TruffleObject unused) {
+ // nop
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static void mokapotCaptureState(@Pointer TruffleObject unused1, int unused2) {
+ // nop
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks, methodName = "mokapotGetRTLD_DEFAULT")
+ @SuppressWarnings("unused")
+ public static @Pointer TruffleObject mokapotGetRTLDDEFAULT() {
+ // nop
+ return sentinelPointer;
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static @Pointer TruffleObject mokapotGetProcessHandle() {
+ // nop
+ return sentinelPointer;
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static @Pointer TruffleObject getPackageAt(@Pointer TruffleObject unused1, int unused2) {
+ // nop
+ return null;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/LibManagement.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/LibManagement.java
new file mode 100644
index 000000000000..b29f36241bed
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/LibManagement.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libmanagement;
+
+import com.oracle.truffle.espresso.libs.Lib;
+import com.oracle.truffle.espresso.libs.Libs;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.substitutions.Collect;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+
+@Collect(Libs.class)
+public final class LibManagement implements Lib.Factory {
+ @Override
+ public String name() {
+ return "management";
+ }
+
+ @Override
+ public Lib create(EspressoContext ctx) {
+ return new Lib(ctx, LibManagementCollector.getInstances(JavaSubstitution.Factory.class), name());
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_MemoryImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_MemoryImpl.java
new file mode 100644
index 000000000000..33ca98794dce
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_MemoryImpl.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libmanagement.impl;
+
+import java.lang.management.MemoryManagerMXBean;
+import java.lang.management.MemoryPoolMXBean;
+
+import com.oracle.truffle.espresso.libs.InformationLeak;
+import com.oracle.truffle.espresso.libs.libmanagement.LibManagement;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.vm.Management;
+
+@EspressoSubstitutions(type = "Lsun/management/MemoryImpl;", group = LibManagement.class)
+public final class Target_sun_management_MemoryImpl {
+
+ @Substitution
+ public static @JavaType(MemoryManagerMXBean[].class) StaticObject getMemoryManagers0(@Inject InformationLeak iL, @Inject EspressoContext context) {
+ Management management = iL.checkAndGetManagement(context);
+ return management.GetMemoryManagers(StaticObject.NULL, context.getMeta());
+ }
+
+ @Substitution
+ public static @JavaType(MemoryPoolMXBean[].class) StaticObject getMemoryPools0(@Inject InformationLeak iL, @Inject EspressoContext context) {
+ Management management = iL.checkAndGetManagement(context);
+ return management.GetMemoryPools(StaticObject.NULL, context.getMeta());
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_MemoryPoolImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_MemoryPoolImpl.java
new file mode 100644
index 000000000000..20d65586123c
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_MemoryPoolImpl.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libmanagement.impl;
+
+import java.lang.management.MemoryUsage;
+
+import com.oracle.truffle.espresso.libs.InformationLeak;
+import com.oracle.truffle.espresso.libs.libmanagement.LibManagement;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.vm.Management;
+
+@EspressoSubstitutions(type = "Lsun/management/MemoryPoolImpl;", group = LibManagement.class)
+public final class Target_sun_management_MemoryPoolImpl {
+ @Substitution(hasReceiver = true)
+ public static @JavaType(MemoryUsage.class) StaticObject getUsage0(@JavaType(internalName = "Lsun/management/MemoryPoolImpl;") StaticObject self, @Inject InformationLeak iL,
+ @Inject EspressoContext context, @Inject Meta meta) {
+ Management management = iL.checkAndGetManagement(context);
+ @JavaType(MemoryUsage.class)
+ StaticObject memUsage = management.GetMemoryPoolUsage(self, meta);
+ if (StaticObject.isNull(memUsage)) {
+ throw meta.throwExceptionWithMessage(meta.java_lang_InternalError, "Memory Pool not found");
+ }
+ return memUsage;
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_ThreadImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_ThreadImpl.java
new file mode 100644
index 000000000000..1eda0d89b08b
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_ThreadImpl.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libmanagement.impl;
+
+import com.oracle.truffle.espresso.libs.libmanagement.LibManagement;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.vm.VM;
+
+@EspressoSubstitutions(type = "Lsun/management/ThreadImpl;", group = LibManagement.class)
+public final class Target_sun_management_ThreadImpl {
+ @Substitution
+ public static @JavaType(Thread[].class) StaticObject getThreads(@Inject VM vm) {
+ return vm.JVM_GetAllThreads(StaticObject.NULL);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_VMManagementImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_VMManagementImpl.java
new file mode 100644
index 000000000000..0f26f6275790
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement/impl/Target_sun_management_VMManagementImpl.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libmanagement.impl;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.espresso.EspressoLanguage;
+import com.oracle.truffle.espresso.libs.InformationLeak;
+import com.oracle.truffle.espresso.libs.LibsMeta;
+import com.oracle.truffle.espresso.libs.libmanagement.LibManagement;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.vm.Management;
+import com.oracle.truffle.espresso.vm.VM;
+
+@EspressoSubstitutions(type = "Lsun/management/VMManagementImpl;", group = LibManagement.class)
+public final class Target_sun_management_VMManagementImpl {
+
+ @CompilerDirectives.TruffleBoundary
+ @Substitution
+ public static @JavaType(String.class) StaticObject getVersion0(@Inject InformationLeak iL, @Inject Meta meta, @Inject EspressoContext context) {
+ Management management = iL.checkAndGetManagement(context);
+ int jmmVersion = management.GetVersion();
+ int major = (jmmVersion & 0x0FFF0000) >>> 16;
+ int minor = (jmmVersion & 0x0000FF00) >>> 8;
+ return meta.toGuestString(major + "." + minor);
+ }
+
+ @Substitution
+ @CompilerDirectives.TruffleBoundary
+ public static void initOptionalSupportFields(@Inject InformationLeak iL, @Inject LibsMeta libsMeta, @Inject EspressoContext context) {
+ Management management = iL.checkAndGetManagement(context);
+ management.initOptionalSupportFields(libsMeta);
+ }
+
+ @Substitution
+ public static boolean isThreadCpuTimeEnabled(@Inject InformationLeak iL, @Inject EspressoContext context) {
+ Management management = iL.checkAndGetManagement(context);
+ return management.GetBoolAttribute(Management.JMM_THREAD_CPU_TIME);
+ }
+
+ @Substitution
+ public static boolean isThreadAllocatedMemoryEnabled(@Inject InformationLeak iL, @Inject EspressoContext context) {
+ Management management = iL.checkAndGetManagement(context);
+ return management.GetBoolAttribute(Management.JMM_THREAD_ALLOCATED_MEMORY);
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static long getStartupTime(@JavaType(internalName = "Lsun/management/VMManagementImpl;") StaticObject self, @Inject InformationLeak iL, @Inject EspressoContext context) {
+ Management management = iL.checkAndGetManagement(context);
+ return management.GetLongAttribute(StaticObject.NULL, Management.JMM_JVM_INIT_DONE_TIME_MS);
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static long getUptime0(@JavaType(internalName = "Lsun/management/VMManagementImpl;") StaticObject self, @Inject InformationLeak iL, @Inject EspressoContext context) {
+ Management management = iL.checkAndGetManagement(context);
+ return management.GetLongAttribute(StaticObject.NULL, Management.JMM_JVM_UPTIME_MS);
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static int getProcessId(@JavaType(internalName = "Lsun/management/VMManagementImpl;") StaticObject self, @Inject InformationLeak iL, @Inject EspressoContext context) {
+ Management management = iL.checkAndGetManagement(context);
+ // In the native code the cast without a check. We could maybe do the same then.
+ return Math.toIntExact(management.GetLongAttribute(StaticObject.NULL, Management.JMM_OS_PROCESS_ID));
+ }
+
+ @Substitution(hasReceiver = true)
+ @SuppressWarnings("unused")
+ public static @JavaType(String[].class) StaticObject getVmArguments0(@JavaType(internalName = "Lsun/management/VMManagementImpl;") StaticObject unusedSelf, @Inject EspressoLanguage lang,
+ @Inject VM vm) {
+ return vm.JVM_GetVmArguments(lang);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement_ext/LibManagementExt.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement_ext/LibManagementExt.java
new file mode 100644
index 000000000000..a0225790c59d
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement_ext/LibManagementExt.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libmanagement_ext;
+
+import com.oracle.truffle.espresso.libs.Lib;
+import com.oracle.truffle.espresso.libs.Libs;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.substitutions.Collect;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+
+@Collect(Libs.class)
+public final class LibManagementExt implements Lib.Factory {
+ @Override
+ public String name() {
+ return "management_ext";
+ }
+
+ @Override
+ public Lib create(EspressoContext ctx) {
+ return new Lib(ctx, LibManagementExtCollector.getInstances(JavaSubstitution.Factory.class), name());
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement_ext/impl/Target_com_sun_management_internal_OperatingSystemImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement_ext/impl/Target_com_sun_management_internal_OperatingSystemImpl.java
new file mode 100644
index 000000000000..76a489214ebb
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libmanagement_ext/impl/Target_com_sun_management_internal_OperatingSystemImpl.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libmanagement_ext.impl;
+
+import com.oracle.truffle.espresso.libs.InformationLeak;
+import com.oracle.truffle.espresso.libs.libmanagement_ext.LibManagementExt;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Lcom/sun/management/internal/OperatingSystemImpl;", group = LibManagementExt.class)
+public final class Target_com_sun_management_internal_OperatingSystemImpl {
+ @Substitution
+ public static void initialize0(@Inject InformationLeak iL, @Inject EspressoContext context) {
+ iL.checkAndGetManagement(context);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnespresso/LibNespresso.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnespresso/LibNespresso.java
new file mode 100644
index 000000000000..70349cf634e7
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnespresso/LibNespresso.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnespresso;
+
+import com.oracle.truffle.espresso.EspressoLanguage;
+import com.oracle.truffle.espresso.ffi.NoNativeAccess;
+import com.oracle.truffle.espresso.libs.Lib;
+import com.oracle.truffle.espresso.libs.Libs;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.substitutions.Collect;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+
+@Collect(Libs.class)
+public final class LibNespresso implements Lib.Factory {
+ @Override
+ public String name() {
+ return "nespresso";
+ }
+
+ @Override
+ public Lib create(EspressoContext ctx) {
+ return new Lib(ctx, LibNespressoCollector.getInstances(JavaSubstitution.Factory.class),
+ name(), false);
+ }
+
+ @Override
+ public boolean isValidfor(EspressoLanguage language) {
+ return language.useEspressoLibs() && language.nativeBackendId().equals(NoNativeAccess.Provider.ID);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnespresso/impl/LibNespressoSubstitutions.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnespresso/impl/LibNespressoSubstitutions.java
new file mode 100644
index 000000000000..d798d15054c3
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnespresso/impl/LibNespressoSubstitutions.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnespresso.impl;
+
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.espresso.ffi.Pointer;
+import com.oracle.truffle.espresso.libs.libnespresso.LibNespresso;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.SubstitutionFlag;
+
+@EspressoSubstitutions(type = "", group = LibNespresso.class)
+public final class LibNespressoSubstitutions {
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static @Pointer TruffleObject initializeNativeContext(@Pointer TruffleObject unused) {
+ // nop
+ return null;
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static void disposeNativeContext(@Pointer TruffleObject unused1, @Pointer TruffleObject unused2) {
+ // nop
+ }
+
+ // Checkstyle: stop field name check
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static boolean pop_boolean(@Pointer TruffleObject unused) {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static byte pop_byte(@Pointer TruffleObject unused) {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static char pop_char(@Pointer TruffleObject unused) {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static short pop_short(@Pointer TruffleObject unused) {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static int pop_int(@Pointer TruffleObject unused) {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static float pop_float(@Pointer TruffleObject unused) {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static double pop_double(@Pointer TruffleObject unused) {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static long pop_long(@Pointer TruffleObject unused) {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+
+ @Substitution(flags = SubstitutionFlag.relaxTypeChecks)
+ @SuppressWarnings("unused")
+ public static Object pop_object(@Pointer TruffleObject unused) {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ // Checkstyle: resume field name check
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/LibNet.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/LibNet.java
index 4f1a513e4d7d..abac13cafc59 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/LibNet.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/LibNet.java
@@ -22,12 +22,11 @@
*/
package com.oracle.truffle.espresso.libs.libnet;
-import java.util.List;
-
import com.oracle.truffle.espresso.libs.Lib;
import com.oracle.truffle.espresso.libs.Libs;
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.substitutions.Collect;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
@Collect(Libs.class)
public final class LibNet implements Lib.Factory {
@@ -38,6 +37,6 @@ public String name() {
@Override
public Lib create(EspressoContext ctx) {
- return new Lib(ctx, List.of() /*- LibNetCollector.getInstances(JavaSubstitution.Factory.class) */, name());
+ return new Lib(ctx, LibNetCollector.getInstances(JavaSubstitution.Factory.class), name());
}
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_Inet4Address.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_Inet4Address.java
new file mode 100644
index 000000000000..dbdd419aae6a
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_Inet4Address.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnet.impl;
+
+import java.net.Inet4Address;
+
+import com.oracle.truffle.espresso.libs.libnet.LibNet;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(value = Inet4Address.class, group = LibNet.class)
+public final class Target_java_net_Inet4Address {
+ @Substitution
+ public static void init() {
+ // nop
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_Inet6Address.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_Inet6Address.java
new file mode 100644
index 000000000000..b5b2a79054c2
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_Inet6Address.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnet.impl;
+
+import java.net.Inet6Address;
+
+import com.oracle.truffle.espresso.libs.libnet.LibNet;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(value = Inet6Address.class, group = LibNet.class)
+public final class Target_java_net_Inet6Address {
+ @Substitution
+ public static void init() {
+ // nop
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_Inet6AddressImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_Inet6AddressImpl.java
new file mode 100644
index 000000000000..34e6ce2aea0f
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_Inet6AddressImpl.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnet.impl;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.io.Throw;
+import com.oracle.truffle.espresso.libs.LibsMeta;
+import com.oracle.truffle.espresso.libs.LibsState;
+import com.oracle.truffle.espresso.libs.libnet.LibNet;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.Throws;
+
+@EspressoSubstitutions(type = "Ljava/net/Inet6AddressImpl;", group = LibNet.class)
+public final class Target_java_net_Inet6AddressImpl {
+ @Substitution(hasReceiver = true)
+ @Throws(UnknownHostException.class)
+ @SuppressWarnings("unused")
+ public static @JavaType(String.class) StaticObject getLocalHostName(@JavaType(internalName = "Ljava/net/Inet6AddressImpl;") StaticObject self,
+ @Inject LibsMeta lMeta, @Inject EspressoContext context) {
+ try {
+ return lMeta.getMeta().toGuestString(InetAddress.getLocalHost().getHostName());
+ } catch (UnknownHostException e) {
+ throw Throw.throwUnknownHostException(e.getMessage(), context);
+ }
+ }
+
+ @Substitution(hasReceiver = true)
+ @Throws(UnknownHostException.class)
+ @SuppressWarnings("unused")
+ @TruffleBoundary
+ public static @JavaType(InetAddress[].class) StaticObject lookupAllHostAddr(@JavaType(internalName = "Ljava/net/Inet6AddressImpl;") StaticObject self,
+ @JavaType(String.class) StaticObject hostname, int characteristics,
+ @Inject LibsMeta lMeta, @Inject LibsState libsState, @Inject EspressoContext context) {
+ Meta meta = context.getMeta();
+ if (hostname == StaticObject.NULL) {
+ throw lMeta.getMeta().throwExceptionWithMessage(meta.java_lang_NullPointerException, "host argument is null");
+ }
+ try {
+ InetAddress[] allIps = InetAddress.getAllByName(meta.toHostString(hostname));
+ // filter and reorder based on characteristics
+ boolean ipv4First = (characteristics & (1 << 2)) != 0;
+ boolean ipv6First = (characteristics & (1 << 3)) != 0;
+ boolean ipv6 = (characteristics & (1 << 1)) != 0;
+ boolean ipv4 = (characteristics & (1 << 0)) != 0;
+ Deque filteredIps = new ArrayDeque<>(allIps.length);
+
+ if (!ipv6 && !ipv4) {
+ throw meta.throwExceptionWithMessage(meta.java_lang_IllegalArgumentException, "characteristics");
+ }
+
+ for (InetAddress ip : allIps) {
+ if (ip instanceof Inet4Address && ipv4) {
+ if (ipv4First) {
+ filteredIps.addFirst(libsState.net.convertInetAddr(ip));
+ } else {
+ filteredIps.addLast(libsState.net.convertInetAddr(ip));
+ }
+ } else if (ip instanceof Inet6Address && ipv6) {
+ if (ipv6First) {
+ filteredIps.addFirst(libsState.net.convertInetAddr(ip));
+ } else {
+ filteredIps.addLast(libsState.net.convertInetAddr(ip));
+ }
+ }
+ }
+ StaticObject[] arr = filteredIps.toArray(StaticObject.EMPTY_ARRAY);
+ return context.getAllocator().wrapArrayAs(lMeta.net.java_net_InetAddress.array(), arr);
+ } catch (UnknownHostException e) {
+ throw Throw.throwUnknownHostException(e.getMessage(), context);
+ }
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_InetAddress.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_InetAddress.java
new file mode 100644
index 000000000000..d21acea362c7
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_InetAddress.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnet.impl;
+
+import java.net.InetAddress;
+
+import com.oracle.truffle.espresso.libs.InformationLeak;
+import com.oracle.truffle.espresso.libs.libnet.LibNet;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(value = InetAddress.class, group = LibNet.class)
+public final class Target_java_net_InetAddress {
+ @Substitution
+ public static void init() {
+ // nop
+ }
+
+ @Substitution
+ public static boolean isIPv6Supported(@Inject InformationLeak iL) {
+ return iL.isIPv6Available0();
+
+ }
+
+ @Substitution
+ public static boolean isIPv4Available(@Inject InformationLeak iL) {
+ return iL.isIPv4Available();
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_NetworkInterface.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_NetworkInterface.java
new file mode 100644
index 000000000000..155a867971c9
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnet/impl/Target_java_net_NetworkInterface.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnet.impl;
+
+import java.net.InetAddress;
+import java.net.InterfaceAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.EspressoLanguage;
+import com.oracle.truffle.espresso.io.Throw;
+import com.oracle.truffle.espresso.libs.InformationLeak;
+import com.oracle.truffle.espresso.libs.LibsMeta;
+import com.oracle.truffle.espresso.libs.LibsState;
+import com.oracle.truffle.espresso.libs.libnet.LibNet;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.Throws;
+
+@EspressoSubstitutions(value = NetworkInterface.class, group = LibNet.class)
+public final class Target_java_net_NetworkInterface {
+ @Substitution
+ public static void init() {
+ // nop
+ }
+
+ @Substitution
+ @Throws(SocketException.class)
+ public static @JavaType(NetworkInterface[].class) StaticObject getAll(@Inject EspressoContext ctx, @Inject EspressoLanguage lang, @Inject LibsMeta lMeta) {
+ if (!lang.enableNetworking()) {
+ StaticObject[] arr = StaticObject.EMPTY_ARRAY;
+ return ctx.getAllocator().wrapArrayAs(lMeta.java_net_NetworkInterface.array(), arr);
+ }
+ // maintain a map between host and guest InetAddresses to avoid redundant conversions.
+ ConcurrentHashMap hostGuestAddrMap = new ConcurrentHashMap<>(32);
+
+ try {
+ Enumeration netIFs = NetworkInterface.getNetworkInterfaces();
+ List guestNetIFs = new ArrayList<>();
+ while (netIFs.hasMoreElements()) {
+ NetworkInterface netIF = netIFs.nextElement();
+ guestNetIFs.add(convertNetIF(netIF, StaticObject.NULL, hostGuestAddrMap, ctx, lMeta));
+ }
+ StaticObject[] arr = guestNetIFs.toArray(StaticObject.EMPTY_ARRAY);
+ return ctx.getAllocator().wrapArrayAs(lMeta.java_net_NetworkInterface.array(), arr);
+ } catch (SocketException e) {
+ throw Throw.throwSocketException(e, ctx);
+ }
+ }
+
+ @Substitution
+ @Throws(SocketException.class)
+ @SuppressWarnings("unused")
+ public static @JavaType(NetworkInterface.class) StaticObject getByName0(@JavaType(String.class) StaticObject name) {
+ throw JavaSubstitution.unimplemented();
+ }
+
+ @Substitution
+ @Throws(SocketException.class)
+ @SuppressWarnings("unused")
+ public static @JavaType(NetworkInterface.class) StaticObject getByIndex0(int index) {
+ throw JavaSubstitution.unimplemented();
+ }
+
+ @Substitution
+ @Throws(SocketException.class)
+ @SuppressWarnings("unused")
+ public static boolean boundInetAddress0(@JavaType(InetAddress.class) StaticObject addr) {
+ throw JavaSubstitution.unimplemented();
+ }
+
+ @Substitution
+ @Throws(SocketException.class)
+ public static @JavaType(NetworkInterface.class) StaticObject getByInetAddress0(@JavaType(InetAddress.class) StaticObject addr,
+ @Inject LibsMeta lMeta,
+ @Inject EspressoContext ctx,
+ @Inject LibsState libsState) {
+ ctx.getInformationLeak().checkNetworkEnabled();
+ InetAddress inetAddress = libsState.net.fromGuestInetAddress(addr);
+ try {
+ NetworkInterface netIF = NetworkInterface.getByInetAddress(inetAddress);
+ return convertNetIFSimple(netIF, ctx, lMeta);
+ } catch (SocketException e) {
+ throw Throw.throwSocketException(e, ctx);
+ }
+ }
+
+ @Substitution
+ @TruffleBoundary
+ @Throws(SocketException.class)
+ public static boolean isUp0(@JavaType(String.class) StaticObject name, int ind, @Inject EspressoContext ctx) {
+ ctx.getInformationLeak().checkNetworkEnabled();
+ try {
+ return getNetIF(name, ind, ctx).isUp();
+ } catch (SocketException e) {
+ throw Throw.throwSocketException(e, ctx);
+ }
+ }
+
+ @Substitution
+ @TruffleBoundary
+ @Throws(SocketException.class)
+ public static boolean isLoopback0(@JavaType(String.class) StaticObject name, int ind, @Inject EspressoContext ctx) {
+ ctx.getInformationLeak().checkNetworkEnabled();
+ try {
+ return getNetIF(name, ind, ctx).isLoopback();
+ } catch (SocketException e) {
+ throw Throw.throwSocketException(e, ctx);
+ }
+ }
+
+ @Substitution
+ @Throws(SocketException.class)
+ @SuppressWarnings("unused")
+ public static boolean supportsMulticast0(@JavaType(String.class) StaticObject name, int ind) {
+ throw JavaSubstitution.unimplemented();
+ }
+
+ @Substitution
+ @Throws(SocketException.class)
+ @SuppressWarnings("unused")
+ public static boolean isP2P0(@JavaType(String.class) StaticObject name, int ind) {
+ throw JavaSubstitution.unimplemented();
+ }
+
+ @Substitution
+ @Throws(SocketException.class)
+ @SuppressWarnings("unused")
+ public static @JavaType(byte[].class) StaticObject getMacAddr0(@JavaType(byte[].class) StaticObject inAddr, @JavaType(String.class) StaticObject name, int ind, @Inject EspressoContext ctx,
+ @Inject InformationLeak iL) {
+ // The inAddr is not used. That's also the case in the native code.
+ iL.checkNetworkEnabled();
+ byte[] macAddrHost = iL.getMacAddress(getNetIF(name, ind, ctx));
+ if (macAddrHost == null) {
+ return StaticObject.NULL;
+ }
+ return ctx.getAllocator().wrapArrayAs(ctx.getMeta()._byte_array, macAddrHost);
+ }
+
+ @Substitution
+ @Throws(SocketException.class)
+ @SuppressWarnings("unused")
+ public static int getMTU0(@JavaType(String.class) StaticObject name, int ind) {
+ throw JavaSubstitution.unimplemented();
+ }
+
+ private static @JavaType(NetworkInterface.class) StaticObject convertNetIFSimple(NetworkInterface netIF,
+ EspressoContext ctx, LibsMeta lMeta) {
+ return convertNetIF(netIF, StaticObject.NULL, new ConcurrentHashMap<>(8), ctx, lMeta);
+ }
+
+ private static @JavaType(NetworkInterface.class) StaticObject convertNetIF(NetworkInterface netIF,
+ @JavaType(NetworkInterface.class) StaticObject parent,
+ ConcurrentHashMap hostGuestAddrMap,
+ EspressoContext ctx, LibsMeta lMeta) {
+ @JavaType(NetworkInterface.class)
+ StaticObject guestNetIF = lMeta.java_net_NetworkInterface.allocateInstance(ctx);
+ // convert constructor parameters
+ @JavaType(InetAddress[].class)
+ StaticObject guestInetAddrs = convertInetAddrs(netIF.getInetAddresses(), guestNetIF, hostGuestAddrMap, ctx, lMeta);
+ @JavaType(InterfaceAddress[].class)
+ StaticObject guestIFAddrs = convertIFAddrs(netIF.getInterfaceAddresses(), guestNetIF, hostGuestAddrMap, ctx, lMeta);
+ @JavaType(String.class)
+ StaticObject name = lMeta.getMeta().toGuestString(netIF.getName());
+
+ // constructor
+ lMeta.net.java_net_NetworkInterface_init.invokeDirectSpecial(
+ /* this */ guestNetIF,
+ /* name */ name,
+ /* index */ netIF.getIndex(),
+ /* addr */ guestInetAddrs);
+
+ lMeta.net.java_net_NetworkInterface_displayName.setObject(guestNetIF, name);
+ lMeta.net.java_net_NetworkInterface_virtual.setBoolean(guestNetIF, netIF.isVirtual());
+ lMeta.net.java_net_NetworkInterface_bindings.setObject(guestNetIF, guestIFAddrs);
+
+ // convert childs if there are any
+ if (netIF.getSubInterfaces().hasMoreElements()) {
+ @JavaType(NetworkInterface[].class)
+ StaticObject guestChilds = convertChilds(netIF.getSubInterfaces(), guestNetIF, hostGuestAddrMap, ctx, lMeta);
+ lMeta.net.java_net_NetworkInterface_childs.setObject(guestNetIF, guestChilds);
+ }
+
+ if (parent != StaticObject.NULL) {
+ lMeta.net.java_net_NetworkInterface_parent.setObject(guestNetIF, parent);
+ }
+
+ return guestNetIF;
+ }
+
+ private static @JavaType(InetAddress[].class) StaticObject convertInetAddrs(Enumeration inetAddrs,
+ @JavaType(NetworkInterface.class) StaticObject netIF,
+ ConcurrentHashMap hostGuestAddrMap,
+ EspressoContext ctx, LibsMeta lMeta) {
+ List guestInetAddrs = new ArrayList<>();
+ while (inetAddrs.hasMoreElements()) {
+ InetAddress hostInetAddr = inetAddrs.nextElement();
+ @JavaType(InetAddress.class)
+ StaticObject guestInetAddr = convertInetAddr(hostInetAddr, netIF, hostGuestAddrMap, ctx);
+ guestInetAddrs.add(guestInetAddr);
+ }
+ StaticObject[] arr = guestInetAddrs.toArray(StaticObject.EMPTY_ARRAY);
+ return ctx.getAllocator().wrapArrayAs(lMeta.net.java_net_InetAddress.array(), arr);
+ }
+
+ private static @JavaType StaticObject convertInetAddr(InetAddress inetAddr,
+ @JavaType(NetworkInterface.class) StaticObject netIF,
+ ConcurrentHashMap hostGuestAddrMap,
+ EspressoContext ctx) {
+ // check cache first
+ if (hostGuestAddrMap.containsKey(inetAddr)) {
+ return hostGuestAddrMap.get(inetAddr);
+ }
+ // not in cache so do full conversion and cache it
+ @JavaType(InetAddress.class)
+ StaticObject guestInetAddr = ctx.getLibsState().net.convertInetAddr(inetAddr, netIF);
+ hostGuestAddrMap.put(inetAddr, guestInetAddr);
+ return guestInetAddr;
+ }
+
+ private static @JavaType(InterfaceAddress[].class) StaticObject convertIFAddrs(List iFAddrs,
+ @JavaType(NetworkInterface.class) StaticObject netIF,
+ ConcurrentHashMap hostGuestAddrMap,
+ EspressoContext ctx, LibsMeta lMeta) {
+ List guestIFAddrs = new ArrayList<>(iFAddrs.size());
+ for (InterfaceAddress iFAddr : iFAddrs) {
+ @JavaType(InterfaceAddress.class)
+ StaticObject guestIFAddr = convertIFAddr(iFAddr, netIF, hostGuestAddrMap, ctx, lMeta);
+ guestIFAddrs.add(guestIFAddr);
+ }
+ StaticObject[] arr = guestIFAddrs.toArray(StaticObject.EMPTY_ARRAY);
+ return ctx.getAllocator().wrapArrayAs(lMeta.net.java_net_InterfaceAddress.array(), arr);
+ }
+
+ private static @JavaType(InterfaceAddress.class) StaticObject convertIFAddr(InterfaceAddress iFAddrs,
+ @JavaType(NetworkInterface.class) StaticObject netIF,
+ ConcurrentHashMap hostGuestAddrMap,
+ EspressoContext ctx, LibsMeta lMeta) {
+ @JavaType(InterfaceAddress.class)
+ StaticObject guestIFAddr = lMeta.net.java_net_InterfaceAddress.allocateInstance(ctx);
+ lMeta.net.java_net_InterfaceAddress_init.invokeDirectSpecial(guestIFAddr);
+
+ @JavaType(InetAddress.class)
+ StaticObject addr = convertInetAddr(iFAddrs.getAddress(), netIF, hostGuestAddrMap, ctx);
+ lMeta.net.java_net_InterfaceAddress_address.setObject(guestIFAddr, addr);
+
+ if (iFAddrs.getBroadcast() != null) {
+ @JavaType(InetAddress.class)
+ StaticObject broadcastAddr = convertInetAddr(iFAddrs.getBroadcast(), netIF, hostGuestAddrMap, ctx);
+ lMeta.net.java_net_InterfaceAddress_broadcast.setObject(guestIFAddr, broadcastAddr);
+ }
+
+ lMeta.net.java_net_InterfaceAddress_maskLength.setShort(guestIFAddr, iFAddrs.getNetworkPrefixLength());
+ return guestIFAddr;
+ }
+
+ private static @JavaType(NetworkInterface[].class) StaticObject convertChilds(Enumeration childs,
+ @JavaType(NetworkInterface.class) StaticObject parent,
+ ConcurrentHashMap hostGuestAddrMap,
+ EspressoContext ctx, LibsMeta lMeta) {
+ List guestChilds = new ArrayList<>();
+ while (childs.hasMoreElements()) {
+ NetworkInterface child = childs.nextElement();
+ @JavaType(NetworkInterface.class)
+ StaticObject guestChild = convertNetIF(child, parent, hostGuestAddrMap, ctx, lMeta);
+ guestChilds.add(guestChild);
+ }
+ StaticObject[] arr = guestChilds.toArray(StaticObject.EMPTY_ARRAY);
+ return ctx.getAllocator().wrapArrayAs(lMeta.java_net_NetworkInterface.array(), arr);
+ }
+
+ private static NetworkInterface getNetIF(@JavaType(String.class) StaticObject name, int ind, EspressoContext ctx) {
+ try {
+ NetworkInterface netIF = NetworkInterface.getByIndex(ind);
+ if (netIF == null) {
+ String hoststring = ctx.getMeta().toHostString(name);
+ netIF = hoststring == null ? null : NetworkInterface.getByName(hoststring);
+ }
+ if (netIF == null) {
+ Throw.throwSocketException("Didn't found a NetworkInterface associated with the given name and index", ctx);
+ }
+ return netIF;
+ } catch (SocketException e) {
+ throw Throw.throwSocketException(e, ctx);
+ }
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_FileDispatcherImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_FileDispatcherImpl.java
index 56e3d898b470..504d9027c67e 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_FileDispatcherImpl.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_FileDispatcherImpl.java
@@ -25,9 +25,18 @@
import java.io.FileDescriptor;
import java.io.IOException;
+import com.oracle.truffle.espresso.ffi.NativeAccess;
+import com.oracle.truffle.espresso.ffi.RawPointer;
+import com.oracle.truffle.espresso.ffi.memory.NativeMemory;
+import com.oracle.truffle.espresso.io.FDAccess;
+import com.oracle.truffle.espresso.io.Throw;
+import com.oracle.truffle.espresso.io.TruffleIO;
import com.oracle.truffle.espresso.libs.libnio.LibNio;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
import com.oracle.truffle.espresso.substitutions.JavaType;
import com.oracle.truffle.espresso.substitutions.Substitution;
@@ -35,22 +44,46 @@
@EspressoSubstitutions(group = LibNio.class)
public final class Target_sun_nio_ch_FileDispatcherImpl {
+
@Substitution
- public static long allocationGranularity0() {
- throw JavaSubstitution.unimplemented();
+ @SuppressWarnings("unused")
+ public static long allocationGranularity0(@Inject Meta meta) {
+ // Currently we can not query the Platforms allocation granularity with the Truffle virtual
+ // filesystem. Considering the allocation granularity is only used when mapping files into
+ // memory returning 1 is a valid approach since we actually just read the file.
+ return 1;
}
@Substitution
@Throws(IOException.class)
@SuppressWarnings("unused")
- public static long map0(@JavaType(FileDescriptor.class) StaticObject fd, int prot, long position, long length, boolean isSync) {
- throw JavaSubstitution.unimplemented();
+ public static long map0(@JavaType(FileDescriptor.class) StaticObject fd, int prot, long position, long length, boolean isSync,
+ @Inject TruffleIO io,
+ @Inject EspressoContext ctx) {
+
+ if (prot == 1) {
+ // We dont allow public writes since we dont actually map the file. See
+ // sun.nio.ch.FileChannelImpl.toProt
+ throw Throw.throwUnsupported("mmap for public writes is not supported at the moment", ctx);
+ }
+ NativeMemory nativeMemory = ctx.getNativeAccess().nativeMemory();
+ long addr = nativeMemory.allocateMemory(length);
+ long oldPosition = io.position(fd, FDAccess.forFileDescriptor());
+ assert oldPosition >= 0;
+ try {
+ io.seek(fd, FDAccess.forFileDescriptor(), position);
+ io.readAddress(fd, FDAccess.forFileDescriptor(), addr, Math.toIntExact(length));
+ } finally {
+ io.seek(fd, FDAccess.forFileDescriptor(), oldPosition);
+ }
+ return addr;
}
@Substitution
@SuppressWarnings("unused")
- public static int unmap0(long address, long length) {
- throw JavaSubstitution.unimplemented();
+ public static int unmap0(long address, long length, @Inject NativeAccess nativeAccess) {
+ nativeAccess.freeMemory(RawPointer.create(address));
+ return 0;
}
@Substitution
@@ -72,9 +105,13 @@ public static long transferFrom0(@JavaType(FileDescriptor.class) StaticObject sr
@Substitution
@Throws(IOException.class)
- @SuppressWarnings("unused")
- public static long seek0(@JavaType(FileDescriptor.class) StaticObject fd, long offset) {
- throw JavaSubstitution.unimplemented();
+ public static long seek0(@JavaType(FileDescriptor.class) StaticObject fd, long offset,
+ @Inject TruffleIO io) {
+ if (offset < 0) {
+ return io.position(fd, FDAccess.forFileDescriptor());
+ }
+ io.seek(fd, FDAccess.forFileDescriptor(), offset);
+ return 0;
}
@Substitution
@@ -107,16 +144,16 @@ public static void release0(@JavaType(FileDescriptor.class) StaticObject fd, lon
@Substitution
@Throws(IOException.class)
- @SuppressWarnings("unused")
- public static long size0(@JavaType(FileDescriptor.class) StaticObject fd) {
- throw JavaSubstitution.unimplemented();
+ public static long size0(@JavaType(FileDescriptor.class) StaticObject fd, @Inject TruffleIO io) {
+ return io.length(fd, FDAccess.forFileDescriptor());
}
@Substitution
@Throws(IOException.class)
- @SuppressWarnings("unused")
- public static int read0(@JavaType(FileDescriptor.class) StaticObject fd, long address, int len) {
- throw JavaSubstitution.unimplemented();
+ public static int read0(@JavaType(FileDescriptor.class) StaticObject fd, long address, int len,
+ @Inject TruffleIO io) {
+ return io.readAddress(fd, FDAccess.forFileDescriptor(), address, len);
+
}
@Substitution
@@ -128,9 +165,8 @@ public static int readv0(@JavaType(FileDescriptor.class) StaticObject fd, long a
@Substitution
@Throws(IOException.class)
- @SuppressWarnings("unused")
- public static int write0(@JavaType(FileDescriptor.class) StaticObject fd, long address, int len) {
- throw JavaSubstitution.unimplemented();
+ public static int write0(@JavaType(FileDescriptor.class) StaticObject fd, long address, int len, @Inject TruffleIO io) {
+ return io.writeAddress(fd, FDAccess.forFileDescriptor(), address, len);
}
@Substitution
@@ -143,15 +179,22 @@ public static int writev0(@JavaType(FileDescriptor.class) StaticObject fd, long
@Substitution
@Throws(IOException.class)
@SuppressWarnings("unused")
- public static void close0(@JavaType(FileDescriptor.class) StaticObject fd) {
- throw JavaSubstitution.unimplemented();
+ public static void close0(@JavaType(FileDescriptor.class) StaticObject fd, @Inject TruffleIO io) {
+ io.close(fd, FDAccess.forFileDescriptor());
}
@Substitution
@Throws(IOException.class)
- @SuppressWarnings("unused")
- public static int pread0(@JavaType(FileDescriptor.class) StaticObject fd, long address, int len, long position) {
- throw JavaSubstitution.unimplemented();
+ public static int pread0(@JavaType(FileDescriptor.class) StaticObject fd, long address, int len, long position,
+ @Inject TruffleIO io) {
+ // Currently, this is not thread safe as we temporarily update the position of the file.
+ long oldPos = io.position(fd, FDAccess.forFileDescriptor());
+ try {
+ io.seek(fd, FDAccess.forFileDescriptor(), position);
+ return io.readAddress(fd, FDAccess.forFileDescriptor(), address, len);
+ } finally {
+ io.seek(fd, FDAccess.forFileDescriptor(), oldPos);
+ }
}
@Substitution
@@ -174,4 +217,10 @@ public static void dup0(@JavaType(FileDescriptor.class) StaticObject fd1, @JavaT
public static int setDirect0(@JavaType(FileDescriptor.class) StaticObject fd, @JavaType(String.class) StaticObject path) {
throw JavaSubstitution.unimplemented();
}
+
+ @Substitution
+ @Throws(IOException.class)
+ public static int available0(@JavaType(FileDescriptor.class) StaticObject fd, @Inject TruffleIO io) {
+ return io.available(fd, FDAccess.forFileDescriptor());
+ }
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_IOUtil.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_IOUtil.java
index 6c83a27ebb3f..6894ea54c904 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_IOUtil.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_IOUtil.java
@@ -26,12 +26,12 @@
import java.io.IOException;
import com.oracle.truffle.espresso.io.Checks;
+import com.oracle.truffle.espresso.io.FDAccess;
import com.oracle.truffle.espresso.io.TruffleIO;
import com.oracle.truffle.espresso.libs.libnio.LibNio;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
import com.oracle.truffle.espresso.substitutions.Inject;
-import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
import com.oracle.truffle.espresso.substitutions.JavaType;
import com.oracle.truffle.espresso.substitutions.Substitution;
import com.oracle.truffle.espresso.substitutions.Throws;
@@ -71,8 +71,8 @@ public final class Target_sun_nio_ch_IOUtil {
@Substitution
@Throws(IOException.class)
@SuppressWarnings("unused")
- static long makePipe(boolean blocking) {
- throw JavaSubstitution.unimplemented();
+ static long makePipe(boolean blocking, @Inject TruffleIO io) {
+ return io.openPipe(blocking);
}
@Substitution
@@ -81,6 +81,12 @@ static int write1(int fd, byte b, @Inject TruffleIO io) {
return io.writeBytes(fd, new byte[]{b}, 0, 1);
}
+ @Substitution
+ @Throws(IOException.class)
+ public static void configureBlocking(@JavaType(FileDescriptor.class) StaticObject fd, boolean blocking, @Inject TruffleIO io) {
+ io.configureBlocking(fd, FDAccess.forFileDescriptor(), blocking);
+ }
+
@Substitution
@Throws(IOException.class)
static boolean drain(int fd, @Inject TruffleIO io) {
@@ -97,13 +103,6 @@ static int drain1(int fd, @Inject TruffleIO io) {
return 0;
}
- @Substitution
- @Throws(IOException.class)
- @SuppressWarnings("unused")
- public static void configureBlocking(@JavaType(FileDescriptor.class) StaticObject fd, boolean blocking) {
- throw JavaSubstitution.unimplemented();
- }
-
@Substitution
public static int fdVal(@JavaType(FileDescriptor.class) StaticObject fd, @Inject TruffleIO io) {
Checks.nullCheck(fd, io);
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_Net.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_Net.java
new file mode 100644
index 000000000000..e8b1acf42ff3
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_Net.java
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnio.impl;
+
+import static java.nio.channels.SelectionKey.OP_CONNECT;
+import static java.nio.channels.SelectionKey.OP_READ;
+import static java.nio.channels.SelectionKey.OP_WRITE;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.SocketOption;
+import java.net.StandardSocketOptions;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.io.FDAccess;
+import com.oracle.truffle.espresso.io.Throw;
+import com.oracle.truffle.espresso.io.TruffleIO;
+import com.oracle.truffle.espresso.libs.InformationLeak;
+import com.oracle.truffle.espresso.libs.LibsMeta;
+import com.oracle.truffle.espresso.libs.LibsState;
+import com.oracle.truffle.espresso.libs.libnio.LibNio;
+import com.oracle.truffle.espresso.meta.EspressoError;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.EspressoException;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.Throws;
+import com.oracle.truffle.espresso.substitutions.VersionFilter;
+
+@EspressoSubstitutions(type = "Lsun/nio/ch/Net;", group = LibNio.class)
+public final class Target_sun_nio_ch_Net {
+ private static final short POLLIN = 0x1;
+ private static final short POLLOUT = 0x4;
+ private static final short POLLERR = 0x8;
+ private static final short POLLHUP = 0x10;
+ private static final short POLLNVAL = 0x20;
+ private static final short POLLCONN = 0x40;
+
+ @Substitution
+ public static void initIDs() {
+ // nop
+ }
+
+ @Substitution
+ public static boolean isIPv6Available0(@Inject InformationLeak iL) {
+ return iL.isIPv6Available0();
+
+ }
+
+ @Substitution
+ public static short pollinValue(@Inject InformationLeak iL) {
+ iL.checkNetworkEnabled();
+ return POLLIN;
+ }
+
+ @Substitution
+ public static short polloutValue(@Inject InformationLeak iL) {
+ iL.checkNetworkEnabled();
+ return POLLOUT;
+ }
+
+ @Substitution
+ public static short pollerrValue(@Inject InformationLeak iL) {
+ iL.checkNetworkEnabled();
+ return POLLERR;
+ }
+
+ @Substitution
+ public static short pollhupValue(@Inject InformationLeak iL) {
+ iL.checkNetworkEnabled();
+ return POLLHUP;
+ }
+
+ @Substitution
+ public static short pollnvalValue(@Inject InformationLeak iL) {
+ iL.checkNetworkEnabled();
+ return POLLNVAL;
+ }
+
+ @Substitution
+ public static short pollconnValue(@Inject InformationLeak iL) {
+ iL.checkNetworkEnabled();
+ return POLLCONN;
+ }
+
+ @Substitution
+ public static int isExclusiveBindAvailable(@Inject InformationLeak iL) {
+ return iL.isExclusvieBindAvailable();
+ }
+
+ @Substitution
+ public static boolean isReusePortAvailable0(@Inject InformationLeak iL) {
+ return iL.isReusePortAvailable0();
+ }
+
+ @Substitution
+ @SuppressWarnings("unused")
+ public static int socket0(boolean preferIPv6, boolean stream, boolean reuse,
+ boolean fastLoopback,
+ @Inject TruffleIO io) {
+ return io.openSocket(preferIPv6, stream, reuse);
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ @TruffleBoundary
+ public static int accept(@JavaType(FileDescriptor.class) StaticObject fd, @JavaType(FileDescriptor.class) StaticObject newfd, @JavaType(InetSocketAddress[].class) StaticObject isaa,
+ @Inject TruffleIO io, @Inject LibsState libsState, @Inject LibsMeta lMeta, @Inject EspressoContext ctx) {
+ // accept connection & populate fd.
+ SocketAddress[] clientSaArr = new SocketAddress[1];
+ int retCode = io.accept(fd, FDAccess.forFileDescriptor(), newfd, clientSaArr, libsState);
+ if (retCode < 0) {
+ return retCode;
+ }
+
+ if (clientSaArr[0] instanceof InetSocketAddress clientIsa) {
+ // convert to guest-object and populate argument-array
+ @JavaType(InetAddress.class)
+ StaticObject guestInetAddress = libsState.net.convertInetAddr(clientIsa.getAddress());
+
+ @JavaType(InetSocketAddress.class)
+ StaticObject guestSocket = lMeta.net.java_net_InetSocketAddress.allocateInstance(ctx);
+ // constructor call for guest-object-conversion
+ lMeta.net.java_net_InetSocketAddress_init.invokeDirectSpecial(guestSocket, guestInetAddress,
+ clientIsa.getPort());
+
+ @JavaType(InetSocketAddress.class)
+ StaticObject[] argArray = isaa.unwrap(ctx.getLanguage());
+ // avoid check for non-emptiness since at every call site an array of length 1 is
+ // provided!
+ argArray[0] = guestSocket;
+ } else {
+ // remote Address is UnixDomainSocketAddress and IPC is not implemented.
+ throw JavaSubstitution.unimplemented();
+ }
+ // return 1 as in the native Method
+ return 1;
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ @SuppressWarnings("unused")
+ @TruffleBoundary
+ public static int connect0(boolean preferIPv6, @JavaType(FileDescriptor.class) StaticObject fd,
+ @JavaType(InetAddress.class) StaticObject remote,
+ int remotePort, @Inject TruffleIO io, @Inject LibsState libsState) {
+ InetAddress remoteAddress = libsState.net.fromGuestInetAddress(remote);
+ SocketAddress remoteSocket = new InetSocketAddress(remoteAddress, remotePort);
+ return io.connect(fd, FDAccess.forFileDescriptor(), remoteSocket) ? 1 : io.ioStatusSync.UNAVAILABLE;
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ @TruffleBoundary
+ public static void shutdown(@JavaType(FileDescriptor.class) StaticObject fd, int how,
+ @Inject TruffleIO io) {
+ io.shutdownSocketChannel(fd, FDAccess.forFileDescriptor(), how);
+ }
+
+ @Substitution(languageFilter = VersionFilter.Java25OrLater.class)
+ public static boolean shouldShutdownWriteBeforeClose0() {
+ // returns false on linux.
+ return false;
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ public static void bind0(@JavaType(FileDescriptor.class) StaticObject fd, boolean preferIPv6,
+ boolean useExclBind, @JavaType(InetAddress.class) StaticObject addr,
+ int port,
+ @Inject TruffleIO io, @Inject LibsState libsState) {
+ io.bind(fd, FDAccess.forFileDescriptor(), preferIPv6, useExclBind, addr, port, libsState);
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ public static void listen(@JavaType(FileDescriptor.class) StaticObject fd, int backlog,
+ @Inject TruffleIO io) {
+ io.listenTCP(fd, FDAccess.forFileDescriptor(), backlog);
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ public static @JavaType(InetAddress.class) StaticObject localInetAddress(@JavaType(FileDescriptor.class) StaticObject fd, @Inject TruffleIO io) {
+ return io.getLocalAddress(fd, FDAccess.forFileDescriptor());
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ public static int localPort(@JavaType(FileDescriptor.class) StaticObject fd, @Inject TruffleIO io) {
+ return io.getPort(fd, FDAccess.forFileDescriptor());
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ @SuppressWarnings({"unused", "unchecked"})
+ @TruffleBoundary
+ public static void setIntOption0(@JavaType(FileDescriptor.class) StaticObject fd, boolean mayNeedConversion,
+ int level, int opt, int arg, boolean isIPv6,
+ @Inject EspressoContext ctx, @Inject TruffleIO io) {
+ // We set the option over the public NetworkChannel API, thus the low-level Plattform
+ // specific arguments like mayNeedConversion and isIpv6 aren't needed
+
+ // recover SocketOption and do Type-Conversion
+ SocketOption> socketOption = getSocketOption(level, opt, ctx);
+ Class> type = socketOption.type();
+ if (type == Integer.class) {
+ SocketOption intSocketOption = (SocketOption) socketOption;
+ io.setSocketOption(fd, FDAccess.forFileDescriptor(), intSocketOption, arg);
+ } else if (type == Boolean.class) {
+ SocketOption boolSocketOption = (SocketOption) socketOption;
+ io.setSocketOption(fd, FDAccess.forFileDescriptor(), boolSocketOption, arg == 1 ? Boolean.TRUE : Boolean.FALSE);
+ } else {
+ // SocketOptions are Integer or Boolean
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ @SuppressWarnings({"unused", "unchecked"})
+ @TruffleBoundary
+ public static int getIntOption0(@JavaType(FileDescriptor.class) StaticObject fd, boolean mayNeedConversion,
+ int level, int opt,
+ @Inject EspressoContext ctx, @Inject TruffleIO io) {
+ // We get the option over the public NetworkChannel API, thus the low-level Plattform
+ // mayNeedConversion and isIpv6 aren't needed
+
+ // recover SocketOption and do Type-Conversion
+ SocketOption> socketOption = getSocketOption(level, opt, ctx);
+ Class> type = socketOption.type();
+ if (type == Integer.class) {
+ SocketOption intSocketOption = (SocketOption) socketOption;
+ return io.getSocketOption(fd, FDAccess.forFileDescriptor(), intSocketOption);
+ } else if (type == Boolean.class) {
+ SocketOption boolSocketOption = (SocketOption) socketOption;
+ return io.getSocketOption(fd, FDAccess.forFileDescriptor(), boolSocketOption) ? 1 : 0;
+ } else {
+ // SocketOptions are Integer or Boolean
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ public static boolean pollConnect(@JavaType(FileDescriptor.class) StaticObject fd, long timeout, @Inject TruffleIO io, @Inject EspressoContext ctx) {
+ int op = poll(fd, POLLCONN, timeout, io, ctx);
+ if (op == POLLCONN) {
+ return io.finishConnect(fd, FDAccess.forFileDescriptor());
+ }
+ return false;
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ @TruffleBoundary
+ public static int poll(@JavaType(FileDescriptor.class) StaticObject fd, int nativeOps, long timeout, @Inject TruffleIO io, @Inject EspressoContext ctx) {
+ try (Selector selector = Selector.open()) {
+ int ops = nativeToSelectorOps(nativeOps, ctx);
+ SelectionKey key = io.register(fd, FDAccess.forFileDescriptor(), selector, ops);
+ // do the select
+ if (timeout == 0) {
+ selector.selectNow();
+ } else if (timeout == -1) {
+ selector.select();
+ // there should be readyOps
+ assert key.readyOps() != 0;
+ } else if (timeout > 0) {
+ selector.select(timeout);
+ }
+ return selectorToNativeOps(key.readyOps(), ctx);
+
+ } catch (IOException | EspressoException | EspressoError e) {
+ return io.ioStatusSync.THROWN;
+ }
+
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ public static int available(@JavaType(FileDescriptor.class) StaticObject fd, @Inject TruffleIO io) {
+ return io.available(fd, FDAccess.forFileDescriptor());
+ }
+
+ private static int selectorToNativeOps(int selectorOps, EspressoContext ctx) {
+ return switch (selectorOps) {
+ case (OP_READ) -> POLLIN;
+ case (OP_WRITE) -> POLLOUT;
+ case (OP_CONNECT) -> POLLCONN;
+ case (0) -> 0;
+ default ->
+ throw Throw.throwUnsupported("The following selector operation is not supported:" + selectorOps, ctx);
+ };
+ }
+
+ private static int nativeToSelectorOps(int nativeOps, EspressoContext ctx) {
+ int ops = 0;
+ if ((nativeOps & POLLIN) != 0) {
+ ops |= OP_READ;
+ }
+ if ((nativeOps & POLLOUT) != 0) {
+ ops |= OP_WRITE;
+ }
+ if ((nativeOps & POLLERR) != 0) {
+ throw Throw.throwUnsupported("currently we dont support polling POLLERR", ctx);
+ }
+ if ((nativeOps & POLLHUP) != 0) {
+ throw Throw.throwUnsupported("currently we dont support polling POLLHUP", ctx);
+ }
+ if ((nativeOps & POLLNVAL) != 0) {
+ throw Throw.throwUnsupported("currently we dont support polling POLLNVAL", ctx);
+ }
+ if ((nativeOps & POLLCONN) != 0) {
+ ops |= OP_CONNECT;
+ }
+ return ops;
+ }
+
+ private static SocketOption> getSocketOption(int level, int opt, EspressoContext ctx) {
+ switch (level) {
+ case 0:
+ switch (opt) {
+ case 1:
+ return StandardSocketOptions.IP_TOS;
+ case 32:
+ return StandardSocketOptions.IP_MULTICAST_IF;
+ case 33:
+ return StandardSocketOptions.IP_MULTICAST_TTL;
+ case 34:
+ return StandardSocketOptions.IP_MULTICAST_LOOP;
+ }
+ break;
+ case 1:
+ switch (opt) {
+ case 2:
+ return StandardSocketOptions.SO_REUSEADDR;
+ case 6:
+ return StandardSocketOptions.SO_BROADCAST;
+ case 7:
+ return StandardSocketOptions.SO_SNDBUF;
+ case 8:
+ return StandardSocketOptions.SO_RCVBUF;
+ case 9:
+ return StandardSocketOptions.SO_KEEPALIVE;
+ case 10:
+ // Would be a ExtendedSocketOption.SO_OOBINLINE, however
+ // ExtendedOption are package private so we cannot easily access them. For
+ // Set and GetOption of Net Extended Option aren't accessed over the native
+ // world anyway thus we shouldn't reach here
+ throw JavaSubstitution.unimplemented();
+ case 13:
+ return StandardSocketOptions.SO_LINGER;
+ case 15:
+ return StandardSocketOptions.SO_REUSEPORT;
+ }
+ break;
+ case 41:
+ switch (opt) {
+ case 17:
+ return StandardSocketOptions.IP_MULTICAST_IF;
+ case 18:
+ return StandardSocketOptions.IP_MULTICAST_TTL;
+ case 19:
+ return StandardSocketOptions.IP_MULTICAST_LOOP;
+ case 67:
+ return StandardSocketOptions.IP_TOS;
+ }
+ break;
+ }
+ if (level == 6 && opt == 1) {
+ return StandardSocketOptions.TCP_NODELAY;
+ }
+ throw Throw.throwUnsupported("Unsupported SocketOption: level = " + level + ", opt = " + opt, ctx);
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_SocketDispatcher.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_SocketDispatcher.java
new file mode 100644
index 000000000000..31cc5d54fd11
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_SocketDispatcher.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnio.impl;
+
+import java.io.FileDescriptor;
+
+import com.oracle.truffle.espresso.io.FDAccess;
+import com.oracle.truffle.espresso.io.TruffleIO;
+import com.oracle.truffle.espresso.libs.libnio.LibNio;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Lsun/nio/ch/SocketDispatcher;", group = LibNio.class)
+public final class Target_sun_nio_ch_SocketDispatcher {
+
+ @Substitution
+ public static boolean isBlocking(@JavaType(FileDescriptor.class) StaticObject fd,
+ @Inject TruffleIO io) {
+ return io.isBlocking(fd, FDAccess.forFileDescriptor());
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_TruffleDispatcher.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_TruffleDispatcher.java
new file mode 100644
index 000000000000..c027bab7f0ef
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_TruffleDispatcher.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnio.impl;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+import com.oracle.truffle.espresso.io.FDAccess;
+import com.oracle.truffle.espresso.io.TruffleIO;
+import com.oracle.truffle.espresso.libs.libnio.LibNio;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+import com.oracle.truffle.espresso.substitutions.Throws;
+
+@EspressoSubstitutions(type = "Lsun/nio/ch/TruffleDispatcher;", group = LibNio.class)
+public final class Target_sun_nio_ch_TruffleDispatcher {
+
+ @Substitution
+ @Throws(IOException.class)
+ public static int read0(@JavaType(FileDescriptor.class) StaticObject fd, long address, int len,
+ @Inject TruffleIO io) {
+ return io.readAddress(fd, FDAccess.forFileDescriptor(), address, len);
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ public static int readv0(@JavaType(FileDescriptor.class) StaticObject fd, long address, int len, @Inject TruffleIO io) {
+ return Math.toIntExact(io.readv(fd, FDAccess.forFileDescriptor(), address, len));
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ public static int write0(@JavaType(FileDescriptor.class) StaticObject fd, long address, int len, @Inject TruffleIO io) {
+ return io.writeAddress(fd, FDAccess.forFileDescriptor(), address, len);
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ public static int writev0(@JavaType(FileDescriptor.class) StaticObject fd, long address, int len, @Inject TruffleIO io) {
+ // len is length of IOV
+ return Math.toIntExact(io.writev(fd, FDAccess.forFileDescriptor(), address, len));
+ }
+
+ @Substitution
+ @Throws(IOException.class)
+ public static void close0(@JavaType(FileDescriptor.class) StaticObject fd, @Inject TruffleIO io) {
+ io.close(fd, FDAccess.forFileDescriptor());
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_TrufflePoller.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_TrufflePoller.java
new file mode 100644
index 000000000000..78c12db9c48e
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_TrufflePoller.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnio.impl;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.util.Set;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.io.Throw;
+import com.oracle.truffle.espresso.io.TruffleIO;
+import com.oracle.truffle.espresso.libs.LibsState;
+import com.oracle.truffle.espresso.libs.libnio.LibNio;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Lsun/nio/ch/TrufflePoller;", group = LibNio.class)
+public final class Target_sun_nio_ch_TrufflePoller {
+ @Substitution
+ public static int init(@Inject LibsState libsState) {
+ return Math.toIntExact(libsState.net.handlifySelector());
+ }
+
+ @Substitution
+ public static void deregister(int id, int fd, @Inject LibsState libsState) {
+ SelectionKey selKey = libsState.net.getSelectionKey(id, fd);
+ if (selKey != null) {
+ selKey.cancel();
+ libsState.net.removeSelectionKey(id, fd);
+ }
+
+ }
+
+ @Substitution
+ public static void register(int id, int fd, int newEvents,
+ @Inject LibsState libsState,
+ @Inject TruffleIO io) {
+ SelectionKey key = libsState.net.setInterestOpsOrRegister(id, fd, newEvents, io);
+ /*
+ * We need to call wake up since Epoll.wait() sees new registrations while waiting where as
+ * the selector does not. Therefore, we force the selector to wake up to see the
+ * registration. Note that the next select call will return immediately but this should be
+ * okay since it is caller is a while(true) loop see: sun.nio.ch.Poller.pollLoop
+ */
+ key.selector().wakeup();
+ }
+
+ @Substitution
+ public static int doSelect(int id, long timeout, @Inject LibsState libsState, @Inject EspressoContext ctx) {
+ Selector selector = libsState.net.getSelector(id);
+ try {
+ if (timeout == 0) {
+ return selector.selectNow();
+ } else if (timeout == -1) {
+ return selector.select();
+ } else if (timeout > 0) {
+ return selector.select(timeout);
+ }
+ throw Throw.throwIOException("timeout should be >= -1", ctx);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
+ }
+
+ @Substitution
+ @TruffleBoundary
+ public static @JavaType(int[].class) StaticObject getReadyFds(int id, @Inject LibsState libsState, @Inject EspressoContext ctx, @Inject Meta meta) {
+ // We need to ensure that all events are one-shot, meaning they should only be polled once.
+ // This is done via synchronization and clearing the interestOps.
+ Selector selector = libsState.net.getSelector(id);
+ synchronized (selector) {
+ Set selectedKeys = selector.selectedKeys();
+ int[] fds = new int[selectedKeys.size()];
+ int i = 0;
+ for (SelectionKey key : selectedKeys) {
+ // Check if the key is valid
+ if (key.isValid()) {
+ int fd = libsState.net.getFdOfSelectionKey(key);
+ if (fd == 0) {
+ // indicates an invalid fd
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ fds[i] = fd;
+ i++;
+ key.interestOps(0);
+ }
+ }
+ selectedKeys.clear();
+ return ctx.getAllocator().wrapArrayAs(meta._int_array, fds);
+ }
+ }
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_TruffleSelector.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_TruffleSelector.java
new file mode 100644
index 000000000000..fb67510262a6
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_ch_TruffleSelector.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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.truffle.espresso.libs.libnio.impl;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.util.Set;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.espresso.io.Throw;
+import com.oracle.truffle.espresso.io.TruffleIO;
+import com.oracle.truffle.espresso.libs.LibsState;
+import com.oracle.truffle.espresso.libs.libnio.LibNio;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
+import com.oracle.truffle.espresso.runtime.EspressoException;
+import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
+import com.oracle.truffle.espresso.substitutions.Inject;
+import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+import com.oracle.truffle.espresso.substitutions.JavaType;
+import com.oracle.truffle.espresso.substitutions.Substitution;
+
+@EspressoSubstitutions(type = "Lsun/nio/ch/TruffleSelector;", group = LibNio.class)
+public final class Target_sun_nio_ch_TruffleSelector {
+ @Substitution
+ public static int init(@Inject LibsState libsState) {
+ return Math.toIntExact(libsState.net.handlifySelector());
+ }
+
+ @Substitution
+ public static void deregister(int id, int fd, @Inject LibsState libsState) {
+ SelectionKey selKey = libsState.net.getSelectionKey(id, fd);
+ if (selKey != null) {
+ selKey.cancel();
+ libsState.net.removeSelectionKey(id, fd);
+ }
+ }
+
+ @Substitution
+ public static void register(int id, int fd, int newEvents,
+ @Inject LibsState libsState,
+ @Inject TruffleIO io) {
+ Selector selector = libsState.net.getSelector(id);
+ try {
+ SelectionKey key = io.register(fd, selector, newEvents);
+ libsState.net.putSelectionKey(id, fd, key);
+ } catch (EspressoException e) {
+ // We should not throw exceptions here according to the Selector API. In
+ // sun.nio.ch.EPollSelectorImpl.processUpdateQueue error numbers from the native
+ // sun.nio.ch.EPoll.ctl are just ignored. So we do the same here.
+ libsState.getLogger().warning(() -> "In io.register the following exception was ingored: " + e.toString());
+ }
+ }
+
+ @Substitution
+ public static void changeEvents(int id, int fd, int newEvents, @Inject LibsState libsState) {
+ SelectionKey selectionKey = libsState.net.getSelectionKey(id, fd);
+ if (selectionKey == null) {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ libsState.net.checkValidOps(selectionKey.channel(), newEvents);
+ selectionKey.interestOps(newEvents);
+ }
+
+ @Substitution
+ public static int doSelect(int id, long timeout, @Inject LibsState libsState, @Inject EspressoContext ctx) {
+ Selector selector = libsState.net.getSelector(id);
+ try {
+ if (timeout == 0) {
+ return selector.selectNow();
+ } else if (timeout == -1) {
+ return selector.select();
+ } else if (timeout > 0) {
+ return selector.select(timeout);
+ }
+ throw Throw.throwIOException("timeout should be >= -1", ctx);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
+ }
+
+ @Substitution
+ public static void wakeup(int id, @Inject LibsState libsState) {
+ Selector selector = libsState.net.getSelector(id);
+ selector.wakeup();
+ }
+
+ @Substitution
+ @TruffleBoundary
+ public static void close(int id, @Inject LibsState libsState, @Inject EspressoContext ctx) {
+ Selector selector = libsState.net.getSelector(id);
+ libsState.net.freeSelector(id);
+ try {
+ selector.close();
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
+ }
+
+ @Substitution
+ @TruffleBoundary
+ public static @JavaType(long[].class) StaticObject processEvents(int id, @Inject LibsState libsState, @Inject EspressoContext ctx, @Inject Meta meta) {
+ Selector selector = libsState.net.getSelector(id);
+ Set selectedKeys = selector.selectedKeys();
+ long[] fdAndOps = new long[selectedKeys.size()];
+ int i = 0;
+ for (SelectionKey key : selectedKeys) {
+ // Check if the key is valid
+ if (key.isValid()) {
+ // Get the ready ops for the key
+ int readyOps = key.readyOps();
+ int fd = libsState.net.getFdOfSelectionKey(key);
+ if (fd == 0) {
+ throw JavaSubstitution.shouldNotReachHere();
+ }
+ fdAndOps[i] = ((long) readyOps << 32) | (fd & 0xFFFFFFFFL);
+ i++;
+ }
+ }
+ selectedKeys.clear();
+ return ctx.getAllocator().wrapArrayAs(meta._long_array, fdAndOps);
+ }
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_fs_TruffleFileSystemProvider.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_fs_TruffleFileSystemProvider.java
index 333604edaf25..6058ea347117 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_fs_TruffleFileSystemProvider.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_fs_TruffleFileSystemProvider.java
@@ -26,20 +26,36 @@
import java.io.FileDescriptor;
import java.io.IOException;
-import java.nio.channels.FileChannel;
+import java.nio.file.CopyOption;
+import java.nio.file.OpenOption;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.TruffleFile;
+import com.oracle.truffle.espresso.io.FDAccess;
+import com.oracle.truffle.espresso.io.Throw;
import com.oracle.truffle.espresso.io.TruffleIO;
import com.oracle.truffle.espresso.libs.libnio.LibNio;
import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
import com.oracle.truffle.espresso.substitutions.Inject;
-import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
import com.oracle.truffle.espresso.substitutions.JavaType;
import com.oracle.truffle.espresso.substitutions.Substitution;
import com.oracle.truffle.espresso.substitutions.Throws;
+/*
+Can use ctx.getTruffleIO().getPublicTruffleFileSafe(path) to get a Trufflefile from a path
+ */
@EspressoSubstitutions(type = "Lsun/nio/fs/TruffleFileSystemProvider;", group = LibNio.class)
public final class Target_sun_nio_fs_TruffleFileSystemProvider {
@@ -50,89 +66,238 @@ public final class Target_sun_nio_fs_TruffleFileSystemProvider {
}
@Substitution
- @Throws(IOException.class)
- @SuppressWarnings("unused")
- public static @JavaType(FileChannel.class) StaticObject newFileChannel0(
+ @TruffleBoundary
+ public static void newFileChannel0(
@JavaType(internalName = TRUFFLE_PATH) StaticObject path,
@JavaType(FileDescriptor.class) StaticObject fileDescriptor,
- int openOptionsMask) {
- throw JavaSubstitution.unimplemented();
+ int openOptionsMask, int fileAttributeMask, @Inject TruffleIO io) {
+ // decode openOptionsMask to avoid guest/host Object passing
+ Set extends OpenOption> options = maskToOpenOptions(openOptionsMask);
+ TruffleFile tf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(path);
+ // populate fd
+ io.open(fileDescriptor, FDAccess.forFileDescriptor(), tf, options, toFileAttribute(fileAttributeMask, io));
}
@Substitution
+ @TruffleBoundary
@Throws(IOException.class)
- @SuppressWarnings("unused")
- public static void createDirectory0(@JavaType(internalName = TRUFFLE_PATH) StaticObject path) {
- throw JavaSubstitution.unimplemented();
+ public static void createDirectory0(@JavaType(internalName = TRUFFLE_PATH) StaticObject path, int fileAttributeMask, @Inject TruffleIO io, @Inject EspressoContext ctx) {
+ TruffleFile tf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(path);
+
+ try {
+ tf.createDirectory(toFileAttribute(fileAttributeMask, io));
+ tf.setPosixPermissions(Set.of(PosixFilePermission.values()));
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
+ }
+
+ private static FileAttribute>[] toFileAttribute(int mask, TruffleIO io) {
+ if (mask == 0) {
+ return new FileAttribute>[0];
+ }
+ Set perms = new HashSet<>();
+ if ((mask & io.fileAttributeParserSync.OWNER_READ_VALUE) != 0) {
+ perms.add(PosixFilePermission.OWNER_READ);
+ }
+ if ((mask & io.fileAttributeParserSync.OWNER_WRITE_VALUE) != 0) {
+ perms.add(PosixFilePermission.OWNER_WRITE);
+ }
+ if ((mask & io.fileAttributeParserSync.OWNER_EXECUTE_VALUE) != 0) {
+ perms.add(PosixFilePermission.OWNER_EXECUTE);
+ }
+
+ if ((mask & io.fileAttributeParserSync.GROUP_READ_VALUE) != 0) {
+ perms.add(PosixFilePermission.GROUP_READ);
+ }
+ if ((mask & io.fileAttributeParserSync.GROUP_WRITE_VALUE) != 0) {
+ perms.add(PosixFilePermission.GROUP_WRITE);
+ }
+ if ((mask & io.fileAttributeParserSync.GROUP_EXECUTE_VALUE) != 0) {
+ perms.add(PosixFilePermission.GROUP_EXECUTE);
+ }
+
+ if ((mask & io.fileAttributeParserSync.OTHERS_READ_VALUE) != 0) {
+ perms.add(PosixFilePermission.OTHERS_READ);
+ }
+ if ((mask & io.fileAttributeParserSync.OTHERS_WRITE_VALUE) != 0) {
+ perms.add(PosixFilePermission.OTHERS_WRITE);
+ }
+ if ((mask & io.fileAttributeParserSync.OTHERS_EXECUTE_VALUE) != 0) {
+ perms.add(PosixFilePermission.OTHERS_EXECUTE);
+ }
+ return new FileAttribute>[]{PosixFilePermissions.asFileAttribute(perms)};
}
@Substitution
@Throws(IOException.class)
- @SuppressWarnings("unused")
- public static void delete0(@JavaType(internalName = TRUFFLE_PATH) StaticObject path) {
- throw JavaSubstitution.unimplemented();
+ public static void delete0(@JavaType(internalName = TRUFFLE_PATH) StaticObject path, @Inject TruffleIO io, @Inject EspressoContext ctx) {
+ TruffleFile tf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(path);
+ try {
+ tf.delete();
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
}
@Substitution
+ @TruffleBoundary
@Throws(IOException.class)
- @SuppressWarnings("unused")
public static void copy0(
@JavaType(internalName = TRUFFLE_PATH) StaticObject source,
@JavaType(internalName = TRUFFLE_PATH) StaticObject target,
- int copyOptions) {
- throw JavaSubstitution.unimplemented();
+ int copyOptions, @Inject TruffleIO io, @Inject EspressoContext ctx) {
+ TruffleFile sourceTf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(source);
+ TruffleFile targetTf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(target);
+ Set copyOptionsSet = maskToCopyOptions(copyOptions);
+ try {
+ sourceTf.copy(targetTf, copyOptionsSet.toArray(new CopyOption[0]));
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
}
@Substitution
+ @TruffleBoundary
@Throws(IOException.class)
- @SuppressWarnings("unused")
public static void move0(
@JavaType(internalName = TRUFFLE_PATH) StaticObject source,
@JavaType(internalName = TRUFFLE_PATH) StaticObject target,
- int copyOptions) {
- throw JavaSubstitution.unimplemented();
+ int copyOptions, @Inject TruffleIO io, @Inject EspressoContext ctx) {
+ TruffleFile sourceTf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(source);
+ TruffleFile targetTf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(target);
+ Set copyOptionsSet = maskToCopyOptions(copyOptions);
+ try {
+ sourceTf.move(targetTf, copyOptionsSet.toArray(new CopyOption[0]));
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
}
@Substitution
@Throws(IOException.class)
- @SuppressWarnings("unused")
public static boolean isSameFile0(
- @JavaType(internalName = TRUFFLE_PATH) StaticObject path,
- @JavaType(internalName = TRUFFLE_PATH) StaticObject path2) {
- throw JavaSubstitution.unimplemented();
+ @JavaType(internalName = TRUFFLE_PATH) StaticObject path1,
+ @JavaType(internalName = TRUFFLE_PATH) StaticObject path2, @Inject TruffleIO io, @Inject EspressoContext ctx) {
+ TruffleFile tf1 = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(path1);
+ TruffleFile tf2 = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(path2);
+ try {
+ return tf1.isSameFile(tf2);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
+
}
@Substitution
+ @TruffleBoundary
@Throws(IOException.class)
- @SuppressWarnings("unused")
public static void checkAccess0(
@JavaType(internalName = TRUFFLE_PATH) StaticObject path,
- int accessModesMask) {
- throw JavaSubstitution.unimplemented();
+ int accessModesMask, @Inject TruffleIO io, @Inject EspressoContext ctx) {
+ // TruffleFile does not have a checkAccess API. So we explicit call the method
+ // corresponding to the accessMode-check.
+ TruffleFile tf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(path);
+ if (!tf.exists()) {
+ throw Throw.throwIOException("No such file: " + tf.getPath(), ctx);
+ }
+ if ((accessModesMask & (1 << 0)) != 0 && !(tf.isReadable())) {
+ throw Throw.throwIOException("Read Access was denied for path: " + tf.getPath(), ctx);
+ }
+
+ if ((accessModesMask & (1 << 1)) != 0 && !(tf.isWritable())) {
+ throw Throw.throwIOException("Write Access was denied for path: " + tf.getPath(), ctx);
+ }
+
+ if ((accessModesMask & (1 << 2)) != 0 && !(tf.isExecutable())) {
+ throw Throw.throwIOException("Executable Access was denied for path: " + tf.getPath(), ctx);
+ }
}
@Substitution
+ @TruffleBoundary
@Throws(IOException.class)
- @SuppressWarnings("unused")
public static void createSymbolicLink0(
@JavaType(internalName = TRUFFLE_PATH) StaticObject link,
- @JavaType(internalName = TRUFFLE_PATH) StaticObject target) {
- throw JavaSubstitution.unimplemented();
+ @JavaType(internalName = TRUFFLE_PATH) StaticObject target, int fileAttributeMask, @Inject TruffleIO io, @Inject EspressoContext ctx) {
+ TruffleFile linkTf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(link);
+ TruffleFile targetTf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(target);
+ try {
+ linkTf.createSymbolicLink(targetTf, toFileAttribute(fileAttributeMask, io));
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
}
@Substitution
@Throws(IOException.class)
- @SuppressWarnings("unused")
public static void createLink0(
@JavaType(internalName = TRUFFLE_PATH) StaticObject link,
- @JavaType(internalName = TRUFFLE_PATH) StaticObject existing) {
- throw JavaSubstitution.unimplemented();
+ @JavaType(internalName = TRUFFLE_PATH) StaticObject target, @Inject TruffleIO io, @Inject EspressoContext ctx) {
+ TruffleFile linkTf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(link);
+ TruffleFile targetTf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(target);
+ try {
+ linkTf.createLink(targetTf);
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
+
}
@Substitution
- @Throws(IOException.class)
- @SuppressWarnings("unused")
- public static @JavaType(String.class) StaticObject readSymbolicLink0(@JavaType(internalName = TRUFFLE_PATH) StaticObject link) {
- throw JavaSubstitution.unimplemented();
+ public static @JavaType(String.class) StaticObject readSymbolicLink0(@JavaType(internalName = TRUFFLE_PATH) StaticObject link, @Inject TruffleIO io, @Inject EspressoContext ctx,
+ @Inject Meta meta) {
+ TruffleFile linkTf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(link);
+ try {
+ return meta.toGuestString(linkTf.readSymbolicLink().getPath());
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
}
+
+ // TODO(peterssen): Add NO_FOLLOW_LINKS?
+ // Keep in sync with TruffleFileSystemProvider#SUPPORTED_COPY_OPTIONS.
+ private static final List SUPPORTED_OPEN_OPTIONS_HOST = Collections.unmodifiableList(List.of(
+ StandardOpenOption.READ,
+ StandardOpenOption.WRITE,
+ StandardOpenOption.APPEND,
+ StandardOpenOption.TRUNCATE_EXISTING,
+ StandardOpenOption.CREATE,
+ StandardOpenOption.CREATE_NEW,
+ StandardOpenOption.DELETE_ON_CLOSE,
+ StandardOpenOption.SPARSE,
+ StandardOpenOption.SYNC,
+ StandardOpenOption.DSYNC));
+
+ // TODO(peterssen): Add NO_FOLLOW_LINKS?
+ // Keep in sync with TruffleFileSystemProvider#SUPPORTED_COPY_OPTIONS.
+ private static final List SUPPORTED_COPY_OPTIONS = Collections.unmodifiableList(List.of(
+ StandardCopyOption.REPLACE_EXISTING,
+ StandardCopyOption.COPY_ATTRIBUTES,
+ StandardCopyOption.ATOMIC_MOVE));
+
+ @TruffleBoundary
+ public static Set maskToOpenOptions(int openOptionsMask) {
+ // Use a general Set instead of EnumSet if non-enum options exist
+ Set options = new HashSet<>();
+ for (int i = 0; i < SUPPORTED_OPEN_OPTIONS_HOST.size(); i++) {
+ if ((openOptionsMask & (1 << i)) != 0) {
+ options.add(SUPPORTED_OPEN_OPTIONS_HOST.get(i));
+ }
+ }
+
+ return options;
+ }
+
+ @TruffleBoundary
+ public static Set maskToCopyOptions(int mask) {
+ Set options = new HashSet<>();
+ for (int i = 0; i < SUPPORTED_COPY_OPTIONS.size(); i++) {
+ if ((mask & (1 << i)) != 0) {
+ options.add(SUPPORTED_COPY_OPTIONS.get(i));
+ }
+ }
+ return options;
+ }
+
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_fs_TruffleFilteredDirectoryStream.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_fs_TruffleFilteredDirectoryStream.java
index ef37c29ee5bf..96b963ecbb17 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_fs_TruffleFilteredDirectoryStream.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libnio/impl/Target_sun_nio_fs_TruffleFilteredDirectoryStream.java
@@ -28,57 +28,116 @@
import java.nio.file.DirectoryStream;
import java.util.Iterator;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.TruffleFile;
+import com.oracle.truffle.espresso.impl.Klass;
+import com.oracle.truffle.espresso.io.Throw;
+import com.oracle.truffle.espresso.io.TruffleIO;
+import com.oracle.truffle.espresso.libs.LibsMeta;
+import com.oracle.truffle.espresso.libs.LibsState;
import com.oracle.truffle.espresso.libs.libnio.LibNio;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
-import com.oracle.truffle.espresso.substitutions.JavaSubstitution;
+import com.oracle.truffle.espresso.substitutions.Inject;
import com.oracle.truffle.espresso.substitutions.JavaType;
import com.oracle.truffle.espresso.substitutions.Substitution;
import com.oracle.truffle.espresso.substitutions.Throws;
-@EspressoSubstitutions(group = LibNio.class)
+@EspressoSubstitutions(type = "Lsun/nio/fs/TruffleFilteredDirectoryStream;", group = LibNio.class)
public final class Target_sun_nio_fs_TruffleFilteredDirectoryStream {
@Substitution
@Throws(IOException.class)
@SuppressWarnings("unused")
+ @TruffleBoundary
public static @JavaType(DirectoryStream.class) StaticObject directoryStream0(
@JavaType(internalName = TRUFFLE_PATH) StaticObject dir,
- @JavaType(Class.class) StaticObject directoryStreamClass) {
- throw JavaSubstitution.unimplemented();
+ @JavaType(Class.class) StaticObject directoryStreamClass,
+ @Inject LibsState libsState,
+ @Inject TruffleIO io,
+ @Inject EspressoContext context,
+ @Inject LibsMeta lMeta) {
+ TruffleFile tf = (TruffleFile) io.sun_nio_fs_TrufflePath_HIDDEN_TRUFFLE_FILE.getHiddenObject(dir);
+ try {
+ DirectoryStream hostStream = tf.newDirectoryStream();
+
+ Klass clazz = directoryStreamClass.getMirrorKlass(context.getMeta());
+ @JavaType(internalName = "Lsun/nio/fs/TruffleFilteredDirectoryStream$ForeignDirectoryStream;")
+ StaticObject guestStream = clazz.allocateInstance(context);
+ lMeta.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream_init.invokeDirectSpecial(
+ /* this */ guestStream);
+ lMeta.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream_HIDDEN_HOST_REFERENCE.setHiddenObject(guestStream, hostStream);
+ return guestStream;
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, context);
+ }
}
@Substitution
- @SuppressWarnings("unused")
- public static boolean hasNext0(@JavaType(Iterator.class) StaticObject iterator) {
- throw JavaSubstitution.unimplemented();
+ @SuppressWarnings({"unused", "unchecked"})
+ @TruffleBoundary
+ public static boolean hasNext0(@JavaType(Iterator.class) StaticObject iterator, @Inject LibsState libsState, @Inject EspressoContext ctx, @Inject LibsMeta lMeta) {
+ Iterator hostIterator = (Iterator) lMeta.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator_HIDDEN_HOST_REFERENCE.getHiddenObject(iterator);
+ if (hostIterator == null) {
+ throw Throw.throwIllegalArgumentException("iterator", ctx);
+ }
+ return hostIterator.hasNext();
}
@Substitution
- @SuppressWarnings("unused")
- public static @JavaType(Object.class) StaticObject next0(@JavaType(Iterator.class) StaticObject iterator) {
- throw JavaSubstitution.unimplemented();
+ @SuppressWarnings({"unused", "unchecked"})
+ @TruffleBoundary
+ public static @JavaType(String.class) StaticObject next0(@JavaType(Iterator.class) StaticObject iterator, @Inject LibsState libsState,
+ @Inject EspressoContext ctx,
+ @Inject LibsMeta lMeta) {
+ Iterator hostIterator = (Iterator) lMeta.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator_HIDDEN_HOST_REFERENCE.getHiddenObject(iterator);
+ if (hostIterator == null) {
+ throw Throw.throwIllegalArgumentException("iterator", ctx);
+ }
+ return ctx.getMeta().toGuestString(hostIterator.next().getName());
}
@Substitution
@Throws(IOException.class)
- @SuppressWarnings("unused")
- public static void close0(@JavaType(DirectoryStream.class) StaticObject directoryStream) {
- throw JavaSubstitution.unimplemented();
+ @SuppressWarnings({"unused", "unchecked"})
+ @TruffleBoundary
+ public static void close0(@JavaType(DirectoryStream.class) StaticObject directoryStream, @Inject LibsState libsState, @Inject EspressoContext ctx, @Inject LibsMeta lMeta) {
+ DirectoryStream hostStream = (DirectoryStream) lMeta.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream_HIDDEN_HOST_REFERENCE.getHiddenObject(
+ directoryStream);
+
+ if (hostStream == null) {
+ throw Throw.throwIllegalArgumentException("directoryStream", ctx);
+ }
+ try {
+ hostStream.close();
+ } catch (IOException e) {
+ throw Throw.throwIOException(e, ctx);
+ }
}
@Substitution
- @SuppressWarnings("unused")
+ @SuppressWarnings({"unused", "unchecked"})
+ @TruffleBoundary
public static @JavaType(Iterator.class) StaticObject iterator0(
@JavaType(DirectoryStream.class) StaticObject directoryStream,
- @JavaType(Class.class) StaticObject iteratorClass) {
- throw JavaSubstitution.unimplemented();
+ @JavaType(Class.class) StaticObject iteratorClass,
+ @Inject EspressoContext ctx, @Inject LibsState libsState,
+ @Inject LibsMeta lMeta) {
+ // retrieve host stream
+ DirectoryStream hostStream = (DirectoryStream) lMeta.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignDirectoryStream_HIDDEN_HOST_REFERENCE.getHiddenObject(
+ directoryStream);
+ if (hostStream == null) {
+ throw Throw.throwIllegalArgumentException("directoryStream", ctx);
+ }
+ // allocate guest Iterator
+ Klass clazz = iteratorClass.getMirrorKlass(ctx.getMeta());
+ @JavaType(internalName = "Lsun/nio/fs/TruffleFilteredDirectoryStream$ForeignIterator;")
+ StaticObject guestIterator = clazz.allocateInstance(ctx);
+ lMeta.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator_init.invokeDirectSpecial(
+ /* this */ guestIterator);
+ // link guest and host iterator
+ lMeta.sun_nio_fs_TruffleFilteredDirectoryStream$ForeignIterator_HIDDEN_HOST_REFERENCE.setHiddenObject(guestIterator, hostStream.iterator());
+ return guestIterator;
}
- @Substitution
- @SuppressWarnings("unused")
- public static @JavaType(internalName = TRUFFLE_PATH) StaticObject toTrufflePath0(
- @JavaType(Object.class) StaticObject truffleFile,
- @JavaType(internalName = "Lsun/nio/fs/TruffleFileSystem;") StaticObject truffleFileSystem) {
- throw JavaSubstitution.unimplemented();
- }
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libzip/impl/Target_java_util_zip_CRC32.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libzip/impl/Target_java_util_zip_CRC32.java
index 17510dd954d8..9859971a5dd7 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libzip/impl/Target_java_util_zip_CRC32.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libzip/impl/Target_java_util_zip_CRC32.java
@@ -25,8 +25,8 @@
import java.util.zip.CRC32;
import com.oracle.truffle.espresso.EspressoLanguage;
+import com.oracle.truffle.espresso.libs.LibsMeta;
import com.oracle.truffle.espresso.libs.libzip.LibZip;
-import com.oracle.truffle.espresso.meta.Meta;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
import com.oracle.truffle.espresso.substitutions.Inject;
@@ -35,54 +35,54 @@
@EspressoSubstitutions(value = CRC32.class, group = LibZip.class)
public final class Target_java_util_zip_CRC32 {
- private static CRC32 getHostCRC32(StaticObject crc, Meta meta) {
+ private static CRC32 getHostCRC32(StaticObject crc, LibsMeta lMeta) {
if (StaticObject.isNull(crc)) {
- throw meta.throwNullPointerException();
+ throw lMeta.getMeta().throwNullPointerException();
}
- Object hostCRC = meta.HIDDEN_CRC32.getHiddenObject(crc);
+ Object hostCRC = lMeta.HIDDEN_CRC32.getHiddenObject(crc);
assert hostCRC != null;
return (CRC32) hostCRC;
}
@Substitution
public static void init(@JavaType(CRC32.class) StaticObject crc,
- @Inject Meta meta) {
- meta.HIDDEN_CRC32.setHiddenObject(crc, new CRC32());
+ @Inject LibsMeta lMeta) {
+ lMeta.HIDDEN_CRC32.setHiddenObject(crc, new CRC32());
}
@Substitution
public static void update0(@JavaType(CRC32.class) StaticObject crc, int b,
- @Inject Meta meta) {
+ @Inject LibsMeta lMeta) {
try {
- getHostCRC32(crc, meta).update(b);
+ getHostCRC32(crc, lMeta).update(b);
} catch (IndexOutOfBoundsException e) {
- meta.throwExceptionWithMessage(meta.java_lang_IndexOutOfBoundsException, e.getMessage());
+ lMeta.getMeta().throwExceptionWithMessage(lMeta.getMeta().java_lang_IndexOutOfBoundsException, e.getMessage());
}
}
@Substitution
public static void updateBytes0(@JavaType(CRC32.class) StaticObject crc, @JavaType(byte[].class) StaticObject b, int off, int len,
- @Inject Meta meta, @Inject EspressoLanguage lang) {
+ @Inject LibsMeta lMeta, @Inject EspressoLanguage lang) {
if (StaticObject.isNull(b)) {
- throw meta.throwNullPointerException();
+ throw lMeta.getMeta().throwNullPointerException();
}
assert b.isArray();
try {
- getHostCRC32(crc, meta).update(b.unwrap(lang), off, len);
+ getHostCRC32(crc, lMeta).update(b.unwrap(lang), off, len);
} catch (IndexOutOfBoundsException e) {
- meta.throwExceptionWithMessage(meta.java_lang_IndexOutOfBoundsException, e.getMessage());
+ lMeta.getMeta().throwExceptionWithMessage(lMeta.getMeta().java_lang_IndexOutOfBoundsException, e.getMessage());
}
}
@Substitution
public static long getValue0(@JavaType(CRC32.class) StaticObject crc,
- @Inject Meta meta) {
- return getHostCRC32(crc, meta).getValue();
+ @Inject LibsMeta lMeta) {
+ return getHostCRC32(crc, lMeta).getValue();
}
@Substitution
public static void reset0(@JavaType(CRC32.class) StaticObject crc,
- @Inject Meta meta) {
- getHostCRC32(crc, meta).reset();
+ @Inject LibsMeta lMeta) {
+ getHostCRC32(crc, lMeta).reset();
}
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libzip/impl/Target_java_util_zip_Inflater.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libzip/impl/Target_java_util_zip_Inflater.java
index ab5275c5d9e2..2f1ded8c0660 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libzip/impl/Target_java_util_zip_Inflater.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/libs/libzip/impl/Target_java_util_zip_Inflater.java
@@ -22,22 +22,22 @@
*/
package com.oracle.truffle.espresso.libs.libzip.impl;
-import java.nio.ByteBuffer;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.espresso.EspressoLanguage;
-import com.oracle.truffle.espresso.ffi.nfi.NativeUtils;
+import com.oracle.truffle.espresso.ffi.memory.NativeMemory;
+import com.oracle.truffle.espresso.io.TruffleIO;
+import com.oracle.truffle.espresso.libs.LibsMeta;
import com.oracle.truffle.espresso.libs.LibsState;
import com.oracle.truffle.espresso.libs.libzip.LibZip;
-import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
import com.oracle.truffle.espresso.substitutions.Inject;
import com.oracle.truffle.espresso.substitutions.JavaType;
import com.oracle.truffle.espresso.substitutions.Substitution;
-import com.oracle.truffle.espresso.substitutions.VersionFilter;
/**
* EspressoLibs substitution for the Inflater class. The implementation associates a HostInflater
@@ -73,18 +73,25 @@ public static void setDictionary(long addr, @JavaType(byte[].class) StaticObject
libsState.getInflater(addr).setDictionary(byteArrayB, off, len);
}
- @Substitution(languageFilter = VersionFilter.Java11OrLater.class)
- public static void setDictionaryBuffer(long addr, long bufAddress, int len, @Inject LibsState libsState) {
- ByteBuffer dst = NativeUtils.directByteBuffer(bufAddress, len);
- libsState.getInflater(addr).setDictionary(dst);
+ @Substitution
+ @TruffleBoundary
+ public static void setDictionaryBuffer(long addr, long bufAddress, int len, @Inject LibsState libsState, @Inject EspressoContext ctx) {
+ NativeMemory nativeMemory = ctx.getNativeAccess().nativeMemory();
+ if (nativeMemory.isDirectBufferSupported()) {
+ libsState.getInflater(addr).setDictionary(nativeMemory.getDirectBuffer(bufAddress, len));
+ } else {
+ byte[] buff = new byte[len];
+ nativeMemory.readMemory(bufAddress, len, buff);
+ libsState.getInflater(addr).setDictionary(buff, 0, len);
+ }
}
- @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java11OrLater.class)
+ @Substitution(hasReceiver = true)
@TruffleBoundary
public static long inflateBytesBytes(@JavaType(Inflater.class) StaticObject guestInflater, long addr,
@JavaType(byte[].class) StaticObject inputArray, int inputOff, int inputLen,
@JavaType(byte[].class) StaticObject outputArray, int outputOff, int outputLen,
- @Inject LibsState libsState, @Inject Meta meta, @Inject EspressoLanguage language) {
+ @Inject LibsState libsState, @Inject LibsMeta libsMeta, @Inject EspressoLanguage language) {
// get Input/Output Array/Buffer
byte[] inputByteArray = inputArray.unwrap(language);
byte[] outputByteArray = outputArray.unwrap(language);
@@ -95,23 +102,25 @@ public static long inflateBytesBytes(@JavaType(Inflater.class) StaticObject gues
long bytesReadOld = hostInflater.getBytesRead();
long bytesWrittenOld = hostInflater.getBytesWritten();
try {
+ // do inflate and encode result
+ outputByteArray = outputArray.unwrap(language);
int written = hostInflater.inflate(outputByteArray, outputOff, outputLen);
int read = Math.toIntExact(hostInflater.getBytesRead() - bytesReadOld);
return encodeResult(read, written, hostInflater);
} catch (DataFormatException e) {
- updateGuestInflater(hostInflater, bytesReadOld, bytesWrittenOld, guestInflater, meta);
- throw meta.throwExceptionWithMessage(meta.java_util_zip_DataFormatException, e.getMessage());
+ updateGuestInflater(hostInflater, bytesReadOld, bytesWrittenOld, guestInflater, libsMeta);
+ throw libsMeta.getMeta().throwExceptionWithMessage(libsMeta.java_util_zip_DataFormatException, e.getMessage());
}
}
- @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java11OrLater.class)
+ @Substitution(hasReceiver = true)
public static long inflateBytesBuffer(@JavaType(Inflater.class) StaticObject guestInflater, long addr,
@JavaType(byte[].class) StaticObject inputArray, int inputOff, int inputLen,
- long outputAddress, int outputLen, @Inject LibsState libsState,
- @Inject Meta meta, @Inject EspressoLanguage lang) {
+ long outputAddress, int outputLen,
+ @Inject LibsState libsState, @Inject LibsMeta libsMeta,
+ @Inject EspressoLanguage language, @Inject EspressoContext ctx) {
// get Input/Output Array/Buffer
- byte[] inputByteArray = inputArray.unwrap(lang);
- ByteBuffer outputByteBuffer = NativeUtils.directByteBuffer(outputAddress, outputLen);
+ byte[] inputByteArray = inputArray.unwrap(language);
// get host Inflater and set Input
Inflater hostInflater = libsState.getInflater(addr);
hostInflater.setInput(inputByteArray, inputOff, inputLen);
@@ -119,103 +128,71 @@ public static long inflateBytesBuffer(@JavaType(Inflater.class) StaticObject gue
long bytesReadOld = hostInflater.getBytesRead();
long bytesWrittenOld = hostInflater.getBytesWritten();
try {
- int written = hostInflater.inflate(outputByteBuffer);
+ // do inflate and encode result
+ int written = inflateFromAddress(outputAddress, outputLen, hostInflater, ctx);
int read = Math.toIntExact(hostInflater.getBytesRead() - bytesReadOld);
return encodeResult(read, written, hostInflater);
} catch (DataFormatException e) {
- updateGuestInflater(hostInflater, bytesReadOld, bytesWrittenOld, guestInflater, meta);
- throw meta.throwExceptionWithMessage(meta.java_util_zip_DataFormatException, e.getMessage());
+ updateGuestInflater(hostInflater, bytesReadOld, bytesWrittenOld, guestInflater, libsMeta);
+ throw libsMeta.getMeta().throwExceptionWithMessage(libsMeta.java_util_zip_DataFormatException, e.getMessage());
}
}
- @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java11OrLater.class)
+ @Substitution(hasReceiver = true)
public static long inflateBufferBytes(@JavaType(Inflater.class) StaticObject guestInflater, long addr,
long inputAddress, int inputLen,
@JavaType(byte[].class) StaticObject outputArray, int outputOff, int outputLen,
- @Inject LibsState libsState, @Inject Meta meta,
- @Inject EspressoLanguage lang) {
+ @Inject LibsState libsState, @Inject LibsMeta libsMeta, @Inject EspressoLanguage language,
+ @Inject EspressoContext ctx) {
- // get Input/Output Array/Buffer
- ByteBuffer inputByteBuffer = NativeUtils.directByteBuffer(inputAddress, inputLen);
- byte[] outputByteArray = outputArray.unwrap(lang);
// get host Inflater and set Input
Inflater hostInflater = libsState.getInflater(addr);
- hostInflater.setInput(inputByteBuffer);
+ setInputFromAddress(inputAddress, inputLen, hostInflater, ctx);
// cache bytes/read/written for the exception case
long bytesReadOld = hostInflater.getBytesRead();
long bytesWrittenOld = hostInflater.getBytesWritten();
try {
+ // do inflate and encode result
+ byte[] outputByteArray = outputArray.unwrap(language);
int written = hostInflater.inflate(outputByteArray, outputOff, outputLen);
int read = Math.toIntExact(hostInflater.getBytesRead() - bytesReadOld);
return encodeResult(read, written, hostInflater);
} catch (DataFormatException e) {
- updateGuestInflater(hostInflater, bytesReadOld, bytesWrittenOld, guestInflater, meta);
- throw meta.throwExceptionWithMessage(meta.java_util_zip_DataFormatException, e.getMessage());
+ updateGuestInflater(hostInflater, bytesReadOld, bytesWrittenOld, guestInflater, libsMeta);
+ throw libsMeta.getMeta().throwExceptionWithMessage(libsMeta.java_util_zip_DataFormatException, e.getMessage());
}
}
- @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java11OrLater.class)
+ @Substitution(hasReceiver = true)
@SuppressWarnings("unused")
public static long inflateBufferBuffer(@JavaType(Inflater.class) StaticObject guestInflater, long addr,
long inputAddress, int inputLen,
long outputAddress, int outputLen,
- @Inject LibsState libsState, @Inject Meta meta,
- @Inject EspressoLanguage lang) {
- // get Input/Output Array/Buffer
- ByteBuffer inputByteBuffer = NativeUtils.directByteBuffer(inputAddress, inputLen);
- ByteBuffer outputByteBuffer = NativeUtils.directByteBuffer(outputAddress, outputLen);
+ @Inject LibsState libsState, @Inject LibsMeta libsMeta, @Inject EspressoLanguage language,
+ @Inject EspressoContext ctx) {
// get host Inflater and set Input
Inflater hostInflater = libsState.getInflater(addr);
- hostInflater.setInput(inputByteBuffer);
+ setInputFromAddress(inputAddress, inputLen, hostInflater, ctx);
// cache bytes/read/written for the exception case
long bytesReadOld = hostInflater.getBytesRead();
long bytesWrittenOld = hostInflater.getBytesWritten();
try {
- int written = hostInflater.inflate(outputByteBuffer);
+ // do inflate and encode result
+ int written = inflateFromAddress(outputAddress, outputLen, hostInflater, ctx);
int read = Math.toIntExact(hostInflater.getBytesRead() - bytesReadOld);
return encodeResult(read, written, hostInflater);
} catch (DataFormatException e) {
- updateGuestInflater(hostInflater, bytesReadOld, bytesWrittenOld, guestInflater, meta);
- throw meta.throwExceptionWithMessage(meta.java_util_zip_DataFormatException, e.getMessage());
- }
- }
-
- @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java8OrEarlier.class)
- public static int inflateBytes(@JavaType(Inflater.class) StaticObject guestInflater, long addr,
- @JavaType(byte[].class) StaticObject outputArray,
- int outputOff, int outputLen,
- @Inject LibsState libsState, @Inject Meta meta,
- @Inject EspressoLanguage lang) {
- // get Input/Output Array/Buffer
- byte[] inputArr = meta.java_util_zip_Inflater_buf.getObject(guestInflater).unwrap(lang);
- int off = meta.java_util_zip_Inflater_off.getInt(guestInflater);
- int len = meta.java_util_zip_Inflater_len.getInt(guestInflater);
- byte[] outputByteArray = outputArray.unwrap(lang);
- // get host Inflater and set Input
- Inflater hostInflater = libsState.getInflater(addr);
- hostInflater.setInput(inputArr, off, len);
- // cache bytesReadOld
- long bytesReadOld = hostInflater.getBytesRead();
- try {
- int written = hostInflater.inflate(outputByteArray, outputOff, outputLen);
- // update fields
- int read = Math.toIntExact(hostInflater.getBytesRead() - bytesReadOld);
- meta.java_util_zip_Inflater_off.setInt(guestInflater, off + read);
- meta.java_util_zip_Inflater_len.setInt(guestInflater, hostInflater.getRemaining());
- meta.java_util_zip_Inflater_needDict.setBoolean(guestInflater, hostInflater.needsDictionary());
- meta.java_util_zip_Inflater_finished.setBoolean(guestInflater, hostInflater.finished());
- return written;
- } catch (DataFormatException e) {
- throw meta.throwExceptionWithMessage(meta.java_util_zip_DataFormatException, e.getMessage());
+ updateGuestInflater(hostInflater, bytesReadOld, bytesWrittenOld, guestInflater, libsMeta);
+ throw libsMeta.getMeta().throwExceptionWithMessage(libsMeta.java_util_zip_DataFormatException, e.getMessage());
}
}
private static void updateGuestInflater(Inflater hostInflater, long bytesReadOld, long bytesWrittenOld,
- @JavaType(Inflater.class) StaticObject guestInflater, Meta meta) {
+ @JavaType(Inflater.class) StaticObject guestInflater, LibsMeta libsMeta) {
int inputConsumed = Math.toIntExact(hostInflater.getBytesRead() - bytesReadOld);
int outputConsumed = Math.toIntExact(hostInflater.getBytesWritten() - bytesWrittenOld);
- meta.java_util_zip_Inflater_inputConsumed.setInt(guestInflater, inputConsumed);
- meta.java_util_zip_Inflater_outputConsumed.setInt(guestInflater, outputConsumed);
+ libsMeta.java_util_zip_Inflater_inputConsumed.setInt(guestInflater, inputConsumed);
+ libsMeta.java_util_zip_Inflater_outputConsumed.setInt(guestInflater, outputConsumed);
}
@Substitution
@@ -259,4 +236,28 @@ private static long encodeResult(int read, int written, Inflater hostInflater) {
return result;
}
+
+ private static void setInputFromAddress(long addr, int len, Inflater hostInflater, EspressoContext ctx) {
+ NativeMemory nativeMemory = ctx.getNativeAccess().nativeMemory();
+ if (nativeMemory.isDirectBufferSupported()) {
+ hostInflater.setInput(nativeMemory.getDirectBuffer(addr, len));
+ } else {
+ byte[] buff = new byte[len];
+ nativeMemory.readMemory(addr, len, buff);
+ hostInflater.setInput(buff);
+ }
+ }
+
+ private static int inflateFromAddress(long addr, int len, Inflater hostInflater, EspressoContext ctx) throws DataFormatException {
+ NativeMemory nativeMemory = ctx.getNativeAccess().nativeMemory();
+ int written = 0;
+ if (nativeMemory.isDirectBufferSupported()) {
+ written = hostInflater.inflate(nativeMemory.getDirectBuffer(addr, len));
+ } else {
+ byte[] outputBuff = new byte[len];
+ written = hostInflater.inflate(outputBuff);
+ nativeMemory.writeMemory(addr, len, outputBuff);
+ }
+ return written;
+ }
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/DiffVersionLoadHelper.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/DiffVersionLoadHelper.java
index 281638c03b57..dcbad253996c 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/DiffVersionLoadHelper.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/DiffVersionLoadHelper.java
@@ -31,39 +31,39 @@
import com.oracle.truffle.espresso.impl.Method;
import com.oracle.truffle.espresso.impl.ObjectKlass;
-final class DiffVersionLoadHelper {
+public final class DiffVersionLoadHelper {
private final Meta meta;
private Symbol name;
private Symbol type;
private Symbol signature;
- DiffVersionLoadHelper(Meta meta) {
+ public DiffVersionLoadHelper(Meta meta) {
this.meta = meta;
}
- DiffVersionLoadHelper klass(VersionRange range, Symbol t) {
+ public DiffVersionLoadHelper klass(VersionRange range, Symbol t) {
if (range.contains(meta.getJavaVersion())) {
this.type = t;
}
return this;
}
- ObjectKlass klass() {
+ public ObjectKlass klass() {
if (type == null) {
throw EspressoError.shouldNotReachHere();
}
return meta.knownKlass(type);
}
- ObjectKlass notRequiredKlass() {
+ public ObjectKlass notRequiredKlass() {
if (type == null) {
return null;
}
return meta.loadKlassWithBootClassLoader(type);
}
- DiffVersionLoadHelper method(VersionRange range, Symbol n, Symbol s) {
+ public DiffVersionLoadHelper method(VersionRange range, Symbol