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 1471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2272 AssertNoContextChange ncc; | 2281 AssertNoContextChange ncc; |
2273 | 2282 |
2274 // Check access rights if needed. | 2283 // Check access rights if needed. |
2275 if (IsAccessCheckNeeded() && | 2284 if (IsAccessCheckNeeded() && |
2276 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { | 2285 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { |
2277 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); | 2286 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); |
2278 return Heap::undefined_value(); | 2287 return Heap::undefined_value(); |
2279 } | 2288 } |
2280 | 2289 |
2281 // TryFlatten before operating on the string. | 2290 // TryFlatten before operating on the string. |
2282 name->TryFlatten(); | 2291 name->TryFlatten(StringShape(name)); |
2283 | 2292 |
2284 // Make sure name is not an index. | 2293 // Make sure name is not an index. |
2285 uint32_t index; | 2294 uint32_t index; |
2286 if (name->AsArrayIndex(&index)) return Heap::undefined_value(); | 2295 if (name->AsArrayIndex(&index)) return Heap::undefined_value(); |
2287 | 2296 |
2288 // Lookup the name. | 2297 // Lookup the name. |
2289 LookupResult result; | 2298 LookupResult result; |
2290 LocalLookup(name, &result); | 2299 LocalLookup(name, &result); |
2291 if (result.IsValid()) { | 2300 if (result.IsValid()) { |
2292 if (result.IsReadOnly()) return Heap::undefined_value(); | 2301 if (result.IsReadOnly()) return Heap::undefined_value(); |
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2895 } | 2904 } |
2896 return GetContentArray()->IsEqualTo(other->GetContentArray()); | 2905 return GetContentArray()->IsEqualTo(other->GetContentArray()); |
2897 } | 2906 } |
2898 #endif | 2907 #endif |
2899 | 2908 |
2900 | 2909 |
2901 static StaticResource<StringInputBuffer> string_input_buffer; | 2910 static StaticResource<StringInputBuffer> string_input_buffer; |
2902 | 2911 |
2903 | 2912 |
2904 bool String::LooksValid() { | 2913 bool String::LooksValid() { |
2905 if (!Heap::Contains(this)) | 2914 if (!Heap::Contains(this)) return false; |
2906 return false; | 2915 return true; |
Mads Ager (chromium)
2008/11/03 08:45:49
Doesn't it make sense to check that the representa
Erik Corry
2008/11/03 09:33:54
It makes no sense because all bit combinations are
| |
2907 switch (representation_tag()) { | |
2908 case kSeqStringTag: | |
2909 case kConsStringTag: | |
2910 case kSlicedStringTag: | |
2911 case kExternalStringTag: | |
2912 return true; | |
2913 default: | |
2914 return false; | |
2915 } | |
2916 } | 2916 } |
2917 | 2917 |
2918 | 2918 |
2919 int String::Utf8Length() { | 2919 int String::Utf8Length() { |
2920 if (is_ascii_representation()) return length(); | 2920 StringShape shape(this); |
2921 if (shape.IsAsciiRepresentation()) return length(shape); | |
2921 // Attempt to flatten before accessing the string. It probably | 2922 // Attempt to flatten before accessing the string. It probably |
2922 // doesn't make Utf8Length faster, but it is very likely that | 2923 // doesn't make Utf8Length faster, but it is very likely that |
2923 // the string will be accessed later (for example by WriteUtf8) | 2924 // the string will be accessed later (for example by WriteUtf8) |
2924 // so it's still a good idea. | 2925 // so it's still a good idea. |
2925 TryFlatten(); | 2926 if (!IsFlat(shape)) { |
2927 TryFlatten(shape); // shape is now no longer valid. | |
2928 } | |
2926 Access<StringInputBuffer> buffer(&string_input_buffer); | 2929 Access<StringInputBuffer> buffer(&string_input_buffer); |
2927 buffer->Reset(0, this); | 2930 buffer->Reset(0, this); |
2928 int result = 0; | 2931 int result = 0; |
2929 while (buffer->has_more()) | 2932 while (buffer->has_more()) |
2930 result += unibrow::Utf8::Length(buffer->GetNext()); | 2933 result += unibrow::Utf8::Length(buffer->GetNext()); |
2931 return result; | 2934 return result; |
2932 } | 2935 } |
2933 | 2936 |
2934 | 2937 |
2935 Vector<const char> String::ToAsciiVector() { | 2938 Vector<const char> String::ToAsciiVector() { |
2936 ASSERT(IsAsciiRepresentation()); | 2939 StringShape shape(this); |
2937 ASSERT(IsFlat()); | 2940 ASSERT(shape.IsAsciiRepresentation()); |
2941 ASSERT(IsFlat(shape)); | |
2938 | 2942 |
2939 int offset = 0; | 2943 int offset = 0; |
2940 int length = this->length(); | 2944 int length = this->length(shape); |
2941 StringRepresentationTag string_tag = representation_tag(); | 2945 StringRepresentationTag string_tag = shape.representation_tag(); |
2942 String* string = this; | 2946 String* string = this; |
2943 if (string_tag == kSlicedStringTag) { | 2947 if (string_tag == kSlicedStringTag) { |
2944 SlicedString* sliced = SlicedString::cast(string); | 2948 SlicedString* sliced = SlicedString::cast(string); |
2945 offset += sliced->start(); | 2949 offset += sliced->start(); |
2946 string = String::cast(sliced->buffer()); | 2950 string = sliced->buffer(); |
2947 string_tag = string->representation_tag(); | 2951 shape = StringShape(string); |
2952 string_tag = shape.representation_tag(); | |
2948 } else if (string_tag == kConsStringTag) { | 2953 } else if (string_tag == kConsStringTag) { |
2949 ConsString* cons = ConsString::cast(string); | 2954 ConsString* cons = ConsString::cast(string); |
2950 ASSERT(String::cast(cons->second())->length() == 0); | 2955 ASSERT(cons->second()->length(StringShape(cons->second())) == 0); |
2951 string = String::cast(cons->first()); | 2956 string = cons->first(); |
2952 string_tag = string->representation_tag(); | 2957 shape = StringShape(string); |
2958 string_tag = shape.representation_tag(); | |
2953 } | 2959 } |
2954 if (string_tag == kSeqStringTag) { | 2960 if (string_tag == kSeqStringTag) { |
2955 SeqAsciiString* seq = SeqAsciiString::cast(string); | 2961 SeqAsciiString* seq = SeqAsciiString::cast(string); |
2956 char* start = seq->GetChars(); | 2962 char* start = seq->GetChars(); |
2957 return Vector<const char>(start + offset, length); | 2963 return Vector<const char>(start + offset, length); |
2958 } | 2964 } |
2959 ASSERT(string_tag == kExternalStringTag); | 2965 ASSERT(string_tag == kExternalStringTag); |
2960 ExternalAsciiString* ext = ExternalAsciiString::cast(string); | 2966 ExternalAsciiString* ext = ExternalAsciiString::cast(string); |
2961 const char* start = ext->resource()->data(); | 2967 const char* start = ext->resource()->data(); |
2962 return Vector<const char>(start + offset, length); | 2968 return Vector<const char>(start + offset, length); |
2963 } | 2969 } |
2964 | 2970 |
2965 | 2971 |
2966 Vector<const uc16> String::ToUC16Vector() { | 2972 Vector<const uc16> String::ToUC16Vector() { |
2967 ASSERT(IsTwoByteStringRepresentation()); | 2973 StringShape shape(this); |
2968 ASSERT(IsFlat()); | 2974 ASSERT(shape.IsTwoByteRepresentation()); |
2975 ASSERT(IsFlat(shape)); | |
2969 | 2976 |
2970 int offset = 0; | 2977 int offset = 0; |
2971 int length = this->length(); | 2978 int length = this->length(shape); |
2972 StringRepresentationTag string_tag = representation_tag(); | 2979 StringRepresentationTag string_tag = shape.representation_tag(); |
2973 String* string = this; | 2980 String* string = this; |
2974 if (string_tag == kSlicedStringTag) { | 2981 if (string_tag == kSlicedStringTag) { |
2975 SlicedString* sliced = SlicedString::cast(string); | 2982 SlicedString* sliced = SlicedString::cast(string); |
2976 offset += sliced->start(); | 2983 offset += sliced->start(); |
2977 string = String::cast(sliced->buffer()); | 2984 string = String::cast(sliced->buffer()); |
2978 string_tag = string->representation_tag(); | 2985 shape = StringShape(string); |
2986 string_tag = shape.representation_tag(); | |
2979 } else if (string_tag == kConsStringTag) { | 2987 } else if (string_tag == kConsStringTag) { |
2980 ConsString* cons = ConsString::cast(string); | 2988 ConsString* cons = ConsString::cast(string); |
2981 ASSERT(String::cast(cons->second())->length() == 0); | 2989 ASSERT(cons->second()->length(StringShape(cons->second())) == 0); |
2982 string = String::cast(cons->first()); | 2990 string = cons->first(); |
2983 string_tag = string->representation_tag(); | 2991 shape = StringShape(string); |
2992 string_tag = shape.representation_tag(); | |
2984 } | 2993 } |
2985 if (string_tag == kSeqStringTag) { | 2994 if (string_tag == kSeqStringTag) { |
2986 SeqTwoByteString* seq = SeqTwoByteString::cast(string); | 2995 SeqTwoByteString* seq = SeqTwoByteString::cast(string); |
2987 return Vector<const uc16>(seq->GetChars() + offset, length); | 2996 return Vector<const uc16>(seq->GetChars() + offset, length); |
2988 } | 2997 } |
2989 ASSERT(string_tag == kExternalStringTag); | 2998 ASSERT(string_tag == kExternalStringTag); |
2990 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string); | 2999 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string); |
2991 const uc16* start = | 3000 const uc16* start = |
2992 reinterpret_cast<const uc16*>(ext->resource()->data()); | 3001 reinterpret_cast<const uc16*>(ext->resource()->data()); |
2993 return Vector<const uc16>(start + offset, length); | 3002 return Vector<const uc16>(start + offset, length); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3053 return ToCString(allow_nulls, robust_flag, 0, -1, length_return); | 3062 return ToCString(allow_nulls, robust_flag, 0, -1, length_return); |
3054 } | 3063 } |
3055 | 3064 |
3056 | 3065 |
3057 const uc16* String::GetTwoByteData() { | 3066 const uc16* String::GetTwoByteData() { |
3058 return GetTwoByteData(0); | 3067 return GetTwoByteData(0); |
3059 } | 3068 } |
3060 | 3069 |
3061 | 3070 |
3062 const uc16* String::GetTwoByteData(unsigned start) { | 3071 const uc16* String::GetTwoByteData(unsigned start) { |
3063 ASSERT(!IsAsciiRepresentation()); | 3072 StringShape shape(this); |
3064 switch (representation_tag()) { | 3073 ASSERT(!shape.IsAsciiRepresentation()); |
3074 switch (shape.representation_tag()) { | |
3065 case kSeqStringTag: | 3075 case kSeqStringTag: |
3066 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); | 3076 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); |
3067 case kExternalStringTag: | 3077 case kExternalStringTag: |
3068 return ExternalTwoByteString::cast(this)-> | 3078 return ExternalTwoByteString::cast(this)-> |
3069 ExternalTwoByteStringGetData(start); | 3079 ExternalTwoByteStringGetData(start); |
3070 case kSlicedStringTag: { | 3080 case kSlicedStringTag: { |
3071 SlicedString* sliced_string = SlicedString::cast(this); | 3081 SlicedString* sliced_string = SlicedString::cast(this); |
3072 String* buffer = String::cast(sliced_string->buffer()); | 3082 String* buffer = sliced_string->buffer(); |
3073 if (buffer->StringIsConsString()) { | 3083 if (StringShape(buffer).IsCons()) { |
3074 ConsString* cons_string = ConsString::cast(buffer); | 3084 ConsString* cs = ConsString::cast(buffer); |
3075 // Flattened string. | 3085 // Flattened string. |
3076 ASSERT(String::cast(cons_string->second())->length() == 0); | 3086 ASSERT(cs->second()->length(StringShape(cs->second())) == 0); |
3077 buffer = String::cast(cons_string->first()); | 3087 buffer = cs->first(); |
3078 } | 3088 } |
3079 return buffer->GetTwoByteData(start + sliced_string->start()); | 3089 return buffer->GetTwoByteData(start + sliced_string->start()); |
3080 } | 3090 } |
3081 case kConsStringTag: | 3091 case kConsStringTag: |
3082 UNREACHABLE(); | 3092 UNREACHABLE(); |
3083 return NULL; | 3093 return NULL; |
3084 } | 3094 } |
3085 UNREACHABLE(); | 3095 UNREACHABLE(); |
3086 return NULL; | 3096 return NULL; |
3087 } | 3097 } |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3168 // -IntoBuffer method it can delegate to one of the efficient | 3178 // -IntoBuffer method it can delegate to one of the efficient |
3169 // *AsciiStringReadBlock routines. | 3179 // *AsciiStringReadBlock routines. |
3170 const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb, | 3180 const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb, |
3171 unsigned* offset_ptr, | 3181 unsigned* offset_ptr, |
3172 unsigned max_chars) { | 3182 unsigned max_chars) { |
3173 ConsString* current = this; | 3183 ConsString* current = this; |
3174 unsigned offset = *offset_ptr; | 3184 unsigned offset = *offset_ptr; |
3175 int offset_correction = 0; | 3185 int offset_correction = 0; |
3176 | 3186 |
3177 while (true) { | 3187 while (true) { |
3178 String* left = String::cast(current->first()); | 3188 String* left = current->first(); |
3179 unsigned left_length = (unsigned)left->length(); | 3189 StringShape left_shape(left); |
3190 unsigned left_length = (unsigned)left->length(left_shape); | |
3180 if (left_length > offset && | 3191 if (left_length > offset && |
3181 (max_chars <= left_length - offset || | 3192 (max_chars <= left_length - offset || |
3182 (rbb->capacity <= left_length - offset && | 3193 (rbb->capacity <= left_length - offset && |
3183 (max_chars = left_length - offset, true)))) { // comma operator! | 3194 (max_chars = left_length - offset, true)))) { // comma operator! |
3184 // Left hand side only - iterate unless we have reached the bottom of | 3195 // Left hand side only - iterate unless we have reached the bottom of |
3185 // the cons tree. The assignment on the left of the comma operator is | 3196 // the cons tree. The assignment on the left of the comma operator is |
3186 // in order to make use of the fact that the -IntoBuffer routines can | 3197 // in order to make use of the fact that the -IntoBuffer routines can |
3187 // produce at most 'capacity' characters. This enables us to postpone | 3198 // produce at most 'capacity' characters. This enables us to postpone |
3188 // the point where we switch to the -IntoBuffer routines (below) in order | 3199 // the point where we switch to the -IntoBuffer routines (below) in order |
3189 // to maximize the chances of delegating a big chunk of work to the | 3200 // to maximize the chances of delegating a big chunk of work to the |
3190 // efficient *AsciiStringReadBlock routines. | 3201 // efficient *AsciiStringReadBlock routines. |
3191 if (left->StringIsConsString()) { | 3202 if (left_shape.IsCons()) { |
3192 current = ConsString::cast(left); | 3203 current = ConsString::cast(left); |
3193 continue; | 3204 continue; |
3194 } else { | 3205 } else { |
3195 const unibrow::byte* answer = | 3206 const unibrow::byte* answer = |
3196 String::ReadBlock(left, rbb, &offset, max_chars); | 3207 String::ReadBlock(left, rbb, &offset, max_chars); |
3197 *offset_ptr = offset + offset_correction; | 3208 *offset_ptr = offset + offset_correction; |
3198 return answer; | 3209 return answer; |
3199 } | 3210 } |
3200 } else if (left_length <= offset) { | 3211 } else if (left_length <= offset) { |
3201 // Right hand side only - iterate unless we have reached the bottom of | 3212 // Right hand side only - iterate unless we have reached the bottom of |
3202 // the cons tree. | 3213 // the cons tree. |
3203 String* right = String::cast(current->second()); | 3214 String* right = current->second(); |
3204 offset -= left_length; | 3215 offset -= left_length; |
3205 offset_correction += left_length; | 3216 offset_correction += left_length; |
3206 if (right->StringIsConsString()) { | 3217 if (StringShape(right).IsCons()) { |
3207 current = ConsString::cast(right); | 3218 current = ConsString::cast(right); |
3208 continue; | 3219 continue; |
3209 } else { | 3220 } else { |
3210 const unibrow::byte* answer = | 3221 const unibrow::byte* answer = |
3211 String::ReadBlock(right, rbb, &offset, max_chars); | 3222 String::ReadBlock(right, rbb, &offset, max_chars); |
3212 *offset_ptr = offset + offset_correction; | 3223 *offset_ptr = offset + offset_correction; |
3213 return answer; | 3224 return answer; |
3214 } | 3225 } |
3215 } else { | 3226 } else { |
3216 // The block to be read spans two sides of the ConsString, so we call the | 3227 // The block to be read spans two sides of the ConsString, so we call the |
(...skipping 11 matching lines...) Expand all Loading... | |
3228 *offset_ptr = offset + offset_correction; | 3239 *offset_ptr = offset + offset_correction; |
3229 return rbb->util_buffer; | 3240 return rbb->util_buffer; |
3230 } | 3241 } |
3231 } | 3242 } |
3232 } | 3243 } |
3233 | 3244 |
3234 | 3245 |
3235 const unibrow::byte* SlicedString::SlicedStringReadBlock(ReadBlockBuffer* rbb, | 3246 const unibrow::byte* SlicedString::SlicedStringReadBlock(ReadBlockBuffer* rbb, |
3236 unsigned* offset_ptr, | 3247 unsigned* offset_ptr, |
3237 unsigned max_chars) { | 3248 unsigned max_chars) { |
3238 String* backing = String::cast(buffer()); | 3249 String* backing = buffer(); |
3239 unsigned offset = start() + *offset_ptr; | 3250 unsigned offset = start() + *offset_ptr; |
3240 unsigned length = backing->length(); | 3251 unsigned length = backing->length(); |
3241 if (max_chars > length - offset) { | 3252 if (max_chars > length - offset) { |
3242 max_chars = length - offset; | 3253 max_chars = length - offset; |
3243 } | 3254 } |
3244 const unibrow::byte* answer = | 3255 const unibrow::byte* answer = |
3245 String::ReadBlock(backing, rbb, &offset, max_chars); | 3256 String::ReadBlock(backing, rbb, &offset, max_chars); |
3246 *offset_ptr = offset - start(); | 3257 *offset_ptr = offset - start(); |
3247 return answer; | 3258 return answer; |
3248 } | 3259 } |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3346 // (see AsciiStringReadBlock). | 3357 // (see AsciiStringReadBlock). |
3347 const unibrow::byte* String::ReadBlock(String* input, | 3358 const unibrow::byte* String::ReadBlock(String* input, |
3348 ReadBlockBuffer* rbb, | 3359 ReadBlockBuffer* rbb, |
3349 unsigned* offset_ptr, | 3360 unsigned* offset_ptr, |
3350 unsigned max_chars) { | 3361 unsigned max_chars) { |
3351 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length())); | 3362 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length())); |
3352 if (max_chars == 0) { | 3363 if (max_chars == 0) { |
3353 rbb->remaining = 0; | 3364 rbb->remaining = 0; |
3354 return NULL; | 3365 return NULL; |
3355 } | 3366 } |
3356 switch (input->representation_tag()) { | 3367 StringShape shape(input); |
3368 switch (shape.representation_tag()) { | |
3357 case kSeqStringTag: | 3369 case kSeqStringTag: |
3358 if (input->is_ascii_representation()) { | 3370 if (shape.IsAsciiRepresentation()) { |
3359 SeqAsciiString* str = SeqAsciiString::cast(input); | 3371 SeqAsciiString* str = SeqAsciiString::cast(input); |
3360 return str->SeqAsciiStringReadBlock(&rbb->remaining, | 3372 return str->SeqAsciiStringReadBlock(&rbb->remaining, |
3361 offset_ptr, | 3373 offset_ptr, |
3362 max_chars); | 3374 max_chars); |
3363 } else { | 3375 } else { |
3364 SeqTwoByteString* str = SeqTwoByteString::cast(input); | 3376 SeqTwoByteString* str = SeqTwoByteString::cast(input); |
3365 str->SeqTwoByteStringReadBlockIntoBuffer(rbb, | 3377 str->SeqTwoByteStringReadBlockIntoBuffer(rbb, |
3366 offset_ptr, | 3378 offset_ptr, |
3367 max_chars); | 3379 max_chars); |
3368 return rbb->util_buffer; | 3380 return rbb->util_buffer; |
3369 } | 3381 } |
3370 case kConsStringTag: | 3382 case kConsStringTag: |
3371 return ConsString::cast(input)->ConsStringReadBlock(rbb, | 3383 return ConsString::cast(input)->ConsStringReadBlock(rbb, |
3372 offset_ptr, | 3384 offset_ptr, |
3373 max_chars); | 3385 max_chars); |
3374 case kSlicedStringTag: | 3386 case kSlicedStringTag: |
3375 return SlicedString::cast(input)->SlicedStringReadBlock(rbb, | 3387 return SlicedString::cast(input)->SlicedStringReadBlock(rbb, |
3376 offset_ptr, | 3388 offset_ptr, |
3377 max_chars); | 3389 max_chars); |
3378 case kExternalStringTag: | 3390 case kExternalStringTag: |
3379 if (input->is_ascii_representation()) { | 3391 if (shape.IsAsciiRepresentation()) { |
3380 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock( | 3392 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock( |
3381 &rbb->remaining, | 3393 &rbb->remaining, |
3382 offset_ptr, | 3394 offset_ptr, |
3383 max_chars); | 3395 max_chars); |
3384 } else { | 3396 } else { |
3385 ExternalTwoByteString::cast(input)-> | 3397 ExternalTwoByteString::cast(input)-> |
3386 ExternalTwoByteStringReadBlockIntoBuffer(rbb, | 3398 ExternalTwoByteStringReadBlockIntoBuffer(rbb, |
3387 offset_ptr, | 3399 offset_ptr, |
3388 max_chars); | 3400 max_chars); |
3389 return rbb->util_buffer; | 3401 return rbb->util_buffer; |
(...skipping 18 matching lines...) Expand all Loading... | |
3408 | 3420 |
3409 | 3421 |
3410 // This method determines the type of string involved and then copies | 3422 // This method determines the type of string involved and then copies |
3411 // a whole chunk of characters into a buffer. It can be used with strings | 3423 // a whole chunk of characters into a buffer. It can be used with strings |
3412 // that have been glued together to form a ConsString and which must cooperate | 3424 // that have been glued together to form a ConsString and which must cooperate |
3413 // to fill up a buffer. | 3425 // to fill up a buffer. |
3414 void String::ReadBlockIntoBuffer(String* input, | 3426 void String::ReadBlockIntoBuffer(String* input, |
3415 ReadBlockBuffer* rbb, | 3427 ReadBlockBuffer* rbb, |
3416 unsigned* offset_ptr, | 3428 unsigned* offset_ptr, |
3417 unsigned max_chars) { | 3429 unsigned max_chars) { |
3418 ASSERT(*offset_ptr <= (unsigned)input->length()); | 3430 StringShape shape(input); |
3431 ASSERT(*offset_ptr <= (unsigned)input->length(shape)); | |
3419 if (max_chars == 0) return; | 3432 if (max_chars == 0) return; |
3420 | 3433 |
3421 switch (input->representation_tag()) { | 3434 switch (shape.representation_tag()) { |
3422 case kSeqStringTag: | 3435 case kSeqStringTag: |
3423 if (input->is_ascii_representation()) { | 3436 if (shape.IsAsciiRepresentation()) { |
3424 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb, | 3437 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb, |
3425 offset_ptr, | 3438 offset_ptr, |
3426 max_chars); | 3439 max_chars); |
3427 return; | 3440 return; |
3428 } else { | 3441 } else { |
3429 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb, | 3442 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb, |
3430 offset_ptr, | 3443 offset_ptr, |
3431 max_chars); | 3444 max_chars); |
3432 return; | 3445 return; |
3433 } | 3446 } |
3434 case kConsStringTag: | 3447 case kConsStringTag: |
3435 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb, | 3448 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb, |
3436 offset_ptr, | 3449 offset_ptr, |
3437 max_chars); | 3450 max_chars); |
3438 return; | 3451 return; |
3439 case kSlicedStringTag: | 3452 case kSlicedStringTag: |
3440 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb, | 3453 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb, |
3441 offset_ptr, | 3454 offset_ptr, |
3442 max_chars); | 3455 max_chars); |
3443 return; | 3456 return; |
3444 case kExternalStringTag: | 3457 case kExternalStringTag: |
3445 if (input->is_ascii_representation()) { | 3458 if (shape.IsAsciiRepresentation()) { |
3446 ExternalAsciiString::cast(input)-> | 3459 ExternalAsciiString::cast(input)-> |
3447 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); | 3460 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); |
3448 } else { | 3461 } else { |
3449 ExternalTwoByteString::cast(input)-> | 3462 ExternalTwoByteString::cast(input)-> |
3450 ExternalTwoByteStringReadBlockIntoBuffer(rbb, | 3463 ExternalTwoByteStringReadBlockIntoBuffer(rbb, |
3451 offset_ptr, | 3464 offset_ptr, |
3452 max_chars); | 3465 max_chars); |
3453 } | 3466 } |
3454 return; | 3467 return; |
3455 default: | 3468 default: |
3456 break; | 3469 break; |
3457 } | 3470 } |
3458 | 3471 |
3459 UNREACHABLE(); | 3472 UNREACHABLE(); |
3460 return; | 3473 return; |
3461 } | 3474 } |
3462 | 3475 |
3463 | 3476 |
3464 const unibrow::byte* String::ReadBlock(String* input, | 3477 const unibrow::byte* String::ReadBlock(String* input, |
3465 unibrow::byte* util_buffer, | 3478 unibrow::byte* util_buffer, |
3466 unsigned capacity, | 3479 unsigned capacity, |
3467 unsigned* remaining, | 3480 unsigned* remaining, |
3468 unsigned* offset_ptr) { | 3481 unsigned* offset_ptr) { |
3469 ASSERT(*offset_ptr <= (unsigned)input->length()); | 3482 StringShape shape(input); |
3470 unsigned chars = input->length() - *offset_ptr; | 3483 ASSERT(*offset_ptr <= (unsigned)input->length(shape)); |
3484 unsigned chars = input->length(shape) - *offset_ptr; | |
3471 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); | 3485 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); |
3472 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars); | 3486 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars); |
3473 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length())); | 3487 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape))); |
3474 *remaining = rbb.remaining; | 3488 *remaining = rbb.remaining; |
3475 return answer; | 3489 return answer; |
3476 } | 3490 } |
3477 | 3491 |
3478 | 3492 |
3479 const unibrow::byte* String::ReadBlock(String** raw_input, | 3493 const unibrow::byte* String::ReadBlock(String** raw_input, |
3480 unibrow::byte* util_buffer, | 3494 unibrow::byte* util_buffer, |
3481 unsigned capacity, | 3495 unsigned capacity, |
3482 unsigned* remaining, | 3496 unsigned* remaining, |
3483 unsigned* offset_ptr) { | 3497 unsigned* offset_ptr) { |
3498 StringShape shape(*raw_input); | |
3484 Handle<String> input(raw_input); | 3499 Handle<String> input(raw_input); |
3485 ASSERT(*offset_ptr <= (unsigned)input->length()); | 3500 ASSERT(*offset_ptr <= (unsigned)input->length(shape)); |
3486 unsigned chars = input->length() - *offset_ptr; | 3501 unsigned chars = input->length(shape) - *offset_ptr; |
3487 if (chars > capacity) chars = capacity; | 3502 if (chars > capacity) chars = capacity; |
3488 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); | 3503 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); |
3489 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars); | 3504 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars); |
3490 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length())); | 3505 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape))); |
3491 *remaining = rbb.remaining; | 3506 *remaining = rbb.remaining; |
3492 return rbb.util_buffer; | 3507 return rbb.util_buffer; |
3493 } | 3508 } |
3494 | 3509 |
3495 | 3510 |
3496 // This will iterate unless the block of string data spans two 'halves' of | 3511 // This will iterate unless the block of string data spans two 'halves' of |
3497 // a ConsString, in which case it will recurse. Since the block of string | 3512 // a ConsString, in which case it will recurse. Since the block of string |
3498 // data to be read has a maximum size this limits the maximum recursion | 3513 // data to be read has a maximum size this limits the maximum recursion |
3499 // depth to something sane. Since C++ does not have tail call recursion | 3514 // depth to something sane. Since C++ does not have tail call recursion |
3500 // elimination, the iteration must be explicit. | 3515 // elimination, the iteration must be explicit. |
3501 void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, | 3516 void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, |
3502 unsigned* offset_ptr, | 3517 unsigned* offset_ptr, |
3503 unsigned max_chars) { | 3518 unsigned max_chars) { |
3504 ConsString* current = this; | 3519 ConsString* current = this; |
3505 unsigned offset = *offset_ptr; | 3520 unsigned offset = *offset_ptr; |
3506 int offset_correction = 0; | 3521 int offset_correction = 0; |
3507 | 3522 |
3508 while (true) { | 3523 while (true) { |
3509 String* left = String::cast(current->first()); | 3524 String* left = current->first(); |
3510 unsigned left_length = (unsigned)left->length(); | 3525 StringShape left_shape(left); |
3526 unsigned left_length = (unsigned)left->length(left_shape); | |
3511 if (left_length > offset && | 3527 if (left_length > offset && |
3512 max_chars <= left_length - offset) { | 3528 max_chars <= left_length - offset) { |
3513 // Left hand side only - iterate unless we have reached the bottom of | 3529 // Left hand side only - iterate unless we have reached the bottom of |
3514 // the cons tree. | 3530 // the cons tree. |
3515 if (left->StringIsConsString()) { | 3531 if (left_shape.IsCons()) { |
3516 current = ConsString::cast(left); | 3532 current = ConsString::cast(left); |
3517 continue; | 3533 continue; |
3518 } else { | 3534 } else { |
3519 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars); | 3535 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars); |
3520 *offset_ptr = offset + offset_correction; | 3536 *offset_ptr = offset + offset_correction; |
3521 return; | 3537 return; |
3522 } | 3538 } |
3523 } else if (left_length <= offset) { | 3539 } else if (left_length <= offset) { |
3524 // Right hand side only - iterate unless we have reached the bottom of | 3540 // Right hand side only - iterate unless we have reached the bottom of |
3525 // the cons tree. | 3541 // the cons tree. |
3526 offset -= left_length; | 3542 offset -= left_length; |
3527 offset_correction += left_length; | 3543 offset_correction += left_length; |
3528 String* right = String::cast(current->second()); | 3544 String* right = current->second(); |
3529 if (right->StringIsConsString()) { | 3545 if (StringShape(right).IsCons()) { |
3530 current = ConsString::cast(right); | 3546 current = ConsString::cast(right); |
3531 continue; | 3547 continue; |
3532 } else { | 3548 } else { |
3533 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars); | 3549 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars); |
3534 *offset_ptr = offset + offset_correction; | 3550 *offset_ptr = offset + offset_correction; |
3535 return; | 3551 return; |
3536 } | 3552 } |
3537 } else { | 3553 } else { |
3538 // The block to be read spans two sides of the ConsString, so we recurse. | 3554 // The block to be read spans two sides of the ConsString, so we recurse. |
3539 // First recurse on the left. | 3555 // First recurse on the left. |
(...skipping 11 matching lines...) Expand all Loading... | |
3551 *offset_ptr = offset + offset_correction; | 3567 *offset_ptr = offset + offset_correction; |
3552 return; | 3568 return; |
3553 } | 3569 } |
3554 } | 3570 } |
3555 } | 3571 } |
3556 | 3572 |
3557 | 3573 |
3558 void SlicedString::SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, | 3574 void SlicedString::SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, |
3559 unsigned* offset_ptr, | 3575 unsigned* offset_ptr, |
3560 unsigned max_chars) { | 3576 unsigned max_chars) { |
3561 String* backing = String::cast(buffer()); | 3577 String* backing = buffer(); |
3562 unsigned offset = start() + *offset_ptr; | 3578 unsigned offset = start() + *offset_ptr; |
3563 unsigned length = backing->length(); | 3579 unsigned length = backing->length(); |
3564 if (max_chars > length - offset) { | 3580 if (max_chars > length - offset) { |
3565 max_chars = length - offset; | 3581 max_chars = length - offset; |
3566 } | 3582 } |
3567 String::ReadBlockIntoBuffer(backing, rbb, &offset, max_chars); | 3583 String::ReadBlockIntoBuffer(backing, rbb, &offset, max_chars); |
3568 *offset_ptr = offset - start(); | 3584 *offset_ptr = offset - start(); |
3569 } | 3585 } |
3570 | 3586 |
3571 | 3587 |
3572 void ConsString::ConsStringIterateBody(ObjectVisitor* v) { | 3588 void ConsString::ConsStringIterateBody(ObjectVisitor* v) { |
3573 IteratePointers(v, kFirstOffset, kSecondOffset + kPointerSize); | 3589 IteratePointers(v, kFirstOffset, kSecondOffset + kPointerSize); |
3574 } | 3590 } |
3575 | 3591 |
3576 | 3592 |
3577 uint16_t ConsString::ConsStringGet(int index) { | 3593 uint16_t ConsString::ConsStringGet(int index) { |
3578 ASSERT(index >= 0 && index < this->length()); | 3594 ASSERT(index >= 0 && index < this->length()); |
3579 | 3595 |
3580 // Check for a flattened cons string | 3596 // Check for a flattened cons string |
3581 if (String::cast(second())->length() == 0) { | 3597 if (second()->length() == 0) { |
3582 return String::cast(first())->Get(index); | 3598 String* left = first(); |
3599 return left->Get(StringShape(left), index); | |
3583 } | 3600 } |
3584 | 3601 |
3585 String* string = String::cast(this); | 3602 String* string = String::cast(this); |
3603 StringShape shape(string); | |
3586 | 3604 |
3587 while (true) { | 3605 while (true) { |
3588 if (string->StringIsConsString()) { | 3606 if (shape.IsCons()) { |
3589 ConsString* cons_string = ConsString::cast(string); | 3607 ConsString* cons_string = ConsString::cast(string); |
3590 String* left = String::cast(cons_string->first()); | 3608 String* left = cons_string->first(); |
3591 if (left->length() > index) { | 3609 StringShape left_shape(left); |
3610 if (left->length(left_shape) > index) { | |
3592 string = left; | 3611 string = left; |
3612 shape = left_shape; | |
3593 } else { | 3613 } else { |
3594 index -= left->length(); | 3614 index -= left->length(left_shape); |
3595 string = String::cast(cons_string->second()); | 3615 string = cons_string->second(); |
3616 shape = StringShape(string); | |
3596 } | 3617 } |
3597 } else { | 3618 } else { |
3598 return string->Get(index); | 3619 return string->Get(shape, index); |
3599 } | 3620 } |
3600 } | 3621 } |
3601 | 3622 |
3602 UNREACHABLE(); | 3623 UNREACHABLE(); |
3603 return 0; | 3624 return 0; |
3604 } | 3625 } |
3605 | 3626 |
3606 | 3627 |
3607 Object* SlicedString::SlicedStringFlatten() { | 3628 Object* SlicedString::SlicedStringFlatten() { |
3608 // The SlicedString constructor should ensure that there are no | 3629 // The SlicedString constructor should ensure that there are no |
3609 // SlicedStrings that are constructed directly on top of other | 3630 // SlicedStrings that are constructed directly on top of other |
3610 // SlicedStrings. | 3631 // SlicedStrings. |
3611 String* buf = String::cast(buffer()); | 3632 String* buf = String::cast(buffer()); |
3612 ASSERT(!buf->StringIsSlicedString()); | 3633 StringShape buf_shape(buf); |
3613 if (buf->StringIsConsString()) { | 3634 ASSERT(!buf_shape.IsSliced()); |
3614 Object* ok = buf->Flatten(); | 3635 if (buf_shape.IsCons()) { |
3636 Object* ok = buf->Flatten(buf_shape); | |
3615 if (ok->IsFailure()) return ok; | 3637 if (ok->IsFailure()) return ok; |
3616 } | 3638 } |
3617 return this; | 3639 return this; |
3618 } | 3640 } |
3619 | 3641 |
3620 | 3642 |
3621 template <typename sinkchar> | 3643 template <typename sinkchar> |
3622 void String::WriteToFlat(String* src, | 3644 void String::WriteToFlat(String* src, |
3645 StringShape src_shape, | |
3623 sinkchar* sink, | 3646 sinkchar* sink, |
3624 int f, | 3647 int f, |
3625 int t) { | 3648 int t) { |
3626 String* source = src; | 3649 String* source = src; |
3650 StringShape shape = src_shape; | |
3627 int from = f; | 3651 int from = f; |
3628 int to = t; | 3652 int to = t; |
3629 while (true) { | 3653 while (true) { |
3630 ASSERT(0 <= from && from <= to && to <= source->length()); | 3654 ASSERT(0 <= from && from <= to && to <= source->length(shape)); |
3631 switch (source->full_representation_tag()) { | 3655 switch (shape.full_representation_tag()) { |
3632 case kAsciiStringTag | kExternalStringTag: { | 3656 case kAsciiStringTag | kExternalStringTag: { |
3633 CopyChars(sink, | 3657 CopyChars(sink, |
3634 ExternalAsciiString::cast(source)->resource()->data() + from, | 3658 ExternalAsciiString::cast(source)->resource()->data() + from, |
3635 to - from); | 3659 to - from); |
3636 return; | 3660 return; |
3637 } | 3661 } |
3638 case kTwoByteStringTag | kExternalStringTag: { | 3662 case kTwoByteStringTag | kExternalStringTag: { |
3639 const uc16* data = | 3663 const uc16* data = |
3640 ExternalTwoByteString::cast(source)->resource()->data(); | 3664 ExternalTwoByteString::cast(source)->resource()->data(); |
3641 CopyChars(sink, | 3665 CopyChars(sink, |
(...skipping 13 matching lines...) Expand all Loading... | |
3655 to - from); | 3679 to - from); |
3656 return; | 3680 return; |
3657 } | 3681 } |
3658 case kAsciiStringTag | kSlicedStringTag: | 3682 case kAsciiStringTag | kSlicedStringTag: |
3659 case kTwoByteStringTag | kSlicedStringTag: { | 3683 case kTwoByteStringTag | kSlicedStringTag: { |
3660 SlicedString* sliced_string = SlicedString::cast(source); | 3684 SlicedString* sliced_string = SlicedString::cast(source); |
3661 int start = sliced_string->start(); | 3685 int start = sliced_string->start(); |
3662 from += start; | 3686 from += start; |
3663 to += start; | 3687 to += start; |
3664 source = String::cast(sliced_string->buffer()); | 3688 source = String::cast(sliced_string->buffer()); |
3689 shape = StringShape(source); | |
3665 break; | 3690 break; |
3666 } | 3691 } |
3667 case kAsciiStringTag | kConsStringTag: | 3692 case kAsciiStringTag | kConsStringTag: |
3668 case kTwoByteStringTag | kConsStringTag: { | 3693 case kTwoByteStringTag | kConsStringTag: { |
3669 ConsString* cons_string = ConsString::cast(source); | 3694 ConsString* cons_string = ConsString::cast(source); |
3670 String* first = String::cast(cons_string->first()); | 3695 String* first = cons_string->first(); |
3671 int boundary = first->length(); | 3696 StringShape first_shape(first); |
3697 int boundary = first->length(first_shape); | |
3672 if (to - boundary >= boundary - from) { | 3698 if (to - boundary >= boundary - from) { |
3673 // Right hand side is longer. Recurse over left. | 3699 // Right hand side is longer. Recurse over left. |
3674 if (from < boundary) { | 3700 if (from < boundary) { |
3675 WriteToFlat(first, sink, from, boundary); | 3701 WriteToFlat(first, first_shape, sink, from, boundary); |
3676 sink += boundary - from; | 3702 sink += boundary - from; |
3677 from = 0; | 3703 from = 0; |
3678 } else { | 3704 } else { |
3679 from -= boundary; | 3705 from -= boundary; |
3680 } | 3706 } |
3681 to -= boundary; | 3707 to -= boundary; |
3682 source = String::cast(cons_string->second()); | 3708 source = cons_string->second(); |
3709 shape = StringShape(source); | |
3683 } else { | 3710 } else { |
3684 // Left hand side is longer. Recurse over right. | 3711 // Left hand side is longer. Recurse over right. |
3685 if (to > boundary) { | 3712 if (to > boundary) { |
3686 String* second = String::cast(cons_string->second()); | 3713 String* second = cons_string->second(); |
3687 WriteToFlat(second, | 3714 WriteToFlat(second, |
3715 StringShape(second), | |
3688 sink + boundary - from, | 3716 sink + boundary - from, |
3689 0, | 3717 0, |
3690 to - boundary); | 3718 to - boundary); |
3691 to = boundary; | 3719 to = boundary; |
3692 } | 3720 } |
3693 source = first; | 3721 source = first; |
3722 shape = first_shape; | |
3694 } | 3723 } |
3695 break; | 3724 break; |
3696 } | 3725 } |
3697 } | 3726 } |
3698 } | 3727 } |
3699 } | 3728 } |
3700 | 3729 |
3701 | 3730 |
3702 void SlicedString::SlicedStringIterateBody(ObjectVisitor* v) { | 3731 void SlicedString::SlicedStringIterateBody(ObjectVisitor* v) { |
3703 IteratePointer(v, kBufferOffset); | 3732 IteratePointer(v, kBufferOffset); |
3704 } | 3733 } |
3705 | 3734 |
3706 | 3735 |
3707 uint16_t SlicedString::SlicedStringGet(int index) { | 3736 uint16_t SlicedString::SlicedStringGet(int index) { |
3708 ASSERT(index >= 0 && index < this->length()); | 3737 ASSERT(index >= 0 && index < this->length()); |
3709 // Delegate to the buffer string. | 3738 // Delegate to the buffer string. |
3710 return String::cast(buffer())->Get(start() + index); | 3739 String* underlying = buffer(); |
3740 return underlying->Get(StringShape(underlying), start() + index); | |
3711 } | 3741 } |
3712 | 3742 |
3713 | 3743 |
3714 template <typename IteratorA, typename IteratorB> | 3744 template <typename IteratorA, typename IteratorB> |
3715 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) { | 3745 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) { |
3716 // General slow case check. We know that the ia and ib iterators | 3746 // General slow case check. We know that the ia and ib iterators |
3717 // have the same length. | 3747 // have the same length. |
3718 while (ia->has_more()) { | 3748 while (ia->has_more()) { |
3719 uc32 ca = ia->GetNext(); | 3749 uc32 ca = ia->GetNext(); |
3720 uc32 cb = ib->GetNext(); | 3750 uc32 cb = ib->GetNext(); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3764 } | 3794 } |
3765 return true; | 3795 return true; |
3766 } | 3796 } |
3767 | 3797 |
3768 | 3798 |
3769 static StringInputBuffer string_compare_buffer_b; | 3799 static StringInputBuffer string_compare_buffer_b; |
3770 | 3800 |
3771 | 3801 |
3772 template <typename IteratorA> | 3802 template <typename IteratorA> |
3773 static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) { | 3803 static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) { |
3774 if (b->IsFlat()) { | 3804 StringShape b_shape(b); |
3775 if (b->IsAsciiRepresentation()) { | 3805 if (b->IsFlat(b_shape)) { |
3806 if (b_shape.IsAsciiRepresentation()) { | |
3776 VectorIterator<char> ib(b->ToAsciiVector()); | 3807 VectorIterator<char> ib(b->ToAsciiVector()); |
3777 return CompareStringContents(ia, &ib); | 3808 return CompareStringContents(ia, &ib); |
3778 } else { | 3809 } else { |
3779 VectorIterator<uc16> ib(b->ToUC16Vector()); | 3810 VectorIterator<uc16> ib(b->ToUC16Vector()); |
3780 return CompareStringContents(ia, &ib); | 3811 return CompareStringContents(ia, &ib); |
3781 } | 3812 } |
3782 } else { | 3813 } else { |
3783 string_compare_buffer_b.Reset(0, b); | 3814 string_compare_buffer_b.Reset(0, b); |
3784 return CompareStringContents(ia, &string_compare_buffer_b); | 3815 return CompareStringContents(ia, &string_compare_buffer_b); |
3785 } | 3816 } |
3786 } | 3817 } |
3787 | 3818 |
3788 | 3819 |
3789 static StringInputBuffer string_compare_buffer_a; | 3820 static StringInputBuffer string_compare_buffer_a; |
3790 | 3821 |
3791 | 3822 |
3792 bool String::SlowEquals(String* other) { | 3823 bool String::SlowEquals(StringShape this_shape, |
3824 String* other, | |
3825 StringShape other_shape) { | |
3793 // Fast check: negative check with lengths. | 3826 // Fast check: negative check with lengths. |
3794 int len = length(); | 3827 int len = length(this_shape); |
3795 if (len != other->length()) return false; | 3828 if (len != other->length(other_shape)) return false; |
3796 if (len == 0) return true; | 3829 if (len == 0) return true; |
3797 | 3830 |
3798 // Fast check: if hash code is computed for both strings | 3831 // Fast check: if hash code is computed for both strings |
3799 // a fast negative check can be performed. | 3832 // a fast negative check can be performed. |
3800 if (HasHashCode() && other->HasHashCode()) { | 3833 if (HasHashCode() && other->HasHashCode()) { |
3801 if (Hash() != other->Hash()) return false; | 3834 if (Hash() != other->Hash()) return false; |
3802 } | 3835 } |
3803 | 3836 |
3804 if (this->IsSeqAsciiString() && other->IsSeqAsciiString()) { | 3837 if (this_shape.IsSequentialAscii() && other_shape.IsSequentialAscii()) { |
3805 const char* str1 = SeqAsciiString::cast(this)->GetChars(); | 3838 const char* str1 = SeqAsciiString::cast(this)->GetChars(); |
3806 const char* str2 = SeqAsciiString::cast(other)->GetChars(); | 3839 const char* str2 = SeqAsciiString::cast(other)->GetChars(); |
3807 return CompareRawStringContents(Vector<const char>(str1, len), | 3840 return CompareRawStringContents(Vector<const char>(str1, len), |
3808 Vector<const char>(str2, len)); | 3841 Vector<const char>(str2, len)); |
3809 } | 3842 } |
3810 | 3843 |
3811 if (this->IsFlat()) { | 3844 if (this->IsFlat(this_shape)) { |
3812 if (this->IsAsciiRepresentation()) { | 3845 if (this_shape.IsAsciiRepresentation()) { |
3813 Vector<const char> vec1 = this->ToAsciiVector(); | 3846 Vector<const char> vec1 = this->ToAsciiVector(); |
3814 if (other->IsFlat()) { | 3847 if (other->IsFlat(other_shape)) { |
3815 if (other->IsAsciiRepresentation()) { | 3848 if (other_shape.IsAsciiRepresentation()) { |
3816 Vector<const char> vec2 = other->ToAsciiVector(); | 3849 Vector<const char> vec2 = other->ToAsciiVector(); |
3817 return CompareRawStringContents(vec1, vec2); | 3850 return CompareRawStringContents(vec1, vec2); |
3818 } else { | 3851 } else { |
3819 VectorIterator<char> buf1(vec1); | 3852 VectorIterator<char> buf1(vec1); |
3820 VectorIterator<uc16> ib(other->ToUC16Vector()); | 3853 VectorIterator<uc16> ib(other->ToUC16Vector()); |
3821 return CompareStringContents(&buf1, &ib); | 3854 return CompareStringContents(&buf1, &ib); |
3822 } | 3855 } |
3823 } else { | 3856 } else { |
3824 VectorIterator<char> buf1(vec1); | 3857 VectorIterator<char> buf1(vec1); |
3825 string_compare_buffer_b.Reset(0, other); | 3858 string_compare_buffer_b.Reset(0, other); |
3826 return CompareStringContents(&buf1, &string_compare_buffer_b); | 3859 return CompareStringContents(&buf1, &string_compare_buffer_b); |
3827 } | 3860 } |
3828 } else { | 3861 } else { |
3829 Vector<const uc16> vec1 = this->ToUC16Vector(); | 3862 Vector<const uc16> vec1 = this->ToUC16Vector(); |
3830 if (other->IsFlat()) { | 3863 if (other->IsFlat(other_shape)) { |
3831 if (other->IsAsciiRepresentation()) { | 3864 if (other_shape.IsAsciiRepresentation()) { |
3832 VectorIterator<uc16> buf1(vec1); | 3865 VectorIterator<uc16> buf1(vec1); |
3833 VectorIterator<char> ib(other->ToAsciiVector()); | 3866 VectorIterator<char> ib(other->ToAsciiVector()); |
3834 return CompareStringContents(&buf1, &ib); | 3867 return CompareStringContents(&buf1, &ib); |
3835 } else { | 3868 } else { |
3836 Vector<const uc16> vec2(other->ToUC16Vector()); | 3869 Vector<const uc16> vec2(other->ToUC16Vector()); |
3837 return CompareRawStringContents(vec1, vec2); | 3870 return CompareRawStringContents(vec1, vec2); |
3838 } | 3871 } |
3839 } else { | 3872 } else { |
3840 VectorIterator<uc16> buf1(vec1); | 3873 VectorIterator<uc16> buf1(vec1); |
3841 string_compare_buffer_b.Reset(0, other); | 3874 string_compare_buffer_b.Reset(0, other); |
3842 return CompareStringContents(&buf1, &string_compare_buffer_b); | 3875 return CompareStringContents(&buf1, &string_compare_buffer_b); |
3843 } | 3876 } |
3844 } | 3877 } |
3845 } else { | 3878 } else { |
3846 string_compare_buffer_a.Reset(0, this); | 3879 string_compare_buffer_a.Reset(0, this); |
3847 return CompareStringContentsPartial(&string_compare_buffer_a, other); | 3880 return CompareStringContentsPartial(&string_compare_buffer_a, other); |
3848 } | 3881 } |
3849 } | 3882 } |
3850 | 3883 |
3851 | 3884 |
3852 bool String::MarkAsUndetectable() { | 3885 bool String::MarkAsUndetectable() { |
3853 if (this->IsSymbol()) return false; | 3886 StringShape shape(this); |
3887 if (shape.IsSymbol()) return false; | |
3854 | 3888 |
3855 Map* map = this->map(); | 3889 Map* map = this->map(); |
3856 if (map == Heap::short_string_map()) { | 3890 if (map == Heap::short_string_map()) { |
3857 this->set_map(Heap::undetectable_short_string_map()); | 3891 this->set_map(Heap::undetectable_short_string_map()); |
3858 return true; | 3892 return true; |
3859 } else if (map == Heap::medium_string_map()) { | 3893 } else if (map == Heap::medium_string_map()) { |
3860 this->set_map(Heap::undetectable_medium_string_map()); | 3894 this->set_map(Heap::undetectable_medium_string_map()); |
3861 return true; | 3895 return true; |
3862 } else if (map == Heap::long_string_map()) { | 3896 } else if (map == Heap::long_string_map()) { |
3863 this->set_map(Heap::undetectable_long_string_map()); | 3897 this->set_map(Heap::undetectable_long_string_map()); |
3864 return true; | 3898 return true; |
3865 } else if (map == Heap::short_ascii_string_map()) { | 3899 } else if (map == Heap::short_ascii_string_map()) { |
3866 this->set_map(Heap::undetectable_short_ascii_string_map()); | 3900 this->set_map(Heap::undetectable_short_ascii_string_map()); |
3867 return true; | 3901 return true; |
3868 } else if (map == Heap::medium_ascii_string_map()) { | 3902 } else if (map == Heap::medium_ascii_string_map()) { |
3869 this->set_map(Heap::undetectable_medium_ascii_string_map()); | 3903 this->set_map(Heap::undetectable_medium_ascii_string_map()); |
3870 return true; | 3904 return true; |
3871 } else if (map == Heap::long_ascii_string_map()) { | 3905 } else if (map == Heap::long_ascii_string_map()) { |
3872 this->set_map(Heap::undetectable_long_ascii_string_map()); | 3906 this->set_map(Heap::undetectable_long_ascii_string_map()); |
3873 return true; | 3907 return true; |
3874 } | 3908 } |
3875 // Rest cannot be marked as undetectable | 3909 // Rest cannot be marked as undetectable |
3876 return false; | 3910 return false; |
3877 } | 3911 } |
3878 | 3912 |
3879 | 3913 |
3880 bool String::IsEqualTo(Vector<const char> str) { | 3914 bool String::IsEqualTo(Vector<const char> str) { |
3881 int slen = length(); | 3915 StringShape this_shape(this); |
3916 int slen = length(this_shape); | |
3882 Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder()); | 3917 Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder()); |
3883 decoder->Reset(str.start(), str.length()); | 3918 decoder->Reset(str.start(), str.length()); |
3884 int i; | 3919 int i; |
3885 for (i = 0; i < slen && decoder->has_more(); i++) { | 3920 for (i = 0; i < slen && decoder->has_more(); i++) { |
3886 uc32 r = decoder->GetNext(); | 3921 uc32 r = decoder->GetNext(); |
3887 if (Get(i) != r) return false; | 3922 if (Get(this_shape, i) != r) return false; |
3888 } | 3923 } |
3889 return i == slen && !decoder->has_more(); | 3924 return i == slen && !decoder->has_more(); |
3890 } | 3925 } |
3891 | 3926 |
3892 | 3927 |
3893 uint32_t String::ComputeAndSetHash() { | 3928 uint32_t String::ComputeAndSetHash() { |
3894 // Should only be call if hash code has not yet been computed. | 3929 // Should only be call if hash code has not yet been computed. |
3895 ASSERT(!(length_field() & kHashComputedMask)); | 3930 ASSERT(!(length_field() & kHashComputedMask)); |
3896 | 3931 |
3897 // Compute the hash code. | 3932 // Compute the hash code. |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3931 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false; | 3966 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false; |
3932 result = (result * 10) + d; | 3967 result = (result * 10) + d; |
3933 } | 3968 } |
3934 | 3969 |
3935 *index = result; | 3970 *index = result; |
3936 return true; | 3971 return true; |
3937 } | 3972 } |
3938 | 3973 |
3939 | 3974 |
3940 bool String::SlowAsArrayIndex(uint32_t* index) { | 3975 bool String::SlowAsArrayIndex(uint32_t* index) { |
3941 if (length() <= kMaxCachedArrayIndexLength) { | 3976 StringShape shape(this); |
3977 if (length(shape) <= kMaxCachedArrayIndexLength) { | |
3942 Hash(); // force computation of hash code | 3978 Hash(); // force computation of hash code |
3943 uint32_t field = length_field(); | 3979 uint32_t field = length_field(); |
3944 if ((field & kIsArrayIndexMask) == 0) return false; | 3980 if ((field & kIsArrayIndexMask) == 0) return false; |
3945 *index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift; | 3981 *index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift; |
3946 return true; | 3982 return true; |
3947 } else { | 3983 } else { |
3948 StringInputBuffer buffer(this); | 3984 StringInputBuffer buffer(this); |
3949 return ComputeArrayIndex(&buffer, index, length()); | 3985 return ComputeArrayIndex(&buffer, index, length(shape)); |
3950 } | 3986 } |
3951 } | 3987 } |
3952 | 3988 |
3953 | 3989 |
3954 static inline uint32_t HashField(uint32_t hash, bool is_array_index) { | 3990 static inline uint32_t HashField(uint32_t hash, bool is_array_index) { |
3955 uint32_t result = | 3991 uint32_t result = |
3956 (hash << String::kLongLengthShift) | String::kHashComputedMask; | 3992 (hash << String::kLongLengthShift) | String::kHashComputedMask; |
3957 if (is_array_index) result |= String::kIsArrayIndexMask; | 3993 if (is_array_index) result |= String::kIsArrayIndexMask; |
3958 return result; | 3994 return result; |
3959 } | 3995 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3999 // Process the remaining characters without updating the array | 4035 // Process the remaining characters without updating the array |
4000 // index. | 4036 // index. |
4001 while (buffer->has_more()) { | 4037 while (buffer->has_more()) { |
4002 hasher.AddCharacterNoIndex(buffer->GetNext()); | 4038 hasher.AddCharacterNoIndex(buffer->GetNext()); |
4003 } | 4039 } |
4004 | 4040 |
4005 return hasher.GetHashField(); | 4041 return hasher.GetHashField(); |
4006 } | 4042 } |
4007 | 4043 |
4008 | 4044 |
4009 Object* String::Slice(int start, int end) { | 4045 Object* String::Slice(StringShape shape, int start, int end) { |
4010 if (start == 0 && end == length()) return this; | 4046 if (start == 0 && end == length(shape)) return this; |
4011 int representation = representation_tag(); | 4047 if (shape.representation_tag() == kSlicedStringTag) { |
4012 if (representation == kSlicedStringTag) { | |
4013 // Translate slices of a SlicedString into slices of the | 4048 // Translate slices of a SlicedString into slices of the |
4014 // underlying string buffer. | 4049 // underlying string buffer. |
4015 SlicedString* str = SlicedString::cast(this); | 4050 SlicedString* str = SlicedString::cast(this); |
4016 return Heap::AllocateSlicedString(String::cast(str->buffer()), | 4051 String* buf = str->buffer(); |
4052 return Heap::AllocateSlicedString(buf, | |
4053 StringShape(buf), | |
4017 str->start() + start, | 4054 str->start() + start, |
4018 str->start() + end); | 4055 str->start() + end); |
4019 } | 4056 } |
4020 Object* answer = Heap::AllocateSlicedString(this, start, end); | 4057 Object* result = Heap::AllocateSlicedString(this, shape, start, end); |
4021 if (answer->IsFailure()) { | 4058 if (result->IsFailure()) { |
4022 return answer; | 4059 return result; |
4023 } | 4060 } |
4024 // Due to the way we retry after GC on allocation failure we are not allowed | 4061 // Due to the way we retry after GC on allocation failure we are not allowed |
4025 // to fail on allocation after this point. This is the one-allocation rule. | 4062 // to fail on allocation after this point. This is the one-allocation rule. |
4026 | 4063 |
4027 // Try to flatten a cons string that is under the sliced string. | 4064 // Try to flatten a cons string that is under the sliced string. |
4028 // This is to avoid memory leaks and possible stack overflows caused by | 4065 // This is to avoid memory leaks and possible stack overflows caused by |
4029 // building 'towers' of sliced strings on cons strings. | 4066 // building 'towers' of sliced strings on cons strings. |
4030 // This may fail due to an allocation failure (when a GC is needed), but it | 4067 // This may fail due to an allocation failure (when a GC is needed), but it |
4031 // will succeed often enough to avoid the problem. We only have to do this | 4068 // will succeed often enough to avoid the problem. We only have to do this |
4032 // if Heap::AllocateSlicedString actually returned a SlicedString. It will | 4069 // if Heap::AllocateSlicedString actually returned a SlicedString. It will |
4033 // return flat strings for small slices for efficiency reasons. | 4070 // return flat strings for small slices for efficiency reasons. |
4034 if (String::cast(answer)->StringIsSlicedString() && | 4071 String* answer = String::cast(result); |
4035 representation == kConsStringTag) { | 4072 StringShape answer_shape(answer); |
4036 TryFlatten(); | 4073 if (answer_shape.IsSliced() && |
4074 shape.representation_tag() == kConsStringTag) { | |
4075 TryFlatten(shape); | |
4037 // If the flatten succeeded we might as well make the sliced string point | 4076 // If the flatten succeeded we might as well make the sliced string point |
4038 // to the flat string rather than the cons string. | 4077 // to the flat string rather than the cons string. |
4039 if (String::cast(ConsString::cast(this)->second())->length() == 0) { | 4078 String* second = ConsString::cast(this)->second(); |
4079 if (second->length(StringShape(second)) == 0) { | |
4040 SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first()); | 4080 SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first()); |
4041 } | 4081 } |
4042 } | 4082 } |
4043 return answer; | 4083 return answer; |
4044 } | 4084 } |
4045 | 4085 |
4046 | 4086 |
4047 void String::PrintOn(FILE* file) { | 4087 void String::PrintOn(FILE* file) { |
4048 int length = this->length(); | 4088 StringShape shape(this); |
4089 int length = this->length(shape); | |
4049 for (int i = 0; i < length; i++) { | 4090 for (int i = 0; i < length; i++) { |
4050 fprintf(file, "%c", Get(i)); | 4091 fprintf(file, "%c", Get(shape, i)); |
4051 } | 4092 } |
4052 } | 4093 } |
4053 | 4094 |
4054 | 4095 |
4055 void Map::CreateBackPointers() { | 4096 void Map::CreateBackPointers() { |
4056 DescriptorArray* descriptors = instance_descriptors(); | 4097 DescriptorArray* descriptors = instance_descriptors(); |
4057 for (DescriptorReader r(descriptors); !r.eos(); r.advance()) { | 4098 for (DescriptorReader r(descriptors); !r.eos(); r.advance()) { |
4058 if (r.type() == MAP_TRANSITION) { | 4099 if (r.type() == MAP_TRANSITION) { |
4059 // Get target. | 4100 // Get target. |
4060 Map* target = Map::cast(r.GetValue()); | 4101 Map* target = Map::cast(r.GetValue()); |
(...skipping 1464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5525 if (storage) { | 5566 if (storage) { |
5526 element_dictionary()->CopyKeysTo(storage, filter); | 5567 element_dictionary()->CopyKeysTo(storage, filter); |
5527 } | 5568 } |
5528 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); | 5569 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); |
5529 } | 5570 } |
5530 | 5571 |
5531 if (this->IsJSValue()) { | 5572 if (this->IsJSValue()) { |
5532 Object* val = JSValue::cast(this)->value(); | 5573 Object* val = JSValue::cast(this)->value(); |
5533 if (val->IsString()) { | 5574 if (val->IsString()) { |
5534 String* str = String::cast(val); | 5575 String* str = String::cast(val); |
5576 StringShape shape(str); | |
5535 if (storage) { | 5577 if (storage) { |
5536 for (int i = 0; i < str->length(); i++) { | 5578 for (int i = 0; i < str->length(shape); i++) { |
5537 storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER); | 5579 storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER); |
5538 } | 5580 } |
5539 } | 5581 } |
5540 counter += str->length(); | 5582 counter += str->length(shape); |
5541 } | 5583 } |
5542 } | 5584 } |
5543 ASSERT(!storage || storage->length() == counter); | 5585 ASSERT(!storage || storage->length() == counter); |
5544 return counter; | 5586 return counter; |
5545 } | 5587 } |
5546 | 5588 |
5547 | 5589 |
5548 int JSObject::GetEnumElementKeys(FixedArray* storage) { | 5590 int JSObject::GetEnumElementKeys(FixedArray* storage) { |
5549 return GetLocalElementKeys(storage, | 5591 return GetLocalElementKeys(storage, |
5550 static_cast<PropertyAttributes>(DONT_ENUM)); | 5592 static_cast<PropertyAttributes>(DONT_ENUM)); |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5715 | 5757 |
5716 bool IsMatch(Object* string) { | 5758 bool IsMatch(Object* string) { |
5717 return String::cast(string)->Equals(string_); | 5759 return String::cast(string)->Equals(string_); |
5718 } | 5760 } |
5719 | 5761 |
5720 uint32_t Hash() { return string_->Hash(); } | 5762 uint32_t Hash() { return string_->Hash(); } |
5721 | 5763 |
5722 Object* GetObject() { | 5764 Object* GetObject() { |
5723 // If the string is a cons string, attempt to flatten it so that | 5765 // If the string is a cons string, attempt to flatten it so that |
5724 // symbols will most often be flat strings. | 5766 // symbols will most often be flat strings. |
5725 if (string_->IsConsString()) { | 5767 StringShape shape(string_); |
5768 if (shape.IsCons()) { | |
5726 ConsString* cons_string = ConsString::cast(string_); | 5769 ConsString* cons_string = ConsString::cast(string_); |
5727 cons_string->TryFlatten(); | 5770 cons_string->TryFlatten(shape); |
5728 if (cons_string->second() == Heap::empty_string()) { | 5771 if (cons_string->second() == Heap::empty_string()) { |
5729 string_ = String::cast(cons_string->first()); | 5772 string_ = cons_string->first(); |
5730 } | 5773 } |
5731 } | 5774 } |
5732 // Transform string to symbol if possible. | 5775 // Transform string to symbol if possible. |
5733 Map* map = Heap::SymbolMapForString(string_); | 5776 Map* map = Heap::SymbolMapForString(string_); |
5734 if (map != NULL) { | 5777 if (map != NULL) { |
5735 string_->set_map(map); | 5778 string_->set_map(map); |
5736 return string_; | 5779 return string_; |
5737 } | 5780 } |
5738 // Otherwise allocate a new symbol. | 5781 // Otherwise allocate a new symbol. |
5739 StringInputBuffer buffer(string_); | 5782 StringInputBuffer buffer(string_); |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5877 } | 5920 } |
5878 | 5921 |
5879 | 5922 |
5880 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { | 5923 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { |
5881 SymbolKey key(string); | 5924 SymbolKey key(string); |
5882 int entry = FindEntry(&key); | 5925 int entry = FindEntry(&key); |
5883 if (entry == -1) { | 5926 if (entry == -1) { |
5884 return false; | 5927 return false; |
5885 } else { | 5928 } else { |
5886 String* result = String::cast(KeyAt(entry)); | 5929 String* result = String::cast(KeyAt(entry)); |
5887 ASSERT(result->is_symbol()); | 5930 ASSERT(StringShape(result).IsSymbol()); |
5888 *symbol = result; | 5931 *symbol = result; |
5889 return true; | 5932 return true; |
5890 } | 5933 } |
5891 } | 5934 } |
5892 | 5935 |
5893 | 5936 |
5894 Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) { | 5937 Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) { |
5895 Utf8SymbolKey key(str); | 5938 Utf8SymbolKey key(str); |
5896 return LookupKey(&key, s); | 5939 return LookupKey(&key, s); |
5897 } | 5940 } |
(...skipping 887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6785 // No break point. | 6828 // No break point. |
6786 if (break_point_objects()->IsUndefined()) return 0; | 6829 if (break_point_objects()->IsUndefined()) return 0; |
6787 // Single beak point. | 6830 // Single beak point. |
6788 if (!break_point_objects()->IsFixedArray()) return 1; | 6831 if (!break_point_objects()->IsFixedArray()) return 1; |
6789 // Multiple break points. | 6832 // Multiple break points. |
6790 return FixedArray::cast(break_point_objects())->length(); | 6833 return FixedArray::cast(break_point_objects())->length(); |
6791 } | 6834 } |
6792 | 6835 |
6793 | 6836 |
6794 } } // namespace v8::internal | 6837 } } // namespace v8::internal |
OLD | NEW |