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

Commits on Nov 5, 2014

  1. Copy the full SHA
    c73b5fe View commit details
  2. Copy the full SHA
    bffdb0a View commit details
  3. Copy the full SHA
    cf46856 View commit details
  4. Copy the full SHA
    624823a View commit details
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/RubyEncoding.java
Original file line number Diff line number Diff line change
@@ -61,6 +61,8 @@ public class RubyEncoding extends RubyObject implements Constantizable {
public static final Charset ISO = Charset.forName("ISO-8859-1");
public static final ByteList LOCALE = ByteList.create("locale");
public static final ByteList EXTERNAL = ByteList.create("external");
public static final ByteList FILESYSTEM = ByteList.create("filesystem");
public static final ByteList INTERNAL = ByteList.create("internal");

public static RubyClass createEncodingClass(Ruby runtime) {
RubyClass encodingc = runtime.defineClass("Encoding", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
Original file line number Diff line number Diff line change
@@ -95,6 +95,7 @@ public void init() {
CoreMethodNodeManager.addCoreMethodNodes(rubyObjectClass, TrueClassNodesFactory.getFactories());
CoreMethodNodeManager.addCoreMethodNodes(rubyObjectClass, TruffleDebugNodesFactory.getFactories());
CoreMethodNodeManager.addCoreMethodNodes(rubyObjectClass, EncodingNodesFactory.getFactories());
CoreMethodNodeManager.addCoreMethodNodes(rubyObjectClass, EncodingConverterNodesFactory.getFactories());

// Give the core library manager a chance to tweak some of those methods

4 changes: 4 additions & 0 deletions core/src/main/java/org/jruby/truffle/nodes/RubyNode.java
Original file line number Diff line number Diff line change
@@ -194,6 +194,10 @@ public RubiniusChannel executeRubiniusChannel(VirtualFrame frame) throws Unexpec
return RubyTypesGen.RUBYTYPES.expectRubiniusChannel(execute(frame));
}

public RubyEncodingConverter executeRubyEncodingConverter(VirtualFrame frame) throws UnexpectedResultException {
return RubyTypesGen.RUBYTYPES.expectRubyEncodingConverter(execute(frame));
}

public Dispatch.DispatchAction executeDispatchAction(VirtualFrame frame) {
throw new UnsupportedOperationException();
}
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/truffle/nodes/RubyTypes.java
Original file line number Diff line number Diff line change
@@ -68,6 +68,7 @@
RubyFalseClass.class, //
RubiniusChannel.class, //
RubiniusByteArray.class, //
RubyEncodingConverter.class, //
RubyObject.class, //
RubyBasicObject.class, //
Object[].class})
64 changes: 64 additions & 0 deletions core/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java
Original file line number Diff line number Diff line change
@@ -40,8 +40,10 @@
import org.jruby.truffle.runtime.util.ArrayUtils;
import org.jruby.util.Memo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

@CoreClass(name = "Array")
public abstract class ArrayNodes {
@@ -2482,6 +2484,68 @@ public RubyString pack(RubyArray array, RubyString format) {

}

@CoreMethod(names = "permutation", required = 1)
public abstract static class PermutationNode extends ArrayCoreMethodNode {

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

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

@Specialization
public RubyArray permutation(RubyArray array, int n) {
notDesignedForCompilation();

final List<RubyArray> permutations = new ArrayList<>();
permutationCommon(n, false, array.slowToArray(), permutations);
return new RubyArray(getContext().getCoreLibrary().getArrayClass(), permutations.toArray(), permutations.size());
}

// Apdapted from JRuby's RubyArray - see attribution there

private void permutationCommon(int r, boolean repeat, Object[] values, List<RubyArray> permutations) {
if (r == 0) {
permutations.add(new RubyArray(getContext().getCoreLibrary().getArrayClass(), null, 0));
} else if (r == 1) {
for (int i = 0; i < values.length; i++) {
permutations.add(new RubyArray(getContext().getCoreLibrary().getArrayClass(), values[i], 1));
}
} else if (r >= 0) {
int n = values.length;
permute(n, r,
new int[r], 0,
new boolean[n],
repeat,
values, permutations);
}
}

private void permute(int n, int r, int[]p, int index, boolean[]used, boolean repeat, Object[] values, List<RubyArray> permutations) {
for (int i = 0; i < n; i++) {
if (repeat || !used[i]) {
p[index] = i;
if (index < r - 1) {
used[i] = true;
permute(n, r, p, index + 1, used, repeat, values, permutations);
used[i] = false;
} else {
Object[] result = new Object[r];

for (int j = 0; j < r; j++) {
result[j] = values[p[j]];
}

permutations.add(new RubyArray(getContext().getCoreLibrary().getArrayClass(), result, r));
}
}
}
}

}

@CoreMethod(names = "pop")
public abstract static class PopNode extends ArrayCoreMethodNode {

Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* 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.Specialization;
import com.oracle.truffle.api.source.SourceSection;
import org.jcodings.Encoding;
import org.jcodings.EncodingDB;
import org.jcodings.specific.UTF8Encoding;
import org.jcodings.transcode.EConv;
import org.jcodings.transcode.Transcoder;
import org.jcodings.transcode.TranscoderDB;
import org.jcodings.util.CaseInsensitiveBytesHash;
import org.jcodings.util.Hash;
import org.jruby.Ruby;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.encoding.EncodingService;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.*;
import org.jruby.util.ByteList;
import org.jruby.util.io.EncodingUtils;

@CoreClass(name = "Encoding::Converter")
public abstract class EncodingConverterNodes {

@CoreMethod(names = "convpath")
public abstract static class ConvPathNode extends CoreMethodNode {

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

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

@Specialization
public RubyArray convpath(RubyEncodingConverter converter) {
notDesignedForCompilation();

// Adapated from RubyConverter - see attribution there

Ruby runtime = getContext().getRuntime();

EConv ec = converter.getEConv();

Object[] result = new Object[ec.numTranscoders];
int r = 0;

for (int i = 0; i < ec.numTranscoders; i++) {
Transcoder tr = ec.elements[i].transcoding.transcoder;
Object v;
if (EncodingUtils.DECORATOR_P(tr.getSource(), tr.getDestination())) {
v = new RubyString(getContext().getCoreLibrary().getStringClass(), new ByteList(tr.getDestination()));
} else {
Encoding source = runtime.getEncodingService().findEncodingOrAliasEntry(tr.getSource()).getEncoding();
Encoding destination = runtime.getEncodingService().findEncodingOrAliasEntry(tr.getDestination()).getEncoding();

v = new RubyArray(getContext().getCoreLibrary().getArrayClass(),
new Object[]{
RubyEncoding.getEncoding(getContext(), source),
RubyEncoding.getEncoding(getContext(), destination)
}, 2);
}
result[r++] = v;
}

return new RubyArray(getContext().getCoreLibrary().getArrayClass(), result, result.length);
}

}

@CoreMethod(names = "initialize", required = 2)
public abstract static class InitializeNode extends CoreMethodNode {

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

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

@Specialization
public RubyNilClass initialize(RubyEncodingConverter self, RubyString source, RubyString destination) {
notDesignedForCompilation();

// Adapted from RubyConverter - see attribution there

Ruby runtime = getContext().getRuntime();
Encoding[] encs = {null, null};
byte[][] encNames = {null, null};
int[] ecflags = {0};
IRubyObject[] ecopts = {runtime.getNil()};

EncodingUtils.econvArgs(runtime.getCurrentContext(), new IRubyObject[]{getContext().toJRuby(source), getContext().toJRuby(destination)}, encNames, encs, ecflags, ecopts);
EConv econv = EncodingUtils.econvOpenOpts(runtime.getCurrentContext(), encNames[0], encNames[1], ecflags[0], ecopts[0]);

if (econv == null) {
throw new UnsupportedOperationException();
}

self.setEConv(econv);

return getContext().getCoreLibrary().getNilObject();
}

}

@CoreMethod(names = "search_convpath", isModuleFunction = true, needsSelf = false, required = 2)
public abstract static class SearchConvPathNode extends CoreMethodNode {

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

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

@Specialization
public RubyArray searchConvpath(RubyString source, RubyString destination) {
notDesignedForCompilation();

// Adapted from RubyConverter - see attribution there

final Ruby runtime = getContext().getRuntime();
final RubyNilClass nil = getContext().getCoreLibrary().getNilObject();
ThreadContext context = runtime.getCurrentContext();
final byte[][] encNames = {null, null};
final Encoding[] encs = {null, null};
final int[] ecflags_p = {0};
final IRubyObject[] ecopts_p = {context.nil};
final Object[] convpath = {getContext().getCoreLibrary().getNilObject()};

EncodingUtils.econvArgs(context, new IRubyObject[]{getContext().toJRuby(source), getContext().toJRuby(destination)}, encNames, encs, ecflags_p, ecopts_p);

TranscoderDB.searchPath(encNames[0], encNames[1], new TranscoderDB.SearchPathCallback() {
EncodingService es = runtime.getEncodingService();

public void call(byte[] source, byte[] destination, int depth) {
Object v;

if (convpath[0] == nil) {
convpath[0] = new RubyArray(getContext().getCoreLibrary().getArrayClass(), null, 0);
}

if (EncodingUtils.DECORATOR_P(encNames[0], encNames[1])) {
v = new RubyString(getContext().getCoreLibrary().getStringClass(), new ByteList(encNames[2]));
} else {
Encoding sourceEncoding = runtime.getEncodingService().findEncodingOrAliasEntry(source).getEncoding();
Encoding destinationEncoding = runtime.getEncodingService().findEncodingOrAliasEntry(destination).getEncoding();

v = new RubyArray(getContext().getCoreLibrary().getArrayClass(),
new Object[]{
RubyEncoding.getEncoding(getContext(), destinationEncoding),
RubyEncoding.getEncoding(getContext(), sourceEncoding)
}, 2);
}

((RubyArray) convpath[0]).slowPush(v); // depth?
}
});

if (convpath[0] == nil) {
throw new UnsupportedOperationException();
}

//if (EncodingUtils.decorateConvpath(context, convpath[0], ecflags_p[0]) == -1) {
// throw EncodingUtils.econvOpenExc(context, encNames[0], encNames[1], ecflags_p[0]);
//}

return (RubyArray) convpath[0];
}

}

}
92 changes: 59 additions & 33 deletions core/src/main/java/org/jruby/truffle/nodes/core/EncodingNodes.java
Original file line number Diff line number Diff line change
@@ -12,43 +12,21 @@
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.dsl.Specialization;
import org.jcodings.Encoding;
import org.jcodings.EncodingDB;
import org.jcodings.specific.UTF8Encoding;
import org.jcodings.transcode.TranscoderDB;
import org.jcodings.util.CaseInsensitiveBytesHash;
import org.jcodings.util.Hash;
import org.jruby.runtime.encoding.EncodingService;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyEncoding;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.util.ByteList;

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

// TODO(cs): this should not exist, Encoding instances should be unique.
@CoreMethod(names = "==", required = 1)
public abstract static class EqualNode extends CoreMethodNode {

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

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

@Specialization
public boolean equal(@SuppressWarnings("unused") RubyString a, @SuppressWarnings("unused") RubyNilClass b) {
notDesignedForCompilation();

return false;
}

@Specialization
public boolean equal(RubyEncoding a, RubyEncoding b) {
notDesignedForCompilation();

return a.compareTo(b);
}

}

@CoreMethod(names = "default_external", onSingleton = true)
public abstract static class DefaultExternalNode extends CoreMethodNode {

@@ -70,7 +48,7 @@ public RubyEncoding defaultExternal() {
encoding = UTF8Encoding.INSTANCE;
}

return new RubyEncoding(getContext().getCoreLibrary().getEncodingClass(), encoding);
return RubyEncoding.getEncoding(getContext(), encoding);
}

}
@@ -96,7 +74,7 @@ public RubyEncoding defaultInternal() {
encoding = UTF8Encoding.INSTANCE;
}

return new RubyEncoding(getContext().getCoreLibrary().getEncodingClass(), encoding);
return RubyEncoding.getEncoding(getContext(), encoding);
}

}
@@ -113,14 +91,62 @@ public FindNode(FindNode prev) {
}

