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: 7a66d8bb338f
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 824f063264de
Choose a head ref
  • 6 commits
  • 7 files changed
  • 1 contributor

Commits on Dec 13, 2014

  1. Copy the full SHA
    1f88220 View commit details
  2. Copy the full SHA
    3beeeb8 View commit details
  3. Copy the full SHA
    7e791ac View commit details
  4. [Truffle] Tag some newly failing language specs.

    These started failing when we started setting __ENCODING__ correctly.  They were passing before due to happenstance.  After investigation, it looks like these only fail when passed through eval and likely due to source position tracking issues.
    nirvdrum committed Dec 13, 2014
    Copy the full SHA
    70c8ce6 View commit details
  5. [Truffle] Tagged a new regexp encoding failure now that we're setting…

    … __ENCODING__ properly.
    nirvdrum committed Dec 13, 2014
    Copy the full SHA
    e0829ab View commit details
  6. [Truffle] New encoding implementation.

    These changes mirror what JRuby is doing for the most part.  We have to track our own lists for now because EncodingService's lookup tables are specific to the non-Truffle JRuby class hierarchy.  These changes fix the ambiguous lookup problem the old implementation suffered from by using the encoding name, rather than the shared JCodings encoding object, as the lookup key.  All known encodings are now eagerly instantiated at startup.  This is in contrast to what non-Truffle JRuby does, whereby it defines its RubyEncoding instance but lazily loads the JCodings encoding object as needed.  Eagerly loading simplified some things, avoided some thread safety issues, and may be useful for other static analysis within Truffle.
    nirvdrum committed Dec 13, 2014
    Copy the full SHA
    824f063 View commit details
94 changes: 71 additions & 23 deletions core/src/main/java/org/jruby/runtime/encoding/EncodingService.java
Original file line number Diff line number Diff line change
@@ -9,9 +9,7 @@
import org.jcodings.util.CaseInsensitiveBytesHash;
import org.jcodings.util.Hash.HashEntryIterator;
import org.jruby.Ruby;
import org.jruby.RubyConverter;
import org.jruby.RubyEncoding;
import org.jruby.exceptions.MainExitException;
import org.jruby.platform.Platform;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
@@ -20,7 +18,9 @@
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.List;

