Skip to content

Commit

Permalink
Merge pull request #4161 from jruby/truffle-encoding-replicate
Browse files Browse the repository at this point in the history
[Truffle] Encoding#replicate
  • Loading branch information
bjfish committed Sep 19, 2016
2 parents 93a79fc + a8367e1 commit cd5efd5
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 19 deletions.
4 changes: 0 additions & 4 deletions spec/truffle/tags/core/encoding/replicate_tags.txt

This file was deleted.

Expand Up @@ -29,14 +29,16 @@
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public class EncodingManager {

private final DynamicObject[] ENCODING_LIST_BY_ENCODING_LIST_INDEX = new DynamicObject[EncodingDB.getEncodings().size()];
private final DynamicObject[] ENCODING_LIST_BY_ENCODING_INDEX = new DynamicObject[EncodingDB.getEncodings().size()];
private final List<DynamicObject> ENCODING_LIST_BY_ENCODING_LIST_INDEX = new ArrayList<DynamicObject>(EncodingDB.getEncodings().size());
private final Map<Integer, DynamicObject> ENCODING_LIST_BY_ENCODING_INDEX = new HashMap<Integer,DynamicObject>(EncodingDB.getEncodings().size());
private final Map<String, DynamicObject> LOOKUP = new HashMap<>();

private final RubyContext context;
Expand All @@ -55,19 +57,20 @@ public static DynamicObject newRubyEncoding(RubyContext context, Encoding encodi
return Layouts.ENCODING.createEncoding(context.getCoreLibrary().getEncodingFactory(), encoding, string, dummy);
}

public DynamicObject[] getUnsafeEncodingList() {
public List<DynamicObject> getUnsafeEncodingList() {
return ENCODING_LIST_BY_ENCODING_LIST_INDEX;
}

@TruffleBoundary
public DynamicObject getRubyEncoding(Encoding encoding) {
DynamicObject rubyEncoding = ENCODING_LIST_BY_ENCODING_INDEX[encoding.getIndex()];
DynamicObject rubyEncoding = ENCODING_LIST_BY_ENCODING_INDEX.get(encoding.getIndex());

if (rubyEncoding == null) {
// Bounded by the number of encodings
CompilerDirectives.transferToInterpreterAndInvalidate();

rubyEncoding = LOOKUP.get(new String(encoding.getName(), StandardCharsets.UTF_8).toLowerCase(Locale.ENGLISH));
ENCODING_LIST_BY_ENCODING_INDEX[encoding.getIndex()] = rubyEncoding;
ENCODING_LIST_BY_ENCODING_INDEX.put(encoding.getIndex(),rubyEncoding);
}

return rubyEncoding;
Expand All @@ -80,14 +83,15 @@ public DynamicObject getRubyEncoding(String name) {

@TruffleBoundary
public DynamicObject getRubyEncoding(int encodingListIndex) {
return ENCODING_LIST_BY_ENCODING_LIST_INDEX[encodingListIndex];
return ENCODING_LIST_BY_ENCODING_LIST_INDEX.get(encodingListIndex);
}

@TruffleBoundary
public void defineEncoding(EncodingDB.Entry encodingEntry, byte[] name, int p, int end) {
final DynamicObject rubyEncoding = newRubyEncoding(context, null, name, p, end, encodingEntry.isDummy());

ENCODING_LIST_BY_ENCODING_LIST_INDEX[encodingEntry.getIndex()] = rubyEncoding;
assert ENCODING_LIST_BY_ENCODING_LIST_INDEX.size() == encodingEntry.getIndex();
ENCODING_LIST_BY_ENCODING_LIST_INDEX.add(encodingEntry.getIndex(), rubyEncoding);
LOOKUP.put(Layouts.ENCODING.getName(rubyEncoding).toString().toLowerCase(Locale.ENGLISH), rubyEncoding);
}

Expand Down
Expand Up @@ -44,12 +44,18 @@
import org.jruby.truffle.core.cast.ToStrNodeGen;
import org.jruby.truffle.core.rope.CodeRange;
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.core.rope.RopeOperations;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.SnippetNode;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.util.ByteList;

import java.util.Collection;
import java.util.List;
import java.util.Locale;

@CoreClass("Encoding")
public abstract class EncodingNodes {

Expand Down Expand Up @@ -409,10 +415,10 @@ public abstract static class ListNode extends CoreMethodArrayArgumentsNode {
@TruffleBoundary
@Specialization
public DynamicObject list() {
final DynamicObject[] encodings = getContext().getEncodingManager().getUnsafeEncodingList();
final Object[] arrayStore = new Object[encodings.length];
final List<DynamicObject> encodingsList = getContext().getEncodingManager().getUnsafeEncodingList();

System.arraycopy(encodings, 0, arrayStore, 0, encodings.length);
final Object[] arrayStore = new Object[encodingsList.size()];
getContext().getEncodingManager().getUnsafeEncodingList().toArray(arrayStore);

return createArray(arrayStore, arrayStore.length);
}
Expand Down Expand Up @@ -554,6 +560,37 @@ public DynamicObject encodingGetObjectEncodingNil(DynamicObject object) {

}

@Primitive(name = "encoding_replicate")
public static abstract class EncodingReplicateNode extends PrimitiveArrayArgumentsNode {

@Specialization(guards = "isRubyString(name)")
public DynamicObject encodingReplicate(VirtualFrame frame, DynamicObject self, DynamicObject name, @Cached("new()") SnippetNode snippetNode) {
final String nameString = StringOperations.getString(name);
final DynamicObject existing = getContext().getEncodingManager().getRubyEncoding(nameString);
if (existing != null) {
throw new RaiseException(coreExceptions().argumentErrorEncodingAlreadyRegistered(nameString, this));
}
final Encoding base = EncodingOperations.getEncoding(self);
EncodingDB.replicate(nameString, new String(base.getName()));
final Entry entry = EncodingDB.getEncodings().get(nameString.getBytes());
getContext().getEncodingManager().defineEncoding(entry, nameString.getBytes(), 0, nameString.getBytes().length);
final DynamicObject newEncoding = getContext().getEncodingManager().getRubyEncoding(nameString.toLowerCase(Locale.ENGLISH));
snippetNode.execute(frame, "Encoding::EncodingMap[enc.name.upcase.to_sym] = [nil, index]", "enc", newEncoding, "index", entry.getIndex());
return newEncoding;
}

}

@Primitive(name = "encoding_get_encoding_by_index", needsSelf = false)
public static abstract class EncodingGetObjectEncodingByIndexNode extends PrimitiveArrayArgumentsNode {

@Specialization
public DynamicObject encodingGetObjectEncodingByIndex(int index) {
return getContext().getEncodingManager().getRubyEncoding(index);
}

}

@NodeChildren({ @NodeChild("first"), @NodeChild("second") })
public static abstract class CheckEncodingNode extends RubyNode {

Expand Down
Expand Up @@ -128,6 +128,11 @@ public DynamicObject argumentErrorNoReceiver(Node currentNode) {
return argumentError("no receiver is available", currentNode);
}

@TruffleBoundary
public DynamicObject argumentErrorEncodingAlreadyRegistered(String nameString, Node currentNode) {
return argumentError(StringUtils.format("encoding %s is already registered", nameString), currentNode);
}

@TruffleBoundary
public DynamicObject argumentError(String message, Node currentNode, Throwable javaThrowable) {
return argumentError(StringOperations.encodeRope(message, UTF8Encoding.INSTANCE), currentNode, javaThrowable);
Expand Down
11 changes: 7 additions & 4 deletions truffle/src/main/ruby/core/encoding.rb
Expand Up @@ -57,7 +57,7 @@ def self.create(source, target)
class << self
def build_encoding_map
map = Rubinius::LookupTable.new
EncodingList.each_with_index { |encoding, index|
Encoding.list.each_with_index { |encoding, index|
key = encoding.name.upcase.to_sym
map[key] = [nil, index]
}
Expand All @@ -79,7 +79,6 @@ def build_encoding_map
end

TranscodingMap = Encoding::Converter.transcoding_map
EncodingList = Encoding.list.freeze
EncodingMap = build_encoding_map

@default_external = undefined
Expand Down Expand Up @@ -549,7 +548,7 @@ def self.aliases
next unless index

aname = r.first
aliases[aname] = EncodingList[index].name if aname
aliases[aname] = Truffle.invoke_primitive(:encoding_get_encoding_by_index, index).name if aname
end

aliases
Expand Down Expand Up @@ -613,7 +612,7 @@ def self.find(name)
def self.name_list
EncodingMap.map do |n, r|
index = r.last
r.first or (index and EncodingList[index].name)
r.first or (index and Truffle.invoke_primitive(:encoding_get_encoding_by_index, index).name)
end
end

Expand All @@ -631,6 +630,10 @@ def names
names
end

def replicate(name)
Truffle.invoke_primitive(:encoding_replicate, self, StringValue(name))
end

def _dump(depth)
name
end
Expand Down
2 changes: 1 addition & 1 deletion truffle/src/main/ruby/core/type.rb
Expand Up @@ -462,7 +462,7 @@ def self.try_convert_to_encoding(obj)
pair = Encoding::EncodingMap[key]
if pair
index = pair.last
return index && Encoding::EncodingList[index]
return index && Truffle.invoke_primitive(:encoding_get_encoding_by_index, index)
end

return undefined
Expand Down

0 comments on commit cd5efd5

Please sign in to comment.