• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 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 #if !V8_ENABLE_WEBASSEMBLY
6 #error This header should only be included if WebAssembly is enabled.
7 #endif  // !V8_ENABLE_WEBASSEMBLY
8 
9 #ifndef V8_WASM_MODULE_DECODER_H_
10 #define V8_WASM_MODULE_DECODER_H_
11 
12 #include <memory>
13 
14 #include "src/common/globals.h"
15 #include "src/logging/metrics.h"
16 #include "src/wasm/function-body-decoder.h"
17 #include "src/wasm/wasm-constants.h"
18 #include "src/wasm/wasm-features.h"
19 #include "src/wasm/wasm-module.h"
20 #include "src/wasm/wasm-result.h"
21 
22 namespace v8 {
23 namespace internal {
24 
25 class Counters;
26 
27 namespace wasm {
28 
29 struct CompilationEnv;
30 
IsValidSectionCode(uint8_t byte)31 inline bool IsValidSectionCode(uint8_t byte) {
32   return kTypeSectionCode <= byte && byte <= kLastKnownModuleSection;
33 }
34 
35 const char* SectionName(SectionCode code);
36 
37 using ModuleResult = Result<std::shared_ptr<WasmModule>>;
38 using FunctionResult = Result<std::unique_ptr<WasmFunction>>;
39 using FunctionOffsets = std::vector<std::pair<int, int>>;
40 using FunctionOffsetsResult = Result<FunctionOffsets>;
41 
42 struct AsmJsOffsetEntry {
43   int byte_offset;
44   int source_position_call;
45   int source_position_number_conversion;
46 };
47 struct AsmJsOffsetFunctionEntries {
48   int start_offset;
49   int end_offset;
50   std::vector<AsmJsOffsetEntry> entries;
51 };
52 struct AsmJsOffsets {
53   std::vector<AsmJsOffsetFunctionEntries> functions;
54 };
55 using AsmJsOffsetsResult = Result<AsmJsOffsets>;
56 
57 // The class names "NameAssoc", "NameMap", and "IndirectNameMap" match
58 // the terms used by the spec:
59 // https://webassembly.github.io/spec/core/bikeshed/index.html#name-section%E2%91%A0
60 class NameAssoc {
61  public:
NameAssoc(int index,WireBytesRef name)62   NameAssoc(int index, WireBytesRef name) : index_(index), name_(name) {}
63 
index()64   int index() const { return index_; }
name()65   WireBytesRef name() const { return name_; }
66 
67   struct IndexLess {
operatorIndexLess68     bool operator()(const NameAssoc& a, const NameAssoc& b) const {
69       return a.index() < b.index();
70     }
71   };
72 
73  private:
74   int index_;
75   WireBytesRef name_;
76 };
77 
78 class NameMap {
79  public:
80   // For performance reasons, {NameMap} should not be copied.
81   MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(NameMap);
82 
NameMap(std::vector<NameAssoc> names)83   explicit NameMap(std::vector<NameAssoc> names) : names_(std::move(names)) {
84     DCHECK(
85         std::is_sorted(names_.begin(), names_.end(), NameAssoc::IndexLess{}));
86   }
87 
GetName(int index)88   WireBytesRef GetName(int index) {
89     auto it = std::lower_bound(names_.begin(), names_.end(),
90                                NameAssoc{index, {}}, NameAssoc::IndexLess{});
91     if (it == names_.end()) return {};
92     if (it->index() != index) return {};
93     return it->name();
94   }
95 
96  private:
97   std::vector<NameAssoc> names_;
98 };
99 
100 class IndirectNameMapEntry : public NameMap {
101  public:
102   // For performance reasons, {IndirectNameMapEntry} should not be copied.
103   MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(IndirectNameMapEntry);
104 
IndirectNameMapEntry(int index,std::vector<NameAssoc> names)105   IndirectNameMapEntry(int index, std::vector<NameAssoc> names)
106       : NameMap(std::move(names)), index_(index) {}
107 
index()108   int index() const { return index_; }
109 
110   struct IndexLess {
operatorIndexLess111     bool operator()(const IndirectNameMapEntry& a,
112                     const IndirectNameMapEntry& b) const {
113       return a.index() < b.index();
114     }
115   };
116 
117  private:
118   int index_;
119 };
120 
121 class IndirectNameMap {
122  public:
123   // For performance reasons, {IndirectNameMap} should not be copied.
124   MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(IndirectNameMap);
125 
IndirectNameMap(std::vector<IndirectNameMapEntry> functions)126   explicit IndirectNameMap(std::vector<IndirectNameMapEntry> functions)
127       : functions_(std::move(functions)) {
128     DCHECK(std::is_sorted(functions_.begin(), functions_.end(),
129                           IndirectNameMapEntry::IndexLess{}));
130   }
131 
GetName(int function_index,int local_index)132   WireBytesRef GetName(int function_index, int local_index) {
133     auto it = std::lower_bound(functions_.begin(), functions_.end(),
134                                IndirectNameMapEntry{function_index, {}},
135                                IndirectNameMapEntry::IndexLess{});
136     if (it == functions_.end()) return {};
137     if (it->index() != function_index) return {};
138     return it->GetName(local_index);
139   }
140 
141  private:
142   std::vector<IndirectNameMapEntry> functions_;
143 };
144 
145 enum class DecodingMethod {
146   kSync,
147   kAsync,
148   kSyncStream,
149   kAsyncStream,
150   kDeserialize
151 };
152 
153 // Decodes the bytes of a wasm module between {module_start} and {module_end}.
154 V8_EXPORT_PRIVATE ModuleResult DecodeWasmModule(
155     const WasmFeatures& enabled, const byte* module_start,
156     const byte* module_end, bool verify_functions, ModuleOrigin origin,
157     Counters* counters, std::shared_ptr<metrics::Recorder> metrics_recorder,
158     v8::metrics::Recorder::ContextId context_id, DecodingMethod decoding_method,
159     AccountingAllocator* allocator);
160 
161 // Exposed for testing. Decodes a single function signature, allocating it
162 // in the given zone. Returns {nullptr} upon failure.
163 V8_EXPORT_PRIVATE const FunctionSig* DecodeWasmSignatureForTesting(
164     const WasmFeatures& enabled, Zone* zone, const byte* start,
165     const byte* end);
166 
167 // Decodes the bytes of a wasm function between
168 // {function_start} and {function_end}.
169 V8_EXPORT_PRIVATE FunctionResult DecodeWasmFunctionForTesting(
170     const WasmFeatures& enabled, Zone* zone, const ModuleWireBytes& wire_bytes,
171     const WasmModule* module, const byte* function_start,
172     const byte* function_end, Counters* counters);
173 
174 V8_EXPORT_PRIVATE ConstantExpression
175 DecodeWasmInitExprForTesting(const WasmFeatures& enabled, const byte* start,
176                              const byte* end, ValueType expected);
177 
178 struct CustomSectionOffset {
179   WireBytesRef section;
180   WireBytesRef name;
181   WireBytesRef payload;
182 };
183 
184 V8_EXPORT_PRIVATE std::vector<CustomSectionOffset> DecodeCustomSections(
185     const byte* start, const byte* end);
186 
187 // Extracts the mapping from wasm byte offset to asm.js source position per
188 // function.
189 AsmJsOffsetsResult DecodeAsmJsOffsets(
190     base::Vector<const uint8_t> encoded_offsets);
191 
192 // Decode the function names from the name section. Returns the result as an
193 // unordered map. Only names with valid utf8 encoding are stored and conflicts
194 // are resolved by choosing the last name read.
195 void DecodeFunctionNames(const byte* module_start, const byte* module_end,
196                          std::unordered_map<uint32_t, WireBytesRef>* names);
197 
198 // Decode the requested subsection of the name section.
199 // The result will be empty if no name section is present. On encountering an
200 // error in the name section, returns all information decoded up to the first
201 // error.
202 NameMap DecodeNameMap(base::Vector<const uint8_t> module_bytes,
203                       uint8_t name_section_kind);
204 IndirectNameMap DecodeIndirectNameMap(base::Vector<const uint8_t> module_bytes,
205                                       uint8_t name_section_kind);
206 
207 class ModuleDecoderImpl;
208 
209 class ModuleDecoder {
210  public:
211   explicit ModuleDecoder(const WasmFeatures& enabled);
212   ~ModuleDecoder();
213 
214   void StartDecoding(Counters* counters,
215                      std::shared_ptr<metrics::Recorder> metrics_recorder,
216                      v8::metrics::Recorder::ContextId context_id,
217                      AccountingAllocator* allocator,
218                      ModuleOrigin origin = ModuleOrigin::kWasmOrigin);
219 
220   void DecodeModuleHeader(base::Vector<const uint8_t> bytes, uint32_t offset);
221 
222   void DecodeSection(SectionCode section_code,
223                      base::Vector<const uint8_t> bytes, uint32_t offset,
224                      bool verify_functions = true);
225 
226   void StartCodeSection();
227 
228   bool CheckFunctionsCount(uint32_t functions_count, uint32_t error_offset);
229 
230   void DecodeFunctionBody(uint32_t index, uint32_t size, uint32_t offset,
231                           bool verify_functions = true);
232 
233   ModuleResult FinishDecoding(bool verify_functions = true);
234 
235   void set_code_section(uint32_t offset, uint32_t size);
236 
237   const std::shared_ptr<WasmModule>& shared_module() const;
238 
module()239   WasmModule* module() const { return shared_module().get(); }
240 
241   bool ok();
242 
243   // Translates the unknown section that decoder is pointing to to an extended
244   // SectionCode if the unknown section is known to decoder.
245   // The decoder is expected to point after the section length and just before
246   // the identifier string of the unknown section.
247   // The return value is the number of bytes that were consumed.
248   static size_t IdentifyUnknownSection(ModuleDecoder* decoder,
249                                        base::Vector<const uint8_t> bytes,
250                                        uint32_t offset, SectionCode* result);
251 
252  private:
253   const WasmFeatures enabled_features_;
254   std::unique_ptr<ModuleDecoderImpl> impl_;
255 };
256 
257 }  // namespace wasm
258 }  // namespace internal
259 }  // namespace v8
260 
261 #endif  // V8_WASM_MODULE_DECODER_H_
262