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

Side by Side Diff: src/parsing/scanner-character-streams.cc

Issue 2415093002: MIPS: Fix Utf16CharacterStream scanner crash due to missaligned access (Closed)
Patch Set: Implement TwoByteExternalBufferedStream for unaligned access Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 612 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 // to point to position. Be careful when converting the byte positions (in 623 // to point to position. Be careful when converting the byte positions (in
624 // Chunk) to the ucs-2 character positions (in buffer_*_ members). 624 // Chunk) to the ucs-2 character positions (in buffer_*_ members).
625 buffer_start_ = reinterpret_cast<const uint16_t*>(current.data + odd_start); 625 buffer_start_ = reinterpret_cast<const uint16_t*>(current.data + odd_start);
626 buffer_end_ = buffer_start_ + number_chars; 626 buffer_end_ = buffer_start_ + number_chars;
627 buffer_pos_ = (current.byte_pos + odd_start) / 2; 627 buffer_pos_ = (current.byte_pos + odd_start) / 2;
628 buffer_cursor_ = buffer_start_ + (position - buffer_pos_); 628 buffer_cursor_ = buffer_start_ + (position - buffer_pos_);
629 DCHECK_EQ(position, pos()); 629 DCHECK_EQ(position, pos());
630 return true; 630 return true;
631 } 631 }
632 632
633 class TwoByteExternalBufferedStream : public Utf16CharacterStream {
634 public:
635 explicit TwoByteExternalBufferedStream(
636 ScriptCompiler::ExternalSourceStream* source);
637 ~TwoByteExternalBufferedStream();
638
639 protected:
640 static const size_t kBufferSize = 512;
641
642 bool ReadBlock() override;
643
644 // FillBuffer should read up to kBufferSize characters at position and store
645 // them into buffer_[0..]. It returns the number of characters stored.
646 size_t FillBuffer(size_t position, size_t chunk_no);
647
648 // Fixed sized buffer that this class reads from.
649 // The base class' buffer_start_ should always point to buffer_.
650 uc16 buffer_[kBufferSize];
651
652 Chunks chunks_;
653 ScriptCompiler::ExternalSourceStream* source_;
654 };
655
656 TwoByteExternalBufferedStream::TwoByteExternalBufferedStream(
657 ScriptCompiler::ExternalSourceStream* source)
658 : Utf16CharacterStream(buffer_, buffer_, buffer_, 0), source_(source) {}
659
660 TwoByteExternalBufferedStream::~TwoByteExternalBufferedStream() {
661 DeleteChunks(chunks_);
662 }
663
664 bool TwoByteExternalBufferedStream::ReadBlock() {
665 size_t position = pos();
666 // Find chunk in which the position belongs
667 size_t chunk_no = FindChunk(chunks_, source_, 2 * position + 1);
668
669 // Out of data? Return 0.
670 if (chunks_[chunk_no].byte_length == 0) {
671 buffer_cursor_ = buffer_start_;
672 buffer_end_ = buffer_start_;
673 return false;
674 }
675
676 Chunk& current = chunks_[chunk_no];
677
678 bool odd_start = current.byte_pos % 2;
679 // Common case: character is in current chunk.
680 DCHECK_LE(current.byte_pos, 2 * position + odd_start);
681 DCHECK_LT(2 * position + 1, current.byte_pos + current.byte_length);
682
683 // If character starts on odd address copy text in buffer so there is always
684 // aligned access to characters. This is important on MIPS and ARM
685 // architectures. Otherwise read characters from memory directly.
686 if (!odd_start) {
687 buffer_start_ = reinterpret_cast<const uint16_t*>(current.data);
688 size_t number_chars = current.byte_length / 2;
689 buffer_end_ = buffer_start_ + number_chars;
690 buffer_pos_ = current.byte_pos / 2;
691 buffer_cursor_ = buffer_start_ + (position - buffer_pos_);
692 DCHECK_EQ(position, pos());
693 return true;
694 } else {
695 buffer_pos_ = position;
696 buffer_cursor_ = buffer_;
697 buffer_end_ = buffer_ + FillBuffer(position, chunk_no);
698 DCHECK_EQ(pos(), position);
699 DCHECK_LE(buffer_end_, buffer_start_ + kBufferSize);
700 return buffer_cursor_ < buffer_end_;
701 }
702 }
703
704 size_t TwoByteExternalBufferedStream::FillBuffer(size_t position,
705 size_t chunk_no) {
706 // Align buffer_pos_ to the size of the buffer.
707 {
708 size_t new_pos = position / kBufferSize * kBufferSize;
709 if (new_pos != position) {
710 chunk_no = FindChunk(chunks_, source_, 2 * new_pos + 1);
711 buffer_pos_ = new_pos;
712 buffer_cursor_ = buffer_start_ + (position - buffer_pos_);
713 position = new_pos;
714 }
715 }
716
717 Chunk* current = &chunks_[chunk_no];
718
719 // Annoying edge case: Chunks may not be 2-byte aligned, meaning that a
720 // character may be split between the previous and the current chunk.
721 // If we find such a lonely byte at the beginning of the chunk, we'll copy
722 // it to the first byte in buffer_.
723 size_t totalLength = 0;
724 bool lonely_byte = (current->byte_pos == (2 * position + 1));
725 if (lonely_byte) {
726 DCHECK_NE(chunk_no, 0);
727 Chunk& previous_chunk = chunks_[chunk_no - 1];
728 *reinterpret_cast<uint8_t*>(buffer_) =
729 previous_chunk.data[previous_chunk.byte_length - 1];
730 totalLength++;
731 }
732
733 // Common case: character is in current chunk.
734 DCHECK_LE(current->byte_pos, 2 * position + 1);
735 DCHECK_LT(2 * position + 1, current->byte_pos + current->byte_length);
736
737 // Copy characters from current chunk starting from chunk_pos to the end of
738 // buffer or chunk.
739 size_t chunk_pos = position - current->byte_pos / 2;
740 bool middle_of_chunk = chunk_pos != 0;
741 size_t bytes_to_move =
742 i::Min(2 * kBufferSize - !middle_of_chunk,
743 current->byte_length - 2 * chunk_pos + middle_of_chunk);
744 i::MemMove(reinterpret_cast<uint8_t*>(buffer_) + !middle_of_chunk,
745 current->data + 2 * chunk_pos - middle_of_chunk, bytes_to_move);
746
747 // Fill up the rest of the buffer if there is space and data left.
748 totalLength += bytes_to_move;
749 position = (current->byte_pos + current->byte_length) / 2;
750 if (position - buffer_pos_ < kBufferSize) {
751 chunk_no = FindChunk(chunks_, source_, 2 * position + 1);
752 current = &chunks_[chunk_no];
753 bytes_to_move = i::Min(2 * kBufferSize - totalLength, current->byte_length);
754 while (bytes_to_move && current->byte_pos % 2) {
755 // Common case: character is in current chunk.
756 DCHECK_LE(current->byte_pos, 2 * position + 1);
757 DCHECK_LT(2 * position + 1, current->byte_pos + current->byte_length);
758
759 i::MemMove(reinterpret_cast<uint8_t*>(buffer_) + totalLength,
760 current->data, bytes_to_move);
761 totalLength += bytes_to_move;
762 position = (current->byte_pos + current->byte_length) / 2;
763 chunk_no = FindChunk(chunks_, source_, 2 * position + 1);
764 current = &chunks_[chunk_no];
765 bytes_to_move =
766 i::Min(2 * kBufferSize - totalLength, current->byte_length);
767 }
768 }
769 return totalLength / 2;
770 }
771
633 // ---------------------------------------------------------------------------- 772 // ----------------------------------------------------------------------------
634 // ScannerStream: Create stream instances. 773 // ScannerStream: Create stream instances.
635 774
636 Utf16CharacterStream* ScannerStream::For(Handle<String> data) { 775 Utf16CharacterStream* ScannerStream::For(Handle<String> data) {
637 return ScannerStream::For(data, 0, data->length()); 776 return ScannerStream::For(data, 0, data->length());
638 } 777 }
639 778
640 Utf16CharacterStream* ScannerStream::For(Handle<String> data, int start_pos, 779 Utf16CharacterStream* ScannerStream::For(Handle<String> data, int start_pos,
641 int end_pos) { 780 int end_pos) {
642 DCHECK(start_pos >= 0); 781 DCHECK(start_pos >= 0);
(...skipping 19 matching lines...) Expand all
662 const char* data, size_t length) { 801 const char* data, size_t length) {
663 return std::unique_ptr<Utf16CharacterStream>( 802 return std::unique_ptr<Utf16CharacterStream>(
664 new ExternalOneByteStringUtf16CharacterStream(data, length)); 803 new ExternalOneByteStringUtf16CharacterStream(data, length));
665 } 804 }
666 805
667 Utf16CharacterStream* ScannerStream::For( 806 Utf16CharacterStream* ScannerStream::For(
668 ScriptCompiler::ExternalSourceStream* source_stream, 807 ScriptCompiler::ExternalSourceStream* source_stream,
669 v8::ScriptCompiler::StreamedSource::Encoding encoding) { 808 v8::ScriptCompiler::StreamedSource::Encoding encoding) {
670 switch (encoding) { 809 switch (encoding) {
671 case v8::ScriptCompiler::StreamedSource::TWO_BYTE: 810 case v8::ScriptCompiler::StreamedSource::TWO_BYTE:
811 #if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM)
vogelheim 2016/10/26 16:44:45 Please add the same #if around the two implementat
672 return new TwoByteExternalStreamingStream(source_stream); 812 return new TwoByteExternalStreamingStream(source_stream);
813 #else
814 return new TwoByteExternalBufferedStream(source_stream);
815 #endif
673 case v8::ScriptCompiler::StreamedSource::ONE_BYTE: 816 case v8::ScriptCompiler::StreamedSource::ONE_BYTE:
674 return new OneByteExternalStreamingStream(source_stream); 817 return new OneByteExternalStreamingStream(source_stream);
675 case v8::ScriptCompiler::StreamedSource::UTF8: 818 case v8::ScriptCompiler::StreamedSource::UTF8:
676 return new Utf8ExternalStreamingStream(source_stream); 819 return new Utf8ExternalStreamingStream(source_stream);
677 } 820 }
678 UNREACHABLE(); 821 UNREACHABLE();
679 return nullptr; 822 return nullptr;
680 } 823 }
681 824
682 } // namespace internal 825 } // namespace internal
683 } // namespace v8 826 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698