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

Side by Side Diff: src/runtime.cc

Issue 5556012: Speed up quoting of JSON strings by allocating a string that is big enough... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 10 years 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 | « no previous file | src/spaces.h » ('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 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 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 4528 matching lines...) Expand 10 before | Expand all | Expand 10 after
4539 int step; 4539 int step;
4540 destination->Set(dest_position, Unescape(source, i, length, &step)); 4540 destination->Set(dest_position, Unescape(source, i, length, &step));
4541 i += step; 4541 i += step;
4542 } 4542 }
4543 return destination; 4543 return destination;
4544 } 4544 }
4545 4545
4546 4546
4547 static const unsigned int kQuoteTableLength = 128u; 4547 static const unsigned int kQuoteTableLength = 128u;
4548 4548
4549 static const char* const JsonQuotes[kQuoteTableLength] = { 4549 static const int kJsonQuotesCharactersPerEntry = 8;
4550 "\\u0000", "\\u0001", "\\u0002", "\\u0003", 4550 static const char* const JsonQuotes =
4551 "\\u0004", "\\u0005", "\\u0006", "\\u0007", 4551 "\\u0000 \\u0001 \\u0002 \\u0003 "
4552 "\\b", "\\t", "\\n", "\\u000b", 4552 "\\u0004 \\u0005 \\u0006 \\u0007 "
4553 "\\f", "\\r", "\\u000e", "\\u000f", 4553 "\\b \\t \\n \\u000b "
4554 "\\u0010", "\\u0011", "\\u0012", "\\u0013", 4554 "\\f \\r \\u000e \\u000f "
4555 "\\u0014", "\\u0015", "\\u0016", "\\u0017", 4555 "\\u0010 \\u0011 \\u0012 \\u0013 "
4556 "\\u0018", "\\u0019", "\\u001a", "\\u001b", 4556 "\\u0014 \\u0015 \\u0016 \\u0017 "
4557 "\\u001c", "\\u001d", "\\u001e", "\\u001f", 4557 "\\u0018 \\u0019 \\u001a \\u001b "
4558 NULL, NULL, "\\\"", NULL, 4558 "\\u001c \\u001d \\u001e \\u001f "
4559 NULL, NULL, NULL, NULL, 4559 " ! \\\" # "
4560 NULL, NULL, NULL, NULL, 4560 "$ % & ' "
4561 NULL, NULL, NULL, NULL, 4561 "( ) * + "
4562 NULL, NULL, NULL, NULL, 4562 ", - . / "
4563 NULL, NULL, NULL, NULL, 4563 "0 1 2 3 "
4564 NULL, NULL, NULL, NULL, 4564 "4 5 6 7 "
4565 NULL, NULL, NULL, NULL, 4565 "8 9 : ; "
4566 NULL, NULL, NULL, NULL, 4566 "< = > ? "
4567 NULL, NULL, NULL, NULL, 4567 "@ A B C "
4568 NULL, NULL, NULL, NULL, 4568 "D E F G "
4569 NULL, NULL, NULL, NULL, 4569 "H I J K "
4570 NULL, NULL, NULL, NULL, 4570 "L M N O "
4571 NULL, NULL, NULL, NULL, 4571 "P Q R S "
4572 NULL, NULL, NULL, NULL, 4572 "T U V W "
4573 "\\\\", NULL, NULL, NULL, 4573 "X Y Z [ "
4574 NULL, NULL, NULL, NULL, 4574 "\\\\ ] ^ _ "
4575 NULL, NULL, NULL, NULL, 4575 "` a b c "
4576 NULL, NULL, NULL, NULL, 4576 "d e f g "
4577 NULL, NULL, NULL, NULL, 4577 "h i j k "
4578 NULL, NULL, NULL, NULL, 4578 "l m n o "
4579 NULL, NULL, NULL, NULL, 4579 "p q r s "
4580 NULL, NULL, NULL, NULL, 4580 "t u v w "
4581 NULL, NULL, NULL, NULL, 4581 "x y z { "
4582 }; 4582 "| } ~ \177 ";
4583 4583
4584 4584
4585 // For a string that is less than 32k characters it should always be
4586 // possible to allocate it in new space.
4587 static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4588
4589
4590 // Doing JSON quoting cannot make the string more than this many times larger.
4591 static const int kJsonQuoteWorstCaseBlowup = 6;
4592
4593
4594 // Covers the entire ASCII range (all other characters are unchanged by JSON
4595 // quoting).
4585 static const byte JsonQuoteLengths[kQuoteTableLength] = { 4596 static const byte JsonQuoteLengths[kQuoteTableLength] = {
Vyacheslav Egorov (Chromium) 2010/12/08 10:51:31 I do not like subtle connection between string abo
Erik Corry 2010/12/08 16:35:56 Changed the string above so it is also 8 per line,
4586 6, 6, 6, 6, 6, 6, 6, 6, 4597 6, 6, 6, 6, 6, 6, 6, 6,
4587 2, 2, 2, 6, 2, 2, 6, 6, 4598 2, 2, 2, 6, 2, 2, 6, 6,
4588 6, 6, 6, 6, 6, 6, 6, 6, 4599 6, 6, 6, 6, 6, 6, 6, 6,
4589 6, 6, 6, 6, 6, 6, 6, 6, 4600 6, 6, 6, 6, 6, 6, 6, 6,
4590 1, 1, 2, 1, 1, 1, 1, 1, 4601 1, 1, 2, 1, 1, 1, 1, 1,
4591 1, 1, 1, 1, 1, 1, 1, 1, 4602 1, 1, 1, 1, 1, 1, 1, 1,
4592 1, 1, 1, 1, 1, 1, 1, 1, 4603 1, 1, 1, 1, 1, 1, 1, 1,
4593 1, 1, 1, 1, 1, 1, 1, 1, 4604 1, 1, 1, 1, 1, 1, 1, 1,
4594 1, 1, 1, 1, 1, 1, 1, 1, 4605 1, 1, 1, 1, 1, 1, 1, 1,
4595 1, 1, 1, 1, 1, 1, 1, 1, 4606 1, 1, 1, 1, 1, 1, 1, 1,
4596 1, 1, 1, 1, 1, 1, 1, 1, 4607 1, 1, 1, 1, 1, 1, 1, 1,
4597 1, 1, 1, 1, 2, 1, 1, 1, 4608 1, 1, 1, 1, 2, 1, 1, 1,
4598 1, 1, 1, 1, 1, 1, 1, 1, 4609 1, 1, 1, 1, 1, 1, 1, 1,
4599 1, 1, 1, 1, 1, 1, 1, 1, 4610 1, 1, 1, 1, 1, 1, 1, 1,
4600 1, 1, 1, 1, 1, 1, 1, 1, 4611 1, 1, 1, 1, 1, 1, 1, 1,
4601 1, 1, 1, 1, 1, 1, 1, 1, 4612 1, 1, 1, 1, 1, 1, 1, 1,
4602 }; 4613 };
4603 4614
4604 4615
4605 template <typename Char>
4606 Char* WriteString(Char* dst, const char* src_string) {
4607 char c;
4608 for (c = *src_string; c; c = *src_string) {
4609 *dst = c;
4610 dst++;
4611 src_string++;
4612 }
4613 return dst;
4614 }
4615
4616
4617 template <typename StringType> 4616 template <typename StringType>
4618 MaybeObject* AllocateRawString(int length); 4617 MaybeObject* AllocateRawString(int length);
4619 4618
4620 4619
4621 template <> 4620 template <>
4622 MaybeObject* AllocateRawString<SeqTwoByteString>(int length) { 4621 MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4623 return Heap::AllocateRawTwoByteString(length); 4622 return Heap::AllocateRawTwoByteString(length);
4624 } 4623 }
4625 4624
4626 4625
4627 template <> 4626 template <>
4628 MaybeObject* AllocateRawString<SeqAsciiString>(int length) { 4627 MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4629 return Heap::AllocateRawAsciiString(length); 4628 return Heap::AllocateRawAsciiString(length);
4630 } 4629 }
4631 4630
4632 4631
4633 template <typename Char, typename StringType> 4632 template <typename Char, typename StringType>
4633 static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
4634 int length = characters.length();
4635 const Char* read_cursor = characters.start();
4636 const Char* end = read_cursor + length;
4637 const int kSpaceForQuotes = 2;
4638 int quoted_length = kSpaceForQuotes;
4639 while (read_cursor < end) {
4640 Char c = *(read_cursor++);
4641 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4642 quoted_length++;
4643 } else {
4644 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
4645 }
4646 }
4647 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4648 Object* new_object;
4649 if (!new_alloc->ToObject(&new_object)) {
4650 return new_alloc;
4651 }
4652 StringType* new_string = StringType::cast(new_object);
4653
4654 Char* write_cursor = reinterpret_cast<Char*>(
4655 new_string->address() + SeqAsciiString::kHeaderSize);
4656 *(write_cursor++) = '"';
4657
4658 read_cursor = characters.start();
4659 while (read_cursor < end) {
4660 Char c = *(read_cursor++);
4661 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4662 *(write_cursor++) = c;
4663 } else {
4664 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4665 const char* replacement = JsonQuotes +
4666 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4667 for (int i = 0; i < len; i++) {
4668 *write_cursor++ = *replacement++;
4669 }
4670 }
4671 }
4672 *(write_cursor++) = '"';
4673 return new_string;
4674 }
4675
4676
4677 template <typename Char, typename StringType>
4634 static MaybeObject* QuoteJsonString(Vector<const Char> characters) { 4678 static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4635 int length = characters.length(); 4679 int length = characters.length();
4636 int quoted_length = 0; 4680 Counters::quote_json_char_count.Increment(length);
4637 for (int i = 0; i < length; i++) { 4681 const int kSpaceForQuotes = 2;
4638 unsigned int c = characters[i]; 4682 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4639 if (sizeof(Char) > 1u) { 4683 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
4640 quoted_length += (c >= kQuoteTableLength) ? 1 : JsonQuoteLengths[c]; 4684 return SlowQuoteJsonString<Char, StringType>(characters);
4641 } else {
4642 quoted_length += JsonQuoteLengths[c];
4643 }
4644 } 4685 }
4645 Counters::quote_json_char_count.Increment(length);
4646 4686
4647 // Add space for quotes. 4687 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4648 quoted_length += 2;
4649
4650 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4651 Object* new_object; 4688 Object* new_object;
4652 if (!new_alloc->ToObject(&new_object)) { 4689 if (!new_alloc->ToObject(&new_object)) {
4653 Counters::quote_json_char_recount.Increment(length);
4654 return new_alloc; 4690 return new_alloc;
4655 } 4691 }
4656 StringType* new_string = StringType::cast(new_object); 4692 StringType* new_string = StringType::cast(new_object);
4657 4693 ASSERT(Heap::new_space()->Contains(new_string));
4658 4694
4659 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); 4695 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4660 Char* write_cursor = reinterpret_cast<Char*>( 4696 Char* write_cursor = reinterpret_cast<Char*>(
4661 new_string->address() + SeqAsciiString::kHeaderSize); 4697 new_string->address() + SeqAsciiString::kHeaderSize);
4662 *(write_cursor++) = '"'; 4698 *(write_cursor++) = '"';
4699
4663 const Char* read_cursor = characters.start(); 4700 const Char* read_cursor = characters.start();
4664 if (quoted_length == length + 2) { 4701 const Char* end = read_cursor + length;
4665 CopyChars(write_cursor, read_cursor, length); 4702 while (read_cursor < end) {
4666 write_cursor += length; 4703 Char c = *(read_cursor++);
4667 } else { 4704 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4668 const Char* end = read_cursor + length; 4705 *(write_cursor++) = c;
4669 while (read_cursor < end) { 4706 } else {
4670 Char c = *(read_cursor++); 4707 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4671 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) { 4708 const char* replacement = JsonQuotes +
4672 *(write_cursor++) = c; 4709 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4673 } else { 4710 write_cursor[0] = replacement[0];
Vyacheslav Egorov (Chromium) 2010/12/08 10:51:31 Some replacements have len == 1. Why we optimisti
Erik Corry 2010/12/08 16:35:56 It is in order to remove mispredicted branches in
4674 const char* replacement = JsonQuotes[static_cast<unsigned>(c)]; 4711 write_cursor[1] = replacement[1];
4675 if (!replacement) { 4712 if (len > 2) {
4676 *(write_cursor++) = c; 4713 ASSERT(len == 6);
4677 } else { 4714 write_cursor[2] = replacement[2];
4678 write_cursor = WriteString(write_cursor, replacement); 4715 write_cursor[3] = replacement[3];
4679 } 4716 write_cursor[4] = replacement[4];
4717 write_cursor[5] = replacement[5];
4680 } 4718 }
4719 write_cursor += len;
4681 } 4720 }
4682 } 4721 }
4683 *(write_cursor++) = '"'; 4722 *(write_cursor++) = '"';
4684 ASSERT_EQ(SeqAsciiString::kHeaderSize + quoted_length * sizeof(Char), 4723
4685 reinterpret_cast<Address>(write_cursor) - new_string->address()); 4724 int final_length =
4725 write_cursor - reinterpret_cast<Char*>(
4726 new_string->address() + SeqAsciiString::kHeaderSize);
4727 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4728 final_length);
4686 return new_string; 4729 return new_string;
4687 } 4730 }
4688 4731
4689 4732
4690 static MaybeObject* Runtime_QuoteJSONString(Arguments args) { 4733 static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4691 NoHandleAllocation ha; 4734 NoHandleAllocation ha;
4692 CONVERT_CHECKED(String, str, args[0]); 4735 CONVERT_CHECKED(String, str, args[0]);
4693 if (!str->IsFlat()) { 4736 if (!str->IsFlat()) {
4694 MaybeObject* try_flatten = str->TryFlatten(); 4737 MaybeObject* try_flatten = str->TryFlatten();
4695 Object* flat; 4738 Object* flat;
(...skipping 6088 matching lines...) Expand 10 before | Expand all | Expand 10 after
10784 } else { 10827 } else {
10785 // Handle last resort GC and make sure to allow future allocations 10828 // Handle last resort GC and make sure to allow future allocations
10786 // to grow the heap without causing GCs (if possible). 10829 // to grow the heap without causing GCs (if possible).
10787 Counters::gc_last_resort_from_js.Increment(); 10830 Counters::gc_last_resort_from_js.Increment();
10788 Heap::CollectAllGarbage(false); 10831 Heap::CollectAllGarbage(false);
10789 } 10832 }
10790 } 10833 }
10791 10834
10792 10835
10793 } } // namespace v8::internal 10836 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | src/spaces.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698