Home | History | Annotate | Download | only in wasm
      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 class V8_EXPORT_PRIVATE StreamingProcessor {
     20  public:
     21   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(OwnedVector<uint8_t> bytes) = 0;
     48   // Report an error detected in the StreamingDecoder.
     49   virtual void OnError(DecodeResult result) = 0;
     50   // Report the abortion of the stream.
     51   virtual void OnAbort() = 0;
     52 };
     53 
     54 // The StreamingDecoder takes a sequence of byte arrays, each received by a call
     55 // of {OnBytesReceived}, and extracts the bytes which belong to section payloads
     56 // and function bodies.
     57 class V8_EXPORT_PRIVATE StreamingDecoder {
     58  public:
     59   explicit StreamingDecoder(std::unique_ptr<StreamingProcessor> processor);
     60 
     61   // The buffer passed into OnBytesReceived is owned by the caller.
     62   void OnBytesReceived(Vector<const uint8_t> bytes);
     63 
     64   void Finish();
     65 
     66   void Abort();
     67 
     68   // Notify the StreamingDecoder that compilation ended and the
     69   // StreamingProcessor should not be called anymore.
     70   void NotifyCompilationEnded() {
     71     // We set {ok_} to false to turn all future calls to the StreamingDecoder
     72     // into no-ops.
     73     ok_ = false;
     74   }
     75 
     76  private:
     77   // TODO(ahaas): Put the whole private state of the StreamingDecoder into the
     78   // cc file (PIMPL design pattern).
     79 
     80   // The SectionBuffer is the data object for the content of a single section.
     81   // It stores all bytes of the section (including section id and section
     82   // length), and the offset where the actual payload starts.
     83   class SectionBuffer {
     84    public:
     85     // id: The section id.
     86     // payload_length: The length of the payload.
     87     // length_bytes: The section length, as it is encoded in the module bytes.
     88     SectionBuffer(uint32_t module_offset, uint8_t id, size_t payload_length,
     89                   Vector<const uint8_t> length_bytes)
     90         :  // ID + length + payload
     91           module_offset_(module_offset),
     92           length_(1 + length_bytes.length() + payload_length),
     93           bytes_(new uint8_t[length_]),
     94           payload_offset_(1 + length_bytes.length()) {
     95       bytes_[0] = id;
     96       memcpy(bytes_.get() + 1, &length_bytes.first(), length_bytes.length());
     97     }
     98 
     99     SectionCode section_code() const {
    100       return static_cast<SectionCode>(bytes_[0]);
    101     }
    102 
    103     uint32_t module_offset() const { return module_offset_; }
    104     uint8_t* bytes() const { return bytes_.get(); }
    105     size_t length() const { return length_; }
    106     size_t payload_offset() const { return payload_offset_; }
    107     size_t payload_length() const { return length_ - payload_offset_; }
    108     Vector<const uint8_t> payload() const {
    109       return Vector<const uint8_t>(bytes() + payload_offset(),
    110                                    payload_length());
    111     }
    112 
    113    private:
    114     uint32_t module_offset_;
    115     size_t length_;
    116     std::unique_ptr<uint8_t[]> bytes_;
    117     size_t payload_offset_;
    118   };
    119 
    120   // The decoding of a stream of wasm module bytes is organized in states. Each
    121   // state provides a buffer to store the bytes required for the current state,
    122   // information on how many bytes have already been received, how many bytes
    123   // are needed, and a {Next} function which starts the next state once all
    124   // bytes of the current state were received.
    125   //
    126   // The states change according to the following state diagram:
    127   //
    128   //       Start
    129   //         |
    130   //         |
    131   //         v
    132   // DecodeModuleHeader
    133   //         |   _________________________________________
    134   //         |   |                                        |
    135   //         v   v                                        |
    136   //  DecodeSectionID --> DecodeSectionLength --> DecodeSectionPayload
    137   //         A                  |
    138   //         |                  | (if the section id == code)
    139   //         |                  v
    140   //         |      DecodeNumberOfFunctions -- > DecodeFunctionLength
    141   //         |                                          A    |
    142   //         |                                          |    |
    143   //         |  (after all functions were read)         |    v
    144   //         ------------------------------------- DecodeFunctionBody
    145   //
    146   class DecodingState {
    147    public:
    148     virtual ~DecodingState() = default;
    149 
    150     // Reads the bytes for the current state and returns the number of read
    151     // bytes.
    152     virtual size_t ReadBytes(StreamingDecoder* streaming,
    153                              Vector<const uint8_t> bytes);
    154 
    155     // Returns the next state of the streaming decoding.
    156     virtual std::unique_ptr<DecodingState> Next(
    157         StreamingDecoder* streaming) = 0;
    158     // The number of bytes to be received.
    159     virtual size_t size() const = 0;
    160     // The buffer to store the received bytes.
    161     virtual uint8_t* buffer() = 0;
    162     // The number of bytes which were already received.
    163     size_t offset() const { return offset_; }
    164     void set_offset(size_t value) { offset_ = value; }
    165     // The number of bytes which are still needed.
    166     size_t remaining() const { return size() - offset(); }
    167     bool is_finished() const { return offset() == size(); }
    168     // A flag to indicate if finishing the streaming decoder is allowed without
    169     // error.
    170     virtual bool is_finishing_allowed() const { return false; }
    171 
    172    private:
    173     size_t offset_ = 0;
    174   };
    175 
    176   // Forward declarations of the concrete states. This is needed so that they
    177   // can access private members of the StreamingDecoder.
    178   class DecodeVarInt32;
    179   class DecodeModuleHeader;
    180   class DecodeSectionID;
    181   class DecodeSectionLength;
    182   class DecodeSectionPayload;
    183   class DecodeNumberOfFunctions;
    184   class DecodeFunctionLength;
    185   class DecodeFunctionBody;
    186 
    187   // Creates a buffer for the next section of the module.
    188   SectionBuffer* CreateNewBuffer(uint32_t module_offset, uint8_t id,
    189                                  size_t length,
    190                                  Vector<const uint8_t> length_bytes) {
    191     // Check the order of sections. Unknown sections can appear at any position.
    192     if (id != kUnknownSectionCode) {
    193       if (id < next_section_id_) {
    194         Error("Unexpected section");
    195         return nullptr;
    196       }
    197       next_section_id_ = id + 1;
    198     }
    199     section_buffers_.emplace_back(
    200         new SectionBuffer(module_offset, id, length, length_bytes));
    201     return section_buffers_.back().get();
    202   }
    203 
    204   std::unique_ptr<DecodingState> Error(DecodeResult result) {
    205     if (ok_) processor_->OnError(std::move(result));
    206     ok_ = false;
    207     return std::unique_ptr<DecodingState>(nullptr);
    208   }
    209 
    210   std::unique_ptr<DecodingState> Error(std::string message) {
    211     DecodeResult result(nullptr);
    212     result.error(module_offset_ - 1, std::move(message));
    213     return Error(std::move(result));
    214   }
    215 
    216   void ProcessModuleHeader() {
    217     if (!ok_) return;
    218     if (!processor_->ProcessModuleHeader(
    219             Vector<const uint8_t>(state_->buffer(),
    220                                   static_cast<int>(state_->size())),
    221             0)) {
    222       ok_ = false;
    223     }
    224   }
    225 
    226   void ProcessSection(SectionBuffer* buffer) {
    227     if (!ok_) return;
    228     if (!processor_->ProcessSection(
    229             buffer->section_code(), buffer->payload(),
    230             buffer->module_offset() +
    231                 static_cast<uint32_t>(buffer->payload_offset()))) {
    232       ok_ = false;
    233     }
    234   }
    235 
    236   void StartCodeSection(size_t num_functions) {
    237     if (!ok_) return;
    238     // The offset passed to {ProcessCodeSectionHeader} is an error offset and
    239     // not the start offset of a buffer. Therefore we need the -1 here.
    240     if (!processor_->ProcessCodeSectionHeader(num_functions,
    241                                               module_offset() - 1)) {
    242       ok_ = false;
    243     }
    244   }
    245 
    246   void ProcessFunctionBody(Vector<const uint8_t> bytes,
    247                            uint32_t module_offset) {
    248     if (!ok_) return;
    249     if (!processor_->ProcessFunctionBody(bytes, module_offset)) ok_ = false;
    250   }
    251 
    252   bool ok() const { return ok_; }
    253 
    254   uint32_t module_offset() const { return module_offset_; }
    255 
    256   std::unique_ptr<StreamingProcessor> processor_;
    257   bool ok_ = true;
    258   std::unique_ptr<DecodingState> state_;
    259   std::vector<std::unique_ptr<SectionBuffer>> section_buffers_;
    260   uint32_t module_offset_ = 0;
    261   size_t total_size_ = 0;
    262   uint8_t next_section_id_ = kFirstSectionInModule;
    263 
    264   DISALLOW_COPY_AND_ASSIGN(StreamingDecoder);
    265 };
    266 
    267 }  // namespace wasm
    268 }  // namespace internal
    269 }  // namespace v8
    270 
    271 #endif  // V8_WASM_STREAMING_DECODER_H_
    272