• 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 #include "src/wasm/streaming-decoder.h"
6 
7 #include "src/base/platform/wrappers.h"
8 #include "src/handles/handles.h"
9 #include "src/objects/descriptor-array.h"
10 #include "src/objects/dictionary.h"
11 #include "src/objects/objects-inl.h"
12 #include "src/wasm/decoder.h"
13 #include "src/wasm/leb-helper.h"
14 #include "src/wasm/module-decoder.h"
15 #include "src/wasm/wasm-code-manager.h"
16 #include "src/wasm/wasm-limits.h"
17 #include "src/wasm/wasm-objects.h"
18 #include "src/wasm/wasm-result.h"
19 
20 #define TRACE_STREAMING(...)                            \
21   do {                                                  \
22     if (FLAG_trace_wasm_streaming) PrintF(__VA_ARGS__); \
23   } while (false)
24 
25 namespace v8 {
26 namespace internal {
27 namespace wasm {
28 
29 class V8_EXPORT_PRIVATE AsyncStreamingDecoder : public StreamingDecoder {
30  public:
31   explicit AsyncStreamingDecoder(std::unique_ptr<StreamingProcessor> processor);
32   AsyncStreamingDecoder(const AsyncStreamingDecoder&) = delete;
33   AsyncStreamingDecoder& operator=(const AsyncStreamingDecoder&) = delete;
34 
35   // The buffer passed into OnBytesReceived is owned by the caller.
36   void OnBytesReceived(base::Vector<const uint8_t> bytes) override;
37 
38   void Finish(bool can_use_compiled_module) override;
39 
40   void Abort() override;
41 
42   // Notify the StreamingDecoder that compilation ended and the
43   // StreamingProcessor should not be called anymore.
NotifyCompilationEnded()44   void NotifyCompilationEnded() override { Fail(); }
45 
46   void NotifyNativeModuleCreated(
47       const std::shared_ptr<NativeModule>& native_module) override;
48 
49  private:
50   // The SectionBuffer is the data object for the content of a single section.
51   // It stores all bytes of the section (including section id and section
52   // length), and the offset where the actual payload starts.
53   class SectionBuffer : public WireBytesStorage {
54    public:
55     // id: The section id.
56     // payload_length: The length of the payload.
57     // 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,base::Vector<const uint8_t> length_bytes)58     SectionBuffer(uint32_t module_offset, uint8_t id, size_t payload_length,
59                   base::Vector<const uint8_t> length_bytes)
60         :  // ID + length + payload
61           module_offset_(module_offset),
62           bytes_(base::OwnedVector<uint8_t>::NewForOverwrite(
63               1 + length_bytes.length() + payload_length)),
64           payload_offset_(1 + length_bytes.length()) {
65       bytes_.start()[0] = id;
66       memcpy(bytes_.start() + 1, &length_bytes.first(), length_bytes.length());
67     }
68 
section_code() const69     SectionCode section_code() const {
70       return static_cast<SectionCode>(bytes_.start()[0]);
71     }
72 
GetCode(WireBytesRef ref) const73     base::Vector<const uint8_t> GetCode(WireBytesRef ref) const final {
74       DCHECK_LE(module_offset_, ref.offset());
75       uint32_t offset_in_code_buffer = ref.offset() - module_offset_;
76       return bytes().SubVector(offset_in_code_buffer,
77                                offset_in_code_buffer + ref.length());
78     }
79 
GetModuleBytes() const80     base::Optional<ModuleWireBytes> GetModuleBytes() const final { return {}; }
81 
module_offset() const82     uint32_t module_offset() const { return module_offset_; }
bytes() const83     base::Vector<uint8_t> bytes() const { return bytes_.as_vector(); }
payload() const84     base::Vector<uint8_t> payload() const { return bytes() + payload_offset_; }
length() const85     size_t length() const { return bytes_.size(); }
payload_offset() const86     size_t payload_offset() const { return payload_offset_; }
87 
88    private:
89     const uint32_t module_offset_;
90     const base::OwnedVector<uint8_t> bytes_;
91     const size_t payload_offset_;
92   };
93 
94   // The decoding of a stream of wasm module bytes is organized in states. Each
95   // state provides a buffer to store the bytes required for the current state,
96   // information on how many bytes have already been received, how many bytes
97   // are needed, and a {Next} function which starts the next state once all
98   // bytes of the current state were received.
99   //
100   // The states change according to the following state diagram:
101   //
102   //       Start
103   //         |
104   //         |
105   //         v
106   // DecodeModuleHeader
107   //         |   _________________________________________
108   //         |   |                                        |
109   //         v   v                                        |
110   //  DecodeSectionID --> DecodeSectionLength --> DecodeSectionPayload
111   //         A                  |
112   //         |                  | (if the section id == code)
113   //         |                  v
114   //         |      DecodeNumberOfFunctions -- > DecodeFunctionLength
115   //         |                                          A    |
116   //         |                                          |    |
117   //         |  (after all functions were read)         |    v
118   //         ------------------------------------- DecodeFunctionBody
119   //
120   class DecodingState {
121    public:
122     virtual ~DecodingState() = default;
123 
124     // Reads the bytes for the current state and returns the number of read
125     // bytes.
126     virtual size_t ReadBytes(AsyncStreamingDecoder* streaming,
127                              base::Vector<const uint8_t> bytes);
128 
129     // Returns the next state of the streaming decoding.
130     virtual std::unique_ptr<DecodingState> Next(
131         AsyncStreamingDecoder* streaming) = 0;
132     // The buffer to store the received bytes.
133     virtual base::Vector<uint8_t> buffer() = 0;
134     // The number of bytes which were already received.
offset() const135     size_t offset() const { return offset_; }
set_offset(size_t value)136     void set_offset(size_t value) { offset_ = value; }
137     // A flag to indicate if finishing the streaming decoder is allowed without
138     // error.
is_finishing_allowed() const139     virtual bool is_finishing_allowed() const { return false; }
140 
141    private:
142     size_t offset_ = 0;
143   };
144 
145   // Forward declarations of the concrete states. This is needed so that they
146   // can access private members of the AsyncStreamingDecoder.
147   class DecodeVarInt32;
148   class DecodeModuleHeader;
149   class DecodeSectionID;
150   class DecodeSectionLength;
151   class DecodeSectionPayload;
152   class DecodeNumberOfFunctions;
153   class DecodeFunctionLength;
154   class DecodeFunctionBody;
155 
156   // Creates a buffer for the next section of the module.
157   SectionBuffer* CreateNewBuffer(uint32_t module_offset, uint8_t section_id,
158                                  size_t length,
159                                  base::Vector<const uint8_t> length_bytes);
160 
Error(const WasmError & error)161   std::unique_ptr<DecodingState> Error(const WasmError& error) {
162     if (ok()) processor_->OnError(error);
163     Fail();
164     return std::unique_ptr<DecodingState>(nullptr);
165   }
166 
Error(std::string message)167   std::unique_ptr<DecodingState> Error(std::string message) {
168     return Error(WasmError{module_offset_ - 1, std::move(message)});
169   }
170 
ProcessModuleHeader()171   void ProcessModuleHeader() {
172     if (!ok()) return;
173     if (!processor_->ProcessModuleHeader(state_->buffer(), 0)) Fail();
174   }
175 
ProcessSection(SectionBuffer * buffer)176   void ProcessSection(SectionBuffer* buffer) {
177     if (!ok()) return;
178     if (!processor_->ProcessSection(
179             buffer->section_code(), buffer->payload(),
180             buffer->module_offset() +
181                 static_cast<uint32_t>(buffer->payload_offset()))) {
182       Fail();
183     }
184   }
185 
StartCodeSection(int num_functions,std::shared_ptr<WireBytesStorage> wire_bytes_storage,int code_section_start,int code_section_length)186   void StartCodeSection(int num_functions,
187                         std::shared_ptr<WireBytesStorage> wire_bytes_storage,
188                         int code_section_start, int code_section_length) {
189     if (!ok()) return;
190     // The offset passed to {ProcessCodeSectionHeader} is an error offset and
191     // not the start offset of a buffer. Therefore we need the -1 here.
192     if (!processor_->ProcessCodeSectionHeader(
193             num_functions, module_offset() - 1, std::move(wire_bytes_storage),
194             code_section_start, code_section_length)) {
195       Fail();
196     }
197   }
198 
ProcessFunctionBody(base::Vector<const uint8_t> bytes,uint32_t module_offset)199   void ProcessFunctionBody(base::Vector<const uint8_t> bytes,
200                            uint32_t module_offset) {
201     if (!ok()) return;
202     if (!processor_->ProcessFunctionBody(bytes, module_offset)) Fail();
203   }
204 
Fail()205   void Fail() {
206     // We reset the {processor_} field to represent failure. This also ensures
207     // that we do not accidentally call further methods on the processor after
208     // failure.
209     processor_.reset();
210   }
211 
ok() const212   bool ok() const { return processor_ != nullptr; }
213 
module_offset() const214   uint32_t module_offset() const { return module_offset_; }
215 
216   std::unique_ptr<StreamingProcessor> processor_;
217   std::unique_ptr<DecodingState> state_;
218   std::vector<std::shared_ptr<SectionBuffer>> section_buffers_;
219   bool code_section_processed_ = false;
220   uint32_t module_offset_ = 0;
221   size_t total_size_ = 0;
222   bool stream_finished_ = false;
223 
224   // We need wire bytes in an array for deserializing cached modules.
225   std::vector<uint8_t> wire_bytes_for_deserializing_;
226 };
227 
OnBytesReceived(base::Vector<const uint8_t> bytes)228 void AsyncStreamingDecoder::OnBytesReceived(base::Vector<const uint8_t> bytes) {
229   if (deserializing()) {
230     wire_bytes_for_deserializing_.insert(wire_bytes_for_deserializing_.end(),
231                                          bytes.begin(), bytes.end());
232     return;
233   }
234 
235   TRACE_STREAMING("OnBytesReceived(%zu bytes)\n", bytes.size());
236 
237   size_t current = 0;
238   while (ok() && current < bytes.size()) {
239     size_t num_bytes =
240         state_->ReadBytes(this, bytes.SubVector(current, bytes.size()));
241     current += num_bytes;
242     module_offset_ += num_bytes;
243     if (state_->offset() == state_->buffer().size()) {
244       state_ = state_->Next(this);
245     }
246   }
247   total_size_ += bytes.size();
248   if (ok()) {
249     processor_->OnFinishedChunk();
250   }
251 }
252 
ReadBytes(AsyncStreamingDecoder * streaming,base::Vector<const uint8_t> bytes)253 size_t AsyncStreamingDecoder::DecodingState::ReadBytes(
254     AsyncStreamingDecoder* streaming, base::Vector<const uint8_t> bytes) {
255   base::Vector<uint8_t> remaining_buf = buffer() + offset();
256   size_t num_bytes = std::min(bytes.size(), remaining_buf.size());
257   TRACE_STREAMING("ReadBytes(%zu bytes)\n", num_bytes);
258   memcpy(remaining_buf.begin(), &bytes.first(), num_bytes);
259   set_offset(offset() + num_bytes);
260   return num_bytes;
261 }
262 
Finish(bool can_use_compiled_module)263 void AsyncStreamingDecoder::Finish(bool can_use_compiled_module) {
264   TRACE_STREAMING("Finish\n");
265   DCHECK(!stream_finished_);
266   stream_finished_ = true;
267   if (!ok()) return;
268 
269   if (deserializing()) {
270     base::Vector<const uint8_t> wire_bytes =
271         base::VectorOf(wire_bytes_for_deserializing_);
272     // Try to deserialize the module from wire bytes and module bytes.
273     if (can_use_compiled_module &&
274         processor_->Deserialize(compiled_module_bytes_, wire_bytes))
275       return;
276 
277     // Compiled module bytes are invalidated by can_use_compiled_module = false
278     // or the deserialization failed. Restart decoding using |wire_bytes|.
279     compiled_module_bytes_ = {};
280     DCHECK(!deserializing());
281     OnBytesReceived(wire_bytes);
282     // The decoder has received all wire bytes; fall through and finish.
283   }
284 
285   if (!state_->is_finishing_allowed()) {
286     // The byte stream ended too early, we report an error.
287     Error("unexpected end of stream");
288     return;
289   }
290 
291   base::OwnedVector<uint8_t> bytes =
292       base::OwnedVector<uint8_t>::NewForOverwrite(total_size_);
293   uint8_t* cursor = bytes.start();
294   {
295 #define BYTES(x) (x & 0xFF), (x >> 8) & 0xFF, (x >> 16) & 0xFF, (x >> 24) & 0xFF
296     uint8_t module_header[]{BYTES(kWasmMagic), BYTES(kWasmVersion)};
297 #undef BYTES
298     memcpy(cursor, module_header, arraysize(module_header));
299     cursor += arraysize(module_header);
300   }
301   for (const auto& buffer : section_buffers_) {
302     DCHECK_LE(cursor - bytes.start() + buffer->length(), total_size_);
303     memcpy(cursor, buffer->bytes().begin(), buffer->length());
304     cursor += buffer->length();
305   }
306   processor_->OnFinishedStream(std::move(bytes));
307 }
308 
Abort()309 void AsyncStreamingDecoder::Abort() {
310   TRACE_STREAMING("Abort\n");
311   if (stream_finished_) return;
312   stream_finished_ = true;
313   if (!ok()) return;  // Failed already.
314   processor_->OnAbort();
315   Fail();
316 }
317 
318 namespace {
319 
320 class CompilationChunkFinishedCallback : public CompilationEventCallback {
321  public:
CompilationChunkFinishedCallback(std::weak_ptr<NativeModule> native_module,AsyncStreamingDecoder::ModuleCompiledCallback callback)322   CompilationChunkFinishedCallback(
323       std::weak_ptr<NativeModule> native_module,
324       AsyncStreamingDecoder::ModuleCompiledCallback callback)
325       : native_module_(std::move(native_module)),
326         callback_(std::move(callback)) {
327     // As a baseline we also count the modules that could be cached but
328     // never reach the threshold.
329     if (std::shared_ptr<NativeModule> module = native_module_.lock()) {
330       module->counters()->wasm_cache_count()->AddSample(0);
331     }
332   }
333 
call(CompilationEvent event)334   void call(CompilationEvent event) override {
335     if (event != CompilationEvent::kFinishedCompilationChunk &&
336         event != CompilationEvent::kFinishedTopTierCompilation) {
337       return;
338     }
339     // If the native module is still alive, get back a shared ptr and call the
340     // callback.
341     if (std::shared_ptr<NativeModule> native_module = native_module_.lock()) {
342       native_module->counters()->wasm_cache_count()->AddSample(++cache_count_);
343       callback_(native_module);
344     }
345   }
346 
release_after_final_event()347   ReleaseAfterFinalEvent release_after_final_event() override {
348     return CompilationEventCallback::ReleaseAfterFinalEvent::kKeep;
349   }
350 
351  private:
352   const std::weak_ptr<NativeModule> native_module_;
353   const AsyncStreamingDecoder::ModuleCompiledCallback callback_;
354   int cache_count_ = 0;
355 };
356 
357 }  // namespace
358 
NotifyNativeModuleCreated(const std::shared_ptr<NativeModule> & native_module)359 void AsyncStreamingDecoder::NotifyNativeModuleCreated(
360     const std::shared_ptr<NativeModule>& native_module) {
361   if (!module_compiled_callback_) return;
362   auto* comp_state = native_module->compilation_state();
363 
364   comp_state->AddCallback(std::make_unique<CompilationChunkFinishedCallback>(
365       std::move(native_module), std::move(module_compiled_callback_)));
366   module_compiled_callback_ = {};
367 }
368 
369 // An abstract class to share code among the states which decode VarInts. This
370 // class takes over the decoding of the VarInt and then calls the actual decode
371 // code with the decoded value.
372 class AsyncStreamingDecoder::DecodeVarInt32 : public DecodingState {
373  public:
DecodeVarInt32(size_t max_value,const char * field_name)374   explicit DecodeVarInt32(size_t max_value, const char* field_name)
375       : max_value_(max_value), field_name_(field_name) {}
376 
buffer()377   base::Vector<uint8_t> buffer() override {
378     return base::ArrayVector(byte_buffer_);
379   }
380 
381   size_t ReadBytes(AsyncStreamingDecoder* streaming,
382                    base::Vector<const uint8_t> bytes) override;
383 
384   std::unique_ptr<DecodingState> Next(
385       AsyncStreamingDecoder* streaming) override;
386 
387   virtual std::unique_ptr<DecodingState> NextWithValue(
388       AsyncStreamingDecoder* streaming) = 0;
389 
390  protected:
391   uint8_t byte_buffer_[kMaxVarInt32Size];
392   // The maximum valid value decoded in this state. {Next} returns an error if
393   // this value is exceeded.
394   const size_t max_value_;
395   const char* const field_name_;
396   size_t value_ = 0;
397   size_t bytes_consumed_ = 0;
398 };
399 
400 class AsyncStreamingDecoder::DecodeModuleHeader : public DecodingState {
401  public:
buffer()402   base::Vector<uint8_t> buffer() override {
403     return base::ArrayVector(byte_buffer_);
404   }
405 
406   std::unique_ptr<DecodingState> Next(
407       AsyncStreamingDecoder* streaming) override;
408 
409  private:
410   // Checks if the magic bytes of the module header are correct.
411   void CheckHeader(Decoder* decoder);
412 
413   // The size of the module header.
414   static constexpr size_t kModuleHeaderSize = 8;
415   uint8_t byte_buffer_[kModuleHeaderSize];
416 };
417 
418 class AsyncStreamingDecoder::DecodeSectionID : public DecodingState {
419  public:
DecodeSectionID(uint32_t module_offset)420   explicit DecodeSectionID(uint32_t module_offset)
421       : module_offset_(module_offset) {}
422 
buffer()423   base::Vector<uint8_t> buffer() override { return {&id_, 1}; }
is_finishing_allowed() const424   bool is_finishing_allowed() const override { return true; }
425 
426   std::unique_ptr<DecodingState> Next(
427       AsyncStreamingDecoder* streaming) override;
428 
429  private:
430   uint8_t id_ = 0;
431   // The start offset of this section in the module.
432   const uint32_t module_offset_;
433 };
434 
435 class AsyncStreamingDecoder::DecodeSectionLength : public DecodeVarInt32 {
436  public:
DecodeSectionLength(uint8_t id,uint32_t module_offset)437   explicit DecodeSectionLength(uint8_t id, uint32_t module_offset)
438       : DecodeVarInt32(max_module_size(), "section length"),
439         section_id_(id),
440         module_offset_(module_offset) {}
441 
442   std::unique_ptr<DecodingState> NextWithValue(
443       AsyncStreamingDecoder* streaming) override;
444 
445  private:
446   const uint8_t section_id_;
447   // The start offset of this section in the module.
448   const uint32_t module_offset_;
449 };
450 
451 class AsyncStreamingDecoder::DecodeSectionPayload : public DecodingState {
452  public:
DecodeSectionPayload(SectionBuffer * section_buffer)453   explicit DecodeSectionPayload(SectionBuffer* section_buffer)
454       : section_buffer_(section_buffer) {}
455 
buffer()456   base::Vector<uint8_t> buffer() override { return section_buffer_->payload(); }
457 
458   std::unique_ptr<DecodingState> Next(
459       AsyncStreamingDecoder* streaming) override;
460 
461  private:
462   SectionBuffer* const section_buffer_;
463 };
464 
465 class AsyncStreamingDecoder::DecodeNumberOfFunctions : public DecodeVarInt32 {
466  public:
DecodeNumberOfFunctions(SectionBuffer * section_buffer)467   explicit DecodeNumberOfFunctions(SectionBuffer* section_buffer)
468       : DecodeVarInt32(kV8MaxWasmFunctions, "functions count"),
469         section_buffer_(section_buffer) {}
470 
471   std::unique_ptr<DecodingState> NextWithValue(
472       AsyncStreamingDecoder* streaming) override;
473 
474  private:
475   SectionBuffer* const section_buffer_;
476 };
477 
478 class AsyncStreamingDecoder::DecodeFunctionLength : public DecodeVarInt32 {
479  public:
DecodeFunctionLength(SectionBuffer * section_buffer,size_t buffer_offset,size_t num_remaining_functions)480   explicit DecodeFunctionLength(SectionBuffer* section_buffer,
481                                 size_t buffer_offset,
482                                 size_t num_remaining_functions)
483       : DecodeVarInt32(kV8MaxWasmFunctionSize, "function body size"),
484         section_buffer_(section_buffer),
485         buffer_offset_(buffer_offset),
486         // We are reading a new function, so one function less is remaining.
487         num_remaining_functions_(num_remaining_functions - 1) {
488     DCHECK_GT(num_remaining_functions, 0);
489   }
490 
491   std::unique_ptr<DecodingState> NextWithValue(
492       AsyncStreamingDecoder* streaming) override;
493 
494  private:
495   SectionBuffer* const section_buffer_;
496   const size_t buffer_offset_;
497   const size_t num_remaining_functions_;
498 };
499 
500 class AsyncStreamingDecoder::DecodeFunctionBody : public DecodingState {
501  public:
DecodeFunctionBody(SectionBuffer * section_buffer,size_t buffer_offset,size_t function_body_length,size_t num_remaining_functions,uint32_t module_offset)502   explicit DecodeFunctionBody(SectionBuffer* section_buffer,
503                               size_t buffer_offset, size_t function_body_length,
504                               size_t num_remaining_functions,
505                               uint32_t module_offset)
506       : section_buffer_(section_buffer),
507         buffer_offset_(buffer_offset),
508         function_body_length_(function_body_length),
509         num_remaining_functions_(num_remaining_functions),
510         module_offset_(module_offset) {}
511 
buffer()512   base::Vector<uint8_t> buffer() override {
513     base::Vector<uint8_t> remaining_buffer =
514         section_buffer_->bytes() + buffer_offset_;
515     return remaining_buffer.SubVector(0, function_body_length_);
516   }
517 
518   std::unique_ptr<DecodingState> Next(
519       AsyncStreamingDecoder* streaming) override;
520 
521  private:
522   SectionBuffer* const section_buffer_;
523   const size_t buffer_offset_;
524   const size_t function_body_length_;
525   const size_t num_remaining_functions_;
526   const uint32_t module_offset_;
527 };
528 
ReadBytes(AsyncStreamingDecoder * streaming,base::Vector<const uint8_t> bytes)529 size_t AsyncStreamingDecoder::DecodeVarInt32::ReadBytes(
530     AsyncStreamingDecoder* streaming, base::Vector<const uint8_t> bytes) {
531   base::Vector<uint8_t> buf = buffer();
532   base::Vector<uint8_t> remaining_buf = buf + offset();
533   size_t new_bytes = std::min(bytes.size(), remaining_buf.size());
534   TRACE_STREAMING("ReadBytes of a VarInt\n");
535   memcpy(remaining_buf.begin(), &bytes.first(), new_bytes);
536   buf.Truncate(offset() + new_bytes);
537   Decoder decoder(buf,
538                   streaming->module_offset() - static_cast<uint32_t>(offset()));
539   value_ = decoder.consume_u32v(field_name_);
540 
541   if (decoder.failed()) {
542     if (new_bytes == remaining_buf.size()) {
543       // We only report an error if we read all bytes.
544       streaming->Error(decoder.error());
545     }
546     set_offset(offset() + new_bytes);
547     return new_bytes;
548   }
549 
550   // The number of bytes we actually needed to read.
551   DCHECK_GT(decoder.pc(), buffer().begin());
552   bytes_consumed_ = static_cast<size_t>(decoder.pc() - buf.begin());
553   TRACE_STREAMING("  ==> %zu bytes consumed\n", bytes_consumed_);
554 
555   // We read all the bytes we needed.
556   DCHECK_GT(bytes_consumed_, offset());
557   new_bytes = bytes_consumed_ - offset();
558   // Set the offset to the buffer size to signal that we are at the end of this
559   // section.
560   set_offset(buffer().size());
561   return new_bytes;
562 }
563 
564 std::unique_ptr<AsyncStreamingDecoder::DecodingState>
Next(AsyncStreamingDecoder * streaming)565 AsyncStreamingDecoder::DecodeVarInt32::Next(AsyncStreamingDecoder* streaming) {
566   if (!streaming->ok()) return nullptr;
567 
568   if (value_ > max_value_) {
569     std::ostringstream oss;
570     oss << "The value " << value_ << " for " << field_name_
571         << " exceeds the maximum allowed value of " << max_value_;
572     return streaming->Error(oss.str());
573   }
574 
575   return NextWithValue(streaming);
576 }
577 
578 std::unique_ptr<AsyncStreamingDecoder::DecodingState>
Next(AsyncStreamingDecoder * streaming)579 AsyncStreamingDecoder::DecodeModuleHeader::Next(
580     AsyncStreamingDecoder* streaming) {
581   TRACE_STREAMING("DecodeModuleHeader\n");
582   streaming->ProcessModuleHeader();
583   if (!streaming->ok()) return nullptr;
584   return std::make_unique<DecodeSectionID>(streaming->module_offset());
585 }
586 
587 std::unique_ptr<AsyncStreamingDecoder::DecodingState>
Next(AsyncStreamingDecoder * streaming)588 AsyncStreamingDecoder::DecodeSectionID::Next(AsyncStreamingDecoder* streaming) {
589   TRACE_STREAMING("DecodeSectionID: %s section\n",
590                   SectionName(static_cast<SectionCode>(id_)));
591   if (id_ == SectionCode::kCodeSectionCode) {
592     // Explicitly check for multiple code sections as module decoder never
593     // sees the code section and hence cannot track this section.
594     if (streaming->code_section_processed_) {
595       // TODO(wasm): This error message (and others in this class) is different
596       // for non-streaming decoding. Bring them in sync and test.
597       return streaming->Error("code section can only appear once");
598     }
599     streaming->code_section_processed_ = true;
600   }
601   return std::make_unique<DecodeSectionLength>(id_, module_offset_);
602 }
603 
604 std::unique_ptr<AsyncStreamingDecoder::DecodingState>
NextWithValue(AsyncStreamingDecoder * streaming)605 AsyncStreamingDecoder::DecodeSectionLength::NextWithValue(
606     AsyncStreamingDecoder* streaming) {
607   TRACE_STREAMING("DecodeSectionLength(%zu)\n", value_);
608   SectionBuffer* buf =
609       streaming->CreateNewBuffer(module_offset_, section_id_, value_,
610                                  buffer().SubVector(0, bytes_consumed_));
611   DCHECK_NOT_NULL(buf);
612   if (value_ == 0) {
613     if (section_id_ == SectionCode::kCodeSectionCode) {
614       return streaming->Error("code section cannot have size 0");
615     }
616     // Process section without payload as well, to enforce section order and
617     // other feature checks specific to each individual section.
618     streaming->ProcessSection(buf);
619     if (!streaming->ok()) return nullptr;
620     // There is no payload, we go to the next section immediately.
621     return std::make_unique<DecodeSectionID>(streaming->module_offset_);
622   }
623   if (section_id_ == SectionCode::kCodeSectionCode) {
624     // We reached the code section. All functions of the code section are put
625     // into the same SectionBuffer.
626     return std::make_unique<DecodeNumberOfFunctions>(buf);
627   }
628   return std::make_unique<DecodeSectionPayload>(buf);
629 }
630 
631 std::unique_ptr<AsyncStreamingDecoder::DecodingState>
Next(AsyncStreamingDecoder * streaming)632 AsyncStreamingDecoder::DecodeSectionPayload::Next(
633     AsyncStreamingDecoder* streaming) {
634   TRACE_STREAMING("DecodeSectionPayload\n");
635   streaming->ProcessSection(section_buffer_);
636   if (!streaming->ok()) return nullptr;
637   return std::make_unique<DecodeSectionID>(streaming->module_offset());
638 }
639 
640 std::unique_ptr<AsyncStreamingDecoder::DecodingState>
NextWithValue(AsyncStreamingDecoder * streaming)641 AsyncStreamingDecoder::DecodeNumberOfFunctions::NextWithValue(
642     AsyncStreamingDecoder* streaming) {
643   TRACE_STREAMING("DecodeNumberOfFunctions(%zu)\n", value_);
644   // Copy the bytes we read into the section buffer.
645   base::Vector<uint8_t> payload_buf = section_buffer_->payload();
646   if (payload_buf.size() < bytes_consumed_) {
647     return streaming->Error("invalid code section length");
648   }
649   memcpy(payload_buf.begin(), buffer().begin(), bytes_consumed_);
650 
651   // {value} is the number of functions.
652   if (value_ == 0) {
653     if (payload_buf.size() != bytes_consumed_) {
654       return streaming->Error("not all code section bytes were used");
655     }
656     return std::make_unique<DecodeSectionID>(streaming->module_offset());
657   }
658 
659   DCHECK_GE(kMaxInt, section_buffer_->module_offset() +
660                          section_buffer_->payload_offset());
661   int code_section_start = static_cast<int>(section_buffer_->module_offset() +
662                                             section_buffer_->payload_offset());
663   DCHECK_GE(kMaxInt, payload_buf.length());
664   int code_section_len = static_cast<int>(payload_buf.length());
665   DCHECK_GE(kMaxInt, value_);
666   streaming->StartCodeSection(static_cast<int>(value_),
667                               streaming->section_buffers_.back(),
668                               code_section_start, code_section_len);
669   if (!streaming->ok()) return nullptr;
670   return std::make_unique<DecodeFunctionLength>(
671       section_buffer_, section_buffer_->payload_offset() + bytes_consumed_,
672       value_);
673 }
674 
675 std::unique_ptr<AsyncStreamingDecoder::DecodingState>
NextWithValue(AsyncStreamingDecoder * streaming)676 AsyncStreamingDecoder::DecodeFunctionLength::NextWithValue(
677     AsyncStreamingDecoder* streaming) {
678   TRACE_STREAMING("DecodeFunctionLength(%zu)\n", value_);
679   // Copy the bytes we consumed into the section buffer.
680   base::Vector<uint8_t> fun_length_buffer =
681       section_buffer_->bytes() + buffer_offset_;
682   if (fun_length_buffer.size() < bytes_consumed_) {
683     return streaming->Error("read past code section end");
684   }
685   memcpy(fun_length_buffer.begin(), buffer().begin(), bytes_consumed_);
686 
687   // {value} is the length of the function.
688   if (value_ == 0) return streaming->Error("invalid function length (0)");
689 
690   if (buffer_offset_ + bytes_consumed_ + value_ > section_buffer_->length()) {
691     return streaming->Error("not enough code section bytes");
692   }
693 
694   return std::make_unique<DecodeFunctionBody>(
695       section_buffer_, buffer_offset_ + bytes_consumed_, value_,
696       num_remaining_functions_, streaming->module_offset());
697 }
698 
699 std::unique_ptr<AsyncStreamingDecoder::DecodingState>
Next(AsyncStreamingDecoder * streaming)700 AsyncStreamingDecoder::DecodeFunctionBody::Next(
701     AsyncStreamingDecoder* streaming) {
702   TRACE_STREAMING("DecodeFunctionBody\n");
703   streaming->ProcessFunctionBody(buffer(), module_offset_);
704   if (!streaming->ok()) return nullptr;
705 
706   size_t end_offset = buffer_offset_ + function_body_length_;
707   if (num_remaining_functions_ > 0) {
708     return std::make_unique<DecodeFunctionLength>(section_buffer_, end_offset,
709                                                   num_remaining_functions_);
710   }
711   // We just read the last function body. Continue with the next section.
712   if (end_offset != section_buffer_->length()) {
713     return streaming->Error("not all code section bytes were used");
714   }
715   return std::make_unique<DecodeSectionID>(streaming->module_offset());
716 }
717 
AsyncStreamingDecoder(std::unique_ptr<StreamingProcessor> processor)718 AsyncStreamingDecoder::AsyncStreamingDecoder(
719     std::unique_ptr<StreamingProcessor> processor)
720     : processor_(std::move(processor)),
721       // A module always starts with a module header.
722       state_(new DecodeModuleHeader()) {}
723 
CreateNewBuffer(uint32_t module_offset,uint8_t section_id,size_t length,base::Vector<const uint8_t> length_bytes)724 AsyncStreamingDecoder::SectionBuffer* AsyncStreamingDecoder::CreateNewBuffer(
725     uint32_t module_offset, uint8_t section_id, size_t length,
726     base::Vector<const uint8_t> length_bytes) {
727   // Section buffers are allocated in the same order they appear in the module,
728   // they will be processed and later on concatenated in that same order.
729   section_buffers_.emplace_back(std::make_shared<SectionBuffer>(
730       module_offset, section_id, length, length_bytes));
731   return section_buffers_.back().get();
732 }
733 
CreateAsyncStreamingDecoder(std::unique_ptr<StreamingProcessor> processor)734 std::unique_ptr<StreamingDecoder> StreamingDecoder::CreateAsyncStreamingDecoder(
735     std::unique_ptr<StreamingProcessor> processor) {
736   return std::make_unique<AsyncStreamingDecoder>(std::move(processor));
737 }
738 
739 }  // namespace wasm
740 }  // namespace internal
741 }  // namespace v8
742 
743 #undef TRACE_STREAMING
744