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

Commits on Dec 21, 2015

  1. Copy the full SHA
    24aeb46 View commit details
  2. Copy the full SHA
    0f73d2b View commit details
  3. Copy the full SHA
    80522a0 View commit details
  4. Copy the full SHA
    94b6f51 View commit details
  5. Copy the full SHA
    2956597 View commit details
  6. Copy the full SHA
    5851935 View commit details
  7. Copy the full SHA
    476cc0e View commit details
16 changes: 11 additions & 5 deletions tool/jt.rb
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@

JDEBUG_PORT = 51819
JDEBUG = "-J-agentlib:jdwp=transport=dt_socket,server=y,address=#{JDEBUG_PORT},suspend=y"
JDEBUG_TEST = "-Dmaven.surefire.debug=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=#{JDEBUG_PORT} -Xnoagent -Djava.compiler=NONE"
JEXCEPTION = "-Xtruffle.exceptions.print_java=true"

# wait for sub-processes to handle the interrupt
@@ -195,12 +196,12 @@ def help
puts ' --server run an instrumentation server on port 8080'
puts ' --igv make sure IGV is running and dump Graal graphs after partial escape (implies --graal)'
puts ' --full show all phases, not just up to the Truffle partial escape'
puts ' --jdebug run a JDWP debug server on 8000'
puts ' --jdebug run a JDWP debug server on #{JDEBUG_PORT}'
puts ' --jexception[s] print java exceptions'
puts 'jt e 14 + 2 evaluate an expression'
puts 'jt puts 14 + 2 evaluate and print an expression'
puts 'jt test run all mri tests and specs'
puts 'jt test tck run the Truffle Compatibility Kit tests'
puts 'jt test tck [--jdebug] run the Truffle Compatibility Kit tests'
puts 'jt test mri run mri tests'
puts 'jt test specs run all specs'
puts 'jt test specs fast run all specs except sub-processes, GC, sleep, ...'
@@ -346,7 +347,12 @@ def test(*args)
test_mri
when 'pe' then test_pe(*rest)
when 'specs' then test_specs('run', *rest)
when 'tck' then test_tck
when 'tck' then
args = []
if rest.include? '--jdebug'
args << JDEBUG_TEST
end
test_tck *args
when 'mri' then test_mri(*rest)
else
if File.expand_path(path).start_with?("#{JRUBY_DIR}/test")
@@ -406,8 +412,8 @@ def test_specs(command, *args)
end
private :test_specs

def test_tck
mvn 'test'
def test_tck(*args)
mvn *args + ['test']
end
private :test_tck

Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@ public Object execute(VirtualFrame frame) {
callNode.forceInlining();
} else {
final TranslatorDriver translator = new TranslatorDriver(context);
final RubyRootNode rootNode = translator.parse(context, source, UTF8Encoding.INSTANCE, ParserContext.TOP_LEVEL, null, true, null);
final RubyRootNode rootNode = translator.parse(context, source, UTF8Encoding.INSTANCE, ParserContext.TOP_LEVEL, argumentNames, null, true, null);
final CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);

callNode = insert(Truffle.getRuntime().createDirectCallNode(callTarget));
Original file line number Diff line number Diff line change
@@ -650,7 +650,7 @@ protected RootNodeWrapper compileSource(VirtualFrame frame, DynamicObject source

final TranslatorDriver translator = new TranslatorDriver(getContext());

return new RootNodeWrapper(translator.parse(getContext(), source, UTF8Encoding.INSTANCE, ParserContext.EVAL, parentFrame, true, this));
return new RootNodeWrapper(translator.parse(getContext(), source, UTF8Encoding.INSTANCE, ParserContext.EVAL, null, parentFrame, true, this));
}

