Commit 99a2440c authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[Scanner] Add support for cloning character streams.

Currently chunked and streaming character streams don't have cloning support as this
requires additional changes on the Blink side.

BUG=v8:8041

Change-Id: I167b3b1cd5ae1ac4038f3715b6a679d3e65d9a85
Reviewed-on: https://chromium-review.googlesource.com/1183429Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55444}
parent 609ec4b7
......@@ -52,11 +52,16 @@ class OnHeapStream {
OnHeapStream(Handle<String> string, size_t start_offset, size_t end)
: string_(string), start_offset_(start_offset), length_(end) {}
OnHeapStream(const OnHeapStream& other) : start_offset_(0), length_(0) {
UNREACHABLE();
}
Range<Char> GetDataAt(size_t pos) {
return {&string_->GetChars()[start_offset_ + Min(length_, pos)],
&string_->GetChars()[start_offset_ + length_]};
}
static const bool kCanBeCloned = false;
static const bool kCanAccessHeap = true;
private:
......@@ -73,10 +78,14 @@ class ExternalStringStream {
ExternalStringStream(const Char* data, size_t end)
: data_(data), length_(end) {}
ExternalStringStream(const ExternalStringStream& other)
: data_(other.data_), length_(other.length_) {}
Range<Char> GetDataAt(size_t pos) {
return {&data_[Min(length_, pos)], &data_[length_]};
}
static const bool kCanBeCloned = true;
static const bool kCanAccessHeap = false;
private:
......@@ -92,6 +101,11 @@ class ChunkedStream {
RuntimeCallStats* stats)
: source_(source), stats_(stats) {}
ChunkedStream(const ChunkedStream& other) {
// TODO(rmcilroy): Implement cloning for chunked streams.
UNREACHABLE();
}
Range<Char> GetDataAt(size_t pos) {
Chunk chunk = FindChunk(pos);
size_t buffer_end = chunk.length;
......@@ -103,6 +117,7 @@ class ChunkedStream {
for (Chunk& chunk : chunks_) delete[] chunk.data;
}
static const bool kCanBeCloned = false;
static const bool kCanAccessHeap = false;
private:
......@@ -261,6 +276,16 @@ class BufferedCharacterStream : public Utf16CharacterStream {
buffer_pos_ = pos;
}
bool can_be_cloned() const final {
return ByteStream<uint16_t>::kCanBeCloned;
}
std::unique_ptr<Utf16CharacterStream> Clone() const override {
CHECK(can_be_cloned());
return std::unique_ptr<Utf16CharacterStream>(
new BufferedCharacterStream<ByteStream>(*this));
}
protected:
bool ReadBlock() final {
size_t position = pos();
......@@ -280,9 +305,14 @@ class BufferedCharacterStream : public Utf16CharacterStream {
return true;
}
bool can_access_heap() final { return ByteStream<uint8_t>::kCanAccessHeap; }
bool can_access_heap() const final {
return ByteStream<uint8_t>::kCanAccessHeap;
}
private:
BufferedCharacterStream(const BufferedCharacterStream<ByteStream>& other)
: byte_stream_(other.byte_stream_) {}
static const size_t kBufferSize = 512;
uc16 buffer_[kBufferSize];
ByteStream<uint8_t> byte_stream_;
......@@ -298,6 +328,19 @@ class UnbufferedCharacterStream : public Utf16CharacterStream {
buffer_pos_ = pos;
}
bool can_access_heap() const final {
return ByteStream<uint16_t>::kCanAccessHeap;
}
bool can_be_cloned() const final {
return ByteStream<uint16_t>::kCanBeCloned;
}
std::unique_ptr<Utf16CharacterStream> Clone() const override {
return std::unique_ptr<Utf16CharacterStream>(
new UnbufferedCharacterStream<ByteStream>(*this));
}
protected:
bool ReadBlock() final {
size_t position = pos();
......@@ -313,7 +356,8 @@ class UnbufferedCharacterStream : public Utf16CharacterStream {
return true;
}
bool can_access_heap() final { return ByteStream<uint16_t>::kCanAccessHeap; }
UnbufferedCharacterStream(const UnbufferedCharacterStream<ByteStream>& other)
: byte_stream_(other.byte_stream_) {}
ByteStream<uint16_t> byte_stream_;
};
......@@ -421,7 +465,13 @@ class Utf8ExternalStreamingStream : public BufferedUtf16CharacterStream {
for (size_t i = 0; i < chunks_.size(); i++) delete[] chunks_[i].data;
}
bool can_access_heap() final { return false; }
bool can_access_heap() const final { return false; }
bool can_be_cloned() const final { return false; }
std::unique_ptr<Utf16CharacterStream> Clone() const override {
UNREACHABLE();
}
protected:
size_t FillBuffer(size_t position) final;
......
......@@ -109,8 +109,16 @@ class Utf16CharacterStream {
}
}
// Returns true if the stream can be cloned with Clone.
// TODO(rmcilroy): Remove this once ChunkedStreams can be cloned.
virtual bool can_be_cloned() const = 0;
// Clones the character stream to enable another independent scanner to access
// the same underlying stream.
virtual std::unique_ptr<Utf16CharacterStream> Clone() const = 0;
// Returns true if the stream could access the V8 heap after construction.
virtual bool can_access_heap() = 0;
virtual bool can_access_heap() const = 0;
protected:
Utf16CharacterStream(const uint16_t* buffer_start,
......@@ -389,6 +397,8 @@ class Scanner {
allow_harmony_numeric_separator_ = allow;
}
const Utf16CharacterStream* stream() const { return source_; }
private:
// Scoped helper for saving & restoring scanner error state.
// This is used for tagged template literals, in which normally forbidden
......
......@@ -400,6 +400,26 @@ void TestCharacterStream(const char* reference, i::Utf16CharacterStream* stream,
CHECK_LT(stream->Advance(), 0);
}
void TestCloneCharacterStream(const char* reference,
i::Utf16CharacterStream* stream,
unsigned length) {
std::unique_ptr<i::Utf16CharacterStream> clone = stream->Clone();
unsigned i;
unsigned halfway = length / 2;
// Advance original half way.
for (i = 0; i < halfway; i++) {
CHECK_EQU(i, stream->pos());
CHECK_EQU(reference[i], stream->Advance());
}
// Test advancing oriignal stream didn't affect the clone.
TestCharacterStream(reference, clone.get(), length, 0, length);
// Test advancing clone didn't affect original stream.
TestCharacterStream(reference, stream, length, i, length);
}
#undef CHECK_EQU
void TestCharacterStreams(const char* one_byte_source, unsigned length,
......@@ -695,3 +715,92 @@ TEST(RelocatingCharacterStream) {
CHECK_EQ('c', two_byte_string_stream->Advance());
CHECK_EQ('d', two_byte_string_stream->Advance());
}
TEST(CloneCharacterStreams) {
v8::HandleScope handles(CcTest::isolate());
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
v8::Context::Scope context_scope(context);
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
const char* one_byte_source = "abcdefghi";
unsigned length = static_cast<unsigned>(strlen(one_byte_source));
// Check that cloning a character stream does not update
// 2-byte external string
std::unique_ptr<i::uc16[]> uc16_buffer(new i::uc16[length]);
i::Vector<const i::uc16> two_byte_vector(uc16_buffer.get(),
static_cast<int>(length));
{
for (unsigned i = 0; i < length; i++) {
uc16_buffer[i] = static_cast<i::uc16>(one_byte_source[i]);
}
TestExternalResource resource(uc16_buffer.get(), length);
i::Handle<i::String> uc16_string(
factory->NewExternalStringFromTwoByte(&resource).ToHandleChecked());
std::unique_ptr<i::Utf16CharacterStream> uc16_stream(
i::ScannerStream::For(isolate, uc16_string, 0, length));
TestCloneCharacterStream(one_byte_source, uc16_stream.get(), length);
// This avoids the GC from trying to free a stack allocated resource.
if (uc16_string->IsExternalString())
i::Handle<i::ExternalTwoByteString>::cast(uc16_string)
->SetResource(isolate, nullptr);
}
// 1-byte external string
i::Vector<const uint8_t> one_byte_vector =
i::OneByteVector(one_byte_source, static_cast<int>(length));
i::Handle<i::String> one_byte_string =
factory->NewStringFromOneByte(one_byte_vector).ToHandleChecked();
{
TestExternalOneByteResource one_byte_resource(one_byte_source, length);
i::Handle<i::String> ext_one_byte_string(
factory->NewExternalStringFromOneByte(&one_byte_resource)
.ToHandleChecked());
std::unique_ptr<i::Utf16CharacterStream> one_byte_stream(
i::ScannerStream::For(isolate, ext_one_byte_string, 0, length));
TestCloneCharacterStream(one_byte_source, one_byte_stream.get(), length);
// This avoids the GC from trying to free a stack allocated resource.
if (ext_one_byte_string->IsExternalString())
i::Handle<i::ExternalOneByteString>::cast(ext_one_byte_string)
->SetResource(isolate, nullptr);
}
// Relocatinable streams aren't clonable.
{
std::unique_ptr<i::Utf16CharacterStream> string_stream(
i::ScannerStream::For(isolate, one_byte_string, 0, length));
CHECK(!string_stream->can_be_cloned());
i::Handle<i::String> two_byte_string =
factory->NewStringFromTwoByte(two_byte_vector).ToHandleChecked();
std::unique_ptr<i::Utf16CharacterStream> two_byte_string_stream(
i::ScannerStream::For(isolate, two_byte_string, 0, length));
CHECK(!two_byte_string_stream->can_be_cloned());
}
// Chunk sources currently not cloneable.
{
const char* chunks[] = {"1234", "\0"};
ChunkSource chunk_source(chunks);
std::unique_ptr<i::Utf16CharacterStream> one_byte_streaming_stream(
i::ScannerStream::For(&chunk_source,
v8::ScriptCompiler::StreamedSource::ONE_BYTE,
nullptr));
CHECK(!one_byte_streaming_stream->can_be_cloned());
std::unique_ptr<i::Utf16CharacterStream> utf8_streaming_stream(
i::ScannerStream::For(
&chunk_source, v8::ScriptCompiler::StreamedSource::UTF8, nullptr));
CHECK(!utf8_streaming_stream->can_be_cloned());
std::unique_ptr<i::Utf16CharacterStream> two_byte_streaming_stream(
i::ScannerStream::For(&chunk_source,
v8::ScriptCompiler::StreamedSource::TWO_BYTE,
nullptr));
CHECK(!two_byte_streaming_stream->can_be_cloned());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment