Skip to content

Commit

Permalink
[Truffle] Specialise for the implicit #to_s in string interpolation.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseaton committed Dec 10, 2014
1 parent 0a172df commit b7a688e
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 17 deletions.
69 changes: 69 additions & 0 deletions core/src/main/java/org/jruby/truffle/nodes/cast/ToSNode.java
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2014 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.nodes.cast;

import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyTypesGen;
import org.jruby.truffle.nodes.core.KernelNodes;
import org.jruby.truffle.nodes.core.KernelNodesFactory;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyString;

@NodeChild(type = RubyNode.class)
public abstract class ToSNode extends RubyNode {

@Child protected DispatchHeadNode callToSNode;
@Child protected KernelNodes.ClassNode classNode;
@Child protected KernelNodes.ToSNode toSNode;

public ToSNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
callToSNode = new DispatchHeadNode(context, true);
classNode = KernelNodesFactory.ClassNodeFactory.create(context, sourceSection, new RubyNode[]{null});
toSNode = KernelNodesFactory.ToSNodeFactory.create(context, sourceSection, new RubyNode[]{null});
}

public ToSNode(ToSNode prev) {
super(prev);
callToSNode = prev.callToSNode;
classNode = prev.classNode;
toSNode = prev.toSNode;
}

@Override
public abstract RubyString executeString(VirtualFrame frame);

@Specialization
public RubyString toS(RubyString string) {
return string;
}

@Specialization(guards = "!isRubyString", rewriteOn = UnexpectedResultException.class)
public RubyString toS(VirtualFrame frame, Object object) throws UnexpectedResultException {
return RubyTypesGen.RUBYTYPES.expectRubyString(callToSNode.call(frame, object, "to_s", null));
}

@Specialization(guards = "!isRubyString")
public RubyString toSFallback(VirtualFrame frame, Object object) {
final Object value = callToSNode.call(frame, object, "to_s", null);

if (value instanceof RubyString) {
return (RubyString) value;
} else {
return toSNode.toS(classNode.executeGetClass(frame, object));
}
}
}
Expand Up @@ -14,6 +14,7 @@
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.nodes.*;
import org.jruby.truffle.nodes.*;
import org.jruby.truffle.nodes.cast.ToSNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.core.RubyBasicObject;
Expand All @@ -25,13 +26,11 @@
*/
public final class InterpolatedStringNode extends RubyNode {

@Children protected final RubyNode[] children;
@Child protected DispatchHeadNode toS;
@Children protected final ToSNode[] children;

public InterpolatedStringNode(RubyContext context, SourceSection sourceSection, RubyNode[] children) {
public InterpolatedStringNode(RubyContext context, SourceSection sourceSection, ToSNode[] children) {
super(context, sourceSection);
this.children = children;
toS = new DispatchHeadNode(context, true);
}

@ExplodeLoop
Expand All @@ -40,16 +39,7 @@ public Object execute(VirtualFrame frame) {
final RubyString[] strings = new RubyString[children.length];

for (int n = 0; n < children.length; n++) {
Object result = toS.call(frame, children[n].execute(frame), "to_s", null);

if (result instanceof RubyString) {
strings[n] = (RubyString) result;
} else if (result instanceof RubyBasicObject) {
strings[n] = KernelNodesFactory.ToSNodeFactory.create(getContext(), getSourceSection(), new RubyNode[]{}).toS((RubyBasicObject) result);
} else {
RubyBasicObject boxed = getContext().getCoreLibrary().getLogicalClass(result);
strings[n] = KernelNodesFactory.ToSNodeFactory.create(getContext(), getSourceSection(), new RubyNode[]{}).toS(boxed);
}
strings[n] = children[n].executeString(frame);
}

return concat(strings);
Expand Down
Expand Up @@ -362,6 +362,8 @@ public ClassNode(ClassNode prev) {
super(prev);
}

public abstract RubyClass executeGetClass(VirtualFrame frame, Object value);

@Specialization
public RubyClass getClass(boolean value) {
notDesignedForCompilation();
Expand Down
Expand Up @@ -702,13 +702,13 @@ public RubyNode visitDSymbolNode(org.jruby.ast.DSymbolNode node) {
}

private RubyNode translateInterpolatedString(SourceSection sourceSection, List<org.jruby.ast.Node> childNodes) {
final List<RubyNode> children = new ArrayList<>();
final List<ToSNode> children = new ArrayList<>();

for (org.jruby.ast.Node child : childNodes) {
children.add(child.accept(this));
children.add(ToSNodeFactory.create(context, sourceSection, child.accept(this)));
}

return new InterpolatedStringNode(context, sourceSection, children.toArray(new RubyNode[children.size()]));
return new InterpolatedStringNode(context, sourceSection, children.toArray(new ToSNode[children.size()]));
}

@Override
Expand Down

0 comments on commit b7a688e

Please sign in to comment.