| 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:
|
|
|