Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ public StaticObject doForeignNull(Object value,
@Specialization(guards = {
"interop.hasIterator(value)",
"interop.hasMetaObject(value)",
"isHostObject(getContext(), value)",
"interop.isHostObject(value)",
"!isStaticObject(value)"
})
@SuppressWarnings("truffle-static-method")
Expand Down Expand Up @@ -734,7 +734,7 @@ public StaticObject doForeignNull(Object value,
@Specialization(guards = {
"interop.hasIterator(value)",
"interop.hasMetaObject(value)",
"isHostObject(getContext(), value)",
"interop.isHostObject(value)",
"!isStaticObject(value)"
})
@SuppressWarnings("truffle-static-method")
Expand Down Expand Up @@ -812,7 +812,7 @@ public StaticObject doForeignNull(Object value,
@Specialization(guards = {
"interop.isIterator(value)",
"interop.hasMetaObject(value)",
"isHostObject(getContext(), value)",
"interop.isHostObject(value)",
"!isStaticObject(value)"
})
@SuppressWarnings("truffle-static-method")
Expand Down Expand Up @@ -890,7 +890,7 @@ public StaticObject doForeignNull(Object value,
@Specialization(guards = {
"interop.hasHashEntries(value)",
"interop.hasMetaObject(value)",
"isHostObject(getContext(), value)",
"interop.isHostObject(value)",
"!isStaticObject(value)"
})
@SuppressWarnings("truffle-static-method")
Expand Down Expand Up @@ -966,7 +966,7 @@ public StaticObject doForeignNull(Object value,

@Specialization(guards = {
"interop.hasMetaObject(value)",
"isHostObject(getContext(), value)",
"interop.isHostObject(value)",
"!isStaticObject(value)"
})
@SuppressWarnings("truffle-static-method")
Expand Down Expand Up @@ -1715,7 +1715,7 @@ public StaticObject doEspresso(StaticObject value,
@Specialization(guards = {
"!isStaticObject(value)",
"!interop.isNull(value)",
"isHostObject(getContext(), value)"
"interop.isHostObject(value)"
})
StaticObject doForeignInterface(Object value,
@Bind Node node,
Expand Down Expand Up @@ -1780,7 +1780,7 @@ public StaticObject doEspresso(StaticObject value,
@Specialization(guards = {
"!isStaticObject(value)",
"!interop.isNull(value)",
"isHostObject(getContext(), value)"
"interop.isHostObject(value)"
})
StaticObject doForeignConverter(Object value,
@Bind Node node,
Expand Down Expand Up @@ -1855,7 +1855,7 @@ public StaticObject doEspresso(StaticObject value,
@Specialization(guards = {
"!isStaticObject(value)",
"!interop.isNull(value)",
"isHostObject(getContext(), value)"
"interop.isHostObject(value)"
})
StaticObject doForeignInternalConverter(Object value,
@Bind Node node,
Expand Down Expand Up @@ -2799,8 +2799,4 @@ static boolean isEspressoException(Object obj) {
static boolean isTypeMappingEnabled(EspressoContext context) {
return context.getPolyglotTypeMappings().hasMappings();
}

static boolean isHostObject(EspressoContext context, Object value) {
return context.getEnv().isHostObject(value);
}
}
3 changes: 3 additions & 0 deletions sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ This changelog summarizes major changes between GraalVM SDK versions. The main f
* GR-65404 Remove `PolyglotLauncher` as it is no longer used.
* GR-68613: JavaScript polyglot isolate now includes support for the WebAssembly (Wasm) language.
* 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`.
* 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.
* GR-35913: `Value#asHostObject()` throws `UnsupportedOperationException` if object is allocated in a foreign heap.
* GR-71402: Added `Value#hasStaticScope` and `Value#getStaticScope` returning the static scope representing static or class-level members associated with the meta object.

## Version 25.0.0
* GR-60636 Truffle now stops compiling when the code cache fills up on HotSpot. A warning is printed when that happens.
Expand Down
2 changes: 2 additions & 0 deletions sdk/src/org.graalvm.polyglot/snapshot.sigtest
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,7 @@ meth public boolean hasIteratorNextElement()
meth public boolean hasMember(java.lang.String)
meth public boolean hasMembers()
meth public boolean hasMetaParents()
meth public boolean hasStaticScope()
meth public boolean isBoolean()
meth public boolean isBufferWritable()
meth public boolean isDate()
Expand Down Expand Up @@ -659,6 +660,7 @@ meth public org.graalvm.polyglot.Value getIteratorNextElement()
meth public org.graalvm.polyglot.Value getMember(java.lang.String)
meth public org.graalvm.polyglot.Value getMetaObject()
meth public org.graalvm.polyglot.Value getMetaParents()
meth public org.graalvm.polyglot.Value getStaticScope()
meth public short asShort()
meth public short readBufferShort(java.nio.ByteOrder,long)
meth public static org.graalvm.polyglot.Value asValue(java.lang.Object)
Expand Down
59 changes: 55 additions & 4 deletions sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Value.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -1008,6 +1008,55 @@ public boolean removeMember(String identifier) {
}
}

/**
* Returns {@code true} if this value is a {@linkplain #isMetaObject() meta object} that
* provides a {@linkplain #getStaticScope() static scope}. A static scope represents the static
* or class level members associated with the type described by this meta object, such as static
* fields or methods.
*
* @throws IllegalStateException if the context is already {@linkplain Context#close() closed}
* @throws PolyglotException if a guest language error occurs during execution
* @see #isMetaObject()
* @see #getStaticScope()
* @since 25.1
*/
public boolean hasStaticScope() {
return dispatch.hasStaticScope(this.context, receiver);
}

/**
* Returns the static scope associated with this value. This value must be a
* {@linkplain #isMetaObject() meta-object}. A static scope is an object that exposes static
* members, members whose values or behavior are independent of any particular instance.
* <p>
* The returned static scope can be used to access static members using
* {@link #getMember(String)}, {@link #getMemberKeys()}, or
* {@link #invokeMember(String, Object...)}.
* <p>
* The returned static scope is always expected to provide {@link #hasMembers() members},
* representing the static context.
* <p>
* <b>Examples:</b>
* </p>
* <ul>
* <li>In Java, the static scope exposes static fields and methods of a class.</li>
* <li>In Python, the static scope exposes class-level attributes and methods, effectively
* corresponding to the members provided by the Python metaobject.</li>
* </ul>
*
* @throws UnsupportedOperationException if and only if this value does not
* {@linkplain #hasStaticScope() have a static scope}
* @throws IllegalStateException if the context is already {@linkplain Context#close() closed}
* @throws PolyglotException if a guest language error occurs during execution
* @see #hasStaticScope()
* @see #isMetaObject()
* @see #hasMembers()
* @since 25.1
*/
public Value getStaticScope() {
return (Value) dispatch.getStaticScope(this.context, receiver);
}

// executable

/**
Expand Down Expand Up @@ -1554,7 +1603,7 @@ public boolean isNativePointer() {
/**
* Returns the value of the pointer as <code>long</code> value.
*
* @throws UnsupportedOperationException if the value is not a pointer.
* @throws ClassCastException if the value is not a pointer.
* @throws PolyglotException if a guest language error occurred during execution.
* @throws IllegalStateException if the underlying context was closed.
* @since 19.0
Expand Down Expand Up @@ -1586,7 +1635,9 @@ public boolean isHostObject() {
/**
* Returns the original Java host language object.
*
* @throws UnsupportedOperationException if {@link #isHostObject()} is <code>false</code>.
* @throws ClassCastException if {@link #isHostObject()} is <code>false</code>
* @throws UnsupportedOperationException if Java host language object is allocated in a foreign
* heap.
* @throws PolyglotException if a guest language error occurred during execution.
* @throws IllegalStateException if the underlying context was closed.
* @since 19.0
Expand Down Expand Up @@ -1620,7 +1671,7 @@ public boolean isProxyObject() {
* Returns the unboxed instance of the {@link Proxy}. Proxies are not automatically boxed to
* {@link #isHostObject() host objects} on host language call boundaries (Java methods).
*
* @throws UnsupportedOperationException if a value is not a proxy object.
* @throws ClassCastException if a value is not a proxy object.
* @throws PolyglotException if a guest language error occurred during execution.
* @throws IllegalStateException if the underlying context was closed.
* @since 19.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1034,32 +1034,16 @@ public abstract void initializeHostContext(Object internalContext, Object contex

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

public abstract boolean isHostValue(Object value);

public abstract Object unboxHostObject(Object hostValue);

public abstract Object unboxProxyObject(Object hostValue);

public abstract Throwable unboxHostException(Throwable hostValue);

public abstract Object toHostObject(Object context, Object value);

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

public abstract boolean isHostException(Object exception);

public abstract boolean isHostFunction(Object obj);

public abstract boolean isHostObject(Object obj);

public abstract boolean isHostSymbol(Object obj);

public abstract Object createHostAdapter(Object hostContextObject, Object[] types, Object classOverrides);

public abstract boolean isHostProxy(Object value);

public abstract Error toHostResourceError(Throwable hostException);

public abstract int findNextGuestToHostStackTraceElement(StackTraceElement firstElement, StackTraceElement[] hostStack, int nextElementIndex);

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

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

public boolean hasStaticScope(Object context, Object receiver) {
return false;
}

public abstract Object getStaticScope(Object context, Object receiver);

public boolean canExecute(Object context, Object receiver) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2024, Oracle and/or its affiliates.
* Copyright (c) 2018, 2025, Oracle and/or its affiliates.
*
* All rights reserved.
*
Expand Down Expand Up @@ -35,6 +35,7 @@
import java.math.BigInteger;
import java.util.HashMap;

import com.oracle.truffle.api.interop.InteropException;
import org.hamcrest.MatcherAssert;
import org.junit.Assert;
import org.junit.Assume;
Expand Down Expand Up @@ -161,13 +162,14 @@ public TestHostInteropNode() {
}

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

Object ret = testHostInterop.call();

Assert.assertTrue("isHostObject", runWithPolyglot.getTruffleTestEnv().isHostObject(ret));
Assert.assertSame("ret", BigInteger.class, runWithPolyglot.getTruffleTestEnv().asHostObject(ret));
InteropLibrary interop = InteropLibrary.getUncached(ret);
Assert.assertTrue("isHostObject", interop.isHostObject(ret));
Assert.assertSame("ret", BigInteger.class, interop.asHostObject(ret));
}

public static class TestEvalNoLang extends SulongTestNode {
Expand Down
4 changes: 4 additions & 0 deletions truffle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ This changelog summarizes major changes between Truffle versions relevant to lan
* GR-71088 Added `CompilerDirectives.EarlyEscapeAnalysis` annotation that runs partial escape analysis early before partial evaluation enabling partial-evaluation-constant scalar replacements.
* 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.
* GR-71887: Bytecode DSL: Added a `ClearLocal` operation for fast clearing of local values.
* GR-71088 Added `CompilerDirectives.EarlyEscapeAnalysis` annotation that runs partial escape analysis early before partial evaluation enabling partial-evaluation-constant scalar replacements.
* 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.
* GR-71402: Added `InteropLibrary#hasStaticScope` and `InteropLibrary#getStaticScope` returning the static scope representing static or class-level members associated with the given meta object.


## Version 25.0
* 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.
Expand Down
1 change: 1 addition & 0 deletions truffle/src/com.oracle.truffle.api.debug/snapshot.sigtest
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ meth public final boolean isNull()
meth public final com.oracle.truffle.api.debug.DebugValue asInLanguage(com.oracle.truffle.api.nodes.LanguageInfo)
meth public final com.oracle.truffle.api.debug.DebugValue getMetaObject()
meth public final com.oracle.truffle.api.debug.DebugValue getProperty(java.lang.String)
meth public final com.oracle.truffle.api.debug.DebugValue getStaticScope()
meth public final com.oracle.truffle.api.nodes.LanguageInfo getOriginalLanguage()
meth public final com.oracle.truffle.api.source.SourceSection getSourceLocation()
meth public final java.lang.String asString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,30 @@ public void accept(Breakpoint b) {
return breakpoints[0] != null ? breakpoints[0] : Collections.emptyList();
}

/**
* Returns a value that provides static members whose value is independent on a specific
* instance. Returns {@code null} when no static scope is available.
*
* @throws DebugException when guest language code throws an exception
* @since 25.1
*/
public final DebugValue getStaticScope() {
if (!isReadable()) {
return null;
}
Object view = getLanguageView();
try {
if (INTEROP.hasStaticScope(view)) {
return new HeapValue(getSession(), resolveLanguage(), null, INTEROP.getStaticScope(view));
}
} catch (ThreadDeath td) {
throw td;
} catch (Throwable ex) {
throw DebugException.create(getSession(), ex, resolveLanguage(), null, true, null);
}
return null;
}

/**
* Provides properties representing an internal structure of this value. The returned collection
* is not thread-safe. If the value is not {@link #isReadable() readable} then <code>null</code>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@
import java.util.ListIterator;
import java.util.function.Function;

import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractHostLanguageService;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleStackTrace;
import com.oracle.truffle.api.TruffleStackTraceElement;
Expand Down Expand Up @@ -183,10 +181,9 @@ public Object getExceptionStackTrace(Object receiver, Object polyglotContext) {

private static Object[] mergeHostGuestFrames(Throwable throwable, List<TruffleStackTraceElement> guestStack, boolean inHost, Object polyglotEngine) {
StackTraceElement[] hostStack = null;
AbstractHostLanguageService hostService = ACCESSOR.engineSupport().getHostService(polyglotEngine);
if (hostService.isHostException(throwable)) {
Throwable original = hostService.unboxHostException(throwable);
hostStack = original.getStackTrace();
Throwable originalHostException;
if (ACCESSOR.engineSupport().isHostException(throwable) && (originalHostException = ACCESSOR.engineSupport().asHostException(throwable)) != null) {
hostStack = originalHostException.getStackTrace();
} else if (throwable instanceof AbstractTruffleException) {
Throwable lazyStackTrace = ((AbstractTruffleException) throwable).getLazyStackTrace();
if (lazyStackTrace != null) {
Expand Down
Loading