OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 1188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1199 result = flat; | 1199 result = flat; |
1200 } else { | 1200 } else { |
1201 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString( | 1201 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString( |
1202 length, tenure).ToHandleChecked(); | 1202 length, tenure).ToHandleChecked(); |
1203 DisallowHeapAllocation no_gc; | 1203 DisallowHeapAllocation no_gc; |
1204 WriteToFlat(*cons, flat->GetChars(), 0, length); | 1204 WriteToFlat(*cons, flat->GetChars(), 0, length); |
1205 result = flat; | 1205 result = flat; |
1206 } | 1206 } |
1207 cons->set_first(*result); | 1207 cons->set_first(*result); |
1208 cons->set_second(isolate->heap()->empty_string()); | 1208 cons->set_second(isolate->heap()->empty_string()); |
| 1209 ASSERT(result->IsFlat()); |
1209 return result; | 1210 return result; |
1210 } | 1211 } |
1211 | 1212 |
1212 | 1213 |
1213 MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) { | |
1214 #ifdef DEBUG | |
1215 // Do not attempt to flatten in debug mode when allocation is not | |
1216 // allowed. This is to avoid an assertion failure when allocating. | |
1217 // Flattening strings is the only case where we always allow | |
1218 // allocation because no GC is performed if the allocation fails. | |
1219 if (!AllowHeapAllocation::IsAllowed()) return this; | |
1220 #endif | |
1221 | |
1222 Heap* heap = GetHeap(); | |
1223 switch (StringShape(this).representation_tag()) { | |
1224 case kConsStringTag: { | |
1225 ConsString* cs = ConsString::cast(this); | |
1226 if (cs->second()->length() == 0) { | |
1227 return cs->first(); | |
1228 } | |
1229 // There's little point in putting the flat string in new space if the | |
1230 // cons string is in old space. It can never get GCed until there is | |
1231 // an old space GC. | |
1232 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED; | |
1233 int len = length(); | |
1234 Object* object; | |
1235 String* result; | |
1236 if (IsOneByteRepresentation()) { | |
1237 { MaybeObject* maybe_object = | |
1238 heap->AllocateRawOneByteString(len, tenure); | |
1239 if (!maybe_object->ToObject(&object)) return maybe_object; | |
1240 } | |
1241 result = String::cast(object); | |
1242 String* first = cs->first(); | |
1243 int first_length = first->length(); | |
1244 uint8_t* dest = SeqOneByteString::cast(result)->GetChars(); | |
1245 WriteToFlat(first, dest, 0, first_length); | |
1246 String* second = cs->second(); | |
1247 WriteToFlat(second, | |
1248 dest + first_length, | |
1249 0, | |
1250 len - first_length); | |
1251 } else { | |
1252 { MaybeObject* maybe_object = | |
1253 heap->AllocateRawTwoByteString(len, tenure); | |
1254 if (!maybe_object->ToObject(&object)) return maybe_object; | |
1255 } | |
1256 result = String::cast(object); | |
1257 uc16* dest = SeqTwoByteString::cast(result)->GetChars(); | |
1258 String* first = cs->first(); | |
1259 int first_length = first->length(); | |
1260 WriteToFlat(first, dest, 0, first_length); | |
1261 String* second = cs->second(); | |
1262 WriteToFlat(second, | |
1263 dest + first_length, | |
1264 0, | |
1265 len - first_length); | |
1266 } | |
1267 cs->set_first(result); | |
1268 cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER); | |
1269 return result; | |
1270 } | |
1271 default: | |
1272 return this; | |
1273 } | |
1274 } | |
1275 | |
1276 | 1214 |
1277 bool String::MakeExternal(v8::String::ExternalStringResource* resource) { | 1215 bool String::MakeExternal(v8::String::ExternalStringResource* resource) { |
1278 // Externalizing twice leaks the external resource, so it's | 1216 // Externalizing twice leaks the external resource, so it's |
1279 // prohibited by the API. | 1217 // prohibited by the API. |
1280 ASSERT(!this->IsExternalString()); | 1218 ASSERT(!this->IsExternalString()); |
1281 #ifdef ENABLE_SLOW_ASSERTS | 1219 #ifdef ENABLE_SLOW_ASSERTS |
1282 if (FLAG_enable_slow_asserts) { | 1220 if (FLAG_enable_slow_asserts) { |
1283 // Assert that the resource and the string are equivalent. | 1221 // Assert that the resource and the string are equivalent. |
1284 ASSERT(static_cast<size_t>(this->length()) == resource->length()); | 1222 ASSERT(static_cast<size_t>(this->length()) == resource->length()); |
1285 ScopedVector<uc16> smart_chars(this->length()); | 1223 ScopedVector<uc16> smart_chars(this->length()); |
(...skipping 4747 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6033 for (int i = 0; i < number_of_own_descriptors; i++) { | 5971 for (int i = 0; i < number_of_own_descriptors; i++) { |
6034 if (descs->GetType(i) == FIELD) { | 5972 if (descs->GetType(i) == FIELD) { |
6035 int current_index = descs->GetFieldIndex(i); | 5973 int current_index = descs->GetFieldIndex(i); |
6036 if (current_index > max_index) max_index = current_index; | 5974 if (current_index > max_index) max_index = current_index; |
6037 } | 5975 } |
6038 } | 5976 } |
6039 return max_index + 1; | 5977 return max_index + 1; |
6040 } | 5978 } |
6041 | 5979 |
6042 | 5980 |
6043 AccessorDescriptor* Map::FindAccessor(Name* name) { | |
6044 DescriptorArray* descs = instance_descriptors(); | |
6045 int number_of_own_descriptors = NumberOfOwnDescriptors(); | |
6046 for (int i = 0; i < number_of_own_descriptors; i++) { | |
6047 if (descs->GetType(i) == CALLBACKS && name->Equals(descs->GetKey(i))) { | |
6048 return descs->GetCallbacks(i); | |
6049 } | |
6050 } | |
6051 return NULL; | |
6052 } | |
6053 | |
6054 | |
6055 void JSReceiver::LocalLookup( | 5981 void JSReceiver::LocalLookup( |
6056 Name* name, LookupResult* result, bool search_hidden_prototypes) { | 5982 Name* name, LookupResult* result, bool search_hidden_prototypes) { |
6057 ASSERT(name->IsName()); | 5983 ASSERT(name->IsName()); |
6058 | 5984 |
6059 Heap* heap = GetHeap(); | 5985 Heap* heap = GetHeap(); |
6060 | 5986 |
6061 if (IsJSGlobalProxy()) { | 5987 if (IsJSGlobalProxy()) { |
6062 Object* proto = GetPrototype(); | 5988 Object* proto = GetPrototype(); |
6063 if (proto->IsNull()) return result->NotFound(); | 5989 if (proto->IsNull()) return result->NotFound(); |
6064 ASSERT(proto->IsJSGlobalObject()); | 5990 ASSERT(proto->IsJSGlobalObject()); |
(...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6550 component, accessor, attributes); | 6476 component, accessor, attributes); |
6551 } | 6477 } |
6552 } else { | 6478 } else { |
6553 // If not, lookup a transition. | 6479 // If not, lookup a transition. |
6554 object->map()->LookupTransition(*object, *name, &result); | 6480 object->map()->LookupTransition(*object, *name, &result); |
6555 | 6481 |
6556 // If there is a transition, try to follow it. | 6482 // If there is a transition, try to follow it. |
6557 if (result.IsFound()) { | 6483 if (result.IsFound()) { |
6558 Handle<Map> target(result.GetTransitionTarget()); | 6484 Handle<Map> target(result.GetTransitionTarget()); |
6559 int descriptor_number = target->LastAdded(); | 6485 int descriptor_number = target->LastAdded(); |
6560 ASSERT(target->instance_descriptors()->GetKey(descriptor_number) | 6486 ASSERT(Name::Equals(name, |
6561 ->Equals(*name)); | 6487 handle(target->instance_descriptors()->GetKey(descriptor_number)))); |
6562 return TryAccessorTransition(object, target, descriptor_number, | 6488 return TryAccessorTransition(object, target, descriptor_number, |
6563 component, accessor, attributes); | 6489 component, accessor, attributes); |
6564 } | 6490 } |
6565 } | 6491 } |
6566 | 6492 |
6567 // If there is no transition yet, add a transition to the a new accessor pair | 6493 // If there is no transition yet, add a transition to the a new accessor pair |
6568 // containing the accessor. Allocate a new pair if there were no source | 6494 // containing the accessor. Allocate a new pair if there were no source |
6569 // accessors. Otherwise, copy the pair and modify the accessor. | 6495 // accessors. Otherwise, copy the pair and modify the accessor. |
6570 Handle<AccessorPair> accessors = source_accessors != NULL | 6496 Handle<AccessorPair> accessors = source_accessors != NULL |
6571 ? AccessorPair::Copy(Handle<AccessorPair>(source_accessors)) | 6497 ? AccessorPair::Copy(Handle<AccessorPair>(source_accessors)) |
(...skipping 1799 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8371 ASSERT(shape.representation_tag() != kConsStringTag && | 8297 ASSERT(shape.representation_tag() != kConsStringTag && |
8372 shape.representation_tag() != kSlicedStringTag); | 8298 shape.representation_tag() != kSlicedStringTag); |
8373 } | 8299 } |
8374 if (shape.encoding_tag() == kOneByteStringTag) { | 8300 if (shape.encoding_tag() == kOneByteStringTag) { |
8375 const uint8_t* start; | 8301 const uint8_t* start; |
8376 if (shape.representation_tag() == kSeqStringTag) { | 8302 if (shape.representation_tag() == kSeqStringTag) { |
8377 start = SeqOneByteString::cast(string)->GetChars(); | 8303 start = SeqOneByteString::cast(string)->GetChars(); |
8378 } else { | 8304 } else { |
8379 start = ExternalAsciiString::cast(string)->GetChars(); | 8305 start = ExternalAsciiString::cast(string)->GetChars(); |
8380 } | 8306 } |
8381 return FlatContent(Vector<const uint8_t>(start + offset, length)); | 8307 return FlatContent(start + offset, length); |
8382 } else { | 8308 } else { |
8383 ASSERT(shape.encoding_tag() == kTwoByteStringTag); | 8309 ASSERT(shape.encoding_tag() == kTwoByteStringTag); |
8384 const uc16* start; | 8310 const uc16* start; |
8385 if (shape.representation_tag() == kSeqStringTag) { | 8311 if (shape.representation_tag() == kSeqStringTag) { |
8386 start = SeqTwoByteString::cast(string)->GetChars(); | 8312 start = SeqTwoByteString::cast(string)->GetChars(); |
8387 } else { | 8313 } else { |
8388 start = ExternalTwoByteString::cast(string)->GetChars(); | 8314 start = ExternalTwoByteString::cast(string)->GetChars(); |
8389 } | 8315 } |
8390 return FlatContent(Vector<const uc16>(start + offset, length)); | 8316 return FlatContent(start + offset, length); |
8391 } | 8317 } |
8392 } | 8318 } |
8393 | 8319 |
8394 | 8320 |
8395 SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls, | 8321 SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls, |
8396 RobustnessFlag robust_flag, | 8322 RobustnessFlag robust_flag, |
8397 int offset, | 8323 int offset, |
8398 int length, | 8324 int length, |
8399 int* length_return) { | 8325 int* length_return) { |
8400 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { | 8326 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { |
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9020 } | 8946 } |
9021 | 8947 |
9022 private: | 8948 private: |
9023 State state_1_; | 8949 State state_1_; |
9024 State state_2_; | 8950 State state_2_; |
9025 DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator); | 8951 DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator); |
9026 }; | 8952 }; |
9027 | 8953 |
9028 | 8954 |
9029 bool String::SlowEquals(String* other) { | 8955 bool String::SlowEquals(String* other) { |
| 8956 DisallowHeapAllocation no_gc; |
9030 // Fast check: negative check with lengths. | 8957 // Fast check: negative check with lengths. |
9031 int len = length(); | 8958 int len = length(); |
9032 if (len != other->length()) return false; | 8959 if (len != other->length()) return false; |
9033 if (len == 0) return true; | 8960 if (len == 0) return true; |
9034 | 8961 |
9035 // Fast check: if hash code is computed for both strings | 8962 // Fast check: if hash code is computed for both strings |
9036 // a fast negative check can be performed. | 8963 // a fast negative check can be performed. |
9037 if (HasHashCode() && other->HasHashCode()) { | 8964 if (HasHashCode() && other->HasHashCode()) { |
9038 #ifdef ENABLE_SLOW_ASSERTS | 8965 #ifdef ENABLE_SLOW_ASSERTS |
9039 if (FLAG_enable_slow_asserts) { | 8966 if (FLAG_enable_slow_asserts) { |
9040 if (Hash() != other->Hash()) { | 8967 if (Hash() != other->Hash()) { |
9041 bool found_difference = false; | 8968 bool found_difference = false; |
9042 for (int i = 0; i < len; i++) { | 8969 for (int i = 0; i < len; i++) { |
9043 if (Get(i) != other->Get(i)) { | 8970 if (Get(i) != other->Get(i)) { |
9044 found_difference = true; | 8971 found_difference = true; |
9045 break; | 8972 break; |
9046 } | 8973 } |
9047 } | 8974 } |
9048 ASSERT(found_difference); | 8975 ASSERT(found_difference); |
9049 } | 8976 } |
9050 } | 8977 } |
9051 #endif | 8978 #endif |
9052 if (Hash() != other->Hash()) return false; | 8979 if (Hash() != other->Hash()) return false; |
9053 } | 8980 } |
9054 | 8981 |
9055 // We know the strings are both non-empty. Compare the first chars | 8982 // We know the strings are both non-empty. Compare the first chars |
9056 // before we try to flatten the strings. | 8983 // before we try to flatten the strings. |
9057 if (this->Get(0) != other->Get(0)) return false; | 8984 if (this->Get(0) != other->Get(0)) return false; |
9058 | 8985 |
9059 String* lhs = this->TryFlattenGetString(); | |
9060 String* rhs = other->TryFlattenGetString(); | |
9061 | |
9062 // TODO(dcarney): Compare all types of flat strings with a Visitor. | 8986 // TODO(dcarney): Compare all types of flat strings with a Visitor. |
9063 if (StringShape(lhs).IsSequentialAscii() && | 8987 if (IsSeqOneByteString() && other->IsSeqOneByteString()) { |
9064 StringShape(rhs).IsSequentialAscii()) { | 8988 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars(); |
9065 const uint8_t* str1 = SeqOneByteString::cast(lhs)->GetChars(); | 8989 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars(); |
9066 const uint8_t* str2 = SeqOneByteString::cast(rhs)->GetChars(); | |
9067 return CompareRawStringContents(str1, str2, len); | 8990 return CompareRawStringContents(str1, str2, len); |
9068 } | 8991 } |
9069 | 8992 |
9070 Isolate* isolate = GetIsolate(); | 8993 Isolate* isolate = GetIsolate(); |
9071 StringComparator comparator(isolate->objects_string_compare_iterator_a(), | 8994 StringComparator comparator(isolate->objects_string_compare_iterator_a(), |
9072 isolate->objects_string_compare_iterator_b()); | 8995 isolate->objects_string_compare_iterator_b()); |
9073 | 8996 |
9074 return comparator.Equals(static_cast<unsigned>(len), lhs, rhs); | 8997 return comparator.Equals(static_cast<unsigned>(len), this, other); |
9075 } | 8998 } |
9076 | 8999 |
9077 | 9000 |
| 9001 bool String::SlowEquals(Handle<String> one, Handle<String> two) { |
| 9002 // Fast check: negative check with lengths. |
| 9003 int one_length = one->length(); |
| 9004 if (one_length != two->length()) return false; |
| 9005 if (one_length == 0) return true; |
| 9006 |
| 9007 // Fast check: if hash code is computed for both strings |
| 9008 // a fast negative check can be performed. |
| 9009 if (one->HasHashCode() && two->HasHashCode()) { |
| 9010 #ifdef ENABLE_SLOW_ASSERTS |
| 9011 if (FLAG_enable_slow_asserts) { |
| 9012 if (one->Hash() != two->Hash()) { |
| 9013 bool found_difference = false; |
| 9014 for (int i = 0; i < one_length; i++) { |
| 9015 if (one->Get(i) != two->Get(i)) { |
| 9016 found_difference = true; |
| 9017 break; |
| 9018 } |
| 9019 } |
| 9020 ASSERT(found_difference); |
| 9021 } |
| 9022 } |
| 9023 #endif |
| 9024 if (one->Hash() != two->Hash()) return false; |
| 9025 } |
| 9026 |
| 9027 // We know the strings are both non-empty. Compare the first chars |
| 9028 // before we try to flatten the strings. |
| 9029 if (one->Get(0) != two->Get(0)) return false; |
| 9030 |
| 9031 one = String::Flatten(one); |
| 9032 two = String::Flatten(two); |
| 9033 |
| 9034 DisallowHeapAllocation no_gc; |
| 9035 String::FlatContent flat1 = one->GetFlatContent(); |
| 9036 String::FlatContent flat2 = two->GetFlatContent(); |
| 9037 |
| 9038 if (flat1.IsAscii() && flat2.IsAscii()) { |
| 9039 return CompareRawStringContents(flat1.ToOneByteVector().start(), |
| 9040 flat2.ToOneByteVector().start(), |
| 9041 one_length); |
| 9042 } else { |
| 9043 for (int i = 0; i < one_length; i++) { |
| 9044 if (flat1.Get(i) != flat2.Get(i)) return false; |
| 9045 } |
| 9046 return true; |
| 9047 } |
| 9048 } |
| 9049 |
| 9050 |
9078 bool String::MarkAsUndetectable() { | 9051 bool String::MarkAsUndetectable() { |
9079 if (StringShape(this).IsInternalized()) return false; | 9052 if (StringShape(this).IsInternalized()) return false; |
9080 | 9053 |
9081 Map* map = this->map(); | 9054 Map* map = this->map(); |
9082 Heap* heap = GetHeap(); | 9055 Heap* heap = GetHeap(); |
9083 if (map == heap->string_map()) { | 9056 if (map == heap->string_map()) { |
9084 this->set_map(heap->undetectable_string_map()); | 9057 this->set_map(heap->undetectable_string_map()); |
9085 return true; | 9058 return true; |
9086 } else if (map == heap->ascii_string_map()) { | 9059 } else if (map == heap->ascii_string_map()) { |
9087 this->set_map(heap->undetectable_ascii_string_map()); | 9060 this->set_map(heap->undetectable_ascii_string_map()); |
(...skipping 7641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16729 #define ERROR_MESSAGES_TEXTS(C, T) T, | 16702 #define ERROR_MESSAGES_TEXTS(C, T) T, |
16730 static const char* error_messages_[] = { | 16703 static const char* error_messages_[] = { |
16731 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) | 16704 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) |
16732 }; | 16705 }; |
16733 #undef ERROR_MESSAGES_TEXTS | 16706 #undef ERROR_MESSAGES_TEXTS |
16734 return error_messages_[reason]; | 16707 return error_messages_[reason]; |
16735 } | 16708 } |
16736 | 16709 |
16737 | 16710 |
16738 } } // namespace v8::internal | 16711 } } // namespace v8::internal |
OLD | NEW |