@Specialization
public Object find(RubyString name) {
public RubyEncoding find(RubyString name) {
notDesignedForCompilation();

// TODO(CS): isn't this a JRuby object?
return RubyEncoding.getEncoding(getContext(), name.toString());
}

}

return RubyEncoding.findEncodingByName(name);
@CoreMethod(names = "name_list", onSingleton = true)
public abstract static class NameListNode extends CoreMethodNode {

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

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

@Specialization
public RubyArray find() {
notDesignedForCompilation();

final EncodingService service = getContext().getRuntime().getEncodingService();

final Object[] array = new Object[service.getEncodings().size() + service.getAliases().size() + 2];
int n = 0;

Hash.HashEntryIterator i;

i = service.getEncodings().entryIterator();

while (i.hasNext()) {
CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<EncodingDB.Entry> e =
((CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<EncodingDB.Entry>)i.next());
array[n++] = new RubyString(getContext().getCoreLibrary().getStringClass(), new ByteList(e.bytes, e.p, e.end - e.p));
}

i = service.getAliases().entryIterator();

while (i.hasNext()) {
CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<EncodingDB.Entry> e =
((CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<EncodingDB.Entry>)i.next());
array[n++] = new RubyString(getContext().getCoreLibrary().getStringClass(), new ByteList(e.bytes, e.p, e.end - e.p));
}

array[n++] = new RubyString(getContext().getCoreLibrary().getStringClass(), org.jruby.RubyEncoding.EXTERNAL);
//array[n++] = new RubyString(getContext().getCoreLibrary().getStringClass(), org.jruby.RubyEncoding.INTERNAL);
array[n++] = new RubyString(getContext().getCoreLibrary().getStringClass(), org.jruby.RubyEncoding.LOCALE);
//array[n++] = new RubyString(getContext().getCoreLibrary().getStringClass(), org.jruby.RubyEncoding.FILESYSTEM);

return new RubyArray(getContext().getCoreLibrary().getArrayClass(), array, array.length);
}

}



}
62 changes: 39 additions & 23 deletions core/src/main/java/org/jruby/truffle/nodes/core/HashNodes.java
Original file line number Diff line number Diff line change
@@ -158,7 +158,7 @@ public RubyHash construct(Object[] args) {
}
}

