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