Skip to content

Commit

Permalink
Using annotations to provide meta information about Node classes. Add…
Browse files Browse the repository at this point in the history
…ing Node#isAnnotationPresent to allow 'dynamic', per node instance decisions whether an annotation should be present or not
  • Loading branch information
Jaroslav Tulach committed Mar 21, 2016
1 parent af947b8 commit 7b30201
Show file tree
Hide file tree
Showing 15 changed files with 152 additions and 150 deletions.
Expand Up @@ -153,7 +153,7 @@ void setActive(boolean breakpointsActive) {
Breakpoint create(int ignoreCount, LineLocation lineLocation, boolean oneShot) throws IOException {
BreakpointImpl breakpoint = breakpoints.get(lineLocation);
if (breakpoint == null) {
final SourceSectionFilter query = SourceSectionFilter.newBuilder().sourceIs(lineLocation.getSource()).lineIs(lineLocation.getLineNumber()).tagIs(Debugger.HALT_TAG).build();
final SourceSectionFilter query = SourceSectionFilter.newBuilder().sourceIs(lineLocation.getSource()).lineIs(lineLocation.getLineNumber()).annotatedBy(Debugger.HaltTag.class).build();
breakpoint = new BreakpointImpl(lineLocation, query, ignoreCount, oneShot);
if (TRACE) {
trace("NEW " + breakpoint.getShortDescription());
Expand Down Expand Up @@ -188,7 +188,7 @@ Breakpoint create(int ignoreCount, LineLocation lineLocation, boolean oneShot) t
Breakpoint create(int ignoreCount, String tag, boolean oneShot) throws IOException {
BreakpointImpl breakpoint = breakpoints.get(tag);
if (breakpoint == null) {
final SourceSectionFilter query = SourceSectionFilter.newBuilder().tagIs(tag).build();
final SourceSectionFilter query = SourceSectionFilter.newBuilder().annotatedBy(Debugger.HaltTag.class).build();
breakpoint = new BreakpointImpl(tag, query, ignoreCount, oneShot);
if (TRACE) {
trace("NEW " + breakpoint.getShortDescription());
Expand Down
Expand Up @@ -54,8 +54,12 @@
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.LineLocation;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.vm.PolyglotEngine;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.Callable;

/**
Expand All @@ -69,30 +73,36 @@
public final class Debugger {

/**
* A {@link SourceSection#withTags(java.lang.String...) tag} used to mark program locations
* where ordinary stepping should halt. The debugger will halt just <em>before</em> a code
* location is executed that is marked with this tag.
* An annotation to mark program locations where ordinary stepping should halt. The debugger
* will halt just <em>before</em> a code location is executed that is marked with this tag.
*
* @since 0.9
* @since 0.12
*/
public static final String HALT_TAG = "debug-HALT";
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface HaltTag {
}

/**
* A {@link SourceSection#withTags(java.lang.String...) tag} used to mark program locations
* where <em>returning</em> or <em>stepping out</em> from a method/procedure call should halt.
* The debugger will halt at the code location that has just executed the call that returned.
* An to mark program locations where <em>returning</em> or <em>stepping out</em> from a
* method/procedure call should halt. The debugger will halt at the code location that has just
* executed the call that returned.
*
* @see #HALT_TAG
* @since 0.9
* @since 0.12
*/
public static final String CALL_TAG = "debug-CALL";
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface CallTag {
}

private static final boolean TRACE = Boolean.getBoolean("truffle.debug.trace");
private static final String TRACE_PREFIX = "Debug: ";
private static final PrintStream OUT = System.out;

private static final SourceSectionFilter CALL_FILTER = SourceSectionFilter.newBuilder().tagIs(CALL_TAG).build();
private static final SourceSectionFilter HALT_FILTER = SourceSectionFilter.newBuilder().tagIs(HALT_TAG).build();
private static final SourceSectionFilter CALL_FILTER = SourceSectionFilter.newBuilder().annotatedBy(CallTag.class).build();
private static final SourceSectionFilter HALT_FILTER = SourceSectionFilter.newBuilder().annotatedBy(HaltTag.class).build();

/**
* Finds debugger associated with given engine. There is at most one debugger associated with
Expand Down
Expand Up @@ -26,14 +26,13 @@

import com.oracle.truffle.api.debug.Debugger;
import com.oracle.truffle.api.instrumentation.Instrumenter;
import com.oracle.truffle.api.instrumentation.RequiredTags;
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
import com.oracle.truffle.api.instrumentation.TruffleInstrument.Registration;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.vm.PolyglotEngine;

@Registration(id = DebuggerInstrument.ID)
@RequiredTags({Debugger.CALL_TAG, Debugger.HALT_TAG})
// @RequiredTags({Debugger.CALL_TAG, Debugger.HALT_TAG})
public final class DebuggerInstrument extends TruffleInstrument {
public static final String ID = "debugger";

Expand Down
Expand Up @@ -96,9 +96,9 @@
* At this time the debugger requries two tags for basic behavior; more tags may be required in the future
* as the debugger acquires more functionality.
* <ul>
* <li>{@link com.oracle.truffle.api.debug.Debugger#HALT_TAG}: must be applied to every Node where the debugger
* <li>{@link com.oracle.truffle.api.debug.Debugger.HaltTag}: must be applied to every Node where the debugger
* should halt during ordinary <em>stepping</em>. This typically corresponds to "statements" in each language.</li>
* <li>{@link com.oracle.truffle.api.debug.Debugger#CALL_TAG}: must be applied to every Node where the debugger
* <li>{@link com.oracle.truffle.api.debug.Debugger.CallTag}: must be applied to every Node where the debugger
* should halt when either <em>returning</em> or <em>stepping out</em> from a call. This typically corresponds
* to function/method calls in each language.</li>
* </ul>
Expand Down
Expand Up @@ -29,6 +29,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.lang.annotation.Annotation;

import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
Expand Down Expand Up @@ -303,7 +304,7 @@ private static final class ExpressionNode extends InstrumentedNode {
}

@Override
protected boolean isTaggedWith(String tag) {
protected boolean isAnnotationPresent(Class<? extends Annotation> tag) {
return tag.equals(EXPRESSION);
}
}
Expand Down Expand Up @@ -339,8 +340,8 @@ private static final class BlockNode extends InstrumentedNode {
}

@Override
protected boolean isTaggedWith(String tag) {
return tag == BLOCK;
protected boolean isAnnotationPresent(Class<? extends Annotation> tag) {
throw new IllegalStateException("return tag == BLOCK;");
}
}

Expand All @@ -351,8 +352,8 @@ private static final class InstrumentableRootNode extends InstrumentedNode {
}

@Override
protected boolean isTaggedWith(String tag) {
return tag == ROOT;
protected boolean isAnnotationPresent(Class<? extends Annotation> tag) {
throw new IllegalStateException("return tag == ROOT;");
}

}
Expand All @@ -365,8 +366,8 @@ private static final class StatementNode extends InstrumentedNode {

@Override
@SuppressFBWarnings("ES_COMPARING_STRINGS_WITH_EQ")
protected boolean isTaggedWith(String tag) {
return tag == STATEMENT;
protected boolean isAnnotationPresent(Class<? extends Annotation> tag) {
throw new IllegalStateException("return tag == STATEMENT;");
}

}
Expand Down Expand Up @@ -404,8 +405,8 @@ private void defineFunction() {

@SuppressFBWarnings("ES_COMPARING_STRINGS_WITH_EQ")
@Override
protected boolean isTaggedWith(String tag) {
return tag == DEFINE;
protected boolean isAnnotationPresent(Class<? extends Annotation> tag) {
throw new IllegalStateException("return tag == DEFINE;");
}

}
Expand Down Expand Up @@ -436,8 +437,8 @@ public Object execute(VirtualFrame frame) {

@SuppressFBWarnings("ES_COMPARING_STRINGS_WITH_EQ")
@Override
protected boolean isTaggedWith(String tag) {
return tag == CALL;
protected boolean isAnnotationPresent(Class<? extends Annotation> tag) {
throw new IllegalStateException("return tag == CALL;");
}

}
Expand All @@ -462,8 +463,8 @@ public Object execute(VirtualFrame frame) {

@SuppressFBWarnings("ES_COMPARING_STRINGS_WITH_EQ")
@Override
protected boolean isTaggedWith(String tag) {
return tag == LOOP;
protected boolean isAnnotationPresent(Class<? extends Annotation> tag) {
throw new IllegalStateException("return tag == LOOP;");
}

}
Expand Down
Expand Up @@ -33,6 +33,7 @@
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import java.lang.annotation.Annotation;

public class SourceSectionFilterTest {

Expand Down Expand Up @@ -71,13 +72,13 @@ public SourceSection getSourceSection() {
}

@Override
protected boolean isTaggedWith(String tag) {
protected boolean isAnnotationPresent(Class<? extends Annotation> tag) {
for (int i = 0; i < tags.length; i++) {
if (tags[i] == tag) {
if (tags[i] == (Object) tag) {
return true;
}
}
return super.isTaggedWith(tag);
return super.isAnnotationPresent(tag);
}

};
Expand Down
Expand Up @@ -52,6 +52,7 @@
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import java.lang.annotation.Annotation;

/**
* Central coordinator class for the Truffle instrumentation framework. Allocated once per
Expand Down Expand Up @@ -427,16 +428,8 @@ private static void invalidateWrapperImpl(WrapperNode parent, Node node) {
}
}

static boolean hasTagImpl(Node node, SourceSection sourceSection, String tag) {
if (sourceSection != null) {
// compatibility
@SuppressWarnings("deprecation")
boolean hasTag = sourceSection.hasTag(tag);
if (hasTag) {
return true;
}
}
return ACCESSOR.hasInstrumentationTag(node, tag);
static boolean isAnnotationPresent(Node node, SourceSection sourceSection, Class<? extends Annotation> tag) {
return ACCESSOR.isAnnotationPresent(node, tag);
}

static Instrumentable getInstrumentable(Node node) {
Expand Down Expand Up @@ -494,11 +487,10 @@ public final boolean visit(Node node) {
}

private static void traceFilterCheck(String result, EventBinding<?> binding, Node node, SourceSection sourceSection) {
Set<String> tags = binding.getFilter().getReferencedTags();
Set<String> containedTags = new HashSet<>();
for (String tag : tags) {
if (hasTagImpl(node, sourceSection, tag)) {
containedTags.add(tag);
for (Annotation tag : node.getClass().getAnnotations()) {
if (isAnnotationPresent(node, sourceSection, tag.getClass())) {
containedTags.add(tag.getClass().getName());
}
}
trace(" Filter %4s %s section:%s tags:%s%n", result, binding.getFilter(), sourceSection, containedTags);
Expand Down Expand Up @@ -837,7 +829,7 @@ final boolean isNodeTaggedWithHelper(Node node, String tag, Class<?> onlyLanguag
return false;
}

return hasTagImpl(node, sourceSection, tag);
return isAnnotationPresent(node, sourceSection, null);
}

@Override
Expand Down Expand Up @@ -912,8 +904,8 @@ protected void detachLanguageFromInstrumentation(Object vm, com.oracle.truffle.a
}

@Override
public boolean hasInstrumentationTag(Node node, String tag) {
return super.hasInstrumentationTag(node, tag);
protected boolean isAnnotationPresent(Node node, Class<? extends Annotation> tag) {
return super.isAnnotationPresent(node, tag);
}

@Override
Expand Down
Expand Up @@ -34,6 +34,7 @@
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import java.lang.annotation.Annotation;

/**
* A source section filter represents an expression for a subset of tagged source sections that are
Expand Down Expand Up @@ -164,18 +165,25 @@ public Builder mimeTypeIs(String... mimeTypes) {
}

/**
* Add a filter for all source sections that are tagged with one of the given String tags.
* Add a filter for all {@link Node} that are tagged with one of the given annotation tags.
*
* @param tags matches one of the given tags
* @param tag the annotation to work with
* @return the builder to chain calls
* @see Node#isAnnotationPresent(java.lang.Class)
* @since 0.12
*/
public Builder tagIs(String... tags) {
verifyNotNull(tags);
expressions.add(new EventFilterExpression.TagIs(tags));
public Builder annotatedBy(Class<? extends Annotation> tag) {
expressions.add(new EventFilterExpression.AnnotatedBy<>(tag));
return this;
}

/**
* @since 0.12
*/
public Builder tagIs(String... tags) {
throw new UnsupportedOperationException();
}

/**
* Add a filter for all sources sections that declare not one of the given String tags.
*
Expand All @@ -184,9 +192,7 @@ public Builder tagIs(String... tags) {
* @since 0.12
*/
public Builder tagIsNot(String... tags) {
verifyNotNull(tags);
expressions.add(new Not(new EventFilterExpression.TagIs(tags)));
return this;
throw new UnsupportedOperationException();
}

/**
Expand Down Expand Up @@ -534,28 +540,25 @@ private static String[] checkAndInternTags(String[] tags) {
return tags;
}

private static final class TagIs extends EventFilterExpression {
private static final class AnnotatedBy<T extends Annotation> extends EventFilterExpression {
private final Class<T> annotation;

private final String[] tags;

TagIs(String... tags) {
this.tags = checkAndInternTags(tags);
AnnotatedBy(Class<T> annotation) {
this.annotation = annotation;
}

@Override
void collectReferencedTags(Set<String> collectTags) {
for (String tag : tags) {
collectTags.add(tag);
}
// for (String tag : tags) {
// collectTags.add(tag);
// }
}

@Override
@SuppressFBWarnings("ES_COMPARING_STRINGS_WITH_EQ")
boolean isIncluded(Node instrumentedNode, SourceSection sourceSection) {
String[] filterTags = this.tags;
for (int i = 0; i < filterTags.length; i++) {
String tag = filterTags[i];
if (InstrumentationHandler.hasTagImpl(instrumentedNode, sourceSection, tag)) {
if (instrumentedNode.getClass().isAnnotationPresent(annotation)) {
if (InstrumentationHandler.isAnnotationPresent(instrumentedNode, sourceSection, annotation)) {
return true;
}
}
Expand All @@ -574,7 +577,7 @@ protected int getOrder() {

@Override
public String toString() {
return String.format("tag is one of %s", Arrays.toString(tags));
return String.format("annotation is %s", annotation);
}
}

Expand Down
Expand Up @@ -49,6 +49,7 @@
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.Source;
import java.lang.annotation.Annotation;

/**
* Communication between PolyglotEngine, TruffleLanguage API/SPI, and other services.
Expand Down Expand Up @@ -311,8 +312,8 @@ protected Object createInstrumentationHandler(Object vm, OutputStream out, Outpu
return INSTRUMENTHANDLER.createInstrumentationHandler(vm, out, err, in);
}

protected boolean hasInstrumentationTag(Node node, String tag) {
return NODES.hasInstrumentationTag(node, tag);
protected boolean isAnnotationPresent(Node node, Class<? extends Annotation> tag) {
return NODES.isAnnotationPresent(node, tag);
}

private static Reference<Object> previousVM = new WeakReference<>(null);
Expand Down

0 comments on commit 7b30201

Please sign in to comment.