LCOV - code coverage report
Current view: top level - src/wasm - streaming-decoder.h (source / functions) Hit Total Coverage
Test: app.info Lines: 49 49 100.0 %
Date: 2017-10-20 Functions: 9 13 69.2 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #ifndef V8_WASM_STREAMING_DECODER_H_
       6             : #define V8_WASM_STREAMING_DECODER_H_
       7             : 
       8             : #include <vector>
       9             : #include "src/isolate.h"
      10             : #include "src/wasm/module-decoder.h"
      11             : #include "src/wasm/wasm-objects.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : namespace wasm {
      16             : 
      17             : // This class is an interface for the StreamingDecoder to start the processing
      18             : // of the incoming module bytes.
      19        1474 : class V8_EXPORT_PRIVATE StreamingProcessor {
      20             :  public:
      21        1474 :   virtual ~StreamingProcessor() = default;
      22             :   // Process the first 8 bytes of a WebAssembly module. Returns true if the
      23             :   // processing finished successfully and the decoding should continue.
      24             :   virtual bool ProcessModuleHeader(Vector<const uint8_t> bytes,
      25             :                                    uint32_t offset) = 0;
      26             : 
      27             :   // Process all sections but the code section. Returns true if the processing
      28             :   // finished successfully and the decoding should continue.
      29             :   virtual bool ProcessSection(SectionCode section_code,
      30             :                               Vector<const uint8_t> bytes, uint32_t offset) = 0;
      31             : 
      32             :   // Process the start of the code section. Returns true if the processing
      33             :   // finished successfully and the decoding should continue.
      34             :   virtual bool ProcessCodeSectionHeader(size_t num_functions,
      35             :                                         uint32_t offset) = 0;
      36             : 
      37             :   // Process a function body. Returns true if the processing finished
      38             :   // successfully and the decoding should continue.
      39             :   virtual bool ProcessFunctionBody(Vector<const uint8_t> bytes,
      40             :                                    uint32_t offset) = 0;
      41             : 
      42             :   // Report the end of a chunk.
      43             :   virtual void OnFinishedChunk() = 0;
      44             :   // Report the end of the stream. If the stream was successful, all
      45             :   // received bytes are passed by parameter. If there has been an error, an
      46             :   // empty array is passed.
      47             :   virtual void OnFinishedStream(std::unique_ptr<uint8_t[]> bytes,
      48             :                                 size_t length) = 0;
      49             :   // Report an error detected in the StreamingDecoder.
      50             :   virtual void OnError(DecodeResult result) = 0;
      51             :   // Report the abortion of the stream.
      52             :   virtual void OnAbort() = 0;
      53             : };
      54             : 
      55             : // The StreamingDecoder takes a sequence of byte arrays, each received by a call
      56             : // of {OnBytesReceived}, and extracts the bytes which belong to section payloads
      57             : // and function bodies.
      58        2948 : class V8_EXPORT_PRIVATE StreamingDecoder {
      59             :  public:
      60             :   explicit StreamingDecoder(std::unique_ptr<StreamingProcessor> processor);
      61             : 
      62             :   // The buffer passed into OnBytesReceived is owned by the caller.
      63             :   void OnBytesReceived(Vector<const uint8_t> bytes);
      64             : 
      65             :   void Finish();
      66             : 
      67             :   void Abort();
      68             : 
      69             :   // Notify the StreamingDecoder that there has been an compilation error.
      70         220 :   void NotifyError() { ok_ = false; }
      71             : 
      72             :  private:
      73             :   // TODO(ahaas): Put the whole private state of the StreamingDecoder into the
      74             :   // cc file (PIMPL design pattern).
      75             : 
      76             :   // The SectionBuffer is the data object for the content of a single section.
      77             :   // It stores all bytes of the section (including section id and section
      78             :   // length), and the offset where the actual payload starts.
      79             :   class SectionBuffer {
      80             :    public:
      81             :     // id: The section id.
      82             :     // payload_length: The length of the payload.
      83             :     // length_bytes: The section length, as it is encoded in the module bytes.
      84        1576 :     SectionBuffer(uint32_t module_offset, uint8_t id, size_t payload_length,
      85             :                   Vector<const uint8_t> length_bytes)
      86             :         :  // ID + length + payload
      87             :           module_offset_(module_offset),
      88        1576 :           length_(1 + length_bytes.length() + payload_length),
      89        1576 :           bytes_(new uint8_t[length_]),
      90        4728 :           payload_offset_(1 + length_bytes.length()) {
      91        1576 :       bytes_[0] = id;
      92        3152 :       memcpy(bytes_.get() + 1, &length_bytes.first(), length_bytes.length());
      93        1576 :     }
      94             : 
      95             :     SectionCode section_code() const {
      96         987 :       return static_cast<SectionCode>(bytes_[0]);
      97             :     }
      98             : 
      99             :     uint32_t module_offset() const { return module_offset_; }
     100             :     uint8_t* bytes() const { return bytes_.get(); }
     101             :     size_t length() const { return length_; }
     102             :     size_t payload_offset() const { return payload_offset_; }
     103        3599 :     size_t payload_length() const { return length_ - payload_offset_; }
     104         987 :     Vector<const uint8_t> payload() const {
     105             :       return Vector<const uint8_t>(bytes() + payload_offset(),
     106         987 :                                    payload_length());
     107             :     }
     108             : 
     109             :    private:
     110             :     uint32_t module_offset_;
     111             :     size_t length_;
     112             :     std::unique_ptr<uint8_t[]> bytes_;
     113             :     size_t payload_offset_;
     114             :   };
     115             : 
     116             :   // The decoding of a stream of wasm module bytes is organized in states. Each
     117             :   // state provides a buffer to store the bytes required for the current state,
     118             :   // information on how many bytes have already been received, how many bytes
     119             :   // are needed, and a {Next} function which starts the next state once all
     120             :   // bytes of the current state were received.
     121             :   //
     122             :   // The states change according to the following state diagram:
     123             :   //
     124             :   //       Start
     125             :   //         |
     126             :   //         |
     127             :   //         v
     128             :   // DecodeModuleHeader
     129             :   //         |   _________________________________________
     130             :   //         |   |                                        |
     131             :   //         v   v                                        |
     132             :   //  DecodeSectionID --> DecodeSectionLength --> DecodeSectionPayload
     133             :   //         A                  |
     134             :   //         |                  | (if the section id == code)
     135             :   //         |                  v
     136             :   //         |      DecodeNumberOfFunctions -- > DecodeFunctionLength
     137             :   //         |                                          A    |
     138             :   //         |                                          |    |
     139             :   //         |  (after all functions were read)         |    v
     140             :   //         ------------------------------------- DecodeFunctionBody
     141             :   //
     142        8451 :   class DecodingState {
     143             :    public:
     144        8451 :     virtual ~DecodingState() = default;
     145             : 
     146             :     // Reads the bytes for the current state and returns the number of read
     147             :     // bytes.
     148             :     virtual size_t ReadBytes(StreamingDecoder* streaming,
     149             :                              Vector<const uint8_t> bytes);
     150             : 
     151             :     // Returns the next state of the streaming decoding.
     152             :     virtual std::unique_ptr<DecodingState> Next(
     153             :         StreamingDecoder* streaming) = 0;
     154             :     // The number of bytes to be received.
     155             :     virtual size_t size() const = 0;
     156             :     // The buffer to store the received bytes.
     157             :     virtual uint8_t* buffer() = 0;
     158             :     // The number of bytes which were already received.
     159             :     size_t offset() const { return offset_; }
     160        8811 :     void set_offset(size_t value) { offset_ = value; }
     161             :     // The number of bytes which are still needed.
     162        8811 :     size_t remaining() const { return size() - offset(); }
     163        8811 :     bool is_finished() const { return offset() == size(); }
     164             :     // A flag to indicate if finishing the streaming decoder is allowed without
     165             :     // error.
     166          87 :     virtual bool is_finishing_allowed() const { return false; }
     167             : 
     168             :    private:
     169             :     size_t offset_ = 0;
     170             :   };
     171             : 
     172             :   // Forward declarations of the concrete states. This is needed so that they
     173             :   // can access private members of the StreamingDecoder.
     174             :   class DecodeVarInt32;
     175             :   class DecodeModuleHeader;
     176             :   class DecodeSectionID;
     177             :   class DecodeSectionLength;
     178             :   class DecodeSectionPayload;
     179             :   class DecodeNumberOfFunctions;
     180             :   class DecodeFunctionLength;
     181             :   class DecodeFunctionBody;
     182             : 
     183             :   // Creates a buffer for the next section of the module.
     184        1619 :   SectionBuffer* CreateNewBuffer(uint32_t module_offset, uint8_t id,
     185             :                                  size_t length,
     186             :                                  Vector<const uint8_t> length_bytes) {
     187             :     // Check the order of sections. Unknown sections can appear at any position.
     188        1619 :     if (id != kUnknownSectionCode) {
     189        1526 :       if (id < next_section_id_) {
     190         129 :         Error("Unexpected section");
     191          43 :         return nullptr;
     192             :       }
     193        1483 :       next_section_id_ = id + 1;
     194             :     }
     195             :     section_buffers_.emplace_back(
     196        1576 :         new SectionBuffer(module_offset, id, length, length_bytes));
     197        1576 :     return section_buffers_.back().get();
     198             :   }
     199             : 
     200         412 :   std::unique_ptr<DecodingState> Error(DecodeResult result) {
     201        1648 :     if (ok_) processor_->OnError(std::move(result));
     202         412 :     ok_ = false;
     203         412 :     return std::unique_ptr<DecodingState>(nullptr);
     204             :   }
     205             : 
     206         367 :   std::unique_ptr<DecodingState> Error(std::string message) {
     207             :     DecodeResult result(nullptr);
     208         734 :     result.error(module_offset_ - 1, std::move(message));
     209        1101 :     return Error(std::move(result));
     210             :   }
     211             : 
     212        1431 :   void ProcessModuleHeader() {
     213        2862 :     if (!ok_) return;
     214             :     ok_ &= processor_->ProcessModuleHeader(
     215        1431 :         Vector<const uint8_t>(state_->buffer(),
     216        1431 :                               static_cast<int>(state_->size())),
     217        4293 :         0);
     218             :   }
     219             : 
     220        1974 :   void ProcessSection(SectionBuffer* buffer) {
     221        1974 :     if (!ok_) return;
     222             :     ok_ &= processor_->ProcessSection(
     223             :         buffer->section_code(), buffer->payload(),
     224             :         buffer->module_offset() +
     225        2961 :             static_cast<uint32_t>(buffer->payload_offset()));
     226             :   }
     227             : 
     228         968 :   void StartCodeSection(size_t num_functions) {
     229         968 :     if (!ok_) return;
     230             :     // The offset passed to {ProcessCodeSectionHeader} is an error offset and
     231             :     // not the start offset of a buffer. Therefore we need the -1 here.
     232             :     ok_ &= processor_->ProcessCodeSectionHeader(num_functions,
     233         968 :                                                 module_offset() - 1);
     234             :   }
     235             : 
     236             :   void ProcessFunctionBody(Vector<const uint8_t> bytes,
     237             :                            uint32_t module_offset) {
     238         791 :     if (!ok_) return;
     239         791 :     ok_ &= processor_->ProcessFunctionBody(bytes, module_offset);
     240             :   }
     241             : 
     242             :   bool ok() const { return ok_; }
     243             : 
     244             :   uint32_t module_offset() const { return module_offset_; }
     245             : 
     246             :   std::unique_ptr<StreamingProcessor> processor_;
     247             :   bool ok_ = true;
     248             :   std::unique_ptr<DecodingState> state_;
     249             :   std::vector<std::unique_ptr<SectionBuffer>> section_buffers_;
     250             :   uint32_t module_offset_ = 0;
     251             :   size_t total_size_ = 0;
     252             :   uint8_t next_section_id_ = kFirstSectionInModule;
     253             : 
     254             :   DISALLOW_COPY_AND_ASSIGN(StreamingDecoder);
     255             : };
     256             : 
     257             : }  // namespace wasm
     258             : }  // namespace internal
     259             : }  // namespace v8
     260             : 
     261             : #endif  // V8_WASM_STREAMING_DECODER_H_

Generated by: LCOV version 1.10