Skip to content

Commit

Permalink
Showing 2 changed files with 48 additions and 1 deletion.
47 changes: 47 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/core/rope/RopeTable.java
Original file line number Diff line number Diff line change
@@ -12,8 +12,11 @@

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import org.jcodings.Encoding;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.util.StringSupport;

import java.lang.ref.WeakReference;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
@@ -25,13 +28,57 @@
public class RopeTable {

private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final WeakHashMap<String, Key> stringsTable = new WeakHashMap<>();
private final WeakHashMap<Key, WeakReference<Rope>> ropesTable = new WeakHashMap<>();
private final Set<Key> keys = new HashSet<>();

private int byteArrayReusedCount;
private int ropesReusedCount;
private int ropeBytesSaved;

@TruffleBoundary
public Rope getRope(String string) {
lock.readLock().lock();

try {
final Key key = stringsTable.get(string);

if (key != null) {
final WeakReference<Rope> ropeReference = ropesTable.get(key);

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

lock.writeLock().lock();

try {
Key key = stringsTable.get(string);

if (key == null) {
key = new Key(string.getBytes(StandardCharsets.UTF_8), UTF8Encoding.INSTANCE);
stringsTable.put(string, key);
}

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

if (ropeReference == null) {
final long packedLengthAndCodeRange = RopeOperations.calculateCodeRangeAndLength(key.encoding, key.bytes, 0, key.bytes.length);
final CodeRange codeRange = CodeRange.fromInt(StringSupport.unpackArg(packedLengthAndCodeRange));
ropeReference = new WeakReference<Rope>(RopeOperations.create(key.bytes, key.encoding, codeRange));
ropesTable.put(key, ropeReference);
}

return ropeReference.get();
} finally {
lock.writeLock().unlock();
}
}

@TruffleBoundary
public Rope getRope(byte[] bytes, Encoding encoding, CodeRange codeRange) {
final Key key = new Key(bytes, encoding);
Original file line number Diff line number Diff line change
@@ -55,7 +55,7 @@ public DynamicObject absolutePath(DynamicObject threadBacktraceLocation) {
if (path == null) {
return coreStrings().UNKNOWN.createInstance();
} else {
return createString(StringOperations.encodeRope(path, UTF8Encoding.INSTANCE));
return createString(getContext().getRopeTable().getRope(path));
}
}

2 comments on commit 7e7f844

@chrisseaton
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nirvdrum I'm using this for where we have a Java string come in from something like a source section, and it makes sense to cache it - think about examining a backtrace where most of the lines are the same long paths.

@nirvdrum
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine. I was a bit lazy originally and didn't enforce only LeafRopes being in the table. This change really shouldn't affect that -- I'd expect the conversion to produce a LeafRope. But if we're going to expand usage we'll want to make sure that we're not caching massive ropes I think.

Sorry, something went wrong.

Please sign in to comment.