Skip to content

Commit

Permalink
[Truffle] Initial work on supporting 64-bit long ropes.
Browse files Browse the repository at this point in the history
nirvdrum committed Apr 8, 2016
1 parent caff747 commit 4710381
Showing 28 changed files with 683 additions and 242 deletions.
20 changes: 17 additions & 3 deletions truffle/src/main/java/org/jruby/truffle/core/array/ArrayNodes.java
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@
import org.jcodings.specific.UTF8Encoding;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.CoreClass;
import org.jruby.truffle.core.CoreLibrary;
import org.jruby.truffle.core.CoreMethod;
import org.jruby.truffle.core.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.core.CoreMethodNode;
@@ -56,6 +57,7 @@
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.core.rope.RopeNodes;
import org.jruby.truffle.core.rope.RopeNodesFactory;
import org.jruby.truffle.core.rope.RopeTooLongException;
import org.jruby.truffle.core.string.StringCachingGuards;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.NotProvided;
@@ -2438,7 +2440,7 @@ public DynamicObject packCached(
DynamicObject array,
DynamicObject format,
@Cached("privatizeRope(format)") Rope cachedFormat,
@Cached("ropeLength(cachedFormat)") int cachedFormatLength,
@Cached("ropeLength(cachedFormat)") long cachedFormatLength,
@Cached("create(compileFormat(format))") DirectCallNode callPackNode) {
final BytesResult result;

@@ -2450,7 +2452,12 @@ public DynamicObject packCached(
throw FormatExceptionTranslator.translate(this, e);
}

return finishPack(cachedFormatLength, result);
if (!CoreLibrary.fitsIntoInteger(cachedFormatLength)) {
CompilerDirectives.transferToInterpreter();
throw new RopeTooLongException("Can't work with format strings larger than int range");
}

return finishPack((int) cachedFormatLength, result);
}

@Specialization(contains = "packCached", guards = "isRubyString(format)")
@@ -2469,7 +2476,14 @@ public DynamicObject packUncached(
throw FormatExceptionTranslator.translate(this, e);
}

return finishPack(Layouts.STRING.getRope(format).byteLength(), result);
final Rope rope = StringOperations.rope(format);

if (!CoreLibrary.fitsIntoInteger(rope.byteLength())) {
CompilerDirectives.transferToInterpreter();
throw new RopeTooLongException("Can't work with format strings longer than int range");
}

return finishPack((int) rope.byteLength(), result);
}

private DynamicObject finishPack(int formatLength, BytesResult result) {
Original file line number Diff line number Diff line change
@@ -42,6 +42,7 @@
import org.jruby.runtime.Visibility;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.CoreClass;
import org.jruby.truffle.core.CoreLibrary;
import org.jruby.truffle.core.CoreMethod;
import org.jruby.truffle.core.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.core.CoreMethodNode;
@@ -77,6 +78,7 @@
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.core.rope.RopeNodes;
import org.jruby.truffle.core.rope.RopeNodesFactory;
import org.jruby.truffle.core.rope.RopeTooLongException;
import org.jruby.truffle.core.rubinius.ObjectPrimitiveNodes;
import org.jruby.truffle.core.rubinius.ObjectPrimitiveNodesFactory;
import org.jruby.truffle.core.string.StringCachingGuards;
@@ -1959,7 +1961,7 @@ public DynamicObject formatCached(
DynamicObject format,
Object[] arguments,
@Cached("privatizeRope(format)") Rope cachedFormat,
@Cached("ropeLength(cachedFormat)") int cachedFormatLength,
@Cached("ropeLength(cachedFormat)") long cachedFormatLength,
@Cached("create(compileFormat(format))") DirectCallNode callPackNode) {
final BytesResult result;

@@ -1971,7 +1973,12 @@ public DynamicObject formatCached(
throw FormatExceptionTranslator.translate(this, e);
}

return finishFormat(cachedFormatLength, result);
if (!CoreLibrary.fitsIntoInteger(cachedFormatLength)) {
CompilerDirectives.transferToInterpreter();
throw new RopeTooLongException("Can't work with format strings larger than int range");
}

return finishFormat((int) cachedFormatLength, result);
}

@Specialization(guards = "isRubyString(format)", contains = "formatCached")
@@ -1990,7 +1997,14 @@ public DynamicObject formatUncached(
throw FormatExceptionTranslator.translate(this, e);
}

return finishFormat(Layouts.STRING.getRope(format).byteLength(), result);
final Rope rope = StringOperations.rope(format);

if (!CoreLibrary.fitsIntoInteger(rope.byteLength())) {
CompilerDirectives.transferToInterpreter();
throw new RopeTooLongException("Can't work with format strings larger than int range");
}

return finishFormat((int) rope.byteLength(), result);
}

