Chromium Code Reviews| 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..4e807665c0420c38b6e50913f4df9e37a4a531dc 100644 |
| --- a/src/parsing/scanner-character-streams.cc |
| +++ b/src/parsing/scanner-character-streams.cc |
| @@ -630,6 +630,145 @@ bool TwoByteExternalStreamingStream::ReadBlock() { |
| return true; |
| } |
| +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; |
| +} |
| + |
| // ---------------------------------------------------------------------------- |
| // ScannerStream: Create stream instances. |
| @@ -669,7 +808,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) |
|
vogelheim
2016/10/26 16:44:45
Please add the same #if around the two implementat
|
| 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: |