Skip to content

Commit ce63100

Browse files
committed
[GR-71402] Adding isHostObject and asHostObject interop messages.
PullRequest: graal/22085
2 parents a1dbb59 + 46bde32 commit ce63100

File tree

51 files changed

+1468
-520
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1468
-520
lines changed

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ public StaticObject doForeignNull(Object value,
656656
@Specialization(guards = {
657657
"interop.hasIterator(value)",
658658
"interop.hasMetaObject(value)",
659-
"isHostObject(getContext(), value)",
659+
"interop.isHostObject(value)",
660660
"!isStaticObject(value)"
661661
})
662662
@SuppressWarnings("truffle-static-method")
@@ -734,7 +734,7 @@ public StaticObject doForeignNull(Object value,
734734
@Specialization(guards = {
735735
"interop.hasIterator(value)",
736736
"interop.hasMetaObject(value)",
737-
"isHostObject(getContext(), value)",
737+
"interop.isHostObject(value)",
738738
"!isStaticObject(value)"
739739
})
740740
@SuppressWarnings("truffle-static-method")
@@ -812,7 +812,7 @@ public StaticObject doForeignNull(Object value,
812812
@Specialization(guards = {
813813
"interop.isIterator(value)",
814814
"interop.hasMetaObject(value)",
815-
"isHostObject(getContext(), value)",
815+
"interop.isHostObject(value)",
816816
"!isStaticObject(value)"
817817
})
818818
@SuppressWarnings("truffle-static-method")
@@ -890,7 +890,7 @@ public StaticObject doForeignNull(Object value,
890890
@Specialization(guards = {
891891
"interop.hasHashEntries(value)",
892892
"interop.hasMetaObject(value)",
893-
"isHostObject(getContext(), value)",
893+
"interop.isHostObject(value)",
894894
"!isStaticObject(value)"
895895
})
896896
@SuppressWarnings("truffle-static-method")
@@ -966,7 +966,7 @@ public StaticObject doForeignNull(Object value,
966966

967967
@Specialization(guards = {
968968
"interop.hasMetaObject(value)",
969-
"isHostObject(getContext(), value)",
969+
"interop.isHostObject(value)",
970970
"!isStaticObject(value)"
971971
})
972972
@SuppressWarnings("truffle-static-method")
@@ -1715,7 +1715,7 @@ public StaticObject doEspresso(StaticObject value,
17151715
@Specialization(guards = {
17161716
"!isStaticObject(value)",
17171717
"!interop.isNull(value)",
1718-
"isHostObject(getContext(), value)"
1718+
"interop.isHostObject(value)"
17191719
})
17201720
StaticObject doForeignInterface(Object value,
17211721
@Bind Node node,
@@ -1780,7 +1780,7 @@ public StaticObject doEspresso(StaticObject value,
17801780
@Specialization(guards = {
17811781
"!isStaticObject(value)",
17821782
"!interop.isNull(value)",
1783-
"isHostObject(getContext(), value)"
1783+
"interop.isHostObject(value)"
17841784
})
17851785
StaticObject doForeignConverter(Object value,
17861786
@Bind Node node,
@@ -1855,7 +1855,7 @@ public StaticObject doEspresso(StaticObject value,
18551855
@Specialization(guards = {
18561856
"!isStaticObject(value)",
18571857
"!interop.isNull(value)",
1858-
"isHostObject(getContext(), value)"
1858+
"interop.isHostObject(value)"
18591859
})
18601860
StaticObject doForeignInternalConverter(Object value,
18611861
@Bind Node node,
@@ -2799,8 +2799,4 @@ static boolean isEspressoException(Object obj) {
27992799
static boolean isTypeMappingEnabled(EspressoContext context) {
28002800
return context.getPolyglotTypeMappings().hasMappings();
28012801
}
2802-
2803-
static boolean isHostObject(EspressoContext context, Object value) {
2804-
return context.getEnv().isHostObject(value);
2805-
}
28062802
}

sdk/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ This changelog summarizes major changes between GraalVM SDK versions. The main f
1010
* GR-65404 Remove `PolyglotLauncher` as it is no longer used.
1111
* GR-68613: JavaScript polyglot isolate now includes support for the WebAssembly (Wasm) language.
1212
* GR-69590: Closing a garbage-collected engine or context now logs only the first failure by default. To log all failures, use `engine.CloseOnGCFailureAction.PrintAll`.
13+
* GR-35913: Updated the Javadoc of `Value#asHostObject()`, `Value#asNativePointer()`, and `Value#asProxyObject()` to clarify that these methods throw a `ClassCastException` rather than an `UnsupportedOperationException` when the value is not of the expected type.
14+
* GR-35913: `Value#asHostObject()` throws `UnsupportedOperationException` if object is allocated in a foreign heap.
15+
* GR-71402: Added `Value#hasStaticScope` and `Value#getStaticScope` returning the static scope representing static or class-level members associated with the meta object.
1316

1417
## Version 25.0.0
1518
* GR-60636 Truffle now stops compiling when the code cache fills up on HotSpot. A warning is printed when that happens.

sdk/src/org.graalvm.polyglot/snapshot.sigtest

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,7 @@ meth public boolean hasIteratorNextElement()
598598
meth public boolean hasMember(java.lang.String)
599599
meth public boolean hasMembers()
600600
meth public boolean hasMetaParents()
601+
meth public boolean hasStaticScope()
601602
meth public boolean isBoolean()
602603
meth public boolean isBufferWritable()
603604
meth public boolean isDate()
@@ -659,6 +660,7 @@ meth public org.graalvm.polyglot.Value getIteratorNextElement()
659660
meth public org.graalvm.polyglot.Value getMember(java.lang.String)
660661
meth public org.graalvm.polyglot.Value getMetaObject()
661662
meth public org.graalvm.polyglot.Value getMetaParents()
663+
meth public org.graalvm.polyglot.Value getStaticScope()
662664
meth public short asShort()
663665
meth public short readBufferShort(java.nio.ByteOrder,long)
664666
meth public static org.graalvm.polyglot.Value asValue(java.lang.Object)

sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Value.java

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -1008,6 +1008,55 @@ public boolean removeMember(String identifier) {
10081008
}
10091009
}
10101010

1011+
/**
1012+
* Returns {@code true} if this value is a {@linkplain #isMetaObject() meta object} that
1013+
* provides a {@linkplain #getStaticScope() static scope}. A static scope represents the static
1014+
* or class level members associated with the type described by this meta object, such as static
1015+
* fields or methods.
1016+
*
1017+
* @throws IllegalStateException if the context is already {@linkplain Context#close() closed}
1018+
* @throws PolyglotException if a guest language error occurs during execution
1019+
* @see #isMetaObject()
1020+
* @see #getStaticScope()
1021+
* @since 25.1
1022+
*/
1023+
public boolean hasStaticScope() {
1024+
return dispatch.hasStaticScope(this.context, receiver);
1025+
}
1026+
1027+
/**
1028+
* Returns the static scope associated with this value. This value must be a
1029+
* {@linkplain #isMetaObject() meta-object}. A static scope is an object that exposes static
1030+
* members, members whose values or behavior are independent of any particular instance.
1031+
* <p>
1032+
* The returned static scope can be used to access static members using
1033+
* {@link #getMember(String)}, {@link #getMemberKeys()}, or
1034+
* {@link #invokeMember(String, Object...)}.
1035+
* <p>
1036+
* The returned static scope is always expected to provide {@link #hasMembers() members},
1037+
* representing the static context.
1038+
* <p>
1039+
* <b>Examples:</b>
1040+
* </p>
1041+
* <ul>
1042+
* <li>In Java, the static scope exposes static fields and methods of a class.</li>
1043+
* <li>In Python, the static scope exposes class-level attributes and methods, effectively
1044+
* corresponding to the members provided by the Python metaobject.</li>
1045+
* </ul>
1046+
*
1047+
* @throws UnsupportedOperationException if and only if this value does not
1048+
* {@linkplain #hasStaticScope() have a static scope}
1049+
* @throws IllegalStateException if the context is already {@linkplain Context#close() closed}
1050+
* @throws PolyglotException if a guest language error occurs during execution
1051+
* @see #hasStaticScope()
1052+
* @see #isMetaObject()
1053+
* @see #hasMembers()
1054+
* @since 25.1
1055+
*/
1056+
public Value getStaticScope() {
1057+
return (Value) dispatch.getStaticScope(this.context, receiver);
1058+
}
1059+
10111060
// executable
10121061

10131062
/**
@@ -1554,7 +1603,7 @@ public boolean isNativePointer() {
15541603
/**
15551604
* Returns the value of the pointer as <code>long</code> value.
15561605
*
1557-
* @throws UnsupportedOperationException if the value is not a pointer.
1606+
* @throws ClassCastException if the value is not a pointer.
15581607
* @throws PolyglotException if a guest language error occurred during execution.
15591608
* @throws IllegalStateException if the underlying context was closed.
15601609
* @since 19.0
@@ -1586,7 +1635,9 @@ public boolean isHostObject() {
15861635
/**
15871636
* Returns the original Java host language object.
15881637
*
1589-
* @throws UnsupportedOperationException if {@link #isHostObject()} is <code>false</code>.
1638+
* @throws ClassCastException if {@link #isHostObject()} is <code>false</code>
1639+
* @throws UnsupportedOperationException if Java host language object is allocated in a foreign
1640+
* heap.
15901641
* @throws PolyglotException if a guest language error occurred during execution.
15911642
* @throws IllegalStateException if the underlying context was closed.
15921643
* @since 19.0
@@ -1620,7 +1671,7 @@ public boolean isProxyObject() {
16201671
* Returns the unboxed instance of the {@link Proxy}. Proxies are not automatically boxed to
16211672
* {@link #isHostObject() host objects} on host language call boundaries (Java methods).
16221673
*
1623-
* @throws UnsupportedOperationException if a value is not a proxy object.
1674+
* @throws ClassCastException if a value is not a proxy object.
16241675
* @throws PolyglotException if a guest language error occurred during execution.
16251676
* @throws IllegalStateException if the underlying context was closed.
16261677
* @since 19.0

sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/impl/AbstractPolyglotImpl.java

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,32 +1034,16 @@ public abstract void initializeHostContext(Object internalContext, Object contex
10341034

10351035
public abstract <T> T toHostType(Object hostNode, Object targetNode, Object hostContext, Object value, Class<T> targetType, Type genericType);
10361036

1037-
public abstract boolean isHostValue(Object value);
1038-
1039-
public abstract Object unboxHostObject(Object hostValue);
1040-
10411037
public abstract Object unboxProxyObject(Object hostValue);
10421038

1043-
public abstract Throwable unboxHostException(Throwable hostValue);
1044-
10451039
public abstract Object toHostObject(Object context, Object value);
10461040

10471041
public abstract RuntimeException toHostException(Object hostContext, Throwable exception);
10481042

1049-
public abstract boolean isHostException(Object exception);
1050-
1051-
public abstract boolean isHostFunction(Object obj);
1052-
1053-
public abstract boolean isHostObject(Object obj);
1054-
1055-
public abstract boolean isHostSymbol(Object obj);
1056-
10571043
public abstract Object createHostAdapter(Object hostContextObject, Object[] types, Object classOverrides);
10581044

10591045
public abstract boolean isHostProxy(Object value);
10601046

1061-
public abstract Error toHostResourceError(Throwable hostException);
1062-
10631047
public abstract int findNextGuestToHostStackTraceElement(StackTraceElement firstElement, StackTraceElement[] hostStack, int nextElementIndex);
10641048

10651049
public abstract Object migrateValue(Object hostContext, Object value, Object valueContext);
@@ -1153,6 +1137,12 @@ public Set<String> getMemberKeys(Object context, Object receiver) {
11531137

11541138
public abstract boolean removeMember(Object context, Object receiver, String key);
11551139

1140+
public boolean hasStaticScope(Object context, Object receiver) {
1141+
return false;
1142+
}
1143+
1144+
public abstract Object getStaticScope(Object context, Object receiver);
1145+
11561146
public boolean canExecute(Object context, Object receiver) {
11571147
return false;
11581148
}

sulong/tests/com.oracle.truffle.llvm.tests.interop/src/com/oracle/truffle/llvm/tests/interop/PolyglotBuiltinTest.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2024, Oracle and/or its affiliates.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates.
33
*
44
* All rights reserved.
55
*
@@ -35,6 +35,7 @@
3535
import java.math.BigInteger;
3636
import java.util.HashMap;
3737

38+
import com.oracle.truffle.api.interop.InteropException;
3839
import org.hamcrest.MatcherAssert;
3940
import org.junit.Assert;
4041
import org.junit.Assume;
@@ -161,13 +162,14 @@ public TestHostInteropNode() {
161162
}
162163

163164
@Test
164-
public void testHostInterop(@Inject(TestHostInteropNode.class) CallTarget testHostInterop) {
165+
public void testHostInterop(@Inject(TestHostInteropNode.class) CallTarget testHostInterop) throws InteropException {
165166
Assume.assumeFalse("skipping host interop test in native mode", TruffleOptions.AOT);
166167

167168
Object ret = testHostInterop.call();
168169

169-
Assert.assertTrue("isHostObject", runWithPolyglot.getTruffleTestEnv().isHostObject(ret));
170-
Assert.assertSame("ret", BigInteger.class, runWithPolyglot.getTruffleTestEnv().asHostObject(ret));
170+
InteropLibrary interop = InteropLibrary.getUncached(ret);
171+
Assert.assertTrue("isHostObject", interop.isHostObject(ret));
172+
Assert.assertSame("ret", BigInteger.class, interop.asHostObject(ret));
171173
}
172174

173175
public static class TestEvalNoLang extends SulongTestNode {

truffle/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ This changelog summarizes major changes between Truffle versions relevant to lan
6161
* GR-71088 Added `CompilerDirectives.EarlyEscapeAnalysis` annotation that runs partial escape analysis early before partial evaluation enabling partial-evaluation-constant scalar replacements.
6262
* GR-71870 Truffle DSL no longer supports mixed exclusive and shared inlined caches. Sharing will now be disabled if mixing was used. To resolve the new warnings it is typically necessary to use either `@Exclusive` or `@Shared` for all caches.
6363
* GR-71887: Bytecode DSL: Added a `ClearLocal` operation for fast clearing of local values.
64+
* GR-71088 Added `CompilerDirectives.EarlyEscapeAnalysis` annotation that runs partial escape analysis early before partial evaluation enabling partial-evaluation-constant scalar replacements.
65+
* GR-71402: Added `InteropLibrary#isHostObject` and `InteropLibrary#asHostObject` for accessing the Java host-object representation of a Truffle guest object. Deprecated `Env#isHostObject`, `Env#isHostException`, `Env#isHostFunction`, `Env#isHostSymbol`, `Env#asHostObject`, and `Env#asHostException` in favor of the new InteropLibrary messages.
66+
* GR-71402: Added `InteropLibrary#hasStaticScope` and `InteropLibrary#getStaticScope` returning the static scope representing static or class-level members associated with the given meta object.
67+
6468

6569
## Version 25.0
6670
* GR-31495 Added ability to specify language and instrument specific options using `Source.Builder.option(String, String)`. Languages may describe available source options by implementing `TruffleLanguage.getSourceOptionDescriptors()` and `TruffleInstrument.getSourceOptionDescriptors()` respectively.

truffle/src/com.oracle.truffle.api.debug/snapshot.sigtest

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ meth public final boolean isNull()
212212
meth public final com.oracle.truffle.api.debug.DebugValue asInLanguage(com.oracle.truffle.api.nodes.LanguageInfo)
213213
meth public final com.oracle.truffle.api.debug.DebugValue getMetaObject()
214214
meth public final com.oracle.truffle.api.debug.DebugValue getProperty(java.lang.String)
215+
meth public final com.oracle.truffle.api.debug.DebugValue getStaticScope()
215216
meth public final com.oracle.truffle.api.nodes.LanguageInfo getOriginalLanguage()
216217
meth public final com.oracle.truffle.api.source.SourceSection getSourceLocation()
217218
meth public final java.lang.String asString()

truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebugValue.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,30 @@ public void accept(Breakpoint b) {
10311031
return breakpoints[0] != null ? breakpoints[0] : Collections.emptyList();
10321032
}
10331033

1034+
/**
1035+
* Returns a value that provides static members whose value is independent on a specific
1036+
* instance. Returns {@code null} when no static scope is available.
1037+
*
1038+
* @throws DebugException when guest language code throws an exception
1039+
* @since 25.1
1040+
*/
1041+
public final DebugValue getStaticScope() {
1042+
if (!isReadable()) {
1043+
return null;
1044+
}
1045+
Object view = getLanguageView();
1046+
try {
1047+
if (INTEROP.hasStaticScope(view)) {
1048+
return new HeapValue(getSession(), resolveLanguage(), null, INTEROP.getStaticScope(view));
1049+
}
1050+
} catch (ThreadDeath td) {
1051+
throw td;
1052+
} catch (Throwable ex) {
1053+
throw DebugException.create(getSession(), ex, resolveLanguage(), null, true, null);
1054+
}
1055+
return null;
1056+
}
1057+
10341058
/**
10351059
* Provides properties representing an internal structure of this value. The returned collection
10361060
* is not thread-safe. If the value is not {@link #isReadable() readable} then <code>null</code>

truffle/src/com.oracle.truffle.api.exception/src/com/oracle/truffle/api/exception/ExceptionAccessor.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@
4747
import java.util.ListIterator;
4848
import java.util.function.Function;
4949

50-
import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractHostLanguageService;
51-
5250
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5351
import com.oracle.truffle.api.TruffleStackTrace;
5452
import com.oracle.truffle.api.TruffleStackTraceElement;
@@ -183,10 +181,9 @@ public Object getExceptionStackTrace(Object receiver, Object polyglotContext) {
183181

184182
private static Object[] mergeHostGuestFrames(Throwable throwable, List<TruffleStackTraceElement> guestStack, boolean inHost, Object polyglotEngine) {
185183
StackTraceElement[] hostStack = null;
186-
AbstractHostLanguageService hostService = ACCESSOR.engineSupport().getHostService(polyglotEngine);
187-
if (hostService.isHostException(throwable)) {
188-
Throwable original = hostService.unboxHostException(throwable);
189-
hostStack = original.getStackTrace();
184+
Throwable originalHostException;
185+
if (ACCESSOR.engineSupport().isHostException(throwable) && (originalHostException = ACCESSOR.engineSupport().asHostException(throwable)) != null) {
186+
hostStack = originalHostException.getStackTrace();
190187
} else if (throwable instanceof AbstractTruffleException) {
191188
Throwable lazyStackTrace = ((AbstractTruffleException) throwable).getLazyStackTrace();
192189
if (lazyStackTrace != null) {

0 commit comments

Comments
 (0)