private DynamicObject finishFormat(int formatLength, BytesResult result) {
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
import org.joni.exception.ValueException;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.CoreClass;
import org.jruby.truffle.core.CoreLibrary;
import org.jruby.truffle.core.CoreMethod;
import org.jruby.truffle.core.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.core.Layouts;
@@ -32,6 +33,7 @@
import org.jruby.truffle.core.coerce.ToIntNode;
import org.jruby.truffle.core.coerce.ToIntNodeGen;
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.core.rope.RopeTooLongException;
import org.jruby.truffle.core.string.StringGuards;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.NotProvided;
@@ -205,7 +207,13 @@ public Object getIndex(DynamicObject matchData, int index, int length) {
public Object getIndexSymbol(DynamicObject matchData, DynamicObject index, NotProvided length) {
try {
final Rope value = Layouts.SYMBOL.getRope(index);
final int i = Layouts.REGEXP.getRegex(Layouts.MATCH_DATA.getRegexp(matchData)).nameToBackrefNumber(value.getBytes(), value.begin(), value.begin() + value.byteLength(), Layouts.MATCH_DATA.getRegion(matchData));

if (!CoreLibrary.fitsIntoInteger(value.byteLength())) {
CompilerDirectives.transferToInterpreter();
throw new RopeTooLongException("Can't work with strings larger than int range");
}

final int i = Layouts.REGEXP.getRegex(Layouts.MATCH_DATA.getRegexp(matchData)).nameToBackrefNumber(value.getBytes(), value.begin(), (int) (value.begin() + value.byteLength()), Layouts.MATCH_DATA.getRegion(matchData));

return getIndex(matchData, i, NotProvided.INSTANCE);
} catch (final ValueException e) {
@@ -221,7 +229,13 @@ public Object getIndexSymbol(DynamicObject matchData, DynamicObject index, NotPr
public Object getIndexString(DynamicObject matchData, DynamicObject index, NotProvided length) {
try {
final Rope value = StringOperations.rope(index);
final int i = Layouts.REGEXP.getRegex(Layouts.MATCH_DATA.getRegexp(matchData)).nameToBackrefNumber(value.getBytes(), value.begin(), value.begin() + value.byteLength(), Layouts.MATCH_DATA.getRegion(matchData));

if (!CoreLibrary.fitsIntoInteger(value.byteLength())) {
CompilerDirectives.transferToInterpreter();
throw new RopeTooLongException("Can't work with strings larger than int range");
}

final int i = Layouts.REGEXP.getRegex(Layouts.MATCH_DATA.getRegexp(matchData)).nameToBackrefNumber(value.getBytes(), value.begin(), (int) (value.begin() + value.byteLength()), Layouts.MATCH_DATA.getRegion(matchData));

return getIndex(matchData, i, NotProvided.INSTANCE);
}
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@
import org.joni.exception.ValueException;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.CoreClass;
import org.jruby.truffle.core.CoreLibrary;
import org.jruby.truffle.core.CoreMethod;
import org.jruby.truffle.core.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.core.Layouts;
@@ -54,6 +55,7 @@
import org.jruby.truffle.core.rope.RopeNodes;
import org.jruby.truffle.core.rope.RopeNodesFactory;
import org.jruby.truffle.core.rope.RopeOperations;
import org.jruby.truffle.core.rope.RopeTooLongException;
import org.jruby.truffle.core.rubinius.RegexpPrimitiveNodes.RegexpSetLastMatchPrimitiveNode;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyGuards;
@@ -81,13 +83,18 @@ public static Object matchCommon(RubyContext context, RopeNodes.MakeSubstringNod

final Rope sourceRope = StringOperations.rope(source);

if (!CoreLibrary.fitsIntoInteger(sourceRope.byteLength())) {
CompilerDirectives.transferToInterpreter();
throw new RopeTooLongException("Can't work with strings larger than int range");
}

final Rope regexpSourceRope = Layouts.REGEXP.getSource(regexp);
final Encoding enc = checkEncoding(regexp, sourceRope, true);
final ByteList preprocessed = RegexpSupport.preprocess(context.getJRubyRuntime(), RopeOperations.getByteListReadOnly(regexpSourceRope), enc, new Encoding[] { null }, RegexpSupport.ErrorMode.RAISE);

final Regex r = new Regex(preprocessed.getUnsafeBytes(), preprocessed.getBegin(), preprocessed.getBegin() + preprocessed.getRealSize(), Layouts.REGEXP.getOptions(regexp).toJoniOptions(), checkEncoding(regexp, sourceRope, true));
final Matcher matcher = r.matcher(sourceRope.getBytes(), sourceRope.begin(), sourceRope.begin() + sourceRope.byteLength());
int range = sourceRope.begin() + sourceRope.byteLength();
final Matcher matcher = r.matcher(sourceRope.getBytes(), sourceRope.begin(), (int) (sourceRope.begin() + sourceRope.byteLength()));
int range = (int) (sourceRope.begin() + sourceRope.byteLength());

return matchCommon(context, makeSubstringNode, regexp, source, operator, setNamedCaptures, matcher, sourceRope.begin() + startPos, range);
}
@@ -99,6 +106,11 @@ public static Object matchCommon(RubyContext context, RopeNodes.MakeSubstringNod

final Rope sourceRope = StringOperations.rope(source);

if (!CoreLibrary.fitsIntoInteger(sourceRope.byteLength())) {
CompilerDirectives.transferToInterpreter();
throw new RopeTooLongException("Can't work with strings larger than int range");
}

final int match = matcher.search(startPos, range, Option.DEFAULT);

final DynamicObject nil = context.getCoreLibrary().getNilObject();
@@ -145,7 +157,7 @@ public static Object matchCommon(RubyContext context, RopeNodes.MakeSubstringNod
}

final DynamicObject pre = createSubstring(makeSubstringNode, source, 0, region.beg[0]);
final DynamicObject post = createSubstring(makeSubstringNode, source, region.end[0], sourceRope.byteLength() - region.end[0]);
final DynamicObject post = createSubstring(makeSubstringNode, source, region.end[0], (int) (sourceRope.byteLength() - region.end[0]));
final DynamicObject global = createSubstring(makeSubstringNode, source, region.beg[0], region.end[0] - region.beg[0]);

final DynamicObject matchObject = Layouts.MATCH_DATA.createMatchData(Layouts.CLASS.getInstanceFactory(context.getCoreLibrary().getMatchDataClass()),
Original file line number Diff line number Diff line change
@@ -11,6 +11,6 @@

public interface BytesVisitor {

void accept(byte[] bytes, int offset, int length);
void accept(byte[] bytes, long offset, long length);

}
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import org.jcodings.Encoding;
import org.jruby.util.func.Function1;

public class ConcatRope extends Rope {

@@ -48,7 +47,7 @@ public Rope withEncoding(Encoding newEncoding, CodeRange newCodeRange) {

@Override
@TruffleBoundary
public byte getByteSlow(int index) {
public byte getByteSlow(long index) {
if (index < left.byteLength()) {
return left.getByteSlow(index);
}
13 changes: 10 additions & 3 deletions truffle/src/main/java/org/jruby/truffle/core/rope/LeafRope.java
Original file line number Diff line number Diff line change
@@ -9,17 +9,24 @@
*/
package org.jruby.truffle.core.rope;

import com.oracle.truffle.api.CompilerDirectives;
import org.jcodings.Encoding;
import org.jruby.truffle.core.CoreLibrary;

public abstract class LeafRope extends Rope {

public LeafRope(byte[] bytes, Encoding encoding, CodeRange codeRange, boolean singleByteOptimizable, int characterLength) {
public LeafRope(byte[] bytes, Encoding encoding, CodeRange codeRange, boolean singleByteOptimizable, long characterLength) {
super(encoding, codeRange, singleByteOptimizable, bytes.length, characterLength, 1, bytes);
}

@Override
public byte getByteSlow(int index) {
return getRawBytes()[index];
public byte getByteSlow(long index) {
if (!CoreLibrary.fitsIntoInteger(index)) {
CompilerDirectives.transferToInterpreter();
throw new RopeTooLongException("Index outside of int range");
}

return getRawBytes()[(int) index];
}

@Override
13 changes: 10 additions & 3 deletions truffle/src/main/java/org/jruby/truffle/core/rope/MutableRope.java
Original file line number Diff line number Diff line change
@@ -10,14 +10,16 @@

package org.jruby.truffle.core.rope;

import com.oracle.truffle.api.CompilerDirectives;
import org.jcodings.Encoding;
import org.jruby.truffle.core.CoreLibrary;
import org.jruby.util.ByteList;

public class MutableRope extends LeafRope {

private final ByteList byteList;

protected MutableRope(byte[] bytes, Encoding encoding, CodeRange codeRange, boolean singleByteOptimizable, int characterLength) {
protected MutableRope(byte[] bytes, Encoding encoding, CodeRange codeRange, boolean singleByteOptimizable, long characterLength) {
super(bytes, encoding, codeRange, singleByteOptimizable, characterLength);
this.byteList = new ByteList(bytes, encoding, true);
}
@@ -37,8 +39,13 @@ public Rope withEncoding(Encoding newEncoding, CodeRange newCodeRange) {
}

@Override
public byte getByteSlow(int index) {
return (byte) byteList.get(index);
public byte getByteSlow(long index) {
if (!CoreLibrary.fitsIntoInteger(index)) {
CompilerDirectives.transferToInterpreter();
throw new RopeTooLongException("Index outside of int range");
}

return (byte) byteList.get((int) index);
}

public ByteList getByteList() {
Original file line number Diff line number Diff line change
@@ -10,14 +10,16 @@

package org.jruby.truffle.core.rope;

import com.oracle.truffle.api.CompilerDirectives;
import org.jcodings.Encoding;
import org.jruby.truffle.core.CoreLibrary;

public class RepeatingRope extends Rope {

private final Rope child;
private final int times;
private final long times;

public RepeatingRope(Rope child, int times) {
public RepeatingRope(Rope child, long times) {
super(child.getEncoding(), child.getCodeRange(), child.isSingleByteOptimizable(), child.byteLength() * times, child.characterLength() * times, child.depth() + 1, null);
this.child = child;
this.times = times;
@@ -29,22 +31,27 @@ public Rope withEncoding(Encoding newEncoding, CodeRange newCodeRange) {
}

@Override
protected byte getByteSlow(int index) {
protected byte getByteSlow(long index) {
return child.getByteSlow(index % child.byteLength());
}

public Rope getChild() {
return child;
}

public int getTimes() {
public long getTimes() {
return times;
}

@Override
public String toString() {
if (!CoreLibrary.fitsIntoInteger(byteLength())) {
CompilerDirectives.transferToInterpreter();
throw new RopeTooLongException("Can't convert larger than int range to a Java String");
}

final String childString = child.toString();
final StringBuilder builder = new StringBuilder(childString.length() * times);
final StringBuilder builder = new StringBuilder((int) (childString.length() * times));

for (int i = 0; i < times; i++) {
builder.append(childString);
12 changes: 6 additions & 6 deletions truffle/src/main/java/org/jruby/truffle/core/rope/Rope.java
Original file line number Diff line number Diff line change
@@ -18,13 +18,13 @@ public abstract class Rope {
private final Encoding encoding;
private final CodeRange codeRange;
private final boolean singleByteOptimizable;
private final int byteLength;
private final int characterLength;
private final long byteLength;
private final long characterLength;
private final int ropeDepth;
private int hashCode = 0;
private byte[] bytes;

protected Rope(Encoding encoding, CodeRange codeRange, boolean singleByteOptimizable, int byteLength, int characterLength, int ropeDepth, byte[] bytes) {
protected Rope(Encoding encoding, CodeRange codeRange, boolean singleByteOptimizable, long byteLength, long characterLength, int ropeDepth, byte[] bytes) {
this.encoding = encoding;
this.codeRange = codeRange;
this.singleByteOptimizable = singleByteOptimizable;
@@ -36,19 +36,19 @@ protected Rope(Encoding encoding, CodeRange codeRange, boolean singleByteOptimiz

public abstract Rope withEncoding(Encoding newEncoding, CodeRange newCodeRange);

public final int characterLength() {
public final long characterLength() {
return characterLength;
}

public final int byteLength() {
public final long byteLength() {
return byteLength;
}

public boolean isEmpty() {
return byteLength == 0;
}

protected abstract byte getByteSlow(int index);
protected abstract byte getByteSlow(long index);

public final byte[] getRawBytes() {
return bytes;
Loading

0 comments on commit 4710381

Please sign in to comment.