OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/parsing/scanner-character-streams.h" | 5 #include "src/parsing/scanner-character-streams.h" |
6 | 6 |
7 #include "include/v8.h" | 7 #include "include/v8.h" |
8 #include "src/globals.h" | 8 #include "src/globals.h" |
9 #include "src/handles.h" | 9 #include "src/handles.h" |
10 #include "src/objects-inl.h" | 10 #include "src/objects-inl.h" |
(...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 size_t OneByteExternalStreamingStream::FillBuffer(size_t position) { | 530 size_t OneByteExternalStreamingStream::FillBuffer(size_t position) { |
531 const Chunk& chunk = chunks_[FindChunk(chunks_, source_, position)]; | 531 const Chunk& chunk = chunks_[FindChunk(chunks_, source_, position)]; |
532 if (chunk.byte_length == 0) return 0; | 532 if (chunk.byte_length == 0) return 0; |
533 | 533 |
534 size_t start_pos = position - chunk.byte_pos; | 534 size_t start_pos = position - chunk.byte_pos; |
535 size_t len = i::Min(kBufferSize, chunk.byte_length - start_pos); | 535 size_t len = i::Min(kBufferSize, chunk.byte_length - start_pos); |
536 i::CopyCharsUnsigned(buffer_, chunk.data + start_pos, len); | 536 i::CopyCharsUnsigned(buffer_, chunk.data + start_pos, len); |
537 return len; | 537 return len; |
538 } | 538 } |
539 | 539 |
| 540 #if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM) |
540 // ---------------------------------------------------------------------------- | 541 // ---------------------------------------------------------------------------- |
541 // TwoByteExternalStreamingStream | 542 // TwoByteExternalStreamingStream |
542 // | 543 // |
543 // A stream of ucs-2 data, delivered in chunks. Chunks may be 'cut' into the | 544 // A stream of ucs-2 data, delivered in chunks. Chunks may be 'cut' into the |
544 // middle of characters (or even contain only one byte), which adds a bit | 545 // middle of characters (or even contain only one byte), which adds a bit |
545 // of complexity. This stream avoid all data copying, except for characters | 546 // of complexity. This stream avoid all data copying, except for characters |
546 // that cross chunk boundaries. | 547 // that cross chunk boundaries. |
547 | 548 |
548 class TwoByteExternalStreamingStream : public Utf16CharacterStream { | 549 class TwoByteExternalStreamingStream : public Utf16CharacterStream { |
549 public: | 550 public: |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
623 // to point to position. Be careful when converting the byte positions (in | 624 // to point to position. Be careful when converting the byte positions (in |
624 // Chunk) to the ucs-2 character positions (in buffer_*_ members). | 625 // Chunk) to the ucs-2 character positions (in buffer_*_ members). |
625 buffer_start_ = reinterpret_cast<const uint16_t*>(current.data + odd_start); | 626 buffer_start_ = reinterpret_cast<const uint16_t*>(current.data + odd_start); |
626 buffer_end_ = buffer_start_ + number_chars; | 627 buffer_end_ = buffer_start_ + number_chars; |
627 buffer_pos_ = (current.byte_pos + odd_start) / 2; | 628 buffer_pos_ = (current.byte_pos + odd_start) / 2; |
628 buffer_cursor_ = buffer_start_ + (position - buffer_pos_); | 629 buffer_cursor_ = buffer_start_ + (position - buffer_pos_); |
629 DCHECK_EQ(position, pos()); | 630 DCHECK_EQ(position, pos()); |
630 return true; | 631 return true; |
631 } | 632 } |
632 | 633 |
| 634 #else |
| 635 |
| 636 // ---------------------------------------------------------------------------- |
| 637 // TwoByteExternalBufferedStream |
| 638 // |
| 639 // This class is made specifically to address unaligned access to 16-bit data |
| 640 // in MIPS and ARM architectures. It replaces class |
| 641 // TwoByteExternalStreamingStream which in some cases does have unaligned |
| 642 // accesse to 16-bit data |
| 643 |
| 644 class TwoByteExternalBufferedStream : public Utf16CharacterStream { |
| 645 public: |
| 646 explicit TwoByteExternalBufferedStream( |
| 647 ScriptCompiler::ExternalSourceStream* source); |
| 648 ~TwoByteExternalBufferedStream(); |
| 649 |
| 650 protected: |
| 651 static const size_t kBufferSize = 512; |
| 652 |
| 653 bool ReadBlock() override; |
| 654 |
| 655 // FillBuffer should read up to kBufferSize characters at position and store |
| 656 // them into buffer_[0..]. It returns the number of characters stored. |
| 657 size_t FillBuffer(size_t position, size_t chunk_no); |
| 658 |
| 659 // Fixed sized buffer that this class reads from. |
| 660 // The base class' buffer_start_ should always point to buffer_. |
| 661 uc16 buffer_[kBufferSize]; |
| 662 |
| 663 Chunks chunks_; |
| 664 ScriptCompiler::ExternalSourceStream* source_; |
| 665 }; |
| 666 |
| 667 TwoByteExternalBufferedStream::TwoByteExternalBufferedStream( |
| 668 ScriptCompiler::ExternalSourceStream* source) |
| 669 : Utf16CharacterStream(buffer_, buffer_, buffer_, 0), source_(source) {} |
| 670 |
| 671 TwoByteExternalBufferedStream::~TwoByteExternalBufferedStream() { |
| 672 DeleteChunks(chunks_); |
| 673 } |
| 674 |
| 675 bool TwoByteExternalBufferedStream::ReadBlock() { |
| 676 size_t position = pos(); |
| 677 // Find chunk in which the position belongs |
| 678 size_t chunk_no = FindChunk(chunks_, source_, 2 * position + 1); |
| 679 |
| 680 // Out of data? Return 0. |
| 681 if (chunks_[chunk_no].byte_length == 0) { |
| 682 buffer_cursor_ = buffer_start_; |
| 683 buffer_end_ = buffer_start_; |
| 684 return false; |
| 685 } |
| 686 |
| 687 Chunk& current = chunks_[chunk_no]; |
| 688 |
| 689 bool odd_start = current.byte_pos % 2; |
| 690 // Common case: character is in current chunk. |
| 691 DCHECK_LE(current.byte_pos, 2 * position + odd_start); |
| 692 DCHECK_LT(2 * position + 1, current.byte_pos + current.byte_length); |
| 693 |
| 694 // If character starts on odd address copy text in buffer so there is always |
| 695 // aligned access to characters. This is important on MIPS and ARM |
| 696 // architectures. Otherwise read characters from memory directly. |
| 697 if (!odd_start) { |
| 698 buffer_start_ = reinterpret_cast<const uint16_t*>(current.data); |
| 699 size_t number_chars = current.byte_length / 2; |
| 700 buffer_end_ = buffer_start_ + number_chars; |
| 701 buffer_pos_ = current.byte_pos / 2; |
| 702 buffer_cursor_ = buffer_start_ + (position - buffer_pos_); |
| 703 DCHECK_EQ(position, pos()); |
| 704 return true; |
| 705 } else { |
| 706 buffer_pos_ = position; |
| 707 buffer_cursor_ = buffer_; |
| 708 buffer_end_ = buffer_ + FillBuffer(position, chunk_no); |
| 709 DCHECK_EQ(pos(), position); |
| 710 DCHECK_LE(buffer_end_, buffer_start_ + kBufferSize); |
| 711 return buffer_cursor_ < buffer_end_; |
| 712 } |
| 713 } |
| 714 |
| 715 size_t TwoByteExternalBufferedStream::FillBuffer(size_t position, |
| 716 size_t chunk_no) { |
| 717 // Align buffer_pos_ to the size of the buffer. |
| 718 { |
| 719 size_t new_pos = position / kBufferSize * kBufferSize; |
| 720 if (new_pos != position) { |
| 721 chunk_no = FindChunk(chunks_, source_, 2 * new_pos + 1); |
| 722 buffer_pos_ = new_pos; |
| 723 buffer_cursor_ = buffer_start_ + (position - buffer_pos_); |
| 724 position = new_pos; |
| 725 } |
| 726 } |
| 727 |
| 728 Chunk* current = &chunks_[chunk_no]; |
| 729 |
| 730 // Annoying edge case: Chunks may not be 2-byte aligned, meaning that a |
| 731 // character may be split between the previous and the current chunk. |
| 732 // If we find such a lonely byte at the beginning of the chunk, we'll copy |
| 733 // it to the first byte in buffer_. |
| 734 size_t totalLength = 0; |
| 735 bool lonely_byte = (current->byte_pos == (2 * position + 1)); |
| 736 if (lonely_byte) { |
| 737 DCHECK_NE(chunk_no, 0); |
| 738 Chunk& previous_chunk = chunks_[chunk_no - 1]; |
| 739 *reinterpret_cast<uint8_t*>(buffer_) = |
| 740 previous_chunk.data[previous_chunk.byte_length - 1]; |
| 741 totalLength++; |
| 742 } |
| 743 |
| 744 // Common case: character is in current chunk. |
| 745 DCHECK_LE(current->byte_pos, 2 * position + 1); |
| 746 DCHECK_LT(2 * position + 1, current->byte_pos + current->byte_length); |
| 747 |
| 748 // Copy characters from current chunk starting from chunk_pos to the end of |
| 749 // buffer or chunk. |
| 750 size_t chunk_pos = position - current->byte_pos / 2; |
| 751 bool middle_of_chunk = chunk_pos != 0; |
| 752 size_t bytes_to_move = |
| 753 i::Min(2 * kBufferSize - !middle_of_chunk, |
| 754 current->byte_length - 2 * chunk_pos + middle_of_chunk); |
| 755 i::MemMove(reinterpret_cast<uint8_t*>(buffer_) + !middle_of_chunk, |
| 756 current->data + 2 * chunk_pos - middle_of_chunk, bytes_to_move); |
| 757 |
| 758 // Fill up the rest of the buffer if there is space and data left. |
| 759 totalLength += bytes_to_move; |
| 760 position = (current->byte_pos + current->byte_length) / 2; |
| 761 if (position - buffer_pos_ < kBufferSize) { |
| 762 chunk_no = FindChunk(chunks_, source_, 2 * position + 1); |
| 763 current = &chunks_[chunk_no]; |
| 764 bytes_to_move = i::Min(2 * kBufferSize - totalLength, current->byte_length); |
| 765 while (bytes_to_move && current->byte_pos % 2) { |
| 766 // Common case: character is in current chunk. |
| 767 DCHECK_LE(current->byte_pos, 2 * position + 1); |
| 768 DCHECK_LT(2 * position + 1, current->byte_pos + current->byte_length); |
| 769 |
| 770 i::MemMove(reinterpret_cast<uint8_t*>(buffer_) + totalLength, |
| 771 current->data, bytes_to_move); |
| 772 totalLength += bytes_to_move; |
| 773 position = (current->byte_pos + current->byte_length) / 2; |
| 774 chunk_no = FindChunk(chunks_, source_, 2 * position + 1); |
| 775 current = &chunks_[chunk_no]; |
| 776 bytes_to_move = |
| 777 i::Min(2 * kBufferSize - totalLength, current->byte_length); |
| 778 } |
| 779 } |
| 780 return totalLength / 2; |
| 781 } |
| 782 #endif |
| 783 |
633 // ---------------------------------------------------------------------------- | 784 // ---------------------------------------------------------------------------- |
634 // ScannerStream: Create stream instances. | 785 // ScannerStream: Create stream instances. |
635 | 786 |
636 Utf16CharacterStream* ScannerStream::For(Handle<String> data) { | 787 Utf16CharacterStream* ScannerStream::For(Handle<String> data) { |
637 return ScannerStream::For(data, 0, data->length()); | 788 return ScannerStream::For(data, 0, data->length()); |
638 } | 789 } |
639 | 790 |
640 Utf16CharacterStream* ScannerStream::For(Handle<String> data, int start_pos, | 791 Utf16CharacterStream* ScannerStream::For(Handle<String> data, int start_pos, |
641 int end_pos) { | 792 int end_pos) { |
642 DCHECK(start_pos >= 0); | 793 DCHECK(start_pos >= 0); |
(...skipping 19 matching lines...) Expand all Loading... |
662 const char* data, size_t length) { | 813 const char* data, size_t length) { |
663 return std::unique_ptr<Utf16CharacterStream>( | 814 return std::unique_ptr<Utf16CharacterStream>( |
664 new ExternalOneByteStringUtf16CharacterStream(data, length)); | 815 new ExternalOneByteStringUtf16CharacterStream(data, length)); |
665 } | 816 } |
666 | 817 |
667 Utf16CharacterStream* ScannerStream::For( | 818 Utf16CharacterStream* ScannerStream::For( |
668 ScriptCompiler::ExternalSourceStream* source_stream, | 819 ScriptCompiler::ExternalSourceStream* source_stream, |
669 v8::ScriptCompiler::StreamedSource::Encoding encoding) { | 820 v8::ScriptCompiler::StreamedSource::Encoding encoding) { |
670 switch (encoding) { | 821 switch (encoding) { |
671 case v8::ScriptCompiler::StreamedSource::TWO_BYTE: | 822 case v8::ScriptCompiler::StreamedSource::TWO_BYTE: |
| 823 #if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM) |
672 return new TwoByteExternalStreamingStream(source_stream); | 824 return new TwoByteExternalStreamingStream(source_stream); |
| 825 #else |
| 826 return new TwoByteExternalBufferedStream(source_stream); |
| 827 #endif |
673 case v8::ScriptCompiler::StreamedSource::ONE_BYTE: | 828 case v8::ScriptCompiler::StreamedSource::ONE_BYTE: |
674 return new OneByteExternalStreamingStream(source_stream); | 829 return new OneByteExternalStreamingStream(source_stream); |
675 case v8::ScriptCompiler::StreamedSource::UTF8: | 830 case v8::ScriptCompiler::StreamedSource::UTF8: |
676 return new Utf8ExternalStreamingStream(source_stream); | 831 return new Utf8ExternalStreamingStream(source_stream); |
677 } | 832 } |
678 UNREACHABLE(); | 833 UNREACHABLE(); |
679 return nullptr; | 834 return nullptr; |
680 } | 835 } |
681 | 836 |
682 } // namespace internal | 837 } // namespace internal |
683 } // namespace v8 | 838 } // namespace v8 |
OLD | NEW |