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