Chromium Code Reviews| 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 |