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