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

Side by Side Diff: src/runtime.cc

Issue 7077004: JSON.stringify improvement. Fast case in C++ for string arrays. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 6 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/runtime.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 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 3516 matching lines...) Expand 10 before | Expand all | Expand 10 after
3527 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array); 3527 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3528 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value(); 3528 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
3529 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); 3529 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3530 return Failure::Exception(); 3530 return Failure::Exception();
3531 } 3531 }
3532 3532
3533 3533
3534 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) { 3534 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
3535 NoHandleAllocation ha; 3535 NoHandleAllocation ha;
3536 ASSERT(args.length() == 2); 3536 ASSERT(args.length() == 2);
3537 CONVERT_SMI_CHECKED(radix, args[1]);
3538 ASSERT(2 <= radix && radix <= 36);
Lasse Reichstein 2011/05/26 11:24:43 ASSERT -> RUNTIME_ASSERT
sandholm 2011/05/26 11:41:36 Done.
3537 3539
3538 // Fast case where the result is a one character string. 3540 // Fast case where the result is a one character string.
3539 if (args[0]->IsSmi() && args[1]->IsSmi()) { 3541 if (args[0]->IsSmi()) {
3540 int value = Smi::cast(args[0])->value(); 3542 int value = Smi::cast(args[0])->value();
3541 int radix = Smi::cast(args[1])->value();
3542 if (value >= 0 && value < radix) { 3543 if (value >= 0 && value < radix) {
3543 RUNTIME_ASSERT(radix <= 36);
3544 // Character array used for conversion. 3544 // Character array used for conversion.
3545 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 3545 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3546 return isolate->heap()-> 3546 return isolate->heap()->
3547 LookupSingleCharacterStringFromCode(kCharTable[value]); 3547 LookupSingleCharacterStringFromCode(kCharTable[value]);
3548 } 3548 }
Lasse Reichstein 2011/05/26 11:24:43 Maybe we should have special case for < radix^2 to
sandholm 2011/05/26 11:41:36 Good idea (for another CL).
3549 } 3549 }
3550 3550
3551 // Slow case. 3551 // Slow case.
3552 CONVERT_DOUBLE_CHECKED(value, args[0]); 3552 CONVERT_DOUBLE_CHECKED(value, args[0]);
3553 if (isnan(value)) { 3553 if (isnan(value)) {
3554 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN")); 3554 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
3555 } 3555 }
3556 if (isinf(value)) { 3556 if (isinf(value)) {
3557 if (value < 0) { 3557 if (value < 0) {
3558 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity")); 3558 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
3559 } 3559 }
3560 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity")); 3560 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
3561 } 3561 }
3562 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3563 int radix = FastD2I(radix_number);
3564 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3565 char* str = DoubleToRadixCString(value, radix); 3562 char* str = DoubleToRadixCString(value, radix);
3566 MaybeObject* result = 3563 MaybeObject* result =
3567 isolate->heap()->AllocateStringFromAscii(CStrVector(str)); 3564 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
3568 DeleteArray(str); 3565 DeleteArray(str);
3569 return result; 3566 return result;
3570 } 3567 }
3571 3568
3572 3569
3573 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) { 3570 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
3574 NoHandleAllocation ha; 3571 NoHandleAllocation ha;
(...skipping 1429 matching lines...) Expand 10 before | Expand all | Expand 10 after
5004 5001
5005 5002
5006 // For a string that is less than 32k characters it should always be 5003 // For a string that is less than 32k characters it should always be
5007 // possible to allocate it in new space. 5004 // possible to allocate it in new space.
5008 static const int kMaxGuaranteedNewSpaceString = 32 * 1024; 5005 static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5009 5006
5010 5007
5011 // Doing JSON quoting cannot make the string more than this many times larger. 5008 // Doing JSON quoting cannot make the string more than this many times larger.
5012 static const int kJsonQuoteWorstCaseBlowup = 6; 5009 static const int kJsonQuoteWorstCaseBlowup = 6;
5013 5010
5011 static const int kSpaceForQuotesAndComma = 3;
5012 static const int kSpaceForBrackets = 2;
5014 5013
5015 // Covers the entire ASCII range (all other characters are unchanged by JSON 5014 // Covers the entire ASCII range (all other characters are unchanged by JSON
5016 // quoting). 5015 // quoting).
5017 static const byte JsonQuoteLengths[kQuoteTableLength] = { 5016 static const byte JsonQuoteLengths[kQuoteTableLength] = {
5018 6, 6, 6, 6, 6, 6, 6, 6, 5017 6, 6, 6, 6, 6, 6, 6, 6,
5019 2, 2, 2, 6, 2, 2, 6, 6, 5018 2, 2, 2, 6, 2, 2, 6, 6,
5020 6, 6, 6, 6, 6, 6, 6, 6, 5019 6, 6, 6, 6, 6, 6, 6, 6,
5021 6, 6, 6, 6, 6, 6, 6, 6, 5020 6, 6, 6, 6, 6, 6, 6, 6,
5022 1, 1, 2, 1, 1, 1, 1, 1, 5021 1, 1, 2, 1, 1, 1, 1, 1,
5023 1, 1, 1, 1, 1, 1, 1, 1, 5022 1, 1, 1, 1, 1, 1, 1, 1,
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
5091 for (int i = 0; i < len; i++) { 5090 for (int i = 0; i < len; i++) {
5092 *write_cursor++ = *replacement++; 5091 *write_cursor++ = *replacement++;
5093 } 5092 }
5094 } 5093 }
5095 } 5094 }
5096 *(write_cursor++) = '"'; 5095 *(write_cursor++) = '"';
5097 return new_string; 5096 return new_string;
5098 } 5097 }
5099 5098
5100 5099
5100 template <typename SinkChar, typename SourceChar>
5101 static inline SinkChar* WriteQuoteJsonString(Isolate* isolate,
5102 SinkChar* write_cursor,
Lasse Reichstein 2011/05/26 11:24:43 indentation.
sandholm 2011/05/26 11:41:36 Done.
5103 Vector<const SourceChar> characters) {
5104 const SourceChar* read_cursor = characters.start();
5105 const SourceChar* end = read_cursor + characters.length();
5106 *(write_cursor++) = '"';
5107 while (read_cursor < end) {
5108 SourceChar c = *(read_cursor++);
5109 if (sizeof(SourceChar) > 1u &&
5110 static_cast<unsigned>(c) >= kQuoteTableLength) {
5111 *(write_cursor++) = c;
5112 } else {
5113 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5114 const char* replacement = JsonQuotes +
5115 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5116 write_cursor[0] = replacement[0];
5117 if (len > 1) {
5118 write_cursor[1] = replacement[1];
5119 if (len > 2) {
5120 ASSERT(len == 6);
5121 write_cursor[2] = replacement[2];
5122 write_cursor[3] = replacement[3];
5123 write_cursor[4] = replacement[4];
5124 write_cursor[5] = replacement[5];
5125 }
5126 }
5127 write_cursor += len;
5128 }
5129 }
5130 *(write_cursor++) = '"';
5131 return write_cursor;
5132 }
5133
5134
5101 template <typename Char, typename StringType, bool comma> 5135 template <typename Char, typename StringType, bool comma>
5102 static MaybeObject* QuoteJsonString(Isolate* isolate, 5136 static MaybeObject* QuoteJsonString(Isolate* isolate,
5103 Vector<const Char> characters) { 5137 Vector<const Char> characters) {
5104 int length = characters.length(); 5138 int length = characters.length();
5105 isolate->counters()->quote_json_char_count()->Increment(length); 5139 isolate->counters()->quote_json_char_count()->Increment(length);
5106 const int kSpaceForQuotes = 2 + (comma ? 1 :0); 5140 int worst_case_length =
5107 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes; 5141 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
5108 if (worst_case_length > kMaxGuaranteedNewSpaceString) { 5142 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5109 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); 5143 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
5110 } 5144 }
5111 5145
5112 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, 5146 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5113 worst_case_length); 5147 worst_case_length);
5114 Object* new_object; 5148 Object* new_object;
5115 if (!new_alloc->ToObject(&new_object)) { 5149 if (!new_alloc->ToObject(&new_object)) {
5116 return new_alloc; 5150 return new_alloc;
5117 } 5151 }
5118 if (!isolate->heap()->new_space()->Contains(new_object)) { 5152 if (!isolate->heap()->new_space()->Contains(new_object)) {
5119 // Even if our string is small enough to fit in new space we still have to 5153 // Even if our string is small enough to fit in new space we still have to
5120 // handle it being allocated in old space as may happen in the third 5154 // handle it being allocated in old space as may happen in the third
5121 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in 5155 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5122 // CEntryStub::GenerateCore. 5156 // CEntryStub::GenerateCore.
5123 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); 5157 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
5124 } 5158 }
5125 StringType* new_string = StringType::cast(new_object); 5159 StringType* new_string = StringType::cast(new_object);
5126 ASSERT(isolate->heap()->new_space()->Contains(new_string)); 5160 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5127 5161
5128 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); 5162 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5129 Char* write_cursor = reinterpret_cast<Char*>( 5163 Char* write_cursor = reinterpret_cast<Char*>(
5130 new_string->address() + SeqAsciiString::kHeaderSize); 5164 new_string->address() + SeqAsciiString::kHeaderSize);
5131 if (comma) *(write_cursor++) = ','; 5165 if (comma) *(write_cursor++) = ',';
5132 *(write_cursor++) = '"'; 5166 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5133 5167 write_cursor,
5134 const Char* read_cursor = characters.start(); 5168 characters);
5135 const Char* end = read_cursor + length;
5136 while (read_cursor < end) {
5137 Char c = *(read_cursor++);
5138 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5139 *(write_cursor++) = c;
5140 } else {
5141 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5142 const char* replacement = JsonQuotes +
5143 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5144 write_cursor[0] = replacement[0];
5145 if (len > 1) {
5146 write_cursor[1] = replacement[1];
5147 if (len > 2) {
5148 ASSERT(len == 6);
5149 write_cursor[2] = replacement[2];
5150 write_cursor[3] = replacement[3];
5151 write_cursor[4] = replacement[4];
5152 write_cursor[5] = replacement[5];
5153 }
5154 }
5155 write_cursor += len;
5156 }
5157 }
5158 *(write_cursor++) = '"';
5159
5160 int final_length = static_cast<int>( 5169 int final_length = static_cast<int>(
5161 write_cursor - reinterpret_cast<Char*>( 5170 write_cursor - reinterpret_cast<Char*>(
5162 new_string->address() + SeqAsciiString::kHeaderSize)); 5171 new_string->address() + SeqAsciiString::kHeaderSize));
5163 isolate->heap()->new_space()-> 5172 isolate->heap()->new_space()->
5164 template ShrinkStringAtAllocationBoundary<StringType>( 5173 template ShrinkStringAtAllocationBoundary<StringType>(
5165 new_string, final_length); 5174 new_string, final_length);
5166 return new_string; 5175 return new_string;
5167 } 5176 }
5168 5177
5169 5178
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
5203 } 5212 }
5204 if (str->IsTwoByteRepresentation()) { 5213 if (str->IsTwoByteRepresentation()) {
5205 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate, 5214 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5206 str->ToUC16Vector()); 5215 str->ToUC16Vector());
5207 } else { 5216 } else {
5208 return QuoteJsonString<char, SeqAsciiString, true>(isolate, 5217 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5209 str->ToAsciiVector()); 5218 str->ToAsciiVector());
5210 } 5219 }
5211 } 5220 }
5212 5221
5222
5223 template <typename Char, typename StringType>
5224 static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5225 FixedArray* array,
5226 int worst_case_length) {
5227 int length = array->length();
5228
5229 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5230 worst_case_length);
5231 Object* new_object;
5232 if (!new_alloc->ToObject(&new_object)) {
5233 return new_alloc;
5234 }
5235 if (!isolate->heap()->new_space()->Contains(new_object)) {
5236 // Even if our string is small enough to fit in new space we still have to
5237 // handle it being allocated in old space as may happen in the third
5238 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5239 // CEntryStub::GenerateCore.
5240 return isolate->heap()->undefined_value();
5241 }
Lasse Reichstein 2011/05/26 11:24:43 I dare you to put an AssertNoAllocation no_gc; he
sandholm 2011/05/26 11:41:36 Done.
5242 StringType* new_string = StringType::cast(new_object);
5243 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5244
5245 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5246 Char* write_cursor = reinterpret_cast<Char*>(
5247 new_string->address() + SeqAsciiString::kHeaderSize);
5248 *(write_cursor++) = '[';
5249 for (int i = 0; i < length; i++) {
5250 if (i != 0) *(write_cursor++) = ',';
5251 String* str = String::cast(array->get(i));
5252 if (str->IsTwoByteRepresentation()) {
5253 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5254 write_cursor,
5255 str->ToUC16Vector());
5256 } else {
5257 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5258 write_cursor,
5259 str->ToAsciiVector());
5260 }
5261 }
5262 *(write_cursor++) = ']';
5263
5264 int final_length = static_cast<int>(
5265 write_cursor - reinterpret_cast<Char*>(
5266 new_string->address() + SeqAsciiString::kHeaderSize));
5267 isolate->heap()->new_space()->
5268 template ShrinkStringAtAllocationBoundary<StringType>(
5269 new_string, final_length);
5270 return new_string;
5271 }
5272
5273
5274 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5275 NoHandleAllocation ha;
5276 ASSERT(args.length() == 1);
5277 CONVERT_CHECKED(JSArray, array, args[0]);
5278
5279 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5280 FixedArray* elements = FixedArray::cast(array->elements());
5281 int n = elements->length();
5282 bool ascii = true;
5283 int total_length = 0;
5284
5285 for (int i = 0; i < n; i++) {
5286 Object* elt = elements->get(i);
5287 if (!elt->IsString()) return isolate->heap()->undefined_value();
5288 String* element = String::cast(elt);
5289 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5290 total_length += element->length();
5291 if (ascii && element->IsTwoByteRepresentation()) {
5292 ascii = false;
5293 }
5294 }
5295
5296 int worst_case_length =
5297 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5298 + total_length * kJsonQuoteWorstCaseBlowup;
5299
5300 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5301 return isolate->heap()->undefined_value();
5302 }
5303
5304 if (ascii) {
5305 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5306 elements,
5307 worst_case_length);
5308 } else {
5309 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5310 elements,
5311 worst_case_length);
5312 }
5313 }
5314
5315
5213 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { 5316 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
5214 NoHandleAllocation ha; 5317 NoHandleAllocation ha;
5215 5318
5216 CONVERT_CHECKED(String, s, args[0]); 5319 CONVERT_CHECKED(String, s, args[0]);
5217 CONVERT_SMI_CHECKED(radix, args[1]); 5320 CONVERT_SMI_CHECKED(radix, args[1]);
5218 5321
5219 s->TryFlatten(); 5322 s->TryFlatten();
5220 5323
5221 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); 5324 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
5222 double value = StringToInt(isolate->unicode_cache(), s, radix); 5325 double value = StringToInt(isolate->unicode_cache(), s, radix);
(...skipping 6994 matching lines...) Expand 10 before | Expand all | Expand 10 after
12217 } else { 12320 } else {
12218 // Handle last resort GC and make sure to allow future allocations 12321 // Handle last resort GC and make sure to allow future allocations
12219 // to grow the heap without causing GCs (if possible). 12322 // to grow the heap without causing GCs (if possible).
12220 isolate->counters()->gc_last_resort_from_js()->Increment(); 12323 isolate->counters()->gc_last_resort_from_js()->Increment();
12221 isolate->heap()->CollectAllGarbage(false); 12324 isolate->heap()->CollectAllGarbage(false);
12222 } 12325 }
12223 } 12326 }
12224 12327
12225 12328
12226 } } // namespace v8::internal 12329 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/runtime.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698