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

Commits on Mar 17, 2015

  1. Copy the full SHA
    336aeb1 View commit details
  2. Copy the full SHA
    9169677 View commit details
  3. Copy the full SHA
    3466bba View commit details
  4. Copy the full SHA
    2a7e9dc View commit details
  5. Copy the full SHA
    c61f0c4 View commit details
  6. Copy the full SHA
    f9818f7 View commit details
38 changes: 6 additions & 32 deletions core/src/main/java/org/jruby/RubyString.java
Original file line number Diff line number Diff line change
@@ -271,23 +271,6 @@ final boolean singleByteOptimizable(Encoding enc) {
return StringSupport.isSingleByteOptimizable(this, enc);
}

// rb_enc_compatible
private Encoding isCompatibleWith(RubyString other) {
Encoding enc1 = value.getEncoding();
Encoding enc2 = other.value.getEncoding();

if (enc1 == enc2) return enc1;

if (other.value.getRealSize() == 0) return enc1;
if (value.getRealSize() == 0) {
return (enc1.isAsciiCompatible() && other.isAsciiOnly()) ? enc1 : enc2;
}

if (!enc1.isAsciiCompatible() || !enc2.isAsciiCompatible()) return null;

return RubyEncoding.areCompatible(enc1, scanForCodeRange(), enc2, other.scanForCodeRange());
}

