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

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: 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') | no next file with comments »
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());
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 if (string.IsTwoByteString()) {
116 for (intptr_t i = start; i < end; i++) {
117 result |= TwoByteString::CharAt(string, i);
118 }
119 } else {
120 for (intptr_t i = start; i < end; i++) {
121 result |= ExternalTwoByteString::CharAt(string, i);
122 }
123 }
124 return result;
125 }
126
127 static const intptr_t kLengthSize = 11;
128 static const intptr_t kLengthMask = (1 << kLengthSize) - 1;
129
130 static bool CheckSlicesOneByte(const String& base,
131 const Array& matches,
132 const int len) {
133 Instance& object = Instance::Handle();
134 // Check each slice for one-bytedness.
135 for (intptr_t i = 0; i < len; i++) {
136 object ^= matches.At(i);
137 if (object.IsSmi()) {
138 intptr_t slice_start = Smi::Cast(object).Value();
139 intptr_t slice_end;
140 if (slice_start < 0) {
141 intptr_t bits = -slice_start;
142 slice_start = bits >> kLengthSize;
143 slice_end = slice_start + (bits & kLengthMask);
144 } else {
145 i++;
146 if (i >= len) {
147 // Bad format, handled later.
148 return false;
149 }
150 object ^= matches.At(i);
151 if (!object.IsSmi()) {
152 // Bad format, handled later.
153 return false;
154 }
155 slice_end = Smi::Cast(object).Value();
156 }
157 uint16_t char_limit = CharacterLimit(base, slice_start, slice_end);
158 if (char_limit > 0xff) {
159 return false;
160 }
161 }
162 }
163 return true;
164 }
165
166
167 DEFINE_NATIVE_ENTRY(StringBase_joinReplaceAllResult, 4) {
168 const String& base = String::CheckedHandle(arguments->NativeArgAt(0));
169 GET_NON_NULL_NATIVE_ARGUMENT(GrowableObjectArray,
170 matches_growable, arguments->NativeArgAt(1));
171 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(2));
172 GET_NON_NULL_NATIVE_ARGUMENT(Bool, is_onebyte_obj, arguments->NativeArgAt(3));
173
174 intptr_t len = matches_growable.Length();
175 const Array& matches = Array::Handle(isolate, matches_growable.data());
176
177 const intptr_t length = length_obj.Value();
178 if (length < 0) {
179 Exceptions::ThrowArgumentError(length_obj);
180 }
181
182 // Start out assuming result is one-byte if replacements are.
183 bool is_onebyte = is_onebyte_obj.value();
184 if (is_onebyte) {
185 // If any of the base string slices are not one-byte, the result will be
186 // a two-byte string.
187 if (!base.IsOneByteString() && !base.IsExternalOneByteString()) {
188 is_onebyte = CheckSlicesOneByte(base, matches, len);
189 }
190 }
191
192 const intptr_t base_length = base.Length();
193 String& result = String::Handle(isolate);
194 if (is_onebyte) {
195 result ^= OneByteString::New(length, Heap::kNew);
196 } else {
197 result ^= TwoByteString::New(length, Heap::kNew);
198 }
199 Instance& object = Instance::Handle(isolate);
200 intptr_t write_index = 0;
201 for (intptr_t i = 0; i < len; i++) {
202 object ^= matches.At(i);
203 if (object.IsSmi()) {
204 intptr_t slice_start = Smi::Cast(object).Value();
205 intptr_t slice_length = -1;
206 // Slices with limited ranges are stored in a single negative Smi.
207 if (slice_start < 0) {
208 intptr_t bits = -slice_start;
209 slice_start = bits >> kLengthSize;
210 slice_length = bits & kLengthMask;
211 } else {
212 i++;
213 if (i < len) { // Otherwise slice_length stays at -1.
214 object ^= matches.At(i);
215 if (object.IsSmi()) {
216 intptr_t slice_end = Smi::Cast(object).Value();
217 slice_length = slice_end - slice_start;
218 }
219 }
220 }
221 if (slice_length > 0) {
222 if (0 <= slice_start &&
223 slice_start + slice_length <= base_length &&
224 write_index + slice_length <= length) {
225 String::Copy(result, write_index,
226 base, slice_start,
227 slice_length);
228 write_index += slice_length;
229 continue;
230 }
231 }
232 // Either the slice_length was zero,
233 // or the first smi was positive and not followed by another smi,
234 // or the smis were not a valid slice of the base string,
235 // or the slice was too large to fit in the result.
236 // Something is wrong with the matches array!
237 Exceptions::ThrowArgumentError(matches_growable);
238 } else if (object.IsString()) {
239 const String& replacement = String::Cast(object);
240 intptr_t replacement_length = replacement.Length();
241 if (write_index + replacement_length > length) {
242 // Invalid input data, either in matches list or the total length.
243 Exceptions::ThrowArgumentError(matches_growable);
244 }
245 String::Copy(result, write_index, replacement, 0, replacement_length);
246 write_index += replacement_length;
247 }
248 }
249 if (write_index < length) {
250 Exceptions::ThrowArgumentError(matches_growable);
251 }
252 return result.raw();
253 }
254
106 DEFINE_NATIVE_ENTRY(OneByteString_substringUnchecked, 3) { 255 DEFINE_NATIVE_ENTRY(OneByteString_substringUnchecked, 3) {
107 const String& receiver = String::CheckedHandle(arguments->NativeArgAt(0)); 256 const String& receiver = String::CheckedHandle(arguments->NativeArgAt(0));
108 ASSERT(receiver.IsOneByteString()); 257 ASSERT(receiver.IsOneByteString());
109 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); 258 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1));
110 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); 259 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2));
111 260
112 const intptr_t start = start_obj.Value(); 261 const intptr_t start = start_obj.Value();
113 const intptr_t end = end_obj.Value(); 262 const intptr_t end = end_obj.Value();
114 return OneByteString::New(receiver, start, end - start, Heap::kNew); 263 return OneByteString::New(receiver, start, end - start, Heap::kNew);
115 } 264 }
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 ? String::Handle(OneByteString::New(length_value, Heap::kNew)) 523 ? String::Handle(OneByteString::New(length_value, Heap::kNew))
375 : String::Handle(TwoByteString::New(length_value, Heap::kNew)); 524 : String::Handle(TwoByteString::New(length_value, Heap::kNew));
376 NoGCScope no_gc; 525 NoGCScope no_gc;
377 526
378 uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.DataAddr(0)); 527 uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.DataAddr(0));
379 String::Copy(result, 0, data_position, length_value); 528 String::Copy(result, 0, data_position, length_value);
380 return result.raw(); 529 return result.raw();
381 } 530 }
382 531
383 } // namespace dart 532 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | runtime/lib/string_patch.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698