Skip to content

Commit

Permalink
Refactor polyglot engine exception handling. Catch exceptions only at…
Browse files Browse the repository at this point in the history
… API boundaries, use unified wrapper for fixed internal error propagation.
  • Loading branch information
chumer committed Apr 3, 2020
1 parent 4b24462 commit 29406cd
Show file tree
Hide file tree
Showing 44 changed files with 1,820 additions and 1,269 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -679,8 +679,8 @@ public UnmodifiableEconomicSet<String> getBindingsAccess(PolyglotAccess access)
}

@Override
public void validatePolyglotAccess(PolyglotAccess access, UnmodifiableEconomicSet<String> languages) {
access.validate(languages);
public String validatePolyglotAccess(PolyglotAccess access, UnmodifiableEconomicSet<String> languages) {
return access.validate(languages);
}

}
Expand Down Expand Up @@ -767,6 +767,11 @@ public Boolean run() {
PolyglotInvalid.AOT = aot.booleanValue();
}

@Override
public Context getCurrentContext() {
throw noPolyglotImplementationFound();
}

@Override
public Engine buildEngine(OutputStream out, OutputStream err, InputStream in, Map<String, String> arguments, long timeout, TimeUnit timeoutUnit, boolean sandbox,
long maximumAllowedAllocationBytes, boolean useSystemProperties, boolean allowExperimentalOptions, boolean boundEngine, MessageTransport messageInterceptor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ private static EconomicMap<String, EconomicSet<String>> copyMap(EconomicMap<Stri
return newMap;
}

void validate(UnmodifiableEconomicSet<String> availableLanguages) {
String validate(UnmodifiableEconomicSet<String> availableLanguages) {
if (evalAccess != null) {
MapCursor<String, EconomicSet<String>> entries = evalAccess.getEntries();
while (entries.advance()) {
Expand All @@ -117,20 +117,21 @@ void validate(UnmodifiableEconomicSet<String> availableLanguages) {
}
}
if (invalidKey != null) {
throw new IllegalArgumentException(String.format("Language '%s' configured in polyglot evaluation rule %s -> %s is not installed or available.",
invalidKey, entries.getKey(), toStringSet(entries.getValue())));
return String.format("Language '%s' configured in polyglot evaluation rule %s -> %s is not installed or available.",
invalidKey, entries.getKey(), toStringSet(entries.getValue()));
}
}
}

if (bindingsAccess != null) {
for (String language : bindingsAccess) {
if (!availableLanguages.contains(language)) {
throw new IllegalArgumentException(String.format("Language '%s' configured in polyglot bindings access rule is not installed or available.",
language));
return String.format("Language '%s' configured in polyglot bindings access rule is not installed or available.",
language);
}
}
}
return null;

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ protected APIAccess() {

public abstract UnmodifiableEconomicSet<String> getBindingsAccess(PolyglotAccess access);

public abstract void validatePolyglotAccess(PolyglotAccess access, UnmodifiableEconomicSet<String> language);
public abstract String validatePolyglotAccess(PolyglotAccess access, UnmodifiableEconomicSet<String> language);

public abstract Object getImpl(ResourceLimits value);

Expand Down Expand Up @@ -752,9 +752,7 @@ public boolean isMetaObject(Object receiver) {

public abstract Class<?> loadLanguageClass(String className);

public Context getCurrentContext() {
throw new IllegalStateException("No current context is available. Make sure the Java method is invoked by a Graal guest language or a context is entered using Context.enter().");
}
public abstract Context getCurrentContext();

public abstract Collection<Engine> findActiveEngines();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,29 @@
*/
package com.oracle.truffle.api.instrumentation.test;

import com.oracle.truffle.api.TruffleContext;
import com.oracle.truffle.api.instrumentation.ContextsListener;
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
import com.oracle.truffle.api.instrumentation.TruffleInstrument.Registration;
import com.oracle.truffle.api.nodes.LanguageInfo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.Test;

import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.Instrument;
import org.graalvm.polyglot.Source;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Test;

import com.oracle.truffle.api.TruffleContext;
import com.oracle.truffle.api.instrumentation.ContextsListener;
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
import com.oracle.truffle.api.instrumentation.TruffleInstrument.Registration;
import com.oracle.truffle.api.nodes.LanguageInfo;

public class ContextsEventsTest {

Expand Down Expand Up @@ -340,4 +342,5 @@ private static class ContextEvent {
this.languageFinalized = languageFinalized;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package com.oracle.truffle.api.instrumentation.test;

import java.util.function.Consumer;

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

import com.oracle.truffle.api.TruffleContext;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.TruffleLanguage.Env;
import com.oracle.truffle.api.TruffleLanguage.Registration;
import com.oracle.truffle.api.instrumentation.ContextsListener;
import com.oracle.truffle.api.nodes.LanguageInfo;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.test.polyglot.AbstractPolyglotTest;
import com.oracle.truffle.api.test.polyglot.ProxyInstrument;
import com.oracle.truffle.api.test.polyglot.ProxyLanguage;

public class InternalErrorPropagationTest extends AbstractPolyglotTest {

static final String OTHER_LANGUAGE = "InstrumentationExceptionTest_OtherLanguage";

@Test
public void testInstrumentCreateException() {
TestListener listener = new TestListener();
ProxyInstrument instrument = new ProxyInstrument() {
@Override
protected void onCreate(Env env) {
super.onCreate(env);
env.getInstrumenter().attachContextsListener(listener, true);
}
};

setupEnv(Context.create(ProxyLanguage.ID), instrument);

try {
listener.onContextCreated = (c) -> triggerParseFailure(languageEnv, c);
setupEnv(Context.create(ProxyLanguage.ID), instrument);
Assert.fail();
} catch (PolyglotException e) {
Assert.assertTrue(e.isInternalError());
}

try {
listener.onContextCreated = null;
listener.onLanguageContextCreated = (c) -> triggerParseFailure(languageEnv, c);
setupEnv(Context.create(ProxyLanguage.ID), instrument);
Assert.fail();
} catch (PolyglotException e) {
Assert.assertTrue(e.isInternalError());
}

try {
listener.onLanguageContextCreated = null;
listener.onLanguageContextInitialized = (c) -> triggerParseFailure(languageEnv, c);
setupEnv(Context.create(ProxyLanguage.ID), instrument);
Assert.fail();
} catch (PolyglotException e) {
Assert.assertTrue(e.isInternalError());
}

listener.onLanguageContextInitialized = null;
setupEnv(Context.create(ProxyLanguage.ID), instrument);
try {
listener.onLanguageContextFinalized = (c) -> triggerParseFailure(languageEnv, c);
context.close();
Assert.fail();
} catch (PolyglotException e) {
Assert.assertTrue(e.isInternalError());
listener.onLanguageContextFinalized = null;
context.close();
}

listener.onLanguageContextFinalized = null;
setupEnv(Context.create(ProxyLanguage.ID), instrument);
try {
listener.onLanguageContextDisposed = (c) -> triggerParseFailure(languageEnv, c);
context.close();
Assert.fail();
} catch (PolyglotException e) {
Assert.assertTrue(e.isInternalError());
listener.onLanguageContextDisposed = null;
context.close();
}

listener.onLanguageContextDisposed = null;
setupEnv(Context.create(ProxyLanguage.ID), instrument);
try {
listener.onContextClosed = (c) -> triggerParseFailure(languageEnv, c);
context.close();
Assert.fail();
} catch (PolyglotException e) {
Assert.assertTrue(e.isInternalError());
listener.onContextClosed = null;
context.close();
}

}

private static void triggerParseFailure(TruffleLanguage.Env env, TruffleContext c) {
Object prev = c.enter();
try {
env.parsePublic(Source.newBuilder(OTHER_LANGUAGE, "", "").build());
} finally {
c.leave(prev);
}
}

@Registration(id = OTHER_LANGUAGE, name = OTHER_LANGUAGE)
public static class OtherLanguage extends TruffleLanguage<Env> {

@Override
protected Env createContext(Env env) {
return env;
}
}

static class TestListener implements ContextsListener {

Consumer<TruffleContext> onLanguageContextInitialized;
Consumer<TruffleContext> onLanguageContextFinalized;
Consumer<TruffleContext> onLanguageContextDisposed;
Consumer<TruffleContext> onLanguageContextCreated;
Consumer<TruffleContext> onContextCreated;
Consumer<TruffleContext> onContextClosed;

public void onLanguageContextInitialized(TruffleContext c, LanguageInfo l) {
if (onLanguageContextInitialized != null) {
onLanguageContextInitialized.accept(c);
}
}

public void onLanguageContextFinalized(TruffleContext c, LanguageInfo l) {
if (onLanguageContextFinalized != null) {
onLanguageContextFinalized.accept(c);
}
}

public void onLanguageContextDisposed(TruffleContext c, LanguageInfo l) {
if (onLanguageContextDisposed != null) {
onLanguageContextDisposed.accept(c);
}
}

public void onLanguageContextCreated(TruffleContext c, LanguageInfo l) {
if (onLanguageContextCreated != null) {
onLanguageContextCreated.accept(c);
}
}

public void onContextCreated(TruffleContext c) {
if (onContextCreated != null) {
onContextCreated.accept(c);
}
}

public void onContextClosed(TruffleContext c) {
if (onContextClosed != null) {
onContextClosed.accept(c);
}
}

}

}
Loading

0 comments on commit 29406cd

Please sign in to comment.