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 ASSERT(2 <= radix && radix <= 36); | |
Lasse Reichstein
2011/05/26 11:24:43
ASSERT -> RUNTIME_ASSERT
sandholm
2011/05/26 11:41:36
Done.
| |
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 } |
Lasse Reichstein
2011/05/26 11:24:43
Maybe we should have special case for < radix^2 to
sandholm
2011/05/26 11:41:36
Good idea (for another CL).
| |
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(Isolate* isolate, | |
5102 SinkChar* write_cursor, | |
Lasse Reichstein
2011/05/26 11:24:43
indentation.
sandholm
2011/05/26 11:41:36
Done.
| |
5103 Vector<const SourceChar> characters) { | |
5104 const SourceChar* read_cursor = characters.start(); | |
5105 const SourceChar* end = read_cursor + characters.length(); | |
5106 *(write_cursor++) = '"'; | |
5107 while (read_cursor < end) { | |
5108 SourceChar c = *(read_cursor++); | |
5109 if (sizeof(SourceChar) > 1u && | |
5110 static_cast<unsigned>(c) >= kQuoteTableLength) { | |
5111 *(write_cursor++) = c; | |
5112 } else { | |
5113 int len = JsonQuoteLengths[static_cast<unsigned>(c)]; | |
5114 const char* replacement = JsonQuotes + | |
5115 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry; | |
5116 write_cursor[0] = replacement[0]; | |
5117 if (len > 1) { | |
5118 write_cursor[1] = replacement[1]; | |
5119 if (len > 2) { | |
5120 ASSERT(len == 6); | |
5121 write_cursor[2] = replacement[2]; | |
5122 write_cursor[3] = replacement[3]; | |
5123 write_cursor[4] = replacement[4]; | |
5124 write_cursor[5] = replacement[5]; | |
5125 } | |
5126 } | |
5127 write_cursor += len; | |
5128 } | |
5129 } | |
5130 *(write_cursor++) = '"'; | |
5131 return write_cursor; | |
5132 } | |
5133 | |
5134 | |
5101 template <typename Char, typename StringType, bool comma> | 5135 template <typename Char, typename StringType, bool comma> |
5102 static MaybeObject* QuoteJsonString(Isolate* isolate, | 5136 static MaybeObject* QuoteJsonString(Isolate* isolate, |
5103 Vector<const Char> characters) { | 5137 Vector<const Char> characters) { |
5104 int length = characters.length(); | 5138 int length = characters.length(); |
5105 isolate->counters()->quote_json_char_count()->Increment(length); | 5139 isolate->counters()->quote_json_char_count()->Increment(length); |
5106 const int kSpaceForQuotes = 2 + (comma ? 1 :0); | 5140 int worst_case_length = |
5107 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes; | 5141 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma; |
5108 if (worst_case_length > kMaxGuaranteedNewSpaceString) { | 5142 if (worst_case_length > kMaxGuaranteedNewSpaceString) { |
5109 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); | 5143 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); |
5110 } | 5144 } |
5111 | 5145 |
5112 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, | 5146 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, |
5113 worst_case_length); | 5147 worst_case_length); |
5114 Object* new_object; | 5148 Object* new_object; |
5115 if (!new_alloc->ToObject(&new_object)) { | 5149 if (!new_alloc->ToObject(&new_object)) { |
5116 return new_alloc; | 5150 return new_alloc; |
5117 } | 5151 } |
5118 if (!isolate->heap()->new_space()->Contains(new_object)) { | 5152 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 | 5153 // 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 | 5154 // 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 | 5155 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in |
5122 // CEntryStub::GenerateCore. | 5156 // CEntryStub::GenerateCore. |
5123 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); | 5157 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); |
5124 } | 5158 } |
5125 StringType* new_string = StringType::cast(new_object); | 5159 StringType* new_string = StringType::cast(new_object); |
5126 ASSERT(isolate->heap()->new_space()->Contains(new_string)); | 5160 ASSERT(isolate->heap()->new_space()->Contains(new_string)); |
5127 | 5161 |
5128 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); | 5162 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); |
5129 Char* write_cursor = reinterpret_cast<Char*>( | 5163 Char* write_cursor = reinterpret_cast<Char*>( |
5130 new_string->address() + SeqAsciiString::kHeaderSize); | 5164 new_string->address() + SeqAsciiString::kHeaderSize); |
5131 if (comma) *(write_cursor++) = ','; | 5165 if (comma) *(write_cursor++) = ','; |
5132 *(write_cursor++) = '"'; | 5166 write_cursor = WriteQuoteJsonString<Char, Char>(isolate, |
5133 | 5167 write_cursor, |
5134 const Char* read_cursor = characters.start(); | 5168 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>( | 5169 int final_length = static_cast<int>( |
5161 write_cursor - reinterpret_cast<Char*>( | 5170 write_cursor - reinterpret_cast<Char*>( |
5162 new_string->address() + SeqAsciiString::kHeaderSize)); | 5171 new_string->address() + SeqAsciiString::kHeaderSize)); |
5163 isolate->heap()->new_space()-> | 5172 isolate->heap()->new_space()-> |
5164 template ShrinkStringAtAllocationBoundary<StringType>( | 5173 template ShrinkStringAtAllocationBoundary<StringType>( |
5165 new_string, final_length); | 5174 new_string, final_length); |
5166 return new_string; | 5175 return new_string; |
5167 } | 5176 } |
5168 | 5177 |
5169 | 5178 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5203 } | 5212 } |
5204 if (str->IsTwoByteRepresentation()) { | 5213 if (str->IsTwoByteRepresentation()) { |
5205 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate, | 5214 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate, |
5206 str->ToUC16Vector()); | 5215 str->ToUC16Vector()); |
5207 } else { | 5216 } else { |
5208 return QuoteJsonString<char, SeqAsciiString, true>(isolate, | 5217 return QuoteJsonString<char, SeqAsciiString, true>(isolate, |
5209 str->ToAsciiVector()); | 5218 str->ToAsciiVector()); |
5210 } | 5219 } |
5211 } | 5220 } |
5212 | 5221 |
5222 | |
5223 template <typename Char, typename StringType> | |
5224 static MaybeObject* QuoteJsonStringArray(Isolate* isolate, | |
5225 FixedArray* array, | |
5226 int worst_case_length) { | |
5227 int length = array->length(); | |
5228 | |
5229 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, | |
5230 worst_case_length); | |
5231 Object* new_object; | |
5232 if (!new_alloc->ToObject(&new_object)) { | |
5233 return new_alloc; | |
5234 } | |
5235 if (!isolate->heap()->new_space()->Contains(new_object)) { | |
5236 // Even if our string is small enough to fit in new space we still have to | |
5237 // handle it being allocated in old space as may happen in the third | |
5238 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in | |
5239 // CEntryStub::GenerateCore. | |
5240 return isolate->heap()->undefined_value(); | |
5241 } | |
Lasse Reichstein
2011/05/26 11:24:43
I dare you to put an
AssertNoAllocation no_gc;
he
sandholm
2011/05/26 11:41:36
Done.
| |
5242 StringType* new_string = StringType::cast(new_object); | |
5243 ASSERT(isolate->heap()->new_space()->Contains(new_string)); | |
5244 | |
5245 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); | |
5246 Char* write_cursor = reinterpret_cast<Char*>( | |
5247 new_string->address() + SeqAsciiString::kHeaderSize); | |
5248 *(write_cursor++) = '['; | |
5249 for (int i = 0; i < length; i++) { | |
5250 if (i != 0) *(write_cursor++) = ','; | |
5251 String* str = String::cast(array->get(i)); | |
5252 if (str->IsTwoByteRepresentation()) { | |
5253 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate, | |
5254 write_cursor, | |
5255 str->ToUC16Vector()); | |
5256 } else { | |
5257 write_cursor = WriteQuoteJsonString<Char, char>(isolate, | |
5258 write_cursor, | |
5259 str->ToAsciiVector()); | |
5260 } | |
5261 } | |
5262 *(write_cursor++) = ']'; | |
5263 | |
5264 int final_length = static_cast<int>( | |
5265 write_cursor - reinterpret_cast<Char*>( | |
5266 new_string->address() + SeqAsciiString::kHeaderSize)); | |
5267 isolate->heap()->new_space()-> | |
5268 template ShrinkStringAtAllocationBoundary<StringType>( | |
5269 new_string, final_length); | |
5270 return new_string; | |
5271 } | |
5272 | |
5273 | |
5274 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) { | |
5275 NoHandleAllocation ha; | |
5276 ASSERT(args.length() == 1); | |
5277 CONVERT_CHECKED(JSArray, array, args[0]); | |
5278 | |
5279 if (!array->HasFastElements()) return isolate->heap()->undefined_value(); | |
5280 FixedArray* elements = FixedArray::cast(array->elements()); | |
5281 int n = elements->length(); | |
5282 bool ascii = true; | |
5283 int total_length = 0; | |
5284 | |
5285 for (int i = 0; i < n; i++) { | |
5286 Object* elt = elements->get(i); | |
5287 if (!elt->IsString()) return isolate->heap()->undefined_value(); | |
5288 String* element = String::cast(elt); | |
5289 if (!element->IsFlat()) return isolate->heap()->undefined_value(); | |
5290 total_length += element->length(); | |
5291 if (ascii && element->IsTwoByteRepresentation()) { | |
5292 ascii = false; | |
5293 } | |
5294 } | |
5295 | |
5296 int worst_case_length = | |
5297 kSpaceForBrackets + n * kSpaceForQuotesAndComma | |
5298 + total_length * kJsonQuoteWorstCaseBlowup; | |
5299 | |
5300 if (worst_case_length > kMaxGuaranteedNewSpaceString) { | |
5301 return isolate->heap()->undefined_value(); | |
5302 } | |
5303 | |
5304 if (ascii) { | |
5305 return QuoteJsonStringArray<char, SeqAsciiString>(isolate, | |
5306 elements, | |
5307 worst_case_length); | |
5308 } else { | |
5309 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate, | |
5310 elements, | |
5311 worst_case_length); | |
5312 } | |
5313 } | |
5314 | |
5315 | |
5213 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { | 5316 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { |
5214 NoHandleAllocation ha; | 5317 NoHandleAllocation ha; |
5215 | 5318 |
5216 CONVERT_CHECKED(String, s, args[0]); | 5319 CONVERT_CHECKED(String, s, args[0]); |
5217 CONVERT_SMI_CHECKED(radix, args[1]); | 5320 CONVERT_SMI_CHECKED(radix, args[1]); |
5218 | 5321 |
5219 s->TryFlatten(); | 5322 s->TryFlatten(); |
5220 | 5323 |
5221 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); | 5324 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); |
5222 double value = StringToInt(isolate->unicode_cache(), s, radix); | 5325 double value = StringToInt(isolate->unicode_cache(), s, radix); |
(...skipping 6994 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12217 } else { | 12320 } else { |
12218 // Handle last resort GC and make sure to allow future allocations | 12321 // Handle last resort GC and make sure to allow future allocations |
12219 // to grow the heap without causing GCs (if possible). | 12322 // to grow the heap without causing GCs (if possible). |
12220 isolate->counters()->gc_last_resort_from_js()->Increment(); | 12323 isolate->counters()->gc_last_resort_from_js()->Increment(); |
12221 isolate->heap()->CollectAllGarbage(false); | 12324 isolate->heap()->CollectAllGarbage(false); |
12222 } | 12325 } |
12223 } | 12326 } |
12224 | 12327 |
12225 | 12328 |
12226 } } // namespace v8::internal | 12329 } } // namespace v8::internal |
OLD | NEW |