Implement bookmarks for ExternalStreamingStream.
authorvogelheim <vogelheim@chromium.org>
Tue, 26 May 2015 07:54:14 +0000 (00:54 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 26 May 2015 07:54:20 +0000 (07:54 +0000)
(Requires the embedder's ExternalSourceStream implementation to cooperate.
 See crrev.com/1154883003 for Blink.)

R=jochen@chromium.org
BUG=chromium:470930
LOG=Y

Review URL: https://codereview.chromium.org/1156733002

Cr-Commit-Position: refs/heads/master@{#28610}

include/v8.h
src/api.cc
src/scanner-character-streams.cc
src/scanner-character-streams.h

index 2b569bdef191378cc94f6f08f3eadac87c33e9d0..27e212d468f054878c5e04fd7e3c2d493d2a23a4 100644 (file)
@@ -1220,6 +1220,23 @@ class V8_EXPORT ScriptCompiler {
      * V8 has parsed the data it received so far.
      */
     virtual size_t GetMoreData(const uint8_t** src) = 0;
+
+    /**
+     * V8 calls this method to set a 'bookmark' at the current position in
+     * the source stream, for the purpose of (maybe) later calling
+     * ResetToBookmark. If ResetToBookmark is called later, then subsequent
+     * calls to GetMoreData should return the same data as they did when
+     * SetBookmark was called earlier.
+     *
+     * The embedder may return 'false' to indicate it cannot provide this
+     * functionality.
+     */
+    virtual bool SetBookmark();
+
+    /**
+     * V8 calls this to return to a previously set bookmark.
+     */
+    virtual void ResetToBookmark();
   };
 
 
index 057cb651d87224c86fde5cb329a809356c422e3e..808def3b0fad215568c02b494e8faac6b5249c5b 100644 (file)
@@ -1527,6 +1527,12 @@ ScriptCompiler::CachedData::~CachedData() {
 }
 
 
+bool ScriptCompiler::ExternalSourceStream::SetBookmark() { return false; }
+
+
+void ScriptCompiler::ExternalSourceStream::ResetToBookmark() { UNREACHABLE(); }
+
+
 ScriptCompiler::StreamedSource::StreamedSource(ExternalSourceStream* stream,
                                                Encoding encoding)
     : impl_(new i::StreamedSource(stream, encoding)) {}
index a710330a2be65c288df06ad6f1ec4741e8f52ee9..98e79aad76fd458715ad69649b692f3083a4ee40 100644 (file)
@@ -356,10 +356,7 @@ size_t ExternalStreamingStream::FillBuffer(size_t position) {
           // chunk. This will only happen when the chunk was really small. We
           // don't handle the case where a UTF-8 character is split over several
           // chunks; in that case V8 won't crash, but it will be a parse error.
-          delete[] current_data_;
-          current_data_ = NULL;
-          current_data_length_ = 0;
-          current_data_offset_ = 0;
+          FlushCurrent();
           continue;  // Request a new chunk.
         }
       }
@@ -383,15 +380,76 @@ size_t ExternalStreamingStream::FillBuffer(size_t position) {
 
     // Did we use all the data in the data chunk?
     if (current_data_offset_ == current_data_length_) {
-      delete[] current_data_;
-      current_data_ = NULL;
-      current_data_length_ = 0;
-      current_data_offset_ = 0;
+      FlushCurrent();
     }
   }
   return data_in_buffer;
 }
 
