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

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 RUNTIME_ASSERT(2 <= radix && radix <= 36);
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 }
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(
5102 Isolate* isolate,
5103 SinkChar* write_cursor,
5104 Vector<const SourceChar> characters) {
5105 const SourceChar* read_cursor = characters.start();
5106 const SourceChar* end = read_cursor + characters.length();
5107 *(write_cursor++) = '"';
5108 while (read_cursor < end) {
5109 SourceChar c = *(read_cursor++);
5110 if (sizeof(SourceChar) > 1u &&
5111 static_cast<unsigned>(c) >= kQuoteTableLength) {
5112 *(write_cursor++) = c;
5113 } else {
5114 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5115 const char* replacement = JsonQuotes +
5116 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5117 write_cursor[0] = replacement[0];
5118 if (len > 1) {
5119 write_cursor[1] = replacement[1];
5120 if (len > 2) {
5121 ASSERT(len == 6);
5122 write_cursor[2] = replacement[2];
5123 write_cursor[3] = replacement[3];
5124 write_cursor[4] = replacement[4];
5125 write_cursor[5] = replacement[5];
5126 }
5127 }
5128 write_cursor += len;
5129 }
5130 }
5131 *(write_cursor++) = '"';
5132 return write_cursor;
5133 }
5134
5135
5101 template <typename Char, typename StringType, bool comma> 5136 template <typename Char, typename StringType, bool comma>
5102 static MaybeObject* QuoteJsonString(Isolate* isolate, 5137 static MaybeObject* QuoteJsonString(Isolate* isolate,
5103 Vector<const Char> characters) { 5138 Vector<const Char> characters) {
5104 int length = characters.length(); 5139 int length = characters.length();
5105 isolate->counters()->quote_json_char_count()->Increment(length); 5140 isolate->counters()->quote_json_char_count()->Increment(length);
5106 const int kSpaceForQuotes = 2 + (comma ? 1 :0); 5141 int worst_case_length =
5107 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes; 5142 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
5108 if (worst_case_length > kMaxGuaranteedNewSpaceString) { 5143 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5109 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); 5144 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
5110 } 5145 }
5111 5146
5112 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, 5147 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5113 worst_case_length); 5148 worst_case_length);
5114 Object* new_object; 5149 Object* new_object;
5115 if (!new_alloc->ToObject(&new_object)) { 5150 if (!new_alloc->ToObject(&new_object)) {
5116 return new_alloc; 5151 return new_alloc;
5117 } 5152 }
5118 if (!isolate->heap()->new_space()->Contains(new_object)) { 5153 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 5154 // 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 5155 // 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 5156 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5122 // CEntryStub::GenerateCore. 5157 // CEntryStub::GenerateCore.
5123 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); 5158 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
5124 } 5159 }
5125 StringType* new_string = StringType::cast(new_object); 5160 StringType* new_string = StringType::cast(new_object);
5126 ASSERT(isolate->heap()->new_space()->Contains(new_string)); 5161 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5127 5162
5128 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); 5163 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5129 Char* write_cursor = reinterpret_cast<Char*>( 5164 Char* write_cursor = reinterpret_cast<Char*>(
5130 new_string->address() + SeqAsciiString::kHeaderSize); 5165 new_string->address() + SeqAsciiString::kHeaderSize);
5131 if (comma) *(write_cursor++) = ','; 5166 if (comma) *(write_cursor++) = ',';
5132 *(write_cursor++) = '"'; 5167 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5133 5168 write_cursor,
5134 const Char* read_cursor = characters.start(); 5169 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>( 5170 int final_length = static_cast<int>(
5161 write_cursor - reinterpret_cast<Char*>( 5171 write_cursor - reinterpret_cast<Char*>(
5162 new_string->address() + SeqAsciiString::kHeaderSize)); 5172 new_string->address() + SeqAsciiString::kHeaderSize));
5163 isolate->heap()->new_space()-> 5173 isolate->heap()->new_space()->
5164 template ShrinkStringAtAllocationBoundary<StringType>( 5174 template ShrinkStringAtAllocationBoundary<StringType>(
5165 new_string, final_length); 5175 new_string, final_length);
5166 return new_string; 5176 return new_string;
5167 } 5177 }
5168 5178
5169 5179
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
5203 } 5213 }
5204 if (str->IsTwoByteRepresentation()) { 5214 if (str->IsTwoByteRepresentation()) {
5205 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate, 5215 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5206 str->ToUC16Vector()); 5216 str->ToUC16Vector());
5207 } else { 5217 } else {
5208 return QuoteJsonString<char, SeqAsciiString, true>(isolate, 5218 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5209 str->ToAsciiVector()); 5219 str->ToAsciiVector());
5210 } 5220 }
5211 } 5221 }
5212 5222
5223
5224 template <typename Char, typename StringType>
5225 static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5226 FixedArray* array,
5227 int worst_case_length) {
5228 int length = array->length();
5229
5230 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5231 worst_case_length);
5232 Object* new_object;
5233 if (!new_alloc->ToObject(&new_object)) {
5234 return new_alloc;
5235 }
5236 if (!isolate->heap()->new_space()->Contains(new_object)) {
5237 // Even if our string is small enough to fit in new space we still have to
5238 // handle it being allocated in old space as may happen in the third
5239 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5240 // CEntryStub::GenerateCore.
5241 return isolate->heap()->undefined_value();
5242 }
5243 AssertNoAllocation no_gc;
5244 StringType* new_string = StringType::cast(new_object);
5245 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5246
5247 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5248 Char* write_cursor = reinterpret_cast<Char*>(
5249 new_string->address() + SeqAsciiString::kHeaderSize);
5250 *(write_cursor++) = '[';
5251 for (int i = 0; i < length; i++) {
5252 if (i != 0) *(write_cursor++) = ',';
5253 String* str = String::cast(array->get(i));
5254 if (str->IsTwoByteRepresentation()) {
5255 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5256 write_cursor,
5257 str->ToUC16Vector());
5258 } else {
5259 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5260 write_cursor,
5261 str->ToAsciiVector());
5262 }
5263 }
5264 *(write_cursor++) = ']';
5265
5266 int final_length = static_cast<int>(
5267 write_cursor - reinterpret_cast<Char*>(
5268 new_string->address() + SeqAsciiString::kHeaderSize));
5269 isolate->heap()->new_space()->
5270 template ShrinkStringAtAllocationBoundary<StringType>(
5271 new_string, final_length);
5272 return new_string;
5273 }
5274
5275
5276 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5277 NoHandleAllocation ha;
5278 ASSERT(args.length() == 1);
5279 CONVERT_CHECKED(JSArray, array, args[0]);
5280
5281 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5282 FixedArray* elements = FixedArray::cast(array->elements());
5283 int n = elements->length();
5284 bool ascii = true;
5285 int total_length = 0;
5286
5287 for (int i = 0; i < n; i++) {
5288 Object* elt = elements->get(i);
5289 if (!elt->IsString()) return isolate->heap()->undefined_value();
5290 String* element = String::cast(elt);
5291 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5292 total_length += element->length();
5293 if (ascii && element->IsTwoByteRepresentation()) {
5294 ascii = false;
5295 }
5296 }
5297
5298 int worst_case_length =
5299 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5300 + total_length * kJsonQuoteWorstCaseBlowup;
5301
5302 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5303 return isolate->heap()->undefined_value();
5304 }
5305
5306 if (ascii) {
5307 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5308 elements,
5309 worst_case_length);
5310 } else {
5311 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5312 elements,
5313 worst_case_length);
5314 }
5315 }
5316
5317
5213 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { 5318 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
5214 NoHandleAllocation ha; 5319 NoHandleAllocation ha;
5215 5320
5216 CONVERT_CHECKED(String, s, args[0]); 5321 CONVERT_CHECKED(String, s, args[0]);
5217 CONVERT_SMI_CHECKED(radix, args[1]); 5322 CONVERT_SMI_CHECKED(radix, args[1]);
5218 5323
5219 s->TryFlatten(); 5324 s->TryFlatten();
5220 5325
5221 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); 5326 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
5222 double value = StringToInt(isolate->unicode_cache(), s, radix); 5327 double value = StringToInt(isolate->unicode_cache(), s, radix);
(...skipping 6995 matching lines...) Expand 10 before | Expand all | Expand 10 after
12218 } else { 12323 } else {
12219 // Handle last resort GC and make sure to allow future allocations 12324 // Handle last resort GC and make sure to allow future allocations
12220 // to grow the heap without causing GCs (if possible). 12325 // to grow the heap without causing GCs (if possible).
12221 isolate->counters()->gc_last_resort_from_js()->Increment(); 12326 isolate->counters()->gc_last_resort_from_js()->Increment();
12222 isolate->heap()->CollectAllGarbage(false); 12327 isolate->heap()->CollectAllGarbage(false);
12223 } 12328 }
12224 } 12329 }
12225 12330
12226 12331
12227 } } // namespace v8::internal 12332 } } // 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