Skip to content

Commit

Permalink
[GR-39551] Use an uncached library to verify parent members.
Browse files Browse the repository at this point in the history
PullRequest: graal/12120
  • Loading branch information
entlicher committed Jun 30, 2022
2 parents 6e28218 + c9c2c1a commit 4219b35
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3477,7 +3477,7 @@ public Object getMembers(Object receiver, boolean internal) throws UnsupportedMe
assert validInteropReturn(receiver, result);
assert validProtocolArgument(receiver, internal);
assert isMultiThreaded(receiver) || assertMemberKeys(receiver, result, internal);
assert !delegate.hasScopeParent(receiver) || assertScopeMembers(receiver, result, delegate.getMembers(delegate.getScopeParent(receiver), internal));
assert !delegate.hasScopeParent(receiver) || assertScopeMembers(receiver, result, getUncached().getMembers(delegate.getScopeParent(receiver), internal));
assert validInteropReturn(receiver, result);
return result;
} catch (InteropException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,17 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

import org.graalvm.polyglot.Context;
import org.junit.Test;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.exception.AbstractTruffleException;
import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.ExceptionType;
Expand Down Expand Up @@ -589,6 +592,134 @@ public void testIsSame() {
assertTrue(l0.isIdentical(v0, v1, l1));
}

@Test
public void testValidScopeUsage() throws Exception {
ScopeCached sc = new ScopeCached(5);
InteropLibrary iop = createLibrary(InteropLibrary.class, sc);
assertTrue(iop.hasMembers(sc));
Object members = iop.getMembers(sc);
assertNotNull(members);
assertTrue(iop.hasScopeParent(sc));
Object scParent = iop.getScopeParent(sc);
assertNotNull(scParent);
if (run == TestRun.CACHED) {
checkInvalidUsage(() -> iop.hasMembers(scParent));
checkInvalidUsage(() -> iop.getMembers(scParent));
checkInvalidUsage(() -> iop.hasScopeParent(scParent));
checkInvalidUsage(() -> iop.getScopeParent(scParent));
}
}

private static void checkInvalidUsage(Callable<Object> call) throws Exception {
boolean invalidUsage = false;
try {
call.call();
} catch (AssertionError err) {
assertTrue(err.getMessage(), err.getMessage().startsWith("Invalid library usage"));
invalidUsage = true;
}
assertTrue(invalidUsage);
}

@ExportLibrary(InteropLibrary.class)
static class ScopeCached implements TruffleObject {

final long id;

ScopeCached(long id) {
this.id = id;
}

@ExportMessage
boolean accepts(@Cached(value = "this.id") long cachedId) {
return this.id == cachedId;
}

@ExportMessage
@SuppressWarnings("static-method")
boolean isScope() {
return true;
}

@ExportMessage
boolean hasScopeParent() {
return this.id > 0;
}

@ExportMessage
@TruffleBoundary
Object getScopeParent() throws UnsupportedMessageException {
if (this.id > 0) {
return new ScopeCached(id - 1);
} else {
throw UnsupportedMessageException.create();
}
}

@ExportMessage
@SuppressWarnings("static-method")
boolean hasMembers() {
return true;
}

@ExportMessage
Object getMembers(@SuppressWarnings("unused") boolean includeInternal) {
return new ScopeMembers(id);
}

@ExportMessage
@SuppressWarnings("static-method")
boolean hasLanguage() {
return true;
}

@ExportMessage
@SuppressWarnings("static-method")
Class<? extends TruffleLanguage<?>> getLanguage() {
return ProxyLanguage.class;
}

@ExportMessage
Object toDisplayString(@SuppressWarnings("unused") boolean allowSideEffects) {
return "ScopeCached[" + id + "]";
}

@ExportLibrary(InteropLibrary.class)
static final class ScopeMembers implements TruffleObject {

private final long len;

private ScopeMembers(long len) {
this.len = len;
}

@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
long getArraySize() {
return len;
}

@ExportMessage
boolean isArrayElementReadable(long index) {
return 0 <= index && index < len;
}
}
}

static class Members implements TruffleObject {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -1892,7 +1893,7 @@ Object readArrayElement(long index) throws InvalidArrayIndexException {
@ExportLibrary(InteropLibrary.class)
static final class TestScope implements TruffleObject {

final Map<String, Object> values = new HashMap<>();
final Map<String, Object> values = new LinkedHashMap<>();
TestScope parentScope;
boolean modifiable;
boolean insertable;
Expand Down Expand Up @@ -2160,9 +2161,9 @@ private void testBindingsWithMultipleScopes(TestScope[] scopes) {
// Expected as the merged scope does not contain parent scopes.
}
// Correct the scope hierarchy:
scopes[0].values.put("foo", "val");
scopes[0].values.put("bar", "val");
scopes[1].values.put("bar", "val");
scopes[0].values.put("foo", "val");
scopes[3].values.clear();
assertValue(bindings, ValueAssert.Trait.MEMBERS);

c.close();
Expand Down

0 comments on commit 4219b35

Please sign in to comment.