Skip to content

Commit

Permalink
Showing 9 changed files with 181 additions and 11 deletions.
13 changes: 11 additions & 2 deletions truffle/src/main/java/org/jruby/truffle/core/array/ArrayNodes.java
Original file line number Diff line number Diff line change
@@ -63,6 +63,7 @@
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.RubyRootNode;
import org.jruby.truffle.language.SnippetNode;
import org.jruby.truffle.language.arguments.MissingArgumentBehavior;
import org.jruby.truffle.language.arguments.ReadPreArgumentNode;
import org.jruby.truffle.language.arguments.RubyArguments;
@@ -3972,9 +3973,17 @@ public DynamicObject sortVeryShortObject(VirtualFrame frame, DynamicObject array
return createArray(getContext(), store, size);
}

public static final String SNIPPET = "sorted = dup; Rubinius.privately { sorted.isort_block!(0, right, block) }; sorted";
public static final String RIGHT = "right";
public static final String BLOCK = "block";

@Specialization(guards = { "!isNullArray(array)" })
public Object sortUsingRubinius(VirtualFrame frame, DynamicObject array, DynamicObject block) {
return ruby("sorted = dup; Rubinius.privately { sorted.isort_block!(0, right, block) }; sorted", "right", getSize(array), "block", block);
public Object sortUsingRubinius(
VirtualFrame frame,
DynamicObject array,
DynamicObject block,
@Cached("new(SNIPPET, RIGHT, BLOCK)") SnippetNode snippet) {
return snippet.execute(frame, getSize(array), block);
}

@Specialization(guards = { "!isNullArray(array)", "!isSmall(array)" })
Original file line number Diff line number Diff line change
@@ -710,7 +710,7 @@ protected RootNodeWrapper compileSource(VirtualFrame frame, DynamicObject source

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

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

protected boolean parseDependsOnDeclarationFrame(RootNodeWrapper rootNode) {
Original file line number Diff line number Diff line change
@@ -82,6 +82,7 @@
import org.jruby.truffle.language.NotProvided;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.SnippetNode;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.language.dispatch.DispatchHeadNodeFactory;
@@ -406,9 +407,14 @@ public Object concatString(DynamicObject string, DynamicObject other) {
}

@Specialization(guards = "!isRubyString(other)")
public Object concat(DynamicObject string, Object other) {
return ruby("string.concat_internal(other)", "string", string, "other", other);
public Object concat(
VirtualFrame frame,
DynamicObject string,
Object other,
@Cached("createMethodCall()") CallDispatchHeadNode callNode) {
return callNode.call(frame, string, "concat_internal", null, other);
}

}

@CoreMethod(names = {"[]", "slice"}, required = 1, optional = 1, lowerFixnumParameters = {0, 1}, taintFromSelf = true)
Original file line number Diff line number Diff line change
@@ -86,7 +86,7 @@ public Object execute(VirtualFrame frame) {
final TranslatorDriver translator = new TranslatorDriver(context);

final RubyRootNode rootNode = translator.parse(context, source, UTF8Encoding.INSTANCE,
ParserContext.TOP_LEVEL, argumentNames, null, true, null);
ParserContext.TOP_LEVEL, argumentNames, null, null, true, null);

final CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);

113 changes: 113 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/language/SnippetNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2016 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.language;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.source.Source;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.arguments.RubyArguments;
import org.jruby.truffle.language.methods.DeclarationContext;
import org.jruby.truffle.language.parser.ParserContext;

public class SnippetNode extends RubyBaseNode {

private final String expression;
private final String[] parameters;

@CompilationFinal private FrameDescriptor frameDescriptor;
@CompilationFinal private FrameSlot[] parameterFrameSlots;

@Child private DirectCallNode directCallNode;

public SnippetNode(String expression, String a, String b) {
this(expression, new String[]{a, b});
}

public SnippetNode(String expression, String... parameters) {
this.expression = expression;
this.parameters = parameters;
}

@ExplodeLoop
public Object execute(VirtualFrame frame, Object... arguments) {
if (directCallNode == null) {
CompilerDirectives.transferToInterpreter();

frameDescriptor = new FrameDescriptor(nil());
parameterFrameSlots = new FrameSlot[parameters.length];

for (int n = 0; n < parameters.length; n++) {
parameterFrameSlots[n] = frameDescriptor.findOrAddFrameSlot(parameters[n]);
}

final Source source = Source.fromText(StringOperations.createByteList(expression), "(snippet)");

final RubyRootNode rootNode = getContext().getCodeLoader().parse(
source,
UTF8Encoding.INSTANCE,
ParserContext.INLINE,
frameDescriptor,
null,
true,
this);

directCallNode = insert(Truffle.getRuntime().createDirectCallNode(Truffle.getRuntime().createCallTarget(rootNode)));

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

final Object[] parentFrameArguments = RubyArguments.pack(
null,
null,
RubyArguments.getMethod(frame),
DeclarationContext.INSTANCE_EVAL,
null,
RubyArguments.getSelf(frame),
null,
new Object[]{});

final MaterializedFrame parentFrame = Truffle.getRuntime().createMaterializedFrame(
parentFrameArguments,
frameDescriptor);

if (arguments.length != parameterFrameSlots.length) {
CompilerDirectives.transferToInterpreter();
throw new UnsupportedOperationException("number of arguments doesn't match number of parameters");
}

for (int n = 0; n < parameters.length; n++) {
parentFrame.setObject(parameterFrameSlots[n], arguments[n]);
}

final Object[] callArguments = RubyArguments.pack(
parentFrame,
null,
RubyArguments.getMethod(frame),
DeclarationContext.INSTANCE_EVAL,
null,
RubyArguments.getSelf(frame),
null,
new Object[]{});

return directCallNode.call(frame, callArguments);
}

}
Original file line number Diff line number Diff line change
@@ -21,6 +21,13 @@ public class CallDispatchHeadNode extends DispatchHeadNode {

@Child private BooleanCastNode booleanCastNode;

public static CallDispatchHeadNode createMethodCall() {
return new CallDispatchHeadNode(
null,
false,
MissingBehavior.CALL_METHOD_MISSING);
}

public CallDispatchHeadNode(RubyContext context, boolean ignoreVisibility, MissingBehavior missingBehavior) {
super(context, ignoreVisibility, missingBehavior, DispatchAction.CALL_METHOD);
}
Original file line number Diff line number Diff line change
@@ -45,15 +45,25 @@ public CodeLoader(RubyContext context) {
public RubyRootNode parse(Source source,
Encoding defaultEncoding,
ParserContext parserContext,
FrameDescriptor frameDescriptor,
MaterializedFrame parentFrame,
boolean ownScopeForAssignments,
Node currentNode) {
final TranslatorDriver translator = new TranslatorDriver(context);

return translator.parse(context, source, defaultEncoding, parserContext, null, parentFrame,
return translator.parse(context, source, defaultEncoding, parserContext, null, frameDescriptor, parentFrame,
ownScopeForAssignments, currentNode);
}

@TruffleBoundary
public RubyRootNode parse(Source source,
Encoding defaultEncoding,
ParserContext parserContext,
MaterializedFrame parentFrame,
boolean ownScopeForAssignments,
Node currentNode) {
return parse(source, defaultEncoding, parserContext, null, parentFrame, ownScopeForAssignments, currentNode);
}

@TruffleBoundary
public DeferredCall prepareExecute(ParserContext parserContext,
DeclarationContext declarationContext,
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
*/
package org.jruby.truffle.language.parser;

import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.Source;
@@ -23,6 +24,7 @@ RubyRootNode parse(RubyContext context,
Encoding defaultEncoding,
ParserContext parserContext,
String[] argumentNames,
FrameDescriptor frameDescriptor,
MaterializedFrame parentFrame,
boolean ownScopeForAssignments,
Node currentNode);
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.language.parser.jruby;

import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.MaterializedFrame;
@@ -57,7 +58,7 @@ public TranslatorDriver(RubyContext context) {
}

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

final org.jruby.parser.Parser parser = new org.jruby.parser.Parser(context.getJRubyRuntime());
@@ -70,8 +71,18 @@ public RubyRootNode parse(RubyContext context, Source source, Encoding defaultEn
* parent scope.
*/

if (parentFrame != null) {
final TranslatorEnvironment parentEnvironment;

if (frameDescriptor != null) {
for (FrameSlot slot : frameDescriptor.getSlots()) {
if (slot.getIdentifier() instanceof String) {
final String name = (String) slot.getIdentifier();
staticScope.addVariableThisScope(name.intern()); // StaticScope expects interned var names
}
}

parentEnvironment = environmentForFrameDescriptor(context, frameDescriptor);
} else if (parentFrame != null) {
MaterializedFrame frame = parentFrame;

while (frame != null) {
@@ -84,6 +95,10 @@ public RubyRootNode parse(RubyContext context, Source source, Encoding defaultEn

frame = RubyArguments.getDeclarationFrame(frame);
}

parentEnvironment = environmentForFrame(context, parentFrame);
} else {
parentEnvironment = environmentForFrame(context, null);
}

if (argumentNames != null) {
@@ -138,7 +153,7 @@ public RubyRootNode parse(RubyContext context, Source source, Encoding defaultEn
// TODO (10 Feb. 2015): name should be "<top (required)> for the require-d/load-ed files.
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, parseEnvironment.getLexicalScope(), Arity.NO_ARGUMENTS, "<main>", false, null, false, false, false);

final TranslatorEnvironment environment = new TranslatorEnvironment(context, environmentForFrame(context, parentFrame),
final TranslatorEnvironment environment = new TranslatorEnvironment(context, parentEnvironment,
parseEnvironment, parseEnvironment.allocateReturnID(), ownScopeForAssignments, false, sharedMethodInfo, sharedMethodInfo.getName(), 0, null);

// Declare arguments as local variables in the top-level environment - we'll put the values there in a prelude
@@ -219,6 +234,14 @@ public RubyRootNode parse(RubyContext context, Source source, Encoding defaultEn
return new RubyRootNode(context, truffleNode.getSourceSection(), environment.getFrameDescriptor(), sharedMethodInfo, truffleNode, environment.needsDeclarationFrame());
}

private TranslatorEnvironment environmentForFrameDescriptor(RubyContext context, FrameDescriptor frameDescriptor) {
SourceSection sourceSection = SourceSection.createUnavailable("Unknown source section", "(unknown)");
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, context.getRootLexicalScope(), Arity.NO_ARGUMENTS, "(unknown)", false, null, false, false, false);
// TODO(CS): how do we know if the frame is a block or not?
return new TranslatorEnvironment(context, null, parseEnvironment,
parseEnvironment.allocateReturnID(), true, true, sharedMethodInfo, sharedMethodInfo.getName(), 0, null, frameDescriptor);
}

private TranslatorEnvironment environmentForFrame(RubyContext context, MaterializedFrame frame) {
if (frame == null) {
return null;

0 comments on commit 0d58bb7

Please sign in to comment.