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