| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 return Construct(RETRY_AFTER_GC, value); | 468 return Construct(RETRY_AFTER_GC, value); |
| 469 } | 469 } |
| 470 | 470 |
| 471 | 471 |
| 472 // Should a word be prefixed by 'a' or 'an' in order to read naturally in | 472 // Should a word be prefixed by 'a' or 'an' in order to read naturally in |
| 473 // English? Returns false for non-ASCII or words that don't start with | 473 // English? Returns false for non-ASCII or words that don't start with |
| 474 // a capital letter. The a/an rule follows pronunciation in English. | 474 // a capital letter. The a/an rule follows pronunciation in English. |
| 475 // We don't use the BBC's overcorrect "an historic occasion" though if | 475 // We don't use the BBC's overcorrect "an historic occasion" though if |
| 476 // you speak a dialect you may well say "an 'istoric occasion". | 476 // you speak a dialect you may well say "an 'istoric occasion". |
| 477 static bool AnWord(String* str) { | 477 static bool AnWord(String* str) { |
| 478 if (str->length() == 0) return false; // a nothing | 478 StringShape shape(str); |
| 479 int c0 = str->Get(0); | 479 if (str->length(shape) == 0) return false; // A nothing. |
| 480 int c1 = str->length() > 1 ? str->Get(1) : 0; | 480 int c0 = str->Get(shape, 0); |
| 481 int c1 = str->length(shape) > 1 ? str->Get(shape, 1) : 0; |
| 481 if (c0 == 'U') { | 482 if (c0 == 'U') { |
| 482 if (c1 > 'Z') { | 483 if (c1 > 'Z') { |
| 483 return true; // an Umpire, but a UTF8String, a U | 484 return true; // An Umpire, but a UTF8String, a U. |
| 484 } | 485 } |
| 485 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') { | 486 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') { |
| 486 return true; // an Ape, an ABCBook | 487 return true; // An Ape, an ABCBook. |
| 487 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) && | 488 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) && |
| 488 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' || | 489 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' || |
| 489 c0 == 'S' || c0 == 'X')) { | 490 c0 == 'S' || c0 == 'X')) { |
| 490 return true; // an MP3File, an M | 491 return true; // An MP3File, an M. |
| 491 } | 492 } |
| 492 return false; | 493 return false; |
| 493 } | 494 } |
| 494 | 495 |
| 495 | 496 |
| 496 Object* String::Flatten() { | 497 Object* String::Flatten(StringShape shape) { |
| 497 #ifdef DEBUG | 498 #ifdef DEBUG |
| 498 // Do not attempt to flatten in debug mode when allocation is not | 499 // Do not attempt to flatten in debug mode when allocation is not |
| 499 // allowed. This is to avoid an assertion failure when allocating. | 500 // allowed. This is to avoid an assertion failure when allocating. |
| 500 // Flattening strings is the only case where we always allow | 501 // Flattening strings is the only case where we always allow |
| 501 // allocation because no GC is performed if the allocation fails. | 502 // allocation because no GC is performed if the allocation fails. |
| 502 if (!Heap::IsAllocationAllowed()) return this; | 503 if (!Heap::IsAllocationAllowed()) return this; |
| 503 #endif | 504 #endif |
| 504 | 505 |
| 505 switch (representation_tag()) { | 506 switch (shape.representation_tag()) { |
| 506 case kSlicedStringTag: { | 507 case kSlicedStringTag: { |
| 507 SlicedString* ss = SlicedString::cast(this); | 508 SlicedString* ss = SlicedString::cast(this); |
| 508 // The SlicedString constructor should ensure that there are no | 509 // The SlicedString constructor should ensure that there are no |
| 509 // SlicedStrings that are constructed directly on top of other | 510 // SlicedStrings that are constructed directly on top of other |
| 510 // SlicedStrings. | 511 // SlicedStrings. |
| 511 ASSERT(!ss->buffer()->IsSlicedString()); | 512 String* buf = ss->buffer(); |
| 512 Object* ok = String::cast(ss->buffer())->Flatten(); | 513 ASSERT(!buf->IsSlicedString()); |
| 514 Object* ok = buf->Flatten(StringShape(buf)); |
| 513 if (ok->IsFailure()) return ok; | 515 if (ok->IsFailure()) return ok; |
| 514 // Under certain circumstances (TryFlatten fails in String::Slice) | 516 // Under certain circumstances (TryFlatten fails in String::Slice) |
| 515 // we can have a cons string under a slice. In this case we need | 517 // we can have a cons string under a slice. In this case we need |
| 516 // to get the flat string out of the cons! | 518 // to get the flat string out of the cons! |
| 517 if (String::cast(ok)->StringIsConsString()) { | 519 if (StringShape(String::cast(ok)).IsCons()) { |
| 518 ss->set_buffer(ConsString::cast(ok)->first()); | 520 ss->set_buffer(ConsString::cast(ok)->first()); |
| 519 } | 521 } |
| 520 return this; | 522 return this; |
| 521 } | 523 } |
| 522 case kConsStringTag: { | 524 case kConsStringTag: { |
| 523 ConsString* cs = ConsString::cast(this); | 525 ConsString* cs = ConsString::cast(this); |
| 524 if (String::cast(cs->second())->length() == 0) { | 526 if (cs->second()->length() == 0) { |
| 525 return this; | 527 return this; |
| 526 } | 528 } |
| 527 // There's little point in putting the flat string in new space if the | 529 // There's little point in putting the flat string in new space if the |
| 528 // cons string is in old space. It can never get GCed until there is | 530 // cons string is in old space. It can never get GCed until there is |
| 529 // an old space GC. | 531 // an old space GC. |
| 530 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED; | 532 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED; |
| 531 int len = length(); | 533 int len = length(shape); |
| 532 Object* object; | 534 Object* object; |
| 533 String* result; | 535 String* result; |
| 534 if (IsAsciiRepresentation()) { | 536 if (shape.IsAsciiRepresentation()) { |
| 535 object = Heap::AllocateRawAsciiString(len, tenure); | 537 object = Heap::AllocateRawAsciiString(len, tenure); |
| 536 if (object->IsFailure()) return object; | 538 if (object->IsFailure()) return object; |
| 537 result = String::cast(object); | 539 result = String::cast(object); |
| 538 String* first = String::cast(cs->first()); | 540 String* first = cs->first(); |
| 539 int first_length = first->length(); | 541 StringShape first_shape(first); |
| 542 int first_length = first->length(first_shape); |
| 540 char* dest = SeqAsciiString::cast(result)->GetChars(); | 543 char* dest = SeqAsciiString::cast(result)->GetChars(); |
| 541 WriteToFlat(first, dest, 0, first_length); | 544 WriteToFlat(first, first_shape, dest, 0, first_length); |
| 542 WriteToFlat(String::cast(cs->second()), | 545 String* second = cs->second(); |
| 546 WriteToFlat(second, |
| 547 StringShape(second), |
| 543 dest + first_length, | 548 dest + first_length, |
| 544 0, | 549 0, |
| 545 len - first_length); | 550 len - first_length); |
| 546 } else { | 551 } else { |
| 547 object = Heap::AllocateRawTwoByteString(len, tenure); | 552 object = Heap::AllocateRawTwoByteString(len, tenure); |
| 548 if (object->IsFailure()) return object; | 553 if (object->IsFailure()) return object; |
| 549 result = String::cast(object); | 554 result = String::cast(object); |
| 550 uc16* dest = SeqTwoByteString::cast(result)->GetChars(); | 555 uc16* dest = SeqTwoByteString::cast(result)->GetChars(); |
| 551 String* first = String::cast(cs->first()); | 556 String* first = cs->first(); |
| 552 int first_length = first->length(); | 557 StringShape first_shape(first); |
| 553 WriteToFlat(first, dest, 0, first_length); | 558 int first_length = first->length(first_shape); |
| 554 WriteToFlat(String::cast(cs->second()), | 559 WriteToFlat(first, first_shape, dest, 0, first_length); |
| 560 String* second = cs->second(); |
| 561 WriteToFlat(second, |
| 562 StringShape(second), |
| 555 dest + first_length, | 563 dest + first_length, |
| 556 0, | 564 0, |
| 557 len - first_length); | 565 len - first_length); |
| 558 } | 566 } |
| 559 cs->set_first(result); | 567 cs->set_first(result); |
| 560 cs->set_second(Heap::empty_string()); | 568 cs->set_second(Heap::empty_string()); |
| 561 return this; | 569 return this; |
| 562 } | 570 } |
| 563 default: | 571 default: |
| 564 return this; | 572 return this; |
| 565 } | 573 } |
| 566 } | 574 } |
| 567 | 575 |
| 568 | 576 |
| 569 void String::StringShortPrint(StringStream* accumulator) { | 577 void String::StringShortPrint(StringStream* accumulator) { |
| 570 int len = length(); | 578 StringShape shape(this); |
| 579 int len = length(shape); |
| 571 if (len > kMaxMediumStringSize) { | 580 if (len > kMaxMediumStringSize) { |
| 572 accumulator->Add("<Very long string[%u]>", len); | 581 accumulator->Add("<Very long string[%u]>", len); |
| 573 return; | 582 return; |
| 574 } | 583 } |
| 575 | 584 |
| 576 if (!LooksValid()) { | 585 if (!LooksValid()) { |
| 577 accumulator->Add("<Invalid String>"); | 586 accumulator->Add("<Invalid String>"); |
| 578 return; | 587 return; |
| 579 } | 588 } |
| 580 | 589 |
| 581 StringInputBuffer buf(this); | 590 StringInputBuffer buf(this); |
| 582 | 591 |
| 583 bool truncated = false; | 592 bool truncated = false; |
| 584 if (len > kMaxShortPrintLength) { | 593 if (len > kMaxShortPrintLength) { |
| 585 len = kMaxShortPrintLength; | 594 len = kMaxShortPrintLength; |
| 586 truncated = true; | 595 truncated = true; |
| 587 } | 596 } |
| 588 bool ascii = true; | 597 bool ascii = true; |
| 589 for (int i = 0; i < len; i++) { | 598 for (int i = 0; i < len; i++) { |
| 590 int c = buf.GetNext(); | 599 int c = buf.GetNext(); |
| 591 | 600 |
| 592 if (c < 32 || c >= 127) { | 601 if (c < 32 || c >= 127) { |
| 593 ascii = false; | 602 ascii = false; |
| 594 } | 603 } |
| 595 } | 604 } |
| 596 buf.Reset(this); | 605 buf.Reset(this); |
| 597 if (ascii) { | 606 if (ascii) { |
| 598 accumulator->Add("<String[%u]: ", length()); | 607 accumulator->Add("<String[%u]: ", length(shape)); |
| 599 for (int i = 0; i < len; i++) { | 608 for (int i = 0; i < len; i++) { |
| 600 accumulator->Put(buf.GetNext()); | 609 accumulator->Put(buf.GetNext()); |
| 601 } | 610 } |
| 602 accumulator->Put('>'); | 611 accumulator->Put('>'); |
| 603 } else { | 612 } else { |
| 604 // Backslash indicates that the string contains control | 613 // Backslash indicates that the string contains control |
| 605 // characters and that backslashes are therefore escaped. | 614 // characters and that backslashes are therefore escaped. |
| 606 accumulator->Add("<String[%u]\\: ", length()); | 615 accumulator->Add("<String[%u]\\: ", length(shape)); |
| 607 for (int i = 0; i < len; i++) { | 616 for (int i = 0; i < len; i++) { |
| 608 int c = buf.GetNext(); | 617 int c = buf.GetNext(); |
| 609 if (c == '\n') { | 618 if (c == '\n') { |
| 610 accumulator->Add("\\n"); | 619 accumulator->Add("\\n"); |
| 611 } else if (c == '\r') { | 620 } else if (c == '\r') { |
| 612 accumulator->Add("\\r"); | 621 accumulator->Add("\\r"); |
| 613 } else if (c == '\\') { | 622 } else if (c == '\\') { |
| 614 accumulator->Add("\\\\"); | 623 accumulator->Add("\\\\"); |
| 615 } else if (c < 32 || c > 126) { | 624 } else if (c < 32 || c > 126) { |
| 616 accumulator->Add("\\x%02x", c); | 625 accumulator->Add("\\x%02x", c); |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 774 } | 783 } |
| 775 } | 784 } |
| 776 | 785 |
| 777 | 786 |
| 778 int HeapObject::SlowSizeFromMap(Map* map) { | 787 int HeapObject::SlowSizeFromMap(Map* map) { |
| 779 // Avoid calling functions such as FixedArray::cast during GC, which | 788 // Avoid calling functions such as FixedArray::cast during GC, which |
| 780 // read map pointer of this object again. | 789 // read map pointer of this object again. |
| 781 InstanceType instance_type = map->instance_type(); | 790 InstanceType instance_type = map->instance_type(); |
| 782 | 791 |
| 783 if (instance_type < FIRST_NONSTRING_TYPE | 792 if (instance_type < FIRST_NONSTRING_TYPE |
| 784 && (reinterpret_cast<String*>(this)->map_representation_tag(map) | 793 && (StringShape(instance_type).IsSequential())) { |
| 785 == kSeqStringTag)) { | 794 StringShape shape(instance_type); |
| 786 if (reinterpret_cast<String*>(this)->is_ascii_representation_map(map)) { | 795 if (shape.IsAsciiRepresentation()) { |
| 787 return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(map); | 796 return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(shape); |
| 788 } else { | 797 } else { |
| 789 SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this); | 798 SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this); |
| 790 return self->SeqTwoByteStringSize(map); | 799 return self->SeqTwoByteStringSize(shape); |
| 791 } | 800 } |
| 792 } | 801 } |
| 793 | 802 |
| 794 switch (instance_type) { | 803 switch (instance_type) { |
| 795 case FIXED_ARRAY_TYPE: | 804 case FIXED_ARRAY_TYPE: |
| 796 return reinterpret_cast<FixedArray*>(this)->FixedArraySize(); | 805 return reinterpret_cast<FixedArray*>(this)->FixedArraySize(); |
| 797 case BYTE_ARRAY_TYPE: | 806 case BYTE_ARRAY_TYPE: |
| 798 return reinterpret_cast<ByteArray*>(this)->ByteArraySize(); | 807 return reinterpret_cast<ByteArray*>(this)->ByteArraySize(); |
| 799 case CODE_TYPE: | 808 case CODE_TYPE: |
| 800 return reinterpret_cast<Code*>(this)->CodeSize(); | 809 return reinterpret_cast<Code*>(this)->CodeSize(); |
| (...skipping 1481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2282 AssertNoContextChange ncc; | 2291 AssertNoContextChange ncc; |
| 2283 | 2292 |
| 2284 // Check access rights if needed. | 2293 // Check access rights if needed. |
| 2285 if (IsAccessCheckNeeded() && | 2294 if (IsAccessCheckNeeded() && |
| 2286 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { | 2295 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { |
| 2287 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); | 2296 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); |
| 2288 return Heap::undefined_value(); | 2297 return Heap::undefined_value(); |
| 2289 } | 2298 } |
| 2290 | 2299 |
| 2291 // TryFlatten before operating on the string. | 2300 // TryFlatten before operating on the string. |
| 2292 name->TryFlatten(); | 2301 name->TryFlatten(StringShape(name)); |
| 2293 | 2302 |
| 2294 // Make sure name is not an index. | 2303 // Make sure name is not an index. |
| 2295 uint32_t index; | 2304 uint32_t index; |
| 2296 if (name->AsArrayIndex(&index)) return Heap::undefined_value(); | 2305 if (name->AsArrayIndex(&index)) return Heap::undefined_value(); |
| 2297 | 2306 |
| 2298 // Check if there is an API defined callback object which prohibits | 2307 // Check if there is an API defined callback object which prohibits |
| 2299 // callback overwriting in this object or it's prototype chain. | 2308 // callback overwriting in this object or it's prototype chain. |
| 2300 // This mechanism is needed for instance in a browser setting, where | 2309 // This mechanism is needed for instance in a browser setting, where |
| 2301 // certain accessors such as window.location should not be allowed | 2310 // certain accessors such as window.location should not be allowed |
| 2302 // to be overwriten because allowing overwriting could potentially | 2311 // to be overwriten because allowing overwriting could potentially |
| (...skipping 618 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2921 } | 2930 } |
| 2922 return GetContentArray()->IsEqualTo(other->GetContentArray()); | 2931 return GetContentArray()->IsEqualTo(other->GetContentArray()); |
| 2923 } | 2932 } |
| 2924 #endif | 2933 #endif |
| 2925 | 2934 |
| 2926 | 2935 |
| 2927 static StaticResource<StringInputBuffer> string_input_buffer; | 2936 static StaticResource<StringInputBuffer> string_input_buffer; |
| 2928 | 2937 |
| 2929 | 2938 |
| 2930 bool String::LooksValid() { | 2939 bool String::LooksValid() { |
| 2931 if (!Heap::Contains(this)) | 2940 if (!Heap::Contains(this)) return false; |
| 2932 return false; | 2941 return true; |
| 2933 switch (representation_tag()) { | |
| 2934 case kSeqStringTag: | |
| 2935 case kConsStringTag: | |
| 2936 case kSlicedStringTag: | |
| 2937 case kExternalStringTag: | |
| 2938 return true; | |
| 2939 default: | |
| 2940 return false; | |
| 2941 } | |
| 2942 } | 2942 } |
| 2943 | 2943 |
| 2944 | 2944 |
| 2945 int String::Utf8Length() { | 2945 int String::Utf8Length() { |
| 2946 if (is_ascii_representation()) return length(); | 2946 StringShape shape(this); |
| 2947 if (shape.IsAsciiRepresentation()) return length(shape); |
| 2947 // Attempt to flatten before accessing the string. It probably | 2948 // Attempt to flatten before accessing the string. It probably |
| 2948 // doesn't make Utf8Length faster, but it is very likely that | 2949 // doesn't make Utf8Length faster, but it is very likely that |
| 2949 // the string will be accessed later (for example by WriteUtf8) | 2950 // the string will be accessed later (for example by WriteUtf8) |
| 2950 // so it's still a good idea. | 2951 // so it's still a good idea. |
| 2951 TryFlatten(); | 2952 if (!IsFlat(shape)) { |
| 2953 TryFlatten(shape); // shape is now no longer valid. |
| 2954 } |
| 2952 Access<StringInputBuffer> buffer(&string_input_buffer); | 2955 Access<StringInputBuffer> buffer(&string_input_buffer); |
| 2953 buffer->Reset(0, this); | 2956 buffer->Reset(0, this); |
| 2954 int result = 0; | 2957 int result = 0; |
| 2955 while (buffer->has_more()) | 2958 while (buffer->has_more()) |
| 2956 result += unibrow::Utf8::Length(buffer->GetNext()); | 2959 result += unibrow::Utf8::Length(buffer->GetNext()); |
| 2957 return result; | 2960 return result; |
| 2958 } | 2961 } |
| 2959 | 2962 |
| 2960 | 2963 |
| 2961 Vector<const char> String::ToAsciiVector() { | 2964 Vector<const char> String::ToAsciiVector() { |
| 2962 ASSERT(IsAsciiRepresentation()); | 2965 StringShape shape(this); |
| 2963 ASSERT(IsFlat()); | 2966 ASSERT(shape.IsAsciiRepresentation()); |
| 2967 ASSERT(IsFlat(shape)); |
| 2964 | 2968 |
| 2965 int offset = 0; | 2969 int offset = 0; |
| 2966 int length = this->length(); | 2970 int length = this->length(shape); |
| 2967 StringRepresentationTag string_tag = representation_tag(); | 2971 StringRepresentationTag string_tag = shape.representation_tag(); |
| 2968 String* string = this; | 2972 String* string = this; |
| 2969 if (string_tag == kSlicedStringTag) { | 2973 if (string_tag == kSlicedStringTag) { |
| 2970 SlicedString* sliced = SlicedString::cast(string); | 2974 SlicedString* sliced = SlicedString::cast(string); |
| 2971 offset += sliced->start(); | 2975 offset += sliced->start(); |
| 2972 string = String::cast(sliced->buffer()); | 2976 string = sliced->buffer(); |
| 2973 string_tag = string->representation_tag(); | 2977 shape = StringShape(string); |
| 2978 string_tag = shape.representation_tag(); |
| 2974 } else if (string_tag == kConsStringTag) { | 2979 } else if (string_tag == kConsStringTag) { |
| 2975 ConsString* cons = ConsString::cast(string); | 2980 ConsString* cons = ConsString::cast(string); |
| 2976 ASSERT(String::cast(cons->second())->length() == 0); | 2981 ASSERT(cons->second()->length(StringShape(cons->second())) == 0); |
| 2977 string = String::cast(cons->first()); | 2982 string = cons->first(); |
| 2978 string_tag = string->representation_tag(); | 2983 shape = StringShape(string); |
| 2984 string_tag = shape.representation_tag(); |
| 2979 } | 2985 } |
| 2980 if (string_tag == kSeqStringTag) { | 2986 if (string_tag == kSeqStringTag) { |
| 2981 SeqAsciiString* seq = SeqAsciiString::cast(string); | 2987 SeqAsciiString* seq = SeqAsciiString::cast(string); |
| 2982 char* start = seq->GetChars(); | 2988 char* start = seq->GetChars(); |
| 2983 return Vector<const char>(start + offset, length); | 2989 return Vector<const char>(start + offset, length); |
| 2984 } | 2990 } |
| 2985 ASSERT(string_tag == kExternalStringTag); | 2991 ASSERT(string_tag == kExternalStringTag); |
| 2986 ExternalAsciiString* ext = ExternalAsciiString::cast(string); | 2992 ExternalAsciiString* ext = ExternalAsciiString::cast(string); |
| 2987 const char* start = ext->resource()->data(); | 2993 const char* start = ext->resource()->data(); |
| 2988 return Vector<const char>(start + offset, length); | 2994 return Vector<const char>(start + offset, length); |
| 2989 } | 2995 } |
| 2990 | 2996 |
| 2991 | 2997 |
| 2992 Vector<const uc16> String::ToUC16Vector() { | 2998 Vector<const uc16> String::ToUC16Vector() { |
| 2993 ASSERT(IsTwoByteStringRepresentation()); | 2999 StringShape shape(this); |
| 2994 ASSERT(IsFlat()); | 3000 ASSERT(shape.IsTwoByteRepresentation()); |
| 3001 ASSERT(IsFlat(shape)); |
| 2995 | 3002 |
| 2996 int offset = 0; | 3003 int offset = 0; |
| 2997 int length = this->length(); | 3004 int length = this->length(shape); |
| 2998 StringRepresentationTag string_tag = representation_tag(); | 3005 StringRepresentationTag string_tag = shape.representation_tag(); |
| 2999 String* string = this; | 3006 String* string = this; |
| 3000 if (string_tag == kSlicedStringTag) { | 3007 if (string_tag == kSlicedStringTag) { |
| 3001 SlicedString* sliced = SlicedString::cast(string); | 3008 SlicedString* sliced = SlicedString::cast(string); |
| 3002 offset += sliced->start(); | 3009 offset += sliced->start(); |
| 3003 string = String::cast(sliced->buffer()); | 3010 string = String::cast(sliced->buffer()); |
| 3004 string_tag = string->representation_tag(); | 3011 shape = StringShape(string); |
| 3012 string_tag = shape.representation_tag(); |
| 3005 } else if (string_tag == kConsStringTag) { | 3013 } else if (string_tag == kConsStringTag) { |
| 3006 ConsString* cons = ConsString::cast(string); | 3014 ConsString* cons = ConsString::cast(string); |
| 3007 ASSERT(String::cast(cons->second())->length() == 0); | 3015 ASSERT(cons->second()->length(StringShape(cons->second())) == 0); |
| 3008 string = String::cast(cons->first()); | 3016 string = cons->first(); |
| 3009 string_tag = string->representation_tag(); | 3017 shape = StringShape(string); |
| 3018 string_tag = shape.representation_tag(); |
| 3010 } | 3019 } |
| 3011 if (string_tag == kSeqStringTag) { | 3020 if (string_tag == kSeqStringTag) { |
| 3012 SeqTwoByteString* seq = SeqTwoByteString::cast(string); | 3021 SeqTwoByteString* seq = SeqTwoByteString::cast(string); |
| 3013 return Vector<const uc16>(seq->GetChars() + offset, length); | 3022 return Vector<const uc16>(seq->GetChars() + offset, length); |
| 3014 } | 3023 } |
| 3015 ASSERT(string_tag == kExternalStringTag); | 3024 ASSERT(string_tag == kExternalStringTag); |
| 3016 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string); | 3025 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string); |
| 3017 const uc16* start = | 3026 const uc16* start = |
| 3018 reinterpret_cast<const uc16*>(ext->resource()->data()); | 3027 reinterpret_cast<const uc16*>(ext->resource()->data()); |
| 3019 return Vector<const uc16>(start + offset, length); | 3028 return Vector<const uc16>(start + offset, length); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3079 return ToCString(allow_nulls, robust_flag, 0, -1, length_return); | 3088 return ToCString(allow_nulls, robust_flag, 0, -1, length_return); |
| 3080 } | 3089 } |
| 3081 | 3090 |
| 3082 | 3091 |
| 3083 const uc16* String::GetTwoByteData() { | 3092 const uc16* String::GetTwoByteData() { |
| 3084 return GetTwoByteData(0); | 3093 return GetTwoByteData(0); |
| 3085 } | 3094 } |
| 3086 | 3095 |
| 3087 | 3096 |
| 3088 const uc16* String::GetTwoByteData(unsigned start) { | 3097 const uc16* String::GetTwoByteData(unsigned start) { |
| 3089 ASSERT(!IsAsciiRepresentation()); | 3098 StringShape shape(this); |
| 3090 switch (representation_tag()) { | 3099 ASSERT(!shape.IsAsciiRepresentation()); |
| 3100 switch (shape.representation_tag()) { |
| 3091 case kSeqStringTag: | 3101 case kSeqStringTag: |
| 3092 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); | 3102 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); |
| 3093 case kExternalStringTag: | 3103 case kExternalStringTag: |
| 3094 return ExternalTwoByteString::cast(this)-> | 3104 return ExternalTwoByteString::cast(this)-> |
| 3095 ExternalTwoByteStringGetData(start); | 3105 ExternalTwoByteStringGetData(start); |
| 3096 case kSlicedStringTag: { | 3106 case kSlicedStringTag: { |
| 3097 SlicedString* sliced_string = SlicedString::cast(this); | 3107 SlicedString* sliced_string = SlicedString::cast(this); |
| 3098 String* buffer = String::cast(sliced_string->buffer()); | 3108 String* buffer = sliced_string->buffer(); |
| 3099 if (buffer->StringIsConsString()) { | 3109 if (StringShape(buffer).IsCons()) { |
| 3100 ConsString* cons_string = ConsString::cast(buffer); | 3110 ConsString* cs = ConsString::cast(buffer); |
| 3101 // Flattened string. | 3111 // Flattened string. |
| 3102 ASSERT(String::cast(cons_string->second())->length() == 0); | 3112 ASSERT(cs->second()->length(StringShape(cs->second())) == 0); |
| 3103 buffer = String::cast(cons_string->first()); | 3113 buffer = cs->first(); |
| 3104 } | 3114 } |
| 3105 return buffer->GetTwoByteData(start + sliced_string->start()); | 3115 return buffer->GetTwoByteData(start + sliced_string->start()); |
| 3106 } | 3116 } |
| 3107 case kConsStringTag: | 3117 case kConsStringTag: |
| 3108 UNREACHABLE(); | 3118 UNREACHABLE(); |
| 3109 return NULL; | 3119 return NULL; |
| 3110 } | 3120 } |
| 3111 UNREACHABLE(); | 3121 UNREACHABLE(); |
| 3112 return NULL; | 3122 return NULL; |
| 3113 } | 3123 } |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3194 // -IntoBuffer method it can delegate to one of the efficient | 3204 // -IntoBuffer method it can delegate to one of the efficient |
| 3195 // *AsciiStringReadBlock routines. | 3205 // *AsciiStringReadBlock routines. |
| 3196 const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb, | 3206 const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb, |
| 3197 unsigned* offset_ptr, | 3207 unsigned* offset_ptr, |
| 3198 unsigned max_chars) { | 3208 unsigned max_chars) { |
| 3199 ConsString* current = this; | 3209 ConsString* current = this; |
| 3200 unsigned offset = *offset_ptr; | 3210 unsigned offset = *offset_ptr; |
| 3201 int offset_correction = 0; | 3211 int offset_correction = 0; |
| 3202 | 3212 |
| 3203 while (true) { | 3213 while (true) { |
| 3204 String* left = String::cast(current->first()); | 3214 String* left = current->first(); |
| 3205 unsigned left_length = (unsigned)left->length(); | 3215 StringShape left_shape(left); |
| 3216 unsigned left_length = (unsigned)left->length(left_shape); |
| 3206 if (left_length > offset && | 3217 if (left_length > offset && |
| 3207 (max_chars <= left_length - offset || | 3218 (max_chars <= left_length - offset || |
| 3208 (rbb->capacity <= left_length - offset && | 3219 (rbb->capacity <= left_length - offset && |
| 3209 (max_chars = left_length - offset, true)))) { // comma operator! | 3220 (max_chars = left_length - offset, true)))) { // comma operator! |
| 3210 // Left hand side only - iterate unless we have reached the bottom of | 3221 // Left hand side only - iterate unless we have reached the bottom of |
| 3211 // the cons tree. The assignment on the left of the comma operator is | 3222 // the cons tree. The assignment on the left of the comma operator is |
| 3212 // in order to make use of the fact that the -IntoBuffer routines can | 3223 // in order to make use of the fact that the -IntoBuffer routines can |
| 3213 // produce at most 'capacity' characters. This enables us to postpone | 3224 // produce at most 'capacity' characters. This enables us to postpone |
| 3214 // the point where we switch to the -IntoBuffer routines (below) in order | 3225 // the point where we switch to the -IntoBuffer routines (below) in order |
| 3215 // to maximize the chances of delegating a big chunk of work to the | 3226 // to maximize the chances of delegating a big chunk of work to the |
| 3216 // efficient *AsciiStringReadBlock routines. | 3227 // efficient *AsciiStringReadBlock routines. |
| 3217 if (left->StringIsConsString()) { | 3228 if (left_shape.IsCons()) { |
| 3218 current = ConsString::cast(left); | 3229 current = ConsString::cast(left); |
| 3219 continue; | 3230 continue; |
| 3220 } else { | 3231 } else { |
| 3221 const unibrow::byte* answer = | 3232 const unibrow::byte* answer = |
| 3222 String::ReadBlock(left, rbb, &offset, max_chars); | 3233 String::ReadBlock(left, rbb, &offset, max_chars); |
| 3223 *offset_ptr = offset + offset_correction; | 3234 *offset_ptr = offset + offset_correction; |
| 3224 return answer; | 3235 return answer; |
| 3225 } | 3236 } |
| 3226 } else if (left_length <= offset) { | 3237 } else if (left_length <= offset) { |
| 3227 // Right hand side only - iterate unless we have reached the bottom of | 3238 // Right hand side only - iterate unless we have reached the bottom of |
| 3228 // the cons tree. | 3239 // the cons tree. |
| 3229 String* right = String::cast(current->second()); | 3240 String* right = current->second(); |
| 3230 offset -= left_length; | 3241 offset -= left_length; |
| 3231 offset_correction += left_length; | 3242 offset_correction += left_length; |
| 3232 if (right->StringIsConsString()) { | 3243 if (StringShape(right).IsCons()) { |
| 3233 current = ConsString::cast(right); | 3244 current = ConsString::cast(right); |
| 3234 continue; | 3245 continue; |
| 3235 } else { | 3246 } else { |
| 3236 const unibrow::byte* answer = | 3247 const unibrow::byte* answer = |
| 3237 String::ReadBlock(right, rbb, &offset, max_chars); | 3248 String::ReadBlock(right, rbb, &offset, max_chars); |
| 3238 *offset_ptr = offset + offset_correction; | 3249 *offset_ptr = offset + offset_correction; |
| 3239 return answer; | 3250 return answer; |
| 3240 } | 3251 } |
| 3241 } else { | 3252 } else { |
| 3242 // The block to be read spans two sides of the ConsString, so we call the | 3253 // The block to be read spans two sides of the ConsString, so we call the |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3254 *offset_ptr = offset + offset_correction; | 3265 *offset_ptr = offset + offset_correction; |
| 3255 return rbb->util_buffer; | 3266 return rbb->util_buffer; |
| 3256 } | 3267 } |
| 3257 } | 3268 } |
| 3258 } | 3269 } |
| 3259 | 3270 |
| 3260 | 3271 |
| 3261 const unibrow::byte* SlicedString::SlicedStringReadBlock(ReadBlockBuffer* rbb, | 3272 const unibrow::byte* SlicedString::SlicedStringReadBlock(ReadBlockBuffer* rbb, |
| 3262 unsigned* offset_ptr, | 3273 unsigned* offset_ptr, |
| 3263 unsigned max_chars) { | 3274 unsigned max_chars) { |
| 3264 String* backing = String::cast(buffer()); | 3275 String* backing = buffer(); |
| 3265 unsigned offset = start() + *offset_ptr; | 3276 unsigned offset = start() + *offset_ptr; |
| 3266 unsigned length = backing->length(); | 3277 unsigned length = backing->length(); |
| 3267 if (max_chars > length - offset) { | 3278 if (max_chars > length - offset) { |
| 3268 max_chars = length - offset; | 3279 max_chars = length - offset; |
| 3269 } | 3280 } |
| 3270 const unibrow::byte* answer = | 3281 const unibrow::byte* answer = |
| 3271 String::ReadBlock(backing, rbb, &offset, max_chars); | 3282 String::ReadBlock(backing, rbb, &offset, max_chars); |
| 3272 *offset_ptr = offset - start(); | 3283 *offset_ptr = offset - start(); |
| 3273 return answer; | 3284 return answer; |
| 3274 } | 3285 } |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3372 // (see AsciiStringReadBlock). | 3383 // (see AsciiStringReadBlock). |
| 3373 const unibrow::byte* String::ReadBlock(String* input, | 3384 const unibrow::byte* String::ReadBlock(String* input, |
| 3374 ReadBlockBuffer* rbb, | 3385 ReadBlockBuffer* rbb, |
| 3375 unsigned* offset_ptr, | 3386 unsigned* offset_ptr, |
| 3376 unsigned max_chars) { | 3387 unsigned max_chars) { |
| 3377 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length())); | 3388 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length())); |
| 3378 if (max_chars == 0) { | 3389 if (max_chars == 0) { |
| 3379 rbb->remaining = 0; | 3390 rbb->remaining = 0; |
| 3380 return NULL; | 3391 return NULL; |
| 3381 } | 3392 } |
| 3382 switch (input->representation_tag()) { | 3393 StringShape shape(input); |
| 3394 switch (shape.representation_tag()) { |
| 3383 case kSeqStringTag: | 3395 case kSeqStringTag: |
| 3384 if (input->is_ascii_representation()) { | 3396 if (shape.IsAsciiRepresentation()) { |
| 3385 SeqAsciiString* str = SeqAsciiString::cast(input); | 3397 SeqAsciiString* str = SeqAsciiString::cast(input); |
| 3386 return str->SeqAsciiStringReadBlock(&rbb->remaining, | 3398 return str->SeqAsciiStringReadBlock(&rbb->remaining, |
| 3387 offset_ptr, | 3399 offset_ptr, |
| 3388 max_chars); | 3400 max_chars); |
| 3389 } else { | 3401 } else { |
| 3390 SeqTwoByteString* str = SeqTwoByteString::cast(input); | 3402 SeqTwoByteString* str = SeqTwoByteString::cast(input); |
| 3391 str->SeqTwoByteStringReadBlockIntoBuffer(rbb, | 3403 str->SeqTwoByteStringReadBlockIntoBuffer(rbb, |
| 3392 offset_ptr, | 3404 offset_ptr, |
| 3393 max_chars); | 3405 max_chars); |
| 3394 return rbb->util_buffer; | 3406 return rbb->util_buffer; |
| 3395 } | 3407 } |
| 3396 case kConsStringTag: | 3408 case kConsStringTag: |
| 3397 return ConsString::cast(input)->ConsStringReadBlock(rbb, | 3409 return ConsString::cast(input)->ConsStringReadBlock(rbb, |
| 3398 offset_ptr, | 3410 offset_ptr, |
| 3399 max_chars); | 3411 max_chars); |
| 3400 case kSlicedStringTag: | 3412 case kSlicedStringTag: |
| 3401 return SlicedString::cast(input)->SlicedStringReadBlock(rbb, | 3413 return SlicedString::cast(input)->SlicedStringReadBlock(rbb, |
| 3402 offset_ptr, | 3414 offset_ptr, |
| 3403 max_chars); | 3415 max_chars); |
| 3404 case kExternalStringTag: | 3416 case kExternalStringTag: |
| 3405 if (input->is_ascii_representation()) { | 3417 if (shape.IsAsciiRepresentation()) { |
| 3406 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock( | 3418 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock( |
| 3407 &rbb->remaining, | 3419 &rbb->remaining, |
| 3408 offset_ptr, | 3420 offset_ptr, |
| 3409 max_chars); | 3421 max_chars); |
| 3410 } else { | 3422 } else { |
| 3411 ExternalTwoByteString::cast(input)-> | 3423 ExternalTwoByteString::cast(input)-> |
| 3412 ExternalTwoByteStringReadBlockIntoBuffer(rbb, | 3424 ExternalTwoByteStringReadBlockIntoBuffer(rbb, |
| 3413 offset_ptr, | 3425 offset_ptr, |
| 3414 max_chars); | 3426 max_chars); |
| 3415 return rbb->util_buffer; | 3427 return rbb->util_buffer; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 3434 | 3446 |
| 3435 | 3447 |
| 3436 // This method determines the type of string involved and then copies | 3448 // This method determines the type of string involved and then copies |
| 3437 // a whole chunk of characters into a buffer. It can be used with strings | 3449 // a whole chunk of characters into a buffer. It can be used with strings |
| 3438 // that have been glued together to form a ConsString and which must cooperate | 3450 // that have been glued together to form a ConsString and which must cooperate |
| 3439 // to fill up a buffer. | 3451 // to fill up a buffer. |
| 3440 void String::ReadBlockIntoBuffer(String* input, | 3452 void String::ReadBlockIntoBuffer(String* input, |
| 3441 ReadBlockBuffer* rbb, | 3453 ReadBlockBuffer* rbb, |
| 3442 unsigned* offset_ptr, | 3454 unsigned* offset_ptr, |
| 3443 unsigned max_chars) { | 3455 unsigned max_chars) { |
| 3444 ASSERT(*offset_ptr <= (unsigned)input->length()); | 3456 StringShape shape(input); |
| 3457 ASSERT(*offset_ptr <= (unsigned)input->length(shape)); |
| 3445 if (max_chars == 0) return; | 3458 if (max_chars == 0) return; |
| 3446 | 3459 |
| 3447 switch (input->representation_tag()) { | 3460 switch (shape.representation_tag()) { |
| 3448 case kSeqStringTag: | 3461 case kSeqStringTag: |
| 3449 if (input->is_ascii_representation()) { | 3462 if (shape.IsAsciiRepresentation()) { |
| 3450 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb, | 3463 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb, |
| 3451 offset_ptr, | 3464 offset_ptr, |
| 3452 max_chars); | 3465 max_chars); |
| 3453 return; | 3466 return; |
| 3454 } else { | 3467 } else { |
| 3455 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb, | 3468 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb, |
| 3456 offset_ptr, | 3469 offset_ptr, |
| 3457 max_chars); | 3470 max_chars); |
| 3458 return; | 3471 return; |
| 3459 } | 3472 } |
| 3460 case kConsStringTag: | 3473 case kConsStringTag: |
| 3461 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb, | 3474 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb, |
| 3462 offset_ptr, | 3475 offset_ptr, |
| 3463 max_chars); | 3476 max_chars); |
| 3464 return; | 3477 return; |
| 3465 case kSlicedStringTag: | 3478 case kSlicedStringTag: |
| 3466 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb, | 3479 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb, |
| 3467 offset_ptr, | 3480 offset_ptr, |
| 3468 max_chars); | 3481 max_chars); |
| 3469 return; | 3482 return; |
| 3470 case kExternalStringTag: | 3483 case kExternalStringTag: |
| 3471 if (input->is_ascii_representation()) { | 3484 if (shape.IsAsciiRepresentation()) { |
| 3472 ExternalAsciiString::cast(input)-> | 3485 ExternalAsciiString::cast(input)-> |
| 3473 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); | 3486 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); |
| 3474 } else { | 3487 } else { |
| 3475 ExternalTwoByteString::cast(input)-> | 3488 ExternalTwoByteString::cast(input)-> |
| 3476 ExternalTwoByteStringReadBlockIntoBuffer(rbb, | 3489 ExternalTwoByteStringReadBlockIntoBuffer(rbb, |
| 3477 offset_ptr, | 3490 offset_ptr, |
| 3478 max_chars); | 3491 max_chars); |
| 3479 } | 3492 } |
| 3480 return; | 3493 return; |
| 3481 default: | 3494 default: |
| 3482 break; | 3495 break; |
| 3483 } | 3496 } |
| 3484 | 3497 |
| 3485 UNREACHABLE(); | 3498 UNREACHABLE(); |
| 3486 return; | 3499 return; |
| 3487 } | 3500 } |
| 3488 | 3501 |
| 3489 | 3502 |
| 3490 const unibrow::byte* String::ReadBlock(String* input, | 3503 const unibrow::byte* String::ReadBlock(String* input, |
| 3491 unibrow::byte* util_buffer, | 3504 unibrow::byte* util_buffer, |
| 3492 unsigned capacity, | 3505 unsigned capacity, |
| 3493 unsigned* remaining, | 3506 unsigned* remaining, |
| 3494 unsigned* offset_ptr) { | 3507 unsigned* offset_ptr) { |
| 3495 ASSERT(*offset_ptr <= (unsigned)input->length()); | 3508 StringShape shape(input); |
| 3496 unsigned chars = input->length() - *offset_ptr; | 3509 ASSERT(*offset_ptr <= (unsigned)input->length(shape)); |
| 3510 unsigned chars = input->length(shape) - *offset_ptr; |
| 3497 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); | 3511 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); |
| 3498 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars); | 3512 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars); |
| 3499 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length())); | 3513 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape))); |
| 3500 *remaining = rbb.remaining; | 3514 *remaining = rbb.remaining; |
| 3501 return answer; | 3515 return answer; |
| 3502 } | 3516 } |
| 3503 | 3517 |
| 3504 | 3518 |
| 3505 const unibrow::byte* String::ReadBlock(String** raw_input, | 3519 const unibrow::byte* String::ReadBlock(String** raw_input, |
| 3506 unibrow::byte* util_buffer, | 3520 unibrow::byte* util_buffer, |
| 3507 unsigned capacity, | 3521 unsigned capacity, |
| 3508 unsigned* remaining, | 3522 unsigned* remaining, |
| 3509 unsigned* offset_ptr) { | 3523 unsigned* offset_ptr) { |
| 3524 StringShape shape(*raw_input); |
| 3510 Handle<String> input(raw_input); | 3525 Handle<String> input(raw_input); |
| 3511 ASSERT(*offset_ptr <= (unsigned)input->length()); | 3526 ASSERT(*offset_ptr <= (unsigned)input->length(shape)); |
| 3512 unsigned chars = input->length() - *offset_ptr; | 3527 unsigned chars = input->length(shape) - *offset_ptr; |
| 3513 if (chars > capacity) chars = capacity; | 3528 if (chars > capacity) chars = capacity; |
| 3514 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); | 3529 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); |
| 3515 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars); | 3530 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars); |
| 3516 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length())); | 3531 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape))); |
| 3517 *remaining = rbb.remaining; | 3532 *remaining = rbb.remaining; |
| 3518 return rbb.util_buffer; | 3533 return rbb.util_buffer; |
| 3519 } | 3534 } |
| 3520 | 3535 |
| 3521 | 3536 |
| 3522 // This will iterate unless the block of string data spans two 'halves' of | 3537 // This will iterate unless the block of string data spans two 'halves' of |
| 3523 // a ConsString, in which case it will recurse. Since the block of string | 3538 // a ConsString, in which case it will recurse. Since the block of string |
| 3524 // data to be read has a maximum size this limits the maximum recursion | 3539 // data to be read has a maximum size this limits the maximum recursion |
| 3525 // depth to something sane. Since C++ does not have tail call recursion | 3540 // depth to something sane. Since C++ does not have tail call recursion |
| 3526 // elimination, the iteration must be explicit. | 3541 // elimination, the iteration must be explicit. |
| 3527 void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, | 3542 void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, |
| 3528 unsigned* offset_ptr, | 3543 unsigned* offset_ptr, |
| 3529 unsigned max_chars) { | 3544 unsigned max_chars) { |
| 3530 ConsString* current = this; | 3545 ConsString* current = this; |
| 3531 unsigned offset = *offset_ptr; | 3546 unsigned offset = *offset_ptr; |
| 3532 int offset_correction = 0; | 3547 int offset_correction = 0; |
| 3533 | 3548 |
| 3534 while (true) { | 3549 while (true) { |
| 3535 String* left = String::cast(current->first()); | 3550 String* left = current->first(); |
| 3536 unsigned left_length = (unsigned)left->length(); | 3551 StringShape left_shape(left); |
| 3552 unsigned left_length = (unsigned)left->length(left_shape); |
| 3537 if (left_length > offset && | 3553 if (left_length > offset && |
| 3538 max_chars <= left_length - offset) { | 3554 max_chars <= left_length - offset) { |
| 3539 // Left hand side only - iterate unless we have reached the bottom of | 3555 // Left hand side only - iterate unless we have reached the bottom of |
| 3540 // the cons tree. | 3556 // the cons tree. |
| 3541 if (left->StringIsConsString()) { | 3557 if (left_shape.IsCons()) { |
| 3542 current = ConsString::cast(left); | 3558 current = ConsString::cast(left); |
| 3543 continue; | 3559 continue; |
| 3544 } else { | 3560 } else { |
| 3545 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars); | 3561 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars); |
| 3546 *offset_ptr = offset + offset_correction; | 3562 *offset_ptr = offset + offset_correction; |
| 3547 return; | 3563 return; |
| 3548 } | 3564 } |
| 3549 } else if (left_length <= offset) { | 3565 } else if (left_length <= offset) { |
| 3550 // Right hand side only - iterate unless we have reached the bottom of | 3566 // Right hand side only - iterate unless we have reached the bottom of |
| 3551 // the cons tree. | 3567 // the cons tree. |
| 3552 offset -= left_length; | 3568 offset -= left_length; |
| 3553 offset_correction += left_length; | 3569 offset_correction += left_length; |
| 3554 String* right = String::cast(current->second()); | 3570 String* right = current->second(); |
| 3555 if (right->StringIsConsString()) { | 3571 if (StringShape(right).IsCons()) { |
| 3556 current = ConsString::cast(right); | 3572 current = ConsString::cast(right); |
| 3557 continue; | 3573 continue; |
| 3558 } else { | 3574 } else { |
| 3559 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars); | 3575 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars); |
| 3560 *offset_ptr = offset + offset_correction; | 3576 *offset_ptr = offset + offset_correction; |
| 3561 return; | 3577 return; |
| 3562 } | 3578 } |
| 3563 } else { | 3579 } else { |
| 3564 // The block to be read spans two sides of the ConsString, so we recurse. | 3580 // The block to be read spans two sides of the ConsString, so we recurse. |
| 3565 // First recurse on the left. | 3581 // First recurse on the left. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3577 *offset_ptr = offset + offset_correction; | 3593 *offset_ptr = offset + offset_correction; |
| 3578 return; | 3594 return; |
| 3579 } | 3595 } |
| 3580 } | 3596 } |
| 3581 } | 3597 } |
| 3582 | 3598 |
| 3583 | 3599 |
| 3584 void SlicedString::SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, | 3600 void SlicedString::SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, |
| 3585 unsigned* offset_ptr, | 3601 unsigned* offset_ptr, |
| 3586 unsigned max_chars) { | 3602 unsigned max_chars) { |
| 3587 String* backing = String::cast(buffer()); | 3603 String* backing = buffer(); |
| 3588 unsigned offset = start() + *offset_ptr; | 3604 unsigned offset = start() + *offset_ptr; |
| 3589 unsigned length = backing->length(); | 3605 unsigned length = backing->length(); |
| 3590 if (max_chars > length - offset) { | 3606 if (max_chars > length - offset) { |
| 3591 max_chars = length - offset; | 3607 max_chars = length - offset; |
| 3592 } | 3608 } |
| 3593 String::ReadBlockIntoBuffer(backing, rbb, &offset, max_chars); | 3609 String::ReadBlockIntoBuffer(backing, rbb, &offset, max_chars); |
| 3594 *offset_ptr = offset - start(); | 3610 *offset_ptr = offset - start(); |
| 3595 } | 3611 } |
| 3596 | 3612 |
| 3597 | 3613 |
| 3598 void ConsString::ConsStringIterateBody(ObjectVisitor* v) { | 3614 void ConsString::ConsStringIterateBody(ObjectVisitor* v) { |
| 3599 IteratePointers(v, kFirstOffset, kSecondOffset + kPointerSize); | 3615 IteratePointers(v, kFirstOffset, kSecondOffset + kPointerSize); |
| 3600 } | 3616 } |
| 3601 | 3617 |
| 3602 | 3618 |
| 3603 uint16_t ConsString::ConsStringGet(int index) { | 3619 uint16_t ConsString::ConsStringGet(int index) { |
| 3604 ASSERT(index >= 0 && index < this->length()); | 3620 ASSERT(index >= 0 && index < this->length()); |
| 3605 | 3621 |
| 3606 // Check for a flattened cons string | 3622 // Check for a flattened cons string |
| 3607 if (String::cast(second())->length() == 0) { | 3623 if (second()->length() == 0) { |
| 3608 return String::cast(first())->Get(index); | 3624 String* left = first(); |
| 3625 return left->Get(StringShape(left), index); |
| 3609 } | 3626 } |
| 3610 | 3627 |
| 3611 String* string = String::cast(this); | 3628 String* string = String::cast(this); |
| 3629 StringShape shape(string); |
| 3612 | 3630 |
| 3613 while (true) { | 3631 while (true) { |
| 3614 if (string->StringIsConsString()) { | 3632 if (shape.IsCons()) { |
| 3615 ConsString* cons_string = ConsString::cast(string); | 3633 ConsString* cons_string = ConsString::cast(string); |
| 3616 String* left = String::cast(cons_string->first()); | 3634 String* left = cons_string->first(); |
| 3617 if (left->length() > index) { | 3635 StringShape left_shape(left); |
| 3636 if (left->length(left_shape) > index) { |
| 3618 string = left; | 3637 string = left; |
| 3638 shape = left_shape; |
| 3619 } else { | 3639 } else { |
| 3620 index -= left->length(); | 3640 index -= left->length(left_shape); |
| 3621 string = String::cast(cons_string->second()); | 3641 string = cons_string->second(); |
| 3642 shape = StringShape(string); |
| 3622 } | 3643 } |
| 3623 } else { | 3644 } else { |
| 3624 return string->Get(index); | 3645 return string->Get(shape, index); |
| 3625 } | 3646 } |
| 3626 } | 3647 } |
| 3627 | 3648 |
| 3628 UNREACHABLE(); | 3649 UNREACHABLE(); |
| 3629 return 0; | 3650 return 0; |
| 3630 } | 3651 } |
| 3631 | 3652 |
| 3632 | 3653 |
| 3633 Object* SlicedString::SlicedStringFlatten() { | 3654 Object* SlicedString::SlicedStringFlatten() { |
| 3634 // The SlicedString constructor should ensure that there are no | 3655 // The SlicedString constructor should ensure that there are no |
| 3635 // SlicedStrings that are constructed directly on top of other | 3656 // SlicedStrings that are constructed directly on top of other |
| 3636 // SlicedStrings. | 3657 // SlicedStrings. |
| 3637 String* buf = String::cast(buffer()); | 3658 String* buf = String::cast(buffer()); |
| 3638 ASSERT(!buf->StringIsSlicedString()); | 3659 StringShape buf_shape(buf); |
| 3639 if (buf->StringIsConsString()) { | 3660 ASSERT(!buf_shape.IsSliced()); |
| 3640 Object* ok = buf->Flatten(); | 3661 if (buf_shape.IsCons()) { |
| 3662 Object* ok = buf->Flatten(buf_shape); |
| 3641 if (ok->IsFailure()) return ok; | 3663 if (ok->IsFailure()) return ok; |
| 3642 } | 3664 } |
| 3643 return this; | 3665 return this; |
| 3644 } | 3666 } |
| 3645 | 3667 |
| 3646 | 3668 |
| 3647 template <typename sinkchar> | 3669 template <typename sinkchar> |
| 3648 void String::WriteToFlat(String* src, | 3670 void String::WriteToFlat(String* src, |
| 3671 StringShape src_shape, |
| 3649 sinkchar* sink, | 3672 sinkchar* sink, |
| 3650 int f, | 3673 int f, |
| 3651 int t) { | 3674 int t) { |
| 3652 String* source = src; | 3675 String* source = src; |
| 3676 StringShape shape = src_shape; |
| 3653 int from = f; | 3677 int from = f; |
| 3654 int to = t; | 3678 int to = t; |
| 3655 while (true) { | 3679 while (true) { |
| 3656 ASSERT(0 <= from && from <= to && to <= source->length()); | 3680 ASSERT(0 <= from && from <= to && to <= source->length(shape)); |
| 3657 switch (source->full_representation_tag()) { | 3681 switch (shape.full_representation_tag()) { |
| 3658 case kAsciiStringTag | kExternalStringTag: { | 3682 case kAsciiStringTag | kExternalStringTag: { |
| 3659 CopyChars(sink, | 3683 CopyChars(sink, |
| 3660 ExternalAsciiString::cast(source)->resource()->data() + from, | 3684 ExternalAsciiString::cast(source)->resource()->data() + from, |
| 3661 to - from); | 3685 to - from); |
| 3662 return; | 3686 return; |
| 3663 } | 3687 } |
| 3664 case kTwoByteStringTag | kExternalStringTag: { | 3688 case kTwoByteStringTag | kExternalStringTag: { |
| 3665 const uc16* data = | 3689 const uc16* data = |
| 3666 ExternalTwoByteString::cast(source)->resource()->data(); | 3690 ExternalTwoByteString::cast(source)->resource()->data(); |
| 3667 CopyChars(sink, | 3691 CopyChars(sink, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3681 to - from); | 3705 to - from); |
| 3682 return; | 3706 return; |
| 3683 } | 3707 } |
| 3684 case kAsciiStringTag | kSlicedStringTag: | 3708 case kAsciiStringTag | kSlicedStringTag: |
| 3685 case kTwoByteStringTag | kSlicedStringTag: { | 3709 case kTwoByteStringTag | kSlicedStringTag: { |
| 3686 SlicedString* sliced_string = SlicedString::cast(source); | 3710 SlicedString* sliced_string = SlicedString::cast(source); |
| 3687 int start = sliced_string->start(); | 3711 int start = sliced_string->start(); |
| 3688 from += start; | 3712 from += start; |
| 3689 to += start; | 3713 to += start; |
| 3690 source = String::cast(sliced_string->buffer()); | 3714 source = String::cast(sliced_string->buffer()); |
| 3715 shape = StringShape(source); |
| 3691 break; | 3716 break; |
| 3692 } | 3717 } |
| 3693 case kAsciiStringTag | kConsStringTag: | 3718 case kAsciiStringTag | kConsStringTag: |
| 3694 case kTwoByteStringTag | kConsStringTag: { | 3719 case kTwoByteStringTag | kConsStringTag: { |
| 3695 ConsString* cons_string = ConsString::cast(source); | 3720 ConsString* cons_string = ConsString::cast(source); |
| 3696 String* first = String::cast(cons_string->first()); | 3721 String* first = cons_string->first(); |
| 3697 int boundary = first->length(); | 3722 StringShape first_shape(first); |
| 3723 int boundary = first->length(first_shape); |
| 3698 if (to - boundary >= boundary - from) { | 3724 if (to - boundary >= boundary - from) { |
| 3699 // Right hand side is longer. Recurse over left. | 3725 // Right hand side is longer. Recurse over left. |
| 3700 if (from < boundary) { | 3726 if (from < boundary) { |
| 3701 WriteToFlat(first, sink, from, boundary); | 3727 WriteToFlat(first, first_shape, sink, from, boundary); |
| 3702 sink += boundary - from; | 3728 sink += boundary - from; |
| 3703 from = 0; | 3729 from = 0; |
| 3704 } else { | 3730 } else { |
| 3705 from -= boundary; | 3731 from -= boundary; |
| 3706 } | 3732 } |
| 3707 to -= boundary; | 3733 to -= boundary; |
| 3708 source = String::cast(cons_string->second()); | 3734 source = cons_string->second(); |
| 3735 shape = StringShape(source); |
| 3709 } else { | 3736 } else { |
| 3710 // Left hand side is longer. Recurse over right. | 3737 // Left hand side is longer. Recurse over right. |
| 3711 if (to > boundary) { | 3738 if (to > boundary) { |
| 3712 String* second = String::cast(cons_string->second()); | 3739 String* second = cons_string->second(); |
| 3713 WriteToFlat(second, | 3740 WriteToFlat(second, |
| 3741 StringShape(second), |
| 3714 sink + boundary - from, | 3742 sink + boundary - from, |
| 3715 0, | 3743 0, |
| 3716 to - boundary); | 3744 to - boundary); |
| 3717 to = boundary; | 3745 to = boundary; |
| 3718 } | 3746 } |
| 3719 source = first; | 3747 source = first; |
| 3748 shape = first_shape; |
| 3720 } | 3749 } |
| 3721 break; | 3750 break; |
| 3722 } | 3751 } |
| 3723 } | 3752 } |
| 3724 } | 3753 } |
| 3725 } | 3754 } |
| 3726 | 3755 |
| 3727 | 3756 |
| 3728 void SlicedString::SlicedStringIterateBody(ObjectVisitor* v) { | 3757 void SlicedString::SlicedStringIterateBody(ObjectVisitor* v) { |
| 3729 IteratePointer(v, kBufferOffset); | 3758 IteratePointer(v, kBufferOffset); |
| 3730 } | 3759 } |
| 3731 | 3760 |
| 3732 | 3761 |
| 3733 uint16_t SlicedString::SlicedStringGet(int index) { | 3762 uint16_t SlicedString::SlicedStringGet(int index) { |
| 3734 ASSERT(index >= 0 && index < this->length()); | 3763 ASSERT(index >= 0 && index < this->length()); |
| 3735 // Delegate to the buffer string. | 3764 // Delegate to the buffer string. |
| 3736 return String::cast(buffer())->Get(start() + index); | 3765 String* underlying = buffer(); |
| 3766 return underlying->Get(StringShape(underlying), start() + index); |
| 3737 } | 3767 } |
| 3738 | 3768 |
| 3739 | 3769 |
| 3740 template <typename IteratorA, typename IteratorB> | 3770 template <typename IteratorA, typename IteratorB> |
| 3741 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) { | 3771 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) { |
| 3742 // General slow case check. We know that the ia and ib iterators | 3772 // General slow case check. We know that the ia and ib iterators |
| 3743 // have the same length. | 3773 // have the same length. |
| 3744 while (ia->has_more()) { | 3774 while (ia->has_more()) { |
| 3745 uc32 ca = ia->GetNext(); | 3775 uc32 ca = ia->GetNext(); |
| 3746 uc32 cb = ib->GetNext(); | 3776 uc32 cb = ib->GetNext(); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3790 } | 3820 } |
| 3791 return true; | 3821 return true; |
| 3792 } | 3822 } |
| 3793 | 3823 |
| 3794 | 3824 |
| 3795 static StringInputBuffer string_compare_buffer_b; | 3825 static StringInputBuffer string_compare_buffer_b; |
| 3796 | 3826 |
| 3797 | 3827 |
| 3798 template <typename IteratorA> | 3828 template <typename IteratorA> |
| 3799 static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) { | 3829 static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) { |
| 3800 if (b->IsFlat()) { | 3830 StringShape b_shape(b); |
| 3801 if (b->IsAsciiRepresentation()) { | 3831 if (b->IsFlat(b_shape)) { |
| 3832 if (b_shape.IsAsciiRepresentation()) { |
| 3802 VectorIterator<char> ib(b->ToAsciiVector()); | 3833 VectorIterator<char> ib(b->ToAsciiVector()); |
| 3803 return CompareStringContents(ia, &ib); | 3834 return CompareStringContents(ia, &ib); |
| 3804 } else { | 3835 } else { |
| 3805 VectorIterator<uc16> ib(b->ToUC16Vector()); | 3836 VectorIterator<uc16> ib(b->ToUC16Vector()); |
| 3806 return CompareStringContents(ia, &ib); | 3837 return CompareStringContents(ia, &ib); |
| 3807 } | 3838 } |
| 3808 } else { | 3839 } else { |
| 3809 string_compare_buffer_b.Reset(0, b); | 3840 string_compare_buffer_b.Reset(0, b); |
| 3810 return CompareStringContents(ia, &string_compare_buffer_b); | 3841 return CompareStringContents(ia, &string_compare_buffer_b); |
| 3811 } | 3842 } |
| 3812 } | 3843 } |
| 3813 | 3844 |
| 3814 | 3845 |
| 3815 static StringInputBuffer string_compare_buffer_a; | 3846 static StringInputBuffer string_compare_buffer_a; |
| 3816 | 3847 |
| 3817 | 3848 |
| 3818 bool String::SlowEquals(String* other) { | 3849 bool String::SlowEquals(StringShape this_shape, |
| 3850 String* other, |
| 3851 StringShape other_shape) { |
| 3819 // Fast check: negative check with lengths. | 3852 // Fast check: negative check with lengths. |
| 3820 int len = length(); | 3853 int len = length(this_shape); |
| 3821 if (len != other->length()) return false; | 3854 if (len != other->length(other_shape)) return false; |
| 3822 if (len == 0) return true; | 3855 if (len == 0) return true; |
| 3823 | 3856 |
| 3824 // Fast check: if hash code is computed for both strings | 3857 // Fast check: if hash code is computed for both strings |
| 3825 // a fast negative check can be performed. | 3858 // a fast negative check can be performed. |
| 3826 if (HasHashCode() && other->HasHashCode()) { | 3859 if (HasHashCode() && other->HasHashCode()) { |
| 3827 if (Hash() != other->Hash()) return false; | 3860 if (Hash() != other->Hash()) return false; |
| 3828 } | 3861 } |
| 3829 | 3862 |
| 3830 if (this->IsSeqAsciiString() && other->IsSeqAsciiString()) { | 3863 if (this_shape.IsSequentialAscii() && other_shape.IsSequentialAscii()) { |
| 3831 const char* str1 = SeqAsciiString::cast(this)->GetChars(); | 3864 const char* str1 = SeqAsciiString::cast(this)->GetChars(); |
| 3832 const char* str2 = SeqAsciiString::cast(other)->GetChars(); | 3865 const char* str2 = SeqAsciiString::cast(other)->GetChars(); |
| 3833 return CompareRawStringContents(Vector<const char>(str1, len), | 3866 return CompareRawStringContents(Vector<const char>(str1, len), |
| 3834 Vector<const char>(str2, len)); | 3867 Vector<const char>(str2, len)); |
| 3835 } | 3868 } |
| 3836 | 3869 |
| 3837 if (this->IsFlat()) { | 3870 if (this->IsFlat(this_shape)) { |
| 3838 if (this->IsAsciiRepresentation()) { | 3871 if (this_shape.IsAsciiRepresentation()) { |
| 3839 Vector<const char> vec1 = this->ToAsciiVector(); | 3872 Vector<const char> vec1 = this->ToAsciiVector(); |
| 3840 if (other->IsFlat()) { | 3873 if (other->IsFlat(other_shape)) { |
| 3841 if (other->IsAsciiRepresentation()) { | 3874 if (other_shape.IsAsciiRepresentation()) { |
| 3842 Vector<const char> vec2 = other->ToAsciiVector(); | 3875 Vector<const char> vec2 = other->ToAsciiVector(); |
| 3843 return CompareRawStringContents(vec1, vec2); | 3876 return CompareRawStringContents(vec1, vec2); |
| 3844 } else { | 3877 } else { |
| 3845 VectorIterator<char> buf1(vec1); | 3878 VectorIterator<char> buf1(vec1); |
| 3846 VectorIterator<uc16> ib(other->ToUC16Vector()); | 3879 VectorIterator<uc16> ib(other->ToUC16Vector()); |
| 3847 return CompareStringContents(&buf1, &ib); | 3880 return CompareStringContents(&buf1, &ib); |
| 3848 } | 3881 } |
| 3849 } else { | 3882 } else { |
| 3850 VectorIterator<char> buf1(vec1); | 3883 VectorIterator<char> buf1(vec1); |
| 3851 string_compare_buffer_b.Reset(0, other); | 3884 string_compare_buffer_b.Reset(0, other); |
| 3852 return CompareStringContents(&buf1, &string_compare_buffer_b); | 3885 return CompareStringContents(&buf1, &string_compare_buffer_b); |
| 3853 } | 3886 } |
| 3854 } else { | 3887 } else { |
| 3855 Vector<const uc16> vec1 = this->ToUC16Vector(); | 3888 Vector<const uc16> vec1 = this->ToUC16Vector(); |
| 3856 if (other->IsFlat()) { | 3889 if (other->IsFlat(other_shape)) { |
| 3857 if (other->IsAsciiRepresentation()) { | 3890 if (other_shape.IsAsciiRepresentation()) { |
| 3858 VectorIterator<uc16> buf1(vec1); | 3891 VectorIterator<uc16> buf1(vec1); |
| 3859 VectorIterator<char> ib(other->ToAsciiVector()); | 3892 VectorIterator<char> ib(other->ToAsciiVector()); |
| 3860 return CompareStringContents(&buf1, &ib); | 3893 return CompareStringContents(&buf1, &ib); |
| 3861 } else { | 3894 } else { |
| 3862 Vector<const uc16> vec2(other->ToUC16Vector()); | 3895 Vector<const uc16> vec2(other->ToUC16Vector()); |
| 3863 return CompareRawStringContents(vec1, vec2); | 3896 return CompareRawStringContents(vec1, vec2); |
| 3864 } | 3897 } |
| 3865 } else { | 3898 } else { |
| 3866 VectorIterator<uc16> buf1(vec1); | 3899 VectorIterator<uc16> buf1(vec1); |
| 3867 string_compare_buffer_b.Reset(0, other); | 3900 string_compare_buffer_b.Reset(0, other); |
| 3868 return CompareStringContents(&buf1, &string_compare_buffer_b); | 3901 return CompareStringContents(&buf1, &string_compare_buffer_b); |
| 3869 } | 3902 } |
| 3870 } | 3903 } |
| 3871 } else { | 3904 } else { |
| 3872 string_compare_buffer_a.Reset(0, this); | 3905 string_compare_buffer_a.Reset(0, this); |
| 3873 return CompareStringContentsPartial(&string_compare_buffer_a, other); | 3906 return CompareStringContentsPartial(&string_compare_buffer_a, other); |
| 3874 } | 3907 } |
| 3875 } | 3908 } |
| 3876 | 3909 |
| 3877 | 3910 |
| 3878 bool String::MarkAsUndetectable() { | 3911 bool String::MarkAsUndetectable() { |
| 3879 if (this->IsSymbol()) return false; | 3912 StringShape shape(this); |
| 3913 if (shape.IsSymbol()) return false; |
| 3880 | 3914 |
| 3881 Map* map = this->map(); | 3915 Map* map = this->map(); |
| 3882 if (map == Heap::short_string_map()) { | 3916 if (map == Heap::short_string_map()) { |
| 3883 this->set_map(Heap::undetectable_short_string_map()); | 3917 this->set_map(Heap::undetectable_short_string_map()); |
| 3884 return true; | 3918 return true; |
| 3885 } else if (map == Heap::medium_string_map()) { | 3919 } else if (map == Heap::medium_string_map()) { |
| 3886 this->set_map(Heap::undetectable_medium_string_map()); | 3920 this->set_map(Heap::undetectable_medium_string_map()); |
| 3887 return true; | 3921 return true; |
| 3888 } else if (map == Heap::long_string_map()) { | 3922 } else if (map == Heap::long_string_map()) { |
| 3889 this->set_map(Heap::undetectable_long_string_map()); | 3923 this->set_map(Heap::undetectable_long_string_map()); |
| 3890 return true; | 3924 return true; |
| 3891 } else if (map == Heap::short_ascii_string_map()) { | 3925 } else if (map == Heap::short_ascii_string_map()) { |
| 3892 this->set_map(Heap::undetectable_short_ascii_string_map()); | 3926 this->set_map(Heap::undetectable_short_ascii_string_map()); |
| 3893 return true; | 3927 return true; |
| 3894 } else if (map == Heap::medium_ascii_string_map()) { | 3928 } else if (map == Heap::medium_ascii_string_map()) { |
| 3895 this->set_map(Heap::undetectable_medium_ascii_string_map()); | 3929 this->set_map(Heap::undetectable_medium_ascii_string_map()); |
| 3896 return true; | 3930 return true; |
| 3897 } else if (map == Heap::long_ascii_string_map()) { | 3931 } else if (map == Heap::long_ascii_string_map()) { |
| 3898 this->set_map(Heap::undetectable_long_ascii_string_map()); | 3932 this->set_map(Heap::undetectable_long_ascii_string_map()); |
| 3899 return true; | 3933 return true; |
| 3900 } | 3934 } |
| 3901 // Rest cannot be marked as undetectable | 3935 // Rest cannot be marked as undetectable |
| 3902 return false; | 3936 return false; |
| 3903 } | 3937 } |
| 3904 | 3938 |
| 3905 | 3939 |
| 3906 bool String::IsEqualTo(Vector<const char> str) { | 3940 bool String::IsEqualTo(Vector<const char> str) { |
| 3907 int slen = length(); | 3941 StringShape this_shape(this); |
| 3942 int slen = length(this_shape); |
| 3908 Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder()); | 3943 Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder()); |
| 3909 decoder->Reset(str.start(), str.length()); | 3944 decoder->Reset(str.start(), str.length()); |
| 3910 int i; | 3945 int i; |
| 3911 for (i = 0; i < slen && decoder->has_more(); i++) { | 3946 for (i = 0; i < slen && decoder->has_more(); i++) { |
| 3912 uc32 r = decoder->GetNext(); | 3947 uc32 r = decoder->GetNext(); |
| 3913 if (Get(i) != r) return false; | 3948 if (Get(this_shape, i) != r) return false; |
| 3914 } | 3949 } |
| 3915 return i == slen && !decoder->has_more(); | 3950 return i == slen && !decoder->has_more(); |
| 3916 } | 3951 } |
| 3917 | 3952 |
| 3918 | 3953 |
| 3919 uint32_t String::ComputeAndSetHash() { | 3954 uint32_t String::ComputeAndSetHash() { |
| 3920 // Should only be call if hash code has not yet been computed. | 3955 // Should only be call if hash code has not yet been computed. |
| 3921 ASSERT(!(length_field() & kHashComputedMask)); | 3956 ASSERT(!(length_field() & kHashComputedMask)); |
| 3922 | 3957 |
| 3923 // Compute the hash code. | 3958 // Compute the hash code. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3957 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false; | 3992 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false; |
| 3958 result = (result * 10) + d; | 3993 result = (result * 10) + d; |
| 3959 } | 3994 } |
| 3960 | 3995 |
| 3961 *index = result; | 3996 *index = result; |
| 3962 return true; | 3997 return true; |
| 3963 } | 3998 } |
| 3964 | 3999 |
| 3965 | 4000 |
| 3966 bool String::SlowAsArrayIndex(uint32_t* index) { | 4001 bool String::SlowAsArrayIndex(uint32_t* index) { |
| 3967 if (length() <= kMaxCachedArrayIndexLength) { | 4002 StringShape shape(this); |
| 4003 if (length(shape) <= kMaxCachedArrayIndexLength) { |
| 3968 Hash(); // force computation of hash code | 4004 Hash(); // force computation of hash code |
| 3969 uint32_t field = length_field(); | 4005 uint32_t field = length_field(); |
| 3970 if ((field & kIsArrayIndexMask) == 0) return false; | 4006 if ((field & kIsArrayIndexMask) == 0) return false; |
| 3971 *index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift; | 4007 *index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift; |
| 3972 return true; | 4008 return true; |
| 3973 } else { | 4009 } else { |
| 3974 StringInputBuffer buffer(this); | 4010 StringInputBuffer buffer(this); |
| 3975 return ComputeArrayIndex(&buffer, index, length()); | 4011 return ComputeArrayIndex(&buffer, index, length(shape)); |
| 3976 } | 4012 } |
| 3977 } | 4013 } |
| 3978 | 4014 |
| 3979 | 4015 |
| 3980 static inline uint32_t HashField(uint32_t hash, bool is_array_index) { | 4016 static inline uint32_t HashField(uint32_t hash, bool is_array_index) { |
| 3981 uint32_t result = | 4017 uint32_t result = |
| 3982 (hash << String::kLongLengthShift) | String::kHashComputedMask; | 4018 (hash << String::kLongLengthShift) | String::kHashComputedMask; |
| 3983 if (is_array_index) result |= String::kIsArrayIndexMask; | 4019 if (is_array_index) result |= String::kIsArrayIndexMask; |
| 3984 return result; | 4020 return result; |
| 3985 } | 4021 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4025 // Process the remaining characters without updating the array | 4061 // Process the remaining characters without updating the array |
| 4026 // index. | 4062 // index. |
| 4027 while (buffer->has_more()) { | 4063 while (buffer->has_more()) { |
| 4028 hasher.AddCharacterNoIndex(buffer->GetNext()); | 4064 hasher.AddCharacterNoIndex(buffer->GetNext()); |
| 4029 } | 4065 } |
| 4030 | 4066 |
| 4031 return hasher.GetHashField(); | 4067 return hasher.GetHashField(); |
| 4032 } | 4068 } |
| 4033 | 4069 |
| 4034 | 4070 |
| 4035 Object* String::Slice(int start, int end) { | 4071 Object* String::Slice(StringShape shape, int start, int end) { |
| 4036 if (start == 0 && end == length()) return this; | 4072 if (start == 0 && end == length(shape)) return this; |
| 4037 int representation = representation_tag(); | 4073 if (shape.representation_tag() == kSlicedStringTag) { |
| 4038 if (representation == kSlicedStringTag) { | |
| 4039 // Translate slices of a SlicedString into slices of the | 4074 // Translate slices of a SlicedString into slices of the |
| 4040 // underlying string buffer. | 4075 // underlying string buffer. |
| 4041 SlicedString* str = SlicedString::cast(this); | 4076 SlicedString* str = SlicedString::cast(this); |
| 4042 return Heap::AllocateSlicedString(String::cast(str->buffer()), | 4077 String* buf = str->buffer(); |
| 4078 return Heap::AllocateSlicedString(buf, |
| 4079 StringShape(buf), |
| 4043 str->start() + start, | 4080 str->start() + start, |
| 4044 str->start() + end); | 4081 str->start() + end); |
| 4045 } | 4082 } |
| 4046 Object* answer = Heap::AllocateSlicedString(this, start, end); | 4083 Object* result = Heap::AllocateSlicedString(this, shape, start, end); |
| 4047 if (answer->IsFailure()) { | 4084 if (result->IsFailure()) { |
| 4048 return answer; | 4085 return result; |
| 4049 } | 4086 } |
| 4050 // Due to the way we retry after GC on allocation failure we are not allowed | 4087 // Due to the way we retry after GC on allocation failure we are not allowed |
| 4051 // to fail on allocation after this point. This is the one-allocation rule. | 4088 // to fail on allocation after this point. This is the one-allocation rule. |
| 4052 | 4089 |
| 4053 // Try to flatten a cons string that is under the sliced string. | 4090 // Try to flatten a cons string that is under the sliced string. |
| 4054 // This is to avoid memory leaks and possible stack overflows caused by | 4091 // This is to avoid memory leaks and possible stack overflows caused by |
| 4055 // building 'towers' of sliced strings on cons strings. | 4092 // building 'towers' of sliced strings on cons strings. |
| 4056 // This may fail due to an allocation failure (when a GC is needed), but it | 4093 // This may fail due to an allocation failure (when a GC is needed), but it |
| 4057 // will succeed often enough to avoid the problem. We only have to do this | 4094 // will succeed often enough to avoid the problem. We only have to do this |
| 4058 // if Heap::AllocateSlicedString actually returned a SlicedString. It will | 4095 // if Heap::AllocateSlicedString actually returned a SlicedString. It will |
| 4059 // return flat strings for small slices for efficiency reasons. | 4096 // return flat strings for small slices for efficiency reasons. |
| 4060 if (String::cast(answer)->StringIsSlicedString() && | 4097 String* answer = String::cast(result); |
| 4061 representation == kConsStringTag) { | 4098 StringShape answer_shape(answer); |
| 4062 TryFlatten(); | 4099 if (answer_shape.IsSliced() && |
| 4100 shape.representation_tag() == kConsStringTag) { |
| 4101 TryFlatten(shape); |
| 4063 // If the flatten succeeded we might as well make the sliced string point | 4102 // If the flatten succeeded we might as well make the sliced string point |
| 4064 // to the flat string rather than the cons string. | 4103 // to the flat string rather than the cons string. |
| 4065 if (String::cast(ConsString::cast(this)->second())->length() == 0) { | 4104 String* second = ConsString::cast(this)->second(); |
| 4105 if (second->length(StringShape(second)) == 0) { |
| 4066 SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first()); | 4106 SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first()); |
| 4067 } | 4107 } |
| 4068 } | 4108 } |
| 4069 return answer; | 4109 return answer; |
| 4070 } | 4110 } |
| 4071 | 4111 |
| 4072 | 4112 |
| 4073 void String::PrintOn(FILE* file) { | 4113 void String::PrintOn(FILE* file) { |
| 4074 int length = this->length(); | 4114 StringShape shape(this); |
| 4115 int length = this->length(shape); |
| 4075 for (int i = 0; i < length; i++) { | 4116 for (int i = 0; i < length; i++) { |
| 4076 fprintf(file, "%c", Get(i)); | 4117 fprintf(file, "%c", Get(shape, i)); |
| 4077 } | 4118 } |
| 4078 } | 4119 } |
| 4079 | 4120 |
| 4080 | 4121 |
| 4081 void Map::CreateBackPointers() { | 4122 void Map::CreateBackPointers() { |
| 4082 DescriptorArray* descriptors = instance_descriptors(); | 4123 DescriptorArray* descriptors = instance_descriptors(); |
| 4083 for (DescriptorReader r(descriptors); !r.eos(); r.advance()) { | 4124 for (DescriptorReader r(descriptors); !r.eos(); r.advance()) { |
| 4084 if (r.type() == MAP_TRANSITION) { | 4125 if (r.type() == MAP_TRANSITION) { |
| 4085 // Get target. | 4126 // Get target. |
| 4086 Map* target = Map::cast(r.GetValue()); | 4127 Map* target = Map::cast(r.GetValue()); |
| (...skipping 1464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5551 if (storage) { | 5592 if (storage) { |
| 5552 element_dictionary()->CopyKeysTo(storage, filter); | 5593 element_dictionary()->CopyKeysTo(storage, filter); |
| 5553 } | 5594 } |
| 5554 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); | 5595 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); |
| 5555 } | 5596 } |
| 5556 | 5597 |
| 5557 if (this->IsJSValue()) { | 5598 if (this->IsJSValue()) { |
| 5558 Object* val = JSValue::cast(this)->value(); | 5599 Object* val = JSValue::cast(this)->value(); |
| 5559 if (val->IsString()) { | 5600 if (val->IsString()) { |
| 5560 String* str = String::cast(val); | 5601 String* str = String::cast(val); |
| 5602 StringShape shape(str); |
| 5561 if (storage) { | 5603 if (storage) { |
| 5562 for (int i = 0; i < str->length(); i++) { | 5604 for (int i = 0; i < str->length(shape); i++) { |
| 5563 storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER); | 5605 storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER); |
| 5564 } | 5606 } |
| 5565 } | 5607 } |
| 5566 counter += str->length(); | 5608 counter += str->length(shape); |
| 5567 } | 5609 } |
| 5568 } | 5610 } |
| 5569 ASSERT(!storage || storage->length() == counter); | 5611 ASSERT(!storage || storage->length() == counter); |
| 5570 return counter; | 5612 return counter; |
| 5571 } | 5613 } |
| 5572 | 5614 |
| 5573 | 5615 |
| 5574 int JSObject::GetEnumElementKeys(FixedArray* storage) { | 5616 int JSObject::GetEnumElementKeys(FixedArray* storage) { |
| 5575 return GetLocalElementKeys(storage, | 5617 return GetLocalElementKeys(storage, |
| 5576 static_cast<PropertyAttributes>(DONT_ENUM)); | 5618 static_cast<PropertyAttributes>(DONT_ENUM)); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5741 | 5783 |
| 5742 bool IsMatch(Object* string) { | 5784 bool IsMatch(Object* string) { |
| 5743 return String::cast(string)->Equals(string_); | 5785 return String::cast(string)->Equals(string_); |
| 5744 } | 5786 } |
| 5745 | 5787 |
| 5746 uint32_t Hash() { return string_->Hash(); } | 5788 uint32_t Hash() { return string_->Hash(); } |
| 5747 | 5789 |
| 5748 Object* GetObject() { | 5790 Object* GetObject() { |
| 5749 // If the string is a cons string, attempt to flatten it so that | 5791 // If the string is a cons string, attempt to flatten it so that |
| 5750 // symbols will most often be flat strings. | 5792 // symbols will most often be flat strings. |
| 5751 if (string_->IsConsString()) { | 5793 StringShape shape(string_); |
| 5794 if (shape.IsCons()) { |
| 5752 ConsString* cons_string = ConsString::cast(string_); | 5795 ConsString* cons_string = ConsString::cast(string_); |
| 5753 cons_string->TryFlatten(); | 5796 cons_string->TryFlatten(shape); |
| 5754 if (cons_string->second() == Heap::empty_string()) { | 5797 if (cons_string->second() == Heap::empty_string()) { |
| 5755 string_ = String::cast(cons_string->first()); | 5798 string_ = cons_string->first(); |
| 5756 } | 5799 } |
| 5757 } | 5800 } |
| 5758 // Transform string to symbol if possible. | 5801 // Transform string to symbol if possible. |
| 5759 Map* map = Heap::SymbolMapForString(string_); | 5802 Map* map = Heap::SymbolMapForString(string_); |
| 5760 if (map != NULL) { | 5803 if (map != NULL) { |
| 5761 string_->set_map(map); | 5804 string_->set_map(map); |
| 5762 return string_; | 5805 return string_; |
| 5763 } | 5806 } |
| 5764 // Otherwise allocate a new symbol. | 5807 // Otherwise allocate a new symbol. |
| 5765 StringInputBuffer buffer(string_); | 5808 StringInputBuffer buffer(string_); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5903 } | 5946 } |
| 5904 | 5947 |
| 5905 | 5948 |
| 5906 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { | 5949 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { |
| 5907 SymbolKey key(string); | 5950 SymbolKey key(string); |
| 5908 int entry = FindEntry(&key); | 5951 int entry = FindEntry(&key); |
| 5909 if (entry == -1) { | 5952 if (entry == -1) { |
| 5910 return false; | 5953 return false; |
| 5911 } else { | 5954 } else { |
| 5912 String* result = String::cast(KeyAt(entry)); | 5955 String* result = String::cast(KeyAt(entry)); |
| 5913 ASSERT(result->is_symbol()); | 5956 ASSERT(StringShape(result).IsSymbol()); |
| 5914 *symbol = result; | 5957 *symbol = result; |
| 5915 return true; | 5958 return true; |
| 5916 } | 5959 } |
| 5917 } | 5960 } |
| 5918 | 5961 |
| 5919 | 5962 |
| 5920 Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) { | 5963 Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) { |
| 5921 Utf8SymbolKey key(str); | 5964 Utf8SymbolKey key(str); |
| 5922 return LookupKey(&key, s); | 5965 return LookupKey(&key, s); |
| 5923 } | 5966 } |
| (...skipping 887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6811 // No break point. | 6854 // No break point. |
| 6812 if (break_point_objects()->IsUndefined()) return 0; | 6855 if (break_point_objects()->IsUndefined()) return 0; |
| 6813 // Single beak point. | 6856 // Single beak point. |
| 6814 if (!break_point_objects()->IsFixedArray()) return 1; | 6857 if (!break_point_objects()->IsFixedArray()) return 1; |
| 6815 // Multiple break points. | 6858 // Multiple break points. |
| 6816 return FixedArray::cast(break_point_objects())->length(); | 6859 return FixedArray::cast(break_point_objects())->length(); |
| 6817 } | 6860 } |
| 6818 | 6861 |
| 6819 | 6862 |
| 6820 } } // namespace v8::internal | 6863 } } // namespace v8::internal |
| OLD | NEW |