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

Unified Diff: src/parsing/scanner-character-streams.cc

Issue 2415093002: MIPS: Fix Utf16CharacterStream scanner crash due to missaligned access (Closed)
Patch Set: Added comments and conditional compilation for TwoByteExternalBufferedStream. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/parsing/scanner-character-streams.cc
diff --git a/src/parsing/scanner-character-streams.cc b/src/parsing/scanner-character-streams.cc
index 3f10cfa4c16421f1481f838d28a71a38b2174a90..48513c9983a95972f7c7475a81ccb96eaefb36fd 100644
--- a/src/parsing/scanner-character-streams.cc
+++ b/src/parsing/scanner-character-streams.cc
@@ -537,6 +537,7 @@ size_t OneByteExternalStreamingStream::FillBuffer(size_t position) {
return len;
}
+#if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM)
// ----------------------------------------------------------------------------
// TwoByteExternalStreamingStream
//
@@ -630,6 +631,156 @@ bool TwoByteExternalStreamingStream::ReadBlock() {
return true;
}
+#else
+
+// ----------------------------------------------------------------------------
+// TwoByteExternalBufferedStream
+//
+// This class is made specifically to address unaligned access to 16-bit data
+// in MIPS and ARM architectures. It replaces class
+// TwoByteExternalStreamingStream which in some cases does have unaligned
+// accesse to 16-bit data
+
+class TwoByteExternalBufferedStream : public Utf16CharacterStream {
+ public:
+ explicit TwoByteExternalBufferedStream(
+ ScriptCompiler::ExternalSourceStream* source);
+ ~TwoByteExternalBufferedStream();
+
+ protected:
+ static const size_t kBufferSize = 512;
+
+ bool ReadBlock() override;
+
+ // FillBuffer should read up to kBufferSize characters at position and store
+ // them into buffer_[0..]. It returns the number of characters stored.
+ size_t FillBuffer(size_t position, size_t chunk_no);
+
+ // Fixed sized buffer that this class reads from.
+ // The base class' buffer_start_ should always point to buffer_.
+ uc16 buffer_[kBufferSize];
+
+ Chunks chunks_;
+ ScriptCompiler::ExternalSourceStream* source_;
+};
+
+TwoByteExternalBufferedStream::TwoByteExternalBufferedStream(
+ ScriptCompiler::ExternalSourceStream* source)
+ : Utf16CharacterStream(buffer_, buffer_, buffer_, 0), source_(source) {}
+
+TwoByteExternalBufferedStream::~TwoByteExternalBufferedStream() {
+ DeleteChunks(chunks_);
+}
+
+bool TwoByteExternalBufferedStream::ReadBlock() {
+ size_t position = pos();
+ // Find chunk in which the position belongs
+ size_t chunk_no = FindChunk(chunks_, source_, 2 * position + 1);
+
+ // Out of data? Return 0.
+ if (chunks_[chunk_no].byte_length == 0) {
+ buffer_cursor_ = buffer_start_;
+ buffer_end_ = buffer_start_;
+ return false;
+ }
+
+ Chunk& current = chunks_[chunk_no];
+
+ bool odd_start = current.byte_pos % 2;
+ // Common case: character is in current chunk.
+ DCHECK_LE(current.byte_pos, 2 * position + odd_start);
+ DCHECK_LT(2 * position + 1, current.byte_pos + current.byte_length);
+
+ // If character starts on odd address copy text in buffer so there is always
+ // aligned access to characters. This is important on MIPS and ARM
+ // architectures. Otherwise read characters from memory directly.
+ if (!odd_start) {
+ buffer_start_ = reinterpret_cast<const uint16_t*>(current.data);
+ size_t number_chars = current.byte_length / 2;
+ buffer_end_ = buffer_start_ + number_chars;
+ buffer_pos_ = current.byte_pos / 2;
+ buffer_cursor_ = buffer_start_ + (position - buffer_pos_);
+ DCHECK_EQ(position, pos());
+ return true;
+ } else {
+ buffer_pos_ = position;
+ buffer_cursor_ = buffer_;
+ buffer_end_ = buffer_ + FillBuffer(position, chunk_no);
+ DCHECK_EQ(pos(), position);
+ DCHECK_LE(buffer_end_, buffer_start_ + kBufferSize);
+ return buffer_cursor_ < buffer_end_;
+ }
+}
+
+size_t TwoByteExternalBufferedStream::FillBuffer(size_t position,
+ size_t chunk_no) {
+ // Align buffer_pos_ to the size of the buffer.
+ {
+ size_t new_pos = position / kBufferSize * kBufferSize;
+ if (new_pos != position) {
+ chunk_no = FindChunk(chunks_, source_, 2 * new_pos + 1);
+ buffer_pos_ = new_pos;
+ buffer_cursor_ = buffer_start_ + (position - buffer_pos_);
+ position = new_pos;
+ }
+ }
+
+ Chunk* current = &chunks_[chunk_no];
+
+ // Annoying edge case: Chunks may not be 2-byte aligned, meaning that a
+ // character may be split between the previous and the current chunk.
+ // If we find such a lonely byte at the beginning of the chunk, we'll copy
+ // it to the first byte in buffer_.
+ size_t totalLength = 0;
+ bool lonely_byte = (current->byte_pos == (2 * position + 1));
+ if (lonely_byte) {
+ DCHECK_NE(chunk_no, 0);
+ Chunk& previous_chunk = chunks_[chunk_no - 1];
+ *reinterpret_cast<uint8_t*>(buffer_) =
+ previous_chunk.data[previous_chunk.byte_length - 1];
+ totalLength++;
+ }
+
+ // Common case: character is in current chunk.
+ DCHECK_LE(current->byte_pos, 2 * position + 1);
+ DCHECK_LT(2 * position + 1, current->byte_pos + current->byte_length);
+
+ // Copy characters from current chunk starting from chunk_pos to the end of
+ // buffer or chunk.
+ size_t chunk_pos = position - current->byte_pos / 2;
+ bool middle_of_chunk = chunk_pos != 0;
+ size_t bytes_to_move =
+ i::Min(2 * kBufferSize - !middle_of_chunk,
+ current->byte_length - 2 * chunk_pos + middle_of_chunk);
+ i::MemMove(reinterpret_cast<uint8_t*>(buffer_) + !middle_of_chunk,
+ current->data + 2 * chunk_pos - middle_of_chunk, bytes_to_move);
+
+ // Fill up the rest of the buffer if there is space and data left.
+ totalLength += bytes_to_move;
+ position = (current->byte_pos + current->byte_length) / 2;
+ if (position - buffer_pos_ < kBufferSize) {
+ chunk_no = FindChunk(chunks_, source_, 2 * position + 1);
+ current = &chunks_[chunk_no];
+ bytes_to_move = i::Min(2 * kBufferSize - totalLength, current->byte_length);
+ while (bytes_to_move && current->byte_pos % 2) {
+ // Common case: character is in current chunk.
+ DCHECK_LE(current->byte_pos, 2 * position + 1);
+ DCHECK_LT(2 * position + 1, current->byte_pos + current->byte_length);
+
+ i::MemMove(reinterpret_cast<uint8_t*>(buffer_) + totalLength,
+ current->data, bytes_to_move);
+ totalLength += bytes_to_move;
+ position = (current->byte_pos + current->byte_length) / 2;
+ chunk_no = FindChunk(chunks_, source_, 2 * position + 1);
+ current = &chunks_[chunk_no];
+ bytes_to_move =
+ i::Min(2 * kBufferSize - totalLength, current->byte_length);
+ }
+ }
+ return totalLength / 2;
+}
+#endif
+
// ----------------------------------------------------------------------------
// ScannerStream: Create stream instances.
@@ -669,7 +820,11 @@ Utf16CharacterStream* ScannerStream::For(
v8::ScriptCompiler::StreamedSource::Encoding encoding) {
switch (encoding) {
case v8::ScriptCompiler::StreamedSource::TWO_BYTE:
+#if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM)
return new TwoByteExternalStreamingStream(source_stream);
+#else
+ return new TwoByteExternalBufferedStream(source_stream);
+#endif
case v8::ScriptCompiler::StreamedSource::ONE_BYTE:
return new OneByteExternalStreamingStream(source_stream);
case v8::ScriptCompiler::StreamedSource::UTF8:
« 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