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

Commits on Dec 25, 2014

  1. Copy the full SHA
    cacfc8b View commit details
  2. Copy the full SHA
    6e530ba View commit details
  3. 2
    Copy the full SHA
    3c9f9c2 View commit details
  4. Copy the full SHA
    7abbe1d View commit details
  5. [Truffle] Fix the resulting value from a multiple assignment with a s…

    …ingle lexical RHS value.
    chrisseaton committed Dec 25, 2014
    Copy the full SHA
    da89fb5 View commit details
  6. Copy the full SHA
    1aee31d View commit details
  7. [Truffle] Expand the behaviour of array cast to better support some p…

    …arts of multiple assignment.
    chrisseaton committed Dec 25, 2014
    4
    Copy the full SHA
    5ec7e73 View commit details
Showing with 289 additions and 89 deletions.
  1. +27 −2 core/src/main/java/org/jruby/truffle/nodes/cast/ArrayCastNode.java
  2. +4 −4 core/src/main/java/org/jruby/truffle/nodes/cast/SplatCastNode.java
  3. +2 −2 core/src/main/java/org/jruby/truffle/nodes/control/TryNode.java
  4. +7 −0 core/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java
  5. +20 −2 core/src/main/java/org/jruby/truffle/nodes/core/InterpolatedStringNode.java
  6. +160 −8 core/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
  7. +1 −1 core/src/main/java/org/jruby/truffle/nodes/objects/ReadInstanceVariableNode.java
  8. +1 −1 core/src/main/java/org/jruby/truffle/nodes/objects/WriteInstanceVariableNode.java
  9. +7 −3 core/src/main/java/org/jruby/truffle/nodes/objectstorage/ReadHeadObjectFieldNode.java
  10. +2 −2 core/src/main/java/org/jruby/truffle/nodes/objectstorage/UninitializedReadObjectFieldNode.java
  11. +2 −2 core/src/main/java/org/jruby/truffle/nodes/objectstorage/UninitializedWriteObjectFieldNode.java
  12. +3 −3 core/src/main/java/org/jruby/truffle/nodes/objectstorage/WriteHeadObjectFieldNode.java
  13. +15 −8 core/src/main/java/org/jruby/truffle/runtime/RubyOperations.java
  14. +10 −7 core/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
  15. +1 −20 core/src/main/java/org/jruby/truffle/runtime/core/RubyBasicObject.java
  16. +1 −1 core/src/main/java/org/jruby/truffle/runtime/core/RubyModule.java
  17. +2 −1 core/src/main/java/org/jruby/truffle/runtime/core/RubyRegexp.java
  18. +14 −4 core/src/main/java/org/jruby/truffle/translator/BodyTranslator.java
  19. +5 −3 core/src/main/java/org/jruby/truffle/translator/LoadArgumentsTranslator.java
  20. +4 −0 core/src/main/ruby/jruby/truffle/core/kernel.rb
  21. +0 −1 spec/truffle/tags/language/module_tags.txt
  22. +0 −2 spec/truffle/tags/language/string_tags.txt
  23. +1 −12 spec/truffle/tags/language/variables_tags.txt
29 changes: 27 additions & 2 deletions core/src/main/java/org/jruby/truffle/nodes/cast/ArrayCastNode.java
Original file line number Diff line number Diff line change
@@ -23,19 +23,30 @@
import org.jruby.truffle.runtime.core.RubyBignum;
import org.jruby.truffle.runtime.core.RubyNilClass;

