LCOV - code coverage report
Current view: top level - src/wasm - streaming-decoder.h (source / functions) Hit Total Coverage
Test: app.info Lines: 38 38 100.0 %
Date: 2019-04-17 Functions: 11 12 91.7 %

          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 <memory>
       9             : #include <vector>
      10             : 
      11             : #include "src/base/macros.h"
      12             : #include "src/vector.h"
      13             : #include "src/wasm/compilation-environment.h"
      14             : #include "src/wasm/wasm-constants.h"
      15             : #include "src/wasm/wasm-result.h"
      16             : 
      17             : namespace v8 {
      18             : namespace internal {
      19             : namespace wasm {
      20             : class NativeModule;
      21             : 
      22             : // This class is an interface for the StreamingDecoder to start the processing
      23             : // of the incoming module bytes.
      24        1582 : class V8_EXPORT_PRIVATE StreamingProcessor {
      25             :  public:
      26        1582 :   virtual ~StreamingProcessor() = default;
      27             :   // Process the first 8 bytes of a WebAssembly module. Returns true if the
      28             :   // processing finished successfully and the decoding should continue.
      29             :   virtual bool ProcessModuleHeader(Vector<const uint8_t> bytes,
      30             :                                    uint32_t offset) = 0;
      31             : 
      32             :   // Process all sections but the code section. Returns true if the processing
      33             :   // finished successfully and the decoding should continue.
      34             :   virtual bool ProcessSection(SectionCode section_code,
      35             :                               Vector<const uint8_t> bytes, uint32_t offset) = 0;
      36             : 
      37             :   // Process the start of the code section. Returns true if the processing
      38             :   // finished successfully and the decoding should continue.
      39             :   virtual bool ProcessCodeSectionHeader(int num_functions, uint32_t offset,
      40             :                                         std::shared_ptr<WireBytesStorage>) = 0;
      41             : 
      42             :   // Process a function body. Returns true if the processing finished
      43             :   // successfully and the decoding should continue.
      44             :   virtual bool ProcessFunctionBody(Vector<const uint8_t> bytes,
      45             :                                    uint32_t offset) = 0;
      46             : 
      47             :   // Report the end of a chunk.
      48             :   virtual void OnFinishedChunk() = 0;
      49             :   // Report the end of the stream. If the stream was successful, all
      50             :   // received bytes are passed by parameter. If there has been an error, an
      51             :   // empty array is passed.
      52             :   virtual void OnFinishedStream(OwnedVector<uint8_t> bytes) = 0;
      53             :   // Report an error detected in the StreamingDecoder.
      54             :   virtual void OnError(const WasmError&) = 0;
      55             :   // Report the abortion of the stream.
      56             :   virtual void OnAbort() = 0;
      57             : 
      58             :   // Attempt to deserialize the module. Supports embedder caching.
      59             :   virtual bool Deserialize(Vector<const uint8_t> module_bytes,
      60             :                            Vector<const uint8_t> wire_bytes) = 0;
      61             : };
      62             : 
      63             : // The StreamingDecoder takes a sequence of byte arrays, each received by a call
      64             : // of {OnBytesReceived}, and extracts the bytes which belong to section payloads
      65             : // and function bodies.
      66        4746 : class V8_EXPORT_PRIVATE StreamingDecoder {
      67             :  public:
      68             :   explicit StreamingDecoder(std::unique_ptr<StreamingProcessor> processor);
      69             : 
      70             :   // The buffer passed into OnBytesReceived is owned by the caller.
      71             :   void OnBytesReceived(Vector<const uint8_t> bytes);
      72             : 
      73             :   void Finish();
      74             : 
      75             :   void Abort();
      76             : 
      77             :   // Notify the StreamingDecoder that compilation ended and the
      78             :   // StreamingProcessor should not be called anymore.
      79             :   void NotifyCompilationEnded() { Fail(); }
      80             : 
      81             :   // Caching support.
      82             :   // Sets the callback that is called after the module is fully compiled.
      83             :   using ModuleCompiledCallback =
      84             :       std::function<void(const std::shared_ptr<NativeModule>&)>;
      85             :   void SetModuleCompiledCallback(ModuleCompiledCallback callback);
      86             :   // Passes previously compiled module bytes from the embedder's cache.
      87             :   bool SetCompiledModuleBytes(Vector<const uint8_t> compiled_module_bytes);
      88             : 
      89             :   void NotifyNativeModuleCreated(
      90             :       const std::shared_ptr<NativeModule>& native_module);
      91             : 
      92             :  private:
      93             :   // TODO(ahaas): Put the whole private state of the StreamingDecoder into the
      94             :   // cc file (PIMPL design pattern).
      95             : 
      96             :   // The SectionBuffer is the data object for the content of a single section.
      97             :   // It stores all bytes of the section (including section id and section
      98             :   // length), and the offset where the actual payload starts.
      99        4062 :   class SectionBuffer : public WireBytesStorage {
     100             :    public:
     101             :     // id: The section id.
     102             :     // payload_length: The length of the payload.
     103             :     // length_bytes: The section length, as it is encoded in the module bytes.
     104        2031 :     SectionBuffer(uint32_t module_offset, uint8_t id, size_t payload_length,
     105             :                   Vector<const uint8_t> length_bytes)
     106             :         :  // ID + length + payload
     107             :           module_offset_(module_offset),
     108        2031 :           bytes_(OwnedVector<uint8_t>::New(1 + length_bytes.length() +
     109             :                                            payload_length)),
     110        6093 :           payload_offset_(1 + length_bytes.length()) {
     111        2031 :       bytes_.start()[0] = id;
     112        4062 :       memcpy(bytes_.start() + 1, &length_bytes.first(), length_bytes.length());
     113        2031 :     }
     114             : 
     115             :     SectionCode section_code() const {
     116        1329 :       return static_cast<SectionCode>(bytes_.start()[0]);
     117             :     }
     118             : 
     119         313 :     Vector<const uint8_t> GetCode(WireBytesRef ref) const final {
     120             :       DCHECK_LE(module_offset_, ref.offset());
     121         313 :       uint32_t offset_in_code_buffer = ref.offset() - module_offset_;
     122             :       return bytes().SubVector(offset_in_code_buffer,
     123         626 :                                offset_in_code_buffer + ref.length());
     124             :     }
     125             : 
     126             :     uint32_t module_offset() const { return module_offset_; }
     127             :     Vector<uint8_t> bytes() const { return bytes_.as_vector(); }
     128        3340 :     Vector<uint8_t> payload() const { return bytes() + payload_offset_; }
     129             :     size_t length() const { return bytes_.size(); }
     130             :     size_t payload_offset() const { return payload_offset_; }
     131             : 
     132             :    private:
     133             :     const uint32_t module_offset_;
     134             :     const OwnedVector<uint8_t> bytes_;
     135             :     const size_t payload_offset_;
     136             :   };
     137             : 
     138             :   // The decoding of a stream of wasm module bytes is organized in states. Each
     139             :   // state provides a buffer to store the bytes required for the current state,
     140             :   // information on how many bytes have already been received, how many bytes
     141             :   // are needed, and a {Next} function which starts the next state once all
     142             :   // bytes of the current state were received.
     143             :   //
     144             :   // The states change according to the following state diagram:
     145             :   //
     146             :   //       Start
     147             :   //         |
     148             :   //         |
     149             :   //         v
     150             :   // DecodeModuleHeader
     151             :   //         |   _________________________________________
     152             :   //         |   |                                        |
     153             :   //         v   v                                        |
     154             :   //  DecodeSectionID --> DecodeSectionLength --> DecodeSectionPayload
     155             :   //         A                  |
     156             :   //         |                  | (if the section id == code)
     157             :   //         |                  v
     158             :   //         |      DecodeNumberOfFunctions -- > DecodeFunctionLength
     159             :   //         |                                          A    |
     160             :   //         |                                          |    |
     161             :   //         |  (after all functions were read)         |    v
     162             :   //         ------------------------------------- DecodeFunctionBody
     163             :   //
     164        9959 :   class DecodingState {
     165             :    public:
     166        6309 :     virtual ~DecodingState() = default;
     167             : 
     168             :     // Reads the bytes for the current state and returns the number of read
     169             :     // bytes.
     170             :     virtual size_t ReadBytes(StreamingDecoder* streaming,
     171             :                              Vector<const uint8_t> bytes);
     172             : 
     173             :     // Returns the next state of the streaming decoding.
     174             :     virtual std::unique_ptr<DecodingState> Next(
     175             :         StreamingDecoder* streaming) = 0;
     176             :     // The buffer to store the received bytes.
     177             :     virtual Vector<uint8_t> buffer() = 0;
     178             :     // The number of bytes which were already received.
     179             :     size_t offset() const { return offset_; }
     180       10192 :     void set_offset(size_t value) { offset_ = value; }
     181             :     // A flag to indicate if finishing the streaming decoder is allowed without
     182             :     // error.
     183          95 :     virtual bool is_finishing_allowed() const { return false; }
     184             : 
     185             :    private:
     186             :     size_t offset_ = 0;
     187             :   };
     188             : 
     189             :   // Forward declarations of the concrete states. This is needed so that they
     190             :   // can access private members of the StreamingDecoder.
     191             :   class DecodeVarInt32;
     192             :   class DecodeModuleHeader;
     193             :   class DecodeSectionID;
     194             :   class DecodeSectionLength;
     195             :   class DecodeSectionPayload;
     196             :   class DecodeNumberOfFunctions;
     197             :   class DecodeFunctionLength;
     198             :   class DecodeFunctionBody;
     199             : 
     200             :   // Creates a buffer for the next section of the module.
     201             :   SectionBuffer* CreateNewBuffer(uint32_t module_offset, uint8_t section_id,
     202             :                                  size_t length,
     203             :                                  Vector<const uint8_t> length_bytes);
     204             : 
     205         406 :   std::unique_ptr<DecodingState> Error(const WasmError& error) {
     206         406 :     if (ok()) processor_->OnError(error);
     207             :     Fail();
     208         406 :     return std::unique_ptr<DecodingState>(nullptr);
     209             :   }
     210             : 
     211         367 :   std::unique_ptr<DecodingState> Error(std::string message) {
     212        1468 :     return Error(WasmError{module_offset_ - 1, std::move(message)});
     213             :   }
     214             : 
     215        1501 :   void ProcessModuleHeader() {
     216        1501 :     if (!ok()) return;
     217        4503 :     if (!processor_->ProcessModuleHeader(state_->buffer(), 0)) Fail();
     218             :   }
     219             : 
     220        1329 :   void ProcessSection(SectionBuffer* buffer) {
     221        1329 :     if (!ok()) return;
     222        2658 :     if (!processor_->ProcessSection(
     223             :             buffer->section_code(), buffer->payload(),
     224             :             buffer->module_offset() +
     225        1329 :                 static_cast<uint32_t>(buffer->payload_offset()))) {
     226             :       Fail();
     227             :     }
     228             :   }
     229             : 
     230         536 :   void StartCodeSection(int num_functions,
     231             :                         std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
     232         536 :     if (!ok()) return;
     233             :     // The offset passed to {ProcessCodeSectionHeader} is an error offset and
     234             :     // not the start offset of a buffer. Therefore we need the -1 here.
     235        1072 :     if (!processor_->ProcessCodeSectionHeader(num_functions,
     236             :                                               module_offset() - 1,
     237         536 :                                               std::move(wire_bytes_storage))) {
     238             :       Fail();
     239             :     }
     240             :   }
     241             : 
     242         849 :   void ProcessFunctionBody(Vector<const uint8_t> bytes,
     243             :                            uint32_t module_offset) {
     244         849 :     if (!ok()) return;
     245         849 :     if (!processor_->ProcessFunctionBody(bytes, module_offset)) Fail();
     246             :   }
     247             : 
     248             :   void Fail() {
     249             :     // We reset the {processor_} field to represent failure. This also ensures
     250             :     // that we do not accidentally call further methods on the processor after
     251             :     // failure.
     252             :     processor_.reset();
     253             :   }
     254             : 
     255             :   bool ok() const { return processor_ != nullptr; }
     256             : 
     257             :   uint32_t module_offset() const { return module_offset_; }
     258             : 
     259             :   bool deserializing() const { return !compiled_module_bytes_.empty(); }
     260             : 
     261             :   std::unique_ptr<StreamingProcessor> processor_;
     262             :   std::unique_ptr<DecodingState> state_;
     263             :   std::vector<std::shared_ptr<SectionBuffer>> section_buffers_;
     264             :   bool code_section_processed_ = false;
     265             :   uint32_t module_offset_ = 0;
     266             :   size_t total_size_ = 0;
     267             : 
     268             :   // Caching support.
     269             :   ModuleCompiledCallback module_compiled_callback_ = nullptr;
     270             :   // We need wire bytes in an array for deserializing cached modules.
     271             :   std::vector<uint8_t> wire_bytes_for_deserializing_;
     272             :   Vector<const uint8_t> compiled_module_bytes_;
     273             : 
     274             :   DISALLOW_COPY_AND_ASSIGN(StreamingDecoder);
     275             : };
     276             : 
     277             : }  // namespace wasm
     278             : }  // namespace internal
     279             : }  // namespace v8
     280             : 
     281             : #endif  // V8_WASM_STREAMING_DECODER_H_

Generated by: LCOV version 1.10