import org.jcodings.specific.USASCIIEncoding;
import org.jruby.RubyFixnum;
import org.jruby.RubyString;
@@ -32,7 +32,7 @@ public final class EncodingService {
private final CaseInsensitiveBytesHash<Entry> aliases;

// for fast lookup: encoding entry => org.jruby.RubyEncoding
private final IRubyObject[] encodingList;
public final IRubyObject[] encodingList;
// for fast lookup: org.joni.encoding.Encoding => org.jruby.RubyEncoding
private RubyEncoding[] encodingIndex = new RubyEncoding[4];
// the runtime
@@ -165,40 +165,87 @@ public RubyEncoding getEncoding(Encoding enc) {
if (index < encodingIndex.length && (rubyEncoding = encodingIndex[index]) != null) {
return rubyEncoding;
}

enc = loadEncoding(new ByteList(enc.getName(), false));
return encodingIndex[enc.getIndex()];
}

public interface EncodingDefinitionVisitor {
public void defineEncoding(Entry encodingEntry, byte[] name, int p, int end);

public void defineConstant(int encodingListIndex, String constName);
}

public interface EncodingAliasVisitor {
public void defineAlias(int encodingListIndex, String constName);

public void defineConstant(int encodingListIndex, String constName);
}

public void defineEncodings() {
defineEncodings(new EncodingDefinitionVisitor() {
@Override
public void defineEncoding(Entry encodingEntry, byte[] name, int p, int end) {
RubyEncoding encoding = RubyEncoding.newEncoding(runtime, name, p, end, encodingEntry.isDummy());
encodingList[encodingEntry.getIndex()] = encoding;
}

@Override
public void defineConstant(int encodingListIndex, String constName) {
defineEncodingConstant(runtime, (RubyEncoding) encodingList[encodingListIndex], constName);
}
});
}

public void defineEncodings(EncodingDefinitionVisitor visitor) {
HashEntryIterator hei = encodings.entryIterator();
while (hei.hasNext()) {
CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<Entry> e =
((CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<Entry>)hei.next());
CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<Entry> e =
((CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<Entry>)hei.next());
Entry ee = e.value;
RubyEncoding encoding = RubyEncoding.newEncoding(runtime, e.bytes, e.p, e.end, ee.isDummy());
encodingList[ee.getIndex()] = encoding;
defineEncodingConstants(runtime, encoding, e.bytes, e.p, e.end);

visitor.defineEncoding(ee, e.bytes, e.p, e.end);

for (String constName : encodingNames(e.bytes, e.p, e.end)) {
visitor.defineConstant(ee.getIndex(), constName);
}
}
}

public void defineAliases() {
defineAliases(new EncodingAliasVisitor() {
@Override
public void defineAlias(int encodingListIndex, String constName) { }

@Override
public void defineConstant(int encodingListIndex, String constName) {
defineEncodingConstant(runtime, (RubyEncoding) encodingList[encodingListIndex], constName);
}
});
}

public void defineAliases(EncodingAliasVisitor visitor) {
HashEntryIterator hei = aliases.entryIterator();
while (hei.hasNext()) {
CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<Entry> e =
((CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<Entry>)hei.next());
Entry ee = e.value;
RubyEncoding encoding = (RubyEncoding)encodingList[ee.getIndex()];
defineEncodingConstants(runtime, encoding, e.bytes, e.p, e.end);
CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<Entry> e =
((CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<Entry>)hei.next());
Entry ee = e.value;

for (String constName : encodingNames(e.bytes, e.p, e.end)) {
visitor.defineAlias(ee.getIndex(), constName);
visitor.defineConstant(ee.getIndex(), constName);
}
}
}

private void defineEncodingConstants(Ruby runtime, RubyEncoding encoding, byte[]name, int p,
int end) {
private List<String> encodingNames(byte[] name, int p, int end) {
final List<String> names = new ArrayList<String>();

Encoding enc = ASCIIEncoding.INSTANCE;
int s = p;

int code = name[s] & 0xff;
if (enc.isDigit(code)) return;
if (enc.isDigit(code)) return names;

boolean hasUpper = false;
boolean hasLower = false;
@@ -212,7 +259,7 @@ private void defineEncodingConstants(Ruby runtime, RubyEncoding encoding, byte[]
boolean isValid = false;
if (s >= end) {
isValid = true;
defineEncodingConstant(runtime, encoding, name, p, end);
names.add(new String(name, p, end));
}

if (!isValid || hasLower) {
@@ -235,22 +282,23 @@ private void defineEncodingConstants(Ruby runtime, RubyEncoding encoding, byte[]
if (!enc.isAlnum(constName[s] & 0xff)) constName[s] = (byte)'_';
}
if (hasUpper) {
defineEncodingConstant(runtime, encoding, constName, 0, constName.length);
names.add(new String(constName, 0, constName.length));
}
}
if (hasLower) {
for (s = 0; s < constName.length; ++s) {
code = constName[s] & 0xff;
if (enc.isLower(code)) constName[s] = AsciiTables.ToUpperCaseTable[code];
}
defineEncodingConstant(runtime, encoding, constName, 0, constName.length);
names.add(new String(constName, 0, constName.length));
}
}

return names;
}

private void defineEncodingConstant(Ruby runtime, RubyEncoding encoding, byte[]constName,
int constP, int constEnd) {
runtime.getEncoding().defineConstant(new String(constName, constP , constEnd), encoding);
private void defineEncodingConstant(Ruby runtime, RubyEncoding encoding, String constName) {
runtime.getEncoding().defineConstant(constName, encoding);
}

public IRubyObject getDefaultExternal() {
17 changes: 2 additions & 15 deletions core/src/main/java/org/jruby/truffle/nodes/core/EncodingNodes.java
Original file line number Diff line number Diff line change
@@ -205,22 +205,9 @@ public ListNode(ListNode prev) {
public RubyArray list() {
notDesignedForCompilation();

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

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

Hash.HashEntryIterator i;

i = service.getEncodings().entryIterator();
final RubyEncoding[] encodings = RubyEncoding.cloneEncodingList();

while (i.hasNext()) {
CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<EncodingDB.Entry> e =
((CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<EncodingDB.Entry>)i.next());
array[n++] = RubyEncoding.getEncoding(getContext(), e.value.getEncoding());
}

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

41 changes: 29 additions & 12 deletions core/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -13,12 +13,11 @@
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;
import org.jcodings.Encoding;
import org.jcodings.EncodingDB;
import org.jruby.runtime.Constants;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.encoding.EncodingService;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.ArrayNodes;
import org.jruby.truffle.runtime.ModuleOperations;
@@ -32,7 +31,6 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.LinkedHashMap;
import java.util.Map;

@@ -356,14 +354,33 @@ public void loadRubyCore(String fileName) {
}

public void initializeEncodingConstants() {
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));
encodingClass.setConstant(null, "IBM437", RubyEncoding.getEncoding(context, USASCIIEncoding.INSTANCE));
getContext().getRuntime().getEncodingService().defineEncodings(new EncodingService.EncodingDefinitionVisitor() {
@Override
public void defineEncoding(EncodingDB.Entry encodingEntry, byte[] name, int p, int end) {
Encoding e = encodingEntry.getEncoding();

RubyEncoding re = RubyEncoding.newEncoding(getContext(), e, name, p, end, encodingEntry.isDummy());
RubyEncoding.storeEncoding(encodingEntry.getIndex(), re);
}

@Override
public void defineConstant(int encodingListIndex, String constName) {
encodingClass.setConstant(null, constName, RubyEncoding.getEncoding(encodingListIndex));
}
});

getContext().getRuntime().getEncodingService().defineAliases(new EncodingService.EncodingAliasVisitor() {
@Override
public void defineAlias(int encodingListIndex, String constName) {
RubyEncoding re = RubyEncoding.getEncoding(encodingListIndex);
RubyEncoding.storeAlias(constName, re);
}

@Override
public void defineConstant(int encodingListIndex, String constName) {
encodingClass.setConstant(null, constName, RubyEncoding.getEncoding(encodingListIndex));
}
});
}

public RubyClass getMetaClass(Object object) {
41 changes: 30 additions & 11 deletions core/src/main/java/org/jruby/truffle/runtime/core/RubyEncoding.java
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.runtime.core;

import org.jcodings.Encoding;
import org.jcodings.EncodingDB;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.util.ByteList;
@@ -22,7 +23,8 @@
*/
public class RubyEncoding extends RubyBasicObject {

private static Map<Encoding, RubyEncoding> map = new HashMap<>();
private static RubyEncoding[] encodingList = new RubyEncoding[EncodingDB.getEncodings().size()];
private static Map<String, RubyEncoding> lookup = new HashMap<>();

private final Encoding encoding;
private final ByteList name;
@@ -46,24 +48,34 @@ public RubyBasicObject newInstance(RubyNode currentNode) {
}

public static synchronized RubyEncoding getEncoding(RubyContext context, Encoding encoding) {
RubyEncoding mapped = map.get(encoding);
return lookup.get(new String(encoding.getName()).toLowerCase());
}

if (mapped == null) {
mapped = new RubyEncoding(context.getCoreLibrary().getEncodingClass(), encoding);
map.put(encoding, mapped);
}
public static RubyEncoding getEncoding(RubyContext context, String name) {
return lookup.get(name.toLowerCase());
}

return mapped;
public static RubyEncoding getEncoding(int index) {
return encodingList[index];
}

public static RubyEncoding getEncoding(RubyContext context, String name) {
return getEncoding(context, context.getRuntime().getEncodingService().getEncodingFromString(name));
public static void storeEncoding(int encodingListIndex, RubyEncoding encoding) {
encodingList[encodingListIndex] = encoding;
lookup.put(encoding.getName().toString().toLowerCase(), encoding);
}

public static void storeAlias(String aliasName, RubyEncoding encoding) {
lookup.put(aliasName.toLowerCase(), encoding);
}

public static RubyEncoding newEncoding(RubyContext context, Encoding encoding, byte[] name, int p, int end, boolean isDummy) {
return new RubyEncoding(context.getCoreLibrary().getEncodingClass(), encoding, new ByteList(name, p, end), isDummy);
}

private RubyEncoding(RubyClass encodingClass, Encoding encoding) {
private RubyEncoding(RubyClass encodingClass, Encoding encoding, ByteList name, boolean isDummy) {
super(encodingClass);
this.encoding = encoding;
this.name = new ByteList(encoding.getName());
this.name = name;
}

public Encoding getEncoding() {
@@ -74,4 +86,11 @@ public ByteList getName() {
return name;
}

public static RubyEncoding[] cloneEncodingList() {
final RubyEncoding[] clone = new RubyEncoding[encodingList.length];

System.arraycopy(encodingList, 0, clone, 0, encodingList.length);

return clone;
}
}
Original file line number Diff line number Diff line change
@@ -13,8 +13,6 @@
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.nodes.NodeUtil;
import org.jcodings.Encoding;
import org.jcodings.specific.USASCIIEncoding;
import org.joni.NameEntry;
import org.joni.Regex;
import org.joni.Syntax;
@@ -817,7 +815,7 @@ public RubyNode visitDotNode(org.jruby.ast.DotNode node) {
@Override
public RubyNode visitEncodingNode(org.jruby.ast.EncodingNode node) {
SourceSection sourceSection = translate(node.getPosition());
return new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getDefaultEncoding());
return new ObjectLiteralNode(context, sourceSection, RubyEncoding.getEncoding(context, node.getEncoding()));
}

@Override
2 changes: 2 additions & 0 deletions spec/truffle/tags/language/magic_comment_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fails:Magic comment must be at the first line
fails:Magic comment must be the first token of the line
1 change: 1 addition & 0 deletions spec/truffle/tags/language/regexp/encoding_tags.txt
Original file line number Diff line number Diff line change
@@ -2,3 +2,4 @@ fails:Regexps with encoding modifiers preserves US-ASCII as /n encoding through
fails:Regexps with encoding modifiers preserves ASCII-8BIT as /n encoding through interpolation if all chars are 7-bit
fails:Regexps with encoding modifiers preserves Windows-31J as /s encoding through interpolation
fails:Regexps with encoding modifiers preserves UTF-8 as /u encoding through interpolation
fails:Regexps with encoding modifiers uses ASCII-8BIT as /n encoding if not all chars are 7-bit