final Encoding isCompatibleWith(EncodingCapable other) {
if (other instanceof RubyString) return checkEncoding((RubyString)other);
Encoding enc1 = value.getEncoding();
@@ -303,7 +286,7 @@ final Encoding isCompatibleWith(EncodingCapable other) {

// rb_enc_check
public final Encoding checkEncoding(RubyString other) {
return checkEncoding((ByteListHolder) other);
return checkEncoding((CodeRangeable) other);
}

final Encoding checkEncoding(EncodingCapable other) {
@@ -314,9 +297,8 @@ final Encoding checkEncoding(EncodingCapable other) {
}

@Override
public final Encoding checkEncoding(ByteListHolder other) {
// TODO (nirvdrum 13-Jan-15): This cast is untenable. It's a temporary measure until isCompatibleWith and its call graph are generalized.
Encoding enc = isCompatibleWith((RubyString) other);
public final Encoding checkEncoding(CodeRangeable other) {
Encoding enc = StringSupport.areCompatible(this, other);
if (enc == null) throw getRuntime().newEncodingCompatibilityError("incompatible character encodings: " +
value.getEncoding() + " and " + other.getByteList().getEncoding());
return enc;
@@ -1141,20 +1123,12 @@ public IRubyObject op_plus(ThreadContext context, IRubyObject _str) {
public IRubyObject op_plus19(ThreadContext context, IRubyObject _str) {
RubyString str = _str.convertToString();
Encoding enc = checkEncoding(str);
RubyString resultStr = newStringNoCopy(context.runtime, addByteLists(value, str.value),
RubyString resultStr = newStringNoCopy(context.runtime, StringSupport.addByteLists(value, str.value),
enc, CodeRangeSupport.codeRangeAnd(getCodeRange(), str.getCodeRange()));
resultStr.infectBy(flags | str.flags);
return resultStr;
}

private ByteList addByteLists(ByteList value1, ByteList value2) {
ByteList result = new ByteList(value1.getRealSize() + value2.getRealSize());
result.setRealSize(value1.getRealSize() + value2.getRealSize());
System.arraycopy(value1.getUnsafeBytes(), value1.getBegin(), result.getUnsafeBytes(), 0, value1.getRealSize());
System.arraycopy(value2.getUnsafeBytes(), value2.getBegin(), result.getUnsafeBytes(), value1.getRealSize(), value2.getRealSize());
return result;
}

public IRubyObject op_mul(ThreadContext context, IRubyObject other) {
return op_mul19(context, other);
}
@@ -1568,7 +1542,7 @@ public IRubyObject casecmp(ThreadContext context, IRubyObject other) {
public IRubyObject casecmp19(ThreadContext context, IRubyObject other) {
Ruby runtime = context.runtime;
RubyString otherStr = other.convertToString();
Encoding enc = isCompatibleWith(otherStr);
Encoding enc = StringSupport.areCompatible(this, otherStr);
if (enc == null) return runtime.getNil();

if (singleByteOptimizable() && otherStr.singleByteOptimizable()) {
@@ -2469,7 +2443,7 @@ private IRubyObject subBangCommon19(ThreadContext context, Regex pattern, Matche
final int end = matcher.getEnd();
int cr = getCodeRange();

Encoding enc = isCompatibleWith(repl);
Encoding enc = StringSupport.areCompatible(this, repl);
if (enc == null) enc = subBangVerifyEncoding(context, repl, beg, end);

final int plen = end - beg;
1 change: 0 additions & 1 deletion core/src/main/java/org/jruby/util/ByteListHolder.java
Original file line number Diff line number Diff line change
@@ -32,5 +32,4 @@ public interface ByteListHolder {
public ByteList getByteList();
public void modify();
public void modify(int length);
public Encoding checkEncoding(ByteListHolder other);
}
3 changes: 3 additions & 0 deletions core/src/main/java/org/jruby/util/CodeRangeable.java
Original file line number Diff line number Diff line change
@@ -26,11 +26,14 @@

package org.jruby.util;

import org.jcodings.Encoding;

public interface CodeRangeable extends ByteListHolder {
public int getCodeRange();
public int scanForCodeRange();
public boolean isCodeRangeValid();
public void setCodeRange(int codeRange);
public void clearCodeRange();
public void keepCodeRange();
public Encoding checkEncoding(CodeRangeable other);
}
29 changes: 29 additions & 0 deletions core/src/main/java/org/jruby/util/StringSupport.java
Original file line number Diff line number Diff line change
@@ -36,6 +36,7 @@
import org.joni.Matcher;
import org.jruby.Ruby;
import org.jruby.RubyBasicObject;
import org.jruby.RubyEncoding;
import org.jruby.RubyObject;
import org.jruby.RubyString;
import org.jruby.runtime.builtin.IRubyObject;
@@ -1345,4 +1346,32 @@ public static int choppedLength19(CodeRangeable rubyString, Ruby runtime) {
}
return s - p;
}

/**
* rb_enc_compatible
*/

public static Encoding areCompatible(CodeRangeable string, CodeRangeable other) {
Encoding enc1 = string.getByteList().getEncoding();
Encoding enc2 = other.getByteList().getEncoding();

if (enc1 == enc2) return enc1;

if (other.getByteList().getRealSize() == 0) return enc1;
if (string.getByteList().getRealSize() == 0) {
return (enc1.isAsciiCompatible() && isAsciiOnly(other)) ? enc1 : enc2;
}

if (!enc1.isAsciiCompatible() || !enc2.isAsciiCompatible()) return null;

return RubyEncoding.areCompatible(enc1, string.scanForCodeRange(), enc2, other.scanForCodeRange());
}

public static ByteList addByteLists(ByteList value1, ByteList value2) {
ByteList result = new ByteList(value1.getRealSize() + value2.getRealSize());
result.setRealSize(value1.getRealSize() + value2.getRealSize());
System.arraycopy(value1.getUnsafeBytes(), value1.getBegin(), result.getUnsafeBytes(), 0, value1.getRealSize());
System.arraycopy(value2.getUnsafeBytes(), value2.getBegin(), result.getUnsafeBytes(), value1.getRealSize(), value2.getRealSize());
return result;
}
}
1 change: 1 addition & 0 deletions spec/truffle/tags/core/string/delete_tags.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
fails:String#delete deletes multibyte characters
fails:String#delete raises if the given ranges are invalid
fails:String#delete deletes all chars in a sequence
4 changes: 0 additions & 4 deletions spec/truffle/tags/core/string/plus_tags.txt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -44,6 +44,7 @@
import org.joni.Region;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.cast.TaintResultNode;
import org.jruby.truffle.nodes.coerce.ToIntNode;
import org.jruby.truffle.nodes.coerce.ToIntNodeFactory;
import org.jruby.truffle.nodes.coerce.ToStrNode;
@@ -80,21 +81,43 @@
public abstract class StringNodes {

@CoreMethod(names = "+", required = 1)
public abstract static class AddNode extends CoreMethodNode {
@NodeChildren({
@NodeChild(value = "string"),
@NodeChild(value = "other")
})
public abstract static class AddNode extends RubyNode {

@Child private TaintResultNode taintResultNode;

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

public AddNode(AddNode prev) {
super(prev);
taintResultNode = prev.taintResultNode;
}

@CreateCast("other") public RubyNode coerceOtherToString(RubyNode other) {
return ToStrNodeFactory.create(getContext(), getSourceSection(), other);
}

@Specialization
public RubyString add(RubyString a, RubyString b) {
notDesignedForCompilation();
public RubyString add(RubyString string, RubyString other) {
final Encoding enc = string.checkEncoding(other, this);
final RubyString ret = getContext().makeString(getContext().getCoreLibrary().getStringClass(),
StringSupport.addByteLists(string.getByteList(), other.getByteList()));

return (RubyString) getContext().toTruffle(getContext().toJRuby(a).op_plus(getContext().getRuntime().getCurrentContext(), getContext().toJRuby(b)));
if (taintResultNode == null) {
CompilerDirectives.transferToInterpreter();
taintResultNode = insert(new TaintResultNode(getContext(), getSourceSection(), false, new int[]{}));
}

ret.getByteList().setEncoding(enc);
taintResultNode.maybeTaint(string, ret);
taintResultNode.maybeTaint(other, ret);

return ret;
}
}

@@ -827,15 +850,15 @@ private Object deleteBangSlow(VirtualFrame frame, RubyString string, Object[] ar
}

RubyString otherString = otherStrings[0];
Encoding enc = string.checkEncoding(otherString);
Encoding enc = string.checkEncoding(otherString, this);

boolean[] squeeze = new boolean[StringSupport.TRANS_SIZE + 1];
StringSupport.TrTables tables = StringSupport.trSetupTable(otherString.getBytes(),
getContext().getRuntime(),
squeeze, null, true, enc);

for (int i = 1; i < otherStrings.length; i++) {
enc = string.checkEncoding(otherStrings[i]);
enc = string.checkEncoding(otherStrings[i], this);
tables = StringSupport.trSetupTable(otherStrings[i].getBytes(), getContext().getRuntime(), squeeze, tables, false, enc);
}

Original file line number Diff line number Diff line change
@@ -68,6 +68,9 @@ public Object execute(VirtualFrame frame) {
} catch (UnsupportedSpecializationException exception) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(translate(exception));
} catch (org.jruby.exceptions.RaiseException e) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().toTruffle(e.getException(), this));
} catch (Throwable exception) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(translate(exception));
Original file line number Diff line number Diff line change
@@ -19,8 +19,8 @@
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.objects.Allocator;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.util.ByteList;
import org.jruby.util.ByteListHolder;
import org.jruby.util.CodeRangeable;
import org.jruby.util.StringSupport;

@@ -205,9 +205,24 @@ public final void modify(int length) {
}

@Override
public Encoding checkEncoding(ByteListHolder other) {
// TODO (nirvdrum Jan. 13, 2015): This should check if the encodings are compatible rather than just always succeeding.
return bytes.getEncoding();
public Encoding checkEncoding(CodeRangeable other) {
// TODO (nirvdrum 16-Mar-15) This will return null for bad cases and we really don't want to propagate that. Need a way to raise an appropriate exception while adhering to the interface.
return StringSupport.areCompatible(this, other);
}

public Encoding checkEncoding(CodeRangeable other, Node node) {
final Encoding encoding = checkEncoding(other);

if (encoding == null) {
throw new RaiseException(
getContext().getCoreLibrary().encodingCompatibilityErrorIncompatible(
this.getByteList().getEncoding().toString(),
other.getByteList().getEncoding().toString(),
node)
);
}

return encoding;
}

@Override
Original file line number Diff line number Diff line change
@@ -25,7 +25,6 @@
import org.jruby.truffle.runtime.methods.Arity;
import org.jruby.truffle.runtime.methods.SharedMethodInfo;
import org.jruby.util.ByteList;
import org.jruby.util.ByteListHolder;
import org.jruby.util.CodeRangeable;
import org.jruby.util.StringSupport;

@@ -139,7 +138,7 @@ public final void modify(int length) {
}

@Override
public Encoding checkEncoding(ByteListHolder other) {
public Encoding checkEncoding(CodeRangeable other) {
// TODO (nirvdrum Jan. 13, 2015): This should check if the encodings are compatible rather than just always succeeding.
return bytes.getEncoding();
}