OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |