• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
NotifyCompilationEnded()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.
SectionBuffer(uint32_t module_offset,uint8_t id,size_t payload_length,Vector<const uint8_t> length_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 
section_code()99     SectionCode section_code() const {
100       return static_cast<SectionCode>(bytes_[0]);
101     }
102 
module_offset()103     uint32_t module_offset() const { return module_offset_; }
bytes()104     uint8_t* bytes() const { return bytes_.get(); }
length()105     size_t length() const { return length_; }
payload_offset()106     size_t payload_offset() const { return payload_offset_; }
payload_length()107     size_t payload_length() const { return length_ - payload_offset_; }
payload()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.
offset()163     size_t offset() const { return offset_; }
set_offset(size_t value)164     void set_offset(size_t value) { offset_ = value; }
165     // The number of bytes which are still needed.
remaining()166     size_t remaining() const { return size() - offset(); }
is_finished()167     bool is_finished() const { return offset() == size(); }
168     // A flag to indicate if finishing the streaming decoder is allowed without
169     // error.
is_finishing_allowed()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.
CreateNewBuffer(uint32_t module_offset,uint8_t id,size_t length,Vector<const uint8_t> length_bytes)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 
Error(DecodeResult result)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 
Error(std::string message)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 
ProcessModuleHeader()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 
ProcessSection(SectionBuffer * buffer)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 
StartCodeSection(size_t num_functions)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 
ProcessFunctionBody(Vector<const uint8_t> bytes,uint32_t module_offset)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 
ok()252   bool ok() const { return ok_; }
253 
module_offset()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