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

Commits on Dec 15, 2016

  1. [Truffle] Simplify Regexp by caching the named_captures in Ruby.

    * Build an Array instead of a complex LookupTable.
    eregon committed Dec 15, 2016
    Copy the full SHA
    d88a101 View commit details
  2. Copy the full SHA
    c4c2c72 View commit details
Original file line number Diff line number Diff line change
@@ -312,17 +312,9 @@ private DynamicObject putback(DynamicObject encodingConverter, int n) {
@Primitive(name = "encoding_converter_last_error")
public static abstract class EncodingConverterLastErrorNode extends PrimitiveArrayArgumentsNode {

@Child private CallDispatchHeadNode newLookupTableNode;
@Child private CallDispatchHeadNode lookupTableWriteNode;

public EncodingConverterLastErrorNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
newLookupTableNode = DispatchHeadNodeFactory.createMethodCall(context);
lookupTableWriteNode = DispatchHeadNodeFactory.createMethodCall(context);
}

@TruffleBoundary
@Specialization
public Object encodingConverterLastError(VirtualFrame frame, DynamicObject encodingConverter) {
public Object encodingConverterLastError(DynamicObject encodingConverter) {
final EConv ec = Layouts.ENCODING_CONVERTER.getEconv(encodingConverter);
final EConv.LastError lastError = ec.lastError;

@@ -332,21 +324,23 @@ public Object encodingConverterLastError(VirtualFrame frame, DynamicObject encod
return nil();
}

Object ret = newLookupTableNode.call(frame, coreLibrary().getLookupTableClass(), "new");
final boolean readAgain = lastError.getReadAgainLength() != 0;
final int size = readAgain ? 5 : 4;
final Object[] store = new Object[size];

lookupTableWriteNode.call(frame, ret, "[]=", getSymbol("result"), eConvResultToSymbol(lastError.getResult()));
lookupTableWriteNode.call(frame, ret, "[]=", getSymbol("source_encoding_name"), createString(new ByteList(lastError.getSource())));
lookupTableWriteNode.call(frame, ret, "[]=", getSymbol("destination_encoding_name"), createString(new ByteList(lastError.getDestination())));
lookupTableWriteNode.call(frame, ret, "[]=", getSymbol("error_bytes"), createString(new ByteList(lastError.getErrorBytes(),
lastError.getErrorBytesP(), lastError.getErrorBytesP() + lastError.getErrorBytesLength())));
store[0] = eConvResultToSymbol(lastError.getResult());
store[1] = createString(new ByteList(lastError.getSource()));
store[2] = createString(new ByteList(lastError.getDestination()));
store[3] = createString(new ByteList(lastError.getErrorBytes(),
lastError.getErrorBytesP(), lastError.getErrorBytesP() + lastError.getErrorBytesLength()));

if (lastError.getReadAgainLength() != 0) {
lookupTableWriteNode.call(frame, ret, "[]=", getSymbol("read_again_bytes"), createString(new ByteList(lastError.getErrorBytes(),
if (readAgain) {
store[4] = createString(new ByteList(lastError.getErrorBytes(),
lastError.getErrorBytesLength() + lastError.getErrorBytesP(),
lastError.getReadAgainLength())));
lastError.getReadAgainLength()));
}

return ret;
return createArray(store, size);
}

private DynamicObject eConvResultToSymbol(EConvResult result) {
Original file line number Diff line number Diff line change
@@ -41,7 +41,4 @@ DynamicObject createRegexp(DynamicObjectFactory factory,
RegexpOptions getOptions(DynamicObject object);
void setOptions(DynamicObject object, RegexpOptions value);

Object getCachedNames(DynamicObject object);
void setCachedNames(DynamicObject object, Object value);

}
Original file line number Diff line number Diff line change
@@ -55,6 +55,7 @@
import org.jruby.truffle.builtins.NonStandard;
import org.jruby.truffle.builtins.Primitive;
import org.jruby.truffle.builtins.PrimitiveArrayArgumentsNode;
import org.jruby.truffle.builtins.PrimitiveNode;
import org.jruby.truffle.core.cast.ToStrNode;
import org.jruby.truffle.core.cast.ToStrNodeGen;
import org.jruby.truffle.core.regexp.RegexpNodesFactory.RegexpSetLastMatchPrimitiveNodeFactory;
@@ -284,14 +285,6 @@ public static Regex compile(Node currentNode, RubyContext context, Rope bytes, R
}
}

public static Object getCachedNames(DynamicObject regexp) {
return Layouts.REGEXP.getCachedNames(regexp);
}

public static void setCachedNames(DynamicObject regexp, Object cachedNames) {
Layouts.REGEXP.setCachedNames(regexp, cachedNames);
}

public static void setRegex(DynamicObject regexp, Regex regex) {
Layouts.REGEXP.setRegex(regexp, regex);
}
@@ -681,54 +674,33 @@ public DynamicObject toS(DynamicObject regexp) {

}

@NonStandard
@NodeChild(value = "self")
public abstract static class RubiniusNamesNode extends RubyNode {

@Child private CallDispatchHeadNode newLookupTableNode;
@Child private CallDispatchHeadNode lookupTableWriteNode;

@Specialization(guards = "!anyNames(regexp)")
public DynamicObject rubiniusNamesNoCaptures(DynamicObject regexp) {
return nil();
}

@Specialization(guards = "anyNames(regexp)")
public Object rubiniusNames(VirtualFrame frame, DynamicObject regexp) {
if (getCachedNames(regexp) != null) {
return getCachedNames(regexp);
}

if (newLookupTableNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
newLookupTableNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}
@Primitive(name = "regexp_names")
public abstract static class RubiniusNamesNode extends PrimitiveArrayArgumentsNode {

if (lookupTableWriteNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
lookupTableWriteNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
@TruffleBoundary
@Specialization
public Object rubiniusNames(DynamicObject regexp) {
final int size = Layouts.REGEXP.getRegex(regexp).numberOfNames();
if (size == 0) {
return createArray(null, size);
}

final Object namesLookupTable = newLookupTableNode.call(frame, coreLibrary().getLookupTableClass(), "new");

for (final Iterator<NameEntry> i = Layouts.REGEXP.getRegex(regexp).namedBackrefIterator(); i.hasNext();) {
final NameEntry e = i.next();
final DynamicObject name = getContext().getSymbolTable().getSymbol(getContext().getRopeTable().getRope(Arrays.copyOfRange(e.name, e.nameP, e.nameEnd), USASCIIEncoding.INSTANCE, CodeRange.CR_7BIT));
final Object[] names = new Object[size];
int i = 0;
for (final Iterator<NameEntry> iter = Layouts.REGEXP.getRegex(regexp).namedBackrefIterator(); iter.hasNext();) {
final NameEntry e = iter.next();
final byte[] bytes = Arrays.copyOfRange(e.name, e.nameP, e.nameEnd);
final Rope rope = getContext().getRopeTable().getRope(bytes, USASCIIEncoding.INSTANCE, CodeRange.CR_7BIT);
final DynamicObject name = getContext().getFrozenStrings().getFrozenString(rope);

final int[] backrefs = e.getBackRefs();
final DynamicObject backrefsRubyArray = createArray(backrefs, backrefs.length);

lookupTableWriteNode.call(frame, namesLookupTable, "[]=", name, backrefsRubyArray);
names[i++] = createArray(new Object[]{ name, backrefsRubyArray }, 2);
}

setCachedNames(regexp, namesLookupTable);

return namesLookupTable;
return createArray(names, size);
}

public static boolean anyNames(DynamicObject regexp) {
return Layouts.REGEXP.getRegex(regexp).numberOfNames() > 0;
}
}

@CoreMethod(names = "allocate", constructor = true)
Original file line number Diff line number Diff line change
@@ -1984,10 +1984,6 @@ public RubyNode visitInstVarNode(InstVarParseNode node) {
ret = MatchDataNodesFactory.RegexpNodeFactory.create(new RubyNode[]{ self });
ret.unsafeSetSourceSection(sourceSection);
return addNewlineIfNeeded(node, ret);
} else if (name.equals("@names")) {
ret = RegexpNodesFactory.RubiniusNamesNodeGen.create(self);
ret.unsafeSetSourceSection(sourceSection);
return addNewlineIfNeeded(node, ret);
}
}

12 changes: 5 additions & 7 deletions truffle/src/main/ruby/core/encoding.rb
Original file line number Diff line number Diff line change
@@ -324,15 +324,13 @@ def last_error
error = Truffle.invoke_primitive :encoding_converter_last_error, self
return if error.nil?

result = error[:result]
error_bytes = error[:error_bytes]
result, source_encoding_name, destination_encoding_name, error_bytes, read_again_bytes = error
read_again_string = nil
codepoint = nil
error_bytes_msg = error_bytes.dump
source_encoding_name = error[:source_encoding_name]
destination_encoding_name = error[:destination_encoding_name]

case result
when :invalid_byte_sequence
read_again_string = error[:read_again_string]
if read_again_string
msg = "#{error_bytes_msg} followed by #{read_again_string.dump} on #{source_encoding_name}"
else
@@ -346,7 +344,7 @@ def last_error
exc = InvalidByteSequenceError.new msg
when :undefined_conversion
error_char = error_bytes
if codepoint = error[:codepoint]
if codepoint
error_bytes_msg = "U+%04X" % codepoint
end

@@ -379,7 +377,7 @@ def last_error
if result == :invalid_byte_sequence or result == :incomplete_input
exc.error_bytes = error_bytes.force_encoding Encoding::ASCII_8BIT

if bytes = error[:read_again_bytes]
if bytes = read_again_bytes
exc.readagain_bytes = bytes.force_encoding Encoding::ASCII_8BIT
end
end
17 changes: 3 additions & 14 deletions truffle/src/main/ruby/core/regexp.rb
Original file line number Diff line number Diff line change
@@ -309,15 +309,8 @@ def option_to_string(option)
# #=> {}
#
def named_captures
hash = {}

if @names
@names.sort_by { |a,b| b.first }.each do |k, v| # LookupTable is unordered
hash[k.to_s] = v
end
end

return hash
@named_captures ||= Hash[Truffle.invoke_primitive(:regexp_names, self)].freeze
@named_captures.dup
end

#
@@ -336,11 +329,7 @@ def named_captures
# #=> []
#
def names
if @names
@names.sort_by { |a,b| b.first }.map { |x| x.first.to_s } # LookupTable is unordered
else
[]
end
named_captures.keys.dup
end

end