Skip to content

Commit

Permalink
Showing 4 changed files with 73 additions and 9 deletions.
20 changes: 19 additions & 1 deletion tool/truffle/callgraph2html.rb
Original file line number Diff line number Diff line change
@@ -68,13 +68,14 @@ def reachable
end

class MethodVersion
attr_reader :id, :method, :callsite_versions, :called_from, :eval_code
attr_reader :id, :method, :callsite_versions, :called_from, :locals, :eval_code

def initialize(id, method)
@id = Integer(id)
@method = method
@callsite_versions = []
@called_from = []
@locals = {}
@eval_code = []
end

@@ -127,6 +128,10 @@ def reachable
method_version = CG::MethodVersion.new(line[2], method)
objects[method_version.id] = method_version
method.versions.push method_version
when 'local'
method_version = objects[Integer(line[1])]
method_version.locals[line[2]] ||= []
method_version.locals[line[2]].push line[3]
when 'eval'
method_version = objects[Integer(line[1])]
eval_code = line.drop(2).join(' ')
@@ -247,6 +252,19 @@ def annotate(method_version, offset)
<% end %>
</ul>
<% end %>
<% unless method_version.locals.empty? %>
<p>Locals:</p>
<ul>
<% method_version.locals.each do |name, types| %>
<li><code><%= h(name) %></li>
<ul>
<% types.each do |type| %>
<li><code><%= h(type) %></li>
<% end %>
</ul>
<% end %>
</ul>
<% end %>
<% unless method_version.eval_code.empty? %>
<p>Evals:</p>
<ul>
Original file line number Diff line number Diff line change
@@ -10,11 +10,14 @@
package org.jruby.truffle.language.locals;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.RubyRootNode;

public class WriteLocalVariableNode extends RubyNode {

@@ -39,9 +42,21 @@ public Object execute(VirtualFrame frame) {
}

final Object value = valueNode.execute(frame);
recordWrite(value);
return writeFrameSlotNode.executeWrite(frame, value);
}

@TruffleBoundary
private void recordWrite(Object value) {
final RubyContext context = getContext();

if (context.getCallGraph() != null) {
final String name = frameSlot.getIdentifier().toString();
final String type = Layouts.CLASS.getFields(context.getCoreLibrary().getLogicalClass(value)).getName();
context.getCallGraph().recordLocalWrite((RubyRootNode) getRootNode(), name, type);
}
}

@Override
public Object isDefined(VirtualFrame frame) {
return coreStrings().ASSIGNMENT.createInstance();
Original file line number Diff line number Diff line change
@@ -9,23 +9,41 @@
*/
package org.jruby.truffle.tools.callgraph;

import com.oracle.truffle.api.nodes.RootNode;
import org.jruby.truffle.language.RubyRootNode;
import org.jruby.truffle.language.methods.SharedMethodInfo;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class CallGraph {

private final Map<SharedMethodInfo, Method> sharedMethodInfoToMethod = new HashMap<>();
private final Map<RubyRootNode, MethodVersion> rootNodeToMethodVersion = new HashMap<>();
private final Map<RubyRootNode, Map<String, Set<String>>> localTypes = new HashMap<>();

public synchronized void registerRootNode(RubyRootNode rootNode) {
rootNodeToMethodVersion(rootNode);
}

public synchronized void recordLocalWrite(RubyRootNode rootNode, String name, String type) {
if (name.equals("foo_a") && type.equals("Object")) {
throw new UnsupportedOperationException();
}

final Map<String, Set<String>> rootNodeLocalTypes = localTypes.computeIfAbsent(rootNode,
(k) -> new HashMap<>());

final Set<String> rootNodeLocalTypeSet = rootNodeLocalTypes.computeIfAbsent(name,
(k) -> new HashSet<>());

rootNodeLocalTypeSet.add(type);
}

public Method sharedMethodInfoToMethod(SharedMethodInfo sharedMethodInfo) {
Method method = sharedMethodInfoToMethod.get(sharedMethodInfo);

@@ -52,10 +70,17 @@ public Collection<Method> getMethods() {
return Collections.unmodifiableCollection(sharedMethodInfoToMethod.values());
}

public void resolve() {
for (MethodVersion methodVersion : rootNodeToMethodVersion.values()) {
methodVersion.resolve();
public Map<String, Set<String>> getLocalTypes(RubyRootNode rootNode) {
final Map<String, Set<String>> rootNodeLocalTypes = localTypes.get(rootNode);

if (rootNodeLocalTypes == null) {
return Collections.EMPTY_MAP;
} else {
return rootNodeLocalTypes;
}
}

public void resolve() {
rootNodeToMethodVersion.values().forEach(MethodVersion::resolve);
}
}
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@
import org.jruby.truffle.language.methods.SharedMethodInfo;

import java.io.PrintStream;
import java.util.Map;
import java.util.Set;

public class SimpleWriter {

@@ -96,11 +98,15 @@ private void write(MethodVersion version) {
write(callSiteVersion);
}

for (FrameSlot slot : version.getRootNode().getFrameDescriptor().getSlots()) {
stream.printf("local %d %s %s%n",
ids.getId(version),
slot.getIdentifier(),
slot.getKind());
for (Map.Entry<String, Set<String>> x : callGraph.getLocalTypes(version.getRootNode()).entrySet()) {
final String name = x.getKey();

for (String type : x.getValue()) {
stream.printf("local %d %s %s%n",
ids.getId(version),
name,
type);
}
}
}

0 comments on commit 3d9a318

Please sign in to comment.