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

Commits on Dec 7, 2014

  1. Copy the full SHA
    7723844 View commit details
  2. Copy the full SHA
    6f49dd7 View commit details
  3. Copy the full SHA
    423da52 View commit details
  4. Copy the full SHA
    4da8bac View commit details
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@
import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.frame.*;
import org.jruby.truffle.nodes.*;
import org.jruby.truffle.nodes.core.ArrayDupNode;
import org.jruby.truffle.nodes.core.ArrayDupNodeFactory;
import org.jruby.truffle.nodes.dispatch.Dispatch;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.runtime.*;
@@ -34,6 +36,7 @@ public static enum NilBehavior {

private final NilBehavior nilBehavior;

@Child protected ArrayDupNode dup;
@Child protected DispatchHeadNode respondToToA;
@Child protected BooleanCastNode respondToCast;
@Child protected DispatchHeadNode toA;
@@ -42,13 +45,15 @@ public SplatCastNode(RubyContext context, SourceSection sourceSection, NilBehavi
super(context, sourceSection);
this.nilBehavior = nilBehavior;
// Calling private #to_a is allowed for the *splat operator.
dup = ArrayDupNodeFactory.create(context, sourceSection, null);
respondToToA = new DispatchHeadNode(context, true, Dispatch.MissingBehavior.RETURN_MISSING);
respondToCast = BooleanCastNodeFactory.create(context, sourceSection, null);
toA = new DispatchHeadNode(context, true, Dispatch.MissingBehavior.RETURN_MISSING);
}

public SplatCastNode(SplatCastNode prev) {
super(prev);
dup = prev.dup;
nilBehavior = prev.nilBehavior;
respondToToA = prev.respondToToA;
respondToCast = prev.respondToCast;
@@ -74,8 +79,10 @@ public RubyArray splat(RubyNilClass nil) {
}

@Specialization
public RubyArray splat(RubyArray array) {
return array;
public RubyArray splat(VirtualFrame frame, RubyArray array) {
// TODO(cs): is it necessary to dup here in all cases?
// It is needed at least for [*ary] (translated as just a SplatNode) and b = *ary.
return dup.executeDup(frame, array);
}

@Specialization(guards = {"!isRubyNilClass", "!isRubyArray"})
66 changes: 66 additions & 0 deletions core/src/main/java/org/jruby/truffle/nodes/core/ArrayDupNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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.core;

import com.oracle.truffle.api.dsl.ImportGuards;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;

import java.util.Arrays;

/**
* Dup an array, without using any method lookup. This isn't a call - it's an operation on a core class.
*/
@NodeChildren({@NodeChild(value = "array", type = RubyNode.class)})
@ImportGuards(ArrayGuards.class)
public abstract class ArrayDupNode extends RubyNode {

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

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

public abstract RubyArray executeDup(VirtualFrame frame, RubyArray array);

@Specialization(guards = "isNull")
public RubyArray dupNull(RubyArray from) {
return new RubyArray(getContext().getCoreLibrary().getArrayClass(), null, 0);
}

@Specialization(guards = "isIntegerFixnum")
public RubyArray dupIntegerFixnum(RubyArray from) {
return new RubyArray(getContext().getCoreLibrary().getArrayClass(), Arrays.copyOf((int[]) from.getStore(), from.getSize()), from.getSize());
}

@Specialization(guards = "isLongFixnum")
public RubyArray dupLongFixnum(RubyArray from) {
return new RubyArray(getContext().getCoreLibrary().getArrayClass(), Arrays.copyOf((long[]) from.getStore(), from.getSize()), from.getSize());
}

@Specialization(guards = "isFloat")
public RubyArray dupFloat(RubyArray from) {
return new RubyArray(getContext().getCoreLibrary().getArrayClass(), Arrays.copyOf((double[]) from.getStore(), from.getSize()), from.getSize());
}

@Specialization(guards = "isObject")
public RubyArray dupObject(RubyArray from) {
return new RubyArray(getContext().getCoreLibrary().getArrayClass(), Arrays.copyOf((Object[]) from.getStore(), from.getSize()), from.getSize());
}

}
67 changes: 62 additions & 5 deletions core/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.control.BreakException;
import org.jruby.truffle.runtime.control.NextException;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.control.RedoException;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.core.RubyArray;
@@ -711,7 +712,8 @@ public int setIntegerFixnum(RubyArray array, int index, int value, UndefinedPlac

if (normalisedIndex < 0) {
tooSmallBranch.enter();
throw new UnsupportedOperationException();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", index, array.getSize(), this));
} else if (normalisedIndex >= array.getSize()) {
pastEndBranch.enter();

@@ -749,7 +751,8 @@ public long setLongInIntegerFixnum(RubyArray array, int index, long value, Undef

if (normalisedIndex < 0) {
tooSmallBranch.enter();
throw new UnsupportedOperationException();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", index, array.getSize(), this));
} else if (normalisedIndex >= array.getSize()) {
pastEndBranch.enter();

@@ -774,6 +777,38 @@ public long setLongInIntegerFixnum(RubyArray array, int index, long value, Undef
return value;
}

@Specialization(guards = "isIntegerFixnum")
public RubyArray setIntegerFixnum(RubyArray array, int start, int length, RubyArray value) {
notDesignedForCompilation();

if (length < 0) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexNegativeLength(length, this));
}

if (value.getSize() == 0) {
final int begin = array.normaliseIndex(start);
final int exclusiveEnd = begin + length;
int[] store = (int[]) array.getStore();

if (begin < 0) {
tooSmallBranch.enter();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", start, array.getSize(), this));
} else if (exclusiveEnd > array.getSize()) {
throw new UnsupportedOperationException();
}

// TODO: This is a moving overlapping memory, should we use sth else instead?
System.arraycopy(store, exclusiveEnd, store, begin, array.getSize() - exclusiveEnd);
array.setSize(array.getSize() - length);

return value;
} else {
throw new UnsupportedOperationException();
}
}

@Specialization(guards = "isLongFixnum")
public int setLongFixnum(RubyArray array, int index, int value, UndefinedPlaceholder unused) {
setLongFixnum(array, index, (long) value, unused);
@@ -787,7 +822,8 @@ public long setLongFixnum(RubyArray array, int index, long value, UndefinedPlace

if (normalisedIndex < 0) {
tooSmallBranch.enter();
throw new UnsupportedOperationException();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", index, array.getSize(), this));
} else if (normalisedIndex >= array.getSize()) {
pastEndBranch.enter();

@@ -819,7 +855,8 @@ public double setFloat(RubyArray array, int index, double value, UndefinedPlaceh

if (normalisedIndex < 0) {
tooSmallBranch.enter();
throw new UnsupportedOperationException();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", index, array.getSize(), this));
} else if (normalisedIndex >= array.getSize()) {
pastEndBranch.enter();

@@ -851,7 +888,8 @@ public Object setObject(RubyArray array, int index, Object value, UndefinedPlace

if (normalisedIndex < 0) {
tooSmallBranch.enter();
throw new UnsupportedOperationException();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", index, array.getSize(), this));
} else if (normalisedIndex >= array.getSize()) {
pastEndBranch.enter();

@@ -876,6 +914,25 @@ public Object setObject(RubyArray array, int index, Object value, UndefinedPlace
return value;
}

@Specialization(guards = {"isObject", "!isRubyArray(arguments[3])"})
public Object setObject(RubyArray array, int start, int length, Object value) {
notDesignedForCompilation();

if (length < 0) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexNegativeLength(length, this));
}

final int begin = array.normaliseIndex(start);

if (begin >= array.getSize()) {
// We don't care of length in this case
return setObject(array, start, value, UndefinedPlaceholder.INSTANCE);
} else {
throw new UnsupportedOperationException();
}
}

@Specialization(guards = "isIntegerFixnum")
public RubyArray setIntegerFixnumRange(RubyArray array, RubyRange.IntegerFixnumRange range, RubyArray other, UndefinedPlaceholder unused) {
if (range.doesExcludeEnd()) {
20 changes: 20 additions & 0 deletions core/src/main/java/org/jruby/truffle/nodes/core/RangeNodes.java
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.utilities.*;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.PredicateDispatchHeadNode;
@@ -28,6 +29,8 @@ public abstract class RangeNodes {
@CoreMethod(names = "==", required = 1)
public abstract static class EqualNode extends CoreMethodNode {

@Child protected KernelNodes.SameOrEqualNode equalNode;

public EqualNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}
@@ -36,6 +39,15 @@ public EqualNode(EqualNode prev) {
super(prev);
}

protected boolean equal(VirtualFrame frame, Object a, Object b) {
if (equalNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
equalNode = insert(KernelNodesFactory.SameOrEqualNodeFactory.create(getContext(), getSourceSection(), new RubyNode[]{null, null}));
}
return equalNode.executeSameOrEqual(frame, a, b);

}

@Specialization
public boolean equal(RubyRange.IntegerFixnumRange a, RubyRange.IntegerFixnumRange b) {
notDesignedForCompilation();
@@ -64,6 +76,14 @@ public boolean equal(RubyRange.LongFixnumRange a, RubyRange.IntegerFixnumRange b
return a.doesExcludeEnd() == b.doesExcludeEnd() && a.getBegin() == b.getBegin() && a.getEnd() == b.getEnd();
}

@Specialization
public boolean equal(VirtualFrame frame, RubyRange.ObjectRange a, RubyRange.ObjectRange b) {
notDesignedForCompilation();

return a.doesExcludeEnd() == b.doesExcludeEnd() &&
equal(frame, a.getBegin(), b.getBegin()) &&
equal(frame, a.getEnd(), b.getEnd());
}
}

@CoreMethod(names = {"collect", "map"}, needsBlock = true, lowerFixnumSelf = true)
Original file line number Diff line number Diff line change
@@ -234,7 +234,7 @@ public RubyString getIndex(RubyString string, int start, int length) {
// TODO(CS): not sure if this is right - encoding
// TODO(CS): why does subSequence return CharSequence?
final int begin = string.normaliseIndex(start);
final int exclusiveEnd = string.normaliseIndex(start + length);
final int exclusiveEnd = string.normaliseIndex(begin + length);
return new RubyString(getContext().getCoreLibrary().getStringClass(), (ByteList) string.getBytes().subSequence(begin, exclusiveEnd - begin));
}

21 changes: 19 additions & 2 deletions core/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -57,6 +57,7 @@ public class CoreLibrary {
@CompilerDirectives.CompilationFinal private RubyClass floatClass;
@CompilerDirectives.CompilationFinal private RubyClass hashClass;
@CompilerDirectives.CompilationFinal private RubyClass integerClass;
@CompilerDirectives.CompilationFinal private RubyClass indexErrorClass;
@CompilerDirectives.CompilationFinal private RubyClass ioClass;
@CompilerDirectives.CompilationFinal private RubyClass loadErrorClass;
@CompilerDirectives.CompilationFinal private RubyClass localJumpErrorClass;
@@ -199,6 +200,7 @@ public void initialize() {
floatClass = new RubyClass(context, objectClass, numericClass, "Float");
gcModule = new RubyModule(context, objectClass, "GC");
hashClass = new RubyHash.RubyHashClass(context, objectClass);
indexErrorClass = new RubyException.RubyExceptionClass(context, objectClass, standardErrorClass, "IndexError");
kernelModule = new RubyModule(context, objectClass, "Kernel");
loadErrorClass = new RubyException.RubyExceptionClass(context, objectClass, standardErrorClass, "LoadError");
localJumpErrorClass = new RubyException.RubyExceptionClass(context, objectClass, standardErrorClass, "LocalJumpError");
@@ -408,7 +410,7 @@ public RubyClass getLogicalClass(Object object) {

public RubyException runtimeError(String message, Node currentNode) {
CompilerAsserts.neverPartOfCompilation();
return new RubyException(runtimeErrorClass, context.makeString(String.format("%s", message)), RubyCallStack.getBacktrace(currentNode));
return new RubyException(runtimeErrorClass, context.makeString(message), RubyCallStack.getBacktrace(currentNode));
}

public RubyException frozenError(String className, Node currentNode) {
@@ -418,7 +420,7 @@ public RubyException frozenError(String className, Node currentNode) {

public RubyException argumentError(String message, Node currentNode) {
CompilerAsserts.neverPartOfCompilation();
return new RubyException(argumentErrorClass, context.makeString(String.format("%s", message)), RubyCallStack.getBacktrace(currentNode));
return new RubyException(argumentErrorClass, context.makeString(message), RubyCallStack.getBacktrace(currentNode));
}

public RubyException argumentError(int passed, int required, Node currentNode) {
@@ -431,6 +433,21 @@ public RubyException argumentError(int passed, int required, int optional, Node
return argumentError(String.format("wrong number of arguments (%d for %d..%d)", passed, required, required + optional), currentNode);
}

public RubyException indexError(String message, Node currentNode) {
CompilerAsserts.neverPartOfCompilation();
return new RubyException(indexErrorClass, context.makeString(message), RubyCallStack.getBacktrace(currentNode));
}

public RubyException indexTooSmallError(String type, int index, int length, Node currentNode) {
CompilerAsserts.neverPartOfCompilation();
return indexError(String.format("index %d too small for %s; minimum: -%d", index, type, length), currentNode);
}

public RubyException indexNegativeLength(int length, Node currentNode) {
CompilerAsserts.neverPartOfCompilation();
return indexError(String.format("negative length (%d)", length), currentNode);
}

public RubyException localJumpError(String message, Node currentNode) {
CompilerAsserts.neverPartOfCompilation();
return new RubyException(localJumpErrorClass, context.makeString(message), RubyCallStack.getBacktrace(currentNode));
3 changes: 0 additions & 3 deletions spec/truffle/tags/language/array_tags.txt

This file was deleted.

4 changes: 0 additions & 4 deletions spec/truffle/tags/language/method_tags.txt
Original file line number Diff line number Diff line change
@@ -68,7 +68,3 @@ fails:"A method assigns local variables from method parameters for definition \n
fails:"A method assigns local variables from method parameters for definition \n def m(**k, &b) [k, b] end"
fails:"A method assigns local variables from method parameters for definition \n def m(a, b=1, *c, (*d, (e)), f: 2, g:, h:, **k, &l)\n [a, b, c, d, e, f, g, h, k, l]\n end"
fails:"A method assigns local variables from method parameters for definition \n def m a, b=1, *c, d, e:, f: 2, g:, **k, &l\n [a, b, c, d, e, f, g, k, l]\n end"
fails:"A method assigns local variables from method parameters for definition \n def m(a, (b, c)) [a, b, c] end"
fails:"A method assigns local variables from method parameters for definition \n def m((a, b), (c, d))\n [a, b, c, d]\n end"
fails:"A method assigns local variables from method parameters for definition \n def m(a=1, (b, c)) [a, b, c] end"
fails:"A method assigns local variables from method parameters for definition \n def m(a=1, (b, c), (d, e)) [a, b, c, d, e] end"
4 changes: 0 additions & 4 deletions spec/truffle/tags/language/predefined_tags.txt
Original file line number Diff line number Diff line change
@@ -61,7 +61,3 @@ fails:Predefined global $-0 raises a TypeError if assigned a Fixnum
fails:Predefined global $-0 raises a TypeError if assigned a boolean
fails:Global variable $0 raises a TypeError when not given an object that can be coerced to a String
fails:Predefined global $~ raises an error if assigned an object not nil or instanceof MatchData
fails:The predefined global constant STDOUT has nil for the internal encoding
fails:The predefined global constant STDOUT has nil for the internal encoding despite Encoding.default_internal being changed
fails:The predefined global constant STDERR has nil for the internal encoding
fails:The predefined global constant STDERR has nil for the internal encoding despite Encoding.default_internal being changed
2 changes: 0 additions & 2 deletions spec/truffle/tags/language/regexp/interpolation_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
fails:Regexps with interpolation allows interpolation of literal regexps
fails:Regexps with interpolation allows interpolation which mixes modifiers
fails:Regexps with interpolation gives precedence to escape sequences over substitution
fails:Regexps with interpolation throws RegexpError for malformed interpolation
fails:Regexps with interpolation allows interpolation in extended mode
fails:Regexps with interpolation allows escape sequences in interpolated regexps
1 change: 0 additions & 1 deletion spec/truffle/tags/language/variables_tags.txt
Original file line number Diff line number Diff line change
@@ -54,7 +54,6 @@ fails:Multiple assignment with a single RHS value calls #to_ary on the value ret
fails:Multiple assignment with a single RHS value assigns global variables
fails:Multiple assignment with a single RHS value assigns indexed elements
fails:Multiple assignment with a single splatted RHS value calls #to_a to convert nil to an empty Array
fails:Multiple assignment with a single splatted RHS value returns a copy of a splatted Array
fails:Multiple assignment with a single splatted RHS value returns an Array when the splatted object is an Array subclass
fails:Multiple assignment with a single splatted RHS value does not call #to_a if #respond_to? returns false
fails:Multiple assignment with a single splatted RHS value raises a TypeError if #to_a does not return an Array