Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 9cb647189ad2
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 87c106c267c1
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Aug 14, 2015

  1. Copy the full SHA
    4890b22 View commit details
  2. Copy the full SHA
    87c106c View commit details
Original file line number Diff line number Diff line change
@@ -10,26 +10,42 @@
package org.jruby.truffle.nodes.instrument;

import com.oracle.truffle.api.instrument.ASTProber;
import com.oracle.truffle.api.instrument.ProbeNode;
import com.oracle.truffle.api.instrument.StandardSyntaxTag;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeVisitor;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.runtime.RubySyntaxTag;

public class RubyDefaultASTProber implements NodeVisitor, ASTProber {

@Override
public boolean visit(Node node) {
if (node.isInstrumentable() && node instanceof RubyNode) {
if (node.isInstrumentable()) {
if (node instanceof RubyNode) {
final RubyNode rubyNode = (RubyNode) node;

final RubyNode rubyNode = (RubyNode) node;
if (rubyNode.isAtNewline()) {
// Identify statements using "newline" nodes created by the JRuby parser.
rubyNode.probe().tagAs(StandardSyntaxTag.STATEMENT, null);
rubyNode.probe().tagAs(RubySyntaxTag.LINE, null);
}

if (rubyNode.isAtNewline()) {
// Identify statements using "newline" nodes created by the JRuby parser.
rubyNode.probe().tagAs(StandardSyntaxTag.STATEMENT, null);
rubyNode.probe().tagAs(RubySyntaxTag.LINE, null);
if (rubyNode.getParent() instanceof RubyRootNode) {
rubyNode.probe().tagAs(RubySyntaxTag.CALL, null);
}

// A RubyRootNode can't have a probe because it doesn't have a parent. So, we do the next best thing and
// tag its immediate child. The trace instrument will know to look at the parent (RubyRootNode) based upon
// the context implied by the tag. We need to tag at the RubyRootNode because the semantics of set_trace_func
// are such that the receiver must be resolved, so we have to push as far into the callee as we can to have
// a properly constructed frame.
} else if (node.getParent() instanceof RubyRootNode) {
node.probe().tagAs(RubySyntaxTag.CALL, null);
}
}

return true;
}

Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.Ruby;
import org.jruby.truffle.nodes.core.ProcNodes;
import org.jruby.truffle.nodes.core.StringNodes;
import org.jruby.truffle.nodes.dispatch.RubyCallNode;
@@ -31,13 +32,16 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class TraceManager {

private final RubyContext context;

private Collection<Instrument> instruments;
private boolean isInTraceFunc = false;
private final Map<SyntaxTag, AdvancedInstrumentRootFactory> eventFactories = new HashMap<>();

public TraceManager(RubyContext context) {
this.context = context;
@@ -137,11 +141,85 @@ public String instrumentationInfo() {

};

final AdvancedInstrumentRootFactory callEventFactory = new AdvancedInstrumentRootFactory() {

@Override
public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) {
final RubyBasicObject event = StringNodes.createString(context.getCoreLibrary().getStringClass(), "call");

return new AdvancedInstrumentRoot() {

@Child private DirectCallNode callNode;

private final ConditionProfile inTraceFuncProfile = ConditionProfile.createBinaryProfile();

@Override
public Object executeRoot(Node node, VirtualFrame frame) {
if (!inTraceFuncProfile.profile(isInTraceFunc)) {
// set_trace_func reports the file and line of the call site.
final SourceSection sourceSection = Truffle.getRuntime().getCallerFrame().getCallNode().getEncapsulatingSourceSection();
final RubyBasicObject file = StringNodes.createString(context.getCoreLibrary().getStringClass(), sourceSection.getSource().getName());
final int line = sourceSection.getStartLine();

final Object self = RubyArguments.getSelf(frame.getArguments());
final Object classname = context.getCoreLibrary().getLogicalClass(self);
final Object id = context.getSymbol(RubyArguments.getMethod(frame.getArguments()).getName());

final RubyBinding binding = new RubyBinding(
context.getCoreLibrary().getBindingClass(),
self,
frame.materialize());

if (callNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();

callNode = insert(Truffle.getRuntime().createDirectCallNode(ProcNodes.getCallTargetForBlocks(traceFunc)));

if (callNode.isCallTargetCloningAllowed()) {
callNode.cloneCallTarget();
}

if (callNode.isInlinable()) {
callNode.forceInlining();
}
}

isInTraceFunc = true;

callNode.call(frame, RubyArguments.pack(
ProcNodes.getMethod(traceFunc),
ProcNodes.getDeclarationFrame(traceFunc),
ProcNodes.getSelfCapturedInScope(traceFunc),
ProcNodes.getBlockCapturedInScope(traceFunc),
new Object[]{event, file, line, id, binding, classname}));

isInTraceFunc = false;
}

return null;
}

@Override
public String instrumentationInfo() {
return "set_trace_func";
}

};
}

};

eventFactories.put(RubySyntaxTag.LINE, lineEventFactory);
eventFactories.put(RubySyntaxTag.CALL, callEventFactory);

instruments = new ArrayList<>();
for (Probe probe : Probe.findProbesTaggedAs(RubySyntaxTag.LINE)) {
final Instrument instrument = Instrument.create(listener, lineEventFactory, null, "set_trace_func");
instruments.add(instrument);
probe.attach(instrument);

for (Map.Entry<SyntaxTag, AdvancedInstrumentRootFactory> entry : eventFactories.entrySet()) {
for (Probe probe : Probe.findProbesTaggedAs(entry.getKey())) {
final Instrument instrument = Instrument.create(listener, entry.getValue(), null, "set_trace_func");
instruments.add(instrument);
probe.attach(instrument);
}
}

Probe.addProbeListener(new ProbeListener() {
@@ -155,8 +233,8 @@ public void newProbeInserted(Probe probe) {

@Override
public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) {
if (tag == StandardSyntaxTag.STATEMENT) {
final Instrument instrument = Instrument.create(listener, lineEventFactory, null, "set_trace_func");
if (eventFactories.containsKey(tag)) {
final Instrument instrument = Instrument.create(listener, eventFactories.get(tag), null, "set_trace_func");
instruments.add(instrument);
probe.attach(instrument);
}