return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, newStore, size);
return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, newStore, size);
} else {
largeObjectArray.enter();
throw new UnsupportedOperationException();
@@ -186,7 +186,7 @@ public RubyHash constructObjectLinkedMapMap(Object[] args) {
store.put(args[n], args[n + 1]);
}

return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, store, 0);
return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, store, 0);
}

}
@@ -216,10 +216,12 @@ public GetIndexNode(GetIndexNode prev) {
public Object getNull(VirtualFrame frame, RubyHash hash, Object key) {
notDesignedForCompilation();

if (hash.getDefaultBlock() == null) {
return getContext().getCoreLibrary().getNilObject();
} else {
if (hash.getDefaultBlock() != null) {
return yield.dispatch(frame, hash.getDefaultBlock(), hash, key);
} else if (hash.getDefaultValue() != null) {
return hash.getDefaultValue();
} else {
return getContext().getCoreLibrary().getNilObject();
}
}

@@ -237,13 +239,17 @@ public Object getObjectArray(VirtualFrame frame, RubyHash hash, Object key) {

notInHashProfile.enter();

if (hash.getDefaultBlock() == null) {
return getContext().getCoreLibrary().getNilObject();
if (hash.getDefaultBlock() != null) {
useDefaultProfile.enter();
return yield.dispatch(frame, hash.getDefaultBlock(), hash, key);
}

useDefaultProfile.enter();
if (hash.getDefaultValue() != null) {
return hash.getDefaultValue();
}

return getContext().getCoreLibrary().getNilObject();

return yield.dispatch(frame, hash.getDefaultBlock(), hash, key);
}

@Specialization(guards = "isObjectLinkedHashMap")
@@ -257,10 +263,12 @@ public Object getObjectLinkedHashMap(VirtualFrame frame, RubyHash hash, Object k
final Object value = store.get(key);

if (value == null) {
if (hash.getDefaultBlock() == null) {
return getContext().getCoreLibrary().getNilObject();
} else {
if (hash.getDefaultBlock() != null) {
return yield.dispatch(frame, hash.getDefaultBlock(), hash, key);
} else if (hash.getDefaultValue() != null) {
return hash.getDefaultValue();
} else {
return getContext().getCoreLibrary().getNilObject();
}
}

@@ -440,7 +448,7 @@ public DupNode(DupNode prev) {
public RubyHash dupNull(RubyHash hash) {
notDesignedForCompilation();

return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, 0);
return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, null, 0);
}

@Specialization(guards = "isObjectArray")
@@ -450,7 +458,7 @@ public RubyHash dupObjectArray(RubyHash hash) {
final Object[] store = (Object[]) hash.getStore();
final Object[] copy = Arrays.copyOf(store, RubyHash.HASHES_SMALL * 2);

return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, copy, hash.getStoreSize());
return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, copy, hash.getStoreSize());
}

@Specialization(guards = "isObjectLinkedHashMap")
@@ -460,7 +468,7 @@ public RubyHash dupObjectLinkedHashMap(RubyHash hash) {
final LinkedHashMap<Object, Object> store = (LinkedHashMap<Object, Object>) hash.getStore();
final LinkedHashMap<Object, Object> copy = new LinkedHashMap<>(store);

return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, copy, 0);
return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, copy, 0);
}

}
@@ -602,7 +610,7 @@ public RubyArray toArray(RubyHash hash) {

}

