Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(711)

Unified Diff: runtime/lib/string.cc

Issue 858543002: Avoid extra duplication of substrings during string.replaceAll. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Also do replaceAllMapped. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | runtime/lib/string_patch.dart » ('j') | runtime/lib/string_patch.dart » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/lib/string.cc
diff --git a/runtime/lib/string.cc b/runtime/lib/string.cc
index 5b450f4a71adf581e2bf87f04e07698e365f575d..5c05ace4b08f43a0e900ffdbd04c429e5bc71554 100644
--- a/runtime/lib/string.cc
+++ b/runtime/lib/string.cc
@@ -103,6 +103,141 @@ DEFINE_NATIVE_ENTRY(StringBase_substringUnchecked, 3) {
}
+
+// Return the bitwise-or of all characters in the slice from start to end.
+static uint16_t CharacterLimit(const String& string,
+ intptr_t start, intptr_t end) {
+ ASSERT(string.IsTwoByteString() ||string.IsExternalTwoByteString());
zerny-google 2015/01/20 13:43:11 Nit: space after ||
Lasse Reichstein Nielsen 2015/01/21 10:48:43 Done.
+ // Maybe do loop unrolling, and handle two uint16_t in a single uint32_t
+ // operation.
+ NoGCScope no_gc;
+ uint16_t result = 0;
+ for (intptr_t i = start; i < end; i++) {
+ result |= TwoByteString::CharAt(string, i);
Florian Schneider 2015/01/20 16:39:33 This should be ExternalTwoByteString::CharAt in th
Lasse Reichstein Nielsen 2015/01/21 10:48:43 Done. Is there a simple way to get the uint16_t* o
+ }
+ return result;
+}
+
+
+DEFINE_NATIVE_ENTRY(StringBase_joinReplaceAllResult, 4) {
+ const String& base = String::CheckedHandle(arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(GrowableObjectArray,
+ matches_growable, arguments->NativeArgAt(1));
+ GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(2));
+ GET_NON_NULL_NATIVE_ARGUMENT(Bool, is_onebyte_obj, arguments->NativeArgAt(3));
+
+ intptr_t len = matches_growable.Length();
+ const Array& matches = Array::Handle(matches_growable.data());
siva 2015/01/21 00:29:20 Since 'isolate' is available to the native method
Lasse Reichstein Nielsen 2015/01/21 10:48:43 Done in this code. The rest of the file could do i
+
+ const intptr_t kLengthShift = 15;
+ const intptr_t kStartMask = (1 << kLengthShift) - 1;
+
+ const intptr_t length = length_obj.Value();
+ if (length < 0) {
+ Exceptions::ThrowArgumentError(length_obj);
+ }
+
+ // Start out assuming result is one-byte if replacements are.
+ bool is_onebyte = is_onebyte_obj.value();
+ if (is_onebyte) {
+ // If any of the base string slices are not one-byte, the result will be
+ // a two-byte string.
+ if (!base.IsOneByteString() && !base.IsExternalOneByteString()) {
+ Instance& object = Instance::Handle();
+ // Check each slice for one-bytedness.
+ for (intptr_t i = 0; i < len; i++) {
+ object ^= matches.At(i);
+ if (object.IsSmi()) {
+ intptr_t slice_start = Smi::Cast(object).Value();
+ intptr_t slice_end;
+ if (slice_start < 0) {
+ intptr_t bits = -slice_start;
+ slice_start = bits & kStartMask;
+ slice_end = slice_start + (bits >> kLengthShift);
+ } else {
+ i++;
+ object ^= matches.At(i);
siva 2015/01/21 00:29:20 Missing check for if (i < len) here?
Lasse Reichstein Nielsen 2015/01/21 10:48:43 Done.
+ if (!object.IsSmi()) {
+ // Should fail, but just continue and handle the failure later.
+ // This branch isn't called in all cases.
+ is_onebyte = false;
+ break;
+ }
+ slice_end = Smi::Cast(object).Value();
+ }
+ uint16_t char_limit = CharacterLimit(base, slice_start, slice_end);
+ if (char_limit > 0xff) {
+ is_onebyte = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ const intptr_t base_length = base.Length();
+ String& result = String::Handle();
+ if (is_onebyte) {
+ result ^= OneByteString::New(length, Heap::kNew);
+ } else {
+ result ^= TwoByteString::New(length, Heap::kNew);
+ }
+ Instance& object = Instance::Handle();
+ intptr_t writeIndex = 0;
+ for (intptr_t i = 0; i < len; i++) {
+ object ^= matches.At(i);
+ if (object.IsSmi()) {
+ intptr_t slice_start = Smi::Cast(object).Value();
+ intptr_t slice_length = -1;
+ // Slices with limited ranges are stored in a single negative Smi.
+ if (slice_start < 0) {
+ intptr_t bits = -slice_start;
+ slice_start = bits & kStartMask;
+ slice_length = bits >> kLengthShift;
+ } else {
+ i++;
+ if (i < len) {
+ object ^= matches.At(i);
+ if (object.IsSmi()) {
+ intptr_t slice_end = Smi::Cast(object).Value();
+ slice_length = slice_end - slice_start;
+ }
+ }
+ }
+ if (slice_length > 0) {
+ if (0 <= slice_start &&
+ slice_start + slice_length <= base_length &&
+ writeIndex + slice_length <= length) {
+ String::Copy(result, writeIndex,
+ base, slice_start,
+ slice_length);
+ writeIndex += slice_length;
+ continue;
+ }
+ }
+ // Either the slice_length was zero,
+ // or the first smi was positive and not followed by another smi,
+ // or the smis were not a valid slice of the base string,
+ // or the slice was too large to fit in the result.
+ // Something is wrong with the matches array!
+ Exceptions::ThrowArgumentError(matches);
+ } else if (object.IsString()) {
+ const String& replacement = String::Cast(object);
+ intptr_t replacement_length = replacement.Length();
+ if (writeIndex + replacement_length > length) {
+ // Invalid input data, either in matches list or the total length.
+ Exceptions::ThrowArgumentError(matches);
+ }
+ String::Copy(result, writeIndex, replacement, 0, replacement_length);
+ writeIndex += replacement_length;
+ }
+ }
+ if (writeIndex < length) {
+ Exceptions::ThrowArgumentError(matches);
+ }
+ return result.raw();
siva 2015/01/21 00:29:20 This function seems to be long, do you think it wo
Lasse Reichstein Nielsen 2015/01/21 10:48:43 I think I'll move the first loop into a helper met
+}
+
DEFINE_NATIVE_ENTRY(OneByteString_substringUnchecked, 3) {
const String& receiver = String::CheckedHandle(arguments->NativeArgAt(0));
ASSERT(receiver.IsOneByteString());
« no previous file with comments | « no previous file | runtime/lib/string_patch.dart » ('j') | runtime/lib/string_patch.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698