OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 3284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3295 | 3295 |
3296 // Returns true for a character in a range. Both limits are inclusive. | 3296 // Returns true for a character in a range. Both limits are inclusive. |
3297 static inline bool Between(uint32_t character, uint32_t from, uint32_t to) { | 3297 static inline bool Between(uint32_t character, uint32_t from, uint32_t to) { |
3298 // This makes uses of the the unsigned wraparound. | 3298 // This makes uses of the the unsigned wraparound. |
3299 return character - from <= to - from; | 3299 return character - from <= to - from; |
3300 } | 3300 } |
3301 | 3301 |
3302 | 3302 |
3303 MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString( | 3303 MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString( |
3304 Heap* heap, | 3304 Heap* heap, |
3305 uint32_t c1, | 3305 uint16_t c1, |
3306 uint32_t c2) { | 3306 uint16_t c2) { |
3307 String* symbol; | 3307 String* symbol; |
3308 // Numeric strings have a different hash algorithm not known by | 3308 // Numeric strings have a different hash algorithm not known by |
3309 // LookupTwoCharsSymbolIfExists, so we skip this step for such strings. | 3309 // LookupTwoCharsSymbolIfExists, so we skip this step for such strings. |
3310 if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) && | 3310 if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) && |
3311 heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) { | 3311 heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) { |
3312 return symbol; | 3312 return symbol; |
3313 // Now we know the length is 2, we might as well make use of that fact | 3313 // Now we know the length is 2, we might as well make use of that fact |
3314 // when building the new string. | 3314 // when building the new string. |
3315 } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this | 3315 } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this |
3316 ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this. | 3316 ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this. |
(...skipping 28 matching lines...) Expand all Loading... |
3345 if (second_length == 0) { | 3345 if (second_length == 0) { |
3346 return first; | 3346 return first; |
3347 } | 3347 } |
3348 | 3348 |
3349 int length = first_length + second_length; | 3349 int length = first_length + second_length; |
3350 | 3350 |
3351 // Optimization for 2-byte strings often used as keys in a decompression | 3351 // Optimization for 2-byte strings often used as keys in a decompression |
3352 // dictionary. Check whether we already have the string in the symbol | 3352 // dictionary. Check whether we already have the string in the symbol |
3353 // table to prevent creation of many unneccesary strings. | 3353 // table to prevent creation of many unneccesary strings. |
3354 if (length == 2) { | 3354 if (length == 2) { |
3355 unsigned c1 = first->Get(0); | 3355 uint16_t c1 = first->Get(0); |
3356 unsigned c2 = second->Get(0); | 3356 uint16_t c2 = second->Get(0); |
3357 return MakeOrFindTwoCharacterString(this, c1, c2); | 3357 return MakeOrFindTwoCharacterString(this, c1, c2); |
3358 } | 3358 } |
3359 | 3359 |
3360 bool first_is_ascii = first->IsOneByteRepresentation(); | 3360 bool first_is_ascii = first->IsOneByteRepresentation(); |
3361 bool second_is_ascii = second->IsOneByteRepresentation(); | 3361 bool second_is_ascii = second->IsOneByteRepresentation(); |
3362 bool is_ascii = first_is_ascii && second_is_ascii; | 3362 bool is_ascii = first_is_ascii && second_is_ascii; |
3363 | 3363 |
3364 // Make sure that an out of memory exception is thrown if the length | 3364 // Make sure that an out of memory exception is thrown if the length |
3365 // of the new cons string is too large. | 3365 // of the new cons string is too large. |
3366 if (length > String::kMaxLength || length < 0) { | 3366 if (length > String::kMaxLength || length < 0) { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3460 PretenureFlag pretenure) { | 3460 PretenureFlag pretenure) { |
3461 int length = end - start; | 3461 int length = end - start; |
3462 if (length <= 0) { | 3462 if (length <= 0) { |
3463 return empty_string(); | 3463 return empty_string(); |
3464 } else if (length == 1) { | 3464 } else if (length == 1) { |
3465 return LookupSingleCharacterStringFromCode(buffer->Get(start)); | 3465 return LookupSingleCharacterStringFromCode(buffer->Get(start)); |
3466 } else if (length == 2) { | 3466 } else if (length == 2) { |
3467 // Optimization for 2-byte strings often used as keys in a decompression | 3467 // Optimization for 2-byte strings often used as keys in a decompression |
3468 // dictionary. Check whether we already have the string in the symbol | 3468 // dictionary. Check whether we already have the string in the symbol |
3469 // table to prevent creation of many unneccesary strings. | 3469 // table to prevent creation of many unneccesary strings. |
3470 unsigned c1 = buffer->Get(start); | 3470 uint16_t c1 = buffer->Get(start); |
3471 unsigned c2 = buffer->Get(start + 1); | 3471 uint16_t c2 = buffer->Get(start + 1); |
3472 return MakeOrFindTwoCharacterString(this, c1, c2); | 3472 return MakeOrFindTwoCharacterString(this, c1, c2); |
3473 } | 3473 } |
3474 | 3474 |
3475 // Make an attempt to flatten the buffer to reduce access time. | 3475 // Make an attempt to flatten the buffer to reduce access time. |
3476 buffer = buffer->TryFlattenGetString(); | 3476 buffer = buffer->TryFlattenGetString(); |
3477 | 3477 |
3478 if (!FLAG_string_slices || | 3478 if (!FLAG_string_slices || |
3479 !buffer->IsFlat() || | 3479 !buffer->IsFlat() || |
3480 length < SlicedString::kMinLength || | 3480 length < SlicedString::kMinLength || |
3481 pretenure == TENURED) { | 3481 pretenure == TENURED) { |
(...skipping 1134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4616 case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map(); | 4616 case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map(); |
4617 case SHORT_EXTERNAL_ASCII_STRING_TYPE: | 4617 case SHORT_EXTERNAL_ASCII_STRING_TYPE: |
4618 return short_external_ascii_symbol_map(); | 4618 return short_external_ascii_symbol_map(); |
4619 case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE: | 4619 case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE: |
4620 return short_external_symbol_with_ascii_data_map(); | 4620 return short_external_symbol_with_ascii_data_map(); |
4621 default: return NULL; // No match found. | 4621 default: return NULL; // No match found. |
4622 } | 4622 } |
4623 } | 4623 } |
4624 | 4624 |
4625 | 4625 |
4626 MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, | 4626 template<typename T> |
| 4627 struct AllocateInternalSymbolHelper { |
| 4628 static void WriteOneByteData(T t, char* chars, int len); |
| 4629 static void WriteTwoByteData(T t, uint16_t* chars, int len); |
| 4630 }; |
| 4631 |
| 4632 |
| 4633 template<> |
| 4634 struct AllocateInternalSymbolHelper< Vector<const char> > { |
| 4635 static inline void WriteOneByteData(Vector<const char> vector, |
| 4636 char* chars, |
| 4637 int len) { |
| 4638 // Only works for ascii. |
| 4639 ASSERT(vector.length() == len); |
| 4640 memcpy(chars, vector.start(), len); |
| 4641 } |
| 4642 |
| 4643 static inline void WriteTwoByteData(Vector<const char> vector, |
| 4644 uint16_t* chars, |
| 4645 int len) { |
| 4646 const uint8_t* stream = reinterpret_cast<const uint8_t*>(vector.start()); |
| 4647 unsigned stream_length = vector.length(); |
| 4648 while (stream_length != 0) { |
| 4649 unsigned consumed = 0; |
| 4650 uint32_t c = unibrow::Utf8::ValueOf(stream, stream_length, &consumed); |
| 4651 ASSERT(c != unibrow::Utf8::kBadChar); |
| 4652 ASSERT(consumed <= stream_length); |
| 4653 stream_length -= consumed; |
| 4654 stream += consumed; |
| 4655 if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) { |
| 4656 len -= 2; |
| 4657 if (len < 0) break; |
| 4658 *chars++ = unibrow::Utf16::LeadSurrogate(c); |
| 4659 *chars++ = unibrow::Utf16::TrailSurrogate(c); |
| 4660 } else { |
| 4661 len -= 1; |
| 4662 if (len < 0) break; |
| 4663 *chars++ = c; |
| 4664 } |
| 4665 } |
| 4666 ASSERT(stream_length == 0); |
| 4667 ASSERT(len == 0); |
| 4668 } |
| 4669 }; |
| 4670 |
| 4671 |
| 4672 template<> |
| 4673 struct AllocateInternalSymbolHelper<String*> { |
| 4674 static inline void WriteOneByteData(String* s, char* chars, int len) { |
| 4675 ASSERT(s->length() == len); |
| 4676 String::WriteToFlat(s, chars, 0, len); |
| 4677 } |
| 4678 |
| 4679 static inline void WriteTwoByteData(String* s, uint16_t* chars, int len) { |
| 4680 ASSERT(s->length() == len); |
| 4681 String::WriteToFlat(s, chars, 0, len); |
| 4682 } |
| 4683 }; |
| 4684 |
| 4685 |
| 4686 template<bool is_one_byte, typename T> |
| 4687 MaybeObject* Heap::AllocateInternalSymbol(T t, |
4627 int chars, | 4688 int chars, |
4628 uint32_t hash_field) { | 4689 uint32_t hash_field) { |
| 4690 typedef AllocateInternalSymbolHelper<T> H; |
4629 ASSERT(chars >= 0); | 4691 ASSERT(chars >= 0); |
4630 // Ensure the chars matches the number of characters in the buffer. | |
4631 ASSERT(static_cast<unsigned>(chars) == buffer->Utf16Length()); | |
4632 // Determine whether the string is ASCII. | |
4633 bool is_ascii = true; | |
4634 while (buffer->has_more()) { | |
4635 if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) { | |
4636 is_ascii = false; | |
4637 break; | |
4638 } | |
4639 } | |
4640 buffer->Rewind(); | |
4641 | |
4642 // Compute map and object size. | 4692 // Compute map and object size. |
4643 int size; | 4693 int size; |
4644 Map* map; | 4694 Map* map; |
4645 | 4695 |
4646 if (is_ascii) { | 4696 if (is_one_byte) { |
4647 if (chars > SeqOneByteString::kMaxLength) { | 4697 if (chars > SeqOneByteString::kMaxLength) { |
4648 return Failure::OutOfMemoryException(); | 4698 return Failure::OutOfMemoryException(); |
4649 } | 4699 } |
4650 map = ascii_symbol_map(); | 4700 map = ascii_symbol_map(); |
4651 size = SeqOneByteString::SizeFor(chars); | 4701 size = SeqOneByteString::SizeFor(chars); |
4652 } else { | 4702 } else { |
4653 if (chars > SeqTwoByteString::kMaxLength) { | 4703 if (chars > SeqTwoByteString::kMaxLength) { |
4654 return Failure::OutOfMemoryException(); | 4704 return Failure::OutOfMemoryException(); |
4655 } | 4705 } |
4656 map = symbol_map(); | 4706 map = symbol_map(); |
4657 size = SeqTwoByteString::SizeFor(chars); | 4707 size = SeqTwoByteString::SizeFor(chars); |
4658 } | 4708 } |
4659 | 4709 |
4660 // Allocate string. | 4710 // Allocate string. |
4661 Object* result; | 4711 Object* result; |
4662 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize) | 4712 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize) |
4663 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE) | 4713 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE) |
4664 : old_data_space_->AllocateRaw(size); | 4714 : old_data_space_->AllocateRaw(size); |
4665 if (!maybe_result->ToObject(&result)) return maybe_result; | 4715 if (!maybe_result->ToObject(&result)) return maybe_result; |
4666 } | 4716 } |
4667 | 4717 |
4668 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map); | 4718 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map); |
4669 // Set length and hash fields of the allocated string. | 4719 // Set length and hash fields of the allocated string. |
4670 String* answer = String::cast(result); | 4720 String* answer = String::cast(result); |
4671 answer->set_length(chars); | 4721 answer->set_length(chars); |
4672 answer->set_hash_field(hash_field); | 4722 answer->set_hash_field(hash_field); |
4673 | 4723 |
4674 ASSERT_EQ(size, answer->Size()); | 4724 ASSERT_EQ(size, answer->Size()); |
4675 | 4725 |
4676 // Fill in the characters. | 4726 if (is_one_byte) { |
4677 int i = 0; | 4727 H::WriteOneByteData(t, SeqOneByteString::cast(answer)->GetChars(), chars); |
4678 while (i < chars) { | 4728 } else { |
4679 uint32_t character = buffer->GetNext(); | 4729 H::WriteTwoByteData(t, SeqTwoByteString::cast(answer)->GetChars(), chars); |
4680 if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) { | |
4681 answer->Set(i++, unibrow::Utf16::LeadSurrogate(character)); | |
4682 answer->Set(i++, unibrow::Utf16::TrailSurrogate(character)); | |
4683 } else { | |
4684 answer->Set(i++, character); | |
4685 } | |
4686 } | 4730 } |
4687 return answer; | 4731 return answer; |
4688 } | 4732 } |
4689 | 4733 |
4690 | 4734 |
| 4735 // Need explicit instantiations. |
| 4736 template |
| 4737 MaybeObject* Heap::AllocateInternalSymbol<true>(String*, int, uint32_t); |
| 4738 template |
| 4739 MaybeObject* Heap::AllocateInternalSymbol<false>(String*, int, uint32_t); |
| 4740 template |
| 4741 MaybeObject* Heap::AllocateInternalSymbol<false>(Vector<const char>, |
| 4742 int, |
| 4743 uint32_t); |
| 4744 |
| 4745 |
4691 MaybeObject* Heap::AllocateRawOneByteString(int length, | 4746 MaybeObject* Heap::AllocateRawOneByteString(int length, |
4692 PretenureFlag pretenure) { | 4747 PretenureFlag pretenure) { |
4693 if (length < 0 || length > SeqOneByteString::kMaxLength) { | 4748 if (length < 0 || length > SeqOneByteString::kMaxLength) { |
4694 return Failure::OutOfMemoryException(); | 4749 return Failure::OutOfMemoryException(); |
4695 } | 4750 } |
4696 | 4751 |
4697 int size = SeqOneByteString::SizeFor(length); | 4752 int size = SeqOneByteString::SizeFor(length); |
4698 ASSERT(size <= SeqOneByteString::kMaxSize); | 4753 ASSERT(size <= SeqOneByteString::kMaxSize); |
4699 | 4754 |
4700 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; | 4755 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; |
(...skipping 2705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7406 static_cast<int>(object_sizes_last_time_[index])); | 7461 static_cast<int>(object_sizes_last_time_[index])); |
7407 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT) | 7462 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT) |
7408 #undef ADJUST_LAST_TIME_OBJECT_COUNT | 7463 #undef ADJUST_LAST_TIME_OBJECT_COUNT |
7409 | 7464 |
7410 memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); | 7465 memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); |
7411 memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); | 7466 memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); |
7412 ClearObjectStats(); | 7467 ClearObjectStats(); |
7413 } | 7468 } |
7414 | 7469 |
7415 } } // namespace v8::internal | 7470 } } // namespace v8::internal |
OLD | NEW |