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 |