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

Side by Side Diff: src/runtime.cc

Issue 12690017: Unify code for fast and slow path of JSON.stringify. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years, 9 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 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 5153 matching lines...) Expand 10 before | Expand all | Expand 10 after
5164 ASSERT(args.length() == 1); 5164 ASSERT(args.length() == 1);
5165 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 5165 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
5166 Handle<String> string = FlattenGetString(source); 5166 Handle<String> string = FlattenGetString(source);
5167 String::FlatContent content = string->GetFlatContent(); 5167 String::FlatContent content = string->GetFlatContent();
5168 ASSERT(content.IsFlat()); 5168 ASSERT(content.IsFlat());
5169 return content.IsAscii() ? *URIUnescape::Unescape<uint8_t>(isolate, source) 5169 return content.IsAscii() ? *URIUnescape::Unescape<uint8_t>(isolate, source)
5170 : *URIUnescape::Unescape<uc16>(isolate, source); 5170 : *URIUnescape::Unescape<uc16>(isolate, source);
5171 } 5171 }
5172 5172
5173 5173
5174 static const unsigned int kQuoteTableLength = 128u;
5175
5176 static const int kJsonQuotesCharactersPerEntry = 8;
5177 static const char* const JsonQuotes =
5178 "\\u0000 \\u0001 \\u0002 \\u0003 "
5179 "\\u0004 \\u0005 \\u0006 \\u0007 "
5180 "\\b \\t \\n \\u000b "
5181 "\\f \\r \\u000e \\u000f "
5182 "\\u0010 \\u0011 \\u0012 \\u0013 "
5183 "\\u0014 \\u0015 \\u0016 \\u0017 "
5184 "\\u0018 \\u0019 \\u001a \\u001b "
5185 "\\u001c \\u001d \\u001e \\u001f "
5186 " ! \\\" # "
5187 "$ % & ' "
5188 "( ) * + "
5189 ", - . / "
5190 "0 1 2 3 "
5191 "4 5 6 7 "
5192 "8 9 : ; "
5193 "< = > ? "
5194 "@ A B C "
5195 "D E F G "
5196 "H I J K "
5197 "L M N O "
5198 "P Q R S "
5199 "T U V W "
5200 "X Y Z [ "
5201 "\\\\ ] ^ _ "
5202 "` a b c "
5203 "d e f g "
5204 "h i j k "
5205 "l m n o "
5206 "p q r s "
5207 "t u v w "
5208 "x y z { "
5209 "| } ~ \177 ";
5210
5211
5212 // For a string that is less than 32k characters it should always be
5213 // possible to allocate it in new space.
5214 static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5215
5216
5217 // Doing JSON quoting cannot make the string more than this many times larger.
5218 static const int kJsonQuoteWorstCaseBlowup = 6;
5219
5220 static const int kSpaceForQuotesAndComma = 3;
5221 static const int kSpaceForBrackets = 2;
5222
5223 // Covers the entire ASCII range (all other characters are unchanged by JSON
5224 // quoting).
5225 static const byte JsonQuoteLengths[kQuoteTableLength] = {
5226 6, 6, 6, 6, 6, 6, 6, 6,
5227 2, 2, 2, 6, 2, 2, 6, 6,
5228 6, 6, 6, 6, 6, 6, 6, 6,
5229 6, 6, 6, 6, 6, 6, 6, 6,
5230 1, 1, 2, 1, 1, 1, 1, 1,
5231 1, 1, 1, 1, 1, 1, 1, 1,
5232 1, 1, 1, 1, 1, 1, 1, 1,
5233 1, 1, 1, 1, 1, 1, 1, 1,
5234 1, 1, 1, 1, 1, 1, 1, 1,
5235 1, 1, 1, 1, 1, 1, 1, 1,
5236 1, 1, 1, 1, 1, 1, 1, 1,
5237 1, 1, 1, 1, 2, 1, 1, 1,
5238 1, 1, 1, 1, 1, 1, 1, 1,
5239 1, 1, 1, 1, 1, 1, 1, 1,
5240 1, 1, 1, 1, 1, 1, 1, 1,
5241 1, 1, 1, 1, 1, 1, 1, 1,
5242 };
5243
5244
5245 template <typename StringType>
5246 MaybeObject* AllocateRawString(Isolate* isolate, int length);
5247
5248
5249 template <>
5250 MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5251 return isolate->heap()->AllocateRawTwoByteString(length);
5252 }
5253
5254
5255 template <>
5256 MaybeObject* AllocateRawString<SeqOneByteString>(Isolate* isolate, int length) {
5257 return isolate->heap()->AllocateRawOneByteString(length);
5258 }
5259
5260
5261 template <typename Char, typename StringType, bool comma>
5262 static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5263 Vector<const Char> characters) {
5264 int length = characters.length();
5265 const Char* read_cursor = characters.start();
5266 const Char* end = read_cursor + length;
5267 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
5268 int quoted_length = kSpaceForQuotes;
5269 while (read_cursor < end) {
5270 Char c = *(read_cursor++);
5271 if (static_cast<unsigned>(c) >= kQuoteTableLength) {
5272 quoted_length++;
5273 } else {
5274 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
5275 }
5276 }
5277 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5278 quoted_length);
5279 Object* new_object;
5280 if (!new_alloc->ToObject(&new_object)) {
5281 return new_alloc;
5282 }
5283 StringType* new_string = StringType::cast(new_object);
5284
5285 Char* write_cursor = reinterpret_cast<Char*>(
5286 new_string->address() + SeqString::kHeaderSize);
5287 if (comma) *(write_cursor++) = ',';
5288 *(write_cursor++) = '"';
5289
5290 read_cursor = characters.start();
5291 while (read_cursor < end) {
5292 Char c = *(read_cursor++);
5293 if (static_cast<unsigned>(c) >= kQuoteTableLength) {
5294 *(write_cursor++) = c;
5295 } else {
5296 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5297 const char* replacement = JsonQuotes +
5298 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5299 for (int i = 0; i < len; i++) {
5300 *write_cursor++ = *replacement++;
5301 }
5302 }
5303 }
5304 *(write_cursor++) = '"';
5305 return new_string;
5306 }
5307
5308
5309 template <typename SinkChar, typename SourceChar>
5310 static inline SinkChar* WriteQuoteJsonString(
5311 Isolate* isolate,
5312 SinkChar* write_cursor,
5313 Vector<const SourceChar> characters) {
5314 // SinkChar is only char if SourceChar is guaranteed to be char.
5315 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
5316 const SourceChar* read_cursor = characters.start();
5317 const SourceChar* end = read_cursor + characters.length();
5318 *(write_cursor++) = '"';
5319 while (read_cursor < end) {
5320 SourceChar c = *(read_cursor++);
5321 if (static_cast<unsigned>(c) >= kQuoteTableLength) {
5322 *(write_cursor++) = static_cast<SinkChar>(c);
5323 } else {
5324 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5325 const char* replacement = JsonQuotes +
5326 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5327 write_cursor[0] = replacement[0];
5328 if (len > 1) {
5329 write_cursor[1] = replacement[1];
5330 if (len > 2) {
5331 ASSERT(len == 6);
5332 write_cursor[2] = replacement[2];
5333 write_cursor[3] = replacement[3];
5334 write_cursor[4] = replacement[4];
5335 write_cursor[5] = replacement[5];
5336 }
5337 }
5338 write_cursor += len;
5339 }
5340 }
5341 *(write_cursor++) = '"';
5342 return write_cursor;
5343 }
5344
5345
5346 template <typename Char, typename StringType, bool comma>
5347 static MaybeObject* QuoteJsonString(Isolate* isolate,
5348 Vector<const Char> characters) {
5349 int length = characters.length();
5350 isolate->counters()->quote_json_char_count()->Increment(length);
5351 int worst_case_length =
5352 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
5353 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5354 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
5355 }
5356
5357 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5358 worst_case_length);
5359 Object* new_object;
5360 if (!new_alloc->ToObject(&new_object)) {
5361 return new_alloc;
5362 }
5363 if (!isolate->heap()->new_space()->Contains(new_object)) {
5364 // Even if our string is small enough to fit in new space we still have to
5365 // handle it being allocated in old space as may happen in the third
5366 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5367 // CEntryStub::GenerateCore.
5368 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
5369 }
5370 StringType* new_string = StringType::cast(new_object);
5371 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5372
5373 Char* write_cursor = reinterpret_cast<Char*>(
5374 new_string->address() + SeqString::kHeaderSize);
5375 if (comma) *(write_cursor++) = ',';
5376 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5377 write_cursor,
5378 characters);
5379 int final_length = static_cast<int>(
5380 write_cursor - reinterpret_cast<Char*>(
5381 new_string->address() + SeqString::kHeaderSize));
5382 isolate->heap()->new_space()->
5383 template ShrinkStringAtAllocationBoundary<StringType>(
5384 new_string, final_length);
5385 return new_string;
5386 }
5387
5388
5389 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) { 5174 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
5390 NoHandleAllocation ha(isolate); 5175 HandleScope scope(isolate);
5391 CONVERT_ARG_CHECKED(String, str, 0); 5176 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
5392 if (!str->IsFlat()) { 5177 ASSERT(args.length() == 1);
5393 MaybeObject* try_flatten = str->TryFlatten(); 5178 return BasicJsonStringifier::StringifyString(isolate, string);
5394 Object* flat;
5395 if (!try_flatten->ToObject(&flat)) {
5396 return try_flatten;
5397 }
5398 str = String::cast(flat);
5399 ASSERT(str->IsFlat());
5400 }
5401 String::FlatContent flat = str->GetFlatContent();
5402 ASSERT(flat.IsFlat());
5403 if (flat.IsTwoByte()) {
5404 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5405 flat.ToUC16Vector());
5406 } else {
5407 return QuoteJsonString<uint8_t, SeqOneByteString, false>(
5408 isolate,
5409 flat.ToOneByteVector());
5410 }
5411 } 5179 }
5412 5180
5413 5181
5414 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
5415 NoHandleAllocation ha(isolate);
5416 CONVERT_ARG_CHECKED(String, str, 0);
5417 if (!str->IsFlat()) {
5418 MaybeObject* try_flatten = str->TryFlatten();
5419 Object* flat;
5420 if (!try_flatten->ToObject(&flat)) {
5421 return try_flatten;
5422 }
5423 str = String::cast(flat);
5424 ASSERT(str->IsFlat());
5425 }
5426 String::FlatContent flat = str->GetFlatContent();
5427 if (flat.IsTwoByte()) {
5428 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5429 flat.ToUC16Vector());
5430 } else {
5431 return QuoteJsonString<uint8_t, SeqOneByteString, true>(
5432 isolate,
5433 flat.ToOneByteVector());
5434 }
5435 }
5436
5437
5438 template <typename Char, typename StringType>
5439 static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5440 FixedArray* array,
5441 int worst_case_length) {
5442 int length = array->length();
5443
5444 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5445 worst_case_length);
5446 Object* new_object;
5447 if (!new_alloc->ToObject(&new_object)) {
5448 return new_alloc;
5449 }
5450 if (!isolate->heap()->new_space()->Contains(new_object)) {
5451 // Even if our string is small enough to fit in new space we still have to
5452 // handle it being allocated in old space as may happen in the third
5453 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5454 // CEntryStub::GenerateCore.
5455 return isolate->heap()->undefined_value();
5456 }
5457 AssertNoAllocation no_gc;
5458 StringType* new_string = StringType::cast(new_object);
5459 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5460
5461 Char* write_cursor = reinterpret_cast<Char*>(
5462 new_string->address() + SeqString::kHeaderSize);
5463 *(write_cursor++) = '[';
5464 for (int i = 0; i < length; i++) {
5465 if (i != 0) *(write_cursor++) = ',';
5466 String* str = String::cast(array->get(i));
5467 String::FlatContent content = str->GetFlatContent();
5468 ASSERT(content.IsFlat());
5469 if (content.IsTwoByte()) {
5470 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5471 write_cursor,
5472 content.ToUC16Vector());
5473 } else {
5474 write_cursor =
5475 WriteQuoteJsonString<Char, uint8_t>(isolate,
5476 write_cursor,
5477 content.ToOneByteVector());
5478 }
5479 }
5480 *(write_cursor++) = ']';
5481
5482 int final_length = static_cast<int>(
5483 write_cursor - reinterpret_cast<Char*>(
5484 new_string->address() + SeqString::kHeaderSize));
5485 isolate->heap()->new_space()->
5486 template ShrinkStringAtAllocationBoundary<StringType>(
5487 new_string, final_length);
5488 return new_string;
5489 }
5490
5491
5492 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5493 NoHandleAllocation ha(isolate);
5494 ASSERT(args.length() == 1);
5495 CONVERT_ARG_CHECKED(JSArray, array, 0);
5496
5497 if (!array->HasFastObjectElements()) {
5498 return isolate->heap()->undefined_value();
5499 }
5500 FixedArray* elements = FixedArray::cast(array->elements());
5501 int n = elements->length();
5502 bool ascii = true;
5503 int total_length = 0;
5504
5505 for (int i = 0; i < n; i++) {
5506 Object* elt = elements->get(i);
5507 if (!elt->IsString()) return isolate->heap()->undefined_value();
5508 String* element = String::cast(elt);
5509 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5510 total_length += element->length();
5511 if (ascii && element->IsTwoByteRepresentation()) {
5512 ascii = false;
5513 }
5514 }
5515
5516 int worst_case_length =
5517 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5518 + total_length * kJsonQuoteWorstCaseBlowup;
5519
5520 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5521 return isolate->heap()->undefined_value();
5522 }
5523
5524 if (ascii) {
5525 return QuoteJsonStringArray<char, SeqOneByteString>(isolate,
5526 elements,
5527 worst_case_length);
5528 } else {
5529 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5530 elements,
5531 worst_case_length);
5532 }
5533 }
5534
5535
5536 RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) { 5182 RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) {
5537 HandleScope scope(isolate); 5183 HandleScope scope(isolate);
5538 ASSERT(args.length() == 1); 5184 ASSERT(args.length() == 1);
5539 BasicJsonStringifier stringifier(isolate); 5185 BasicJsonStringifier stringifier(isolate);
5540 return stringifier.Stringify(Handle<Object>(args[0], isolate)); 5186 return stringifier.Stringify(Handle<Object>(args[0], isolate));
5541 } 5187 }
5542 5188
5543 5189
5544 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { 5190 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
5545 NoHandleAllocation ha(isolate); 5191 NoHandleAllocation ha(isolate);
(...skipping 7859 matching lines...) Expand 10 before | Expand all | Expand 10 after
13405 // Handle last resort GC and make sure to allow future allocations 13051 // Handle last resort GC and make sure to allow future allocations
13406 // to grow the heap without causing GCs (if possible). 13052 // to grow the heap without causing GCs (if possible).
13407 isolate->counters()->gc_last_resort_from_js()->Increment(); 13053 isolate->counters()->gc_last_resort_from_js()->Increment();
13408 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, 13054 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13409 "Runtime::PerformGC"); 13055 "Runtime::PerformGC");
13410 } 13056 }
13411 } 13057 }
13412 13058
13413 13059
13414 } } // namespace v8::internal 13060 } } // 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