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