Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(474)

Side by Side Diff: src/runtime.cc

Issue 551045: Merge r3560, r3562 and r3568 from bleeding_edge to 1.3 branch to fix... (Closed) Base URL: http://v8.googlecode.com/svn/branches/1.3/
Patch Set: '' Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects.cc ('k') | src/utils.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 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 1388 matching lines...) Expand 10 before | Expand all | Expand 10 after
1399 StringBuilderConcatHelper(*subject_, 1399 StringBuilderConcatHelper(*subject_,
1400 char_buffer, 1400 char_buffer,
1401 *parts_, 1401 *parts_,
1402 part_count_); 1402 part_count_);
1403 } 1403 }
1404 return joined_string; 1404 return joined_string;
1405 } 1405 }
1406 1406
1407 1407
1408 void IncrementCharacterCount(int by) { 1408 void IncrementCharacterCount(int by) {
1409 if (character_count_ > Smi::kMaxValue - by) { 1409 if (character_count_ > String::kMaxLength - by) {
1410 V8::FatalProcessOutOfMemory("String.replace result too large."); 1410 V8::FatalProcessOutOfMemory("String.replace result too large.");
1411 } 1411 }
1412 character_count_ += by; 1412 character_count_ += by;
1413 } 1413 }
1414 1414
1415 private: 1415 private:
1416 1416
1417 Handle<String> NewRawAsciiString(int size) { 1417 Handle<String> NewRawAsciiString(int size) {
1418 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String); 1418 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
1419 } 1419 }
(...skipping 1825 matching lines...) Expand 10 before | Expand all | Expand 10 after
3245 while (buffer->has_more()) { 3245 while (buffer->has_more()) {
3246 uint16_t character = buffer->GetNext(); 3246 uint16_t character = buffer->GetNext();
3247 if (character >= 256) { 3247 if (character >= 256) {
3248 escaped_length += 6; 3248 escaped_length += 6;
3249 } else if (IsNotEscaped(character)) { 3249 } else if (IsNotEscaped(character)) {
3250 escaped_length++; 3250 escaped_length++;
3251 } else { 3251 } else {
3252 escaped_length += 3; 3252 escaped_length += 3;
3253 } 3253 }
3254 // We don't allow strings that are longer than a maximal length. 3254 // We don't allow strings that are longer than a maximal length.
3255 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
3255 if (escaped_length > String::kMaxLength) { 3256 if (escaped_length > String::kMaxLength) {
3256 Top::context()->mark_out_of_memory(); 3257 Top::context()->mark_out_of_memory();
3257 return Failure::OutOfMemoryException(); 3258 return Failure::OutOfMemoryException();
3258 } 3259 }
3259 } 3260 }
3260 } 3261 }
3261 // No length change implies no change. Return original string if no change. 3262 // No length change implies no change. Return original string if no change.
3262 if (escaped_length == length) { 3263 if (escaped_length == length) {
3263 return source; 3264 return source;
3264 } 3265 }
(...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after
3806 3807
3807 if (array_length == 0) { 3808 if (array_length == 0) {
3808 return Heap::empty_string(); 3809 return Heap::empty_string();
3809 } else if (array_length == 1) { 3810 } else if (array_length == 1) {
3810 Object* first = fixed_array->get(0); 3811 Object* first = fixed_array->get(0);
3811 if (first->IsString()) return first; 3812 if (first->IsString()) return first;
3812 } 3813 }
3813 3814
3814 bool ascii = special->IsAsciiRepresentation(); 3815 bool ascii = special->IsAsciiRepresentation();
3815 int position = 0; 3816 int position = 0;
3817 int increment = 0;
3816 for (int i = 0; i < array_length; i++) { 3818 for (int i = 0; i < array_length; i++) {
3817 Object* elt = fixed_array->get(i); 3819 Object* elt = fixed_array->get(i);
3818 if (elt->IsSmi()) { 3820 if (elt->IsSmi()) {
3819 int len = Smi::cast(elt)->value(); 3821 int len = Smi::cast(elt)->value();
3820 int pos = len >> 11; 3822 int pos = len >> 11;
3821 len &= 0x7ff; 3823 len &= 0x7ff;
3822 if (pos + len > special_length) { 3824 if (pos + len > special_length) {
3823 return Top::Throw(Heap::illegal_argument_symbol()); 3825 return Top::Throw(Heap::illegal_argument_symbol());
3824 } 3826 }
3825 position += len; 3827 increment = len;
3826 } else if (elt->IsString()) { 3828 } else if (elt->IsString()) {
3827 String* element = String::cast(elt); 3829 String* element = String::cast(elt);
3828 int element_length = element->length(); 3830 int element_length = element->length();
3829 position += element_length; 3831 increment = element_length;
3830 if (ascii && !element->IsAsciiRepresentation()) { 3832 if (ascii && !element->IsAsciiRepresentation()) {
3831 ascii = false; 3833 ascii = false;
3832 } 3834 }
3833 } else { 3835 } else {
3834 return Top::Throw(Heap::illegal_argument_symbol()); 3836 return Top::Throw(Heap::illegal_argument_symbol());
3835 } 3837 }
3836 if (position > String::kMaxLength) { 3838 if (increment > String::kMaxLength - position) {
3837 Top::context()->mark_out_of_memory(); 3839 Top::context()->mark_out_of_memory();
3838 return Failure::OutOfMemoryException(); 3840 return Failure::OutOfMemoryException();
3839 } 3841 }
3842 position += increment;
3840 } 3843 }
3841 3844
3842 int length = position; 3845 int length = position;
3843 Object* object; 3846 Object* object;
3844 3847
3845 if (ascii) { 3848 if (ascii) {
3846 object = Heap::AllocateRawAsciiString(length); 3849 object = Heap::AllocateRawAsciiString(length);
3847 if (object->IsFailure()) return object; 3850 if (object->IsFailure()) return object;
3848 SeqAsciiString* answer = SeqAsciiString::cast(object); 3851 SeqAsciiString* answer = SeqAsciiString::cast(object);
3849 StringBuilderConcatHelper(special, 3852 StringBuilderConcatHelper(special,
(...skipping 1375 matching lines...) Expand 10 before | Expand all | Expand 10 after
5225 * 5228 *
5226 * An index limit is used to deal with the situation that a result array 5229 * An index limit is used to deal with the situation that a result array
5227 * length overflows 32-bit non-negative integer. 5230 * length overflows 32-bit non-negative integer.
5228 */ 5231 */
5229 class ArrayConcatVisitor { 5232 class ArrayConcatVisitor {
5230 public: 5233 public:
5231 ArrayConcatVisitor(Handle<FixedArray> storage, 5234 ArrayConcatVisitor(Handle<FixedArray> storage,
5232 uint32_t index_limit, 5235 uint32_t index_limit,
5233 bool fast_elements) : 5236 bool fast_elements) :
5234 storage_(storage), index_limit_(index_limit), 5237 storage_(storage), index_limit_(index_limit),
5235 fast_elements_(fast_elements), index_offset_(0) { } 5238 index_offset_(0), fast_elements_(fast_elements) { }
5236 5239
5237 void visit(uint32_t i, Handle<Object> elm) { 5240 void visit(uint32_t i, Handle<Object> elm) {
5238 uint32_t index = i + index_offset_; 5241 if (i >= index_limit_ - index_offset_) return;
5239 if (index >= index_limit_) return; 5242 uint32_t index = index_offset_ + i;
5240 5243
5241 if (fast_elements_) { 5244 if (fast_elements_) {
5242 ASSERT(index < static_cast<uint32_t>(storage_->length())); 5245 ASSERT(index < static_cast<uint32_t>(storage_->length()));
5243 storage_->set(index, *elm); 5246 storage_->set(index, *elm);
5244 5247
5245 } else { 5248 } else {
5246 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_); 5249 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
5247 Handle<NumberDictionary> result = 5250 Handle<NumberDictionary> result =
5248 Factory::DictionaryAtNumberPut(dict, index, elm); 5251 Factory::DictionaryAtNumberPut(dict, index, elm);
5249 if (!result.is_identical_to(dict)) 5252 if (!result.is_identical_to(dict))
5250 storage_ = result; 5253 storage_ = result;
5251 } 5254 }
5252 } 5255 }
5253 5256
5254 void increase_index_offset(uint32_t delta) { 5257 void increase_index_offset(uint32_t delta) {
5255 index_offset_ += delta; 5258 if (index_limit_ - index_offset_ < delta) {
5259 index_offset_ = index_limit_;
5260 } else {
5261 index_offset_ += delta;
5262 }
5256 } 5263 }
5257 5264
5258 Handle<FixedArray> storage() { return storage_; } 5265 Handle<FixedArray> storage() { return storage_; }
5259 5266
5260 private: 5267 private:
5261 Handle<FixedArray> storage_; 5268 Handle<FixedArray> storage_;
5269 // Limit on the accepted indices. Elements with indices larger than the
5270 // limit are ignored by the visitor.
5262 uint32_t index_limit_; 5271 uint32_t index_limit_;
5272 // Index after last seen index. Always less than or equal to index_limit_.
5273 uint32_t index_offset_;
5263 bool fast_elements_; 5274 bool fast_elements_;
5264 uint32_t index_offset_;
5265 }; 5275 };
5266 5276
5267 5277
5268 template<class ExternalArrayClass, class ElementType> 5278 template<class ExternalArrayClass, class ElementType>
5269 static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver, 5279 static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
5270 bool elements_are_ints, 5280 bool elements_are_ints,
5271 bool elements_are_guaranteed_smis, 5281 bool elements_are_guaranteed_smis,
5272 uint32_t range, 5282 uint32_t range,
5273 ArrayConcatVisitor* visitor) { 5283 ArrayConcatVisitor* visitor) {
5274 Handle<ExternalArrayClass> array( 5284 Handle<ExternalArrayClass> array(
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
5426 5436
5427 /** 5437 /**
5428 * A helper function that visits elements of an Array object, and elements 5438 * A helper function that visits elements of an Array object, and elements
5429 * on its prototypes. 5439 * on its prototypes.
5430 * 5440 *
5431 * Elements on prototypes are visited first, and only elements whose indices 5441 * Elements on prototypes are visited first, and only elements whose indices
5432 * less than Array length are visited. 5442 * less than Array length are visited.
5433 * 5443 *
5434 * If a ArrayConcatVisitor object is given, the visitor is called with 5444 * If a ArrayConcatVisitor object is given, the visitor is called with
5435 * parameters, element's index + visitor_index_offset and the element. 5445 * parameters, element's index + visitor_index_offset and the element.
5446 *
5447 * The returned number of elements is an upper bound on the actual number
5448 * of elements added. If the same element occurs in more than one object
5449 * in the array's prototype chain, it will be counted more than once, but
5450 * will only occur once in the result.
5436 */ 5451 */
5437 static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array, 5452 static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
5438 ArrayConcatVisitor* visitor) { 5453 ArrayConcatVisitor* visitor) {
5439 uint32_t range = static_cast<uint32_t>(array->length()->Number()); 5454 uint32_t range = static_cast<uint32_t>(array->length()->Number());
5440 Handle<Object> obj = array; 5455 Handle<Object> obj = array;
5441 5456
5442 static const int kEstimatedPrototypes = 3; 5457 static const int kEstimatedPrototypes = 3;
5443 List< Handle<JSObject> > objects(kEstimatedPrototypes); 5458 List< Handle<JSObject> > objects(kEstimatedPrototypes);
5444 5459
5445 // Visit prototype first. If an element on the prototype is shadowed by 5460 // Visit prototype first. If an element on the prototype is shadowed by
5446 // the inheritor using the same index, the ArrayConcatVisitor visits 5461 // the inheritor using the same index, the ArrayConcatVisitor visits
5447 // the prototype element before the shadowing element. 5462 // the prototype element before the shadowing element.
5448 // The visitor can simply overwrite the old value by new value using 5463 // The visitor can simply overwrite the old value by new value using
5449 // the same index. This follows Array::concat semantics. 5464 // the same index. This follows Array::concat semantics.
5450 while (!obj->IsNull()) { 5465 while (!obj->IsNull()) {
5451 objects.Add(Handle<JSObject>::cast(obj)); 5466 objects.Add(Handle<JSObject>::cast(obj));
5452 obj = Handle<Object>(obj->GetPrototype()); 5467 obj = Handle<Object>(obj->GetPrototype());
5453 } 5468 }
5454 5469
5455 uint32_t nof_elements = 0; 5470 uint32_t nof_elements = 0;
5456 for (int i = objects.length() - 1; i >= 0; i--) { 5471 for (int i = objects.length() - 1; i >= 0; i--) {
5457 Handle<JSObject> obj = objects[i]; 5472 Handle<JSObject> obj = objects[i];
5458 nof_elements += 5473 uint32_t encountered_elements =
5459 IterateElements(Handle<JSObject>::cast(obj), range, visitor); 5474 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
5475
5476 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
5477 nof_elements = JSObject::kMaxElementCount;
5478 } else {
5479 nof_elements += encountered_elements;
5480 }
5460 } 5481 }
5461 5482
5462 return nof_elements; 5483 return nof_elements;
5463 } 5484 }
5464 5485
5465 5486
5466 /** 5487 /**
5467 * A helper function of Runtime_ArrayConcat. 5488 * A helper function of Runtime_ArrayConcat.
5468 * 5489 *
5469 * The first argument is an Array of arrays and objects. It is the 5490 * The first argument is an Array of arrays and objects. It is the
5470 * same as the arguments array of Array::concat JS function. 5491 * same as the arguments array of Array::concat JS function.
5471 * 5492 *
5472 * If an argument is an Array object, the function visits array 5493 * If an argument is an Array object, the function visits array
5473 * elements. If an argument is not an Array object, the function 5494 * elements. If an argument is not an Array object, the function
5474 * visits the object as if it is an one-element array. 5495 * visits the object as if it is an one-element array.
5475 * 5496 *
5476 * If the result array index overflows 32-bit integer, the rounded 5497 * If the result array index overflows 32-bit unsigned integer, the rounded
5477 * non-negative number is used as new length. For example, if one 5498 * non-negative number is used as new length. For example, if one
5478 * array length is 2^32 - 1, second array length is 1, the 5499 * array length is 2^32 - 1, second array length is 1, the
5479 * concatenated array length is 0. 5500 * concatenated array length is 0.
5501 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
5502 * is one more than the last array index to get a value assigned).
5480 */ 5503 */
5481 static uint32_t IterateArguments(Handle<JSArray> arguments, 5504 static uint32_t IterateArguments(Handle<JSArray> arguments,
5482 ArrayConcatVisitor* visitor) { 5505 ArrayConcatVisitor* visitor) {
5483 uint32_t visited_elements = 0; 5506 uint32_t visited_elements = 0;
5484 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); 5507 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
5485 5508
5486 for (uint32_t i = 0; i < num_of_args; i++) { 5509 for (uint32_t i = 0; i < num_of_args; i++) {
5487 Handle<Object> obj(arguments->GetElement(i)); 5510 Handle<Object> obj(arguments->GetElement(i));
5488 if (obj->IsJSArray()) { 5511 if (obj->IsJSArray()) {
5489 Handle<JSArray> array = Handle<JSArray>::cast(obj); 5512 Handle<JSArray> array = Handle<JSArray>::cast(obj);
5490 uint32_t len = static_cast<uint32_t>(array->length()->Number()); 5513 uint32_t len = static_cast<uint32_t>(array->length()->Number());
5491 uint32_t nof_elements = 5514 uint32_t nof_elements =
5492 IterateArrayAndPrototypeElements(array, visitor); 5515 IterateArrayAndPrototypeElements(array, visitor);
5493 // Total elements of array and its prototype chain can be more than 5516 // Total elements of array and its prototype chain can be more than
5494 // the array length, but ArrayConcat can only concatenate at most 5517 // the array length, but ArrayConcat can only concatenate at most
5495 // the array length number of elements. 5518 // the array length number of elements. We use the length as an estimate
5496 visited_elements += (nof_elements > len) ? len : nof_elements; 5519 // for the actual number of elements added.
5520 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
5521 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
5522 visited_elements = JSArray::kMaxElementCount;
5523 } else {
5524 visited_elements += added_elements;
5525 }
5497 if (visitor) visitor->increase_index_offset(len); 5526 if (visitor) visitor->increase_index_offset(len);
5498
5499 } else { 5527 } else {
5500 if (visitor) { 5528 if (visitor) {
5501 visitor->visit(0, obj); 5529 visitor->visit(0, obj);
5502 visitor->increase_index_offset(1); 5530 visitor->increase_index_offset(1);
5503 } 5531 }
5504 visited_elements++; 5532 if (visited_elements < JSArray::kMaxElementCount) {
5533 visited_elements++;
5534 }
5505 } 5535 }
5506 } 5536 }
5507 return visited_elements; 5537 return visited_elements;
5508 } 5538 }
5509 5539
5510 5540
5511 /** 5541 /**
5512 * Array::concat implementation. 5542 * Array::concat implementation.
5513 * See ECMAScript 262, 15.4.4.4. 5543 * See ECMAScript 262, 15.4.4.4.
5544 * TODO(lrn): Fix non-compliance for very large concatenations and update to
5545 * following the ECMAScript 5 specification.
5514 */ 5546 */
5515 static Object* Runtime_ArrayConcat(Arguments args) { 5547 static Object* Runtime_ArrayConcat(Arguments args) {
5516 ASSERT(args.length() == 1); 5548 ASSERT(args.length() == 1);
5517 HandleScope handle_scope; 5549 HandleScope handle_scope;
5518 5550
5519 CONVERT_CHECKED(JSArray, arg_arrays, args[0]); 5551 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
5520 Handle<JSArray> arguments(arg_arrays); 5552 Handle<JSArray> arguments(arg_arrays);
5521 5553
5522 // Pass 1: estimate the number of elements of the result 5554 // Pass 1: estimate the number of elements of the result
5523 // (it could be more than real numbers if prototype has elements). 5555 // (it could be more than real numbers if prototype has elements).
5524 uint32_t result_length = 0; 5556 uint32_t result_length = 0;
5525 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); 5557 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
5526 5558
5527 { AssertNoAllocation nogc; 5559 { AssertNoAllocation nogc;
5528 for (uint32_t i = 0; i < num_of_args; i++) { 5560 for (uint32_t i = 0; i < num_of_args; i++) {
5529 Object* obj = arguments->GetElement(i); 5561 Object* obj = arguments->GetElement(i);
5562 uint32_t length_estimate;
5530 if (obj->IsJSArray()) { 5563 if (obj->IsJSArray()) {
5531 result_length += 5564 length_estimate =
5532 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number()); 5565 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
5533 } else { 5566 } else {
5534 result_length++; 5567 length_estimate = 1;
5535 } 5568 }
5569 if (JSObject::kMaxElementCount - result_length < length_estimate) {
5570 result_length = JSObject::kMaxElementCount;
5571 break;
5572 }
5573 result_length += length_estimate;
5536 } 5574 }
5537 } 5575 }
5538 5576
5539 // Allocate an empty array, will set length and content later. 5577 // Allocate an empty array, will set length and content later.
5540 Handle<JSArray> result = Factory::NewJSArray(0); 5578 Handle<JSArray> result = Factory::NewJSArray(0);
5541 5579
5542 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL); 5580 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
5543 // If estimated number of elements is more than half of length, a 5581 // If estimated number of elements is more than half of length, a
5544 // fixed array (fast case) is more time and space-efficient than a 5582 // fixed array (fast case) is more time and space-efficient than a
5545 // dictionary. 5583 // dictionary.
(...skipping 2312 matching lines...) Expand 10 before | Expand all | Expand 10 after
7858 } else { 7896 } else {
7859 // Handle last resort GC and make sure to allow future allocations 7897 // Handle last resort GC and make sure to allow future allocations
7860 // to grow the heap without causing GCs (if possible). 7898 // to grow the heap without causing GCs (if possible).
7861 Counters::gc_last_resort_from_js.Increment(); 7899 Counters::gc_last_resort_from_js.Increment();
7862 Heap::CollectAllGarbage(false); 7900 Heap::CollectAllGarbage(false);
7863 } 7901 }
7864 } 7902 }
7865 7903
7866 7904
7867 } } // namespace v8::internal 7905 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.cc ('k') | src/utils.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698