@CoreMethod(names = "initialize", needsBlock = true)
@CoreMethod(names = "initialize", needsBlock = true, optional = 1)
public abstract static class InitializeNode extends HashCoreMethodNode {

public InitializeNode(RubyContext context, SourceSection sourceSection) {
@@ -614,21 +622,28 @@ public InitializeNode(InitializeNode prev) {
}

@Specialization
public RubyNilClass initialize(RubyHash hash, @SuppressWarnings("unused") UndefinedPlaceholder block) {
public RubyNilClass initialize(RubyHash hash, UndefinedPlaceholder defaultValue, UndefinedPlaceholder block) {
notDesignedForCompilation();
hash.setStore(null, 0);
hash.setDefaultBlock(null);
return getContext().getCoreLibrary().getNilObject();
}

@Specialization
public RubyNilClass initialize(RubyHash hash, RubyProc block) {
public RubyNilClass initialize(RubyHash hash, UndefinedPlaceholder defaultValue, RubyProc block) {
notDesignedForCompilation();
hash.setStore(null, 0);
hash.setDefaultBlock(block);
return getContext().getCoreLibrary().getNilObject();
}

@Specialization
public RubyNilClass initialize(RubyHash hash, Object defaultValue, UndefinedPlaceholder block) {
notDesignedForCompilation();
hash.setDefaultValue(defaultValue);
return getContext().getCoreLibrary().getNilObject();
}

}

@CoreMethod(names = {"inspect", "to_s"})
@@ -811,7 +826,7 @@ public RubyHash mergeObjectArrayNull(RubyHash hash, RubyHash other) {
final Object[] store = (Object[]) hash.getStore();
final Object[] copy = Arrays.copyOf(store, RubyHash.HASHES_SMALL * 2);

return new RubyHash(getContext().getCoreLibrary().getHashClass(), hash.getDefaultBlock(), copy, hash.getStoreSize());
return new RubyHash(getContext().getCoreLibrary().getHashClass(), hash.getDefaultBlock(), hash.getDefaultValue(), copy, hash.getStoreSize());
}

@ExplodeLoop
@@ -851,14 +866,14 @@ public RubyHash mergeObjectArrayObjectArray(VirtualFrame frame, RubyHash hash, R

if (mergeFromACount == 0) {
nothingFromFirstProfile.enter();
return new RubyHash(getContext().getCoreLibrary().getHashClass(), hash.getDefaultBlock(), Arrays.copyOf(storeB, RubyHash.HASHES_SMALL * 2), storeBSize);
return new RubyHash(getContext().getCoreLibrary().getHashClass(), hash.getDefaultBlock(), hash.getDefaultValue(), Arrays.copyOf(storeB, RubyHash.HASHES_SMALL * 2), storeBSize);
}

considerNothingFromSecondProfile.enter();

if (mergeFromACount == storeB.length) {
nothingFromSecondProfile.enter();
return new RubyHash(getContext().getCoreLibrary().getHashClass(), hash.getDefaultBlock(), Arrays.copyOf(storeB, RubyHash.HASHES_SMALL * 2), storeBSize);
return new RubyHash(getContext().getCoreLibrary().getHashClass(), hash.getDefaultBlock(), hash.getDefaultValue(), Arrays.copyOf(storeB, RubyHash.HASHES_SMALL * 2), storeBSize);
}

considerResultIsSmallProfile.enter();
@@ -886,7 +901,7 @@ public RubyHash mergeObjectArrayObjectArray(VirtualFrame frame, RubyHash hash, R
index += 2;
}

return new RubyHash(getContext().getCoreLibrary().getHashClass(), hash.getDefaultBlock(), merged, mergedSize);
return new RubyHash(getContext().getCoreLibrary().getHashClass(), hash.getDefaultBlock(), hash.getDefaultValue(), merged, mergedSize);
}

CompilerDirectives.transferToInterpreter();
@@ -919,10 +934,11 @@ public boolean keyNull(RubyHash hash, Object key) {
public boolean keyObjectArray(VirtualFrame frame, RubyHash hash, Object key) {
notDesignedForCompilation();

final int size = hash.getStoreSize();
final Object[] store = (Object[]) hash.getStore();

for (int n = 0; n < store.length; n += 2) {
if (eqlNode.callIsTruthy(frame, store[n], "eql?", null, key)) {
if (n < size && eqlNode.callIsTruthy(frame, store[n], "eql?", null, key)) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -411,7 +411,7 @@ public EncodingNode(EncodingNode prev) {
public RubyEncoding encoding(RubyString string) {
notDesignedForCompilation();

return new RubyEncoding(getContext().getCoreLibrary().getEncodingClass(), string.getBytes().getEncoding());
return RubyEncoding.getEncoding(getContext(), string.getBytes().getEncoding());
}
}

@@ -449,8 +449,8 @@ public ForceEncodingNode(ForceEncodingNode prev) {
public RubyString forceEncoding(RubyString string, RubyString encodingName) {
notDesignedForCompilation();

RubyEncoding encoding = RubyEncoding.findEncodingByName(encodingName);
string.forceEncoding(encoding.getRubyEncoding().getEncoding());
RubyEncoding encoding = RubyEncoding.getEncoding(getContext(), encodingName.toString());
string.forceEncoding(encoding.getEncoding());

return string;
}
Original file line number Diff line number Diff line change
@@ -68,7 +68,7 @@ public EmptyHashLiteralNode(RubyContext context, SourceSection sourceSection) {
@ExplodeLoop
@Override
public RubyHash executeRubyHash(VirtualFrame frame) {
return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, 0);
return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, null, 0);
}

}
@@ -110,7 +110,7 @@ public RubyHash executeRubyHash(VirtualFrame frame) {
position += 2;
}

return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, storage, position / 2);
return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, storage, position / 2);
}

}
@@ -143,7 +143,7 @@ public RubyHash executeRubyHash(VirtualFrame frame) {
storage.put(key, value);
}

return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, storage, 0);
return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, storage, 0);
}

}
Original file line number Diff line number Diff line change
@@ -119,7 +119,7 @@ private RubyBasicObject translate(UnsupportedSpecializationException exception)
}

