+ * This factory method is intended for use in {@link CompilerDirectives#inCompiledCode()
+ * compiled code paths}.
+ *
+ * @since 25.1
+ */
+ public static HeapIsolationException create() {
+ return new HeapIsolationException();
+ }
+
+ /**
+ * Creates a new {@link HeapIsolationException} indicating that a host object cannot be unboxed
+ * because it was allocated in a foreign heap. For example, when
+ * {@link InteropLibrary#asHostObject(Object)} is invoked from within a polyglot isolate.
+ *
+ * In addition, a cause may be provided. The cause should only be set if the guest language code
+ * caused this problem. An example for this is a language specific proxy mechanism that invokes
+ * guest language code to describe an object. If the guest language code fails to execute and
+ * this interop exception is a valid interpretation of the error, then the error should be
+ * provided as cause. The cause can then be used by the source language as new exception cause
+ * if the {@link InteropException} is translated to a source language error. If the
+ * {@link InteropException} is discarded, then the cause will most likely get discarded by the
+ * source language as well. Note that the cause must be of type
+ * {@link com.oracle.truffle.api.exception.AbstractTruffleException} otherwise an
+ * {@link IllegalArgumentException} is thrown.
+ *
+ * This factory method is intended for use in {@link CompilerDirectives#inCompiledCode()
+ * compiled code paths}.
+ *
+ * @since 25.1
+ */
+ public static HeapIsolationException create(Throwable cause) {
+ return new HeapIsolationException(cause);
+ }
+}
diff --git a/truffle/src/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/InteropLibrary.java b/truffle/src/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/InteropLibrary.java
index 9d3fe707d143..13de7a460e82 100644
--- a/truffle/src/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/InteropLibrary.java
+++ b/truffle/src/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/InteropLibrary.java
@@ -141,6 +141,7 @@
*
{@link #hasBufferElements(Object) buffer elements}
@@ -962,6 +963,63 @@ public boolean hasMemberWriteSideEffects(Object receiver, String member) {
return false;
}
+ /**
+ * Returns {@code true} if the given receiver is a {@linkplain #isMetaObject(Object) meta
+ * object} that provides a {@linkplain #getStaticScope(Object) static scope}. A static scope
+ * represents the static or class-level members associated with the receiver's type, such as
+ * static fields or methods.
+ *
+ * Invoking this message must not cause any observable side effects.
+ *
+ * Only {@link #isMetaObject(Object) meta objects} are permitted to expose a static scope, for
+ * all non-meta objects this method must return {@code false}.
+ *
+ * By default, this method returns {@code false}.
+ *
+ * @see #getStaticScope(Object)
+ * @see #isMetaObject(Object)
+ * @since 25.1
+ */
+ @Abstract(ifExported = {"getStaticScope"})
+ public boolean hasStaticScope(Object receiver) {
+ return false;
+ }
+
+ /**
+ * Returns the static scope associated with the given receiver. The receiver must be a
+ * {@linkplain #isMetaObject(Object) meta object}. A static scope is an object that exposes
+ * static members, members whose values or behaviors are independent of any particular instance
+ * of the receiver.
+ *
+ * The static scope typically serves as an artificial or meta-level object that provides access
+ * to instance-independent members declared by the meta object. The returned object can be used
+ * as the receiver for interop messages such as {@link #readMember(Object, String) readMember},
+ * {@link #writeMember(Object, String, Object) writeMember}, and
+ * {@link #invokeMember(Object, String, Object...) invokeMember} when accessing static members.
+ *
+ * The returned static scope is always expected to be a {@link #isScope(Object) scope} and
+ * provide {@link #hasMembers(Object) members}, representing the receiver's static context.
+ *
+ * Examples:
+ *
+ * In Java, the static scope exposes static fields and methods of a class.
+ * In Python, the static scope exposes class-level attributes and methods, effectively
+ * corresponding to the members provided by the Python metaobject.
+ *
+ *
+ * @throws UnsupportedMessageException if and only if the receiver does not
+ * {@linkplain #hasStaticScope(Object) have a static scope}
+ * @see #hasStaticScope(Object)
+ * @see #isMetaObject(Object)
+ * @see #isScope(Object)
+ * @see #hasMembers(Object)
+ * @since 25.1
+ */
+ @Abstract(ifExported = {"hasStaticScope"})
+ public Object getStaticScope(Object receiver) throws UnsupportedMessageException {
+ throw UnsupportedMessageException.create();
+ }
+
// Hashes
/**
* Returns {@code true} if the receiver may have hash entries. Therefore, at least one of
@@ -2460,7 +2518,7 @@ public Class extends TruffleLanguage>> getLanguage(Object receiver) throws U
* @see #toDisplayString(Object)
* @since 25.1
*/
- @Abstract(ifExported = {"getLanguageId"}, ifExportedAsWarning = {"isScope", "hasLanguage"}, replacementOf = "hasLanguage(Object)", replacementMethod = "hasLanguageLegacy")
+ @Abstract(ifExported = {"getLanguageId"}, ifExportedAsWarning = {"hasLanguage"}, replacementOf = "hasLanguage(Object)", replacementMethod = "hasLanguageLegacy")
public boolean hasLanguageId(Object receiver) {
if (!hasLanguage(receiver)) {
return false;
@@ -2591,7 +2649,7 @@ public Object getMetaObject(Object receiver) throws UnsupportedMessageException
* @see TruffleLanguage#getLanguageView(Object, Object)
* @since 20.1
*/
- @Abstract(ifExported = {"hasLanguageId", "getLanguageId", "hasLanguage", "getLanguage", "isScope"})
+ @Abstract(ifExported = {"hasLanguageId", "getLanguageId", "hasLanguage", "getLanguage"})
@TruffleBoundary
public Object toDisplayString(Object receiver, boolean allowSideEffects) {
if (allowSideEffects) {
@@ -2630,7 +2688,7 @@ public final Object toDisplayString(Object receiver) {
*
* @since 20.1
*/
- @Abstract(ifExported = {"getMetaQualifiedName", "getMetaSimpleName", "isMetaInstance"})
+ @Abstract(ifExported = {"getMetaQualifiedName", "getMetaSimpleName", "isMetaInstance", "hasStaticScope"})
public boolean isMetaObject(Object receiver) {
return false;
}
@@ -2939,12 +2997,10 @@ public int identityHashCode(Object receiver) throws UnsupportedMessageException
/**
* Returns true if the value represents a scope object, else false.
- * The scope object contains variables as {@link #getMembers(Object) members} and has a
- * {@link InteropLibrary#toDisplayString(Object, boolean) scope display name}. It needs to be
- * associated with a {@link #getLanguage(Object) language}. The scope may return a
- * {@link InteropLibrary#getSourceLocation(Object) source location} that indicates the range of
- * the scope in the source code. The scope may have {@link #hasScopeParent(Object) parent
- * scopes}.
+ * The scope object contains variables as {@link #getMembers(Object) members}. The scope may
+ * return a {@link InteropLibrary#getSourceLocation(Object) source location} that indicates the
+ * range of the scope in the source code. The scope may have {@link #hasScopeParent(Object)
+ * parent scopes}.
*
* The {@link #getMembers(Object) members} of a scope represent all visible flattened variables,
* including all parent scopes, if any. The variables of the current scope must be listed first
@@ -2959,10 +3015,9 @@ public int identityHashCode(Object receiver) throws UnsupportedMessageException
* member elements providing the same {@link #asString(Object) name}.
*
* This method must not cause any observable side-effects. If this method is implemented then
- * also {@link #hasMembers(Object)} and {@link #toDisplayString(Object, boolean)} must be
- * implemented and {@link #hasSourceLocation(Object)} is recommended.
+ * also {@link #hasMembers(Object)} must be implemented and {@link #hasSourceLocation(Object)}
+ * is recommended.
*
- * @see #getLanguage(Object)
* @see #getMembers(Object)
* @see #hasScopeParent(Object)
* @since 20.3
@@ -3008,6 +3063,39 @@ public Object getScopeParent(Object receiver) throws UnsupportedMessageException
throw UnsupportedMessageException.create();
}
+ /**
+ * Returns {@code true} if the argument is wrapped Java host language object. This method must
+ * not cause any observable side-effects. If this method is implemented then also
+ * {@link #asHostObject(Object)} must be implemented.
+ *
+ * @see #asHostObject(Object)
+ * @since 25.1
+ */
+ @Abstract(ifExported = "asHostObject")
+ public boolean isHostObject(Object receiver) {
+ return false;
+ }
+
+ /**
+ * Returns the Java host object representation of the given Truffle guest object.
+ *
+ * Implementations of this method must not produce any observable side effects. If this method
+ * is implemented, {@link #isHostObject(Object)} must also be implemented and return
+ * {@code true} for the same receiver.
+ *
+ * @throws UnsupportedMessageException if {@link #isHostObject(Object)} returns {@code false}
+ * for the given receiver.
+ * @throws HeapIsolationException if the guest object represents a host object located in a
+ * foreign heap, for example in a polyglot isolate.
+ *
+ * @see #isHostObject(Object)
+ * @since 25.1
+ */
+ @Abstract(ifExported = "isHostObject")
+ public Object asHostObject(Object receiver) throws UnsupportedMessageException, HeapIsolationException {
+ throw UnsupportedMessageException.create();
+ }
+
/**
* Returns the library factory for the interop library. Short-cut for
* {@link LibraryFactory#resolve(Class) ResolvedLibrary.resolve(InteropLibrary.class)}.
@@ -3872,6 +3960,64 @@ public boolean isMemberInternal(Object receiver, String identifier) {
return result;
}
+ @Override
+ public boolean hasStaticScope(Object receiver) {
+ if (CompilerDirectives.inCompiledCode()) {
+ return delegate.hasStaticScope(receiver);
+ }
+ assert preCondition(receiver);
+ boolean result = delegate.hasStaticScope(receiver);
+ if (result) {
+ assert UNCACHED.isMetaObject(receiver) : violationPost(receiver, result);
+ assert assertHasStaticScope(receiver);
+ } else {
+ assert assertHasNoStaticScope(receiver);
+ }
+ assert validProtocolReturn(receiver, result);
+ return result;
+ }
+
+ private boolean assertHasStaticScope(Object receiver) {
+ try {
+ delegate.getStaticScope(receiver);
+ } catch (InteropException e) {
+ assert false : violationInvariant(receiver);
+ }
+ return true;
+ }
+
+ private boolean assertHasNoStaticScope(Object receiver) {
+ try {
+ delegate.getStaticScope(receiver);
+ assert false : violationInvariant(receiver);
+ } catch (UnsupportedMessageException e) {
+ // Falls to return true
+ }
+ return true;
+ }
+
+ @Override
+ public Object getStaticScope(Object receiver) throws UnsupportedMessageException {
+ if (CompilerDirectives.inCompiledCode()) {
+ return delegate.getStaticScope(receiver);
+ }
+ assert preCondition(receiver);
+ boolean hadStaticReceiver = delegate.hasStaticScope(receiver);
+ try {
+ Object result = delegate.getStaticScope(receiver);
+ assert hadStaticReceiver || isMultiThreaded(receiver) : violationInvariant(receiver);
+ assert validInteropReturn(receiver, result);
+ assert UNCACHED.isMetaObject(receiver) : violationPost(receiver, result);
+ assert UNCACHED.isScope(result) : violationPost(receiver, result);
+ assert UNCACHED.hasMembers(result) : violationPost(receiver, result);
+ return result;
+ } catch (InteropException e) {
+ assert e instanceof UnsupportedMessageException : violationPost(receiver, e);
+ assert isMultiThreaded(receiver) || !hadStaticReceiver : violationInvariant(receiver);
+ throw e;
+ }
+ }
+
@Override
public boolean hasHashEntries(Object receiver) {
assert preCondition(receiver);
@@ -5517,6 +5663,40 @@ private boolean assertHasNoLanguageId(Object receiver) {
return true;
}
+ @Override
+ public boolean isHostObject(Object receiver) {
+ if (CompilerDirectives.inCompiledCode()) {
+ return delegate.isHostObject(receiver);
+ }
+ assert preCondition(receiver);
+ boolean result = delegate.isHostObject(receiver);
+ if (result) {
+ assert assertHasHostObject(receiver);
+ } else {
+ assert assertHasNoHostObject(receiver);
+ }
+ assert validProtocolReturn(receiver, result);
+ return result;
+ }
+
+ private boolean assertHasHostObject(Object receiver) {
+ try {
+ delegate.asHostObject(receiver);
+ } catch (InteropException e) {
+ assert e instanceof HeapIsolationException : violationInvariant(receiver);
+ }
+ return true;
+ }
+
+ private boolean assertHasNoHostObject(Object receiver) {
+ try {
+ delegate.asHostObject(receiver);
+ assert false : violationInvariant(receiver);
+ } catch (UnsupportedMessageException | HeapIsolationException e) {
+ }
+ return true;
+ }
+
@Override
public String getLanguageId(Object receiver) throws UnsupportedMessageException {
if (CompilerDirectives.inCompiledCode()) {
@@ -5535,6 +5715,26 @@ public String getLanguageId(Object receiver) throws UnsupportedMessageException
throw e;
}
}
+
+ @Override
+ public Object asHostObject(Object receiver) throws HeapIsolationException, UnsupportedMessageException {
+ if (CompilerDirectives.inCompiledCode()) {
+ return delegate.asHostObject(receiver);
+ }
+ assert preCondition(receiver);
+ boolean wasHasHostObject = delegate.isHostObject(receiver);
+ try {
+ Object result = delegate.asHostObject(receiver);
+ assert wasHasHostObject : violationInvariant(receiver);
+ return result;
+ } catch (UnsupportedMessageException e) {
+ assert !wasHasHostObject : violationInvariant(receiver);
+ throw e;
+ } catch (InteropException e) {
+ assert e instanceof HeapIsolationException : violationInvariant(receiver);
+ throw e;
+ }
+ }
}
}
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/CallerSensitiveTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/CallerSensitiveTest.java
index ea00b9fc966a..4f1013697d2d 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/CallerSensitiveTest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/CallerSensitiveTest.java
@@ -69,13 +69,13 @@ public void testLogger() throws InteropException {
TruffleObject getLogger = (TruffleObject) INTEROP.readMember(loggerClass, "getLogger");
logger = (TruffleObject) INTEROP.execute(getLogger, loggerName);
- assertTrue(env.isHostObject(logger));
- assertTrue(env.asHostObject(logger) instanceof Logger);
+ assertTrue(INTEROP.isHostObject(logger));
+ assertTrue(INTEROP.asHostObject(logger) instanceof Logger);
assertEquals(loggerName, asJavaObject(Logger.class, logger).getName());
logger = (TruffleObject) INTEROP.invokeMember(loggerClass, "getLogger", loggerName);
- assertTrue(env.isHostObject(logger));
- assertTrue(env.asHostObject(logger) instanceof Logger);
+ assertTrue(INTEROP.isHostObject(logger));
+ assertTrue(INTEROP.asHostObject(logger) instanceof Logger);
assertEquals(loggerName, asJavaObject(Logger.class, logger).getName());
}
}
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/FunctionalInterfaceTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/FunctionalInterfaceTest.java
index 1e1cbb03eea0..268340ca3935 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/FunctionalInterfaceTest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/FunctionalInterfaceTest.java
@@ -110,8 +110,8 @@ public void testLegacyFunctionalInterface() throws InteropException {
public void testThread() throws InteropException {
TruffleObject threadClass = (TruffleObject) env.lookupHostSymbol("java.lang.Thread");
Object result = INTEROP.instantiate(threadClass, new TestExecutable());
- assertTrue(env.isHostObject(result));
- Object thread = env.asHostObject(result);
+ assertTrue(INTEROP.isHostObject(result));
+ Object thread = INTEROP.asHostObject(result);
assertTrue(thread instanceof Thread);
}
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostAdapterTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostAdapterTest.java
index e3930077df03..c67b85bbe0a8 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostAdapterTest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostAdapterTest.java
@@ -136,9 +136,11 @@ private Object asHostType(TruffleLanguage.Env env, Class> c) {
}
}
+ @SuppressWarnings("deprecation")
private static Object verifyHostAdapterClass(TruffleLanguage.Env env, Object hostAdapterClass) {
- assertTrue(env.isHostObject(hostAdapterClass));
+ assertTrue(INTEROP.isHostObject(hostAdapterClass));
assertTrue(env.isHostSymbol(hostAdapterClass));
+ assertTrue(INTEROP.isScope(hostAdapterClass));
assertTrue(INTEROP.isMetaObject(hostAdapterClass));
assertTrue(INTEROP.isInstantiable(hostAdapterClass));
return hostAdapterClass;
@@ -162,10 +164,10 @@ Object createHostAdapterClassWithClassOverrides(TruffleLanguage.Env env, Class
return verifyHostAdapterClass(env, env.createHostAdapterWithClassOverrides(hostTypes, classOverrides));
}
- private static Object instantianteHostAdapter(TruffleLanguage.Env env, Object adapter, Object... arguments) throws InteropException {
+ private static Object instantianteHostAdapter(Object adapter, Object... arguments) throws InteropException {
Object instance = INTEROP.instantiate(adapter, arguments);
assertTrue(INTEROP.isMetaInstance(adapter, instance));
- assertTrue(env.isHostObject(instance));
+ assertTrue(INTEROP.isHostObject(instance));
return instance;
}
@@ -174,7 +176,7 @@ public void testCreateHostAdapterFromInterface() throws InteropException {
try (TestContext c = new TestContext((b) -> b.allowHostAccess(explicitHostAccessAllowImplementations(Callable.class)))) {
TruffleLanguage.Env env = c.env;
Object adapter = createHostAdapterClass(env, new Class>[]{Callable.class});
- Object instance = instantianteHostAdapter(env, adapter, env.asGuestValue(ProxyObject.fromMap(Collections.singletonMap("call", (ProxyExecutable) (args) -> 42))));
+ Object instance = instantianteHostAdapter(adapter, env.asGuestValue(ProxyObject.fromMap(Collections.singletonMap("call", (ProxyExecutable) (args) -> 42))));
assertEquals(42, INTEROP.invokeMember(instance, "call"));
assertTrue(INTEROP.isMetaInstance(env.asHostSymbol(Callable.class), instance));
@@ -186,16 +188,16 @@ public void testCreateHostAdapterFromClass() throws InteropException {
try (TestContext c = new TestContext((b) -> b.allowHostAccess(explicitHostAccessAllowImplementations(Extensible.class)))) {
TruffleLanguage.Env env = c.env;
Object adapter = createHostAdapterClass(env, new Class>[]{Extensible.class});
- Object instance1 = instantianteHostAdapter(env, adapter, env.asGuestValue(ProxyObject.fromMap(Collections.singletonMap("abstractMethod", (ProxyExecutable) (args) -> "override"))));
+ Object instance1 = instantianteHostAdapter(adapter, env.asGuestValue(ProxyObject.fromMap(Collections.singletonMap("abstractMethod", (ProxyExecutable) (args) -> "override"))));
assertEquals("override", INTEROP.invokeMember(instance1, "abstractMethod"));
assertEquals("base", INTEROP.invokeMember(instance1, "baseMethod"));
- Object instance2 = instantianteHostAdapter(env, adapter, env.asGuestValue(ProxyObject.fromMap(Collections.singletonMap("baseMethod", (ProxyExecutable) (args) -> "override"))));
+ Object instance2 = instantianteHostAdapter(adapter, env.asGuestValue(ProxyObject.fromMap(Collections.singletonMap("baseMethod", (ProxyExecutable) (args) -> "override"))));
assertEquals("override", INTEROP.invokeMember(instance2, "baseMethod"));
assertFails(() -> {
return INTEROP.invokeMember(instance2, "abstractMethod");
- }, AbstractTruffleException.class, e -> assertTrue(e.toString(), env.isHostException(e)));
+ }, AbstractTruffleException.class, e -> assertTrue(e.toString(), INTEROP.isHostObject(e) && INTEROP.isException(e)));
assertTrue(INTEROP.isMetaInstance(env.asHostSymbol(Extensible.class), instance1));
assertTrue(INTEROP.isMetaInstance(env.asHostSymbol(Extensible.class), instance2));
@@ -213,7 +215,7 @@ public void testCreateHostAdapterFromClassAndInterfaces() throws InteropExceptio
impl.put("baseMethod", (ProxyExecutable) (args) -> "baseMethodImpl");
impl.put("call", (ProxyExecutable) (args) -> "callImpl");
impl.put("defaultMethod", (ProxyExecutable) (args) -> "defaultMethodImpl");
- Object instance = instantianteHostAdapter(env, adapter, env.asGuestValue(ProxyObject.fromMap(impl)));
+ Object instance = instantianteHostAdapter(adapter, env.asGuestValue(ProxyObject.fromMap(impl)));
assertEquals("abstractMethodImpl", INTEROP.invokeMember(instance, "abstractMethod"));
assertEquals("baseMethodImpl", INTEROP.invokeMember(instance, "baseMethod"));
@@ -245,7 +247,7 @@ public void testCreateHostAdapterFromClassWithConstructorParams() throws Interop
Map impl = new HashMap<>();
impl.put("abstractMethod", (ProxyExecutable) (args) -> "abstractMethodImpl");
impl.put("finalMethod", (ProxyExecutable) (args) -> "finalMethodImpl");
- Object instance = instantianteHostAdapter(env, adapter, "concreteName", env.asGuestValue(ProxyObject.fromMap(impl)));
+ Object instance = instantianteHostAdapter(adapter, "concreteName", env.asGuestValue(ProxyObject.fromMap(impl)));
assertEquals("abstractMethodImpl", INTEROP.invokeMember(instance, "abstractMethod"));
assertEquals("final", INTEROP.invokeMember(instance, "finalMethod"));
assertEquals("concreteName", INTEROP.readMember(instance, "name"));
@@ -347,7 +349,7 @@ public void testCreateHostAdapterThis() throws InteropException {
impl.put("baseMethod", (ProxyExecutable) (args) -> "baseMethodImpl");
impl.put("defaultMethod", (ProxyExecutable) (args) -> "defaultMethodImpl");
Object guestObject = env.asGuestValue(ProxyObject.fromMap(impl));
- Object instance = instantianteHostAdapter(env, adapter, guestObject);
+ Object instance = instantianteHostAdapter(adapter, guestObject);
assertEquals("abstractMethodImpl", INTEROP.invokeMember(instance, "abstractMethod"));
assertEquals("baseMethodImpl", INTEROP.invokeMember(instance, "baseMethod"));
@@ -375,7 +377,7 @@ public void testHostAdapterWithCustomHostAccess() throws InteropException {
impl.put("baseMethod", (ProxyExecutable) (args) -> "baseMethodImpl");
impl.put("defaultMethod", (ProxyExecutable) (args) -> "defaultMethodImpl");
Object guestObject = env.asGuestValue(ProxyObject.fromMap(impl));
- Object instance = instantianteHostAdapter(env, adapter, guestObject);
+ Object instance = instantianteHostAdapter(adapter, guestObject);
assertEquals("abstractMethodImpl", INTEROP.invokeMember(instance, "abstractMethod"));
assertEquals("baseMethodImpl", INTEROP.invokeMember(instance, "baseMethod"));
@@ -398,7 +400,7 @@ public void testStackedHostAdaptersWithClassOverrides() throws InteropException
impl1.put("defaultMethod", (ProxyExecutable) (args) -> "defaultMethodImpl1");
Object guestObject1 = env.asGuestValue(ProxyObject.fromMap(impl1));
Object adapterClass1 = createHostAdapterClassWithClassOverrides(env, supertypes, guestObject1);
- Object parent = instantianteHostAdapter(env, adapterClass1);
+ Object parent = instantianteHostAdapter(adapterClass1);
assertEquals("abstractMethodImpl1", INTEROP.invokeMember(parent, "abstractMethod"));
assertEquals("baseMethodImpl1", INTEROP.invokeMember(parent, "baseMethod"));
@@ -409,8 +411,8 @@ public void testStackedHostAdaptersWithClassOverrides() throws InteropException
impl2.put("baseMethod", (ProxyExecutable) (args) -> "baseMethodImpl2");
impl2.put("defaultMethod", (ProxyExecutable) (args) -> "defaultMethodImpl2");
Object guestObject2 = env.asGuestValue(ProxyObject.fromMap(impl2));
- Object adapterClass2 = createHostAdapterClass(env, new Class>[]{Interface.class, (Class>) env.asHostObject(adapterClass1)});
- Object instance = instantianteHostAdapter(env, adapterClass2, guestObject2);
+ Object adapterClass2 = createHostAdapterClass(env, new Class>[]{Interface.class, (Class>) INTEROP.asHostObject(adapterClass1)});
+ Object instance = instantianteHostAdapter(adapterClass2, guestObject2);
assertEquals("abstractMethodImpl2", INTEROP.invokeMember(instance, "abstractMethod"));
assertEquals("baseMethodImpl2", INTEROP.invokeMember(instance, "baseMethod"));
@@ -435,7 +437,7 @@ public void testStackedHostAdaptersWithoutClassOverrides() throws InteropExcepti
impl1.put("defaultMethod", (ProxyExecutable) (args) -> "defaultMethodImpl1");
Object guestObject1 = env.asGuestValue(ProxyObject.fromMap(impl1));
Object adapterClass1 = createHostAdapterClass(env, supertypes);
- Object parent = instantianteHostAdapter(env, adapterClass1, guestObject1);
+ Object parent = instantianteHostAdapter(adapterClass1, guestObject1);
assertEquals("abstractMethodImpl1", INTEROP.invokeMember(parent, "abstractMethod"));
assertEquals("baseMethodImpl1", INTEROP.invokeMember(parent, "baseMethod"));
@@ -446,8 +448,8 @@ public void testStackedHostAdaptersWithoutClassOverrides() throws InteropExcepti
impl2.put("baseMethod", (ProxyExecutable) (args) -> "baseMethodImpl2");
impl2.put("defaultMethod", (ProxyExecutable) (args) -> "defaultMethodImpl2");
Object guestObject2 = env.asGuestValue(ProxyObject.fromMap(impl2));
- Object adapterClass2 = createHostAdapterClass(env, new Class>[]{Interface.class, (Class>) env.asHostObject(adapterClass1)});
- Object instance = instantianteHostAdapter(env, adapterClass2, guestObject1, guestObject2);
+ Object adapterClass2 = createHostAdapterClass(env, new Class>[]{Interface.class, (Class>) INTEROP.asHostObject(adapterClass1)});
+ Object instance = instantianteHostAdapter(adapterClass2, guestObject1, guestObject2);
assertEquals("abstractMethodImpl2", INTEROP.invokeMember(instance, "abstractMethod"));
assertEquals("baseMethodImpl2", INTEROP.invokeMember(instance, "baseMethod"));
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostExceptionTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostExceptionTest.java
index 9ceb666504b2..1bae8fb3db44 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostExceptionTest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostExceptionTest.java
@@ -63,6 +63,7 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
+import com.oracle.truffle.api.interop.HeapIsolationException;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.HostAccess;
import org.graalvm.polyglot.PolyglotException;
@@ -100,7 +101,6 @@
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.test.polyglot.ProxyLanguage;
-import com.oracle.truffle.api.test.polyglot.ProxyLanguage.LanguageContext;
import com.oracle.truffle.tck.tests.TruffleTestAssumptions;
public class HostExceptionTest {
@@ -186,12 +186,14 @@ public void after() {
}
@Test(expected = IllegalArgumentException.class)
+ @SuppressWarnings("deprecation")
public void testAsHostExceptionIllegalArgument() {
TruffleTestAssumptions.assumeWeakEncapsulation();
env.asHostException(new Exception());
}
@Test(expected = IllegalArgumentException.class)
+ @SuppressWarnings("deprecation")
public void testAsHostExceptionNull() {
TruffleTestAssumptions.assumeWeakEncapsulation();
env.asHostException(null);
@@ -528,7 +530,7 @@ public void testHostExceptionIsHostSymbol() {
TruffleTestAssumptions.assumeWeakEncapsulation();
expectedException = RuntimeException.class;
customExceptionVerifier = (t) -> {
- assertFalse(env.isHostSymbol(t));
+ assertFalse(INTEROP.isHostObject(t) && INTEROP.isScope(t));
};
Value catcher = context.eval(ProxyLanguage.ID, CATCHER);
Runnable thrower = HostExceptionTest::thrower;
@@ -577,7 +579,7 @@ public void testHostExceptionCause() {
assertTrue("should have exception cause", INTEROP.hasExceptionCause(hostEx));
Object cause = INTEROP.getExceptionCause(hostEx);
assertTrue("cause should be an exception", INTEROP.isException(cause));
- assertTrue("cause should be a host exception", env.isHostObject(cause));
+ assertTrue("cause should be a host exception", INTEROP.isHostObject(cause));
Class extends Throwable> causeClass = NoSuchFieldException.class;
assertTrue("cause should be instanceof " + causeClass.getSimpleName(), INTEROP.isMetaInstance(env.asHostSymbol(causeClass), cause));
assertFalse("cause should not have another cause", INTEROP.hasExceptionCause(cause));
@@ -628,7 +630,7 @@ public void testThrowHostExceptionObject() {
assertTrue("should have exception cause", INTEROP.hasExceptionCause(hostEx));
Object cause = INTEROP.getExceptionCause(hostEx);
assertTrue("cause should be an exception", INTEROP.isException(cause));
- assertTrue("cause should be a host exception", env.isHostObject(cause));
+ assertTrue("cause should be a host exception", INTEROP.isHostObject(cause));
Class extends Throwable> causeClass = NoSuchFieldException.class;
assertTrue("cause should be instanceof " + causeClass.getSimpleName(), INTEROP.isMetaInstance(env.asHostSymbol(causeClass), cause));
assertFalse("cause should not have another cause", INTEROP.hasExceptionCause(cause));
@@ -897,7 +899,7 @@ public void testGuestExceptionCaughtByHost() {
hostExceptionVerifier = null;
customExceptionVerifier = (guestEx) -> {
- assertFalse(guestEx.toString(), env.isHostException(guestEx));
+ assertFalse(guestEx.toString(), INTEROP.isHostObject(guestEx) && INTEROP.isException(guestEx));
assertTrue(guestEx.toString(), INTEROP.isException(guestEx));
assertEquals(List.of(expectedMessage,
@@ -976,7 +978,7 @@ public void testHideHostStackFrames() {
hostExceptionVerifier = null;
customExceptionVerifier = (guestEx) -> {
- assertFalse(guestEx.toString(), env.isHostException(guestEx));
+ assertFalse(guestEx.toString(), INTEROP.isHostObject(guestEx) && INTEROP.isException(guestEx));
assertTrue(guestEx.toString(), INTEROP.isException(guestEx));
List expectedStack = List.of(expectedMessage,
@@ -1218,10 +1220,10 @@ public Object execute(VirtualFrame frame) {
}
private void verifyHostException(Throwable ex) {
- assertTrue(env.isHostObject(ex));
+ assertTrue(INTEROP.isHostObject(ex));
assertNotNull("Unexpected exception: " + ex, expectedException);
- assertThat(env.asHostObject(ex), instanceOf(expectedException));
- assertThat(LanguageContext.get(null).getEnv().asHostException(ex), instanceOf(expectedException));
+ assertThat(asHostObject(ex), instanceOf(expectedException));
+ assertThat(asHostObject(ex), instanceOf(expectedException));
try {
assertTrue(InteropLibrary.getUncached().isMetaInstance(env.asHostSymbol(Throwable.class), ex));
} catch (UnsupportedMessageException e) {
@@ -1229,11 +1231,19 @@ private void verifyHostException(Throwable ex) {
}
}
+ private static Object asHostObject(Object guestObject) {
+ try {
+ return INTEROP.asHostObject(guestObject);
+ } catch (UnsupportedMessageException | HeapIsolationException e) {
+ throw CompilerDirectives.shouldNotReachHere(e);
+ }
+ }
+
@TruffleBoundary
Object checkAndUnwrapException(Throwable ex) {
// Avoid catching an AssertionError wrapped as a host exception.
- if (env.isHostException(ex)) {
- Throwable t = env.asHostException(ex);
+ if (INTEROP.isHostObject(ex) && INTEROP.isException(ex)) {
+ Throwable t = (Throwable) asHostObject(ex);
if (t instanceof AssertionError) {
throw (AssertionError) t;
}
@@ -1314,7 +1324,7 @@ public Object execute(VirtualFrame frame) {
throw CompilerDirectives.shouldNotReachHere(e);
} catch (Exception ex) {
if (interop.isException(ex)) {
- assertTrue(env.isHostObject(ex));
+ assertTrue(INTEROP.isHostObject(ex));
try {
throw interop.throwException(ex);
} catch (UnsupportedMessageException e) {
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostInteropErrorTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostInteropErrorTest.java
index 55789c44973f..f65eaa6d8430 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostInteropErrorTest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/HostInteropErrorTest.java
@@ -210,10 +210,10 @@ public void testClassCastExceptionInHostMethod() throws InteropException {
Object foo = INTEROP.readMember(hostObj, "cce");
AbstractPolyglotTest.assertFails(() -> INTEROP.invokeMember(hostObj, "cce", 42), RuntimeException.class, (e) -> {
- assertTrue(env.isHostException(e));
+ assertTrue(INTEROP.isHostObject(e) && INTEROP.isException(e));
});
AbstractPolyglotTest.assertFails(() -> INTEROP.execute(foo, 42), RuntimeException.class, (e) -> {
- assertTrue(env.isHostException(e));
+ assertTrue(INTEROP.isHostObject(e) && INTEROP.isException(e));
});
}
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/ProxyLanguageEnvTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/ProxyLanguageEnvTest.java
index 9e56dd0a48fc..2ce5d3c6db9d 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/ProxyLanguageEnvTest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/ProxyLanguageEnvTest.java
@@ -47,6 +47,8 @@
import java.util.List;
import java.util.concurrent.Callable;
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.interop.HeapIsolationException;
import org.graalvm.polyglot.Context;
import org.junit.After;
import org.junit.Before;
@@ -90,13 +92,20 @@ void assertThrowsExceptionWithCause(Callable> callable, Class extends Except
} catch (Exception e) {
List> causes = new ArrayList<>();
Throwable cause = e;
+ InteropLibrary interopLibrary = InteropLibrary.getUncached();
while (cause != null) {
if (cause.getClass() == exception) {
return;
}
causes.add(cause.getClass());
- if (env.isHostException(cause)) {
- cause = env.asHostException(cause);
+ if (interopLibrary.isHostObject(cause) && interopLibrary.isException(cause)) {
+ try {
+ cause = (Throwable) interopLibrary.asHostObject(cause);
+ } catch (HeapIsolationException ex) {
+ cause = cause.getCause();
+ } catch (UnsupportedMessageException ex) {
+ throw CompilerDirectives.shouldNotReachHere(ex);
+ }
} else {
cause = cause.getCause();
}
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/TestMemberAccess.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/TestMemberAccess.java
index 933862b51db9..16ad4ea5a6ee 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/TestMemberAccess.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/host/TestMemberAccess.java
@@ -430,7 +430,7 @@ public void testOverloadedConstructor2() throws InteropException {
public void testOverloadedConstructor3() throws InteropException {
TruffleObject clazz = asTruffleHostSymbol(TestConstructorException.class);
Object testObj = INTEROP.instantiate(clazz, "test", 42);
- assertTrue(testObj instanceof TruffleObject && env.asHostObject(testObj) instanceof TestConstructorException);
+ assertTrue(testObj instanceof TruffleObject && INTEROP.asHostObject(testObj) instanceof TestConstructorException);
assertThrowsExceptionWithCause(() -> INTEROP.instantiate(clazz, "test"), IOException.class);
}
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/interop/InteropAssertionsTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/interop/InteropAssertionsTest.java
index 415a87f8ebc1..8dd37bbd7584 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/interop/InteropAssertionsTest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/interop/InteropAssertionsTest.java
@@ -53,6 +53,8 @@
import java.util.function.Predicate;
import java.util.function.Supplier;
+import com.oracle.truffle.api.interop.HeapIsolationException;
+import org.graalvm.collections.Pair;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.proxy.ProxyArray;
import org.graalvm.polyglot.proxy.ProxyExecutable;
@@ -793,40 +795,40 @@ String getLanguageId() {
Object toDisplayString(@SuppressWarnings("unused") boolean allowSideEffects) {
return "ScopeCached[" + id + "]";
}
+ }
- @ExportLibrary(InteropLibrary.class)
- static final class ScopeMembers implements TruffleObject {
+ @ExportLibrary(InteropLibrary.class)
+ static final class ScopeMembers implements TruffleObject {
- private final long len;
+ private final long len;
- private ScopeMembers(long len) {
- this.len = len;
- }
+ private ScopeMembers(long len) {
+ this.len = len;
+ }
- @ExportMessage
- @SuppressWarnings("static-method")
- boolean hasArrayElements() {
- return true;
- }
+ @ExportMessage
+ @SuppressWarnings("static-method")
+ boolean hasArrayElements() {
+ return true;
+ }
- @ExportMessage
- Object readArrayElement(long index) throws InvalidArrayIndexException {
- if (0 <= index && index < len) {
- return Long.toString(len - index);
- } else {
- throw InvalidArrayIndexException.create(index);
- }
+ @ExportMessage
+ Object readArrayElement(long index) throws InvalidArrayIndexException {
+ if (0 <= index && index < len) {
+ return Long.toString(len - index);
+ } else {
+ throw InvalidArrayIndexException.create(index);
}
+ }
- @ExportMessage
- long getArraySize() {
- return len;
- }
+ @ExportMessage
+ long getArraySize() {
+ return len;
+ }
- @ExportMessage
- boolean isArrayElementReadable(long index) {
- return 0 <= index && index < len;
- }
+ @ExportMessage
+ boolean isArrayElementReadable(long index) {
+ return 0 <= index && index < len;
}
}
@@ -1953,6 +1955,317 @@ public void testIsInvocableMemberWithReadSideEffects() throws UnsupportedMessage
assertEquals(42, memberLib.invokeMember(obj, memberName));
}
+ @Test
+ public void testIsHostObject() {
+ AsHostObjectTest hostObject = new AsHostObjectTest();
+ InteropLibrary hostObjectLib = createLibrary(InteropLibrary.class, hostObject);
+
+ hostObject.isHostObject = true;
+ hostObject.hostObjectProvider = () -> {
+ throw UnsupportedMessageException.create();
+ };
+ assertFails(() -> hostObjectLib.isHostObject(hostObject), AssertionError.class);
+
+ hostObject.hostObjectProvider = () -> Pair.create(42, "42");
+ assertTrue(hostObjectLib.isHostObject(hostObject));
+
+ hostObject.hostObjectProvider = () -> {
+ throw HeapIsolationException.create();
+ };
+ assertTrue(hostObjectLib.isHostObject(hostObject));
+
+ hostObject.isHostObject = false;
+ hostObject.hostObjectProvider = null;
+ assertFalse(hostObjectLib.isHostObject(hostObject));
+
+ hostObject.hostObjectProvider = () -> Pair.create(42, "42");
+ assertFails(() -> hostObjectLib.isHostObject(hostObject), AssertionError.class);
+
+ hostObject.hostObjectProvider = () -> {
+ throw HeapIsolationException.create();
+ };
+ assertFalse(hostObjectLib.isHostObject(hostObject));
+ }
+
+ @Test
+ public void testAsHostObject() throws UnsupportedMessageException, HeapIsolationException {
+ AsHostObjectTest hostObject = new AsHostObjectTest();
+ InteropLibrary l = createLibrary(InteropLibrary.class, hostObject);
+
+ hostObject.isHostObject = false;
+ hostObject.hostObjectProvider = null;
+ assertFails(() -> l.asHostObject(hostObject), UnsupportedMessageException.class);
+
+ hostObject.isHostObject = true;
+ Object value = new Object();
+ hostObject.hostObjectProvider = () -> value;
+ assertSame(value, l.asHostObject(hostObject));
+
+ hostObject.isHostObject = true;
+ hostObject.hostObjectProvider = null;
+ assertFails(() -> l.asHostObject(hostObject), AssertionError.class);
+
+ hostObject.isHostObject = false;
+ hostObject.hostObjectProvider = () -> value;
+ assertFails(() -> l.asHostObject(hostObject), AssertionError.class);
+ }
+
+ @ExportLibrary(InteropLibrary.class)
+ static class AsHostObjectTest implements TruffleObject {
+
+ boolean isHostObject;
+ HostObjectProvider hostObjectProvider;
+
+ @ExportMessage
+ boolean isHostObject() {
+ return isHostObject;
+ }
+
+ @ExportMessage
+ Object asHostObject() throws UnsupportedMessageException, HeapIsolationException {
+ if (hostObjectProvider != null) {
+ return hostObjectProvider.call();
+ } else {
+ throw UnsupportedMessageException.create();
+ }
+ }
+ }
+
+ @FunctionalInterface
+ interface HostObjectProvider extends Callable {
+
+ @Override
+ Object call() throws UnsupportedMessageException, HeapIsolationException;
+ }
+
+ @Test
+ public void testHasStaticScope() {
+ GetStaticScopeTest receiver = new GetStaticScopeTest();
+ InteropLibrary hasStaticScopeLib = createLibrary(InteropLibrary.class, receiver);
+
+ receiver.isMetaObject = true;
+ receiver.hasStaticScope = true;
+ receiver.staticScopeProvider = () -> new StaticScope(true, true);
+ assertTrue(hasStaticScopeLib.hasStaticScope(receiver));
+
+ receiver.isMetaObject = true;
+ receiver.hasStaticScope = false;
+ receiver.staticScopeProvider = () -> {
+ throw UnsupportedMessageException.create();
+ };
+ assertFalse(hasStaticScopeLib.hasStaticScope(receiver));
+
+ receiver.isMetaObject = false;
+ receiver.hasStaticScope = false;
+ receiver.staticScopeProvider = () -> {
+ throw UnsupportedMessageException.create();
+ };
+ assertFalse(hasStaticScopeLib.hasStaticScope(receiver));
+
+ receiver.isMetaObject = false;
+ receiver.hasStaticScope = true;
+ receiver.staticScopeProvider = () -> new StaticScope(true, true);
+ assertFails(() -> hasStaticScopeLib.hasStaticScope(receiver), AssertionError.class);
+
+ receiver.isMetaObject = true;
+ receiver.hasStaticScope = false;
+ receiver.staticScopeProvider = () -> new StaticScope(true, true);
+ assertFails(() -> hasStaticScopeLib.hasStaticScope(receiver), AssertionError.class);
+
+ receiver.isMetaObject = true;
+ receiver.hasStaticScope = true;
+ receiver.staticScopeProvider = () -> {
+ throw UnsupportedMessageException.create();
+ };
+ assertFails(() -> hasStaticScopeLib.hasStaticScope(receiver), AssertionError.class);
+ }
+
+ @Test
+ public void testGetStaticScope() throws Exception {
+ setupEnv(Context.create()); // we need no multi threaded context.
+ GetStaticScopeTest receiver = new GetStaticScopeTest();
+ InteropLibrary getStaticScopeLib = createLibrary(InteropLibrary.class, receiver);
+
+ receiver.isMetaObject = true;
+ receiver.hasStaticScope = true;
+ receiver.staticScopeProvider = () -> new StaticScope(true, true);
+ assertNotNull(getStaticScopeLib.getStaticScope(receiver));
+
+ receiver.isMetaObject = true;
+ receiver.hasStaticScope = false;
+ receiver.staticScopeProvider = () -> {
+ throw UnsupportedMessageException.create();
+ };
+ assertFails(() -> getStaticScopeLib.getStaticScope(receiver), UnsupportedMessageException.class);
+
+ receiver.isMetaObject = false;
+ receiver.hasStaticScope = false;
+ receiver.staticScopeProvider = () -> {
+ throw UnsupportedMessageException.create();
+ };
+ assertFails(() -> getStaticScopeLib.getStaticScope(receiver), UnsupportedMessageException.class);
+
+ receiver.isMetaObject = false;
+ receiver.hasStaticScope = true;
+ receiver.staticScopeProvider = () -> new StaticScope(true, true);
+ assertFails(() -> getStaticScopeLib.getStaticScope(receiver), AssertionError.class);
+
+ receiver.isMetaObject = true;
+ receiver.hasStaticScope = false;
+ receiver.staticScopeProvider = () -> new StaticScope(true, true);
+ assertFails(() -> getStaticScopeLib.getStaticScope(receiver), AssertionError.class);
+
+ receiver.isMetaObject = true;
+ receiver.hasStaticScope = true;
+ receiver.staticScopeProvider = () -> {
+ throw UnsupportedMessageException.create();
+ };
+ assertFails(() -> getStaticScopeLib.getStaticScope(receiver), AssertionError.class);
+
+ receiver.isMetaObject = true;
+ receiver.hasStaticScope = true;
+ receiver.staticScopeProvider = () -> new StaticScope(false, true);
+ assertFails(() -> getStaticScopeLib.getStaticScope(receiver), AssertionError.class);
+
+ receiver.isMetaObject = true;
+ receiver.hasStaticScope = true;
+ receiver.staticScopeProvider = () -> new StaticScope(true, false);
+ assertFails(() -> getStaticScopeLib.getStaticScope(receiver), AssertionError.class);
+ }
+
+ @ExportLibrary(InteropLibrary.class)
+ static final class GetStaticScopeTest implements TruffleObject {
+
+ boolean hasStaticScope;
+ boolean isMetaObject;
+ StaticScopeProvider staticScopeProvider;
+
+ @ExportMessage
+ boolean isMetaObject() {
+ return isMetaObject;
+ }
+
+ @ExportMessage
+ Object getMetaQualifiedName() throws UnsupportedMessageException {
+ if (isMetaObject) {
+ return GetStaticScopeTest.class.getName();
+ } else {
+ throw UnsupportedMessageException.create();
+ }
+ }
+
+ @ExportMessage
+ Object getMetaSimpleName() throws UnsupportedMessageException {
+ if (isMetaObject) {
+ return GetStaticScopeTest.class.getSimpleName();
+ } else {
+ throw UnsupportedMessageException.create();
+ }
+ }
+
+ @ExportMessage
+ @SuppressWarnings("unused")
+ boolean isMetaInstance(Object instance) throws UnsupportedMessageException {
+ if (isMetaObject) {
+ return false;
+ } else {
+ throw UnsupportedMessageException.create();
+ }
+ }
+
+ @ExportMessage
+ boolean hasStaticScope() {
+ return hasStaticScope;
+ }
+
+ @ExportMessage
+ Object getStaticScope() throws UnsupportedMessageException {
+ return staticScopeProvider.call();
+ }
+
+ /*
+ * Needed for multi-threaded check.
+ */
+ @ExportMessage
+ @SuppressWarnings("static-method")
+ boolean hasLanguageId() {
+ return true;
+ }
+
+ /*
+ * Needed for multi-threaded check.
+ */
+ @ExportMessage
+ @SuppressWarnings("static-method")
+ String getLanguageId() {
+ return ProxyLanguage.ID;
+ }
+
+ /*
+ * Needed for multi-threaded check.
+ */
+ @ExportMessage
+ @SuppressWarnings({"static-method", "unused"})
+ Object toDisplayString(boolean allowSideEffects) {
+ return GetStaticScopeTest.class.getSimpleName();
+ }
+ }
+
+ @FunctionalInterface
+ interface StaticScopeProvider extends Callable {
+
+ @Override
+ Object call() throws UnsupportedMessageException;
+ }
+
+ @ExportLibrary(InteropLibrary.class)
+ static final class StaticScope implements TruffleObject {
+
+ private final boolean isScope;
+ private final boolean hasMembers;
+
+ StaticScope(boolean isScope, boolean hasMembers) {
+ this.isScope = isScope;
+ this.hasMembers = hasMembers;
+ }
+
+ @ExportMessage
+ boolean isScope() {
+ return isScope;
+ }
+
+ @ExportMessage
+ boolean hasLanguageId() {
+ return isScope();
+ }
+
+ @ExportMessage
+ String getLanguageId() throws UnsupportedMessageException {
+ if (isScope()) {
+ return ProxyLanguage.ID;
+ } else {
+ throw UnsupportedMessageException.create();
+ }
+ }
+
+ @ExportMessage
+ @SuppressWarnings({"static-method", "unused"})
+ String toDisplayString(boolean sideEffects) {
+ return StaticScope.class.getSimpleName();
+ }
+
+ @ExportMessage
+ boolean hasMembers() {
+ return hasMembers;
+ }
+
+ @ExportMessage
+ @SuppressWarnings({"static-method", "unused"})
+ Object getMembers(boolean includeInternal) {
+ return new ScopeMembers(0);
+ }
+ }
+
@SuppressWarnings("static-method")
@ExportLibrary(InteropLibrary.class)
static class IsInvocableUnknown implements TruffleObject {
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ContextBuilderExtendAPITest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ContextBuilderExtendAPITest.java
index b6f2c049a109..a9def153877b 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ContextBuilderExtendAPITest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ContextBuilderExtendAPITest.java
@@ -485,7 +485,7 @@ static class ContextExtendTestLanguage extends AbstractExecutableTestLanguage {
@TruffleBoundary
protected Object execute(RootNode node, Env env, Object[] contextArguments, Object[] frameArguments) {
try {
- if (frameArguments.length == 1 && env.isHostObject(frameArguments[0])) {
+ if (frameArguments.length == 1 && interop.isHostObject(frameArguments[0])) {
return interop.invokeMember(frameArguments[0], "getName");
}
if (frameArguments.length == 1 && interop.isString(frameArguments[0]) && interop.asString(frameArguments[0]).equals("return-array")) {
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/FileSystemsTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/FileSystemsTest.java
index e9b9cf88b4a9..e0daf6811004 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/FileSystemsTest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/FileSystemsTest.java
@@ -1942,12 +1942,12 @@ protected Object execute(RootNode node, Env env, Object[] contextArguments, Obje
Assert.fail("Should not reach here.");
} catch (Exception e) {
if (isInternal) {
- Assert.assertFalse(env.isHostException(e));
+ Assert.assertFalse(interop.isHostObject(e) && interop.isException(e));
Assert.assertTrue(e instanceof RuntimeException);
} else {
- Assert.assertTrue(env.isHostException(e));
+ Assert.assertTrue(interop.isHostObject(e) && interop.isException(e));
if (weakEncapsulation) {
- Assert.assertTrue(env.asHostException(e) instanceof NullPointerException);
+ Assert.assertTrue(interop.asHostObject(e) instanceof NullPointerException);
}
}
}
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/HostClassLoadingTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/HostClassLoadingTest.java
index 5477f9b5843e..1ec49397bb3d 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/HostClassLoadingTest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/HostClassLoadingTest.java
@@ -93,6 +93,7 @@ public class HostClassLoadingTest extends AbstractPolyglotTest {
static final String TEST_REPLACE_CLASS_NAME = "HostClassLoadingTestClazz1";
private static final String TEST_REPLACE_CLASS_NAME_2 = "HostClassLoadingTestClazz2";
private static final String TEST_REPLACE_QUALIFIED_CLASS_NAME = HostClassLoadingTestClass1.class.getPackage().getName() + ".HostClassLoadingTestClazz1";
+ private static final InteropLibrary INTEROP = InteropLibrary.getFactory().getUncached();
// static number that has the same lifetime as HostClassLoadingTestClass1.class.
private static int hostStaticFieldValue = 42;
@@ -463,14 +464,14 @@ public void testResourceBundleFolder() throws IOException {
}
@Test
- public void testProtectionDomainJar() throws IOException {
+ public void testProtectionDomainJar() throws IOException, InteropException {
setupEnv();
Class> hostClass = HostClassLoadingTestClass1.class;
Path tempDir = renameHostClass(hostClass, TEST_REPLACE_CLASS_NAME);
Path jar = createJar(tempDir);
languageEnv.addToHostClassPath(languageEnv.getPublicTruffleFile(jar.toString()));
Object newSymbol = languageEnv.lookupHostSymbol(hostClass.getPackage().getName() + "." + TEST_REPLACE_CLASS_NAME);
- Class> clz = (Class>) languageEnv.asHostObject(newSymbol);
+ Class> clz = (Class>) INTEROP.asHostObject(newSymbol);
ProtectionDomain protectionDomain = clz.getProtectionDomain();
assertNotNull(protectionDomain);
CodeSource codeSource = protectionDomain.getCodeSource();
@@ -481,13 +482,13 @@ public void testProtectionDomainJar() throws IOException {
}
@Test
- public void testProtectionDomainFolder() throws IOException {
+ public void testProtectionDomainFolder() throws IOException, InteropException {
setupEnv();
Class> hostClass = HostClassLoadingTestClass1.class;
Path tempDir = renameHostClass(hostClass, TEST_REPLACE_CLASS_NAME);
languageEnv.addToHostClassPath(languageEnv.getPublicTruffleFile(tempDir.toString()));
Object newSymbol = languageEnv.lookupHostSymbol(hostClass.getPackage().getName() + "." + TEST_REPLACE_CLASS_NAME);
- Class> clz = (Class>) languageEnv.asHostObject(newSymbol);
+ Class> clz = (Class>) INTEROP.asHostObject(newSymbol);
ProtectionDomain protectionDomain = clz.getProtectionDomain();
assertNotNull(protectionDomain);
CodeSource codeSource = protectionDomain.getCodeSource();
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/LanguageSPIHostInteropTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/LanguageSPIHostInteropTest.java
index 5704eac6b9ce..ef49bdf1f2a5 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/LanguageSPIHostInteropTest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/LanguageSPIHostInteropTest.java
@@ -53,6 +53,8 @@
import java.util.List;
import java.util.concurrent.Callable;
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.interop.HeapIsolationException;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -102,9 +104,9 @@ public static class TestClass {
}
@Test
- public void conversionToClassYieldsTheClass() {
- Object javaValue = languageEnv.asHostObject(languageEnv.asGuestValue(TestClass.class));
- Object javaSymbol = languageEnv.asHostObject(languageEnv.lookupHostSymbol(TestClass.class.getName()));
+ public void conversionToClassYieldsTheClass() throws Exception {
+ Object javaValue = INTEROP.asHostObject(languageEnv.asGuestValue(TestClass.class));
+ Object javaSymbol = INTEROP.asHostObject(languageEnv.lookupHostSymbol(TestClass.class.getName()));
assertTrue(javaValue instanceof Class);
assertSame("Both class objects are the same", javaValue, javaSymbol);
@@ -117,10 +119,10 @@ public void conversionToClassNull() {
}
@Test
- public void nullAsJavaObject() {
+ public void nullAsJavaObject() throws Exception {
Object nullObject = languageEnv.asGuestValue(null);
- assertTrue(languageEnv.isHostObject(nullObject));
- assertNull(languageEnv.asHostObject(nullObject));
+ assertTrue(INTEROP.isHostObject(nullObject));
+ assertNull(INTEROP.asHostObject(nullObject));
}
@SuppressWarnings("unchecked")
@@ -153,7 +155,7 @@ public void invokeJavaLangObjectFields() throws InteropException {
Object string = INTEROP.invokeMember(obj, "toString");
assertTrue(string instanceof String && ((String) string).startsWith(Data.class.getName() + "@"));
Object clazz = INTEROP.invokeMember(obj, "getClass");
- assertTrue(clazz instanceof TruffleObject && languageEnv.asHostObject(clazz) == Data.class);
+ assertTrue(clazz instanceof TruffleObject && INTEROP.asHostObject(clazz) == Data.class);
assertEquals(true, INTEROP.invokeMember(obj, "equals", obj));
assertTrue(INTEROP.invokeMember(obj, "hashCode") instanceof Integer);
@@ -245,8 +247,8 @@ private void assertNumberMembers(Number testNumber) throws InteropException {
assertInvocable(testNumber.hashCode(), guestValue, "hashCode");
assertInvocable(testNumber.toString(), guestValue, "toString");
- assertTrue(languageEnv.isHostObject(guestValue));
- assertEquals(testNumber, languageEnv.asHostObject(guestValue));
+ assertTrue(INTEROP.isHostObject(guestValue));
+ assertEquals(testNumber, INTEROP.asHostObject(guestValue));
}
private static void assertInvocable(Object expectedValue, Object receiver, String method, Object... args) throws InteropException {
@@ -280,7 +282,7 @@ private static void assertHasKey(Object receiver, String key) throws InteropExce
throw new AssertionError("Key not found " + key + ". Keys are " + allKeys);
}
- private void assertStringMembers(String unboxValue, Object stringObject) throws InteropException {
+ private static void assertStringMembers(String unboxValue, Object stringObject) throws InteropException {
String string = INTEROP.asString(stringObject);
assertEquals(unboxValue, string);
@@ -291,11 +293,11 @@ private void assertStringMembers(String unboxValue, Object stringObject) throws
assertInvocable(string.equals(unboxValue), stringObject, "equals", unboxValue);
assertInvocable(string.hashCode(), stringObject, "hashCode");
assertInvocable(string.toString(), stringObject, "toString");
- assertTrue(languageEnv.isHostObject(stringObject));
- assertEquals(string, languageEnv.asHostObject(stringObject));
+ assertTrue(INTEROP.isHostObject(stringObject));
+ assertEquals(string, INTEROP.asHostObject(stringObject));
}
- private void assertBooleanMembers(Object unboxValue, Object booleanObject) throws InteropException {
+ private static void assertBooleanMembers(Object unboxValue, Object booleanObject) throws InteropException {
Boolean b = INTEROP.asBoolean(booleanObject);
assertEquals(unboxValue, b);
@@ -305,11 +307,11 @@ private void assertBooleanMembers(Object unboxValue, Object booleanObject) throw
assertInvocable(b.hashCode(), booleanObject, "hashCode");
assertInvocable(b.toString(), booleanObject, "toString");
- assertTrue(languageEnv.isHostObject(booleanObject));
- assertEquals(b, languageEnv.asHostObject(booleanObject));
+ assertTrue(INTEROP.isHostObject(booleanObject));
+ assertEquals(b, INTEROP.asHostObject(booleanObject));
}
- private void assertCharacterMembers(Character unboxValue, Object charObject) throws InteropException {
+ private static void assertCharacterMembers(Character unboxValue, Object charObject) throws InteropException {
String b = INTEROP.asString(charObject);
assertEquals(unboxValue.toString(), b);
@@ -319,8 +321,8 @@ private void assertCharacterMembers(Character unboxValue, Object charObject) thr
assertInvocable(b.hashCode(), charObject, "hashCode");
assertInvocable(b.toString(), charObject, "toString");
- assertTrue(languageEnv.isHostObject(charObject));
- assertEquals(unboxValue, languageEnv.asHostObject(charObject));
+ assertTrue(INTEROP.isHostObject(charObject));
+ assertEquals(unboxValue, INTEROP.asHostObject(charObject));
}
@Test
@@ -350,30 +352,39 @@ private static void assertError(Callable> callable, Class extends Exception>
}
}
- private void assertThrowsExceptionWithCause(Callable> callable, Class extends Exception> exception) {
+ private static void assertThrowsExceptionWithCause(Callable> callable, Class extends Exception> exception) {
try {
callable.call();
fail("Expected " + exception.getSimpleName() + " but no exception was thrown");
} catch (Exception e) {
- assertTrue(languageEnv.isHostException(e));
- assertSame(exception, languageEnv.asHostException(e).getClass());
+ assertTrue(INTEROP.isHostObject(e) && INTEROP.isException(e));
+ try {
+ assertSame(exception, INTEROP.asHostObject(e).getClass());
+ } catch (UnsupportedMessageException | HeapIsolationException ex) {
+ throw CompilerDirectives.shouldNotReachHere(ex);
+ }
}
}
@Test
+ @SuppressWarnings("deprecation")
public void testIsHostFunction() throws InteropException {
TruffleObject system = (TruffleObject) languageEnv.lookupHostSymbol(System.class.getName());
Object exit = INTEROP.readMember(system, "exit");
assertTrue(exit instanceof TruffleObject);
- assertFalse(languageEnv.isHostObject(exit));
+ assertTrue(INTEROP.isHostObject(exit));
+ assertTrue(INTEROP.isHostObject(exit) && INTEROP.isExecutable(exit) && !INTEROP.hasMembers(exit));
+ assertFails(() -> INTEROP.asHostObject(exit), HeapIsolationException.class);
assertTrue(languageEnv.isHostFunction(exit));
Object out = INTEROP.readMember(system, "out");
assertTrue(exit instanceof TruffleObject);
- assertTrue(languageEnv.isHostObject(out));
+ assertTrue(INTEROP.isHostObject(out));
+ assertFalse(INTEROP.isHostObject(out) && INTEROP.isExecutable(out) && !INTEROP.hasMembers(out));
assertFalse(languageEnv.isHostFunction(out));
assertFalse(languageEnv.isHostFunction(system));
+ assertFalse(INTEROP.isHostObject(system) && INTEROP.isExecutable(system) && !INTEROP.hasMembers(system));
assertFalse(languageEnv.isHostFunction(false));
}
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ProxySPITest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ProxySPITest.java
index 5babfbb62b88..c86d59b3f661 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ProxySPITest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ProxySPITest.java
@@ -927,7 +927,7 @@ private static void assertEmpty(Object proxyInner) {
}
}
- private void assertHostError(InteropCallable r) {
+ private static void assertHostError(InteropCallable r) throws InteropException {
try {
r.call();
Assert.fail();
@@ -937,7 +937,7 @@ private void assertHostError(InteropCallable r) {
InteropLibrary interop = InteropLibrary.getUncached();
Assert.assertTrue(interop.isException(e));
Assert.assertEquals("Host Error", e.getMessage());
- Assert.assertTrue(languageEnv.asHostException(e) instanceof TestError);
+ Assert.assertTrue(INTEROP.asHostObject(e) instanceof TestError);
}
}
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueAPITest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueAPITest.java
index deb899a2aff6..ffda6dc6d114 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueAPITest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueAPITest.java
@@ -306,7 +306,7 @@ public void testBooleans() {
@Test
public void testNull() {
assertValueInContexts(context.asValue(null), HOST_OBJECT, NULL);
- assertValueInContexts(createDelegateInteropWrapper(context, context.asValue(null)), NULL);
+ assertValueInContexts(createDelegateInteropWrapper(context, context.asValue(null)), HOST_OBJECT, NULL);
}
private static class BigIntegerSubClass extends BigInteger {
@@ -419,10 +419,7 @@ public void testHostObject() {
Value v = context.asValue(value);
assertValueInContexts(v, expectedTraits.toArray(new Trait[0]));
-
- expectedTraits.remove(HOST_OBJECT);
assertValueInContexts(createDelegateInteropWrapper(context, v), expectedTraits.toArray(new Trait[0]));
-
}
}
@@ -519,10 +516,7 @@ public void testBuffers() {
final Value value = context.asValue(buffer);
assertValueInContexts(value, BUFFER_ELEMENTS, HOST_OBJECT, MEMBERS);
-
- // with the wrapper these buffers are no longer host buffers and trigger context to
- // context migration code
- assertValueInContexts(createDelegateInteropWrapper(context, value), BUFFER_ELEMENTS, MEMBERS);
+ assertValueInContexts(createDelegateInteropWrapper(context, value), BUFFER_ELEMENTS, HOST_OBJECT, MEMBERS);
}
}
@@ -2333,7 +2327,7 @@ private static void expandObjectVariants(Context sourceContext, List obj
public void testHostException() {
Value exceptionValue = context.asValue(new RuntimeException("expected"));
assertValueInContexts(exceptionValue, HOST_OBJECT, MEMBERS, EXCEPTION);
- assertValueInContexts(createDelegateInteropWrapper(context, exceptionValue), MEMBERS, EXCEPTION);
+ assertValueInContexts(createDelegateInteropWrapper(context, exceptionValue), HOST_OBJECT, MEMBERS, EXCEPTION);
try {
exceptionValue.throwException();
fail("should have thrown");
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueHostInteropTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueHostInteropTest.java
index b6a2b1ac1d53..7caf6be29e32 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueHostInteropTest.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueHostInteropTest.java
@@ -358,6 +358,14 @@ public void accessAllPublicPropertiesDirectly() {
assertEquals("One field x", "x", propertyNames[0]);
assertEquals("One method to access x", "readX", propertyNames[1]);
+ Value staticPojo = pojo.getMetaObject().getStaticScope();
+ assertTrue(staticPojo.hasMembers());
+ propertyNames = staticPojo.getMemberKeys().toArray();
+ assertEquals("One static field, one method and class", 3, propertyNames.length);
+ assertEquals("One field y", "y", propertyNames[0]);
+ assertEquals("One method to access y", "readY", propertyNames[1]);
+ assertEquals("The class", "class", propertyNames[2]);
+
Value readX = pojo.getMember("readX");
assertTrue(readX.canExecute());
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/GuestToHostLanguageService.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/GuestToHostLanguageService.java
index 6d4236acb601..99f83aa20d68 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/GuestToHostLanguageService.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/GuestToHostLanguageService.java
@@ -103,26 +103,11 @@ public T toHostType(Object hostNode, Object targetNode, Object hostContext,
throw new UnsupportedOperationException();
}
- @Override
- public boolean isHostValue(Object value) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object unboxHostObject(Object hostValue) {
- throw new UnsupportedOperationException();
- }
-
@Override
public Object unboxProxyObject(Object hostValue) {
throw new UnsupportedOperationException();
}
- @Override
- public Throwable unboxHostException(Throwable hostValue) {
- throw new UnsupportedOperationException();
- }
-
@Override
public Object toHostObject(Object context, Object value) {
throw new UnsupportedOperationException();
@@ -133,26 +118,6 @@ public RuntimeException toHostException(Object hostContext, Throwable exception)
throw new UnsupportedOperationException();
}
- @Override
- public boolean isHostException(Object exception) {
- return false;
- }
-
- @Override
- public boolean isHostFunction(Object obj) {
- return false;
- }
-
- @Override
- public boolean isHostObject(Object obj) {
- return false;
- }
-
- @Override
- public boolean isHostSymbol(Object obj) {
- return false;
- }
-
@Override
public Object createHostAdapter(Object hostContextObject, Object[] types, Object classOverrides) {
return null;
@@ -168,11 +133,6 @@ public Object migrateValue(Object hostContext, Object value, Object valueContext
return null;
}
- @Override
- public Error toHostResourceError(Throwable hostException) {
- return null;
- }
-
@Override
public int findNextGuestToHostStackTraceElement(StackTraceElement firstElement, StackTraceElement[] hostStack, int nextElementIndex) {
return -1;
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/HostEntryPoint.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/HostEntryPoint.java
index 023ee5db491b..57b04c1c35a4 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/HostEntryPoint.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/HostEntryPoint.java
@@ -46,6 +46,7 @@
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
+import com.oracle.truffle.api.interop.InteropException;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.EnvironmentAccess;
@@ -144,7 +145,7 @@ public long remoteGetBindings(long contextId, String languageId) {
return guestToHost(api.getValueReceiver(v));
}
- public Object remoteMessage(long contextId, long receiverId, Message message, Object[] args) {
+ public Object remoteMessage(long contextId, long receiverId, Message message, Object[] args) throws InteropException {
Context c = unmarshall(Context.class, contextId);
c.enter();
try {
@@ -154,13 +155,13 @@ public Object remoteMessage(long contextId, long receiverId, Message message, Ob
Object result;
try {
result = lib.send(receiver, message, localValues);
+ } catch (InteropException e) {
+ throw e;
+ } catch (AbstractTruffleException e) {
+ // also send over stack traces and messages
+ return new GuestExceptionPointer(guestToHost(e), e.getMessage());
} catch (Exception e) {
- if (e instanceof AbstractTruffleException) {
- // also send over stack traces and messages
- return new GuestExceptionPointer(guestToHost(e), e.getMessage());
- } else {
- throw new RuntimeException("Internal error thrown by remote message.", e);
- }
+ throw new RuntimeException("Internal error thrown by remote message.", e);
}
return marshallAtGuest(result);
} finally {
diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/HostGuestValue.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/HostGuestValue.java
index e4ad57759bf6..16535e97395e 100644
--- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/HostGuestValue.java
+++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/wrapper/HostGuestValue.java
@@ -43,6 +43,7 @@
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.exception.AbstractTruffleException;
import com.oracle.truffle.api.interop.ExceptionType;
+import com.oracle.truffle.api.interop.InteropException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.ExportLibrary;
@@ -81,7 +82,7 @@ final Object send(Message message, Object... args) throws Exception {
}
}
- static Object sendImpl(HostEntryPoint hostToGuest, long contextId, long guestId, Message message, Object... args) throws AbstractTruffleException {
+ static Object sendImpl(HostEntryPoint hostToGuest, long contextId, long guestId, Message message, Object... args) throws InteropException, AbstractTruffleException {
Object[] marshalledArgs = marshalToRemote(hostToGuest, args);
Object result = hostToGuest.remoteMessage(contextId, guestId, message, marshalledArgs);
return unmarshallAtHost(hostToGuest, contextId, result);
diff --git a/truffle/src/com.oracle.truffle.api/snapshot.sigtest b/truffle/src/com.oracle.truffle.api/snapshot.sigtest
index 3f2c84e0f650..42de8dbb4c2f 100644
--- a/truffle/src/com.oracle.truffle.api/snapshot.sigtest
+++ b/truffle/src/com.oracle.truffle.api/snapshot.sigtest
@@ -578,10 +578,14 @@ meth public boolean isCreateProcessAllowed()
meth public boolean isCreateThreadAllowed()
meth public boolean isFileIOAllowed()
meth public boolean isHostException(java.lang.Throwable)
+ anno 0 java.lang.Deprecated(boolean forRemoval=false, java.lang.String since="25.1")
meth public boolean isHostFunction(java.lang.Object)
+ anno 0 java.lang.Deprecated(boolean forRemoval=false, java.lang.String since="25.1")
meth public boolean isHostLookupAllowed()
meth public boolean isHostObject(java.lang.Object)
+ anno 0 java.lang.Deprecated(boolean forRemoval=false, java.lang.String since="25.1")
meth public boolean isHostSymbol(java.lang.Object)
+ anno 0 java.lang.Deprecated(boolean forRemoval=false, java.lang.String since="25.1")
meth public boolean isIOAllowed()
anno 0 java.lang.Deprecated(boolean forRemoval=false, java.lang.String since="23.0")
meth public boolean isInnerContextOptionsAllowed()
@@ -616,6 +620,7 @@ meth public java.io.OutputStream out()
meth public java.lang.Object asBoxedGuestValue(java.lang.Object)
meth public java.lang.Object asGuestValue(java.lang.Object)
meth public java.lang.Object asHostObject(java.lang.Object)
+ anno 0 java.lang.Deprecated(boolean forRemoval=false, java.lang.String since="25.1")
meth public java.lang.Object asHostSymbol(java.lang.Class>)
meth public java.lang.Object createHostAdapter(java.lang.Object[])
meth public java.lang.Object createHostAdapterClass(java.lang.Class>[])
@@ -643,6 +648,7 @@ meth public java.lang.Thread createThread(java.lang.Runnable,com.oracle.truffle.
meth public java.lang.Thread createThread(java.lang.Runnable,com.oracle.truffle.api.TruffleContext,java.lang.ThreadGroup,long)
anno 0 java.lang.Deprecated(boolean forRemoval=false, java.lang.String since="")
meth public java.lang.Throwable asHostException(java.lang.Throwable)
+ anno 0 java.lang.Deprecated(boolean forRemoval=false, java.lang.String since="25.1")
meth public java.time.ZoneId getTimeZone()
meth public java.util.Map getInstruments()
meth public java.util.Map getInternalLanguages()
diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java
index f4ed255ad5d1..a539aed8bc00 100644
--- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java
+++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java
@@ -2237,13 +2237,17 @@ public Object lookupHostSymbol(String symbolName) {
* Returns true if the argument is Java host language object wrapped using
* Truffle interop.
*
+ * @deprecated Use
+ * {@linkplain com.oracle.truffle.api.interop.InteropLibrary#isHostObject(Object)
+ * isHostObject}.
* @see #asHostObject(Object)
* @since 19.0
*/
+ @Deprecated(since = "25.1")
@SuppressWarnings("static-method")
public boolean isHostObject(Object value) {
try {
- return LanguageAccessor.engineAccess().isHostObject(polyglotLanguageContext, value);
+ return LanguageAccessor.engineAccess().isHostObject(value);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
@@ -2254,15 +2258,19 @@ public boolean isHostObject(Object value) {
* host language object. Throws {@link ClassCastException} if the provided argument is not a
* {@link #isHostObject(Object) host object}.
*
+ * @deprecated Use
+ * {@linkplain com.oracle.truffle.api.interop.InteropLibrary#asHostObject(Object)
+ * asHostObject}.
* @since 19.0
*/
+ @Deprecated(since = "25.1")
public Object asHostObject(Object value) {
if (!isHostObject(value)) {
CompilerDirectives.transferToInterpreterAndInvalidate();
throw new ClassCastException();
}
try {
- return LanguageAccessor.engineAccess().asHostObject(polyglotLanguageContext, value);
+ return LanguageAccessor.engineAccess().asHostObject(value);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
@@ -2321,11 +2329,14 @@ public Object asBoxedGuestValue(Object guestObject) {
* Truffle interop.
*
* @since 19.0
+ * @deprecated Use
+ * {@code interopLibrary.isHostObject(obj) && interopLibrary.isExecutable(obj) && !interopLibrary.hasMembers(obj)}
*/
+ @Deprecated(since = "25.1")
@SuppressWarnings("static-method")
public boolean isHostFunction(Object value) {
try {
- return LanguageAccessor.engineAccess().isHostFunction(polyglotLanguageContext, value);
+ return LanguageAccessor.engineAccess().isHostFunction(value);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
@@ -2355,7 +2366,7 @@ public Object findMetaObject(Object value) {
/**
* Tests whether an exception is a host exception thrown by a Java Interop method
* invocation.
- *
+ *
* Host exceptions may be thrown by interoperability messages. The host exception may be
* unwrapped using {@link #asHostException(Throwable)}.
*
@@ -2364,11 +2375,14 @@ public Object findMetaObject(Object value) {
* otherwise
* @see #asHostException(Throwable)
* @since 19.0
+ * @deprecated Use
+ * {@code interopLibrary.isHostObject(obj) && interopLibrary.isException(obj)}.
*/
+ @Deprecated(since = "25.1")
@SuppressWarnings("static-method")
public boolean isHostException(Throwable exception) {
try {
- return LanguageAccessor.engineAccess().isHostException(polyglotLanguageContext, exception);
+ return LanguageAccessor.engineAccess().isHostException(exception);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
@@ -2376,7 +2390,7 @@ public boolean isHostException(Throwable exception) {
/**
* Unwraps a host exception thrown by a Java method invocation.
- *
+ *
* Host exceptions may be thrown by interoperability messages. The host exception may be
* unwrapped using {@link #asHostException(Throwable)}.
*
@@ -2385,11 +2399,15 @@ public boolean isHostException(Throwable exception) {
* @throws IllegalArgumentException if the {@code exception} is not a host exception
* @see #isHostException(Throwable)
* @since 19.0
+ * @deprecated Use
+ * {@linkplain com.oracle.truffle.api.interop.InteropLibrary#asHostObject(Object)
+ * asHostObject}.
*/
+ @Deprecated(since = "25.1")
@SuppressWarnings("static-method")
public Throwable asHostException(Throwable exception) {
try {
- return LanguageAccessor.engineAccess().asHostException(polyglotLanguageContext, exception);
+ return LanguageAccessor.engineAccess().asHostException(exception);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
@@ -2401,11 +2419,13 @@ public Throwable asHostException(Throwable exception) {
*
* @see #lookupHostSymbol(String)
* @since 19.0
+ * @deprecated Use {@code interopLibrary.isHostObject(obj) && interopLibrary.isScope(obj)}.
*/
+ @Deprecated(since = "25.1")
@SuppressWarnings("static-method")
public boolean isHostSymbol(Object guestObject) {
try {
- return LanguageAccessor.engineAccess().isHostSymbol(polyglotLanguageContext, guestObject);
+ return LanguageAccessor.engineAccess().isHostSymbol(guestObject);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
@@ -2568,10 +2588,9 @@ public boolean isPolyglotBindingsAccessAllowed() {
* Allows it to be determined if this {@link org.graalvm.polyglot.Context} can execute code
* written in a language with a given MIME type.
*
+ * @return a boolean that indicates if the MIME type is supported
* @see Source#getMimeType()
* @see #parsePublic(Source, String...)
- *
- * @return a boolean that indicates if the MIME type is supported
* @since 0.11
*/
@TruffleBoundary
@@ -2729,7 +2748,7 @@ public OutputStream err() {
* language} may also be associated with additional services. One can request
* implementations of such services by calling this method with the type identifying the
* requested service and its API.
- *
+ *
* Services that can be obtained via this method include
* {@link com.oracle.truffle.api.instrumentation.Instrumenter} and others.
*
@@ -3048,13 +3067,13 @@ public TruffleFile getPublicTruffleFile(URI uri) {
*
* @param path the absolute or relative path to create {@link TruffleFile} for
* @return {@link TruffleFile}
- * @since 19.3.0
* @throws UnsupportedOperationException when the {@link FileSystem} supports only
* {@link URI}
* @throws IllegalArgumentException if the {@code path} string cannot be converted to a
* {@link Path}
* @see #getTruffleFileInternal(String, Predicate)
* @see #getPublicTruffleFile(java.lang.String)
+ * @since 19.3.0
*/
@TruffleBoundary
public TruffleFile getInternalTruffleFile(String path) {
@@ -3075,13 +3094,13 @@ public TruffleFile getInternalTruffleFile(String path) {
*
* @param uri the {@link URI} to create {@link TruffleFile} for
* @return {@link TruffleFile}
- * @since 19.3.0
* @throws UnsupportedOperationException when {@link URI} scheme is not supported
* @throws IllegalArgumentException if preconditions on the {@code uri} do not hold.
* @throws java.nio.file.FileSystemNotFoundException is the file system, identified by the
* {@code uri}, does not exist and cannot be created automatically
* @see #getTruffleFileInternal(URI, Predicate)
* @see #getPublicTruffleFile(java.net.URI)
+ * @since 19.3.0
*/
@TruffleBoundary
public TruffleFile getInternalTruffleFile(URI uri) {
@@ -3136,11 +3155,10 @@ public TruffleFile getInternalTruffleFile(URI uri) {
* {@link URI}
* @throws IllegalArgumentException if the {@code path} string cannot be converted to a
* {@link Path}
- * @since 21.1.0
* @see #getTruffleFileInternal(URI, Predicate)
* @see #getPublicTruffleFile(String)
* @see #getInternalTruffleFile(String)
- *
+ * @since 21.1.0
*/
@TruffleBoundary
public TruffleFile getTruffleFileInternal(String path, Predicate filter) {
@@ -3161,11 +3179,10 @@ public TruffleFile getTruffleFileInternal(String path, Predicate fi
* @throws IllegalArgumentException if preconditions on the {@code uri} do not hold.
* @throws java.nio.file.FileSystemNotFoundException is the file system, identified by the
* {@code uri}, does not exist and cannot be created automatically
- * @since 21.1.0
* @see #getTruffleFileInternal(String, Predicate)
* @see #getPublicTruffleFile(URI)
* @see #getInternalTruffleFile(URI)
- *
+ * @since 21.1.0
*/
@TruffleBoundary
public TruffleFile getTruffleFileInternal(URI uri, Predicate filter) {
@@ -3580,7 +3597,6 @@ public Object createHostAdapterClassWithStaticOverrides(Class>[] types, Object
* @throws UnsupportedOperationException if creating adapter classes is not supported on
* this runtime at all, which is currently the case for native images.
* @throws NullPointerException if {@code types} is null
- *
* @see #createHostAdapterWithClassOverrides(Object[], Object)
* @since 22.1
*/
@@ -3622,7 +3638,6 @@ public Object createHostAdapter(Object[] types) {
* @throws UnsupportedOperationException if creating adapter classes is not supported on
* this runtime at all, which is currently the case for native images.
* @throws NullPointerException if either {@code types} or {@code classOverrides} is null.
- *
* @see #createHostAdapter(Object[])
* @since 22.1
*/
@@ -3700,7 +3715,6 @@ public TruffleFile getInternalResource(String resourceId) throws IOException {
* empty a root logger for language or instrument is returned
* @return a {@link TruffleLogger}
* @since 21.1
- *
*/
@TruffleBoundary
public TruffleLogger getLogger(String loggerName) {
@@ -4051,7 +4065,7 @@ static RuntimeException engineToLanguageException(T
* current {@link Node}, if available, as parameter.
*
* Example intended usage:
- *
+ *
* See {@link ContextReference} for a full usage example.
*
* @since 0.25 revised in 21.3
@@ -4338,15 +4352,14 @@ public enum ContextPolicy {
/**
* Mode of exit operation.
*
- * @since 22.0
* @see #exitContext(Object, ExitMode, int)
+ * @since 22.0
*/
public enum ExitMode {
/**
* Natural exit that occurs during normal context close.
*
* @since 22.0
- *
*/
NATURAL,
/**
diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleStackTrace.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleStackTrace.java
index 07d0e4cd9cb7..37d917700d8f 100644
--- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleStackTrace.java
+++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleStackTrace.java
@@ -47,7 +47,6 @@
import java.util.Objects;
import org.graalvm.polyglot.PolyglotException;
-import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractHostLanguageService;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.Frame;
@@ -270,13 +269,7 @@ public static TruffleStackTrace fillIn(Throwable throwable) {
}
private static boolean isHostException(Throwable throwable) {
- Object polyglotEngine = LanguageAccessor.ENGINE.getCurrentPolyglotEngine();
- if (polyglotEngine == null) {
- return false;
- }
- AbstractHostLanguageService hostService = LanguageAccessor.ENGINE.getHostService(polyglotEngine);
- // hostService is null during context pre-initialization
- return hostService != null && hostService.isHostException(throwable);
+ return LanguageAccessor.ENGINE.isHostException(throwable);
}
private static final class TracebackElement {
diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java
index 92e033a50b57..b2abd6ff5529 100644
--- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java
+++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java
@@ -507,9 +507,9 @@ public abstract Thread createThread(Object polyglotLanguageContext, Runnable run
public abstract RuntimeException wrapHostException(Node callNode, Object languageContext, Throwable exception);
- public abstract boolean isHostException(Object polyglotLanguageContext, Throwable exception);
+ public abstract boolean isHostException(Throwable exception);
- public abstract Throwable asHostException(Object polyglotLanguageContext, Throwable exception);
+ public abstract Throwable asHostException(Throwable exception);
public abstract Object getCurrentHostContext();
@@ -567,13 +567,13 @@ public abstract Thread createThread(Object polyglotLanguageContext, Runnable run
public abstract Set getValidMimeTypes(Object engineObject, String language);
- public abstract Object asHostObject(Object languageContext, Object value);
+ public abstract Object asHostObject(Object value) throws Exception;
- public abstract boolean isHostObject(Object languageContext, Object value);
+ public abstract boolean isHostObject(Object value);
- public abstract boolean isHostFunction(Object languageContext, Object value);
+ public abstract boolean isHostFunction(Object value);
- public abstract boolean isHostSymbol(Object languageContext, Object guestObject);
+ public abstract boolean isHostSymbol(Object guestObject);
public abstract S lookupService(Object polyglotLanguageContext, LanguageInfo language, LanguageInfo accessingLanguage, Class type);
diff --git a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostAccessor.java b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostAccessor.java
index 67fe38282720..79a1b00bff51 100644
--- a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostAccessor.java
+++ b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostAccessor.java
@@ -110,12 +110,19 @@ public boolean isDisconnectedHostProxy(Object value) {
@Override
public boolean isDisconnectedHostObject(Object obj) {
- return HostObject.isInstance(null, obj);
+ return obj instanceof HostObject || obj instanceof HostException || obj instanceof HostFunction;
}
@Override
public Object unboxDisconnectedHostObject(Object hostValue) {
- return HostObject.valueOf(null, hostValue);
+ if (hostValue instanceof HostObject) {
+ return ((HostObject) hostValue).obj;
+ } else if (hostValue instanceof HostException) {
+ return ((HostException) hostValue).delegate.obj;
+ } else if (hostValue instanceof HostFunction) {
+ throw new UnsupportedOperationException();
+ }
+ return hostValue;
}
@Override
diff --git a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostFunction.java b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostFunction.java
index 3df874363797..d95e42fd0b96 100644
--- a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostFunction.java
+++ b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostFunction.java
@@ -46,6 +46,7 @@
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.ArityException;
+import com.oracle.truffle.api.interop.HeapIsolationException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
@@ -67,18 +68,22 @@ final class HostFunction implements TruffleObject {
this.context = context;
}
- public static boolean isInstance(HostLanguage language, TruffleObject obj) {
- return isInstance(language, (Object) obj);
+ @SuppressWarnings("static-method")
+ @ExportMessage
+ boolean isExecutable() {
+ return true;
}
- public static boolean isInstance(HostLanguage language, Object obj) {
- return HostLanguage.unwrapIfScoped(language, obj) instanceof HostFunction;
+ @SuppressWarnings("static-method")
+ @ExportMessage
+ boolean isHostObject() {
+ return true;
}
@SuppressWarnings("static-method")
@ExportMessage
- boolean isExecutable() {
- return true;
+ Object asHostObject() throws HeapIsolationException {
+ throw HeapIsolationException.create();
}
@ExportMessage
@@ -145,5 +150,4 @@ public boolean equals(Object o) {
public int hashCode() {
return method.hashCode();
}
-
}
diff --git a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostLanguageService.java b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostLanguageService.java
index 2e84806c1945..f90f41030d0d 100644
--- a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostLanguageService.java
+++ b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostLanguageService.java
@@ -161,33 +161,11 @@ private boolean validHostValue(Object node, Object hostValue) {
return unboxed == hostValue;
}
- @Override
- public boolean isHostValue(Object value) {
- Object obj = HostLanguage.unwrapIfScoped(language, value);
- return (obj instanceof HostObject) ||
- (obj instanceof HostFunction) ||
- (obj instanceof HostException) ||
- (obj instanceof HostProxy);
- }
-
- @Override
- public Object unboxHostObject(Object hostValue) {
- return HostObject.valueOf(language, hostValue);
- }
-
@Override
public Object unboxProxyObject(Object hostValue) {
return HostProxy.toProxyHostObject(language, hostValue);
}
- @Override
- public Throwable unboxHostException(Throwable hostValue) {
- if (hostValue instanceof HostException) {
- return ((HostException) hostValue).getOriginal();
- }
- return null;
- }
-
@Override
public Object toHostObject(Object hostContext, Object value) {
HostContext context = (HostContext) hostContext;
@@ -199,35 +177,11 @@ public Object asHostDynamicClass(Object context, Class> value) {
return null;
}
- @Override
- public boolean isHostException(Object exception) {
- return exception instanceof HostException;
- }
-
- @Override
- public boolean isHostFunction(Object value) {
- return HostFunction.isInstance(language, value);
- }
-
- @Override
- public boolean isHostObject(Object value) {
- return HostObject.isInstance(language, value);
- }
-
@Override
public boolean isHostProxy(Object value) {
return HostProxy.isProxyGuestObject(language, value);
}
- @Override
- public boolean isHostSymbol(Object obj) {
- Object o = HostLanguage.unwrapIfScoped(language, obj);
- if (o instanceof HostObject) {
- return ((HostObject) o).isStaticClass();
- }
- return false;
- }
-
@Override
public Object createHostAdapter(Object context, Object[] hostTypes, Object classOverrides) {
CompilerAsserts.neverPartOfCompilation();
@@ -261,7 +215,6 @@ public RuntimeException toHostException(Object context, Throwable exception) {
public Object migrateValue(Object targetContext, Object value, Object valueContext) {
assert targetContext != valueContext;
if (value instanceof TruffleObject) {
- assert value instanceof TruffleObject;
if (HostObject.isInstance(language, value)) {
return HostObject.withContext(language, value, (HostContext) HostAccessor.ENGINE.getHostContext(targetContext));
} else if (value instanceof HostProxy) {
@@ -271,7 +224,6 @@ public Object migrateValue(Object targetContext, Object value, Object valueConte
* The only way this can happen is with Value.asValue(TruffleObject). If it happens
* otherwise, its wrong.
*/
- assert value instanceof TruffleObject;
return value;
} else {
// cannot migrate
@@ -283,15 +235,6 @@ public Object migrateValue(Object targetContext, Object value, Object valueConte
}
}
- @Override
- public Error toHostResourceError(Throwable hostException) {
- Throwable t = unboxHostException(hostException);
- if (t instanceof StackOverflowError || t instanceof OutOfMemoryError) {
- return (Error) t;
- }
- return null;
- }
-
@Override
public int findNextGuestToHostStackTraceElement(StackTraceElement firstElement, StackTraceElement[] hostStack, int nextElementIndex) {
StackTraceElement element = firstElement;
diff --git a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostMethodScope.java b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostMethodScope.java
index b63011c1c166..bc663efc64c3 100644
--- a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostMethodScope.java
+++ b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostMethodScope.java
@@ -65,6 +65,7 @@ final class HostMethodScope {
private static final ScopedObject[] EMTPY_SCOPE_ARRAY = new ScopedObject[0];
private static final Unsafe UNSAFE = getUnsafe();
+ private static final Message MESSAGE_AS_HOST_OBJECT = Message.resolveExact(InteropLibrary.class, "asHostObject", Object.class);
private ScopedObject[] scope;
private int nextDynamicIndex;
@@ -246,7 +247,7 @@ Object send(Message message, Object[] args,
"Alternatively, use Value.pin() to prevent a scoped object from being released after the host call completed.");
}
Object returnValue = library.send(d, message, args);
- if (message.getReturnType() == Object.class && !(d instanceof PinnedObject)) {
+ if (message.getReturnType() == Object.class && !(d instanceof PinnedObject) && message != MESSAGE_AS_HOST_OBJECT) {
/*
* Object return type indicates for an interop message that any interop value may be
* returned.
diff --git a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostObject.java b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostObject.java
index 20d5c320bdba..70a742ec33af 100644
--- a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostObject.java
+++ b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostObject.java
@@ -61,6 +61,7 @@
import java.util.NoSuchElementException;
import java.util.Objects;
+import com.oracle.truffle.api.interop.HeapIsolationException;
import org.graalvm.polyglot.impl.AbstractPolyglotImpl.APIAccess;
import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractHostAccess;
@@ -169,34 +170,6 @@ static Object withContext(HostLanguage language, Object originalValue, HostConte
}
}
- static boolean isJavaInstance(HostLanguage language, Class> targetType, Object javaObject) {
- Object unboxed = unboxHostObject(language, javaObject);
- if (unboxed != null) {
- return targetType.isInstance(unboxed);
- }
- return false;
- }
-
- static Object unboxHostObject(HostLanguage language, Object value) {
- Object v = HostLanguage.unwrapIfScoped(language, value);
- if (v instanceof HostObject) {
- return ((HostObject) v).obj;
- } else if (v instanceof HostException) {
- return ((HostException) v).delegate.obj;
- }
- return null;
- }
-
- static Object valueOf(HostLanguage language, Object value) {
- Object v = HostLanguage.unwrapIfScoped(language, value);
- if (v instanceof HostObject) {
- return ((HostObject) v).obj;
- } else if (v instanceof HostException) {
- return ((HostException) v).delegate.obj;
- }
- return v;
- }
-
@Override
public int hashCode() {
return System.identityHashCode(obj);
@@ -3304,12 +3277,16 @@ Object getMetaObject() throws UnsupportedMessageException {
}
}
- @SuppressWarnings("static-method")
@ExportMessage
boolean isMetaObject() {
return isClass();
}
+ @ExportMessage
+ boolean isScope() {
+ return isStaticClass();
+ }
+
@ExportMessage
Object getMetaQualifiedName() throws UnsupportedMessageException {
if (isClass()) {
@@ -3343,13 +3320,19 @@ Object getMetaSimpleName() throws UnsupportedMessageException {
@TruffleBoundary
boolean isMetaInstance(Object other,
@Bind Node node,
- @CachedLibrary("this") InteropLibrary library,
@Shared @Cached InlinedBranchProfile error) throws UnsupportedMessageException {
if (isClass()) {
Class> c = asClass();
- HostLanguage language = context != null ? HostLanguage.get(library) : null;
- if (HostObject.isInstance(language, other)) {
- Object otherHostObj = HostObject.valueOf(language, other);
+ HostLanguage language = context != null ? HostLanguage.get(node) : null;
+ InteropLibrary otherInterop = InteropLibrary.getUncached(other);
+ if (otherInterop.isHostObject(other)) {
+ Object otherHostObj;
+ try {
+ otherHostObj = otherInterop.asHostObject(other);
+ } catch (HeapIsolationException e) {
+ error.enter(node);
+ throw UnsupportedMessageException.create();
+ }
if (otherHostObj == null) {
return false;
} else {
@@ -3435,6 +3418,22 @@ Object readArrayElement(long idx,
}
}
+ @ExportMessage
+ boolean hasStaticScope() {
+ return isMetaObject();
+ }
+
+ @ExportMessage
+ Object getStaticScope(
+ @Bind Node node,
+ @Shared("error") @Cached InlinedBranchProfile error) throws UnsupportedMessageException {
+ if (!hasStaticScope()) {
+ error.enter(node);
+ throw UnsupportedMessageException.create();
+ }
+ return HostObject.forStaticClass((Class>) obj, context);
+ }
+
boolean isStaticClass() {
return extraInfo instanceof Class>;
}
@@ -3490,6 +3489,17 @@ static int identityHashCode(HostObject receiver) {
return System.identityHashCode(receiver.obj);
}
+ @ExportMessage
+ @SuppressWarnings("static-method")
+ boolean isHostObject() {
+ return true;
+ }
+
+ @ExportMessage
+ Object asHostObject() {
+ return this.obj;
+ }
+
@Override
public boolean equals(Object o) {
if (o instanceof HostObject) {
diff --git a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostToTypeNode.java b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostToTypeNode.java
index 78a03afc06b0..a86295e75706 100644
--- a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostToTypeNode.java
+++ b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostToTypeNode.java
@@ -64,6 +64,8 @@
import java.util.Objects;
import java.util.function.Function;
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.interop.HeapIsolationException;
import org.graalvm.polyglot.HostAccess.MutableTargetMapping;
import org.graalvm.polyglot.Value;
@@ -183,9 +185,10 @@ private static Object convertImpl(Node node, Object value, Class> targetType,
return convertedValue;
}
}
- HostLanguage language = HostLanguage.get(interop);
- if (HostObject.isJavaInstance(language, targetType, value)) {
- return HostObject.valueOf(language, value);
+
+ Object hostValue;
+ if ((hostValue = toJavaInstance(value, targetType, interop)) != null) {
+ return hostValue;
}
if (useCustomTargetTypes) {
@@ -201,6 +204,8 @@ private static Object convertImpl(Node node, Object value, Class> targetType,
return convertedValue;
}
}
+
+ HostLanguage language = HostLanguage.get(interop);
if (targetType == language.valueClass && context != null) {
return language.valueClass.isInstance(value) ? value : context.asValue(interop, value);
} else if (interop.isNull(value)) {
@@ -269,7 +274,7 @@ static boolean canConvert(Node node, Object value, Class> targetType, Type gen
return true;
}
}
- if (HostObject.isJavaInstance(language, targetType, value)) {
+ if (toJavaInstance(value, targetType, interop) != null) {
return true;
}
@@ -317,7 +322,7 @@ static boolean canConvert(Node node, Object value, Class> targetType, Type gen
}
if (value instanceof TruffleObject) {
- if (priority < HOST_PROXY && HostObject.isInstance(language, value)) {
+ if (priority < HOST_PROXY && interop.isHostObject(value)) {
return false;
} else {
if (priority >= FUNCTION_PROXY && HostInteropReflect.isFunctionalInterface(targetType) &&
@@ -427,8 +432,9 @@ private static T asJavaObject(Node node, HostContext hostContext, Object val
InteropLibrary interop = InteropLibrary.getFactory().getUncached(value);
assert !interop.isNull(value); // already handled
Object obj;
- if (HostObject.isJavaInstance(hostContext.language, targetType, value)) {
- obj = HostObject.valueOf(hostContext.language, value);
+ Object hostObject = toJavaInstance(value, targetType, interop);
+ if (hostObject != null) {
+ obj = hostObject;
} else if (targetType == Object.class) {
obj = convertToObject(node, hostContext, value, interop);
} else if (targetType == List.class || targetType == Collection.class) {
@@ -651,6 +657,22 @@ private static T asJavaObject(Node node, HostContext hostContext, Object val
return targetType.cast(obj);
}
+ private static Object toJavaInstance(Object value, Class> targetType, InteropLibrary interop) {
+ if (interop.isHostObject(value)) {
+ try {
+ Object hostObject = interop.asHostObject(value);
+ if (hostObject != null && targetType.isInstance(hostObject)) {
+ return hostObject;
+ }
+ } catch (HeapIsolationException e) {
+ return null;
+ } catch (UnsupportedMessageException e) {
+ throw CompilerDirectives.shouldNotReachHere(e);
+ }
+ }
+ return null;
+ }
+
private static Object asPolyglotException(HostContext hostContext, Object value, InteropLibrary interop) {
try {
interop.throwException(value);
diff --git a/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/SerializeArgumentNode.java b/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/SerializeArgumentNode.java
index bc7f75496974..a3e2ca8e7bdd 100644
--- a/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/SerializeArgumentNode.java
+++ b/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/SerializeArgumentNode.java
@@ -50,6 +50,7 @@
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.GenerateInline;
import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.interop.HeapIsolationException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.InvalidBufferOffsetException;
import com.oracle.truffle.api.interop.TruffleObject;
@@ -628,17 +629,20 @@ abstract static class SerializeArrayNode extends SerializeArgumentNode {
}
}
- final boolean isHostObject(Object value) {
- return LibFFIContext.get(this).env.isHostObject(value);
- }
-
- final Object asHostObject(Object value) {
- return LibFFIContext.get(this).env.asHostObject(value);
+ final Object asHostObject(Object value, InteropLibrary interop) throws UnsupportedTypeException {
+ try {
+ return interop.asHostObject(value);
+ } catch (UnsupportedMessageException e) {
+ throw CompilerDirectives.shouldNotReachHere(e);
+ } catch (HeapIsolationException e) {
+ throw UnsupportedTypeException.create(new Object[]{value});
+ }
}
- @Specialization(guards = {"isHostObject(value)", "tag != null"})
+ @Specialization(guards = {"interop.isHostObject(value)", "tag != null"}, limit = "3")
void doHostObject(@SuppressWarnings("unused") Object value, NativeArgumentBuffer buffer,
- @Bind("asHostObject(value)") Object hostObject,
+ @CachedLibrary("value") InteropLibrary interop,
+ @Bind("asHostObject(value, interop)") Object hostObject,
@Bind("getTypeTag.execute(hostObject)") TypeTag tag) {
buffer.putObject(tag, hostObject, type.size);
}
diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/DefaultPolyglotHostService.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/DefaultPolyglotHostService.java
index 9224ae1a5489..caa350476b47 100644
--- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/DefaultPolyglotHostService.java
+++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/DefaultPolyglotHostService.java
@@ -44,6 +44,7 @@
import static com.oracle.truffle.polyglot.PolyglotFastThreadLocals.LANGUAGE_CONTEXT_OFFSET;
import static com.oracle.truffle.polyglot.PolyglotFastThreadLocals.computeLanguageIndexFromStaticIndex;
+import com.oracle.truffle.api.interop.InteropLibrary;
import org.graalvm.polyglot.impl.AbstractPolyglotImpl;
import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractHostLanguageService;
import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractPolyglotHostService;
@@ -76,10 +77,15 @@ public void notifyEngineClosed(Object engineReceiver, boolean cancelIfExecuting)
@Override
public RuntimeException hostToGuestException(AbstractHostLanguageService host, Throwable throwable) {
- assert !host.isHostException(throwable);
+ assert !isHostException(throwable);
return host.toHostException(PolyglotFastThreadLocals.getLanguageContext(null, computeLanguageIndexFromStaticIndex(HOST_LANGUAGE_INDEX, LANGUAGE_CONTEXT_OFFSET)), throwable);
}
+ private static boolean isHostException(Throwable throwable) {
+ InteropLibrary interop = InteropLibrary.getUncached(throwable);
+ return interop.isHostObject(throwable) && interop.isException(throwable);
+ }
+
@Override
public void notifyPolyglotThreadStart(Object contextReceiver, Thread threadToStart) {
}
diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java
index 60df2b5f83fe..1248951f1c77 100644
--- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java
+++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java
@@ -74,6 +74,7 @@
import java.util.logging.Level;
import java.util.logging.LogRecord;
+import com.oracle.truffle.api.interop.HeapIsolationException;
import org.graalvm.collections.Pair;
import org.graalvm.nativeimage.ImageInfo;
import org.graalvm.options.OptionKey;
@@ -628,7 +629,7 @@ public boolean isMultiThreaded(Object guestObject) {
}
if (isPrimitive(guestObject)) {
return false;
- } else if (context.engine.host.isHostValue(guestObject) || guestObject instanceof PolyglotBindings) {
+ } else if (InteropLibrary.getFactory().getUncached(guestObject).isHostObject(guestObject) || context.engine.host.isHostProxy(guestObject) || guestObject instanceof PolyglotBindings) {
return true;
}
PolyglotLanguage language = findObjectLanguage(context.engine, guestObject);
@@ -1259,24 +1260,29 @@ public RuntimeException wrapHostException(Node location, Object languageContext,
}
@Override
- public boolean isHostException(Object languageContext, Throwable exception) {
- PolyglotContextImpl context = ((PolyglotLanguageContext) languageContext).context;
- PolyglotEngineImpl engine = context.engine;
- // During context pre-initialization, engine.host is null, languages are not allowed to
- // use host interop. But the call to isHostException is supported and returns false
- // because languages cannot create a HostObject.
- return !engine.inEnginePreInitialization && engine.host.isHostException(exception);
+ @TruffleBoundary
+ public boolean isHostException(Throwable exception) {
+ InteropLibrary interop = InteropLibrary.getUncached(exception);
+ return interop.isHostObject(exception) && interop.isException(exception);
}
@Override
- public Throwable asHostException(Object languageContext, Throwable exception) {
- PolyglotContextImpl context = ((PolyglotLanguageContext) languageContext).context;
- Throwable host = context.engine.host.unboxHostException(exception);
- if (host == null) {
- CompilerDirectives.transferToInterpreterAndInvalidate();
- throw new IllegalArgumentException("Provided value not a host exception.");
+ @TruffleBoundary
+ public Throwable asHostException(Throwable exception) {
+ if (exception != null) {
+ InteropLibrary interop = InteropLibrary.getUncached(exception);
+ boolean isHostException = interop.isHostObject(exception) && interop.isException(exception);
+ if (isHostException) {
+ try {
+ return (Throwable) interop.asHostObject(exception);
+ } catch (HeapIsolationException e) {
+ return null;
+ } catch (UnsupportedMessageException e) {
+ // Fall through to IllegalArgumentException
+ }
+ }
}
- return host;
+ throw new IllegalArgumentException("Provided value not a host exception.");
}
@Override
@@ -1543,40 +1549,40 @@ public Object getLoggerOwner(Object loggerCache) {
}
@Override
- public Object asHostObject(Object languageContext, Object obj) {
- PolyglotContextImpl context = ((PolyglotLanguageContext) languageContext).context;
- assert isHostObject(languageContext, obj);
- return context.engine.host.unboxHostObject(obj);
+ @TruffleBoundary
+ public Object asHostObject(Object obj) {
+ InteropLibrary interop = InteropLibrary.getUncached(obj);
+ if (interop.isHostObject(obj)) {
+ try {
+ return interop.asHostObject(obj);
+ } catch (HeapIsolationException e) {
+ return null;
+ } catch (UnsupportedMessageException e) {
+ // Fall through to IllegalArgumentException
+ }
+ }
+ throw new IllegalArgumentException("Provided value not a host object.");
}
@Override
- public boolean isHostFunction(Object languageContext, Object obj) {
- PolyglotContextImpl context = ((PolyglotLanguageContext) languageContext).context;
- PolyglotEngineImpl engine = context.engine;
- // During context pre-initialization, engine.host is null, languages are not allowed to
- // use host interop. But the call to isHostFunction is supported and returns false
- // because languages cannot create a HostObject.
- return !engine.inEnginePreInitialization && engine.host.isHostFunction(obj);
+ @TruffleBoundary
+ public boolean isHostFunction(Object obj) {
+ InteropLibrary interop = InteropLibrary.getUncached(obj);
+ return interop.isHostObject(obj) && interop.isExecutable(obj) && !interop.hasMembers(obj);
}
@Override
- public boolean isHostObject(Object languageContext, Object obj) {
- PolyglotContextImpl context = ((PolyglotLanguageContext) languageContext).context;
- PolyglotEngineImpl engine = context.engine;
- // During context pre-initialization, engine.host is null, languages are not allowed to
- // use host interop. But the call to isHostObject is supported and returns false because
- // languages cannot create a HostObject.
- return !engine.inEnginePreInitialization && engine.host.isHostObject(obj);
+ @TruffleBoundary
+ public boolean isHostObject(Object obj) {
+ InteropLibrary interop = InteropLibrary.getUncached(obj);
+ return interop.isHostObject(obj);
}
@Override
- public boolean isHostSymbol(Object languageContext, Object obj) {
- PolyglotContextImpl context = ((PolyglotLanguageContext) languageContext).context;
- PolyglotEngineImpl engine = context.engine;
- // During context pre-initialization, engine.host is null, languages are not allowed to
- // use host interop. But the call to isHostSymbol is supported and returns false because
- // languages cannot create a HostObject.
- return !engine.inEnginePreInitialization && engine.host.isHostSymbol(obj);
+ @TruffleBoundary
+ public boolean isHostSymbol(Object obj) {
+ InteropLibrary interop = InteropLibrary.getUncached(obj);
+ return interop.isHostObject(obj) && interop.isScope(obj);
}
@Override
diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/OtherContextGuestObject.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/OtherContextGuestObject.java
index fde3cbb578b6..01d0e86abe25 100644
--- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/OtherContextGuestObject.java
+++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/OtherContextGuestObject.java
@@ -66,6 +66,7 @@ final class OtherContextGuestObject implements TruffleObject {
static final Object OTHER_VALUE = new Object();
static final ReflectionLibrary OTHER_VALUE_UNCACHED = ReflectionLibrary.getFactory().getUncached(OTHER_VALUE);
+ private static final Message MESSAGE_AS_HOST_OBJECT = Message.resolveExact(InteropLibrary.class, "asHostObject", Object.class);
final PolyglotContextImpl receiverContext;
final Object delegate;
@@ -159,7 +160,7 @@ static Object sendImpl(Node node, PolyglotSharingLayer layer, Object receiver, M
if (message.getReturnType() == void.class) {
return null;
}
- return migrateReturn(returnValue, receiverContext, delegateContext);
+ return migrateReturn(returnValue, message, receiverContext, delegateContext);
} catch (Throwable e) {
seenError.enter(node);
throw migrateException(receiverContext, e, delegateContext);
@@ -264,8 +265,10 @@ private static Object fallbackSend(Message message, Object[] args) throws Except
return OTHER_VALUE_UNCACHED.send(OTHER_VALUE, message, args);
}
- private static Object migrateReturn(Object arg, PolyglotContextImpl receiverContext, PolyglotContextImpl delegateContext) {
- if (arg instanceof TruffleObject) {
+ private static Object migrateReturn(Object arg, Message message, PolyglotContextImpl receiverContext, PolyglotContextImpl delegateContext) {
+ if (message == MESSAGE_AS_HOST_OBJECT) {
+ return arg;
+ } else if (arg instanceof TruffleObject) {
return receiverContext.migrateValue(arg, delegateContext);
} else {
assert InteropLibrary.isValidProtocolValue(arg) : "unexpected interop primitive";
diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotExceptionImpl.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotExceptionImpl.java
index 4820305b91b6..845bbee1faa3 100644
--- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotExceptionImpl.java
+++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotExceptionImpl.java
@@ -131,7 +131,7 @@ final class PolyglotExceptionImpl {
} else {
creationStackTrace = null;
}
- Error resourceLimitError = getResourceLimitError(engine, exception);
+ Error resourceLimitError = getResourceLimitError(exception);
String exceptionQualifiedName = null;
String exceptionMessage = null;
InteropLibrary interop;
@@ -158,7 +158,7 @@ final class PolyglotExceptionImpl {
} else {
this.sourceLocation = null;
}
- if (entered && languageContext != null && languageContext.isCreated() && !isHostException(engine, exception)) {
+ if (entered && languageContext != null && languageContext.isCreated() && !isHostException(exception)) {
this.guestObject = languageContext.asValue(exception);
} else {
this.guestObject = null;
@@ -173,7 +173,7 @@ final class PolyglotExceptionImpl {
* InterruptExecution was thrown before the context was made invalid.
*/
boolean interruptException = (exception instanceof PolyglotEngineImpl.InterruptExecution) || (exception != null && exception.getCause() instanceof InterruptedException) ||
- (isHostException(engine, exception) && asHostException() instanceof InterruptedException);
+ (isHostException(exception) && asHostException() instanceof InterruptedException);
boolean truffleException = exception instanceof com.oracle.truffle.api.exception.AbstractTruffleException;
boolean cancelInducedTruffleOrInterruptException = (polyglotContextState != null &&
(polyglotContextState.isCancelling() || polyglotContextState == PolyglotContextImpl.State.CLOSED_CANCELLED) &&
@@ -228,11 +228,11 @@ final class PolyglotExceptionImpl {
qualifiedName = exceptionQualifiedName;
}
- private static Error getResourceLimitError(PolyglotEngineImpl engine, Throwable e) {
+ private static Error getResourceLimitError(Throwable e) {
if (e instanceof CancelExecution) {
return ((CancelExecution) e).isResourceLimit() ? (Error) e : null;
- } else if (isHostException(engine, e)) {
- Error toCheck = engine.host.toHostResourceError(e);
+ } else if (isHostException(e)) {
+ Error toCheck = toHostResourceError(e);
assert toCheck == null || toCheck instanceof StackOverflowError || toCheck instanceof OutOfMemoryError;
return toCheck;
} else if (e instanceof StackOverflowError || e instanceof OutOfMemoryError) {
@@ -241,6 +241,14 @@ private static Error getResourceLimitError(PolyglotEngineImpl engine, Throwable
return null;
}
+ private static Error toHostResourceError(Throwable hostException) {
+ Throwable t = unboxHostException(hostException);
+ if (t instanceof StackOverflowError || t instanceof OutOfMemoryError) {
+ return (Error) t;
+ }
+ return null;
+ }
+
private Object newSourceSection(com.oracle.truffle.api.source.SourceSection section) {
com.oracle.truffle.api.source.Source truffleSource = section.getSource();
Object source = polyglot.getAPIAccess().newSource(polyglot.getSourceDispatch(), truffleSource);
@@ -277,7 +285,7 @@ public boolean isInterrupted() {
}
public boolean isHostException() {
- return isHostException(engine, exception);
+ return isHostException(exception);
}
public Throwable asHostException() {
@@ -285,7 +293,7 @@ public Throwable asHostException() {
throw PolyglotEngineException.unsupported(
String.format("Unsupported operation PolyglotException.asHostException(). You can ensure that the operation is supported using PolyglotException.isHostException()"));
}
- return engine.host.unboxHostException(exception);
+ return unboxHostException(exception);
}
void printStackTrace(PrintWriter s) {
@@ -536,9 +544,9 @@ static Iterator createStackFrameIterator(PolyglotExceptionImpl impl) {
APIAccess apiAccess = impl.polyglot.getAPIAccess();
StackTraceElement[] hostStack = null;
- if (isHostException(impl.engine, impl.exception)) {
- Throwable original = impl.engine.host.unboxHostException(impl.exception);
- hostStack = original.getStackTrace();
+ if (isHostException(impl.exception)) {
+ Throwable original = unboxHostException(impl.exception);
+ hostStack = original != null ? original.getStackTrace() : impl.exception.getStackTrace();
} else if (EngineAccessor.EXCEPTION.isException(impl.exception)) {
Throwable lazyStack = EngineAccessor.EXCEPTION.getLazyStackTrace(impl.exception);
if (lazyStack != null) {
@@ -581,11 +589,17 @@ public Object apply(TruffleStackTraceElement guestFrame) {
});
}
- private static boolean isHostException(PolyglotEngineImpl engine, Throwable cause) {
- /*
- * Note that engine.host can be null if the error happens during initialization.
- */
- return engine != null && engine.host != null && engine.host.isHostException(cause);
+ private static boolean isHostException(Throwable cause) {
+ InteropLibrary interop = InteropLibrary.getUncached(cause);
+ return interop.isHostObject(cause) && interop.isException(cause);
+ }
+
+ private static Throwable unboxHostException(Throwable cause) {
+ try {
+ return (Throwable) InteropLibrary.getUncached(cause).asHostObject(cause);
+ } catch (Exception e) {
+ throw CompilerDirectives.shouldNotReachHere(e);
+ }
}
static class MergedHostGuestIterator implements Iterator {
diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java
index b4a1fbcb1d94..82bf41134be0 100644
--- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java
+++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java
@@ -100,6 +100,7 @@
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.api.strings.TruffleString.Encoding;
import com.oracle.truffle.polyglot.EngineAccessor.AbstractClassLoaderSupplier;
+import com.oracle.truffle.polyglot.PolyglotEngineImpl.CancelExecution;
import com.oracle.truffle.polyglot.PolyglotEngineImpl.LogConfig;
import com.oracle.truffle.polyglot.PolyglotLoggers.EngineLoggerProvider;
@@ -928,22 +929,35 @@ static RuntimeException guestToHostException(PolyglotLangu
PolyglotExceptionImpl suppressedImpl = null;
PolyglotContextImpl.State localContextState = context.state;
PolyglotImpl polyglot = context.engine.impl;
- if (localContextState.isInvalidOrClosed()) {
- exceptionImpl = new PolyglotExceptionImpl(polyglot, context.engine, localContextState, context.invalidResourceLimit, context.exitCode, languageContext, e, false, false);
- } else {
- try {
- exceptionImpl = new PolyglotExceptionImpl(languageContext.getImpl(), languageContext.context.engine, localContextState, false, 0,
- languageContext, e, true, entered);
- } catch (Throwable t) {
- /*
- * It is possible that we fail to produce a guest value or interop message failed.
- * We report the original exception without using interop messages. We also convert
- * the exception thrown from the PolyglotExceptionImpl constructor to a new
- * PolyglotException and add it to resulting exception suppressed exceptions.
- */
- exceptionImpl = new PolyglotExceptionImpl(context.engine, localContextState, false, 0, e);
- suppressedImpl = new PolyglotExceptionImpl(context.engine, localContextState, false, 0, t);
+ try {
+ if (localContextState.isInvalidOrClosed()) {
+ exceptionImpl = new PolyglotExceptionImpl(polyglot, context.engine, localContextState, context.invalidResourceLimit, context.exitCode, languageContext, e, false, false);
+ } else {
+ try {
+ exceptionImpl = new PolyglotExceptionImpl(languageContext.getImpl(), languageContext.context.engine, localContextState, false, 0,
+ languageContext, e, true, entered);
+ } catch (Throwable t) {
+ /*
+ * It is possible that we fail to produce a guest value or interop message
+ * failed. We report the original exception without using interop messages. We
+ * also convert the exception thrown from the PolyglotExceptionImpl constructor
+ * to a new PolyglotException and add it to resulting exception suppressed
+ * exceptions.
+ */
+ exceptionImpl = new PolyglotExceptionImpl(context.engine, localContextState, false, 0, e);
+ suppressedImpl = new PolyglotExceptionImpl(context.engine, localContextState, false, 0, t);
+ }
}
+ } catch (CancelExecution cancelExecution) {
+ /*
+ * The interop protocol is used to create a PolyglotExceptionImpl. A polyglot isolate
+ * always attempts to enter a context before processing an interop message. If the
+ * context has been cancelled, the enter operation throws a CancelExecution exception
+ * that is propagated to PolyglotExceptionImpl constructor. In such cases, the
+ * CancelExecution exception is wrapped in a PolyglotException and rethrown to the
+ * embedder.
+ */
+ exceptionImpl = new PolyglotExceptionImpl(context.engine, localContextState, false, 0, cancelExecution);
}
APIAccess access = polyglot.getAPIAccess();
RuntimeException polyglotException = access.newLanguageException(exceptionImpl.getMessage(), polyglot.exceptionDispatch, exceptionImpl, context.getContextAPIOrNull());
diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotValueDispatch.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotValueDispatch.java
index 2638b726f215..032763b917d1 100644
--- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotValueDispatch.java
+++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotValueDispatch.java
@@ -59,6 +59,7 @@
import java.util.NoSuchElementException;
import java.util.Set;
+import com.oracle.truffle.api.interop.HeapIsolationException;
import org.graalvm.polyglot.impl.AbstractPolyglotImpl;
import org.graalvm.polyglot.impl.AbstractPolyglotImpl.APIAccess;
import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractValueDispatch;
@@ -92,6 +93,7 @@
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.AsClassLiteralNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.AsDateNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.AsDurationNodeGen;
+import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.AsHostObjectNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.AsInstantNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.AsNativePointerNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.AsTimeNodeGen;
@@ -118,6 +120,7 @@
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.GetMemberNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.GetMetaQualifiedNameNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.GetMetaSimpleNameNodeGen;
+import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.GetStaticScopeNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.HasArrayElementsNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.HasBufferElementsNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.HasHashEntriesNodeGen;
@@ -126,12 +129,14 @@
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.HasIteratorNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.HasMemberNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.HasMembersNodeGen;
+import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.HasStaticScopeNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.InvokeNoArgsNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.InvokeNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.IsBufferWritableNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.IsDateNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.IsDurationNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.IsExceptionNodeGen;
+import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.IsHostObjectNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.IsMetaInstanceNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.IsMetaObjectNodeGen;
import com.oracle.truffle.polyglot.PolyglotValueDispatchFactory.InteropValueFactory.IsNativePointerNodeGen;
@@ -585,6 +590,24 @@ static RuntimeException removeMemberUnsupported(PolyglotLanguageContext context,
throw unsupported(context, receiver, "removeMember(String, Object)", null);
}
+ @Override
+ public Object getStaticScope(Object languageContext, Object receiver) {
+ PolyglotLanguageContext context = (PolyglotLanguageContext) languageContext;
+ Object prev = hostEnter(context);
+ try {
+ return getStaticScopeUnsupported(context, receiver);
+ } catch (Throwable e) {
+ throw guestToHostException(context, e, true);
+ } finally {
+ hostLeave(context, prev);
+ }
+ }
+
+ @TruffleBoundary
+ static Object getStaticScopeUnsupported(PolyglotLanguageContext context, Object receiver) {
+ throw unsupported(context, receiver, "getStaticScope(Object)", "hasStaticScope");
+ }
+
@Override
public Object execute(Object languageContext, Object receiver, Object[] arguments) {
PolyglotLanguageContext context = (PolyglotLanguageContext) languageContext;
@@ -2293,9 +2316,13 @@ static final class InteropValue extends PolyglotValueDispatch {
final CallTarget getHashEntriesIterator;
final CallTarget getHashKeysIterator;
final CallTarget getHashValuesIterator;
-
+ final CallTarget isHostObject;
+ final CallTarget asHostObject;
final CallTarget asClassLiteral;
final CallTarget asTypeLiteral;
+ final CallTarget hasStaticScope;
+ final CallTarget getStaticScope;
+
final Class> receiverType;
InteropValue(PolyglotImpl polyglot, PolyglotLanguageInstance languageInstance, Object receiverObject, Class> receiverType) {
@@ -2375,7 +2402,10 @@ static final class InteropValue extends PolyglotValueDispatch {
this.getHashEntriesIterator = createTarget(GetHashEntriesIteratorNodeGen.create(this));
this.getHashKeysIterator = createTarget(GetHashKeysIteratorNodeGen.create(this));
this.getHashValuesIterator = createTarget(GetHashValuesIteratorNodeGen.create(this));
-
+ this.isHostObject = createTarget(IsHostObjectNodeGen.create(this));
+ this.asHostObject = createTarget(AsHostObjectNodeGen.create(this));
+ this.hasStaticScope = createTarget(HasStaticScopeNodeGen.create(this));
+ this.getStaticScope = createTarget(GetStaticScopeNodeGen.create(this));
}
@SuppressWarnings("unchecked")
@@ -2540,6 +2570,16 @@ public Set getMemberKeys(Object languageContext, Object receiver) {
return new MemberSet(this.getEngine().getAPIAccess(), languageContext, receiver, keys);
}
+ @Override
+ public boolean hasStaticScope(Object languageContext, Object receiver) {
+ return (boolean) RUNTIME.callProfiled(this.hasStaticScope, languageContext, receiver);
+ }
+
+ @Override
+ public Object getStaticScope(Object languageContext, Object receiver) {
+ return RUNTIME.callProfiled(this.getStaticScope, languageContext, receiver);
+ }
+
@Override
public long asNativePointer(Object languageContext, Object receiver) {
return (long) RUNTIME.callProfiled(this.asNativePointer, languageContext, receiver);
@@ -2592,15 +2632,7 @@ public Duration asDuration(Object languageContext, Object receiver) {
@Override
public boolean isHostObject(Object languageContext, Object receiver) {
- PolyglotLanguageContext context = (PolyglotLanguageContext) languageContext;
- Object prev = hostEnter(context);
- try {
- return getEngine().host.isHostObject(receiver);
- } catch (Throwable e) {
- throw guestToHostException(context, e, true);
- } finally {
- hostLeave(context, prev);
- }
+ return (boolean) RUNTIME.callProfiled(this.isHostObject, languageContext, receiver);
}
private PolyglotEngineImpl getEngine() {
@@ -2631,11 +2663,7 @@ public Object asProxyObject(Object languageContext, Object receiver) {
@Override
public Object asHostObject(Object languageContext, Object receiver) {
- if (isHostObject(languageContext, receiver)) {
- return getEngine().host.unboxHostObject(receiver);
- } else {
- return super.asHostObject(languageContext, receiver);
- }
+ return RUNTIME.callProfiled(this.asHostObject, languageContext, receiver);
}
@Override
@@ -5587,6 +5615,120 @@ static Object doCached(PolyglotLanguageContext context, Object receiver, Object[
}
}
- }
+ abstract static class IsHostObjectNode extends InteropNode {
+
+ protected IsHostObjectNode(InteropValue interop) {
+ super(interop);
+ }
+
+ @Override
+ protected Class>[] getArgumentTypes() {
+ return new Class>[]{PolyglotLanguageContext.class, polyglot.receiverType};
+ }
+
+ @Override
+ protected String getOperationName() {
+ return "isHostObject";
+ }
+ @Specialization(limit = "CACHE_LIMIT")
+ static Object doCached(PolyglotLanguageContext context, Object receiver, Object[] args, @Bind Node node,
+ @CachedLibrary("receiver") InteropLibrary objects) {
+ return objects.isHostObject(receiver);
+ }
+ }
+
+ abstract static class AsHostObjectNode extends InteropNode {
+
+ protected AsHostObjectNode(InteropValue interop) {
+ super(interop);
+ }
+
+ @Override
+ protected Class>[] getArgumentTypes() {
+ return new Class>[]{PolyglotLanguageContext.class, polyglot.receiverType};
+ }
+
+ @Override
+ protected String getOperationName() {
+ return "asHostObject";
+ }
+
+ @Specialization(limit = "CACHE_LIMIT")
+ static Object doCached(PolyglotLanguageContext context, Object receiver, Object[] args, @Bind Node node,
+ @CachedLibrary("receiver") InteropLibrary objects,
+ @Cached InlinedBranchProfile unsupported,
+ @Cached InlinedBranchProfile isolatedHeap) {
+ try {
+ return objects.asHostObject(receiver);
+ } catch (UnsupportedMessageException e) {
+ unsupported.enter(node);
+ return asHostObjectUnsupported(context, receiver);
+ } catch (HeapIsolationException e) {
+ isolatedHeap.enter(node);
+ throw asHostObjectIsolatedHeap(context, receiver);
+ }
+ }
+
+ @TruffleBoundary
+ static RuntimeException asHostObjectIsolatedHeap(PolyglotLanguageContext context, Object receiver) {
+ String polyglotMessage = String.format("Unsupported operation Value.asHostObject() for %s. The referenced host object resides in an isolated heap.", getValueInfo(context, receiver));
+ return PolyglotEngineException.unsupported(polyglotMessage);
+ }
+ }
+
+ abstract static class HasStaticScopeNode extends InteropNode {
+
+ protected HasStaticScopeNode(InteropValue interop) {
+ super(interop);
+ }
+
+ @Override
+ protected Class>[] getArgumentTypes() {
+ return new Class>[]{PolyglotLanguageContext.class, polyglot.receiverType};
+ }
+
+ @Override
+ protected String getOperationName() {
+ return "hasStaticScope";
+ }
+
+ @Specialization(limit = "CACHE_LIMIT")
+ static Object doCached(PolyglotLanguageContext context, Object receiver, Object[] args, //
+ @CachedLibrary("receiver") InteropLibrary objects) {
+ return objects.hasStaticScope(receiver);
+ }
+ }
+
+ abstract static class GetStaticScopeNode extends InteropNode {
+
+ protected GetStaticScopeNode(InteropValue interop) {
+ super(interop);
+ }
+
+ @Override
+ protected Class>[] getArgumentTypes() {
+ return new Class>[]{PolyglotLanguageContext.class, polyglot.receiverType};
+ }
+
+ @Override
+ protected String getOperationName() {
+ return "getStaticScope";
+ }
+
+ @Specialization(limit = "CACHE_LIMIT")
+ static Object doCached(PolyglotLanguageContext context, Object receiver, Object[] args, //
+ @Bind Node node,
+ @CachedLibrary("receiver") InteropLibrary objects,
+ @Cached ToHostValueNode toHost,
+ @Cached InlinedBranchProfile unsupported) {
+ try {
+ return toHost.execute(node, context, objects.getStaticScope(receiver));
+ } catch (UnsupportedMessageException e) {
+ unsupported.enter(node);
+ return getStaticScopeUnsupported(context, receiver);
+ }
+ }
+ }
+ }
}
diff --git a/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/ValueAssert.java b/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/ValueAssert.java
index 4302fa7d90d9..4240f2c80bf4 100644
--- a/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/ValueAssert.java
+++ b/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/ValueAssert.java
@@ -210,7 +210,7 @@ public static void assertUnsupported(Value value, Trait... supported) {
assertFails(() -> value.asDouble(), NullPointerException.class);
} else {
- if (value.isHostObject() && value.asHostObject() instanceof Number) {
+ if (isReachableHostObject(value) && value.asHostObject() instanceof Number) {
assertSame(value.asHostObject(), value.as(Number.class));
} else {
assertFails(() -> value.as(Number.class), ClassCastException.class);
@@ -282,7 +282,7 @@ public static void assertUnsupported(Value value, Trait... supported) {
if (value.isNull()) {
assertNull(value.as(Map.class));
} else {
- if ((!value.isHostObject() || (!(value.asHostObject() instanceof Map))) && !value.hasHashEntries()) {
+ if ((!isReachableHostObject(value) || (!(value.asHostObject() instanceof Map))) && !value.hasHashEntries()) {
assertFails(() -> value.as(Map.class), ClassCastException.class);
}
}
@@ -301,7 +301,7 @@ public static void assertUnsupported(Value value, Trait... supported) {
if (value.hasMembers()) {
assertFails(() -> value.as(FUNCTION).apply(null), UnsupportedOperationException.class);
assertFails(() -> value.as(IsFunctionalInterfaceVarArgs.class).foobarbaz(123), UnsupportedOperationException.class);
- } else if (!value.isHostObject() || (!(value.asHostObject() instanceof Function))) {
+ } else if (!isReachableHostObject(value) || (!(value.asHostObject() instanceof Function))) {
assertFails(() -> value.as(FUNCTION), ClassCastException.class);
assertFails(() -> value.as(IsFunctionalInterfaceVarArgs.class), ClassCastException.class);
}
@@ -320,7 +320,7 @@ public static void assertUnsupported(Value value, Trait... supported) {
if (value.hasMembers()) {
assertFails(() -> value.as(FUNCTION).apply(null), UnsupportedOperationException.class);
assertFails(() -> value.as(IsFunctionalInterfaceVarArgs.class).foobarbaz(123), UnsupportedOperationException.class);
- } else if (!value.isHostObject() || (!(value.asHostObject() instanceof Function))) {
+ } else if (!isReachableHostObject(value) || (!(value.asHostObject() instanceof Function))) {
assertFails(() -> value.as(FUNCTION), ClassCastException.class);
assertFails(() -> value.as(IsFunctionalInterfaceVarArgs.class), ClassCastException.class);
}
@@ -335,7 +335,7 @@ public static void assertUnsupported(Value value, Trait... supported) {
assertFails(() -> value.setArrayElement(0, null), UnsupportedOperationException.class);
assertFails(() -> value.getArraySize(), UnsupportedOperationException.class);
if (!value.isNull()) {
- if ((!value.isHostObject() || (!(value.asHostObject() instanceof List) && !(value.asHostObject() instanceof Object[])))) {
+ if ((!isReachableHostObject(value) || (!(value.asHostObject() instanceof List) && !(value.asHostObject() instanceof Object[])))) {
assertFails(() -> value.as(List.class), ClassCastException.class);
assertFails(() -> value.as(Object[].class), ClassCastException.class);
}
@@ -362,7 +362,7 @@ public static void assertUnsupported(Value value, Trait... supported) {
assertFails(() -> value.writeBufferDouble(ByteOrder.LITTLE_ENDIAN, 0, 0.0), UnsupportedOperationException.class);
if (!value.isNull()) {
- if ((!value.isHostObject() || (!(value.asHostObject() instanceof ByteBuffer)))) {
+ if ((!isReachableHostObject(value) || (!(value.asHostObject() instanceof ByteBuffer)))) {
assertFails(() -> value.as(ByteBuffer.class), ClassCastException.class);
}
} else {
@@ -371,7 +371,7 @@ public static void assertUnsupported(Value value, Trait... supported) {
break;
case HOST_OBJECT:
assertFalse(value.isHostObject());
- assertFails(() -> value.asHostObject(), ClassCastException.class);
+ assertFails(() -> value.asHostObject(), ClassCastException.class, UnsupportedOperationException.class);
break;
case PROXY_OBJECT:
assertFalse(value.isProxyObject());
@@ -459,6 +459,8 @@ public static void assertUnsupported(Value value, Trait... supported) {
assertFails(() -> value.isMetaInstance(""), UnsupportedOperationException.class);
assertFalse(value.hasMetaParents());
assertFails(() -> value.getMetaParents(), UnsupportedOperationException.class);
+ assertFalse(value.hasStaticScope());
+ assertFails(() -> value.getStaticScope(), UnsupportedOperationException.class);
break;
case ITERABLE:
assertFalse(value.hasIterator());
@@ -479,7 +481,7 @@ public static void assertUnsupported(Value value, Trait... supported) {
if (value.isNull()) {
assertNull(value.as(Map.class));
} else {
- if ((!value.isHostObject() || (!(value.asHostObject() instanceof Map))) && !value.hasMembers()) {
+ if ((!isReachableHostObject(value) || (!(value.asHostObject() instanceof Map))) && !value.hasMembers()) {
assertFails(() -> value.as(Map.class), ClassCastException.class);
}
}
@@ -490,6 +492,19 @@ public static void assertUnsupported(Value value, Trait... supported) {
}
}
+ private static boolean isReachableHostObject(Value value) {
+ if (!value.isHostObject()) {
+ return false;
+ }
+ try {
+ value.asHostObject();
+ return true;
+ } catch (UnsupportedOperationException unsupported) {
+ // HeapIsolationException - unboxing is not supported.
+ return false;
+ }
+ }
+
@SuppressWarnings("unchecked")
private static void assertValueImpl(Value value, int depth, boolean hasHostAccess, Trait... expectedTypes) {
if (depth > 1) {
@@ -567,36 +582,37 @@ private static void assertValueImpl(Value value, int depth, boolean hasHostAcces
break;
case HOST_OBJECT:
assertTrue(msg, value.isHostObject());
- Object hostObject = value.asHostObject();
- assertFalse(hostObject instanceof Proxy);
- boolean isStaticClass = false;
- if (hasHostAccess && hostObject != null && value.hasMembers() && !java.lang.reflect.Proxy.isProxyClass(hostObject.getClass())) {
- if (hostObject instanceof Class) {
- isStaticClass = value.hasMember("class");
- if (isStaticClass) {
- assertClassMembers(value, (Class>) hostObject, true);
+ if (isReachableHostObject(value)) {
+ Object hostObject = value.asHostObject();
+ assertFalse(hostObject instanceof Proxy);
+ boolean isStaticClass = false;
+ if (hasHostAccess && hostObject != null && value.hasMembers() && !java.lang.reflect.Proxy.isProxyClass(hostObject.getClass())) {
+ if (hostObject instanceof Class) {
+ isStaticClass = value.hasMember("class");
+ if (isStaticClass) {
+ assertClassMembers(value, (Class>) hostObject, true);
+ } else {
+ assertClassMembers(value, Class.class, false);
+ assertTrue(value.hasMember("static"));
+ }
} else {
- assertClassMembers(value, Class.class, false);
- assertTrue(value.hasMember("static"));
- }
- } else {
- // Asserts that value exposes the same members as the host object's
- // class first public inclusive ancestor.
- for (Class> clazz = hostObject.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
- if (Modifier.isPublic(clazz.getModifiers())) {
- assertClassMembers(value, clazz, false);
- break;
+ // Asserts that value exposes the same members as the host object's
+ // class first public inclusive ancestor.
+ for (Class> clazz = hostObject.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
+ if (Modifier.isPublic(clazz.getModifiers())) {
+ assertClassMembers(value, clazz, false);
+ break;
+ }
}
}
}
+ if (isStaticClass) {
+ assertNotEquals(Value.asValue(hostObject), value);
+ } else {
+ assertEquals(Value.asValue(hostObject), value);
+ }
+ assertEquals(Value.asValue(hostObject).hashCode(), value.hashCode());
}
- if (isStaticClass) {
- assertNotEquals(Value.asValue(hostObject), value);
- } else {
- assertEquals(Value.asValue(hostObject), value);
- }
- assertEquals(Value.asValue(hostObject).hashCode(), value.hashCode());
-
break;
case PROXY_OBJECT:
assertTrue(msg, value.isProxyObject());
@@ -621,7 +637,7 @@ private static void assertValueImpl(Value value, int depth, boolean hasHostAcces
if (value.isNull()) {
assertNull(value.as(STRING_OBJECT_MAP));
- } else if (value.isHostObject() && value.asHostObject() instanceof Map) {
+ } else if (isReachableHostObject(value) && value.asHostObject() instanceof Map) {
Map expectedValues = value.asHostObject();
assertEquals(value.as(OBJECT_OBJECT_MAP), expectedValues);
} else if (value.hasHashEntries()) {
@@ -734,6 +750,23 @@ private static void assertValueImpl(Value value, int depth, boolean hasHostAcces
// caught expected exception
}
}
+ if (value.hasStaticScope()) {
+ Value staticScope = value.getStaticScope();
+ assertTrue(staticScope.hasMembers());
+ for (String key : staticScope.getMemberKeys()) {
+ Value staticMember = staticScope.getMember(key);
+ assertValueImpl(staticMember, depth + 1, hasHostAccess, detectSupportedTypes(staticMember));
+ }
+ } else {
+ try {
+ value.getStaticScope();
+ fail("should have thrown");
+ } catch (PolyglotException expected) {
+ throw new AssertionError(expected);
+ } catch (UnsupportedOperationException expected) {
+ // caught expected exception
+ }
+ }
break;
case ITERABLE:
assertTrue(msg, value.hasIterator());
@@ -756,7 +789,7 @@ private static void assertValueImpl(Value value, int depth, boolean hasHostAcces
}
private static boolean isSameHostObject(Value a, Value b) {
- return a.isHostObject() && b.isHostObject() && a.asHostObject() == b.asHostObject();
+ return isReachableHostObject(a) && isReachableHostObject(b) && a.asHostObject() == b.asHostObject();
}
@SuppressWarnings("unchecked")
@@ -777,7 +810,7 @@ private static void assertValueArrayElements(Value value, int depth, boolean has
List objectList1 = value.as(OBJECT_LIST);
List objectList2 = Arrays.asList(value.as(Object[].class));
- if (!value.isHostObject() || !(value.asHostObject() instanceof List>)) {
+ if (!isReachableHostObject(value) || !(value.asHostObject() instanceof List>)) {
assertFalse(objectList1.equals(objectList2));
}
assertTrue(objectList1.equals(objectList1));
diff --git a/truffle/src/org.graalvm.truffle.benchmark/src/org/graalvm/truffle/benchmark/interop/HostProxyBenchmarkLanguage.java b/truffle/src/org.graalvm.truffle.benchmark/src/org/graalvm/truffle/benchmark/interop/HostProxyBenchmarkLanguage.java
index 84375abc2e7f..9e301b7318da 100644
--- a/truffle/src/org.graalvm.truffle.benchmark/src/org/graalvm/truffle/benchmark/interop/HostProxyBenchmarkLanguage.java
+++ b/truffle/src/org.graalvm.truffle.benchmark/src/org/graalvm/truffle/benchmark/interop/HostProxyBenchmarkLanguage.java
@@ -50,6 +50,7 @@
import com.oracle.truffle.api.dsl.NeverDefault;
import com.oracle.truffle.api.exception.AbstractTruffleException;
import com.oracle.truffle.api.interop.ArityException;
+import com.oracle.truffle.api.interop.HeapIsolationException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
@@ -109,11 +110,16 @@ Object execute(Object[] args, @Bind Node node) throws ArityException, Unsupporte
Object receiver = args[0];
String messageName = InteropLibrary.getUncached().asString(args[1]);
Object arg1 = args[2];
- if (!env.isHostObject(arg1)) {
+ InteropLibrary hostObjects = InteropLibrary.getUncached(arg1);
+ if (!hostObjects.isHostObject(arg1)) {
throw new InteropBenchmarkException("Invalid arguments. Interop message name and arguments with receiver as host Object[].");
}
- Object[] hostArguments = (Object[]) env.asHostObject(arg1);
- return new ExecuteInteropExecutable(receiver, messageName, hostArguments);
+ try {
+ Object[] hostArguments = (Object[]) hostObjects.asHostObject(arg1);
+ return new ExecuteInteropExecutable(receiver, messageName, hostArguments);
+ } catch (HeapIsolationException e) {
+ throw new InteropBenchmarkException("Invalid arguments. Host object cannot be unboxed because it was allocated in an isolated heap.");
+ }
}
}
diff --git a/truffle/src/org.graalvm.truffle.benchmark/src/org/graalvm/truffle/benchmark/tstring/TStringBenchDummyLanguage.java b/truffle/src/org.graalvm.truffle.benchmark/src/org/graalvm/truffle/benchmark/tstring/TStringBenchDummyLanguage.java
index 7faa5f5197a1..72583e7f1eeb 100644
--- a/truffle/src/org.graalvm.truffle.benchmark/src/org/graalvm/truffle/benchmark/tstring/TStringBenchDummyLanguage.java
+++ b/truffle/src/org.graalvm.truffle.benchmark/src/org/graalvm/truffle/benchmark/tstring/TStringBenchDummyLanguage.java
@@ -41,11 +41,16 @@
package org.graalvm.truffle.benchmark.tstring;
import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.HeapIsolationException;
+import com.oracle.truffle.api.interop.InteropLibrary;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.strings.TruffleString;
@@ -236,9 +241,9 @@ abstract static class RawIterateBytesNode extends Node {
public abstract int execute(Object input);
- @Specialization
- int bench(Object hostObject) {
- byte[] input = (byte[]) DummyLanguageContext.get(this).getEnv().asHostObject(hostObject);
+ @Specialization(limit = "3")
+ int bench(Object hostObject, @CachedLibrary("hostObject") InteropLibrary interop) {
+ byte[] input = (byte[]) asHostObject(hostObject, interop);
int ret = 0;
for (int i = 0; i < input.length; i++) {
ret += Byte.toUnsignedInt(input[i]);
@@ -323,10 +328,11 @@ abstract static class CalcStringAttributesUTF8Node extends Node {
abstract TruffleString execute(Object hostObject, int length);
- @Specialization
+ @Specialization(limit = "3")
TruffleString bench(Object hostObject, int length,
- @Cached TruffleString.FromByteArrayNode fromByteArrayNode) {
- byte[] input = (byte[]) DummyLanguageContext.get(this).getEnv().asHostObject(hostObject);
+ @Cached TruffleString.FromByteArrayNode fromByteArrayNode,
+ @CachedLibrary("hostObject") InteropLibrary interop) {
+ byte[] input = (byte[]) asHostObject(hostObject, interop);
return fromByteArrayNode.execute(input, 0, length, TruffleString.Encoding.UTF_8, false);
}
}
@@ -335,10 +341,11 @@ abstract static class CalcStringAttributesUTF16Node extends Node {
abstract TruffleString execute(Object hostObject, int length);
- @Specialization
+ @Specialization(limit = "3")
TruffleString bench(Object hostObject, int length,
- @Cached TruffleString.FromByteArrayNode fromByteArrayNode) {
- byte[] input = (byte[]) DummyLanguageContext.get(this).getEnv().asHostObject(hostObject);
+ @Cached TruffleString.FromByteArrayNode fromByteArrayNode,
+ @CachedLibrary("hostObject") InteropLibrary interop) {
+ byte[] input = (byte[]) asHostObject(hostObject, interop);
return fromByteArrayNode.execute(input, 0, length, TruffleString.Encoding.UTF_16, false);
}
}
@@ -347,10 +354,11 @@ abstract static class FromByteArrayUTF16Node extends Node {
abstract TruffleString execute(Object hostObject, int length);
- @Specialization
+ @Specialization(limit = "3")
TruffleString bench(Object hostObject, int length,
- @Cached TruffleString.FromByteArrayNode fromByteArrayNode) {
- byte[] input = (byte[]) DummyLanguageContext.get(this).getEnv().asHostObject(hostObject);
+ @Cached TruffleString.FromByteArrayNode fromByteArrayNode,
+ @CachedLibrary("hostObject") InteropLibrary interop) {
+ byte[] input = (byte[]) asHostObject(hostObject, interop);
return fromByteArrayNode.execute(input, 0, length, TruffleString.Encoding.UTF_16, true);
}
}
@@ -359,10 +367,11 @@ abstract static class FromByteArrayUTF32Node extends Node {
abstract TruffleString execute(Object hostObject, int length);
- @Specialization
+ @Specialization(limit = "3")
TruffleString bench(Object hostObject, int length,
- @Cached TruffleString.FromByteArrayNode fromByteArrayNode) {
- byte[] input = (byte[]) DummyLanguageContext.get(this).getEnv().asHostObject(hostObject);
+ @Cached TruffleString.FromByteArrayNode fromByteArrayNode,
+ @CachedLibrary("hostObject") InteropLibrary interop) {
+ byte[] input = (byte[]) asHostObject(hostObject, interop);
return fromByteArrayNode.execute(input, 0, length, TruffleString.Encoding.UTF_32, true);
}
}
@@ -371,10 +380,11 @@ abstract static class FromByteArrayUTF16FENode extends Node {
abstract TruffleString execute(Object hostObject, int length);
- @Specialization
+ @Specialization(limit = "3")
TruffleString bench(Object hostObject, int length,
- @Cached TruffleString.FromByteArrayNode fromByteArrayNode) {
- byte[] input = (byte[]) DummyLanguageContext.get(this).getEnv().asHostObject(hostObject);
+ @Cached TruffleString.FromByteArrayNode fromByteArrayNode,
+ @CachedLibrary("hostObject") InteropLibrary interop) {
+ byte[] input = (byte[]) asHostObject(hostObject, interop);
return fromByteArrayNode.execute(input, 0, length, TruffleString.Encoding.UTF_16BE, false);
}
}
@@ -383,11 +393,12 @@ abstract static class FromByteArrayUTF16FESwitchNode extends Node {
abstract TruffleString execute(Object hostObject, int length);
- @Specialization
+ @Specialization(limit = "3")
TruffleString bench(Object hostObject, int length,
@Cached TruffleString.FromByteArrayNode fromByteArrayNode,
- @Cached TruffleString.SwitchEncodingNode switchEncodingNode) {
- byte[] input = (byte[]) DummyLanguageContext.get(this).getEnv().asHostObject(hostObject);
+ @Cached TruffleString.SwitchEncodingNode switchEncodingNode,
+ @CachedLibrary("hostObject") InteropLibrary interop) {
+ byte[] input = (byte[]) asHostObject(hostObject, interop);
return switchEncodingNode.execute(fromByteArrayNode.execute(input, 0, length, TruffleString.Encoding.UTF_16BE, false), TruffleString.Encoding.UTF_16);
}
}
@@ -396,10 +407,11 @@ abstract static class FromByteArrayUTF32FENode extends Node {
abstract TruffleString execute(Object hostObject, int length);
- @Specialization
+ @Specialization(limit = "3")
TruffleString bench(Object hostObject, int length,
- @Cached TruffleString.FromByteArrayNode fromByteArrayNode) {
- byte[] input = (byte[]) DummyLanguageContext.get(this).getEnv().asHostObject(hostObject);
+ @Cached TruffleString.FromByteArrayNode fromByteArrayNode,
+ @CachedLibrary("hostObject") InteropLibrary interop) {
+ byte[] input = (byte[]) asHostObject(hostObject, interop);
return fromByteArrayNode.execute(input, 0, length, TruffleString.Encoding.UTF_32BE, false);
}
}
@@ -408,11 +420,12 @@ abstract static class FromByteArrayUTF32FESwitchNode extends Node {
abstract TruffleString execute(Object hostObject, int length);
- @Specialization
+ @Specialization(limit = "3")
TruffleString bench(Object hostObject, int length,
@Cached TruffleString.FromByteArrayNode fromByteArrayNode,
- @Cached TruffleString.SwitchEncodingNode switchEncodingNode) {
- byte[] input = (byte[]) DummyLanguageContext.get(this).getEnv().asHostObject(hostObject);
+ @Cached TruffleString.SwitchEncodingNode switchEncodingNode,
+ @CachedLibrary("hostObject") InteropLibrary interop) {
+ byte[] input = (byte[]) asHostObject(hostObject, interop);
return switchEncodingNode.execute(fromByteArrayNode.execute(input, 0, length, TruffleString.Encoding.UTF_32BE, false), TruffleString.Encoding.UTF_32);
}
}
@@ -455,4 +468,12 @@ public static DummyLanguageContext get(Node node) {
return REFERENCE.get(node);
}
}
+
+ static Object asHostObject(Object guestObject, InteropLibrary interop) {
+ try {
+ return interop.asHostObject(guestObject);
+ } catch (UnsupportedMessageException | HeapIsolationException e) {
+ throw CompilerDirectives.shouldNotReachHere(e);
+ }
+ }
}