/*
* TODO(CS): could probably unify this with SplatCastNode with some final configuration options.
*/
@NodeChild("child")
public abstract class ArrayCastNode extends RubyNode {

private final SplatCastNode.NilBehavior nilBehavior;

@Child protected DispatchHeadNode toArrayNode;

public ArrayCastNode(RubyContext context, SourceSection sourceSection) {
this(context, sourceSection, SplatCastNode.NilBehavior.NIL);
}

public ArrayCastNode(RubyContext context, SourceSection sourceSection, SplatCastNode.NilBehavior nilBehavior) {
super(context, sourceSection);
toArrayNode = new DispatchHeadNode(context, Dispatch.MissingBehavior.RETURN_MISSING);
this.nilBehavior = nilBehavior;
}

public ArrayCastNode(ArrayCastNode prev) {
super(prev);
toArrayNode = prev.toArrayNode;
nilBehavior = prev.nilBehavior;
}

protected abstract RubyNode getChild();
@@ -71,8 +82,22 @@ public RubyArray cast(RubyArray array) {
}

@Specialization
public RubyNilClass cast(RubyNilClass nil) {
return nil;
public Object cast(RubyNilClass nil) {
switch (nilBehavior) {
case EMPTY_ARRAY:
return new RubyArray(getContext().getCoreLibrary().getArrayClass());

case ARRAY_WITH_NIL:
return RubyArray.fromObject(getContext().getCoreLibrary().getArrayClass(), getContext().getCoreLibrary().getNilObject());

case NIL:
return nil;

default: {
CompilerAsserts.neverPartOfCompilation();
throw new UnsupportedOperationException();
}
}
}

@Specialization(guards = {"!isRubyNilClass", "!isRubyArray"})
Original file line number Diff line number Diff line change
@@ -33,7 +33,8 @@ public abstract class SplatCastNode extends RubyNode {

public static enum NilBehavior {
EMPTY_ARRAY,
ARRAY_WITH_NIL
ARRAY_WITH_NIL,
NIL
}

private final NilBehavior nilBehavior;
@@ -91,9 +92,8 @@ public RubyArray splat(VirtualFrame frame, RubyArray array) {
public RubyArray splat(VirtualFrame frame, Object object) {
notDesignedForCompilation();

RubyString toAString = getContext().makeString("to_a"); // TODO

if (respondToCast.executeBoolean(frame, respondToToA.call(frame, object, "respond_to?", null, toAString, true))) {
// TODO(CS): why are we directly calling #respond_to? instead of using a respondsTo on a dispatch head node?
if (respondToCast.executeBoolean(frame, respondToToA.call(frame, object, "respond_to?", null, getContext().makeString("to_a"), true))) {
final Object array = toA.call(frame, object, "to_a", null);

if (array instanceof RubyArray) {
Original file line number Diff line number Diff line change
@@ -18,7 +18,6 @@
import org.jruby.truffle.nodes.methods.ExceptionTranslatingNode;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.control.*;
import org.jruby.truffle.runtime.core.RubyBasicObject;

/**
* Represents a block of code run with exception handlers. There's no {@code try} keyword in Ruby -
@@ -73,7 +72,8 @@ public Object execute(VirtualFrame frame) {
private Object handleException(VirtualFrame frame, RaiseException exception) {
CompilerAsserts.neverPartOfCompilation();

getContext().getCoreLibrary().getGlobalVariablesObject().setInstanceVariable("$!", exception.getRubyException());
notDesignedForCompilation();
getContext().getCoreLibrary().getGlobalVariablesObject().getOperations().setInstanceVariable(getContext().getCoreLibrary().getGlobalVariablesObject(), "$!", exception.getRubyException());

for (RescueNode rescue : rescueParts) {
if (rescue.canHandle(frame, exception.getRubyException())) {
Original file line number Diff line number Diff line change
@@ -1948,6 +1948,13 @@ public RubyArray initialize(VirtualFrame frame, RubyArray array, int size, Undef
return array;
}

@Specialization
public RubyArray initialize(RubyArray array, RubyArray copy, UndefinedPlaceholder defaultValue, UndefinedPlaceholder block) {
notDesignedForCompilation();
array.setStore(copy.slowToArray(), copy.getSize());
return array;
}

}

@CoreMethod(names = "initialize_copy", visibility = Visibility.PRIVATE, required = 1)
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
import com.oracle.truffle.api.source.*;
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.nodes.*;
import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.truffle.nodes.*;
import org.jruby.truffle.nodes.cast.ToSNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
@@ -28,21 +29,38 @@ public final class InterpolatedStringNode extends RubyNode {

@Children protected final ToSNode[] children;

@Child protected KernelNodes.TaintedNode taintedNode;
@Child protected KernelNodes.TaintNode taintNode;

private final ConditionProfile taintProfile = ConditionProfile.createCountingProfile();

public InterpolatedStringNode(RubyContext context, SourceSection sourceSection, ToSNode[] children) {
super(context, sourceSection);
this.children = children;
taintedNode = KernelNodesFactory.TaintedNodeFactory.create(context, sourceSection, new RubyNode[]{});
taintNode = KernelNodesFactory.TaintNodeFactory.create(context, sourceSection, new RubyNode[]{});
}

@ExplodeLoop
@Override
public Object execute(VirtualFrame frame) {
final RubyString[] strings = new RubyString[children.length];

boolean tainted = false;

for (int n = 0; n < children.length; n++) {
strings[n] = children[n].executeString(frame);
final RubyString toInterpolate = children[n].executeString(frame);
strings[n] = toInterpolate;
tainted |= taintedNode.tainted(toInterpolate);
}

final RubyString string = concat(strings);

if (taintProfile.profile(tainted)) {
taintNode.taint(string);
}

return concat(strings);
return string;
}

@CompilerDirectives.TruffleBoundary
168 changes: 160 additions & 8 deletions core/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.*;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.source.*;
import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.frame.*;
@@ -28,6 +29,8 @@
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.PredicateDispatchHeadNode;
import org.jruby.truffle.nodes.literal.*;
import org.jruby.truffle.nodes.objectstorage.ReadHeadObjectFieldNode;
import org.jruby.truffle.nodes.objectstorage.WriteHeadObjectFieldNode;
import org.jruby.truffle.nodes.yield.*;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.backtrace.Activation;
@@ -341,7 +344,8 @@ public Object doCatch(VirtualFrame frame, Object tag, RubyProc block) {
} catch (ThrowException e) {
if (e.getTag().equals(tag)) {
// TODO(cs): unset rather than set to Nil?
getContext().getCoreLibrary().getGlobalVariablesObject().setInstanceVariable("$!", getContext().getCoreLibrary().getNilObject());
notDesignedForCompilation();
getContext().getCoreLibrary().getGlobalVariablesObject().getOperations().setInstanceVariable(getContext().getCoreLibrary().getGlobalVariablesObject(), "$!", getContext().getCoreLibrary().getNilObject());
return e.getValue();
} else {
throw e;
@@ -430,7 +434,7 @@ public Object clone(VirtualFrame frame, RubyBasicObject self) {
newObject.getSingletonClass(this).initCopy(self.getMetaClass());
}

newObject.setInstanceVariables(self.getInstanceVariables());
newObject.getOperations().setInstanceVariables(newObject, self.getOperations().getInstanceVariables(self));
initializeCloneNode.call(frame, newObject, "initialize_clone", null, self);

return newObject;
@@ -459,7 +463,7 @@ public Object dup(VirtualFrame frame, RubyBasicObject self) {
// This method is pretty crappy for compilation - it should improve with the OM

final RubyBasicObject newObject = self.getLogicalClass().newInstance(this);
newObject.setInstanceVariables(self.getInstanceVariables());
newObject.getOperations().setInstanceVariables(newObject, self.getOperations().getInstanceVariables(self));
initializeDupNode.call(frame, newObject, "initialize_dup", null, self);

return newObject;
@@ -999,15 +1003,17 @@ public InstanceVariableSetNode(InstanceVariableSetNode prev) {
public Object isInstanceVariableSet(RubyBasicObject object, RubyString name, Object value) {
notDesignedForCompilation();

object.setInstanceVariable(RubyContext.checkInstanceVariableName(getContext(), name.toString(), this), value);
notDesignedForCompilation();
object.getOperations().setInstanceVariable(object, RubyContext.checkInstanceVariableName(getContext(), name.toString(), this), value);
return value;
}

@Specialization
public Object isInstanceVariableSet(RubyBasicObject object, RubySymbol name, Object value) {
notDesignedForCompilation();

object.setInstanceVariable(RubyContext.checkInstanceVariableName(getContext(), name.toString(), this), value);
notDesignedForCompilation();
object.getOperations().setInstanceVariable(object, RubyContext.checkInstanceVariableName(getContext(), name.toString(), this), value);
return value;
}

@@ -1028,14 +1034,16 @@ public InstanceVariablesNode(InstanceVariablesNode prev) {
public RubyArray instanceVariables(RubyBasicObject self) {
notDesignedForCompilation();

final String[] instanceVariableNames = self.getFieldNames();
final Object[] instanceVariableNames = self.getOperations().getFieldNames(self);

Arrays.sort(instanceVariableNames);

final RubyArray array = new RubyArray(getContext().getCoreLibrary().getArrayClass());

for (String name : instanceVariableNames) {
array.slowPush(getContext().getSymbolTable().getSymbol(name));
for (Object name : instanceVariableNames) {
if (name instanceof String) {
array.slowPush(getContext().getSymbolTable().getSymbol((String) name));
}
}

return array;
@@ -1987,6 +1995,101 @@ public Object fork(Object[] args) {

}

@CoreMethod(names = "taint")
public abstract static class TaintNode extends CoreMethodNode {

@Child protected WriteHeadObjectFieldNode writeTaintNode;

public TaintNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
writeTaintNode = new WriteHeadObjectFieldNode(RubyBasicObject.TAINTED_IDENTIFIER);
}

public TaintNode(TaintNode prev) {
super(prev);
writeTaintNode = prev.writeTaintNode;
}

@Specialization
public Object taint(boolean object) {
return frozen(object);
}

@Specialization
public Object taint(int object) {
return frozen(object);
}

@Specialization
public Object taint(long object) {
return frozen(object);
}

@Specialization
public Object taint(double object) {
return frozen(object);
}

private Object frozen(Object object) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().frozenError(getContext().getCoreLibrary().getLogicalClass(object).getName(), this));
}


@Specialization
public Object taint(RubyBasicObject object) {
writeTaintNode.execute(object, true);
return object;
}

}

@CoreMethod(names = "tainted?")
public abstract static class TaintedNode extends CoreMethodNode {

@Child protected ReadHeadObjectFieldNode readTaintNode;

public TaintedNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
readTaintNode = new ReadHeadObjectFieldNode(RubyBasicObject.TAINTED_IDENTIFIER);
}

public TaintedNode(TaintedNode prev) {
super(prev);
readTaintNode = prev.readTaintNode;
}

@Specialization
public boolean tainted(boolean object) {
return false;
}

@Specialization
public boolean tainted(int object) {
return false;
}

@Specialization
public boolean tainted(long object) {
return false;
}

@Specialization
public boolean tainted(double object) {
return false;
}

@Specialization
public boolean tainted(RubyBasicObject object) {
try {
return readTaintNode.isSet(object) && readTaintNode.executeBoolean(object);
} catch (UnexpectedResultException e) {
throw new UnsupportedOperationException();
}
}

}

@CoreMethod(names = "throw", isModuleFunction = true, required = 1, optional = 1)
public abstract static class ThrowNode extends CoreMethodNode {

@@ -2086,4 +2189,53 @@ public RubyString toS(VirtualFrame frame, Object self) {

}

@CoreMethod(names = "untaint")
public abstract static class UntaintNode extends CoreMethodNode {

@Child protected WriteHeadObjectFieldNode writeTaintNode;

public UntaintNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
writeTaintNode = new WriteHeadObjectFieldNode(RubyBasicObject.TAINTED_IDENTIFIER);
}

public UntaintNode(UntaintNode prev) {
super(prev);
writeTaintNode = prev.writeTaintNode;
}

@Specialization
public Object taint(boolean object) {
return frozen(object);
}

@Specialization
public Object taint(int object) {
return frozen(object);
}

@Specialization
public Object taint(long object) {
return frozen(object);
}

@Specialization
public Object taint(double object) {
return frozen(object);
}

private Object frozen(Object object) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().frozenError(getContext().getCoreLibrary().getLogicalClass(object).getName(), this));
}


@Specialization
public Object taint(RubyBasicObject object) {
writeTaintNode.execute(object, false);
return object;
}

}

}
Loading