public RubyBasicObject translate(Throwable throwable) {
if (throwable instanceof NullPointerException || throwable instanceof UnsupportedOperationException || Options.TRUFFLE_EXCEPTIONS_PRINT_JAVA.load()) {
if (Options.TRUFFLE_EXCEPTIONS_PRINT_JAVA.load()) {
throwable.printStackTrace();
}

26 changes: 18 additions & 8 deletions core/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.Source;
import org.jcodings.specific.BIG5Encoding;
import org.jcodings.specific.EUCJPEncoding;
import org.jcodings.specific.SJISEncoding;
import org.jcodings.specific.USASCIIEncoding;
@@ -97,6 +98,7 @@ public class CoreLibrary {
@CompilerDirectives.CompilationFinal private RubyModule truffleModule;
@CompilerDirectives.CompilationFinal private RubyModule truffleDebugModule;
@CompilerDirectives.CompilationFinal private RubyClass edomClass;
@CompilerDirectives.CompilationFinal private RubyClass encodingConverterClass;

@CompilerDirectives.CompilationFinal private RubyArray argv;
@CompilerDirectives.CompilationFinal private RubyBasicObject globalVariablesObject;
@@ -186,6 +188,7 @@ public void initialize() {
truffleDebugModule = new RubyModule(moduleClass, null, "Debug");
typeErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "TypeError");
zeroDivisionErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "ZeroDivisionError");
encodingConverterClass = new RubyEncodingConverter.RubyEncodingConverterClass(objectClass);

// Includes

@@ -275,6 +278,8 @@ public void initialize() {
objectClass.setConstant(null, module.getName(), module);
}

encodingClass.setConstant(null, encodingConverterClass.getName(), encodingConverterClass);

truffleModule.setConstant(null, truffleDebugModule.getName(), truffleDebugModule);

// Create some key objects
@@ -305,7 +310,7 @@ public void initialize() {
objectClass.setConstant(null, "FALSE", false);
objectClass.setConstant(null, "NIL", nilObject);

final RubyHash configHash = new RubyHash(hashClass, null, configHashMap, 0);
final RubyHash configHash = new RubyHash(hashClass, null, null, configHashMap, 0);
configModule.setConstant(null, "CONFIG", configHash);

objectClass.setConstant(null, "RbConfig", configModule);
@@ -371,11 +376,12 @@ public void loadRubyCore(String fileName) {
}

public void initializeEncodingConstants() {
encodingClass.setConstant(null, "US_ASCII", new RubyEncoding(encodingClass, USASCIIEncoding.INSTANCE));
encodingClass.setConstant(null, "ASCII_8BIT", new RubyEncoding(encodingClass, USASCIIEncoding.INSTANCE));
encodingClass.setConstant(null, "UTF_8", new RubyEncoding(encodingClass, USASCIIEncoding.INSTANCE));
encodingClass.setConstant(null, "EUC_JP", new RubyEncoding(encodingClass, EUCJPEncoding.INSTANCE));
encodingClass.setConstant(null, "Windows_31J", new RubyEncoding(encodingClass, SJISEncoding.INSTANCE));
encodingClass.setConstant(null, "US_ASCII", RubyEncoding.getEncoding(context, USASCIIEncoding.INSTANCE));
encodingClass.setConstant(null, "ASCII_8BIT", RubyEncoding.getEncoding(context, USASCIIEncoding.INSTANCE));
encodingClass.setConstant(null, "UTF_8", RubyEncoding.getEncoding(context, USASCIIEncoding.INSTANCE));
encodingClass.setConstant(null, "EUC_JP", RubyEncoding.getEncoding(context, EUCJPEncoding.INSTANCE));
encodingClass.setConstant(null, "Windows_31J", RubyEncoding.getEncoding(context, SJISEncoding.INSTANCE));
encodingClass.setConstant(null, "Big5", RubyEncoding.getEncoding(context, BIG5Encoding.INSTANCE));

}

@@ -744,7 +750,7 @@ public RubyNilClass getNilObject() {
return nilObject;
}

public RubyEncoding getDefaultEncoding() { return RubyEncoding.findEncodingByName(context.makeString("US-ASCII")); }
public RubyEncoding getDefaultEncoding() { return RubyEncoding.getEncoding(context, "US-ASCII"); }

public RubyHash getEnv() {
final LinkedHashMap<Object, Object> storage = new LinkedHashMap<>();
@@ -753,7 +759,7 @@ public RubyHash getEnv() {
storage.put(context.makeString(variable.getKey()), context.makeString(variable.getValue()));
}

return new RubyHash(context.getCoreLibrary().getHashClass(), null, storage, 0);
return new RubyHash(context.getCoreLibrary().getHashClass(), null, null, storage, 0);
}

public ArrayNodes.MinBlock getArrayMinBlock() {
@@ -779,4 +785,8 @@ public RubiniusLibrary getRubiniusLibrary() {
public RubyClass getArgumentErrorClass() {
return argumentErrorClass;
}

public RubyClass getEncodingConverterClass() {
return encodingConverterClass;
}
}
77 changes: 24 additions & 53 deletions core/src/main/java/org/jruby/truffle/runtime/core/RubyEncoding.java
Original file line number Diff line number Diff line change
@@ -12,13 +12,20 @@
import org.jcodings.Encoding;
import org.jcodings.specific.USASCIIEncoding;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* This is a bridge between JRuby encoding and Truffle encoding
*/
public class RubyEncoding extends RubyObject{
public class RubyEncoding extends RubyObject {

private static Map<Encoding, RubyEncoding> map = new HashMap<>();

private final org.jruby.RubyEncoding rubyEncoding;
private final Encoding encoding;

/**
* The class from which we create the object that is {@code Encoding}. A subclass of
@@ -33,69 +40,33 @@ public RubyEncodingClass(RubyClass objectClass) {

@Override
public RubyBasicObject newInstance(RubyNode currentNode) {
return new RubyEncoding(getContext().getCoreLibrary().getEncodingClass(), USASCIIEncoding.INSTANCE);
throw new UnsupportedOperationException();
}

}

public RubyEncoding(RubyClass encodingClass, Encoding encoding) {
super(encodingClass);
assert encoding != null;
rubyEncoding = org.jruby.RubyEncoding.newEncoding(getJRubyRuntime(), encoding);
}

public RubyEncoding(RubyClass encodingClass, org.jruby.RubyEncoding jrubyEncoding) {
super(encodingClass);
this.rubyEncoding = jrubyEncoding;
}

public static RubyEncoding findEncodingByName(RubyString name) {
RubyNode.notDesignedForCompilation();

org.jruby.RubyEncoding enc = findJRubyEncoding(name);
return new RubyEncoding(name.getContext().getCoreLibrary().getEncodingClass(), enc);
}

public static org.jruby.RubyEncoding findJRubyEncoding(RubyString name) {
RubyNode.notDesignedForCompilation();
public static synchronized RubyEncoding getEncoding(RubyContext context, Encoding encoding) {
RubyEncoding mapped = map.get(encoding);

org.jruby.RubyString string = org.jruby.RubyString.newString(name.getJRubyRuntime(), name.toString());
return (org.jruby.RubyEncoding) name.getJRubyRuntime().getEncodingService().rubyEncodingFromObject(string);
}
public String toString(){
return rubyEncoding.to_s(getJRubyRuntime().getCurrentContext()).asJavaString();
}
if (mapped == null) {
mapped = new RubyEncoding(context.getCoreLibrary().getEncodingClass(), encoding);
map.put(encoding, mapped);
}

public org.jruby.RubyEncoding getRubyEncoding() {
return rubyEncoding;
return mapped;
}

public boolean compareTo(RubyEncoding other) {
RubyNode.notDesignedForCompilation();

return getRubyEncoding().getEncoding().equals(other.getRubyEncoding().getEncoding());
public static RubyEncoding getEncoding(RubyContext context, String name) {
return getEncoding(context, context.getRuntime().getEncodingService().getEncodingFromString(name));
}

@Override
public boolean equals(Object o) {
RubyNode.notDesignedForCompilation();

if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

RubyEncoding that = (RubyEncoding) o;

if (!rubyEncoding.equals(that.rubyEncoding)) return false;

return true;
private RubyEncoding(RubyClass encodingClass, Encoding encoding) {
super(encodingClass);
this.encoding = encoding;
}

@Override
public int hashCode() {
RubyNode.notDesignedForCompilation();

return rubyEncoding.hashCode();
public Encoding getEncoding() {
return encoding;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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.runtime.core;

import java.util.*;

import org.jcodings.transcode.EConv;
import org.jruby.truffle.nodes.RubyNode;

public class RubyEncodingConverter extends RubyObject {

public EConv getEConv() {
return econv;
}

public static class RubyEncodingConverterClass extends RubyClass {

public RubyEncodingConverterClass(RubyClass objectClass) {
super(null, null, objectClass, "Converter");
}

@Override
public RubyBasicObject newInstance(RubyNode currentNode) {
return new RubyEncodingConverter(this, null);
}

}

private EConv econv;

public RubyEncodingConverter(RubyClass rubyClass, EConv econv) {
super(rubyClass);
this.econv = econv;
}

public void setEConv(EConv econv) {
this.econv = econv;
}

}
14 changes: 12 additions & 2 deletions core/src/main/java/org/jruby/truffle/runtime/core/RubyHash.java
Original file line number Diff line number Diff line change
@@ -35,23 +35,25 @@ public RubyHashClass(RubyClass objectClass) {

@Override
public RubyBasicObject newInstance(RubyNode currentNode) {
return new RubyHash(this, null, null, 0);
return new RubyHash(this, null, null, null, 0);
}

}

private RubyProc defaultBlock;
private Object defaultValue;
private Object store;
private int storeSize;

public RubyHash(RubyClass rubyClass, RubyProc defaultBlock, Object store, int storeSize) {
public RubyHash(RubyClass rubyClass, RubyProc defaultBlock, Object defaultValue, Object store, int storeSize) {
super(rubyClass);

assert store == null || store instanceof Object[] || store instanceof LinkedHashMap<?, ?>;
assert !(store instanceof Object[]) || ((Object[]) store).length == HASHES_SMALL * 2;
assert !(store instanceof Object[]) || storeSize <= HASHES_SMALL;

this.defaultBlock = defaultBlock;
this.defaultValue = defaultValue;
this.store = store;
this.storeSize = storeSize;
}
@@ -60,6 +62,10 @@ public RubyProc getDefaultBlock() {
return defaultBlock;
}

public Object getDefaultValue() {
return defaultValue;
}

public Object getStore() {
return store;
}
@@ -72,6 +78,10 @@ public void setDefaultBlock(RubyProc defaultBlock) {
this.defaultBlock = defaultBlock;
}

public void setDefaultValue(Object defaultValue) {
this.defaultValue = defaultValue;
}

public void setStore(Object store, int storeSize) {
assert store == null || store instanceof Object[] || store instanceof LinkedHashMap<?, ?>;
assert !(store instanceof Object[]) || ((Object[]) store).length == HASHES_SMALL * 2;
6 changes: 0 additions & 6 deletions spec/truffle/tags/core/encoding/converter/convpath_tags.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
fails:Encoding::Converter#convpath returns an Array
fails:Encoding::Converter#convpath returns each encoding pair as a sub-Array
fails:Encoding::Converter#convpath returns each encoding as an Encoding object
fails:Encoding::Converter#convpath returns multiple encoding pairs when direct conversion is impossible
fails:Encoding::Converter#convpath sets the last element of each pair to the first element of the next
fails:Encoding::Converter#convpath only lists a source encoding once
fails:Encoding::Converter#convpath indicates if crlf_newline conversion would occur
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
fails:Encoding::Converter.search_convpath returns an Array
fails:Encoding::Converter.search_convpath returns each encoding pair as a sub-Array
fails:Encoding::Converter.search_convpath returns each encoding as an Encoding object
fails:Encoding::Converter.search_convpath returns multiple encoding pairs when direct conversion is impossible
fails:Encoding::Converter.search_convpath sets the last element of each pair to the first element of the next
fails:Encoding::Converter.search_convpath only lists a source encoding once
fails:Encoding::Converter.search_convpath indicates if crlf_newline conversion would occur
fails:Encoding::Converter.search_convpath raises an Encoding::ConverterNotFoundError if no conversion path exists
1 change: 1 addition & 0 deletions spec/truffle/truffle.mspec
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ class MSpecScript
"spec/ruby/core/continuation",
"spec/ruby/core/dir",
"spec/ruby/core/encoding",
"spec/ruby/core/encoding/converter",
"spec/ruby/core/exception",
"spec/ruby/core/false",
"spec/ruby/core/fiber",