+
+bool ExternalStreamingStream::SetBookmark() {
+  DCHECK(utf8_split_char_buffer_length_ == 0);  // We can't be within a char.
+
+  // Bookmarking for this stream is a bit more complex than expected, since
+  // the stream state is distributed over several places:
+  // - pos_ (inherited from Utf16CharacterStream)
+  // - buffer_cursor_ and buffer_end_ (also from Utf16CharacterStream)
+  // - buffer_ (from BufferedUtf16CharacterStream)
+  // - current_data_ (+ .._offset_ and .._length) (this class)
+  //
+  // The underlying source_stream_ instance likely could re-construct this
+  // local data for us, but with the given interfaces we have no way of
+  // accomplishing this. Thus, we'll have to save all data locally.
+  //
+  // What gets saved where:
+  // - pos_  =>  bookmark_
+  // - buffer_[buffer_cursor_ .. buffer_end_]  =>  bookmark_buffer_
+  // - current_data_[.._offset_ .. .._length_]  =>  bookmark_data_
+
+  bookmark_ = pos_;
+
+  size_t buffer_length = buffer_end_ - buffer_cursor_;
+  bookmark_buffer_.Dispose();
+  bookmark_buffer_ = Vector<uint16_t>::New(static_cast<int>(buffer_length));
+  CopyCharsUnsigned(bookmark_buffer_.start(), buffer_cursor_, buffer_length);
+
+  size_t data_length = current_data_length_ - current_data_offset_;
+  bookmark_data_.Dispose();
+  bookmark_data_ = Vector<uint8_t>::New(static_cast<int>(data_length));
+  CopyBytes(bookmark_data_.start(), current_data_ + current_data_offset_,
+            data_length);
+
+  return source_stream_->SetBookmark();
+}
+
+
+void ExternalStreamingStream::ResetToBookmark() {
+  source_stream_->ResetToBookmark();
+  FlushCurrent();
+
+  pos_ = bookmark_;
+
+  // current_data_ can point to bookmark_data_'s buffer.
+  current_data_ = bookmark_data_.start();
+  current_data_offset_ = 0;
+  current_data_length_ = bookmark_data_.length();
+
+  // bookmark_buffer_ needs to be copied to buffer_.
+  CopyCharsUnsigned(buffer_, bookmark_buffer_.begin(),
+                    bookmark_buffer_.length());
+  buffer_cursor_ = buffer_;
+  buffer_end_ = buffer_ + bookmark_buffer_.length();
+}
+
+
+void ExternalStreamingStream::FlushCurrent() {
+  delete[] current_data_;
+  current_data_ = NULL;
+  current_data_length_ = 0;
+  current_data_offset_ = 0;
+}
+
+
 void ExternalStreamingStream::HandleUtf8SplitCharacters(
     size_t* data_in_buffer) {
   // Note the following property of UTF-8 which makes this function possible:
index 36d84bc0f6b5d82a16b005bef0ea737138642a1f..e9047d3212e101675e777151e7a70f58ce290124 100644 (file)
@@ -92,9 +92,14 @@ class ExternalStreamingStream : public BufferedUtf16CharacterStream {
         current_data_(NULL),
         current_data_offset_(0),
         current_data_length_(0),
-        utf8_split_char_buffer_length_(0) {}
+        utf8_split_char_buffer_length_(0),
+        bookmark_(0) {}
 
-  virtual ~ExternalStreamingStream() { delete[] current_data_; }
+  virtual ~ExternalStreamingStream() {
+    delete[] current_data_;
+    bookmark_buffer_.Dispose();
+    bookmark_data_.Dispose();
+  }
 
   size_t BufferSeekForward(size_t delta) override {
     // We never need to seek forward when streaming scripts. We only seek
@@ -107,8 +112,12 @@ class ExternalStreamingStream : public BufferedUtf16CharacterStream {
 
   size_t FillBuffer(size_t position) override;
 
+  virtual bool SetBookmark() override;
+  virtual void ResetToBookmark() override;
+
  private:
   void HandleUtf8SplitCharacters(size_t* data_in_buffer);
+  void FlushCurrent();
 
   ScriptCompiler::ExternalSourceStream* source_stream_;
   v8::ScriptCompiler::StreamedSource::Encoding encoding_;
@@ -118,6 +127,12 @@ class ExternalStreamingStream : public BufferedUtf16CharacterStream {
   // For converting UTF-8 characters which are split across two data chunks.
   uint8_t utf8_split_char_buffer_[4];
   size_t utf8_split_char_buffer_length_;
+
+  // Bookmark support. See comments in ExternalStreamingStream::SetBookmark
+  // for additional details.
+  size_t bookmark_;
+  Vector<uint16_t> bookmark_buffer_;
+  Vector<uint8_t> bookmark_data_;
 };