| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |