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

Commits on Jan 21, 2016

  1. Copy the full SHA
    1207099 View commit details
  2. Copy the full SHA
    dfa0dcd View commit details

Commits on Jan 22, 2016

  1. [Truffle] Updated Symbols to be backed by Ropes.

    This prevents a lot of converting Ropes into ByteLists so they can be used by Symbols.
    nirvdrum committed Jan 22, 2016
    Copy the full SHA
    c1ced33 View commit details
  2. Copy the full SHA
    82ebf67 View commit details
Showing with 304 additions and 105 deletions.
  1. +2 −1 test/truffle/compiler/pe/core/string_pe.rb
  2. +4 −0 truffle/src/main/java/org/jruby/truffle/nodes/RubyNode.java
  3. +1 −1 truffle/src/main/java/org/jruby/truffle/nodes/conversion/ToSymbolNode.java
  4. +2 −2 truffle/src/main/java/org/jruby/truffle/nodes/core/EncodingNodes.java
  5. +3 −2 truffle/src/main/java/org/jruby/truffle/nodes/core/MatchDataNodes.java
  6. +1 −1 truffle/src/main/java/org/jruby/truffle/nodes/core/StringNodes.java
  7. +2 −2 truffle/src/main/java/org/jruby/truffle/nodes/core/SymbolNodes.java
  8. +1 −1 truffle/src/main/java/org/jruby/truffle/nodes/dispatch/CachedDispatchNode.java
  9. +3 −4 truffle/src/main/java/org/jruby/truffle/nodes/literal/StringLiteralNode.java
  10. +1 −1 truffle/src/main/java/org/jruby/truffle/nodes/rubinius/EncodingPrimitiveNodes.java
  11. +17 −15 truffle/src/main/java/org/jruby/truffle/nodes/rubinius/StringPrimitiveNodes.java
  12. +11 −0 truffle/src/main/java/org/jruby/truffle/runtime/RubyContext.java
  13. +108 −0 truffle/src/main/java/org/jruby/truffle/runtime/core/RopeTable.java
  14. +10 −14 truffle/src/main/java/org/jruby/truffle/runtime/core/SymbolCodeRangeableWrapper.java
  15. +20 −10 truffle/src/main/java/org/jruby/truffle/runtime/core/SymbolTable.java
  16. +3 −6 truffle/src/main/java/org/jruby/truffle/runtime/layouts/SymbolLayout.java
  17. +11 −20 truffle/src/main/java/org/jruby/truffle/runtime/rope/ConcatRope.java
  18. +5 −25 truffle/src/main/java/org/jruby/truffle/runtime/rope/LeafRope.java
  19. +32 −0 truffle/src/main/java/org/jruby/truffle/runtime/rope/Rope.java
  20. +62 −0 truffle/src/main/java/org/jruby/truffle/runtime/rope/RopeOperations.java
  21. +5 −0 truffle/src/main/java/org/jruby/truffle/runtime/rope/SubstringRope.java
3 changes: 2 additions & 1 deletion test/truffle/compiler/pe/core/string_pe.rb
Original file line number Diff line number Diff line change
@@ -17,9 +17,10 @@
example "'abc'.bytesize", 3
example "'こにちわ'.bytesize", 12

tagged_example "'abc' == 'abc'", true # seems to fail sometimes
example "'abc' == 'abc'", true
example "x = 'abc'; x == x", true
example "x = 'abc'; x == x.dup", true
example "x = 'abc'; 'abc' == x.dup", true

example "'abc'.ascii_only?", true
example "'こにちわ'.ascii_only?", false
4 changes: 4 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/nodes/RubyNode.java
Original file line number Diff line number Diff line change
@@ -157,6 +157,10 @@ public DynamicObject getSymbol(ByteList name) {
return getContext().getSymbol(name);
}

public DynamicObject getSymbol(Rope name) {
return getContext().getSymbol(name);
}

/** Creates a String from the ByteList, with unknown CR */
protected DynamicObject createString(ByteList bytes) {
return StringOperations.createString(getContext(), bytes);
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ protected DynamicObject toSymbolSymbol(DynamicObject symbol) {

@Specialization(guards = "isRubyString(string)")
protected DynamicObject toSymbolString(DynamicObject string) {
return getSymbol(StringOperations.getByteListReadOnly(string));
return getSymbol(StringOperations.rope(string));
}

@Specialization
Original file line number Diff line number Diff line change
@@ -192,7 +192,7 @@ public Object isCompatibleRegexpRegexp(DynamicObject first, DynamicObject second
@TruffleBoundary
@Specialization(guards = {"isRubyRegexp(first)", "isRubySymbol(second)"})
public Object isCompatibleRegexpSymbol(DynamicObject first, DynamicObject second) {
final Encoding compatibleEncoding = org.jruby.RubyEncoding.areCompatible(Layouts.REGEXP.getRegex(first).getEncoding(), Layouts.SYMBOL.getByteList(second).getEncoding());
final Encoding compatibleEncoding = org.jruby.RubyEncoding.areCompatible(Layouts.REGEXP.getRegex(first).getEncoding(), Layouts.SYMBOL.getRope(second).getEncoding());

if (compatibleEncoding != null) {
return getEncoding(compatibleEncoding);
@@ -204,7 +204,7 @@ public Object isCompatibleRegexpSymbol(DynamicObject first, DynamicObject second
@TruffleBoundary
@Specialization(guards = {"isRubySymbol(first)", "isRubyRegexp(second)"})
public Object isCompatibleSymbolRegexp(DynamicObject first, DynamicObject second) {
final Encoding compatibleEncoding = org.jruby.RubyEncoding.areCompatible(Layouts.SYMBOL.getByteList(first).getEncoding(), Layouts.REGEXP.getRegex(second).getEncoding());
final Encoding compatibleEncoding = org.jruby.RubyEncoding.areCompatible(Layouts.SYMBOL.getRope(first).getEncoding(), Layouts.REGEXP.getRegex(second).getEncoding());

if (compatibleEncoding != null) {
return getEncoding(compatibleEncoding);
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@
import org.jruby.truffle.runtime.core.ArrayOperations;
import org.jruby.truffle.runtime.core.StringOperations;
import org.jruby.truffle.runtime.layouts.Layouts;
import org.jruby.truffle.runtime.rope.Rope;
import org.jruby.util.ByteList;
import org.jruby.util.StringSupport;

@@ -197,8 +198,8 @@ public Object getIndex(DynamicObject matchData, int index, int length) {
@Specialization(guards = "isRubySymbol(index)")
public Object getIndexSymbol(DynamicObject matchData, DynamicObject index, NotProvided length) {
try {
ByteList value = Layouts.SYMBOL.getByteList(index);
final int i = Layouts.REGEXP.getRegex(Layouts.MATCH_DATA.getRegexp(matchData)).nameToBackrefNumber(value.getUnsafeBytes(), value.getBegin(), value.getBegin() + value.getRealSize(), Layouts.MATCH_DATA.getRegion(matchData));
final Rope value = Layouts.SYMBOL.getRope(index);
final int i = Layouts.REGEXP.getRegex(Layouts.MATCH_DATA.getRegexp(matchData)).nameToBackrefNumber(value.getBytes(), value.getBegin(), value.getBegin() + value.getRealSize(), Layouts.MATCH_DATA.getRegion(matchData));

return getIndex(matchData, i, NotProvided.INSTANCE);
} catch (final ValueException e) {
Original file line number Diff line number Diff line change
@@ -2073,7 +2073,7 @@ public ToSymNode(RubyContext context, SourceSection sourceSection) {

@Specialization
public DynamicObject toSym(DynamicObject string) {
return getSymbol(StringOperations.getByteListReadOnly(string));
return getSymbol(rope(string));
}
}

Original file line number Diff line number Diff line change
@@ -94,7 +94,7 @@ public EncodingNode(RubyContext context, SourceSection sourceSection) {

@Specialization
public DynamicObject encoding(DynamicObject symbol) {
return EncodingNodes.getEncoding(Layouts.SYMBOL.getByteList(symbol).getEncoding());
return EncodingNodes.getEncoding(Layouts.SYMBOL.getRope(symbol).getEncoding());
}

}
@@ -176,7 +176,7 @@ public ToSNode(RubyContext context, SourceSection sourceSection) {

@Specialization
public DynamicObject toS(DynamicObject symbol) {
return createString(Layouts.SYMBOL.getByteList(symbol).dup());
return createString(Layouts.SYMBOL.getRope(symbol));
}

}
Original file line number Diff line number Diff line change
@@ -44,7 +44,7 @@ public CachedDispatchNode(
if (RubyGuards.isRubySymbol(cachedName)) {
cachedNameAsSymbol = (DynamicObject) cachedName;
} else if (RubyGuards.isRubyString(cachedName)) {
cachedNameAsSymbol = context.getSymbol(StringOperations.getByteListReadOnly((DynamicObject) cachedName));
cachedNameAsSymbol = context.getSymbol(StringOperations.rope((DynamicObject) cachedName));
} else if (cachedName instanceof String) {
cachedNameAsSymbol = context.getSymbol((String) cachedName);
} else {
Original file line number Diff line number Diff line change
@@ -16,20 +16,19 @@
import org.jruby.truffle.nodes.objects.AllocateObjectNode;
import org.jruby.truffle.nodes.objects.AllocateObjectNodeGen;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.rope.LeafRope;
import org.jruby.truffle.runtime.rope.RopeOperations;
import org.jruby.truffle.runtime.rope.Rope;
import org.jruby.util.ByteList;

public class StringLiteralNode extends RubyNode {

private final LeafRope rope;
private final Rope rope;

@Child private AllocateObjectNode allocateObjectNode;

public StringLiteralNode(RubyContext context, SourceSection sourceSection, ByteList byteList, int codeRange) {
super(context, sourceSection);
assert byteList != null;
this.rope = RopeOperations.create(byteList.bytes(), byteList.getEncoding(), codeRange);
this.rope = context.getRopeTable().getRope(byteList.bytes(), byteList.getEncoding(), codeRange);
allocateObjectNode = AllocateObjectNodeGen.create(context, sourceSection, false, null, null);
}

Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ public DynamicObject encodingGetObjectEncodingString(DynamicObject string) {

@Specialization(guards = "isRubySymbol(symbol)")
public DynamicObject encodingGetObjectEncodingSymbol(DynamicObject symbol) {
return EncodingNodes.getEncoding(Layouts.SYMBOL.getByteList(symbol).getEncoding());
return EncodingNodes.getEncoding(Layouts.SYMBOL.getRope(symbol).getEncoding());
}

@Specialization(guards = "isRubyEncoding(encoding)")
Original file line number Diff line number Diff line change
@@ -247,11 +247,9 @@ public DynamicObject stringAwkSplit(DynamicObject string, int lim) {
private DynamicObject makeString(DynamicObject source, int index, int length) {
assert RubyGuards.isRubyString(source);

final ByteList bytes = new ByteList(StringOperations.getByteListReadOnly(source), index, length);
bytes.setEncoding(Layouts.STRING.getRope(source).getEncoding());
final Rope rope = RopeOperations.substring(rope(source), index, length);

// TODO (nirvdrum 08-Jan-16) We should be able to work out the code range from the parent string in some cases.
final DynamicObject ret = Layouts.STRING.createString(Layouts.CLASS.getInstanceFactory(Layouts.BASIC_OBJECT.getLogicalClass(source)), StringOperations.ropeFromByteList(bytes, StringSupport.CR_UNKNOWN), null);
final DynamicObject ret = Layouts.STRING.createString(Layouts.CLASS.getInstanceFactory(Layouts.BASIC_OBJECT.getLogicalClass(source)), rope, null);
taintResultNode.maybeTaint(source, ret);

return ret;
@@ -1225,9 +1223,10 @@ public Object stringRindex(DynamicObject string, DynamicObject pattern, int star
throw new RaiseException(getContext().getCoreLibrary().argumentError("negative start given", this));
}

final ByteList buf = StringOperations.getByteListReadOnly(string);
final int total = buf.getRealSize();
final int matchSize = Layouts.STRING.getRope(pattern).byteLength();
final Rope stringRope = rope(string);
final Rope patternRope = rope(pattern);
final int total = stringRope.byteLength();
final int matchSize = patternRope.byteLength();

if (pos >= total) {
pos = total - 1;
@@ -1239,10 +1238,10 @@ public Object stringRindex(DynamicObject string, DynamicObject pattern, int star
}

case 1: {
final int matcher = StringOperations.getByteListReadOnly(pattern).get(0);
final int matcher = patternRope.get(0);

while (pos >= 0) {
if (buf.get(pos) == matcher) {
if (stringRope.get(pos) == matcher) {
return pos;
}

@@ -1260,7 +1259,8 @@ public Object stringRindex(DynamicObject string, DynamicObject pattern, int star
int cur = pos;

while (cur >= 0) {
if (ByteList.memcmp(StringOperations.getByteListReadOnly(string).getUnsafeBytes(), cur, StringOperations.getByteListReadOnly(pattern).getUnsafeBytes(), 0, matchSize) == 0) {
// TODO (nirvdrum 21-Jan-16): Investigate a more rope efficient memcmp.
if (ByteList.memcmp(stringRope.getBytes(), cur, patternRope.getBytes(), 0, matchSize) == 0) {
return cur;
}

@@ -1299,16 +1299,18 @@ public DynamicObject stringPattern(DynamicObject stringClass, int size, int valu

@Specialization(guards = "isRubyString(string)")
public DynamicObject stringPattern(DynamicObject stringClass, int size, DynamicObject string) {
final Rope rope = rope(string);
final byte[] bytes = new byte[size];
final ByteList byteList = StringOperations.getByteListReadOnly(string);

if (byteList.length() > 0) {
for (int n = 0; n < size; n += byteList.length()) {
System.arraycopy(byteList.unsafeBytes(), byteList.begin(), bytes, n, Math.min(byteList.length(), size - n));
// TODO (nirvdrum 21-Jan-16): Investigate whether using a ConcatRope would be better here.
if (! rope.isEmpty()) {
for (int n = 0; n < size; n += rope.byteLength()) {
System.arraycopy(rope.getBytes(), rope.begin(), bytes, n, Math.min(rope.byteLength(), size - n));
}
}

return allocateObjectNode.allocate(stringClass, StringOperations.ropeFromByteList(new ByteList(bytes), StringSupport.CR_UNKNOWN), null);
// TODO (nirvdrum 21-Jan-16): Verify the encoding and code range are correct.
return allocateObjectNode.allocate(stringClass, RopeOperations.create(bytes, encoding(string), StringSupport.CR_UNKNOWN), null);
}

}
11 changes: 11 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/runtime/RubyContext.java
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.ArrayOperations;
import org.jruby.truffle.runtime.core.CoreLibrary;
import org.jruby.truffle.runtime.core.RopeTable;
import org.jruby.truffle.runtime.core.StringOperations;
import org.jruby.truffle.runtime.core.SymbolTable;
import org.jruby.truffle.runtime.ffi.LibCClockGetTime;
@@ -56,6 +57,7 @@
import org.jruby.truffle.runtime.methods.InternalMethod;
import org.jruby.truffle.runtime.object.ObjectIDOperations;
import org.jruby.truffle.runtime.platform.CrtExterns;
import org.jruby.truffle.runtime.rope.Rope;
import org.jruby.truffle.runtime.rubinius.RubiniusConfiguration;
import org.jruby.truffle.runtime.sockets.NativeSockets;
import org.jruby.truffle.runtime.subsystems.*;
@@ -96,6 +98,7 @@ public class RubyContext extends ExecutionContext {
private final ObjectSpaceManager objectSpaceManager;
private final ThreadManager threadManager;
private final AtExitManager atExitManager;
private final RopeTable ropeTable = new RopeTable();
private final SymbolTable symbolTable = new SymbolTable(this);
private final Warnings warnings;
private final SafepointManager safepointManager;
@@ -382,6 +385,10 @@ public void load(Source source, Node currentNode) {
parseAndExecute(source, UTF8Encoding.INSTANCE, ParserContext.TOP_LEVEL, coreLibrary.getMainObject(), null, true, DeclarationContext.TOP_LEVEL, currentNode);
}

public RopeTable getRopeTable() {
return ropeTable;
}

public SymbolTable getSymbolTable() {
return symbolTable;
}
@@ -394,6 +401,10 @@ public DynamicObject getSymbol(ByteList name) {
return symbolTable.getSymbol(name);
}

public DynamicObject getSymbol(Rope name) {
return symbolTable.getSymbol(name);
}

@TruffleBoundary
public Object instanceEval(ByteList code, Object self, String filename, Node currentNode) {
final Source source = Source.fromText(code, filename);
108 changes: 108 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/runtime/core/RopeTable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2013, 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.runtime.core;

import com.oracle.truffle.api.CompilerDirectives;
import org.jcodings.Encoding;
import org.jruby.truffle.runtime.rope.Rope;
import org.jruby.truffle.runtime.rope.RopeOperations;
import org.jruby.util.StringSupport;

import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.WeakHashMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class RopeTable {

private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final WeakHashMap<Key, WeakReference<Rope>> ropesTable = new WeakHashMap<>();

@CompilerDirectives.TruffleBoundary
public Rope getRope(byte[] bytes, Encoding encoding, int codeRange) {
final Key key = new Key(bytes, encoding);

lock.readLock().lock();

try {
final WeakReference<Rope> ropeReference = ropesTable.get(key);

if (ropeReference != null) {
final Rope rope = ropeReference.get();

if (rope != null) {
return rope;
}
}
} finally {
lock.readLock().unlock();
}

lock.writeLock().lock();

try {
final WeakReference<Rope> ropeReference = ropesTable.get(key);

if (ropeReference != null) {
final Rope rope = ropeReference.get();

if (rope != null) {
return rope;
}
}

final Rope rope = RopeOperations.create(bytes, encoding, codeRange);

ropesTable.put(key, new WeakReference<>(rope));

return rope;
} finally {
lock.writeLock().unlock();
}
}

public static class Key {

private final byte[] bytes;
private final Encoding encoding;
private int hashCode;

public Key(byte[] bytes, Encoding encoding) {
this.bytes = bytes;
this.encoding = encoding;
this.hashCode = Arrays.hashCode(bytes);
}

@Override
public int hashCode() {
return hashCode;
}

@Override
public boolean equals(Object o) {
if (o instanceof Key) {
final Key other = (Key) o;

return encoding == other.encoding && Arrays.equals(bytes, other.bytes);
}

return false;
}

@Override
public String toString() {
return RopeOperations.create(bytes, encoding, StringSupport.CR_UNKNOWN).toString();
}

}

}
Loading