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