|
28 | 28 | import com.oracle.truffle.api.profiles.ConditionProfile;
|
29 | 29 | import com.oracle.truffle.api.source.SourceSection;
|
30 | 30 | import org.jcodings.Encoding;
|
| 31 | +import org.jcodings.specific.ASCIIEncoding; |
31 | 32 | import org.jcodings.specific.UTF8Encoding;
|
32 | 33 | import org.truffleruby.Layouts;
|
33 | 34 | import org.truffleruby.RubyContext;
|
|
63 | 64 | import org.truffleruby.core.string.StringSupport;
|
64 | 65 | import org.truffleruby.interop.ToJavaStringNodeGen;
|
65 | 66 | import org.truffleruby.language.LexicalScope;
|
| 67 | +import org.truffleruby.language.NotOptimizedWarningNode; |
66 | 68 | import org.truffleruby.language.NotProvided;
|
67 | 69 | import org.truffleruby.language.RubyBaseNode;
|
68 | 70 | import org.truffleruby.language.RubyGuards;
|
@@ -443,15 +445,43 @@ public long capacity(DynamicObject string,
|
443 | 445 | @CoreMethod(names = "rb_str_set_len", onSingleton = true, required = 2, lowerFixnum = 2)
|
444 | 446 | public abstract static class RbStrSetLenNode extends CoreMethodArrayArgumentsNode {
|
445 | 447 |
|
| 448 | + @Child NotOptimizedWarningNode notOptimizedWarningNode; |
| 449 | + |
446 | 450 | @Specialization
|
447 |
| - public DynamicObject strSetLen(DynamicObject string, int len, |
448 |
| - @Cached("create()") StringToNativeNode stringToNativeNode) { |
| 451 | + public DynamicObject strSetLen(DynamicObject string, int newByteLength, |
| 452 | + @Cached("create()") StringToNativeNode stringToNativeNode, |
| 453 | + @Cached("createBinaryProfile()") ConditionProfile binaryProfile) { |
449 | 454 | final NativeRope nativeRope = stringToNativeNode.executeToNative(string);
|
450 |
| - final NativeRope newNativeRope = nativeRope.withByteLength(len); |
| 455 | + final NativeRope newNativeRope; |
| 456 | + |
| 457 | + if (binaryProfile.profile(nativeRope.getEncoding() == ASCIIEncoding.INSTANCE)) { |
| 458 | + // TODO (eregon, 17 Jan 2019): We use CR_VALID here as zlib relies on it. Computing |
| 459 | + // the coderange here on every call is too slow. A proper fix is to compute the |
| 460 | + // CodeRange lazily on NativeRope. |
| 461 | + newNativeRope = nativeRope.withByteLength(newByteLength, newByteLength, CodeRange.CR_VALID); |
| 462 | + } else { |
| 463 | + performanceWarn("calling rb_str_set_len() on non-binary string is not yet optimized"); |
| 464 | + |
| 465 | + final byte[] bytes = new byte[newByteLength]; |
| 466 | + nativeRope.getNativePointer().readBytes(0, bytes, 0, newByteLength); |
| 467 | + final long packedLengthAndCodeRange = RopeOperations.calculateCodeRangeAndLength(nativeRope.getEncoding(), bytes, 0, newByteLength); |
| 468 | + final CodeRange codeRange = CodeRange.fromInt(StringSupport.unpackArg(packedLengthAndCodeRange)); |
| 469 | + final int characterLength = StringSupport.unpackResult(packedLengthAndCodeRange); |
| 470 | + newNativeRope = nativeRope.withByteLength(newByteLength, characterLength, codeRange); |
| 471 | + } |
| 472 | + |
451 | 473 | StringOperations.setRope(string, newNativeRope);
|
452 | 474 | return string;
|
453 | 475 | }
|
454 | 476 |
|
| 477 | + private void performanceWarn(String message) { |
| 478 | + if (notOptimizedWarningNode == null) { |
| 479 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 480 | + notOptimizedWarningNode = insert(new NotOptimizedWarningNode()); |
| 481 | + } |
| 482 | + notOptimizedWarningNode.warn(message); |
| 483 | + } |
| 484 | + |
455 | 485 | }
|
456 | 486 |
|
457 | 487 | @CoreMethod(names = "rb_str_resize", onSingleton = true, required = 2, lowerFixnum = 2)
|
|
0 commit comments