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 <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 1474 : class V8_EXPORT_PRIVATE StreamingProcessor {
20 : public:
21 1474 : 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(std::unique_ptr<uint8_t[]> bytes,
48 : size_t length) = 0;
49 : // Report an error detected in the StreamingDecoder.
50 : virtual void OnError(DecodeResult result) = 0;
51 : // Report the abortion of the stream.
52 : virtual void OnAbort() = 0;
53 : };
54 :
55 : // The StreamingDecoder takes a sequence of byte arrays, each received by a call
56 : // of {OnBytesReceived}, and extracts the bytes which belong to section payloads
57 : // and function bodies.
58 2948 : class V8_EXPORT_PRIVATE StreamingDecoder {
59 : public:
60 : explicit StreamingDecoder(std::unique_ptr<StreamingProcessor> processor);
61 :
62 : // The buffer passed into OnBytesReceived is owned by the caller.
63 : void OnBytesReceived(Vector<const uint8_t> bytes);
64 :
65 : void Finish();
66 :
67 : void Abort();
68 :
69 : // Notify the StreamingDecoder that there has been an compilation error.
70 220 : void NotifyError() { ok_ = false; }
71 :
72 : private:
73 : // TODO(ahaas): Put the whole private state of the StreamingDecoder into the
74 : // cc file (PIMPL design pattern).
75 :
76 : // The SectionBuffer is the data object for the content of a single section.
77 : // It stores all bytes of the section (including section id and section
78 : // length), and the offset where the actual payload starts.
79 : class SectionBuffer {
80 : public:
81 : // id: The section id.
82 : // payload_length: The length of the payload.
83 : // length_bytes: The section length, as it is encoded in the module bytes.
84 1576 : SectionBuffer(uint32_t module_offset, uint8_t id, size_t payload_length,
85 : Vector<const uint8_t> length_bytes)
86 : : // ID + length + payload
87 : module_offset_(module_offset),
88 1576 : length_(1 + length_bytes.length() + payload_length),
89 1576 : bytes_(new uint8_t[length_]),
90 4728 : payload_offset_(1 + length_bytes.length()) {
91 1576 : bytes_[0] = id;
92 3152 : memcpy(bytes_.get() + 1, &length_bytes.first(), length_bytes.length());
93 1576 : }
94 :
95 : SectionCode section_code() const {
96 987 : return static_cast<SectionCode>(bytes_[0]);
97 : }
98 :
99 : uint32_t module_offset() const { return module_offset_; }
100 : uint8_t* bytes() const { return bytes_.get(); }
101 : size_t length() const { return length_; }
102 : size_t payload_offset() const { return payload_offset_; }
103 3599 : size_t payload_length() const { return length_ - payload_offset_; }
104 987 : Vector<const uint8_t> payload() const {
105 : return Vector<const uint8_t>(bytes() + payload_offset(),
106 987 : payload_length());
107 : }
108 :
109 : private:
110 : uint32_t module_offset_;
111 : size_t length_;
112 : std::unique_ptr<uint8_t[]> bytes_;
113 : size_t payload_offset_;
114 : };
115 :
116 : // The decoding of a stream of wasm module bytes is organized in states. Each
117 : // state provides a buffer to store the bytes required for the current state,
118 : // information on how many bytes have already been received, how many bytes
119 : // are needed, and a {Next} function which starts the next state once all
120 : // bytes of the current state were received.
121 : //
122 : // The states change according to the following state diagram:
123 : //
124 : // Start
125 : // |
126 : // |
127 : // v
128 : // DecodeModuleHeader
129 : // | _________________________________________
130 : // | | |
131 : // v v |
132 : // DecodeSectionID --> DecodeSectionLength --> DecodeSectionPayload
133 : // A |
134 : // | | (if the section id == code)
135 : // | v
136 : // | DecodeNumberOfFunctions -- > DecodeFunctionLength
137 : // | A |
138 : // | | |
139 : // | (after all functions were read) | v
140 : // ------------------------------------- DecodeFunctionBody
141 : //
142 8451 : class DecodingState {
143 : public:
144 8451 : virtual ~DecodingState() = default;
145 :
146 : // Reads the bytes for the current state and returns the number of read
147 : // bytes.
148 : virtual size_t ReadBytes(StreamingDecoder* streaming,
149 : Vector<const uint8_t> bytes);
150 :
151 : // Returns the next state of the streaming decoding.
152 : virtual std::unique_ptr<DecodingState> Next(
153 : StreamingDecoder* streaming) = 0;
154 : // The number of bytes to be received.
155 : virtual size_t size() const = 0;
156 : // The buffer to store the received bytes.
157 : virtual uint8_t* buffer() = 0;
158 : // The number of bytes which were already received.
159 : size_t offset() const { return offset_; }
160 8811 : void set_offset(size_t value) { offset_ = value; }
161 : // The number of bytes which are still needed.
162 8811 : size_t remaining() const { return size() - offset(); }
163 8811 : bool is_finished() const { return offset() == size(); }
164 : // A flag to indicate if finishing the streaming decoder is allowed without
165 : // error.
166 87 : virtual bool is_finishing_allowed() const { return false; }
167 :
168 : private:
169 : size_t offset_ = 0;
170 : };
171 :
172 : // Forward declarations of the concrete states. This is needed so that they
173 : // can access private members of the StreamingDecoder.
174 : class DecodeVarInt32;
175 : class DecodeModuleHeader;
176 : class DecodeSectionID;
177 : class DecodeSectionLength;
178 : class DecodeSectionPayload;
179 : class DecodeNumberOfFunctions;
180 : class DecodeFunctionLength;
181 : class DecodeFunctionBody;
182 :
183 : // Creates a buffer for the next section of the module.
184 1619 : SectionBuffer* CreateNewBuffer(uint32_t module_offset, uint8_t id,
185 : size_t length,
186 : Vector<const uint8_t> length_bytes) {
187 : // Check the order of sections. Unknown sections can appear at any position.
188 1619 : if (id != kUnknownSectionCode) {
189 1526 : if (id < next_section_id_) {
190 129 : Error("Unexpected section");
191 43 : return nullptr;
192 : }
193 1483 : next_section_id_ = id + 1;
194 : }
195 : section_buffers_.emplace_back(
196 1576 : new SectionBuffer(module_offset, id, length, length_bytes));
197 1576 : return section_buffers_.back().get();
198 : }
199 :
200 412 : std::unique_ptr<DecodingState> Error(DecodeResult result) {
201 1648 : if (ok_) processor_->OnError(std::move(result));
202 412 : ok_ = false;
203 412 : return std::unique_ptr<DecodingState>(nullptr);
204 : }
205 :
206 367 : std::unique_ptr<DecodingState> Error(std::string message) {
207 : DecodeResult result(nullptr);
208 734 : result.error(module_offset_ - 1, std::move(message));
209 1101 : return Error(std::move(result));
210 : }
211 :
212 1431 : void ProcessModuleHeader() {
213 2862 : if (!ok_) return;
214 : ok_ &= processor_->ProcessModuleHeader(
215 1431 : Vector<const uint8_t>(state_->buffer(),
216 1431 : static_cast<int>(state_->size())),
217 4293 : 0);
218 : }
219 :
220 1974 : void ProcessSection(SectionBuffer* buffer) {
221 1974 : if (!ok_) return;
222 : ok_ &= processor_->ProcessSection(
223 : buffer->section_code(), buffer->payload(),
224 : buffer->module_offset() +
225 2961 : static_cast<uint32_t>(buffer->payload_offset()));
226 : }
227 :
228 968 : void StartCodeSection(size_t num_functions) {
229 968 : if (!ok_) return;
230 : // The offset passed to {ProcessCodeSectionHeader} is an error offset and
231 : // not the start offset of a buffer. Therefore we need the -1 here.
232 : ok_ &= processor_->ProcessCodeSectionHeader(num_functions,
233 968 : module_offset() - 1);
234 : }
235 :
236 : void ProcessFunctionBody(Vector<const uint8_t> bytes,
237 : uint32_t module_offset) {
238 791 : if (!ok_) return;
239 791 : ok_ &= processor_->ProcessFunctionBody(bytes, module_offset);
240 : }
241 :
242 : bool ok() const { return ok_; }
243 :
244 : uint32_t module_offset() const { return module_offset_; }
245 :
246 : std::unique_ptr<StreamingProcessor> processor_;
247 : bool ok_ = true;
248 : std::unique_ptr<DecodingState> state_;
249 : std::vector<std::unique_ptr<SectionBuffer>> section_buffers_;
250 : uint32_t module_offset_ = 0;
251 : size_t total_size_ = 0;
252 : uint8_t next_section_id_ = kFirstSectionInModule;
253 :
254 : DISALLOW_COPY_AND_ASSIGN(StreamingDecoder);
255 : };
256 :
257 : } // namespace wasm
258 : } // namespace internal
259 : } // namespace v8
260 :
261 : #endif // V8_WASM_STREAMING_DECODER_H_
|