OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
568 return Construct(RETRY_AFTER_GC, value); | 568 return Construct(RETRY_AFTER_GC, value); |
569 } | 569 } |
570 | 570 |
571 | 571 |
572 // Should a word be prefixed by 'a' or 'an' in order to read naturally in | 572 // Should a word be prefixed by 'a' or 'an' in order to read naturally in |
573 // English? Returns false for non-ASCII or words that don't start with | 573 // English? Returns false for non-ASCII or words that don't start with |
574 // a capital letter. The a/an rule follows pronunciation in English. | 574 // a capital letter. The a/an rule follows pronunciation in English. |
575 // We don't use the BBC's overcorrect "an historic occasion" though if | 575 // We don't use the BBC's overcorrect "an historic occasion" though if |
576 // you speak a dialect you may well say "an 'istoric occasion". | 576 // you speak a dialect you may well say "an 'istoric occasion". |
577 static bool AnWord(String* str) { | 577 static bool AnWord(String* str) { |
578 StringShape shape(str); | 578 if (str->length() == 0) return false; // A nothing. |
579 if (str->length(shape) == 0) return false; // A nothing. | 579 int c0 = str->Get(0); |
580 int c0 = str->Get(shape, 0); | 580 int c1 = str->length() > 1 ? str->Get(1) : 0; |
581 int c1 = str->length(shape) > 1 ? str->Get(shape, 1) : 0; | |
582 if (c0 == 'U') { | 581 if (c0 == 'U') { |
583 if (c1 > 'Z') { | 582 if (c1 > 'Z') { |
584 return true; // An Umpire, but a UTF8String, a U. | 583 return true; // An Umpire, but a UTF8String, a U. |
585 } | 584 } |
586 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') { | 585 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') { |
587 return true; // An Ape, an ABCBook. | 586 return true; // An Ape, an ABCBook. |
588 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) && | 587 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) && |
589 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' || | 588 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' || |
590 c0 == 'S' || c0 == 'X')) { | 589 c0 == 'S' || c0 == 'X')) { |
591 return true; // An MP3File, an M. | 590 return true; // An MP3File, an M. |
592 } | 591 } |
593 return false; | 592 return false; |
594 } | 593 } |
595 | 594 |
596 | 595 |
597 Object* String::TryFlatten(StringShape shape) { | 596 Object* String::TryFlatten() { |
598 #ifdef DEBUG | 597 #ifdef DEBUG |
599 // Do not attempt to flatten in debug mode when allocation is not | 598 // Do not attempt to flatten in debug mode when allocation is not |
600 // allowed. This is to avoid an assertion failure when allocating. | 599 // allowed. This is to avoid an assertion failure when allocating. |
601 // Flattening strings is the only case where we always allow | 600 // Flattening strings is the only case where we always allow |
602 // allocation because no GC is performed if the allocation fails. | 601 // allocation because no GC is performed if the allocation fails. |
603 if (!Heap::IsAllocationAllowed()) return this; | 602 if (!Heap::IsAllocationAllowed()) return this; |
604 #endif | 603 #endif |
605 | 604 |
606 switch (shape.representation_tag()) { | 605 switch (StringShape(this).representation_tag()) { |
607 case kSlicedStringTag: { | 606 case kSlicedStringTag: { |
608 SlicedString* ss = SlicedString::cast(this); | 607 SlicedString* ss = SlicedString::cast(this); |
609 // The SlicedString constructor should ensure that there are no | 608 // The SlicedString constructor should ensure that there are no |
610 // SlicedStrings that are constructed directly on top of other | 609 // SlicedStrings that are constructed directly on top of other |
611 // SlicedStrings. | 610 // SlicedStrings. |
612 String* buf = ss->buffer(); | 611 String* buf = ss->buffer(); |
613 ASSERT(!buf->IsSlicedString()); | 612 ASSERT(!buf->IsSlicedString()); |
614 Object* ok = buf->TryFlatten(StringShape(buf)); | 613 Object* ok = buf->TryFlatten(); |
615 if (ok->IsFailure()) return ok; | 614 if (ok->IsFailure()) return ok; |
616 // Under certain circumstances (TryFlattenIfNotFlat fails in | 615 // Under certain circumstances (TryFlattenIfNotFlat fails in |
617 // String::Slice) we can have a cons string under a slice. | 616 // String::Slice) we can have a cons string under a slice. |
618 // In this case we need to get the flat string out of the cons! | 617 // In this case we need to get the flat string out of the cons! |
619 if (StringShape(String::cast(ok)).IsCons()) { | 618 if (StringShape(String::cast(ok)).IsCons()) { |
620 ss->set_buffer(ConsString::cast(ok)->first()); | 619 ss->set_buffer(ConsString::cast(ok)->first()); |
621 } | 620 } |
622 return this; | 621 return this; |
623 } | 622 } |
624 case kConsStringTag: { | 623 case kConsStringTag: { |
625 ConsString* cs = ConsString::cast(this); | 624 ConsString* cs = ConsString::cast(this); |
626 if (cs->second()->length() == 0) { | 625 if (cs->second()->length() == 0) { |
627 return this; | 626 return this; |
628 } | 627 } |
629 // There's little point in putting the flat string in new space if the | 628 // There's little point in putting the flat string in new space if the |
630 // cons string is in old space. It can never get GCed until there is | 629 // cons string is in old space. It can never get GCed until there is |
631 // an old space GC. | 630 // an old space GC. |
632 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED; | 631 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED; |
633 int len = length(shape); | 632 int len = length(); |
634 Object* object; | 633 Object* object; |
635 String* result; | 634 String* result; |
636 if (shape.IsAsciiRepresentation()) { | 635 if (StringShape(this).IsAsciiRepresentation()) { |
637 object = Heap::AllocateRawAsciiString(len, tenure); | 636 object = Heap::AllocateRawAsciiString(len, tenure); |
638 if (object->IsFailure()) return object; | 637 if (object->IsFailure()) return object; |
639 result = String::cast(object); | 638 result = String::cast(object); |
640 String* first = cs->first(); | 639 String* first = cs->first(); |
641 StringShape first_shape(first); | 640 int first_length = first->length(); |
642 int first_length = first->length(first_shape); | |
643 char* dest = SeqAsciiString::cast(result)->GetChars(); | 641 char* dest = SeqAsciiString::cast(result)->GetChars(); |
644 WriteToFlat(first, first_shape, dest, 0, first_length); | 642 WriteToFlat(first, dest, 0, first_length); |
645 String* second = cs->second(); | 643 String* second = cs->second(); |
646 WriteToFlat(second, | 644 WriteToFlat(second, |
647 StringShape(second), | |
648 dest + first_length, | 645 dest + first_length, |
649 0, | 646 0, |
650 len - first_length); | 647 len - first_length); |
651 } else { | 648 } else { |
652 object = Heap::AllocateRawTwoByteString(len, tenure); | 649 object = Heap::AllocateRawTwoByteString(len, tenure); |
653 if (object->IsFailure()) return object; | 650 if (object->IsFailure()) return object; |
654 result = String::cast(object); | 651 result = String::cast(object); |
655 uc16* dest = SeqTwoByteString::cast(result)->GetChars(); | 652 uc16* dest = SeqTwoByteString::cast(result)->GetChars(); |
656 String* first = cs->first(); | 653 String* first = cs->first(); |
657 StringShape first_shape(first); | 654 int first_length = first->length(); |
658 int first_length = first->length(first_shape); | 655 WriteToFlat(first, dest, 0, first_length); |
659 WriteToFlat(first, first_shape, dest, 0, first_length); | |
660 String* second = cs->second(); | 656 String* second = cs->second(); |
661 WriteToFlat(second, | 657 WriteToFlat(second, |
662 StringShape(second), | |
663 dest + first_length, | 658 dest + first_length, |
664 0, | 659 0, |
665 len - first_length); | 660 len - first_length); |
666 } | 661 } |
667 cs->set_first(result); | 662 cs->set_first(result); |
668 cs->set_second(Heap::empty_string()); | 663 cs->set_second(Heap::empty_string()); |
669 return this; | 664 return this; |
670 } | 665 } |
671 default: | 666 default: |
672 return this; | 667 return this; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
754 } | 749 } |
755 | 750 |
756 // Fill the remainder of the string with dead wood. | 751 // Fill the remainder of the string with dead wood. |
757 int new_size = this->Size(); // Byte size of the external String object. | 752 int new_size = this->Size(); // Byte size of the external String object. |
758 Heap::CreateFillerObjectAt(this->address() + new_size, size - new_size); | 753 Heap::CreateFillerObjectAt(this->address() + new_size, size - new_size); |
759 return true; | 754 return true; |
760 } | 755 } |
761 | 756 |
762 | 757 |
763 void String::StringShortPrint(StringStream* accumulator) { | 758 void String::StringShortPrint(StringStream* accumulator) { |
764 StringShape shape(this); | 759 int len = length(); |
765 int len = length(shape); | |
766 if (len > kMaxMediumStringSize) { | 760 if (len > kMaxMediumStringSize) { |
767 accumulator->Add("<Very long string[%u]>", len); | 761 accumulator->Add("<Very long string[%u]>", len); |
768 return; | 762 return; |
769 } | 763 } |
770 | 764 |
771 if (!LooksValid()) { | 765 if (!LooksValid()) { |
772 accumulator->Add("<Invalid String>"); | 766 accumulator->Add("<Invalid String>"); |
773 return; | 767 return; |
774 } | 768 } |
775 | 769 |
776 StringInputBuffer buf(this); | 770 StringInputBuffer buf(this); |
777 | 771 |
778 bool truncated = false; | 772 bool truncated = false; |
779 if (len > kMaxShortPrintLength) { | 773 if (len > kMaxShortPrintLength) { |
780 len = kMaxShortPrintLength; | 774 len = kMaxShortPrintLength; |
781 truncated = true; | 775 truncated = true; |
782 } | 776 } |
783 bool ascii = true; | 777 bool ascii = true; |
784 for (int i = 0; i < len; i++) { | 778 for (int i = 0; i < len; i++) { |
785 int c = buf.GetNext(); | 779 int c = buf.GetNext(); |
786 | 780 |
787 if (c < 32 || c >= 127) { | 781 if (c < 32 || c >= 127) { |
788 ascii = false; | 782 ascii = false; |
789 } | 783 } |
790 } | 784 } |
791 buf.Reset(this); | 785 buf.Reset(this); |
792 if (ascii) { | 786 if (ascii) { |
793 accumulator->Add("<String[%u]: ", length(shape)); | 787 accumulator->Add("<String[%u]: ", length()); |
794 for (int i = 0; i < len; i++) { | 788 for (int i = 0; i < len; i++) { |
795 accumulator->Put(buf.GetNext()); | 789 accumulator->Put(buf.GetNext()); |
796 } | 790 } |
797 accumulator->Put('>'); | 791 accumulator->Put('>'); |
798 } else { | 792 } else { |
799 // Backslash indicates that the string contains control | 793 // Backslash indicates that the string contains control |
800 // characters and that backslashes are therefore escaped. | 794 // characters and that backslashes are therefore escaped. |
801 accumulator->Add("<String[%u]\\: ", length(shape)); | 795 accumulator->Add("<String[%u]\\: ", length()); |
802 for (int i = 0; i < len; i++) { | 796 for (int i = 0; i < len; i++) { |
803 int c = buf.GetNext(); | 797 int c = buf.GetNext(); |
804 if (c == '\n') { | 798 if (c == '\n') { |
805 accumulator->Add("\\n"); | 799 accumulator->Add("\\n"); |
806 } else if (c == '\r') { | 800 } else if (c == '\r') { |
807 accumulator->Add("\\r"); | 801 accumulator->Add("\\r"); |
808 } else if (c == '\\') { | 802 } else if (c == '\\') { |
809 accumulator->Add("\\\\"); | 803 accumulator->Add("\\\\"); |
810 } else if (c < 32 || c > 126) { | 804 } else if (c < 32 || c > 126) { |
811 accumulator->Add("\\x%02x", c); | 805 accumulator->Add("\\x%02x", c); |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
972 } | 966 } |
973 | 967 |
974 | 968 |
975 int HeapObject::SlowSizeFromMap(Map* map) { | 969 int HeapObject::SlowSizeFromMap(Map* map) { |
976 // Avoid calling functions such as FixedArray::cast during GC, which | 970 // Avoid calling functions such as FixedArray::cast during GC, which |
977 // read map pointer of this object again. | 971 // read map pointer of this object again. |
978 InstanceType instance_type = map->instance_type(); | 972 InstanceType instance_type = map->instance_type(); |
979 | 973 |
980 if (instance_type < FIRST_NONSTRING_TYPE | 974 if (instance_type < FIRST_NONSTRING_TYPE |
981 && (StringShape(instance_type).IsSequential())) { | 975 && (StringShape(instance_type).IsSequential())) { |
982 StringShape shape(instance_type); | 976 if (StringShape(instance_type).IsAsciiRepresentation()) { |
983 if (shape.IsAsciiRepresentation()) { | 977 SeqAsciiString* seq_ascii_this = reinterpret_cast<SeqAsciiString*>(this); |
984 return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(shape); | 978 return seq_ascii_this->SeqAsciiStringSize(instance_type); |
985 } else { | 979 } else { |
986 SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this); | 980 SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this); |
987 return self->SeqTwoByteStringSize(shape); | 981 return self->SeqTwoByteStringSize(instance_type); |
988 } | 982 } |
989 } | 983 } |
990 | 984 |
991 switch (instance_type) { | 985 switch (instance_type) { |
992 case FIXED_ARRAY_TYPE: | 986 case FIXED_ARRAY_TYPE: |
993 return reinterpret_cast<FixedArray*>(this)->FixedArraySize(); | 987 return reinterpret_cast<FixedArray*>(this)->FixedArraySize(); |
994 case BYTE_ARRAY_TYPE: | 988 case BYTE_ARRAY_TYPE: |
995 return reinterpret_cast<ByteArray*>(this)->ByteArraySize(); | 989 return reinterpret_cast<ByteArray*>(this)->ByteArraySize(); |
996 case CODE_TYPE: | 990 case CODE_TYPE: |
997 return reinterpret_cast<Code*>(this)->CodeSize(); | 991 return reinterpret_cast<Code*>(this)->CodeSize(); |
(...skipping 1554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2552 AssertNoContextChange ncc; | 2546 AssertNoContextChange ncc; |
2553 | 2547 |
2554 // Check access rights if needed. | 2548 // Check access rights if needed. |
2555 if (IsAccessCheckNeeded() && | 2549 if (IsAccessCheckNeeded() && |
2556 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { | 2550 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { |
2557 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); | 2551 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); |
2558 return Heap::undefined_value(); | 2552 return Heap::undefined_value(); |
2559 } | 2553 } |
2560 | 2554 |
2561 // Try to flatten before operating on the string. | 2555 // Try to flatten before operating on the string. |
2562 name->TryFlattenIfNotFlat(StringShape(name)); | 2556 name->TryFlattenIfNotFlat(); |
2563 | 2557 |
2564 // Check if there is an API defined callback object which prohibits | 2558 // Check if there is an API defined callback object which prohibits |
2565 // callback overwriting in this object or it's prototype chain. | 2559 // callback overwriting in this object or it's prototype chain. |
2566 // This mechanism is needed for instance in a browser setting, where | 2560 // This mechanism is needed for instance in a browser setting, where |
2567 // certain accessors such as window.location should not be allowed | 2561 // certain accessors such as window.location should not be allowed |
2568 // to be overwritten because allowing overwriting could potentially | 2562 // to be overwritten because allowing overwriting could potentially |
2569 // cause security problems. | 2563 // cause security problems. |
2570 LookupResult callback_result; | 2564 LookupResult callback_result; |
2571 LookupCallback(name, &callback_result); | 2565 LookupCallback(name, &callback_result); |
2572 if (callback_result.IsValid()) { | 2566 if (callback_result.IsValid()) { |
(...skipping 694 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3267 static StaticResource<StringInputBuffer> string_input_buffer; | 3261 static StaticResource<StringInputBuffer> string_input_buffer; |
3268 | 3262 |
3269 | 3263 |
3270 bool String::LooksValid() { | 3264 bool String::LooksValid() { |
3271 if (!Heap::Contains(this)) return false; | 3265 if (!Heap::Contains(this)) return false; |
3272 return true; | 3266 return true; |
3273 } | 3267 } |
3274 | 3268 |
3275 | 3269 |
3276 int String::Utf8Length() { | 3270 int String::Utf8Length() { |
3277 StringShape shape(this); | 3271 if (StringShape(this).IsAsciiRepresentation()) return length(); |
3278 if (shape.IsAsciiRepresentation()) return length(shape); | |
3279 // Attempt to flatten before accessing the string. It probably | 3272 // Attempt to flatten before accessing the string. It probably |
3280 // doesn't make Utf8Length faster, but it is very likely that | 3273 // doesn't make Utf8Length faster, but it is very likely that |
3281 // the string will be accessed later (for example by WriteUtf8) | 3274 // the string will be accessed later (for example by WriteUtf8) |
3282 // so it's still a good idea. | 3275 // so it's still a good idea. |
3283 TryFlattenIfNotFlat(shape); // shape is now no longer valid. | 3276 TryFlattenIfNotFlat(); |
3284 Access<StringInputBuffer> buffer(&string_input_buffer); | 3277 Access<StringInputBuffer> buffer(&string_input_buffer); |
3285 buffer->Reset(0, this); | 3278 buffer->Reset(0, this); |
3286 int result = 0; | 3279 int result = 0; |
3287 while (buffer->has_more()) | 3280 while (buffer->has_more()) |
3288 result += unibrow::Utf8::Length(buffer->GetNext()); | 3281 result += unibrow::Utf8::Length(buffer->GetNext()); |
3289 return result; | 3282 return result; |
3290 } | 3283 } |
3291 | 3284 |
3292 | 3285 |
3293 Vector<const char> String::ToAsciiVector() { | 3286 Vector<const char> String::ToAsciiVector() { |
3294 StringShape shape(this); | 3287 ASSERT(StringShape(this).IsAsciiRepresentation()); |
3295 ASSERT(shape.IsAsciiRepresentation()); | 3288 ASSERT(IsFlat()); |
3296 ASSERT(IsFlat(shape)); | |
3297 | 3289 |
3298 int offset = 0; | 3290 int offset = 0; |
3299 int length = this->length(shape); | 3291 int length = this->length(); |
3300 StringRepresentationTag string_tag = shape.representation_tag(); | 3292 StringRepresentationTag string_tag = StringShape(this).representation_tag(); |
3301 String* string = this; | 3293 String* string = this; |
3302 if (string_tag == kSlicedStringTag) { | 3294 if (string_tag == kSlicedStringTag) { |
3303 SlicedString* sliced = SlicedString::cast(string); | 3295 SlicedString* sliced = SlicedString::cast(string); |
3304 offset += sliced->start(); | 3296 offset += sliced->start(); |
3305 string = sliced->buffer(); | 3297 string = sliced->buffer(); |
3306 shape = StringShape(string); | 3298 string_tag = StringShape(string).representation_tag(); |
3307 string_tag = shape.representation_tag(); | |
3308 } else if (string_tag == kConsStringTag) { | 3299 } else if (string_tag == kConsStringTag) { |
3309 ConsString* cons = ConsString::cast(string); | 3300 ConsString* cons = ConsString::cast(string); |
3310 ASSERT(cons->second()->length(StringShape(cons->second())) == 0); | 3301 ASSERT(cons->second()->length() == 0); |
3311 string = cons->first(); | 3302 string = cons->first(); |
3312 shape = StringShape(string); | 3303 string_tag = StringShape(string).representation_tag(); |
3313 string_tag = shape.representation_tag(); | |
3314 } | 3304 } |
3315 if (string_tag == kSeqStringTag) { | 3305 if (string_tag == kSeqStringTag) { |
3316 SeqAsciiString* seq = SeqAsciiString::cast(string); | 3306 SeqAsciiString* seq = SeqAsciiString::cast(string); |
3317 char* start = seq->GetChars(); | 3307 char* start = seq->GetChars(); |
3318 return Vector<const char>(start + offset, length); | 3308 return Vector<const char>(start + offset, length); |
3319 } | 3309 } |
3320 ASSERT(string_tag == kExternalStringTag); | 3310 ASSERT(string_tag == kExternalStringTag); |
3321 ExternalAsciiString* ext = ExternalAsciiString::cast(string); | 3311 ExternalAsciiString* ext = ExternalAsciiString::cast(string); |
3322 const char* start = ext->resource()->data(); | 3312 const char* start = ext->resource()->data(); |
3323 return Vector<const char>(start + offset, length); | 3313 return Vector<const char>(start + offset, length); |
3324 } | 3314 } |
3325 | 3315 |
3326 | 3316 |
3327 Vector<const uc16> String::ToUC16Vector() { | 3317 Vector<const uc16> String::ToUC16Vector() { |
3328 StringShape shape(this); | 3318 ASSERT(StringShape(this).IsTwoByteRepresentation()); |
3329 ASSERT(shape.IsTwoByteRepresentation()); | 3319 ASSERT(IsFlat()); |
3330 ASSERT(IsFlat(shape)); | |
3331 | 3320 |
3332 int offset = 0; | 3321 int offset = 0; |
3333 int length = this->length(shape); | 3322 int length = this->length(); |
3334 StringRepresentationTag string_tag = shape.representation_tag(); | 3323 StringRepresentationTag string_tag = StringShape(this).representation_tag(); |
3335 String* string = this; | 3324 String* string = this; |
3336 if (string_tag == kSlicedStringTag) { | 3325 if (string_tag == kSlicedStringTag) { |
3337 SlicedString* sliced = SlicedString::cast(string); | 3326 SlicedString* sliced = SlicedString::cast(string); |
3338 offset += sliced->start(); | 3327 offset += sliced->start(); |
3339 string = String::cast(sliced->buffer()); | 3328 string = String::cast(sliced->buffer()); |
3340 shape = StringShape(string); | 3329 string_tag = StringShape(string).representation_tag(); |
3341 string_tag = shape.representation_tag(); | |
3342 } else if (string_tag == kConsStringTag) { | 3330 } else if (string_tag == kConsStringTag) { |
3343 ConsString* cons = ConsString::cast(string); | 3331 ConsString* cons = ConsString::cast(string); |
3344 ASSERT(cons->second()->length(StringShape(cons->second())) == 0); | 3332 ASSERT(cons->second()->length() == 0); |
3345 string = cons->first(); | 3333 string = cons->first(); |
3346 shape = StringShape(string); | 3334 string_tag = StringShape(string).representation_tag(); |
3347 string_tag = shape.representation_tag(); | |
3348 } | 3335 } |
3349 if (string_tag == kSeqStringTag) { | 3336 if (string_tag == kSeqStringTag) { |
3350 SeqTwoByteString* seq = SeqTwoByteString::cast(string); | 3337 SeqTwoByteString* seq = SeqTwoByteString::cast(string); |
3351 return Vector<const uc16>(seq->GetChars() + offset, length); | 3338 return Vector<const uc16>(seq->GetChars() + offset, length); |
3352 } | 3339 } |
3353 ASSERT(string_tag == kExternalStringTag); | 3340 ASSERT(string_tag == kExternalStringTag); |
3354 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string); | 3341 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string); |
3355 const uc16* start = | 3342 const uc16* start = |
3356 reinterpret_cast<const uc16*>(ext->resource()->data()); | 3343 reinterpret_cast<const uc16*>(ext->resource()->data()); |
3357 return Vector<const uc16>(start + offset, length); | 3344 return Vector<const uc16>(start + offset, length); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3417 return ToCString(allow_nulls, robust_flag, 0, -1, length_return); | 3404 return ToCString(allow_nulls, robust_flag, 0, -1, length_return); |
3418 } | 3405 } |
3419 | 3406 |
3420 | 3407 |
3421 const uc16* String::GetTwoByteData() { | 3408 const uc16* String::GetTwoByteData() { |
3422 return GetTwoByteData(0); | 3409 return GetTwoByteData(0); |
3423 } | 3410 } |
3424 | 3411 |
3425 | 3412 |
3426 const uc16* String::GetTwoByteData(unsigned start) { | 3413 const uc16* String::GetTwoByteData(unsigned start) { |
3427 StringShape shape(this); | 3414 ASSERT(!StringShape(this).IsAsciiRepresentation()); |
3428 ASSERT(!shape.IsAsciiRepresentation()); | 3415 switch (StringShape(this).representation_tag()) { |
3429 switch (shape.representation_tag()) { | |
3430 case kSeqStringTag: | 3416 case kSeqStringTag: |
3431 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); | 3417 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); |
3432 case kExternalStringTag: | 3418 case kExternalStringTag: |
3433 return ExternalTwoByteString::cast(this)-> | 3419 return ExternalTwoByteString::cast(this)-> |
3434 ExternalTwoByteStringGetData(start); | 3420 ExternalTwoByteStringGetData(start); |
3435 case kSlicedStringTag: { | 3421 case kSlicedStringTag: { |
3436 SlicedString* sliced_string = SlicedString::cast(this); | 3422 SlicedString* sliced_string = SlicedString::cast(this); |
3437 String* buffer = sliced_string->buffer(); | 3423 String* buffer = sliced_string->buffer(); |
3438 if (StringShape(buffer).IsCons()) { | 3424 if (StringShape(buffer).IsCons()) { |
3439 ConsString* cs = ConsString::cast(buffer); | 3425 ConsString* cs = ConsString::cast(buffer); |
3440 // Flattened string. | 3426 // Flattened string. |
3441 ASSERT(cs->second()->length(StringShape(cs->second())) == 0); | 3427 ASSERT(cs->second()->length() == 0); |
3442 buffer = cs->first(); | 3428 buffer = cs->first(); |
3443 } | 3429 } |
3444 return buffer->GetTwoByteData(start + sliced_string->start()); | 3430 return buffer->GetTwoByteData(start + sliced_string->start()); |
3445 } | 3431 } |
3446 case kConsStringTag: | 3432 case kConsStringTag: |
3447 UNREACHABLE(); | 3433 UNREACHABLE(); |
3448 return NULL; | 3434 return NULL; |
3449 } | 3435 } |
3450 UNREACHABLE(); | 3436 UNREACHABLE(); |
3451 return NULL; | 3437 return NULL; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3534 // *AsciiStringReadBlock routines. | 3520 // *AsciiStringReadBlock routines. |
3535 const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb, | 3521 const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb, |
3536 unsigned* offset_ptr, | 3522 unsigned* offset_ptr, |
3537 unsigned max_chars) { | 3523 unsigned max_chars) { |
3538 ConsString* current = this; | 3524 ConsString* current = this; |
3539 unsigned offset = *offset_ptr; | 3525 unsigned offset = *offset_ptr; |
3540 int offset_correction = 0; | 3526 int offset_correction = 0; |
3541 | 3527 |
3542 while (true) { | 3528 while (true) { |
3543 String* left = current->first(); | 3529 String* left = current->first(); |
3544 StringShape left_shape(left); | 3530 unsigned left_length = (unsigned)left->length(); |
3545 unsigned left_length = (unsigned)left->length(left_shape); | |
3546 if (left_length > offset && | 3531 if (left_length > offset && |
3547 (max_chars <= left_length - offset || | 3532 (max_chars <= left_length - offset || |
3548 (rbb->capacity <= left_length - offset && | 3533 (rbb->capacity <= left_length - offset && |
3549 (max_chars = left_length - offset, true)))) { // comma operator! | 3534 (max_chars = left_length - offset, true)))) { // comma operator! |
3550 // Left hand side only - iterate unless we have reached the bottom of | 3535 // Left hand side only - iterate unless we have reached the bottom of |
3551 // the cons tree. The assignment on the left of the comma operator is | 3536 // the cons tree. The assignment on the left of the comma operator is |
3552 // in order to make use of the fact that the -IntoBuffer routines can | 3537 // in order to make use of the fact that the -IntoBuffer routines can |
3553 // produce at most 'capacity' characters. This enables us to postpone | 3538 // produce at most 'capacity' characters. This enables us to postpone |
3554 // the point where we switch to the -IntoBuffer routines (below) in order | 3539 // the point where we switch to the -IntoBuffer routines (below) in order |
3555 // to maximize the chances of delegating a big chunk of work to the | 3540 // to maximize the chances of delegating a big chunk of work to the |
3556 // efficient *AsciiStringReadBlock routines. | 3541 // efficient *AsciiStringReadBlock routines. |
3557 if (left_shape.IsCons()) { | 3542 if (StringShape(left).IsCons()) { |
3558 current = ConsString::cast(left); | 3543 current = ConsString::cast(left); |
3559 continue; | 3544 continue; |
3560 } else { | 3545 } else { |
3561 const unibrow::byte* answer = | 3546 const unibrow::byte* answer = |
3562 String::ReadBlock(left, rbb, &offset, max_chars); | 3547 String::ReadBlock(left, rbb, &offset, max_chars); |
3563 *offset_ptr = offset + offset_correction; | 3548 *offset_ptr = offset + offset_correction; |
3564 return answer; | 3549 return answer; |
3565 } | 3550 } |
3566 } else if (left_length <= offset) { | 3551 } else if (left_length <= offset) { |
3567 // Right hand side only - iterate unless we have reached the bottom of | 3552 // Right hand side only - iterate unless we have reached the bottom of |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3712 // (see AsciiStringReadBlock). | 3697 // (see AsciiStringReadBlock). |
3713 const unibrow::byte* String::ReadBlock(String* input, | 3698 const unibrow::byte* String::ReadBlock(String* input, |
3714 ReadBlockBuffer* rbb, | 3699 ReadBlockBuffer* rbb, |
3715 unsigned* offset_ptr, | 3700 unsigned* offset_ptr, |
3716 unsigned max_chars) { | 3701 unsigned max_chars) { |
3717 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length())); | 3702 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length())); |
3718 if (max_chars == 0) { | 3703 if (max_chars == 0) { |
3719 rbb->remaining = 0; | 3704 rbb->remaining = 0; |
3720 return NULL; | 3705 return NULL; |
3721 } | 3706 } |
3722 StringShape shape(input); | 3707 switch (StringShape(input).representation_tag()) { |
3723 switch (shape.representation_tag()) { | |
3724 case kSeqStringTag: | 3708 case kSeqStringTag: |
3725 if (shape.IsAsciiRepresentation()) { | 3709 if (StringShape(input).IsAsciiRepresentation()) { |
3726 SeqAsciiString* str = SeqAsciiString::cast(input); | 3710 SeqAsciiString* str = SeqAsciiString::cast(input); |
3727 return str->SeqAsciiStringReadBlock(&rbb->remaining, | 3711 return str->SeqAsciiStringReadBlock(&rbb->remaining, |
3728 offset_ptr, | 3712 offset_ptr, |
3729 max_chars); | 3713 max_chars); |
3730 } else { | 3714 } else { |
3731 SeqTwoByteString* str = SeqTwoByteString::cast(input); | 3715 SeqTwoByteString* str = SeqTwoByteString::cast(input); |
3732 str->SeqTwoByteStringReadBlockIntoBuffer(rbb, | 3716 str->SeqTwoByteStringReadBlockIntoBuffer(rbb, |
3733 offset_ptr, | 3717 offset_ptr, |
3734 max_chars); | 3718 max_chars); |
3735 return rbb->util_buffer; | 3719 return rbb->util_buffer; |
3736 } | 3720 } |
3737 case kConsStringTag: | 3721 case kConsStringTag: |
3738 return ConsString::cast(input)->ConsStringReadBlock(rbb, | 3722 return ConsString::cast(input)->ConsStringReadBlock(rbb, |
3739 offset_ptr, | 3723 offset_ptr, |
3740 max_chars); | 3724 max_chars); |
3741 case kSlicedStringTag: | 3725 case kSlicedStringTag: |
3742 return SlicedString::cast(input)->SlicedStringReadBlock(rbb, | 3726 return SlicedString::cast(input)->SlicedStringReadBlock(rbb, |
3743 offset_ptr, | 3727 offset_ptr, |
3744 max_chars); | 3728 max_chars); |
3745 case kExternalStringTag: | 3729 case kExternalStringTag: |
3746 if (shape.IsAsciiRepresentation()) { | 3730 if (StringShape(input).IsAsciiRepresentation()) { |
3747 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock( | 3731 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock( |
3748 &rbb->remaining, | 3732 &rbb->remaining, |
3749 offset_ptr, | 3733 offset_ptr, |
3750 max_chars); | 3734 max_chars); |
3751 } else { | 3735 } else { |
3752 ExternalTwoByteString::cast(input)-> | 3736 ExternalTwoByteString::cast(input)-> |
3753 ExternalTwoByteStringReadBlockIntoBuffer(rbb, | 3737 ExternalTwoByteStringReadBlockIntoBuffer(rbb, |
3754 offset_ptr, | 3738 offset_ptr, |
3755 max_chars); | 3739 max_chars); |
3756 return rbb->util_buffer; | 3740 return rbb->util_buffer; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3788 | 3772 |
3789 FlatStringReader::~FlatStringReader() { | 3773 FlatStringReader::~FlatStringReader() { |
3790 ASSERT_EQ(top_, this); | 3774 ASSERT_EQ(top_, this); |
3791 top_ = prev_; | 3775 top_ = prev_; |
3792 } | 3776 } |
3793 | 3777 |
3794 | 3778 |
3795 void FlatStringReader::RefreshState() { | 3779 void FlatStringReader::RefreshState() { |
3796 if (str_ == NULL) return; | 3780 if (str_ == NULL) return; |
3797 Handle<String> str(str_); | 3781 Handle<String> str(str_); |
3798 StringShape shape(*str); | 3782 ASSERT(str->IsFlat()); |
3799 ASSERT(str->IsFlat(shape)); | 3783 is_ascii_ = StringShape(*str).IsAsciiRepresentation(); |
3800 is_ascii_ = shape.IsAsciiRepresentation(); | |
3801 if (is_ascii_) { | 3784 if (is_ascii_) { |
3802 start_ = str->ToAsciiVector().start(); | 3785 start_ = str->ToAsciiVector().start(); |
3803 } else { | 3786 } else { |
3804 start_ = str->ToUC16Vector().start(); | 3787 start_ = str->ToUC16Vector().start(); |
3805 } | 3788 } |
3806 } | 3789 } |
3807 | 3790 |
3808 | 3791 |
3809 void FlatStringReader::PostGarbageCollectionProcessing() { | 3792 void FlatStringReader::PostGarbageCollectionProcessing() { |
3810 FlatStringReader* current = top_; | 3793 FlatStringReader* current = top_; |
(...skipping 15 matching lines...) Expand all Loading... |
3826 | 3809 |
3827 | 3810 |
3828 // This method determines the type of string involved and then copies | 3811 // This method determines the type of string involved and then copies |
3829 // a whole chunk of characters into a buffer. It can be used with strings | 3812 // a whole chunk of characters into a buffer. It can be used with strings |
3830 // that have been glued together to form a ConsString and which must cooperate | 3813 // that have been glued together to form a ConsString and which must cooperate |
3831 // to fill up a buffer. | 3814 // to fill up a buffer. |
3832 void String::ReadBlockIntoBuffer(String* input, | 3815 void String::ReadBlockIntoBuffer(String* input, |
3833 ReadBlockBuffer* rbb, | 3816 ReadBlockBuffer* rbb, |
3834 unsigned* offset_ptr, | 3817 unsigned* offset_ptr, |
3835 unsigned max_chars) { | 3818 unsigned max_chars) { |
3836 StringShape shape(input); | 3819 ASSERT(*offset_ptr <= (unsigned)input->length()); |
3837 ASSERT(*offset_ptr <= (unsigned)input->length(shape)); | |
3838 if (max_chars == 0) return; | 3820 if (max_chars == 0) return; |
3839 | 3821 |
3840 switch (shape.representation_tag()) { | 3822 switch (StringShape(input).representation_tag()) { |
3841 case kSeqStringTag: | 3823 case kSeqStringTag: |
3842 if (shape.IsAsciiRepresentation()) { | 3824 if (StringShape(input).IsAsciiRepresentation()) { |
3843 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb, | 3825 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb, |
3844 offset_ptr, | 3826 offset_ptr, |
3845 max_chars); | 3827 max_chars); |
3846 return; | 3828 return; |
3847 } else { | 3829 } else { |
3848 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb, | 3830 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb, |
3849 offset_ptr, | 3831 offset_ptr, |
3850 max_chars); | 3832 max_chars); |
3851 return; | 3833 return; |
3852 } | 3834 } |
3853 case kConsStringTag: | 3835 case kConsStringTag: |
3854 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb, | 3836 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb, |
3855 offset_ptr, | 3837 offset_ptr, |
3856 max_chars); | 3838 max_chars); |
3857 return; | 3839 return; |
3858 case kSlicedStringTag: | 3840 case kSlicedStringTag: |
3859 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb, | 3841 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb, |
3860 offset_ptr, | 3842 offset_ptr, |
3861 max_chars); | 3843 max_chars); |
3862 return; | 3844 return; |
3863 case kExternalStringTag: | 3845 case kExternalStringTag: |
3864 if (shape.IsAsciiRepresentation()) { | 3846 if (StringShape(input).IsAsciiRepresentation()) { |
3865 ExternalAsciiString::cast(input)-> | 3847 ExternalAsciiString::cast(input)-> |
3866 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); | 3848 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); |
3867 } else { | 3849 } else { |
3868 ExternalTwoByteString::cast(input)-> | 3850 ExternalTwoByteString::cast(input)-> |
3869 ExternalTwoByteStringReadBlockIntoBuffer(rbb, | 3851 ExternalTwoByteStringReadBlockIntoBuffer(rbb, |
3870 offset_ptr, | 3852 offset_ptr, |
3871 max_chars); | 3853 max_chars); |
3872 } | 3854 } |
3873 return; | 3855 return; |
3874 default: | 3856 default: |
3875 break; | 3857 break; |
3876 } | 3858 } |
3877 | 3859 |
3878 UNREACHABLE(); | 3860 UNREACHABLE(); |
3879 return; | 3861 return; |
3880 } | 3862 } |
3881 | 3863 |
3882 | 3864 |
3883 const unibrow::byte* String::ReadBlock(String* input, | 3865 const unibrow::byte* String::ReadBlock(String* input, |
3884 unibrow::byte* util_buffer, | 3866 unibrow::byte* util_buffer, |
3885 unsigned capacity, | 3867 unsigned capacity, |
3886 unsigned* remaining, | 3868 unsigned* remaining, |
3887 unsigned* offset_ptr) { | 3869 unsigned* offset_ptr) { |
3888 StringShape shape(input); | 3870 ASSERT(*offset_ptr <= (unsigned)input->length()); |
3889 ASSERT(*offset_ptr <= (unsigned)input->length(shape)); | 3871 unsigned chars = input->length() - *offset_ptr; |
3890 unsigned chars = input->length(shape) - *offset_ptr; | |
3891 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); | 3872 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); |
3892 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars); | 3873 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars); |
3893 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape))); | 3874 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length())); |
3894 *remaining = rbb.remaining; | 3875 *remaining = rbb.remaining; |
3895 return answer; | 3876 return answer; |
3896 } | 3877 } |
3897 | 3878 |
3898 | 3879 |
3899 const unibrow::byte* String::ReadBlock(String** raw_input, | 3880 const unibrow::byte* String::ReadBlock(String** raw_input, |
3900 unibrow::byte* util_buffer, | 3881 unibrow::byte* util_buffer, |
3901 unsigned capacity, | 3882 unsigned capacity, |
3902 unsigned* remaining, | 3883 unsigned* remaining, |
3903 unsigned* offset_ptr) { | 3884 unsigned* offset_ptr) { |
3904 StringShape shape(*raw_input); | |
3905 Handle<String> input(raw_input); | 3885 Handle<String> input(raw_input); |
3906 ASSERT(*offset_ptr <= (unsigned)input->length(shape)); | 3886 ASSERT(*offset_ptr <= (unsigned)input->length()); |
3907 unsigned chars = input->length(shape) - *offset_ptr; | 3887 unsigned chars = input->length() - *offset_ptr; |
3908 if (chars > capacity) chars = capacity; | 3888 if (chars > capacity) chars = capacity; |
3909 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); | 3889 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); |
3910 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars); | 3890 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars); |
3911 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape))); | 3891 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length())); |
3912 *remaining = rbb.remaining; | 3892 *remaining = rbb.remaining; |
3913 return rbb.util_buffer; | 3893 return rbb.util_buffer; |
3914 } | 3894 } |
3915 | 3895 |
3916 | 3896 |
3917 // This will iterate unless the block of string data spans two 'halves' of | 3897 // This will iterate unless the block of string data spans two 'halves' of |
3918 // a ConsString, in which case it will recurse. Since the block of string | 3898 // a ConsString, in which case it will recurse. Since the block of string |
3919 // data to be read has a maximum size this limits the maximum recursion | 3899 // data to be read has a maximum size this limits the maximum recursion |
3920 // depth to something sane. Since C++ does not have tail call recursion | 3900 // depth to something sane. Since C++ does not have tail call recursion |
3921 // elimination, the iteration must be explicit. | 3901 // elimination, the iteration must be explicit. |
3922 void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, | 3902 void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, |
3923 unsigned* offset_ptr, | 3903 unsigned* offset_ptr, |
3924 unsigned max_chars) { | 3904 unsigned max_chars) { |
3925 ConsString* current = this; | 3905 ConsString* current = this; |
3926 unsigned offset = *offset_ptr; | 3906 unsigned offset = *offset_ptr; |
3927 int offset_correction = 0; | 3907 int offset_correction = 0; |
3928 | 3908 |
3929 while (true) { | 3909 while (true) { |
3930 String* left = current->first(); | 3910 String* left = current->first(); |
3931 StringShape left_shape(left); | 3911 unsigned left_length = (unsigned)left->length(); |
3932 unsigned left_length = (unsigned)left->length(left_shape); | |
3933 if (left_length > offset && | 3912 if (left_length > offset && |
3934 max_chars <= left_length - offset) { | 3913 max_chars <= left_length - offset) { |
3935 // Left hand side only - iterate unless we have reached the bottom of | 3914 // Left hand side only - iterate unless we have reached the bottom of |
3936 // the cons tree. | 3915 // the cons tree. |
3937 if (left_shape.IsCons()) { | 3916 if (StringShape(left).IsCons()) { |
3938 current = ConsString::cast(left); | 3917 current = ConsString::cast(left); |
3939 continue; | 3918 continue; |
3940 } else { | 3919 } else { |
3941 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars); | 3920 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars); |
3942 *offset_ptr = offset + offset_correction; | 3921 *offset_ptr = offset + offset_correction; |
3943 return; | 3922 return; |
3944 } | 3923 } |
3945 } else if (left_length <= offset) { | 3924 } else if (left_length <= offset) { |
3946 // Right hand side only - iterate unless we have reached the bottom of | 3925 // Right hand side only - iterate unless we have reached the bottom of |
3947 // the cons tree. | 3926 // the cons tree. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3995 IteratePointers(v, kFirstOffset, kSecondOffset + kPointerSize); | 3974 IteratePointers(v, kFirstOffset, kSecondOffset + kPointerSize); |
3996 } | 3975 } |
3997 | 3976 |
3998 | 3977 |
3999 uint16_t ConsString::ConsStringGet(int index) { | 3978 uint16_t ConsString::ConsStringGet(int index) { |
4000 ASSERT(index >= 0 && index < this->length()); | 3979 ASSERT(index >= 0 && index < this->length()); |
4001 | 3980 |
4002 // Check for a flattened cons string | 3981 // Check for a flattened cons string |
4003 if (second()->length() == 0) { | 3982 if (second()->length() == 0) { |
4004 String* left = first(); | 3983 String* left = first(); |
4005 return left->Get(StringShape(left), index); | 3984 return left->Get(index); |
4006 } | 3985 } |
4007 | 3986 |
4008 String* string = String::cast(this); | 3987 String* string = String::cast(this); |
4009 StringShape shape(string); | |
4010 | 3988 |
4011 while (true) { | 3989 while (true) { |
4012 if (shape.IsCons()) { | 3990 if (StringShape(string).IsCons()) { |
4013 ConsString* cons_string = ConsString::cast(string); | 3991 ConsString* cons_string = ConsString::cast(string); |
4014 String* left = cons_string->first(); | 3992 String* left = cons_string->first(); |
4015 StringShape left_shape(left); | 3993 if (left->length() > index) { |
4016 if (left->length(left_shape) > index) { | |
4017 string = left; | 3994 string = left; |
4018 shape = left_shape; | |
4019 } else { | 3995 } else { |
4020 index -= left->length(left_shape); | 3996 index -= left->length(); |
4021 string = cons_string->second(); | 3997 string = cons_string->second(); |
4022 shape = StringShape(string); | |
4023 } | 3998 } |
4024 } else { | 3999 } else { |
4025 return string->Get(shape, index); | 4000 return string->Get(index); |
4026 } | 4001 } |
4027 } | 4002 } |
4028 | 4003 |
4029 UNREACHABLE(); | 4004 UNREACHABLE(); |
4030 return 0; | 4005 return 0; |
4031 } | 4006 } |
4032 | 4007 |
4033 | 4008 |
4034 template <typename sinkchar> | 4009 template <typename sinkchar> |
4035 void String::WriteToFlat(String* src, | 4010 void String::WriteToFlat(String* src, |
4036 StringShape src_shape, | |
4037 sinkchar* sink, | 4011 sinkchar* sink, |
4038 int f, | 4012 int f, |
4039 int t) { | 4013 int t) { |
4040 String* source = src; | 4014 String* source = src; |
4041 StringShape shape = src_shape; | |
4042 int from = f; | 4015 int from = f; |
4043 int to = t; | 4016 int to = t; |
4044 while (true) { | 4017 while (true) { |
4045 ASSERT(0 <= from && from <= to && to <= source->length(shape)); | 4018 ASSERT(0 <= from && from <= to && to <= source->length()); |
4046 switch (shape.full_representation_tag()) { | 4019 switch (StringShape(source).full_representation_tag()) { |
4047 case kAsciiStringTag | kExternalStringTag: { | 4020 case kAsciiStringTag | kExternalStringTag: { |
4048 CopyChars(sink, | 4021 CopyChars(sink, |
4049 ExternalAsciiString::cast(source)->resource()->data() + from, | 4022 ExternalAsciiString::cast(source)->resource()->data() + from, |
4050 to - from); | 4023 to - from); |
4051 return; | 4024 return; |
4052 } | 4025 } |
4053 case kTwoByteStringTag | kExternalStringTag: { | 4026 case kTwoByteStringTag | kExternalStringTag: { |
4054 const uc16* data = | 4027 const uc16* data = |
4055 ExternalTwoByteString::cast(source)->resource()->data(); | 4028 ExternalTwoByteString::cast(source)->resource()->data(); |
4056 CopyChars(sink, | 4029 CopyChars(sink, |
(...skipping 13 matching lines...) Expand all Loading... |
4070 to - from); | 4043 to - from); |
4071 return; | 4044 return; |
4072 } | 4045 } |
4073 case kAsciiStringTag | kSlicedStringTag: | 4046 case kAsciiStringTag | kSlicedStringTag: |
4074 case kTwoByteStringTag | kSlicedStringTag: { | 4047 case kTwoByteStringTag | kSlicedStringTag: { |
4075 SlicedString* sliced_string = SlicedString::cast(source); | 4048 SlicedString* sliced_string = SlicedString::cast(source); |
4076 int start = sliced_string->start(); | 4049 int start = sliced_string->start(); |
4077 from += start; | 4050 from += start; |
4078 to += start; | 4051 to += start; |
4079 source = String::cast(sliced_string->buffer()); | 4052 source = String::cast(sliced_string->buffer()); |
4080 shape = StringShape(source); | |
4081 break; | 4053 break; |
4082 } | 4054 } |
4083 case kAsciiStringTag | kConsStringTag: | 4055 case kAsciiStringTag | kConsStringTag: |
4084 case kTwoByteStringTag | kConsStringTag: { | 4056 case kTwoByteStringTag | kConsStringTag: { |
4085 ConsString* cons_string = ConsString::cast(source); | 4057 ConsString* cons_string = ConsString::cast(source); |
4086 String* first = cons_string->first(); | 4058 String* first = cons_string->first(); |
4087 StringShape first_shape(first); | 4059 int boundary = first->length(); |
4088 int boundary = first->length(first_shape); | |
4089 if (to - boundary >= boundary - from) { | 4060 if (to - boundary >= boundary - from) { |
4090 // Right hand side is longer. Recurse over left. | 4061 // Right hand side is longer. Recurse over left. |
4091 if (from < boundary) { | 4062 if (from < boundary) { |
4092 WriteToFlat(first, first_shape, sink, from, boundary); | 4063 WriteToFlat(first, sink, from, boundary); |
4093 sink += boundary - from; | 4064 sink += boundary - from; |
4094 from = 0; | 4065 from = 0; |
4095 } else { | 4066 } else { |
4096 from -= boundary; | 4067 from -= boundary; |
4097 } | 4068 } |
4098 to -= boundary; | 4069 to -= boundary; |
4099 source = cons_string->second(); | 4070 source = cons_string->second(); |
4100 shape = StringShape(source); | |
4101 } else { | 4071 } else { |
4102 // Left hand side is longer. Recurse over right. | 4072 // Left hand side is longer. Recurse over right. |
4103 if (to > boundary) { | 4073 if (to > boundary) { |
4104 String* second = cons_string->second(); | 4074 String* second = cons_string->second(); |
4105 WriteToFlat(second, | 4075 WriteToFlat(second, |
4106 StringShape(second), | |
4107 sink + boundary - from, | 4076 sink + boundary - from, |
4108 0, | 4077 0, |
4109 to - boundary); | 4078 to - boundary); |
4110 to = boundary; | 4079 to = boundary; |
4111 } | 4080 } |
4112 source = first; | 4081 source = first; |
4113 shape = first_shape; | |
4114 } | 4082 } |
4115 break; | 4083 break; |
4116 } | 4084 } |
4117 } | 4085 } |
4118 } | 4086 } |
4119 } | 4087 } |
4120 | 4088 |
4121 | 4089 |
4122 void SlicedString::SlicedStringIterateBody(ObjectVisitor* v) { | 4090 void SlicedString::SlicedStringIterateBody(ObjectVisitor* v) { |
4123 IteratePointer(v, kBufferOffset); | 4091 IteratePointer(v, kBufferOffset); |
4124 } | 4092 } |
4125 | 4093 |
4126 | 4094 |
4127 uint16_t SlicedString::SlicedStringGet(int index) { | 4095 uint16_t SlicedString::SlicedStringGet(int index) { |
4128 ASSERT(index >= 0 && index < this->length()); | 4096 ASSERT(index >= 0 && index < this->length()); |
4129 // Delegate to the buffer string. | 4097 // Delegate to the buffer string. |
4130 String* underlying = buffer(); | 4098 String* underlying = buffer(); |
4131 return underlying->Get(StringShape(underlying), start() + index); | 4099 return underlying->Get(start() + index); |
4132 } | 4100 } |
4133 | 4101 |
4134 | 4102 |
4135 template <typename IteratorA, typename IteratorB> | 4103 template <typename IteratorA, typename IteratorB> |
4136 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) { | 4104 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) { |
4137 // General slow case check. We know that the ia and ib iterators | 4105 // General slow case check. We know that the ia and ib iterators |
4138 // have the same length. | 4106 // have the same length. |
4139 while (ia->has_more()) { | 4107 while (ia->has_more()) { |
4140 uc32 ca = ia->GetNext(); | 4108 uc32 ca = ia->GetNext(); |
4141 uc32 cb = ib->GetNext(); | 4109 uc32 cb = ib->GetNext(); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4185 } | 4153 } |
4186 return true; | 4154 return true; |
4187 } | 4155 } |
4188 | 4156 |
4189 | 4157 |
4190 static StringInputBuffer string_compare_buffer_b; | 4158 static StringInputBuffer string_compare_buffer_b; |
4191 | 4159 |
4192 | 4160 |
4193 template <typename IteratorA> | 4161 template <typename IteratorA> |
4194 static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) { | 4162 static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) { |
4195 StringShape b_shape(b); | 4163 if (b->IsFlat()) { |
4196 if (b->IsFlat(b_shape)) { | 4164 if (StringShape(b).IsAsciiRepresentation()) { |
4197 if (b_shape.IsAsciiRepresentation()) { | |
4198 VectorIterator<char> ib(b->ToAsciiVector()); | 4165 VectorIterator<char> ib(b->ToAsciiVector()); |
4199 return CompareStringContents(ia, &ib); | 4166 return CompareStringContents(ia, &ib); |
4200 } else { | 4167 } else { |
4201 VectorIterator<uc16> ib(b->ToUC16Vector()); | 4168 VectorIterator<uc16> ib(b->ToUC16Vector()); |
4202 return CompareStringContents(ia, &ib); | 4169 return CompareStringContents(ia, &ib); |
4203 } | 4170 } |
4204 } else { | 4171 } else { |
4205 string_compare_buffer_b.Reset(0, b); | 4172 string_compare_buffer_b.Reset(0, b); |
4206 return CompareStringContents(ia, &string_compare_buffer_b); | 4173 return CompareStringContents(ia, &string_compare_buffer_b); |
4207 } | 4174 } |
4208 } | 4175 } |
4209 | 4176 |
4210 | 4177 |
4211 static StringInputBuffer string_compare_buffer_a; | 4178 static StringInputBuffer string_compare_buffer_a; |
4212 | 4179 |
4213 | 4180 |
4214 bool String::SlowEquals(StringShape this_shape, | 4181 bool String::SlowEquals(String* other) { |
4215 String* other, | |
4216 StringShape other_shape) { | |
4217 // Fast check: negative check with lengths. | 4182 // Fast check: negative check with lengths. |
4218 int len = length(this_shape); | 4183 int len = length(); |
4219 if (len != other->length(other_shape)) return false; | 4184 if (len != other->length()) return false; |
4220 if (len == 0) return true; | 4185 if (len == 0) return true; |
4221 | 4186 |
4222 // Fast check: if hash code is computed for both strings | 4187 // Fast check: if hash code is computed for both strings |
4223 // a fast negative check can be performed. | 4188 // a fast negative check can be performed. |
4224 if (HasHashCode() && other->HasHashCode()) { | 4189 if (HasHashCode() && other->HasHashCode()) { |
4225 if (Hash() != other->Hash()) return false; | 4190 if (Hash() != other->Hash()) return false; |
4226 } | 4191 } |
4227 | 4192 |
4228 if (this_shape.IsSequentialAscii() && other_shape.IsSequentialAscii()) { | 4193 if (StringShape(this).IsSequentialAscii() && StringShape(other).IsSequentialAs
cii()) { |
4229 const char* str1 = SeqAsciiString::cast(this)->GetChars(); | 4194 const char* str1 = SeqAsciiString::cast(this)->GetChars(); |
4230 const char* str2 = SeqAsciiString::cast(other)->GetChars(); | 4195 const char* str2 = SeqAsciiString::cast(other)->GetChars(); |
4231 return CompareRawStringContents(Vector<const char>(str1, len), | 4196 return CompareRawStringContents(Vector<const char>(str1, len), |
4232 Vector<const char>(str2, len)); | 4197 Vector<const char>(str2, len)); |
4233 } | 4198 } |
4234 | 4199 |
4235 if (this->IsFlat(this_shape)) { | 4200 if (this->IsFlat()) { |
4236 if (this_shape.IsAsciiRepresentation()) { | 4201 if (StringShape(this).IsAsciiRepresentation()) { |
4237 Vector<const char> vec1 = this->ToAsciiVector(); | 4202 Vector<const char> vec1 = this->ToAsciiVector(); |
4238 if (other->IsFlat(other_shape)) { | 4203 if (other->IsFlat()) { |
4239 if (other_shape.IsAsciiRepresentation()) { | 4204 if (StringShape(other).IsAsciiRepresentation()) { |
4240 Vector<const char> vec2 = other->ToAsciiVector(); | 4205 Vector<const char> vec2 = other->ToAsciiVector(); |
4241 return CompareRawStringContents(vec1, vec2); | 4206 return CompareRawStringContents(vec1, vec2); |
4242 } else { | 4207 } else { |
4243 VectorIterator<char> buf1(vec1); | 4208 VectorIterator<char> buf1(vec1); |
4244 VectorIterator<uc16> ib(other->ToUC16Vector()); | 4209 VectorIterator<uc16> ib(other->ToUC16Vector()); |
4245 return CompareStringContents(&buf1, &ib); | 4210 return CompareStringContents(&buf1, &ib); |
4246 } | 4211 } |
4247 } else { | 4212 } else { |
4248 VectorIterator<char> buf1(vec1); | 4213 VectorIterator<char> buf1(vec1); |
4249 string_compare_buffer_b.Reset(0, other); | 4214 string_compare_buffer_b.Reset(0, other); |
4250 return CompareStringContents(&buf1, &string_compare_buffer_b); | 4215 return CompareStringContents(&buf1, &string_compare_buffer_b); |
4251 } | 4216 } |
4252 } else { | 4217 } else { |
4253 Vector<const uc16> vec1 = this->ToUC16Vector(); | 4218 Vector<const uc16> vec1 = this->ToUC16Vector(); |
4254 if (other->IsFlat(other_shape)) { | 4219 if (other->IsFlat()) { |
4255 if (other_shape.IsAsciiRepresentation()) { | 4220 if (StringShape(other).IsAsciiRepresentation()) { |
4256 VectorIterator<uc16> buf1(vec1); | 4221 VectorIterator<uc16> buf1(vec1); |
4257 VectorIterator<char> ib(other->ToAsciiVector()); | 4222 VectorIterator<char> ib(other->ToAsciiVector()); |
4258 return CompareStringContents(&buf1, &ib); | 4223 return CompareStringContents(&buf1, &ib); |
4259 } else { | 4224 } else { |
4260 Vector<const uc16> vec2(other->ToUC16Vector()); | 4225 Vector<const uc16> vec2(other->ToUC16Vector()); |
4261 return CompareRawStringContents(vec1, vec2); | 4226 return CompareRawStringContents(vec1, vec2); |
4262 } | 4227 } |
4263 } else { | 4228 } else { |
4264 VectorIterator<uc16> buf1(vec1); | 4229 VectorIterator<uc16> buf1(vec1); |
4265 string_compare_buffer_b.Reset(0, other); | 4230 string_compare_buffer_b.Reset(0, other); |
(...skipping 29 matching lines...) Expand all Loading... |
4295 } else if (map == Heap::long_ascii_string_map()) { | 4260 } else if (map == Heap::long_ascii_string_map()) { |
4296 this->set_map(Heap::undetectable_long_ascii_string_map()); | 4261 this->set_map(Heap::undetectable_long_ascii_string_map()); |
4297 return true; | 4262 return true; |
4298 } | 4263 } |
4299 // Rest cannot be marked as undetectable | 4264 // Rest cannot be marked as undetectable |
4300 return false; | 4265 return false; |
4301 } | 4266 } |
4302 | 4267 |
4303 | 4268 |
4304 bool String::IsEqualTo(Vector<const char> str) { | 4269 bool String::IsEqualTo(Vector<const char> str) { |
4305 StringShape this_shape(this); | 4270 int slen = length(); |
4306 int slen = length(this_shape); | |
4307 Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder()); | 4271 Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder()); |
4308 decoder->Reset(str.start(), str.length()); | 4272 decoder->Reset(str.start(), str.length()); |
4309 int i; | 4273 int i; |
4310 for (i = 0; i < slen && decoder->has_more(); i++) { | 4274 for (i = 0; i < slen && decoder->has_more(); i++) { |
4311 uc32 r = decoder->GetNext(); | 4275 uc32 r = decoder->GetNext(); |
4312 if (Get(this_shape, i) != r) return false; | 4276 if (Get(i) != r) return false; |
4313 } | 4277 } |
4314 return i == slen && !decoder->has_more(); | 4278 return i == slen && !decoder->has_more(); |
4315 } | 4279 } |
4316 | 4280 |
4317 | 4281 |
4318 uint32_t String::ComputeAndSetHash() { | 4282 uint32_t String::ComputeAndSetHash() { |
4319 // Should only be call if hash code has not yet been computed. | 4283 // Should only be call if hash code has not yet been computed. |
4320 ASSERT(!(length_field() & kHashComputedMask)); | 4284 ASSERT(!(length_field() & kHashComputedMask)); |
4321 | 4285 |
4322 // Compute the hash code. | 4286 // Compute the hash code. |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4356 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false; | 4320 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false; |
4357 result = (result * 10) + d; | 4321 result = (result * 10) + d; |
4358 } | 4322 } |
4359 | 4323 |
4360 *index = result; | 4324 *index = result; |
4361 return true; | 4325 return true; |
4362 } | 4326 } |
4363 | 4327 |
4364 | 4328 |
4365 bool String::SlowAsArrayIndex(uint32_t* index) { | 4329 bool String::SlowAsArrayIndex(uint32_t* index) { |
4366 StringShape shape(this); | 4330 if (length() <= kMaxCachedArrayIndexLength) { |
4367 if (length(shape) <= kMaxCachedArrayIndexLength) { | |
4368 Hash(); // force computation of hash code | 4331 Hash(); // force computation of hash code |
4369 uint32_t field = length_field(); | 4332 uint32_t field = length_field(); |
4370 if ((field & kIsArrayIndexMask) == 0) return false; | 4333 if ((field & kIsArrayIndexMask) == 0) return false; |
4371 *index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift; | 4334 *index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift; |
4372 return true; | 4335 return true; |
4373 } else { | 4336 } else { |
4374 StringInputBuffer buffer(this); | 4337 StringInputBuffer buffer(this); |
4375 return ComputeArrayIndex(&buffer, index, length(shape)); | 4338 return ComputeArrayIndex(&buffer, index, length()); |
4376 } | 4339 } |
4377 } | 4340 } |
4378 | 4341 |
4379 | 4342 |
4380 static inline uint32_t HashField(uint32_t hash, bool is_array_index) { | 4343 static inline uint32_t HashField(uint32_t hash, bool is_array_index) { |
4381 uint32_t result = | 4344 uint32_t result = |
4382 (hash << String::kLongLengthShift) | String::kHashComputedMask; | 4345 (hash << String::kLongLengthShift) | String::kHashComputedMask; |
4383 if (is_array_index) result |= String::kIsArrayIndexMask; | 4346 if (is_array_index) result |= String::kIsArrayIndexMask; |
4384 return result; | 4347 return result; |
4385 } | 4348 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4426 // index. | 4389 // index. |
4427 while (buffer->has_more()) { | 4390 while (buffer->has_more()) { |
4428 hasher.AddCharacterNoIndex(buffer->GetNext()); | 4391 hasher.AddCharacterNoIndex(buffer->GetNext()); |
4429 } | 4392 } |
4430 | 4393 |
4431 return hasher.GetHashField(); | 4394 return hasher.GetHashField(); |
4432 } | 4395 } |
4433 | 4396 |
4434 | 4397 |
4435 Object* String::Slice(int start, int end) { | 4398 Object* String::Slice(int start, int end) { |
4436 StringShape shape(this); | 4399 if (start == 0 && end == length()) return this; |
4437 if (start == 0 && end == length(shape)) return this; | 4400 if (StringShape(this).representation_tag() == kSlicedStringTag) { |
4438 if (shape.representation_tag() == kSlicedStringTag) { | |
4439 // Translate slices of a SlicedString into slices of the | 4401 // Translate slices of a SlicedString into slices of the |
4440 // underlying string buffer. | 4402 // underlying string buffer. |
4441 SlicedString* str = SlicedString::cast(this); | 4403 SlicedString* str = SlicedString::cast(this); |
4442 String* buf = str->buffer(); | 4404 String* buf = str->buffer(); |
4443 return Heap::AllocateSlicedString(buf, | 4405 return Heap::AllocateSlicedString(buf, |
4444 str->start() + start, | 4406 str->start() + start, |
4445 str->start() + end); | 4407 str->start() + end); |
4446 } | 4408 } |
4447 Object* result = Heap::AllocateSlicedString(this, start, end); | 4409 Object* result = Heap::AllocateSlicedString(this, start, end); |
4448 if (result->IsFailure()) { | 4410 if (result->IsFailure()) { |
4449 return result; | 4411 return result; |
4450 } | 4412 } |
4451 // Due to the way we retry after GC on allocation failure we are not allowed | 4413 // Due to the way we retry after GC on allocation failure we are not allowed |
4452 // to fail on allocation after this point. This is the one-allocation rule. | 4414 // to fail on allocation after this point. This is the one-allocation rule. |
4453 | 4415 |
4454 // Try to flatten a cons string that is under the sliced string. | 4416 // Try to flatten a cons string that is under the sliced string. |
4455 // This is to avoid memory leaks and possible stack overflows caused by | 4417 // This is to avoid memory leaks and possible stack overflows caused by |
4456 // building 'towers' of sliced strings on cons strings. | 4418 // building 'towers' of sliced strings on cons strings. |
4457 // This may fail due to an allocation failure (when a GC is needed), but it | 4419 // This may fail due to an allocation failure (when a GC is needed), but it |
4458 // will succeed often enough to avoid the problem. We only have to do this | 4420 // will succeed often enough to avoid the problem. We only have to do this |
4459 // if Heap::AllocateSlicedString actually returned a SlicedString. It will | 4421 // if Heap::AllocateSlicedString actually returned a SlicedString. It will |
4460 // return flat strings for small slices for efficiency reasons. | 4422 // return flat strings for small slices for efficiency reasons. |
4461 String* answer = String::cast(result); | 4423 String* answer = String::cast(result); |
4462 StringShape answer_shape(answer); | 4424 if (StringShape(answer).IsSliced() && |
4463 if (answer_shape.IsSliced() && | 4425 StringShape(this).representation_tag() == kConsStringTag) { |
4464 shape.representation_tag() == kConsStringTag) { | 4426 TryFlatten(); |
4465 TryFlatten(shape); | |
4466 // If the flatten succeeded we might as well make the sliced string point | 4427 // If the flatten succeeded we might as well make the sliced string point |
4467 // to the flat string rather than the cons string. | 4428 // to the flat string rather than the cons string. |
4468 String* second = ConsString::cast(this)->second(); | 4429 String* second = ConsString::cast(this)->second(); |
4469 if (second->length(StringShape(second)) == 0) { | 4430 if (second->length() == 0) { |
4470 SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first()); | 4431 SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first()); |
4471 } | 4432 } |
4472 } | 4433 } |
4473 return answer; | 4434 return answer; |
4474 } | 4435 } |
4475 | 4436 |
4476 | 4437 |
4477 void String::PrintOn(FILE* file) { | 4438 void String::PrintOn(FILE* file) { |
4478 StringShape shape(this); | 4439 int length = this->length(); |
4479 int length = this->length(shape); | |
4480 for (int i = 0; i < length; i++) { | 4440 for (int i = 0; i < length; i++) { |
4481 fprintf(file, "%c", Get(shape, i)); | 4441 fprintf(file, "%c", Get(i)); |
4482 } | 4442 } |
4483 } | 4443 } |
4484 | 4444 |
4485 | 4445 |
4486 void Map::CreateBackPointers() { | 4446 void Map::CreateBackPointers() { |
4487 DescriptorArray* descriptors = instance_descriptors(); | 4447 DescriptorArray* descriptors = instance_descriptors(); |
4488 for (DescriptorReader r(descriptors); !r.eos(); r.advance()) { | 4448 for (DescriptorReader r(descriptors); !r.eos(); r.advance()) { |
4489 if (r.type() == MAP_TRANSITION) { | 4449 if (r.type() == MAP_TRANSITION) { |
4490 // Get target. | 4450 // Get target. |
4491 Map* target = Map::cast(r.GetValue()); | 4451 Map* target = Map::cast(r.GetValue()); |
(...skipping 1535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6027 if (storage) { | 5987 if (storage) { |
6028 element_dictionary()->CopyKeysTo(storage, filter); | 5988 element_dictionary()->CopyKeysTo(storage, filter); |
6029 } | 5989 } |
6030 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); | 5990 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); |
6031 } | 5991 } |
6032 | 5992 |
6033 if (this->IsJSValue()) { | 5993 if (this->IsJSValue()) { |
6034 Object* val = JSValue::cast(this)->value(); | 5994 Object* val = JSValue::cast(this)->value(); |
6035 if (val->IsString()) { | 5995 if (val->IsString()) { |
6036 String* str = String::cast(val); | 5996 String* str = String::cast(val); |
6037 StringShape shape(str); | |
6038 if (storage) { | 5997 if (storage) { |
6039 for (int i = 0; i < str->length(shape); i++) { | 5998 for (int i = 0; i < str->length(); i++) { |
6040 storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER); | 5999 storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER); |
6041 } | 6000 } |
6042 } | 6001 } |
6043 counter += str->length(shape); | 6002 counter += str->length(); |
6044 } | 6003 } |
6045 } | 6004 } |
6046 ASSERT(!storage || storage->length() == counter); | 6005 ASSERT(!storage || storage->length() == counter); |
6047 return counter; | 6006 return counter; |
6048 } | 6007 } |
6049 | 6008 |
6050 | 6009 |
6051 int JSObject::GetEnumElementKeys(FixedArray* storage) { | 6010 int JSObject::GetEnumElementKeys(FixedArray* storage) { |
6052 return GetLocalElementKeys(storage, | 6011 return GetLocalElementKeys(storage, |
6053 static_cast<PropertyAttributes>(DONT_ENUM)); | 6012 static_cast<PropertyAttributes>(DONT_ENUM)); |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6281 | 6240 |
6282 bool IsMatch(Object* string) { | 6241 bool IsMatch(Object* string) { |
6283 return String::cast(string)->Equals(string_); | 6242 return String::cast(string)->Equals(string_); |
6284 } | 6243 } |
6285 | 6244 |
6286 uint32_t Hash() { return string_->Hash(); } | 6245 uint32_t Hash() { return string_->Hash(); } |
6287 | 6246 |
6288 Object* GetObject() { | 6247 Object* GetObject() { |
6289 // If the string is a cons string, attempt to flatten it so that | 6248 // If the string is a cons string, attempt to flatten it so that |
6290 // symbols will most often be flat strings. | 6249 // symbols will most often be flat strings. |
6291 StringShape shape(string_); | 6250 if (StringShape(string_).IsCons()) { |
6292 if (shape.IsCons()) { | |
6293 ConsString* cons_string = ConsString::cast(string_); | 6251 ConsString* cons_string = ConsString::cast(string_); |
6294 cons_string->TryFlatten(shape); | 6252 cons_string->TryFlatten(); |
6295 if (cons_string->second() == Heap::empty_string()) { | 6253 if (cons_string->second() == Heap::empty_string()) { |
6296 string_ = cons_string->first(); | 6254 string_ = cons_string->first(); |
6297 } | 6255 } |
6298 } | 6256 } |
6299 // Transform string to symbol if possible. | 6257 // Transform string to symbol if possible. |
6300 Map* map = Heap::SymbolMapForString(string_); | 6258 Map* map = Heap::SymbolMapForString(string_); |
6301 if (map != NULL) { | 6259 if (map != NULL) { |
6302 string_->set_map(map); | 6260 string_->set_map(map); |
6303 return string_; | 6261 return string_; |
6304 } | 6262 } |
(...skipping 1100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7405 // No break point. | 7363 // No break point. |
7406 if (break_point_objects()->IsUndefined()) return 0; | 7364 if (break_point_objects()->IsUndefined()) return 0; |
7407 // Single beak point. | 7365 // Single beak point. |
7408 if (!break_point_objects()->IsFixedArray()) return 1; | 7366 if (!break_point_objects()->IsFixedArray()) return 1; |
7409 // Multiple break points. | 7367 // Multiple break points. |
7410 return FixedArray::cast(break_point_objects())->length(); | 7368 return FixedArray::cast(break_point_objects())->length(); |
7411 } | 7369 } |
7412 | 7370 |
7413 | 7371 |
7414 } } // namespace v8::internal | 7372 } } // namespace v8::internal |
OLD | NEW |