package com.oracle.truffle.trufflenode.test;
import com.oracle.truffle.api.Option;
import com.oracle.truffle.api.TruffleContext;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.ContextsListener;
import com.oracle.truffle.api.instrumentation.ExecutionEventNode;
import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
import com.oracle.truffle.api.instrumentation.StandardTags;
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.nodes.LanguageInfo;
import com.oracle.truffle.js.nodes.instrumentation.JSTags;
import org.graalvm.options.OptionCategory;
import org.graalvm.options.OptionDescriptors;
import org.graalvm.options.OptionKey;
@Option.Group(ForeignCallTestingInstrument.ID)
@TruffleInstrument.Registration(id = ForeignCallTestingInstrument.ID, name = "Test Instrument", services = {ForeignCallTestingInstrument.class})
public class ForeignCallTestingInstrument extends TruffleInstrument implements ContextsListener {
static final String ID = "testing-agent";
private TruffleInstrument.Env env;
public ForeignCallTestingInstrument() {
super();
}
@Option(name = "", help = "Enable testing instrument.", category = OptionCategory.USER)
static final OptionKey<Boolean> ENABLED = new OptionKey<>(true);
@Override
protected OptionDescriptors getOptionDescriptors() {
return new ForeignCallTestingInstrumentOptionDescriptors();
}
@Override
protected void onCreate(final TruffleInstrument.Env environment) {
this.env = environment;
environment.getInstrumenter().attachContextsListener(this, false);
environment.registerService(this);
SourceSectionFilter sourceSectionFilter = SourceSectionFilter.newBuilder().tagIs(JSTags.ALL).build();
SourceSectionFilter inputGeneratingObjects = SourceSectionFilter.newBuilder().tagIs(
StandardTags.ExpressionTag.class,
StandardTags.StatementTag.class,
JSTags.InputNodeTag.class).build();
environment.getInstrumenter().attachExecutionEventFactory(sourceSectionFilter, inputGeneratingObjects, context -> new ExecutionEventNode() {
@Child private InteropLibrary dispatch = InteropLibrary.getFactory().createDispatched(5);
@Override
public void onEnter(VirtualFrame frame) {
try {
InteropLibrary interopLibrary = InteropLibrary.getFactory().getUncached();
if (interopLibrary.isMemberReadable(env.getPolyglotBindings(), "emptyFunction")) {
Object func = interopLibrary.readMember(env.getPolyglotBindings(), "emptyFunction");
dispatch.execute(func);
}
} catch (Exception e) {
throw new AssertionError(e);
}
}
});
}
@Override
public void onLanguageContextInitialized(TruffleContext context, LanguageInfo language) {
try {
InteropLibrary.getFactory().getUncached().writeMember(env.getPolyglotBindings(), "testingControlValue", 42);
} catch (UnsupportedMessageException | UnknownIdentifierException | UnsupportedTypeException e) {
throw new AssertionError(e);
}
}
@Override
protected void onDispose(final TruffleInstrument.Env environment) {
}
@Override
public void onContextCreated(TruffleContext context) {
}
@Override
public void onLanguageContextCreated(TruffleContext context, LanguageInfo language) {
}
@Override
public void onLanguageContextFinalized(TruffleContext context, LanguageInfo language) {
}
@Override
public void onLanguageContextDisposed(TruffleContext context, LanguageInfo language) {
}
@Override
public void onContextClosed(TruffleContext context) {
}
}