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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/lib/string_patch.dart » ('j') | runtime/lib/string_patch.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/bootstrap_natives.h" 5 #include "vm/bootstrap_natives.h"
6 6
7 #include "include/dart_api.h" 7 #include "include/dart_api.h"
8 #include "vm/exceptions.h" 8 #include "vm/exceptions.h"
9 #include "vm/dart_api_impl.h" 9 #include "vm/dart_api_impl.h"
10 #include "vm/isolate.h" 10 #include "vm/isolate.h"
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 const String& receiver = String::CheckedHandle(arguments->NativeArgAt(0)); 96 const String& receiver = String::CheckedHandle(arguments->NativeArgAt(0));
97 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); 97 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1));
98 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); 98 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2));
99 99
100 intptr_t start = start_obj.Value(); 100 intptr_t start = start_obj.Value();
101 intptr_t end = end_obj.Value(); 101 intptr_t end = end_obj.Value();
102 return String::SubString(receiver, start, (end - start)); 102 return String::SubString(receiver, start, (end - start));
103 } 103 }
104 104
105 105
106
107 // Return the bitwise-or of all characters in the slice from start to end.
108 static uint16_t CharacterLimit(const String& string,
109 intptr_t start, intptr_t end) {
110 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.
111 // Maybe do loop unrolling, and handle two uint16_t in a single uint32_t
112 // operation.
113 NoGCScope no_gc;
114 uint16_t result = 0;
115 for (intptr_t i = start; i < end; i++) {
116 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
117 }
118 return result;
119 }
120
121
122 DEFINE_NATIVE_ENTRY(StringBase_joinReplaceAllResult, 4) {
123 const String& base = String::CheckedHandle(arguments->NativeArgAt(0));
124 GET_NON_NULL_NATIVE_ARGUMENT(GrowableObjectArray,
125 matches_growable, arguments->NativeArgAt(1));
126 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(2));
127 GET_NON_NULL_NATIVE_ARGUMENT(Bool, is_onebyte_obj, arguments->NativeArgAt(3));
128
129 intptr_t len = matches_growable.Length();
130 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
131
132 const intptr_t kLengthShift = 15;
133 const intptr_t kStartMask = (1 << kLengthShift) - 1;
134
135 const intptr_t length = length_obj.Value();
136 if (length < 0) {
137 Exceptions::ThrowArgumentError(length_obj);
138 }
139
140 // Start out assuming result is one-byte if replacements are.
141 bool is_onebyte = is_onebyte_obj.value();
142 if (is_onebyte) {
143 // If any of the base string slices are not one-byte, the result will be
144 // a two-byte string.
145 if (!base.IsOneByteString() && !base.IsExternalOneByteString()) {
146 Instance& object = Instance::Handle();
147 // Check each slice for one-bytedness.
148 for (intptr_t i = 0; i < len; i++) {
149 object ^= matches.At(i);
150 if (object.IsSmi()) {
151 intptr_t slice_start = Smi::Cast(object).Value();
152 intptr_t slice_end;
153 if (slice_start < 0) {
154 intptr_t bits = -slice_start;
155 slice_start = bits & kStartMask;
156 slice_end = slice_start + (bits >> kLengthShift);
157 } else {
158 i++;
159 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.
160 if (!object.IsSmi()) {
161 // Should fail, but just continue and handle the failure later.
162 // This branch isn't called in all cases.
163 is_onebyte = false;
164 break;
165 }
166 slice_end = Smi::Cast(object).Value();
167 }
168 uint16_t char_limit = CharacterLimit(base, slice_start, slice_end);
169 if (char_limit > 0xff) {
170 is_onebyte = false;
171 break;
172 }
173 }
174 }
175 }
176 }
177
178 const intptr_t base_length = base.Length();
179 String& result = String::Handle();
180 if (is_onebyte) {
181 result ^= OneByteString::New(length, Heap::kNew);
182 } else {
183 result ^= TwoByteString::New(length, Heap::kNew);
184 }
185 Instance& object = Instance::Handle();
186 intptr_t writeIndex = 0;
187 for (intptr_t i = 0; i < len; i++) {
188 object ^= matches.At(i);
189 if (object.IsSmi()) {
190 intptr_t slice_start = Smi::Cast(object).Value();
191 intptr_t slice_length = -1;
192 // Slices with limited ranges are stored in a single negative Smi.
193 if (slice_start < 0) {
194 intptr_t bits = -slice_start;
195 slice_start = bits & kStartMask;
196 slice_length = bits >> kLengthShift;
197 } else {
198 i++;
199 if (i < len) {
200 object ^= matches.At(i);
201 if (object.IsSmi()) {
202 intptr_t slice_end = Smi::Cast(object).Value();
203 slice_length = slice_end - slice_start;
204 }
205 }
206 }
207 if (slice_length > 0) {
208 if (0 <= slice_start &&
209 slice_start + slice_length <= base_length &&
210 writeIndex + slice_length <= length) {
211 String::Copy(result, writeIndex,
212 base, slice_start,
213 slice_length);
214 writeIndex += slice_length;
215 continue;
216 }
217 }
218 // Either the slice_length was zero,
219 // or the first smi was positive and not followed by another smi,
220 // or the smis were not a valid slice of the base string,
221 // or the slice was too large to fit in the result.
222 // Something is wrong with the matches array!
223 Exceptions::ThrowArgumentError(matches);
224 } else if (object.IsString()) {
225 const String& replacement = String::Cast(object);
226 intptr_t replacement_length = replacement.Length();
227 if (writeIndex + replacement_length > length) {
228 // Invalid input data, either in matches list or the total length.
229 Exceptions::ThrowArgumentError(matches);
230 }
231 String::Copy(result, writeIndex, replacement, 0, replacement_length);
232 writeIndex += replacement_length;
233 }
234 }
235 if (writeIndex < length) {
236 Exceptions::ThrowArgumentError(matches);
237 }
238 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
239 }
240
106 DEFINE_NATIVE_ENTRY(OneByteString_substringUnchecked, 3) { 241 DEFINE_NATIVE_ENTRY(OneByteString_substringUnchecked, 3) {
107 const String& receiver = String::CheckedHandle(arguments->NativeArgAt(0)); 242 const String& receiver = String::CheckedHandle(arguments->NativeArgAt(0));
108 ASSERT(receiver.IsOneByteString()); 243 ASSERT(receiver.IsOneByteString());
109 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); 244 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1));
110 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); 245 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2));
111 246
112 const intptr_t start = start_obj.Value(); 247 const intptr_t start = start_obj.Value();
113 const intptr_t end = end_obj.Value(); 248 const intptr_t end = end_obj.Value();
114 return OneByteString::New(receiver, start, end - start, Heap::kNew); 249 return OneByteString::New(receiver, start, end - start, Heap::kNew);
115 } 250 }
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 ? String::Handle(OneByteString::New(length_value, Heap::kNew)) 509 ? String::Handle(OneByteString::New(length_value, Heap::kNew))
375 : String::Handle(TwoByteString::New(length_value, Heap::kNew)); 510 : String::Handle(TwoByteString::New(length_value, Heap::kNew));
376 NoGCScope no_gc; 511 NoGCScope no_gc;
377 512
378 uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.DataAddr(0)); 513 uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.DataAddr(0));
379 String::Copy(result, 0, data_position, length_value); 514 String::Copy(result, 0, data_position, length_value);
380 return result.raw(); 515 return result.raw();
381 } 516 }
382 517
383 } // namespace dart 518 } // namespace dart
OLDNEW
« 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