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 |
5174 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) { | 5389 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) { |
5175 HandleScope scope(isolate); | 5390 NoHandleAllocation ha(isolate); |
5176 CONVERT_ARG_HANDLE_CHECKED(String, string, 0); | 5391 CONVERT_ARG_CHECKED(String, str, 0); |
| 5392 if (!str->IsFlat()) { |
| 5393 MaybeObject* try_flatten = str->TryFlatten(); |
| 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 } |
| 5412 |
| 5413 |
| 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); |
5177 ASSERT(args.length() == 1); | 5494 ASSERT(args.length() == 1); |
5178 return BasicJsonStringifier::StringifyString(isolate, string); | 5495 CONVERT_ARG_CHECKED(JSArray, array, 0); |
5179 } | 5496 |
5180 | 5497 if (!array->HasFastObjectElements()) { |
5181 | 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 |
5182 RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) { | 5536 RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) { |
5183 HandleScope scope(isolate); | 5537 HandleScope scope(isolate); |
5184 ASSERT(args.length() == 1); | 5538 ASSERT(args.length() == 1); |
5185 BasicJsonStringifier stringifier(isolate); | 5539 BasicJsonStringifier stringifier(isolate); |
5186 return stringifier.Stringify(Handle<Object>(args[0], isolate)); | 5540 return stringifier.Stringify(Handle<Object>(args[0], isolate)); |
5187 } | 5541 } |
5188 | 5542 |
5189 | 5543 |
5190 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { | 5544 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { |
5191 NoHandleAllocation ha(isolate); | 5545 NoHandleAllocation ha(isolate); |
(...skipping 7794 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12986 // Handle last resort GC and make sure to allow future allocations | 13340 // Handle last resort GC and make sure to allow future allocations |
12987 // to grow the heap without causing GCs (if possible). | 13341 // to grow the heap without causing GCs (if possible). |
12988 isolate->counters()->gc_last_resort_from_js()->Increment(); | 13342 isolate->counters()->gc_last_resort_from_js()->Increment(); |
12989 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, | 13343 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, |
12990 "Runtime::PerformGC"); | 13344 "Runtime::PerformGC"); |
12991 } | 13345 } |
12992 } | 13346 } |
12993 | 13347 |
12994 | 13348 |
12995 } } // namespace v8::internal | 13349 } } // namespace v8::internal |
OLD | NEW |