|
76 | 76 | import java.nio.charset.StandardCharsets;
|
77 | 77 |
|
78 | 78 | import com.oracle.truffle.api.dsl.Bind;
|
| 79 | +import com.oracle.truffle.api.nodes.LoopNode; |
| 80 | +import com.oracle.truffle.api.profiles.LoopConditionProfile; |
79 | 81 | import org.jcodings.Config;
|
80 | 82 | import org.jcodings.Encoding;
|
81 | 83 | import org.jcodings.specific.ASCIIEncoding;
|
|
100 | 102 | import org.truffleruby.core.cast.BooleanCastNode;
|
101 | 103 | import org.truffleruby.core.cast.ToIntNode;
|
102 | 104 | import org.truffleruby.core.cast.ToLongNode;
|
| 105 | +import org.truffleruby.core.cast.ToRopeNodeGen; |
103 | 106 | import org.truffleruby.core.cast.ToStrNode;
|
104 | 107 | import org.truffleruby.core.cast.ToStrNodeGen;
|
105 | 108 | import org.truffleruby.core.encoding.EncodingLeftCharHeadNode;
|
@@ -4461,42 +4464,88 @@ protected Object stringCharacterIndex(Object string, Object pattern, int offset,
|
4461 | 4464 | }
|
4462 | 4465 |
|
4463 | 4466 | @Primitive(name = "string_byte_index", lowerFixnum = 2)
|
4464 |
| - public abstract static class StringByteIndexPrimitiveNode extends PrimitiveArrayArgumentsNode { |
| 4467 | + @NodeChild(value = "string", type = RubyNode.class) |
| 4468 | + @NodeChild(value = "pattern", type = RubyNode.class) |
| 4469 | + @NodeChild(value = "offset", type = RubyNode.class) |
| 4470 | + public abstract static class StringByteIndexPrimitiveNode extends PrimitiveNode { |
4465 | 4471 |
|
4466 |
| - @TruffleBoundary |
4467 |
| - @Specialization |
4468 |
| - protected Object stringCharacterIndex(Object string, Object pattern, int offset, |
4469 |
| - @Cached RopeNodes.CalculateCharacterLengthNode calculateCharacterLengthNode, |
4470 |
| - @CachedLibrary(limit = "2") RubyStringLibrary libString, |
4471 |
| - @CachedLibrary(limit = "2") RubyStringLibrary libPattern) { |
4472 |
| - if (offset < 0) { |
4473 |
| - return nil; |
4474 |
| - } |
| 4472 | + @Child SingleByteOptimizableNode singleByteOptimizableNode = SingleByteOptimizableNode.create(); |
4475 | 4473 |
|
4476 |
| - final Rope stringRope = libString.getRope(string); |
4477 |
| - final Rope patternRope = libPattern.getRope(pattern); |
| 4474 | + @CreateCast("string") |
| 4475 | + protected RubyNode coerceStringToRope(RubyNode string) { |
| 4476 | + return ToRopeNodeGen.create(string); |
| 4477 | + } |
4478 | 4478 |
|
4479 |
| - final int total = stringRope.byteLength(); |
4480 |
| - int p = 0; |
4481 |
| - final int e = p + total; |
| 4479 | + @CreateCast("pattern") |
| 4480 | + protected RubyNode coercePatternToRope(RubyNode pattern) { |
| 4481 | + return ToRopeNodeGen.create(pattern); |
| 4482 | + } |
| 4483 | + |
| 4484 | + @Specialization(guards = "offset < 0") |
| 4485 | + protected Object stringByteIndexNegativeOffset(Rope stringRope, Rope patternRope, int offset) { |
| 4486 | + return nil; |
| 4487 | + } |
| 4488 | + |
| 4489 | + @Specialization( |
| 4490 | + guards = { |
| 4491 | + "offset >= 0", |
| 4492 | + "singleByteOptimizableNode.execute(stringRope)", |
| 4493 | + "patternRope.byteLength() > stringRope.byteLength()" }) |
| 4494 | + protected Object stringByteIndexPatternTooLarge(Rope stringRope, Rope patternRope, int offset) { |
| 4495 | + return nil; |
| 4496 | + } |
| 4497 | + |
| 4498 | + @Specialization( |
| 4499 | + guards = { |
| 4500 | + "offset >= 0", |
| 4501 | + "singleByteOptimizableNode.execute(stringRope)", |
| 4502 | + "patternRope.byteLength() <= stringRope.byteLength()" }) |
| 4503 | + protected Object stringCharacterIndexSingleByteOptimizable(Rope stringRope, Rope patternRope, int offset, |
| 4504 | + @Cached RopeNodes.BytesNode stringBytesNode, |
| 4505 | + @Cached RopeNodes.BytesNode patternBytesNode, |
| 4506 | + @Cached LoopConditionProfile loopProfile, |
| 4507 | + @Cached("createCountingProfile()") ConditionProfile matchProfile) { |
| 4508 | + |
| 4509 | + int p = offset; |
| 4510 | + final int e = stringRope.byteLength(); |
4482 | 4511 | final int pe = patternRope.byteLength();
|
4483 | 4512 | final int l = e - pe + 1;
|
4484 | 4513 |
|
4485 |
| - final byte[] stringBytes = stringRope.getBytes(); |
4486 |
| - final byte[] patternBytes = patternRope.getBytes(); |
4487 |
| - |
4488 |
| - p += offset; |
| 4514 | + final byte[] stringBytes = stringBytesNode.execute(stringRope); |
| 4515 | + final byte[] patternBytes = patternBytesNode.execute(patternRope); |
4489 | 4516 |
|
4490 |
| - if (stringRope.isSingleByteOptimizable()) { |
4491 |
| - for (; p < l; p++) { |
4492 |
| - if (ArrayUtils.memcmp(stringBytes, p, patternBytes, 0, pe) == 0) { |
| 4517 | + try { |
| 4518 | + for (; loopProfile.profile(p < l); p++) { |
| 4519 | + if (matchProfile.profile(ArrayUtils.memcmp(stringBytes, p, patternBytes, 0, pe) == 0)) { |
4493 | 4520 | return p;
|
4494 | 4521 | }
|
4495 | 4522 | }
|
4496 |
| - |
4497 |
| - return nil; |
| 4523 | + } finally { |
| 4524 | + LoopNode.reportLoopCount(this, p - offset); |
4498 | 4525 | }
|
4499 | 4526 |
|
| 4527 | + return nil; |
| 4528 | + } |
| 4529 | + |
| 4530 | + @TruffleBoundary |
| 4531 | + @Specialization( |
| 4532 | + guards = { |
| 4533 | + "offset >= 0", |
| 4534 | + "!singleByteOptimizableNode.execute(stringRope)", |
| 4535 | + "patternRope.byteLength() <= stringRope.byteLength()" }) |
| 4536 | + protected Object stringCharacterIndex(Rope stringRope, Rope patternRope, int offset, |
| 4537 | + @Cached RopeNodes.CalculateCharacterLengthNode calculateCharacterLengthNode, |
| 4538 | + @Cached RopeNodes.BytesNode stringBytesNode, |
| 4539 | + @Cached RopeNodes.BytesNode patternBytesNode) { |
| 4540 | + |
| 4541 | + int p = offset; |
| 4542 | + final int e = stringRope.byteLength(); |
| 4543 | + final int pe = patternRope.byteLength(); |
| 4544 | + final int l = e - pe + 1; |
| 4545 | + |
| 4546 | + final byte[] stringBytes = stringBytesNode.execute(stringRope); |
| 4547 | + final byte[] patternBytes = patternBytesNode.execute(patternRope); |
| 4548 | + |
4500 | 4549 | final Encoding enc = stringRope.getEncoding();
|
4501 | 4550 | final CodeRange cr = stringRope.getCodeRange();
|
4502 | 4551 | int c = 0;
|
|
0 commit comments