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: 9700ff3cfe33
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f193426a5416
Choose a head ref
  • 4 commits
  • 8 files changed
  • 1 contributor

Commits on Feb 28, 2015

  1. Copy the full SHA
    12c97bc View commit details
  2. Copy the full SHA
    865a93a View commit details
  3. Copy the full SHA
    8f8f0e0 View commit details
  4. Copy the full SHA
    f193426 View commit details
Original file line number Diff line number Diff line change
@@ -166,10 +166,7 @@ public Object execute(final TranslatorDriver.ParserContext parserContext, final
// Assume UTF-8 for the moment
source = Source.fromBytes(runtime.getInstanceConfig().inlineScript(), "-e", new BytesDecoder.UTF8BytesDecoder());
} else {
final byte[] bytes = FileUtils.readAllBytesInterruptedly(truffleContext, inputFile);

// Assume UTF-8 for the moment
source = Source.fromBytes(bytes, inputFile, new BytesDecoder.UTF8BytesDecoder());
source = truffleContext.getSourceManager().forFile(inputFile);
}

truffleContext.load(source, null, new NodeWrapper() {
Original file line number Diff line number Diff line change
@@ -515,4 +515,44 @@ public RubyNilClass coverageStart() {

}

@CoreMethod(names = "attach", onSingleton = true, required = 2, needsBlock = true)
public abstract static class AttachNode extends CoreMethodNode {

public AttachNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public AttachNode(AttachNode prev) {
super(prev);
}

@CompilerDirectives.TruffleBoundary
@Specialization
public RubyNilClass attach(RubyString file, int line, RubyProc block) {
getContext().getAttachmentsManager().attach(file.toString(), line, block);
return getContext().getCoreLibrary().getNilObject();
}

}

@CoreMethod(names = "detach", onSingleton = true, required = 2)
public abstract static class DetachNode extends CoreMethodNode {

public DetachNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public DetachNode(DetachNode prev) {
super(prev);
}

@CompilerDirectives.TruffleBoundary
@Specialization
public RubyNilClass detach(RubyString file, int line) {
getContext().getAttachmentsManager().detach(file.toString(), line);
return getContext().getCoreLibrary().getNilObject();
}

}

}
24 changes: 18 additions & 6 deletions truffle/src/main/java/org/jruby/truffle/runtime/RubyContext.java
Original file line number Diff line number Diff line change
@@ -71,6 +71,8 @@ public class RubyContext extends ExecutionContext {
private final RubiniusPrimitiveManager rubiniusPrimitiveManager;
private final CoverageTracker coverageTracker;
private final InstrumentationServerManager instrumentationServerManager;
private final AttachmentsManager attachmentsManager;
private final SourceManager sourceManager;

private final AtomicLong nextObjectID = new AtomicLong(ObjectIDOperations.FIRST_OBJECT_ID);

@@ -89,10 +91,12 @@ public RubyContext(Ruby runtime) {
compilerOptions.setOption("MinInliningMaxCallerSize", 5000);
}

// TODO CS 28-Feb-15 this is global
Probe.registerASTProber(new RubyDefaultASTProber());

// TODO(CS, 28-Jan-15) this is global
// TODO(CS, 28-Jan-15) maybe not do this for core?
if (Options.TRUFFLE_COVERAGE.load()) {
Probe.registerASTProber(new RubyDefaultASTProber());
coverageTracker = new CoverageTracker();
} else {
coverageTracker = null;
@@ -134,6 +138,10 @@ public RubyContext(Ruby runtime) {
}

runningOnWindows = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).indexOf("win") >= 0;

attachmentsManager = new AttachmentsManager(this);

sourceManager = new SourceManager(this);
}

public Shape getEmptyShape() {
@@ -175,11 +183,7 @@ public void loadFile(String fileName, Node currentNode) {
}

private void loadFileAbsolute(String fileName, Node currentNode) {
final byte[] bytes = FileUtils.readAllBytesInterruptedly(this, fileName);

// Assume UTF-8 for the moment
final Source source = Source.fromBytes(bytes, fileName, new BytesDecoder.UTF8BytesDecoder());

final Source source = sourceManager.forFile(fileName);
load(source, currentNode, NodeWrapper.IDENTITY);
}

@@ -467,4 +471,12 @@ public RubiniusPrimitiveManager getRubiniusPrimitiveManager() {
public CoverageTracker getCoverageTracker() {
return coverageTracker;
}

public AttachmentsManager getAttachmentsManager() {
return attachmentsManager;
}

public SourceManager getSourceManager() {
return sourceManager;
}
}
Original file line number Diff line number Diff line change
@@ -490,6 +490,7 @@ public void loadRubyCore(String fileName, String prefix) {
final Source source;

try {
// TODO CS 28-Feb-15 need to use SourceManager here so that the debugger knows about the core files
source = Source.fromReader(new InputStreamReader(getRubyCoreInputStream(fileName), StandardCharsets.UTF_8), prefix + fileName);
} catch (IOException e) {
throw new RuntimeException(e);
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/

package org.jruby.truffle.runtime.subsystems;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrument.Instrument;
import com.oracle.truffle.api.instrument.Probe;
import com.oracle.truffle.api.instrument.StandardSyntaxTag;
import com.oracle.truffle.api.instrument.impl.SimpleEventListener;
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.tools.LineToProbesMap;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyBinding;
import org.jruby.truffle.runtime.core.RubyProc;

import java.util.*;

public class AttachmentsManager {

private final RubyContext context;
private final LineToProbesMap lineToProbesMap;
private final Map<LineLocation, List<Instrument>> attachments = new HashMap<>();

public AttachmentsManager(RubyContext context) {
this.context = context;

// TODO CS 28-Feb-15 this is global isn't it?

lineToProbesMap = new LineToProbesMap();
lineToProbesMap.install();
}

public synchronized void attach(String file, int line, final RubyProc block) {
final Instrument instrument = Instrument.create(new SimpleEventListener() {

@Override
public void enter(Node node, VirtualFrame frame) {
final RubyBinding binding = new RubyBinding(context.getCoreLibrary().getBindingClass(), RubyArguments.getSelf(frame.getArguments()), frame.materialize());
block.rootCall(binding);
}

}, String.format("Truffle::Primitive.attach@%s:%d", file, line));

final Source source = context.getSourceManager().forFileBestFuzzily(file);

final LineLocation lineLocation = source.createLineLocation(line);

List<Instrument> instruments = attachments.get(lineLocation);

if (instruments == null) {
instruments = new ArrayList<>();
attachments.put(lineLocation, instruments);
}

instruments.add(instrument);

for (Probe probe : lineToProbesMap.findProbes(lineLocation)) {
if (probe.isTaggedAs(StandardSyntaxTag.STATEMENT)) {
probe.attach(instrument);
return;
}
}

throw new RuntimeException("couldn't find a statement!");
}

public synchronized void detach(String file, int line) {
final Source source = context.getSourceManager().forFileBestFuzzily(file);

final LineLocation lineLocation = source.createLineLocation(line);

final List<Instrument> instruments = attachments.remove(lineLocation);

if (instruments != null) {
for (Instrument instrument : instruments) {
instrument.dispose();
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/

package org.jruby.truffle.runtime.subsystems;

import com.oracle.truffle.api.source.BytesDecoder;
import com.oracle.truffle.api.source.Source;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.util.FileUtils;

import java.io.File;
import java.io.IOException;
import java.util.*;

public class SourceManager {

private final RubyContext context;

private final Map<String, Source> sources = new HashMap<>();

public SourceManager(RubyContext context) {
this.context = context;
}

// TODO CS 28-Feb-15 best not to synchronize so coarsely in the future - would like to load files concurrently
public synchronized Source forFile(String path) {
final String canonicalPath;

try {
canonicalPath = new File(path).getCanonicalPath();
} catch (IOException e) {
throw new RuntimeException(e);
}

Source source = sources.get(canonicalPath);

if (source == null) {
final byte[] bytes = FileUtils.readAllBytesInterruptedly(context, path);

// Assume UTF-8 for the moment
source = Source.fromBytes(bytes, path, new BytesDecoder.UTF8BytesDecoder());

sources.put(canonicalPath, source);
}

return source;
}

public synchronized Source forFileBestFuzzily(final String path) {
final List<Map.Entry<String, Source>> matches = new ArrayList<>(sources.entrySet());

// TODO CS 28-Feb-15 only need the max value - don't need a full sort, but no convenient API?

matches.sort(new Comparator<Map.Entry<String, Source>>() {

@Override
public int compare(Map.Entry<String, Source> a, Map.Entry<String, Source> b) {
return Integer.compare(common(path, b.getKey()), common(path, a.getKey()));
}

});

return matches.get(0).getValue();
}

public int common(String path, String existingPath) {
int n = 0;

while (n < path.length() && n < existingPath.length() && path.charAt(path.length() - n) == existingPath.charAt(existingPath.length() - n)) {
n++;
}

return n;
}

}
11 changes: 10 additions & 1 deletion truffle/src/main/ruby/core/shims.rb
Original file line number Diff line number Diff line change
@@ -223,4 +223,13 @@ def [](index)
@array[index]
end
end
end
end

class Binding

def eval(string)
Kernel.eval(string, self)
end

end

27 changes: 25 additions & 2 deletions truffle/src/main/ruby/core/truffle/debug.rb
Original file line number Diff line number Diff line change
@@ -10,8 +10,31 @@ module Truffle

module Debug

def self.break
Truffle::Primitive.simple_shell
def self.break(file = nil, line = nil, condition = nil)
if line.nil?
raise 'must specify both a file and a line, or neither' unless file.nil?
Truffle::Primitive.simple_shell
elsif not condition.nil?
Truffle::Primitive.attach file, line do |binding|
if binding.eval(condition)
Truffle::Primitive.simple_shell
end
end
elsif block_given?
Truffle::Primitive.attach file, line do |binding|
if yield binding
Truffle::Primitive.simple_shell
end
end
else
Truffle::Primitive.attach file, line do |binding|
Truffle::Primitive.simple_shell
end
end
end

def self.clear(file, line)
Truffle::Primitive.detach file, line
end

end