Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Side by Side Diff: src/json-stringifier.h

Issue 12257005: Improve JSON stringifier's escape check. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: reduce impact on the scanner. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/heap.cc ('k') | src/parser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 static const int kPartLengthGrowthFactor = 2; 47 static const int kPartLengthGrowthFactor = 2;
48 48
49 enum Result { UNCHANGED, SUCCESS, EXCEPTION, CIRCULAR, STACK_OVERFLOW }; 49 enum Result { UNCHANGED, SUCCESS, EXCEPTION, CIRCULAR, STACK_OVERFLOW };
50 50
51 void Extend(); 51 void Extend();
52 52
53 void ChangeEncoding(); 53 void ChangeEncoding();
54 54
55 void ShrinkCurrentPart(); 55 void ShrinkCurrentPart();
56 56
57 template <bool is_ascii, typename Char> 57 template <bool ascii_mode, typename Char>
58 INLINE(void Append_(Char c)); 58 INLINE(void Append_(Char c));
59 59
60 template <bool is_ascii, typename Char> 60 template <bool ascii_mode, typename Char>
61 INLINE(void Append_(const Char* chars)); 61 INLINE(void Append_(const Char* chars));
62 62
63 INLINE(void Append(uint8_t c)) { 63 INLINE(void Append(uint8_t c)) {
64 if (is_ascii_) { 64 if (ascii_mode_) {
65 Append_<true>(c); 65 Append_<true>(c);
66 } else { 66 } else {
67 Append_<false>(c); 67 Append_<false>(c);
68 } 68 }
69 } 69 }
70 70
71 INLINE(void AppendAscii(const char* chars)) { 71 INLINE(void AppendAscii(const char* chars)) {
72 if (is_ascii_) { 72 if (ascii_mode_) {
73 Append_<true>(reinterpret_cast<const uint8_t*>(chars)); 73 Append_<true>(reinterpret_cast<const uint8_t*>(chars));
74 } else { 74 } else {
75 Append_<false>(reinterpret_cast<const uint8_t*>(chars)); 75 Append_<false>(reinterpret_cast<const uint8_t*>(chars));
76 } 76 }
77 } 77 }
78 78
79 Handle<Object> ApplyToJsonFunction(Handle<Object> object, 79 Handle<Object> ApplyToJsonFunction(Handle<Object> object,
80 Handle<Object> key); 80 Handle<Object> key);
81 81
82 Result SerializeGeneric(Handle<Object> object, 82 Result SerializeGeneric(Handle<Object> object,
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 123
124 Result SerializeJSValue(Handle<JSValue> object); 124 Result SerializeJSValue(Handle<JSValue> object);
125 125
126 INLINE(Result SerializeJSArray(Handle<JSArray> object)); 126 INLINE(Result SerializeJSArray(Handle<JSArray> object));
127 INLINE(Result SerializeJSObject(Handle<JSObject> object)); 127 INLINE(Result SerializeJSObject(Handle<JSObject> object));
128 128
129 Result SerializeJSArraySlow(Handle<JSArray> object, int length); 129 Result SerializeJSArraySlow(Handle<JSArray> object, int length);
130 130
131 void SerializeString(Handle<String> object); 131 void SerializeString(Handle<String> object);
132 132
133 template <typename SrcChar, typename DestChar> 133 template <bool printable_ascii_only, typename SrcChar, typename DestChar>
134 INLINE(void SerializeStringUnchecked_(const SrcChar* src, 134 INLINE(void SerializeStringUnchecked_(const SrcChar* src,
135 DestChar* dest, 135 DestChar* dest,
136 int length)); 136 int length));
137 137
138 template <bool is_ascii, typename Char> 138 template <bool printable_ascii_only, bool ascii_mode, typename Char>
139 INLINE(void SerializeString_(Handle<String> string)); 139 INLINE(void SerializeString_(Handle<String> string));
140 140
141 template <typename Char> 141 template <bool printable_ascii_only, typename Char>
142 INLINE(bool DoNotEscape(Char c)); 142 INLINE(bool DoNotEscape(Char c));
143 143
144 template <typename Char> 144 template <typename Char>
145 INLINE(Vector<const Char> GetCharVector(Handle<String> string)); 145 INLINE(Vector<const Char> GetCharVector(Handle<String> string));
146 146
147 Result StackPush(Handle<Object> object); 147 Result StackPush(Handle<Object> object);
148 void StackPop(); 148 void StackPop();
149 149
150 INLINE(Handle<String> accumulator()) { 150 INLINE(Handle<String> accumulator()) {
151 return Handle<String>(String::cast(accumulator_store_->value()), isolate_); 151 return Handle<String>(String::cast(accumulator_store_->value()), isolate_);
152 } 152 }
153 153
154 INLINE(void set_accumulator(Handle<String> string)) { 154 INLINE(void set_accumulator(Handle<String> string)) {
155 return accumulator_store_->set_value(*string); 155 return accumulator_store_->set_value(*string);
156 } 156 }
157 157
158 Isolate* isolate_; 158 Isolate* isolate_;
159 Factory* factory_; 159 Factory* factory_;
160 // We use a value wrapper for the string accumulator to keep the 160 // We use a value wrapper for the string accumulator to keep the
161 // (indirect) handle to it in the outermost handle scope. 161 // (indirect) handle to it in the outermost handle scope.
162 Handle<JSValue> accumulator_store_; 162 Handle<JSValue> accumulator_store_;
163 Handle<String> current_part_; 163 Handle<String> current_part_;
164 Handle<String> tojson_symbol_; 164 Handle<String> tojson_symbol_;
165 Handle<JSArray> stack_; 165 Handle<JSArray> stack_;
166 int current_index_; 166 int current_index_;
167 int part_length_; 167 int part_length_;
168 bool is_ascii_; 168 bool ascii_mode_;
169 169
170 static const int kJsonEscapeTableEntrySize = 8; 170 static const int kJsonEscapeTableEntrySize = 8;
171 static const char* const JsonEscapeTable; 171 static const char* const JsonEscapeTable;
172 }; 172 };
173 173
174 174
175 // Translation table to escape ASCII characters. 175 // Translation table to escape ASCII characters.
176 // Table entries start at a multiple of 8 and are null-terminated. 176 // Table entries start at a multiple of 8 and are null-terminated.
177 const char* const BasicJsonStringifier::JsonEscapeTable = 177 const char* const BasicJsonStringifier::JsonEscapeTable =
178 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 " 178 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
(...skipping 24 matching lines...) Expand all
203 "d\0 e\0 f\0 g\0 " 203 "d\0 e\0 f\0 g\0 "
204 "h\0 i\0 j\0 k\0 " 204 "h\0 i\0 j\0 k\0 "
205 "l\0 m\0 n\0 o\0 " 205 "l\0 m\0 n\0 o\0 "
206 "p\0 q\0 r\0 s\0 " 206 "p\0 q\0 r\0 s\0 "
207 "t\0 u\0 v\0 w\0 " 207 "t\0 u\0 v\0 w\0 "
208 "x\0 y\0 z\0 {\0 " 208 "x\0 y\0 z\0 {\0 "
209 "|\0 }\0 ~\0 \177\0 "; 209 "|\0 }\0 ~\0 \177\0 ";
210 210
211 211
212 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate) 212 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
213 : isolate_(isolate), current_index_(0), is_ascii_(true) { 213 : isolate_(isolate), current_index_(0), ascii_mode_(true) {
214 factory_ = isolate_->factory(); 214 factory_ = isolate_->factory();
215 accumulator_store_ = Handle<JSValue>::cast( 215 accumulator_store_ = Handle<JSValue>::cast(
216 factory_->ToObject(factory_->empty_string())); 216 factory_->ToObject(factory_->empty_string()));
217 part_length_ = kInitialPartLength; 217 part_length_ = kInitialPartLength;
218 current_part_ = factory_->NewRawOneByteString(kInitialPartLength); 218 current_part_ = factory_->NewRawOneByteString(kInitialPartLength);
219 tojson_symbol_ = 219 tojson_symbol_ =
220 factory_->LookupOneByteSymbol(STATIC_ASCII_VECTOR("toJSON")); 220 factory_->LookupOneByteSymbol(STATIC_ASCII_VECTOR("toJSON"));
221 stack_ = factory_->NewJSArray(8); 221 stack_ = factory_->NewJSArray(8);
222 } 222 }
223 223
224 224
225 MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) { 225 MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) {
226 switch (SerializeObject(object)) { 226 switch (SerializeObject(object)) {
227 case UNCHANGED: 227 case UNCHANGED:
228 return isolate_->heap()->undefined_value(); 228 return isolate_->heap()->undefined_value();
229 case SUCCESS: 229 case SUCCESS:
230 ShrinkCurrentPart(); 230 ShrinkCurrentPart();
231 return *factory_->NewConsString(accumulator(), current_part_); 231 return *factory_->NewConsString(accumulator(), current_part_);
232 case CIRCULAR: 232 case CIRCULAR:
233 return isolate_->Throw(*factory_->NewTypeError( 233 return isolate_->Throw(*factory_->NewTypeError(
234 "circular_structure", HandleVector<Object>(NULL, 0))); 234 "circular_structure", HandleVector<Object>(NULL, 0)));
235 case STACK_OVERFLOW: 235 case STACK_OVERFLOW:
236 return isolate_->StackOverflow(); 236 return isolate_->StackOverflow();
237 default: 237 default:
238 return Failure::Exception(); 238 return Failure::Exception();
239 } 239 }
240 } 240 }
241 241
242 242
243 template <bool is_ascii, typename Char> 243 template <bool ascii_mode, typename Char>
244 void BasicJsonStringifier::Append_(Char c) { 244 void BasicJsonStringifier::Append_(Char c) {
245 if (is_ascii) { 245 if (ascii_mode) {
246 SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet( 246 SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet(
247 current_index_++, c); 247 current_index_++, c);
248 } else { 248 } else {
249 SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet( 249 SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
250 current_index_++, c); 250 current_index_++, c);
251 } 251 }
252 if (current_index_ == part_length_) Extend(); 252 if (current_index_ == part_length_) Extend();
253 } 253 }
254 254
255 255
256 template <bool is_ascii, typename Char> 256 template <bool ascii_mode, typename Char>
257 void BasicJsonStringifier::Append_(const Char* chars) { 257 void BasicJsonStringifier::Append_(const Char* chars) {
258 for ( ; *chars != '\0'; chars++) Append_<is_ascii, Char>(*chars); 258 for ( ; *chars != '\0'; chars++) Append_<ascii_mode, Char>(*chars);
259 } 259 }
260 260
261 261
262 Handle<Object> BasicJsonStringifier::ApplyToJsonFunction( 262 Handle<Object> BasicJsonStringifier::ApplyToJsonFunction(
263 Handle<Object> object, Handle<Object> key) { 263 Handle<Object> object, Handle<Object> key) {
264 LookupResult lookup(isolate_); 264 LookupResult lookup(isolate_);
265 JSObject::cast(*object)->LookupRealNamedProperty(*tojson_symbol_, &lookup); 265 JSObject::cast(*object)->LookupRealNamedProperty(*tojson_symbol_, &lookup);
266 if (!lookup.IsProperty()) return object; 266 if (!lookup.IsProperty()) return object;
267 PropertyAttributes attr; 267 PropertyAttributes attr;
268 Handle<Object> fun = 268 Handle<Object> fun =
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
601 current_part_ = Handle<String>( 601 current_part_ = Handle<String>(
602 SeqString::cast(*current_part_)->Truncate(current_index_), isolate_); 602 SeqString::cast(*current_part_)->Truncate(current_index_), isolate_);
603 } 603 }
604 604
605 605
606 void BasicJsonStringifier::Extend() { 606 void BasicJsonStringifier::Extend() {
607 set_accumulator(factory_->NewConsString(accumulator(), current_part_)); 607 set_accumulator(factory_->NewConsString(accumulator(), current_part_));
608 if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) { 608 if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
609 part_length_ *= kPartLengthGrowthFactor; 609 part_length_ *= kPartLengthGrowthFactor;
610 } 610 }
611 if (is_ascii_) { 611 if (ascii_mode_) {
612 current_part_ = factory_->NewRawOneByteString(part_length_); 612 current_part_ = factory_->NewRawOneByteString(part_length_);
613 } else { 613 } else {
614 current_part_ = factory_->NewRawTwoByteString(part_length_); 614 current_part_ = factory_->NewRawTwoByteString(part_length_);
615 } 615 }
616 current_index_ = 0; 616 current_index_ = 0;
617 } 617 }
618 618
619 619
620 void BasicJsonStringifier::ChangeEncoding() { 620 void BasicJsonStringifier::ChangeEncoding() {
621 ShrinkCurrentPart(); 621 ShrinkCurrentPart();
622 set_accumulator(factory_->NewConsString(accumulator(), current_part_)); 622 set_accumulator(factory_->NewConsString(accumulator(), current_part_));
623 current_part_ = factory_->NewRawTwoByteString(part_length_); 623 current_part_ = factory_->NewRawTwoByteString(part_length_);
624 current_index_ = 0; 624 current_index_ = 0;
625 is_ascii_ = false; 625 ascii_mode_ = false;
626 } 626 }
627 627
628 628
629 template <typename SrcChar, typename DestChar> 629 template < bool printable_ascii_only, typename SrcChar, typename DestChar>
630 void BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src, 630 void BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
631 DestChar* dest, 631 DestChar* dest,
632 int length) { 632 int length) {
633 dest += current_index_; 633 dest += current_index_;
634 DestChar* dest_start = dest; 634 DestChar* dest_start = dest;
635 635
636 // Assert that uc16 character is not truncated down to 8 bit. 636 // Assert that uc16 character is not truncated down to 8 bit.
637 // The <uc16, char> version of this method must not be called. 637 // The <uc16, char> version of this method must not be called.
638 ASSERT(sizeof(*dest) >= sizeof(*src)); 638 ASSERT(sizeof(*dest) >= sizeof(*src));
639 639
640 for (int i = 0; i < length; i++) { 640 for (int i = 0; i < length; i++) {
641 SrcChar c = src[i]; 641 SrcChar c = src[i];
642 if (DoNotEscape(c)) { 642 if (DoNotEscape<printable_ascii_only>(c)) {
643 *(dest++) = static_cast<DestChar>(c); 643 *(dest++) = static_cast<DestChar>(c);
644 } else { 644 } else {
645 const char* chars = &JsonEscapeTable[c * kJsonEscapeTableEntrySize]; 645 const char* chars = &JsonEscapeTable[c * kJsonEscapeTableEntrySize];
646 while (*chars != '\0') *(dest++) = *(chars++); 646 while (*chars != '\0') *(dest++) = *(chars++);
647 } 647 }
648 } 648 }
649 649
650 current_index_ += static_cast<int>(dest - dest_start); 650 current_index_ += static_cast<int>(dest - dest_start);
651 } 651 }
652 652
653 653
654 template <bool is_ascii, typename Char> 654 template <bool printable_ascii_only, bool ascii_mode, typename Char>
655 void BasicJsonStringifier::SerializeString_(Handle<String> string) { 655 void BasicJsonStringifier::SerializeString_(Handle<String> string) {
656 int length = string->length(); 656 int length = string->length();
657 Append_<is_ascii, char>('"'); 657 Append_<ascii_mode, char>('"');
658 // We make a rough estimate to find out if the current string can be 658 // We make a rough estimate to find out if the current string can be
659 // serialized without allocating a new string part. The worst case length of 659 // serialized without allocating a new string part. The worst case length of
660 // an escaped character is 6. Shifting the remainin string length right by 3 660 // an escaped character is 6. Shifting the remainin string length right by 3
661 // is a more pessimistic estimate, but faster to calculate. 661 // is a more pessimistic estimate, but faster to calculate.
662 662
663 if (((part_length_ - current_index_) >> 3) > length) { 663 if (((part_length_ - current_index_) >> 3) > length) {
664 AssertNoAllocation no_allocation; 664 AssertNoAllocation no_allocation;
665 Vector<const Char> vector = GetCharVector<Char>(string); 665 Vector<const Char> vector = GetCharVector<Char>(string);
666 if (is_ascii) { 666 if (ascii_mode) {
667 SerializeStringUnchecked_( 667 SerializeStringUnchecked_<printable_ascii_only>(
668 vector.start(), 668 vector.start(),
669 SeqOneByteString::cast(*current_part_)->GetChars(), 669 SeqOneByteString::cast(*current_part_)->GetChars(),
670 length); 670 length);
671 } else { 671 } else {
672 SerializeStringUnchecked_( 672 SerializeStringUnchecked_<printable_ascii_only>(
673 vector.start(), 673 vector.start(),
674 SeqTwoByteString::cast(*current_part_)->GetChars(), 674 SeqTwoByteString::cast(*current_part_)->GetChars(),
675 length); 675 length);
676 } 676 }
677 } else { 677 } else {
678 String* string_location = *string; 678 String* string_location = *string;
679 Vector<const Char> vector = GetCharVector<Char>(string); 679 Vector<const Char> vector = GetCharVector<Char>(string);
680 for (int i = 0; i < length; i++) { 680 for (int i = 0; i < length; i++) {
681 Char c = vector[i]; 681 Char c = vector[i];
682 if (DoNotEscape(c)) { 682 if (DoNotEscape<printable_ascii_only>(c)) {
683 Append_<is_ascii, Char>(c); 683 Append_<ascii_mode, Char>(c);
684 } else { 684 } else {
685 Append_<is_ascii, uint8_t>( 685 Append_<ascii_mode, uint8_t>(
686 reinterpret_cast<const uint8_t*>( 686 reinterpret_cast<const uint8_t*>(
687 &JsonEscapeTable[c * kJsonEscapeTableEntrySize])); 687 &JsonEscapeTable[c * kJsonEscapeTableEntrySize]));
688 } 688 }
689 // If GC moved the string, we need to refresh the vector. 689 // If GC moved the string, we need to refresh the vector.
690 if (*string != string_location) { 690 if (*string != string_location) {
691 vector = GetCharVector<Char>(string); 691 vector = GetCharVector<Char>(string);
692 string_location = *string; 692 string_location = *string;
693 } 693 }
694 } 694 }
695 } 695 }
696 696
697 Append_<is_ascii, uint8_t>('"'); 697 Append_<ascii_mode, uint8_t>('"');
698 } 698 }
699 699
700 700
701 template <typename Char> 701 template <bool printable_ascii_only, typename Char>
702 bool BasicJsonStringifier::DoNotEscape(Char c) { 702 bool BasicJsonStringifier::DoNotEscape(Char c) {
703 return (c >= 0x80) || (c >= '#' && c <= '~' && c != '\\'); 703 // "Printable" ASCII is in the range 0x20 .. 0x7e.
704 return (c != '"' && c != '\\') &&
705 (printable_ascii_only || (c != 0x7f && c >= 0x20));
704 } 706 }
705 707
706 708
707 template <> 709 template <>
708 Vector<const uint8_t> BasicJsonStringifier::GetCharVector( 710 Vector<const uint8_t> BasicJsonStringifier::GetCharVector(
709 Handle<String> string) { 711 Handle<String> string) {
710 String::FlatContent flat = string->GetFlatContent(); 712 String::FlatContent flat = string->GetFlatContent();
711 ASSERT(flat.IsAscii()); 713 ASSERT(flat.IsAscii());
712 return flat.ToOneByteVector(); 714 return flat.ToOneByteVector();
713 } 715 }
714 716
715 717
716 template <> 718 template <>
717 Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) { 719 Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) {
718 String::FlatContent flat = string->GetFlatContent(); 720 String::FlatContent flat = string->GetFlatContent();
719 ASSERT(flat.IsTwoByte()); 721 ASSERT(flat.IsTwoByte());
720 return flat.ToUC16Vector(); 722 return flat.ToUC16Vector();
721 } 723 }
722 724
723 725
724 void BasicJsonStringifier::SerializeString(Handle<String> object) { 726 void BasicJsonStringifier::SerializeString(Handle<String> object) {
725 FlattenString(object); 727 FlattenString(object);
726 String::FlatContent flat = object->GetFlatContent(); 728 String::FlatContent flat = object->GetFlatContent();
727 if (is_ascii_) { 729 if (ascii_mode_) {
728 if (flat.IsAscii()) { 730 if (flat.IsAscii()) {
729 SerializeString_<true, uint8_t>(object); 731 if (object->map() == isolate_->heap()->printable_ascii_symbol_map()) {
732 SerializeString_<true, true, uint8_t>(object);
733 } else {
734 SerializeString_<false, true, uint8_t>(object);
735 }
730 } else { 736 } else {
731 ChangeEncoding(); 737 ChangeEncoding();
732 SerializeString(object); 738 SerializeString(object);
733 } 739 }
734 } else { 740 } else {
735 if (flat.IsAscii()) { 741 if (flat.IsAscii()) {
736 SerializeString_<false, uint8_t>(object); 742 if (object->map() == isolate_->heap()->printable_ascii_symbol_map()) {
743 SerializeString_<true, false, uint8_t>(object);
744 } else {
745 SerializeString_<false, false, uint8_t>(object);
746 }
737 } else { 747 } else {
738 SerializeString_<false, uc16>(object); 748 SerializeString_<false, false, uc16>(object);
739 } 749 }
740 } 750 }
741 } 751 }
742 752
743 } } // namespace v8::internal 753 } } // namespace v8::internal
744 754
745 #endif // V8_JSON_STRINGIFIER_H_ 755 #endif // V8_JSON_STRINGIFIER_H_
OLDNEW
« no previous file with comments | « src/heap.cc ('k') | src/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698