protected boolean parseDependsOnDeclarationFrame(RootNodeWrapper rootNode) {
Original file line number Diff line number Diff line change
@@ -29,13 +29,17 @@
import org.jruby.truffle.nodes.StringCachingGuards;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.layouts.Layouts;
import org.jruby.truffle.runtime.layouts.StringLayout;
import org.jruby.util.ByteList;
import org.jruby.util.StringSupport;

import java.io.IOException;

@CoreClass(name = "Truffle::Interop")
public abstract class TruffleInteropNodes {

// TODO CS 21-Dec-15 this shouldn't be needed any more - we can handle byte, short, float etc natively

@CoreMethod(names = "interop_to_ruby_primitive", isModuleFunction = true, needsSelf = false, required = 1)
public abstract static class InteropToRubyNode extends CoreMethodArrayArgumentsNode {

@@ -154,100 +158,104 @@ public boolean hasSizeProperty(VirtualFrame frame, TruffleObject receiver) {
}

@CoreMethod(names = "read_property", isModuleFunction = true, needsSelf = false, required = 2)
@ImportStatic(StringCachingGuards.class)
public abstract static class ReadPropertyNode extends CoreMethodArrayArgumentsNode {

@Child private Node node;

public ReadPropertyNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
this.node = Message.READ.createNode();
}

// TODO CS 21-Dec-15 should Truffle provide foreign access for strings?

@Specialization
public Object executeForeign(VirtualFrame frame, TruffleObject receiver, int identifier) {
return ForeignAccess.execute(node, frame, receiver, identifier);
}

@Specialization
public Object executeForeign(VirtualFrame frame, String receiver, int identifier) {
public Object readProperty(String receiver, int identifier) {
return receiver.charAt(identifier);
}

@Specialization
public Object executeForeign(VirtualFrame frame, String receiver, long identifier) {
public Object readProperty(String receiver, long identifier) {
return receiver.charAt((int) identifier);
}


@Specialization
public Object executeForeign(VirtualFrame frame, TruffleObject receiver, long identifier) {
return ForeignAccess.execute(node, frame, receiver, (int) identifier);
@Specialization(guards = {"!isRubySymbol(identifier)", "!isRubyString(identifier)"})
public Object readProperty(VirtualFrame frame,
TruffleObject receiver,
Object identifier,
@Cached("createReadNode()") Node readNode) {
return ForeignAccess.execute(readNode, frame, receiver, identifier);
}

@CompilationFinal private String identifier;
@Specialization(guards = {"isRubySymbol(identifier)", "identifier == cachedIdentifier"})
public Object readProperty(VirtualFrame frame,
TruffleObject receiver,
DynamicObject identifier,
@Cached("identifier") DynamicObject cachedIdentifier,
@Cached("identifier.toString()") String identifierString,
@Cached("createReadNode()") Node readNode) {
return ForeignAccess.execute(readNode, frame, receiver, identifierString);
}

@Specialization(guards = "isRubySymbol(identifier)")
public Object executeForeignSymbol(VirtualFrame frame, TruffleObject receiver, DynamicObject identifier) {
if (this.identifier == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
this.identifier = Layouts.SYMBOL.getString(identifier).intern();
}
return ForeignAccess.execute(node, frame, receiver, this.identifier);
@Specialization(guards = {"isRubyString(identifier)", "byteListsEqual(identifier, cachedIdentifier)"})
public Object readProperty(VirtualFrame frame,
TruffleObject receiver,
DynamicObject identifier,
@Cached("privatizeByteList(identifier)") ByteList cachedIdentifier,
@Cached("identifier.toString()") String identifierString,
@Cached("createReadNode()") Node readNode) {
return ForeignAccess.execute(readNode, frame, receiver, identifierString);
}

@Specialization
public Object executeForeign(VirtualFrame frame, TruffleObject receiver, DynamicObject identifier) {
return ForeignAccess.execute(node, frame, receiver, slowPathToString(identifier));
protected static Node createReadNode() {
return Message.READ.createNode();
}

@TruffleBoundary
private static String slowPathToString(DynamicObject identifier) {
assert RubyGuards.isRubyString(identifier);
return identifier.toString();
protected int getCacheLimit() {
return getContext().getOptions().EVAL_CACHE;
}

}

@CoreMethod(names = "write_property", isModuleFunction = true, needsSelf = false, required = 3)
@ImportStatic(StringCachingGuards.class)
public abstract static class WritePropertyNode extends CoreMethodArrayArgumentsNode {

@Child private Node node;

public WritePropertyNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
this.node = Message.WRITE.createNode();
}

@Specialization
public Object executeForeign(VirtualFrame frame, TruffleObject receiver, int identifier, Object value) {
return ForeignAccess.execute(node, frame, receiver, identifier, value);
@Specialization(guards = {"!isRubySymbol(identifier)", "!isRubyString(identifier)"})
public Object writeProperty(VirtualFrame frame,
TruffleObject receiver,
Object identifier,
Object value,
@Cached("createWriteNode()") Node writeNode) {
return ForeignAccess.execute(writeNode, frame, receiver, identifier, value);
}

@Specialization
public Object executeForeign(VirtualFrame frame, TruffleObject receiver, long identifier, Object value) {
return ForeignAccess.execute(node, frame, receiver, identifier, value);
}

@CompilationFinal private String identifier;

@Specialization(guards = "isRubySymbol(identifier)")
public Object executeForeignSymbol(VirtualFrame frame, TruffleObject receiver, DynamicObject identifier, Object value) {
if (this.identifier == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
this.identifier = Layouts.SYMBOL.getString(identifier).intern();
}
return ForeignAccess.execute(node, frame, receiver, this.identifier, value);
@Specialization(guards = {"isRubySymbol(identifier)", "identifier == cachedIdentifier"})
public Object writeProperty(VirtualFrame frame,
TruffleObject receiver,
DynamicObject identifier,
Object value,
@Cached("identifier") DynamicObject cachedIdentifier,
@Cached("identifier.toString()") String identifierString,
@Cached("createWriteNode()") Node writeNode) {
return ForeignAccess.execute(writeNode, frame, receiver, identifierString, value);
}

@Specialization(guards = "isRubyString(identifier)")
public Object executeForeignString(VirtualFrame frame, TruffleObject receiver, DynamicObject identifier, Object value) {
return ForeignAccess.execute(node, frame, receiver, slowPathToString(identifier), value);
@Specialization(guards = {"isRubyString(identifier)", "byteListsEqual(identifier, cachedIdentifier)"})
public Object writeProperty(VirtualFrame frame,
TruffleObject receiver,
DynamicObject identifier,
Object value,
@Cached("privatizeByteList(identifier)") ByteList cachedIdentifier,
@Cached("identifier.toString()") String identifierString,
@Cached("createWriteNode()") Node writeNode) {
return ForeignAccess.execute(writeNode, frame, receiver, identifierString, value);
}

@TruffleBoundary
private static String slowPathToString(DynamicObject identifier) {
assert RubyGuards.isRubyString(identifier);
return identifier.toString();
protected static Node createWriteNode() {
return Message.WRITE.createNode();
}

}
@@ -393,4 +401,21 @@ protected int getCacheLimit() {

}

// TODO CS-21-Dec-15 this shouldn't be needed - we need to convert j.l.String to Ruby's String automatically

@CoreMethod(names = "java_string_to_ruby", isModuleFunction = true, needsSelf = false, required = 1)
public abstract static class JavaStringToRubyNode extends CoreMethodArrayArgumentsNode {

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

@Specialization
@TruffleBoundary
public DynamicObject javaStringToRuby(String string) {
return Layouts.STRING.createString(getContext().getCoreLibrary().getStringFactory(), ByteList.create(string), StringSupport.CR_UNKNOWN, null);
}

}

}
Original file line number Diff line number Diff line change
@@ -410,7 +410,7 @@ public Object parseAndExecute(Source source, Encoding defaultEncoding, ParserCon
@TruffleBoundary
private RubyRootNode parse(Source source, Encoding defaultEncoding, ParserContext parserContext, MaterializedFrame parentFrame, boolean ownScopeForAssignments, Node currentNode) {
final TranslatorDriver translator = new TranslatorDriver(this);
return translator.parse(this, source, defaultEncoding, parserContext, parentFrame, ownScopeForAssignments, currentNode);
return translator.parse(this, source, defaultEncoding, parserContext, null, parentFrame, ownScopeForAssignments, currentNode);
}

@TruffleBoundary
Original file line number Diff line number Diff line change
@@ -24,7 +24,10 @@
import org.jruby.runtime.scope.ManyVarsDynamicScope;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.arguments.MissingArgumentBehaviour;
import org.jruby.truffle.nodes.arguments.ReadPreArgumentNode;
import org.jruby.truffle.nodes.control.SequenceNode;
import org.jruby.truffle.nodes.locals.WriteLocalVariableNode;
import org.jruby.truffle.nodes.methods.CatchNextNode;
import org.jruby.truffle.nodes.methods.CatchRetryAsErrorNode;
import org.jruby.truffle.nodes.methods.CatchReturnAsErrorNode;
@@ -38,6 +41,8 @@
import org.jruby.truffle.runtime.methods.SharedMethodInfo;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class TranslatorDriver {

@@ -51,18 +56,20 @@ public TranslatorDriver(RubyContext context) {
parseEnvironment = new ParseEnvironment(context);
}

public RubyRootNode parse(RubyContext context, Source source, Encoding defaultEncoding, ParserContext parserContext, MaterializedFrame parentFrame, boolean ownScopeForAssignments, Node currentNode) {
public RubyRootNode parse(RubyContext context, Source source, Encoding defaultEncoding, ParserContext parserContext, String[] argumentNames, MaterializedFrame parentFrame, boolean ownScopeForAssignments, Node currentNode) {
// Set up the JRuby parser

final org.jruby.parser.Parser parser = new org.jruby.parser.Parser(context.getRuntime());

final StaticScope staticScope = context.getRuntime().getStaticScopeFactory().newLocalScope(null);

/*
* Note that jruby-parser will be mistaken about how deep the existing variables are,
* but that doesn't matter as we look them up ourselves after being told they're in some
* parent scope.
*/

if (parentFrame != null) {
/*
* Note that jruby-parser will be mistaken about how deep the existing variables are,
* but that doesn't matter as we look them up ourselves after being told they're in some
* parent scope.
*/

MaterializedFrame frame = parentFrame;

@@ -78,6 +85,12 @@ public RubyRootNode parse(RubyContext context, Source source, Encoding defaultEn
}
}

if (argumentNames != null) {
for (String name : argumentNames) {
staticScope.addVariableThisScope(name.intern()); // StaticScope expects interned var names
}
}

final DynamicScope dynamicScope = new ManyVarsDynamicScope(staticScope);

boolean isInlineSource = parserContext == ParserContext.SHELL;
@@ -101,10 +114,10 @@ public RubyRootNode parse(RubyContext context, Source source, Encoding defaultEn
throw new RaiseException(context.getCoreLibrary().syntaxError(message, currentNode));
}

return parse(currentNode, context, source, parserContext, parentFrame, ownScopeForAssignments, node);
return parse(currentNode, context, source, parserContext, argumentNames, parentFrame, ownScopeForAssignments, node);
}

private RubyRootNode parse(Node currentNode, RubyContext context, Source source, ParserContext parserContext, MaterializedFrame parentFrame, boolean ownScopeForAssignments, org.jruby.ast.RootNode rootNode) {
private RubyRootNode parse(Node currentNode, RubyContext context, Source source, ParserContext parserContext, String[] argumentNames, MaterializedFrame parentFrame, boolean ownScopeForAssignments, org.jruby.ast.RootNode rootNode) {
final SourceSection sourceSection = source.createSection("<main>", 0, source.getCode().length());

final InternalMethod parentMethod = parentFrame == null ? null : RubyArguments.getMethod(parentFrame.getArguments());
@@ -126,6 +139,14 @@ private RubyRootNode parse(Node currentNode, RubyContext context, Source source,
final TranslatorEnvironment environment = new TranslatorEnvironment(context, environmentForFrame(context, parentFrame),
parseEnvironment, parseEnvironment.allocateReturnID(), ownScopeForAssignments, false, sharedMethodInfo, sharedMethodInfo.getName(), false, null);

// Declare arguments as local variables in the top-level environment - we'll put the values there in a prelude

if (argumentNames != null) {
for (String name : argumentNames) {
environment.declareVar(name);
}
}

// Get the DATA constant

final Object data = getData(context);
@@ -151,6 +172,22 @@ private RubyRootNode parse(Node currentNode, RubyContext context, Source source,
truffleNode = rootNode.getBodyNode().accept(translator);
}

// Load arguments

if (argumentNames != null && argumentNames.length > 0) {
final List<RubyNode> sequence = new ArrayList<>();

for (int n = 0; n < argumentNames.length; n++) {
final String name = argumentNames[n];
final RubyNode readNode = new ReadPreArgumentNode(context, sourceSection, n, MissingArgumentBehaviour.NIL);
final FrameSlot slot = environment.getFrameDescriptor().findFrameSlot(name);
sequence.add(new WriteLocalVariableNode(context, sourceSection, readNode, slot));
}

sequence.add(truffleNode);
truffleNode = SequenceNode.sequence(context, sourceSection, sequence);
}

// Load flip-flop states

if (environment.getFlipFlopStates().size() > 0) {
Loading