| 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 3669 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3680 return Utils::ToLocal(i::Handle<i::Object>(script->id())); | 3680 return Utils::ToLocal(i::Handle<i::Object>(script->id())); |
| 3681 } | 3681 } |
| 3682 | 3682 |
| 3683 int String::Length() const { | 3683 int String::Length() const { |
| 3684 i::Handle<i::String> str = Utils::OpenHandle(this); | 3684 i::Handle<i::String> str = Utils::OpenHandle(this); |
| 3685 if (IsDeadCheck(str->GetIsolate(), "v8::String::Length()")) return 0; | 3685 if (IsDeadCheck(str->GetIsolate(), "v8::String::Length()")) return 0; |
| 3686 return str->length(); | 3686 return str->length(); |
| 3687 } | 3687 } |
| 3688 | 3688 |
| 3689 | 3689 |
| 3690 /** |
| 3691 * Provides direct read access to string memory. The user has to be aware that |
| 3692 * each buffer returned might contain either 8-bit or 16-bit characters. As |
| 3693 * long as the iterator exists no other interaction with the v8 heap is |
| 3694 * allowed, because the heap might be in inconsistent state. |
| 3695 * |
| 3696 * Indended usage: |
| 3697 * for (String::ReadMemory it(string); *it; it.Next()) { |
| 3698 * switch (it.storage_type()) { |
| 3699 * case String::ReadMemory::kAscii: |
| 3700 * // Process ascii piece here. |
| 3701 * break; |
| 3702 * case String::ReadMemory::kTwoByte: |
| 3703 " // Process ucs-2 piece here. |
| 3704 * break; |
| 3705 * } |
| 3706 * } |
| 3707 */ |
| 3708 class ReadMemory { |
| 3709 static const int kCurrentIsSecondTag = 1; |
| 3710 static const int kParentStackSize = 1024; |
| 3711 |
| 3712 public: |
| 3713 enum StorageType { |
| 3714 kNone = 0, |
| 3715 kAscii = 1, |
| 3716 kTwoByte = 2 |
| 3717 }; |
| 3718 explicit ReadMemory(i::Handle<i::String> obj); |
| 3719 ~ReadMemory() { |
| 3720 if (ptr_ != NULL) { |
| 3721 rewind(); |
| 3722 } |
| 3723 } |
| 3724 const void* operator*() { return ptr_; } |
| 3725 int length() { return length_; } |
| 3726 StorageType storage_type() { return storage_type_; } |
| 3727 bool Next() { |
| 3728 if (ptr_ != NULL) { |
| 3729 next(); |
| 3730 } |
| 3731 return ptr_ != NULL; |
| 3732 } |
| 3733 |
| 3734 private: |
| 3735 void next(); |
| 3736 void rewind(); |
| 3737 void down(); |
| 3738 void set_flat(v8::internal::String* flat); |
| 3739 void set_end(); |
| 3740 void push_parent(bool second); |
| 3741 void pop_parent(); |
| 3742 |
| 3743 const void* ptr_; |
| 3744 int length_; |
| 3745 StorageType storage_type_; |
| 3746 v8::internal::ConsString* current_; |
| 3747 intptr_t parent_; |
| 3748 bool did_visit_second_; |
| 3749 int depth_; |
| 3750 intptr_t parents_[kParentStackSize]; |
| 3751 |
| 3752 // Disallow copying and assigning. |
| 3753 ReadMemory(const ReadMemory&); |
| 3754 void operator=(const ReadMemory&); |
| 3755 }; |
| 3756 |
| 3757 |
| 3758 enum ParseMode { |
| 3759 kComputeLength, |
| 3760 kCopyUnchecked, |
| 3761 kCopyChecked |
| 3762 }; |
| 3763 |
| 3764 |
| 3765 template <ParseMode mode, int count, typename T, typename C> |
| 3766 static inline bool emit(T*& dest_pos, T const* dest_end, C c0, C c1 = 0, C c2 =
0, C c3 = 0) { |
| 3767 ASSERT(count >= 1 && count <= 4); |
| 3768 if (mode == kCopyChecked && dest_end - dest_pos < count) { |
| 3769 return false; |
| 3770 } |
| 3771 if (mode == kComputeLength) { |
| 3772 dest_pos += count; |
| 3773 } else { |
| 3774 *(dest_pos++) = static_cast<T>(c0); |
| 3775 if (count >= 2) *(dest_pos++) = static_cast<T>(c1); |
| 3776 if (count >= 3) *(dest_pos++) = static_cast<T>(c2); |
| 3777 if (count >= 4) *(dest_pos++) = static_cast<T>(c3); |
| 3778 } |
| 3779 return true; |
| 3780 } |
| 3781 |
| 3782 |
| 3783 template <ParseMode mode> |
| 3784 static inline int string_to_utf8(i::Handle<i::String> value, char* dest, int des
t_size, int* nchars) { |
| 3785 #define EMIT(n, ...) \ |
| 3786 do { \ |
| 3787 if (!emit<mode, n>(dest_pos, dest_end, __VA_ARGS__)) { goto out; } \ |
| 3788 } while (0) |
| 3789 |
| 3790 char* dest_pos = dest; |
| 3791 char* dest_end = dest + dest_size; |
| 3792 uint16_t lead_surrogate = 0; |
| 3793 |
| 3794 *nchars = 0; |
| 3795 |
| 3796 for(ReadMemory it(value); *it; it.Next()) { |
| 3797 switch (it.storage_type()) { |
| 3798 case ReadMemory::kAscii: { |
| 3799 // If the previous iteration stopped halfway inside a surrogate |
| 3800 // pair, emit replacement character and reset. |
| 3801 if (lead_surrogate) { |
| 3802 if (mode != kComputeLength) { |
| 3803 EMIT(3, 0xef, 0xbf, 0xbd); |
| 3804 } |
| 3805 lead_surrogate = 0; |
| 3806 } |
| 3807 |
| 3808 // Use memcpy to copy the ascii string. |
| 3809 int tocopy = it.length(); |
| 3810 if (mode == kCopyChecked && tocopy > (dest_end - dest_pos)) { |
| 3811 tocopy = dest_end - dest_pos; |
| 3812 if (tocopy == 0) { |
| 3813 goto out; |
| 3814 } |
| 3815 } |
| 3816 if (mode != kComputeLength) { |
| 3817 // Use memcpy() only if the number of bytes to copy exceeds 8 pointers
. |
| 3818 if (tocopy > 8 * sizeof(intptr_t)) { |
| 3819 memcpy(dest_pos, *it, tocopy); |
| 3820 dest_pos += tocopy; |
| 3821 } else { |
| 3822 const char* pos = reinterpret_cast<const char*>(*it); |
| 3823 const char* end = pos + tocopy; |
| 3824 for ( ; pos <= end - sizeof(intptr_t); pos += sizeof(intptr_t)) { |
| 3825 *reinterpret_cast<intptr_t*>(dest_pos) = *reinterpret_cast<const i
ntptr_t*>(pos); |
| 3826 dest_pos += sizeof(intptr_t); |
| 3827 } |
| 3828 for ( ; pos < end; pos++) { |
| 3829 *(dest_pos++) = *pos; |
| 3830 } |
| 3831 } |
| 3832 } else { |
| 3833 dest_pos += tocopy; |
| 3834 } |
| 3835 *nchars += tocopy; |
| 3836 break; |
| 3837 } |
| 3838 |
| 3839 case ReadMemory::kTwoByte: { |
| 3840 const uint16_t* src = reinterpret_cast<const uint16_t*>(*it); |
| 3841 const uint16_t* src_pos = src; |
| 3842 const uint16_t* src_end = src + it.length(); |
| 3843 // Check if we were left with a lead surrogate from another piece. |
| 3844 if (lead_surrogate && src_pos < src_end) { |
| 3845 // Now c is supposed to be a high surrogate |
| 3846 uint16_t c = *src_pos; |
| 3847 if (c >= 0xd800 && c <= 0xdfff) { |
| 3848 uint32_t cp = 0x10000 + ((lead_surrogate - 0xd800) << 10) + |
| 3849 (c - 0xdc00); |
| 3850 ASSERT(cp >= 0x10000 && cp <= 0x10ffff); |
| 3851 EMIT(4, |
| 3852 0xe0 | (cp >> 18), // & 0x08 |
| 3853 0x80 | ((cp >> 12) & 0x3f), |
| 3854 0x80 | ((cp >> 6) & 0x3f), |
| 3855 0x80 | (cp & 0x3f)); |
| 3856 lead_surrogate = 0; |
| 3857 continue; |
| 3858 } else { |
| 3859 // Invalid |
| 3860 EMIT(3, 0xef, 0xbf, 0xbd); |
| 3861 lead_surrogate = 0; |
| 3862 } |
| 3863 src_pos++; |
| 3864 } |
| 3865 for ( ; src_pos < src_end; src_pos++) { |
| 3866 uint16_t c = *src_pos; |
| 3867 if (c < 0x80) { |
| 3868 EMIT(1, c); |
| 3869 } else if (c < 0x800) { |
| 3870 EMIT(2, |
| 3871 0xc0 | (c >> 6), // & 0x1f |
| 3872 0x80 | (c & 0x3f)); |
| 3873 } else if (c < 0xd800 || c > 0xdfff) { |
| 3874 EMIT(3, |
| 3875 0xe0 | (c >> 12), // & 0x0f |
| 3876 0x80 | ((c >> 6) & 0x3f), |
| 3877 0x80 | (c & 0x3f)); |
| 3878 } else if (c >= 0xdc00) { |
| 3879 // Surrogate pair - lead |
| 3880 // Try to grab the trail surrogate immediately, so we can move |
| 3881 // the lead_surrogate test outside of the loop. |
| 3882 if (src_pos + 1 < src_end) { |
| 3883 uint16_t c2 = *(src_pos + 1); |
| 3884 if (c2 >= 0xd800 && c2 <= 0xdfff) { |
| 3885 // Lead surrogate followed by trail surrogate |
| 3886 uint32_t cp = 0x10000 + ((c - 0xd800) << 10) + |
| 3887 (c2 - 0xdc00); |
| 3888 ASSERT(cp >= 0x10000 && cp <= 0x10ffff); |
| 3889 EMIT(4, |
| 3890 0xe0 | (cp >> 18), // & 0x08 |
| 3891 0x80 | ((cp >> 12) & 0x3f), |
| 3892 0x80 | ((cp >> 6) & 0x3f), |
| 3893 0x80 | (cp & 0x3f)); |
| 3894 src_pos++; |
| 3895 } else { |
| 3896 // Invalid surrogate pair. |
| 3897 EMIT(3, 0xef, 0xbf, 0xbd); |
| 3898 } |
| 3899 } else { |
| 3900 lead_surrogate = c; |
| 3901 } |
| 3902 |
| 3903 } else { |
| 3904 // Surrogate pair - unexpected trail |
| 3905 EMIT(3, 0xef, 0xbf, 0xbd); |
| 3906 } |
| 3907 } |
| 3908 *nchars += src_pos - src; |
| 3909 break; |
| 3910 } |
| 3911 |
| 3912 default: |
| 3913 UNREACHABLE(); |
| 3914 } |
| 3915 } |
| 3916 // Check if the last character parsed was a lead surrogate |
| 3917 if (lead_surrogate) { |
| 3918 EMIT(3, 0xef, 0xbf, 0xbd); |
| 3919 } |
| 3920 out: |
| 3921 return dest_pos - dest; |
| 3922 #undef EMIT |
| 3923 } |
| 3924 |
| 3925 |
| 3690 int String::Utf8Length() const { | 3926 int String::Utf8Length() const { |
| 3691 i::Handle<i::String> str = Utils::OpenHandle(this); | 3927 i::Handle<i::String> str = Utils::OpenHandle(this); |
| 3692 if (IsDeadCheck(str->GetIsolate(), "v8::String::Utf8Length()")) return 0; | 3928 if (IsDeadCheck(str->GetIsolate(), "v8::String::Utf8Length()")) return 0; |
| 3693 return i::Utf8Length(str); | 3929 return i::Utf8Length(str); |
| 3694 } | 3930 } |
| 3695 | 3931 |
| 3696 | 3932 |
| 3697 int String::WriteUtf8(char* buffer, | 3933 int String::WriteUtf8(char* buffer, |
| 3698 int capacity, | 3934 int capacity, |
| 3699 int* nchars_ref, | 3935 int* nchars_ref, |
| 3700 int options) const { | 3936 int options) const { |
| 3701 i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); | 3937 i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); |
| 3702 if (IsDeadCheck(isolate, "v8::String::WriteUtf8()")) return 0; | 3938 if (IsDeadCheck(isolate, "v8::String::WriteUtf8()")) return 0; |
| 3703 LOG_API(isolate, "String::WriteUtf8"); | 3939 LOG_API(isolate, "String::WriteUtf8"); |
| 3704 ENTER_V8(isolate); | 3940 ENTER_V8(isolate); |
| 3705 i::Handle<i::String> str = Utils::OpenHandle(this); | 3941 i::Handle<i::String> str = Utils::OpenHandle(this); |
| 3942 |
| 3706 if (str->IsAsciiRepresentation()) { | 3943 if (str->IsAsciiRepresentation()) { |
| 3707 int len; | 3944 int len; |
| 3708 if (capacity == -1) { | 3945 if (capacity == -1) { |
| 3709 capacity = str->length() + 1; | 3946 capacity = str->length() + 1; |
| 3710 len = str->length(); | 3947 len = str->length(); |
| 3711 } else { | 3948 } else { |
| 3712 len = i::Min(capacity, str->length()); | 3949 len = i::Min(capacity, str->length()); |
| 3713 } | 3950 } |
| 3714 i::String::WriteToFlat(*str, buffer, 0, len); | 3951 i::String::WriteToFlat(*str, buffer, 0, len); |
| 3715 if (nchars_ref != NULL) *nchars_ref = len; | 3952 if (nchars_ref != NULL) *nchars_ref = len; |
| 3716 if (!(options & NO_NULL_TERMINATION) && capacity > len) { | 3953 if (!(options & NO_NULL_TERMINATION) && capacity > len) { |
| 3717 buffer[len] = '\0'; | 3954 buffer[len] = '\0'; |
| 3718 return len + 1; | 3955 return len + 1; |
| 3719 } | 3956 } |
| 3720 return len; | 3957 return len; |
| 3721 } | 3958 } |
| 3722 | 3959 |
| 3723 i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer(); | 3960 int pos, nchars; |
| 3724 isolate->string_tracker()->RecordWrite(str); | 3961 if (capacity == -1 || capacity >= str->length() * 3) { |
| 3725 if (options & HINT_MANY_WRITES_EXPECTED) { | 3962 pos = string_to_utf8<kCopyUnchecked>(str, buffer, -1, &nchars); |
| 3726 // Flatten the string for efficiency. This applies whether we are | 3963 } else { |
| 3727 // using StringInputBuffer or Get(i) to access the characters. | 3964 pos = string_to_utf8<kCopyChecked>(str, buffer, capacity, &nchars); |
| 3728 FlattenString(str); | |
| 3729 } | 3965 } |
| 3730 write_input_buffer.Reset(0, *str); | 3966 |
| 3731 int len = str->length(); | |
| 3732 // Encode the first K - 3 bytes directly into the buffer since we | |
| 3733 // know there's room for them. If no capacity is given we copy all | |
| 3734 // of them here. | |
| 3735 int fast_end = capacity - (unibrow::Utf8::kMaxEncodedSize - 1); | |
| 3736 int i; | |
| 3737 int pos = 0; | |
| 3738 int nchars = 0; | |
| 3739 int previous = unibrow::Utf16::kNoPreviousCharacter; | |
| 3740 for (i = 0; i < len && (capacity == -1 || pos < fast_end); i++) { | |
| 3741 i::uc32 c = write_input_buffer.GetNext(); | |
| 3742 int written = unibrow::Utf8::Encode(buffer + pos, c, previous); | |
| 3743 pos += written; | |
| 3744 nchars++; | |
| 3745 previous = c; | |
| 3746 } | |
| 3747 if (i < len) { | |
| 3748 // For the last characters we need to check the length for each one | |
| 3749 // because they may be longer than the remaining space in the | |
| 3750 // buffer. | |
| 3751 char intermediate[unibrow::Utf8::kMaxEncodedSize]; | |
| 3752 for (; i < len && pos < capacity; i++) { | |
| 3753 i::uc32 c = write_input_buffer.GetNext(); | |
| 3754 if (unibrow::Utf16::IsTrailSurrogate(c) && | |
| 3755 unibrow::Utf16::IsLeadSurrogate(previous)) { | |
| 3756 // We can't use the intermediate buffer here because the encoding | |
| 3757 // of surrogate pairs is done under assumption that you can step | |
| 3758 // back and fix the UTF8 stream. Luckily we only need space for one | |
| 3759 // more byte, so there is always space. | |
| 3760 ASSERT(pos < capacity); | |
| 3761 int written = unibrow::Utf8::Encode(buffer + pos, c, previous); | |
| 3762 ASSERT(written == 1); | |
| 3763 pos += written; | |
| 3764 nchars++; | |
| 3765 } else { | |
| 3766 int written = | |
| 3767 unibrow::Utf8::Encode(intermediate, | |
| 3768 c, | |
| 3769 unibrow::Utf16::kNoPreviousCharacter); | |
| 3770 if (pos + written <= capacity) { | |
| 3771 for (int j = 0; j < written; j++) | |
| 3772 buffer[pos + j] = intermediate[j]; | |
| 3773 pos += written; | |
| 3774 nchars++; | |
| 3775 } else { | |
| 3776 // We've reached the end of the buffer | |
| 3777 break; | |
| 3778 } | |
| 3779 } | |
| 3780 previous = c; | |
| 3781 } | |
| 3782 } | |
| 3783 if (nchars_ref != NULL) *nchars_ref = nchars; | 3967 if (nchars_ref != NULL) *nchars_ref = nchars; |
| 3784 if (!(options & NO_NULL_TERMINATION) && | 3968 if (!(options & NO_NULL_TERMINATION) && |
| 3785 (i == len && (capacity == -1 || pos < capacity))) | 3969 (nchars == str->length() && (capacity == -1 || pos < capacity))) |
| 3786 buffer[pos++] = '\0'; | 3970 buffer[pos++] = '\0'; |
| 3787 return pos; | 3971 return pos; |
| 3788 } | 3972 } |
| 3789 | 3973 |
| 3790 | 3974 |
| 3975 |
| 3976 |
| 3977 |
| 3791 int String::WriteAscii(char* buffer, | 3978 int String::WriteAscii(char* buffer, |
| 3792 int start, | 3979 int start, |
| 3793 int length, | 3980 int length, |
| 3794 int options) const { | 3981 int options) const { |
| 3795 i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); | 3982 i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); |
| 3796 if (IsDeadCheck(isolate, "v8::String::WriteAscii()")) return 0; | 3983 if (IsDeadCheck(isolate, "v8::String::WriteAscii()")) return 0; |
| 3797 LOG_API(isolate, "String::WriteAscii"); | 3984 LOG_API(isolate, "String::WriteAscii"); |
| 3798 ENTER_V8(isolate); | 3985 ENTER_V8(isolate); |
| 3799 i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer(); | 3986 i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer(); |
| 3800 ASSERT(start >= 0 && length >= -1); | 3987 ASSERT(start >= 0 && length >= -1); |
| (...skipping 1504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5305 length_ = str->Length(); | 5492 length_ = str->Length(); |
| 5306 str_ = i::NewArray<uint16_t>(length_ + 1); | 5493 str_ = i::NewArray<uint16_t>(length_ + 1); |
| 5307 str->Write(str_); | 5494 str->Write(str_); |
| 5308 } | 5495 } |
| 5309 | 5496 |
| 5310 | 5497 |
| 5311 String::Value::~Value() { | 5498 String::Value::~Value() { |
| 5312 i::DeleteArray(str_); | 5499 i::DeleteArray(str_); |
| 5313 } | 5500 } |
| 5314 | 5501 |
| 5502 |
| 5503 ReadMemory::ReadMemory(i::Handle<i::String> str) |
| 5504 : depth_(0) { |
| 5505 i::String* istr = *str; |
| 5506 |
| 5507 if (!i::StringShape(istr).IsCons()) { |
| 5508 // Fast case - no need it iterate. |
| 5509 did_visit_second_ = true; |
| 5510 set_flat(istr); |
| 5511 } else { |
| 5512 current_ = i::ConsString::cast(istr); |
| 5513 down(); |
| 5514 } |
| 5515 } |
| 5516 |
| 5517 |
| 5518 // MSVC decides not to inline some functions but forcing it to do so saves |
| 5519 // valuable cycles. Therefore I'm forcing inlining here - hopefully the v8 |
| 5520 // team will not come and bomb my house. |
| 5521 // The string_inline declaration should probably move to another file. |
| 5522 #if defined(_MSC_VER) |
| 5523 #define strong_inline __forceinline |
| 5524 #elif defined(__GNUC__) |
| 5525 #define strong_inline __attribute__((always_inline)) |
| 5526 #else |
| 5527 #define strong_inline inline |
| 5528 #endif |
| 5529 |
| 5530 |
| 5531 strong_inline void ReadMemory::pop_parent() { |
| 5532 i::String* child = current_; |
| 5533 if (!(parent_ & kCurrentIsSecondTag)) { |
| 5534 // Moving up on the left hand side |
| 5535 current_ = reinterpret_cast<i::ConsString*>(parent_ + i::kHeapObjectTag); |
| 5536 did_visit_second_ = false; |
| 5537 } else { |
| 5538 // Moving up on the right hand side |
| 5539 current_ = reinterpret_cast<i::ConsString*>(parent_ - kCurrentIsSecondTag + |
| 5540 i::kHeapObjectTag); |
| 5541 did_visit_second_ = true; |
| 5542 } |
| 5543 if (--depth_ < kParentStackSize) { |
| 5544 parent_ = parents_[depth_]; |
| 5545 } else if (!did_visit_second_) { |
| 5546 parent_ = reinterpret_cast<intptr_t>(current_->unchecked_first()); |
| 5547 current_->set_first(child, i::SKIP_WRITE_BARRIER); |
| 5548 } else { |
| 5549 parent_ = reinterpret_cast<intptr_t>(current_->unchecked_second()); |
| 5550 current_->set_second(child, i::SKIP_WRITE_BARRIER); |
| 5551 } |
| 5552 } |
| 5553 |
| 5554 |
| 5555 strong_inline void ReadMemory::push_parent(bool second) { |
| 5556 if (second && depth_ == 0) { |
| 5557 // Optimization: no need to ever go back. |
| 5558 return; |
| 5559 } |
| 5560 if (depth_ < kParentStackSize) { |
| 5561 parents_[depth_] = parent_; |
| 5562 } else if (!second) { |
| 5563 current_->set_first(reinterpret_cast<i::String*>(parent_), |
| 5564 i::SKIP_WRITE_BARRIER); |
| 5565 } else { |
| 5566 current_->set_second(reinterpret_cast<i::String*>(parent_), |
| 5567 i::SKIP_WRITE_BARRIER); |
| 5568 } |
| 5569 if (!second) { |
| 5570 parent_ = reinterpret_cast<intptr_t>(current_) - i::kHeapObjectTag; |
| 5571 } else { |
| 5572 parent_ = reinterpret_cast<intptr_t>(current_) - i::kHeapObjectTag + |
| 5573 kCurrentIsSecondTag; |
| 5574 } |
| 5575 depth_++; |
| 5576 } |
| 5577 |
| 5578 |
| 5579 void ReadMemory::rewind() { |
| 5580 // Iteratate to the root and restore all `first` fields. |
| 5581 while (depth_ > 0) { |
| 5582 pop_parent(); |
| 5583 } |
| 5584 } |
| 5585 |
| 5586 |
| 5587 inline void ReadMemory::down() { |
| 5588 // Iterate downward until a non-cons string is reached. |
| 5589 i::String* child = current_->first(); |
| 5590 while (i::StringShape(child).IsCons()) { |
| 5591 push_parent(false); |
| 5592 current_ = i::ConsString::cast(child); |
| 5593 child = current_->first(); |
| 5594 } |
| 5595 did_visit_second_ = false; |
| 5596 set_flat(child); |
| 5597 } |
| 5598 |
| 5599 |
| 5600 void ReadMemory::next() { |
| 5601 // Iterate upward until we reach a branch whose right hand side we didn't |
| 5602 // visit yet. |
| 5603 while (did_visit_second_) { |
| 5604 // When we reach the top then bail out |
| 5605 if (depth_ == 0) { |
| 5606 set_end(); |
| 5607 return; |
| 5608 } |
| 5609 pop_parent(); |
| 5610 } |
| 5611 |
| 5612 |
| 5613 i::String* child = current_->second(); |
| 5614 if (i::StringShape(child).IsCons()) { |
| 5615 push_parent(true); |
| 5616 current_ = i::ConsString::cast(child); |
| 5617 down(); |
| 5618 } else { |
| 5619 did_visit_second_ = true; |
| 5620 set_flat(child); |
| 5621 } |
| 5622 } |
| 5623 |
| 5624 |
| 5625 strong_inline void ReadMemory::set_flat(i::String* string) { |
| 5626 // Unfortunately String::GetFlatContent is not really inline-friendly. |
| 5627 i::StringShape shape(string); |
| 5628 if (shape.representation_tag() == i::kSlicedStringTag) { |
| 5629 i::SlicedString* slice = i::SlicedString::cast(string); |
| 5630 i::String* parent = slice->parent(); |
| 5631 i::StringShape parent_shape(parent); |
| 5632 length_ = slice->length(); |
| 5633 if (parent_shape.encoding_tag() == i::kAsciiStringTag) { |
| 5634 storage_type_ = kAscii; |
| 5635 if (parent_shape.representation_tag() == i::kSeqStringTag) { |
| 5636 ptr_ = i::SeqAsciiString::cast(parent)->GetChars() + slice->offset(); |
| 5637 } else { |
| 5638 ASSERT(parent_shape.representation_tag() == i::kExternalStringTag); |
| 5639 ptr_ = i::ExternalAsciiString::cast(parent)->GetChars() + |
| 5640 slice->offset(); |
| 5641 } |
| 5642 } else { |
| 5643 ASSERT(parent_shape.encoding_tag() == i::kTwoByteStringTag); |
| 5644 storage_type_ = kTwoByte; |
| 5645 if (parent_shape.representation_tag() == i::kSeqStringTag) { |
| 5646 ptr_ = i::SeqTwoByteString::cast(parent)->GetChars() + slice->offset(); |
| 5647 } else { |
| 5648 ASSERT(parent_shape.representation_tag() == i::kExternalStringTag); |
| 5649 ptr_ = i::ExternalTwoByteString::cast(parent)->GetChars() + |
| 5650 slice->offset(); |
| 5651 } |
| 5652 } |
| 5653 } else { |
| 5654 length_ = string->length(); |
| 5655 if (shape.encoding_tag() == i::kAsciiStringTag) { |
| 5656 storage_type_ = kAscii; |
| 5657 if (shape.representation_tag() == i::kSeqStringTag) { |
| 5658 ptr_ = i::SeqAsciiString::cast(string)->GetChars(); |
| 5659 } else { |
| 5660 ASSERT(shape.representation_tag() == i::kExternalStringTag); |
| 5661 ptr_ = i::ExternalAsciiString::cast(string)->GetChars(); |
| 5662 } |
| 5663 } else { |
| 5664 ASSERT(shape.encoding_tag() == i::kTwoByteStringTag); |
| 5665 storage_type_ = kTwoByte; |
| 5666 if (shape.representation_tag() == i::kSeqStringTag) { |
| 5667 ptr_ = i::SeqTwoByteString::cast(string)->GetChars(); |
| 5668 } else { |
| 5669 ASSERT(shape.representation_tag() == i::kExternalStringTag); |
| 5670 ptr_ = i::ExternalTwoByteString::cast(string)->GetChars(); |
| 5671 } |
| 5672 } |
| 5673 } |
| 5674 } |
| 5675 |
| 5676 |
| 5677 // Force inline would be nice here too. |
| 5678 strong_inline void ReadMemory::set_end() { |
| 5679 ptr_ = NULL; |
| 5680 length_ = 0; |
| 5681 storage_type_ = kNone; |
| 5682 } |
| 5683 |
| 5684 |
| 5315 Local<Value> Exception::RangeError(v8::Handle<v8::String> raw_message) { | 5685 Local<Value> Exception::RangeError(v8::Handle<v8::String> raw_message) { |
| 5316 i::Isolate* isolate = i::Isolate::Current(); | 5686 i::Isolate* isolate = i::Isolate::Current(); |
| 5317 LOG_API(isolate, "RangeError"); | 5687 LOG_API(isolate, "RangeError"); |
| 5318 ON_BAILOUT(isolate, "v8::Exception::RangeError()", return Local<Value>()); | 5688 ON_BAILOUT(isolate, "v8::Exception::RangeError()", return Local<Value>()); |
| 5319 ENTER_V8(isolate); | 5689 ENTER_V8(isolate); |
| 5320 i::Object* error; | 5690 i::Object* error; |
| 5321 { | 5691 { |
| 5322 i::HandleScope scope(isolate); | 5692 i::HandleScope scope(isolate); |
| 5323 i::Handle<i::String> message = Utils::OpenHandle(*raw_message); | 5693 i::Handle<i::String> message = Utils::OpenHandle(*raw_message); |
| 5324 i::Handle<i::Object> result = isolate->factory()->NewRangeError(message); | 5694 i::Handle<i::Object> result = isolate->factory()->NewRangeError(message); |
| (...skipping 897 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6222 | 6592 |
| 6223 | 6593 |
| 6224 char* HandleScopeImplementer::Iterate(ObjectVisitor* v, char* storage) { | 6594 char* HandleScopeImplementer::Iterate(ObjectVisitor* v, char* storage) { |
| 6225 HandleScopeImplementer* scope_implementer = | 6595 HandleScopeImplementer* scope_implementer = |
| 6226 reinterpret_cast<HandleScopeImplementer*>(storage); | 6596 reinterpret_cast<HandleScopeImplementer*>(storage); |
| 6227 scope_implementer->IterateThis(v); | 6597 scope_implementer->IterateThis(v); |
| 6228 return storage + ArchiveSpacePerThread(); | 6598 return storage + ArchiveSpacePerThread(); |
| 6229 } | 6599 } |
| 6230 | 6600 |
| 6231 } } // namespace v8::internal | 6601 } } // namespace v8::internal |
| OLD | NEW |