• 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_WASM_MODULE_H_
10 #define V8_WASM_WASM_MODULE_H_
11 
12 #include <map>
13 #include <memory>
14 
15 #include "src/base/optional.h"
16 #include "src/base/platform/wrappers.h"
17 #include "src/base/vector.h"
18 #include "src/common/globals.h"
19 #include "src/handles/handles.h"
20 #include "src/wasm/branch-hint-map.h"
21 #include "src/wasm/signature-map.h"
22 #include "src/wasm/struct-types.h"
23 #include "src/wasm/wasm-constants.h"
24 #include "src/wasm/wasm-init-expr.h"
25 #include "src/wasm/wasm-limits.h"
26 
27 namespace v8 {
28 
29 namespace internal {
30 
31 class WasmModuleObject;
32 
33 namespace wasm {
34 
35 using WasmName = base::Vector<const char>;
36 
37 struct AsmJsOffsets;
38 class ErrorThrower;
39 
40 // Reference to a string in the wire bytes.
41 class WireBytesRef {
42  public:
WireBytesRef()43   WireBytesRef() : WireBytesRef(0, 0) {}
WireBytesRef(uint32_t offset,uint32_t length)44   WireBytesRef(uint32_t offset, uint32_t length)
45       : offset_(offset), length_(length) {
46     DCHECK_IMPLIES(offset_ == 0, length_ == 0);
47     DCHECK_LE(offset_, offset_ + length_);  // no uint32_t overflow.
48   }
49 
offset()50   uint32_t offset() const { return offset_; }
length()51   uint32_t length() const { return length_; }
end_offset()52   uint32_t end_offset() const { return offset_ + length_; }
is_empty()53   bool is_empty() const { return length_ == 0; }
is_set()54   bool is_set() const { return offset_ != 0; }
55 
56  private:
57   uint32_t offset_;
58   uint32_t length_;
59 };
60 
61 // Static representation of a wasm function.
62 struct WasmFunction {
63   const FunctionSig* sig;  // signature of the function.
64   uint32_t func_index;     // index into the function table.
65   uint32_t sig_index;      // index into the signature table.
66   WireBytesRef code;       // code of this function.
67   // Required number of slots in a feedback vector. Marked {mutable} because
68   // this is computed late (by Liftoff compilation), when the rest of the
69   // {WasmFunction} is typically considered {const}.
70   mutable int feedback_slots;
71   bool imported;
72   bool exported;
73   bool declared;
74 };
75 
76 // A representation of a constant expression. The most common expression types
77 // are hard-coded, while the rest are represented as a {WireBytesRef}.
78 class ConstantExpression {
79  public:
80   enum Kind {
81     kEmpty,
82     kI32Const,
83     kRefNull,
84     kRefFunc,
85     kWireBytesRef,
86     kLastKind = kWireBytesRef
87   };
88 
89   union Value {
90     int32_t i32_value;
91     uint32_t index_or_offset;
92     HeapType::Representation repr;
93   };
94 
ConstantExpression()95   ConstantExpression() : bit_field_(KindField::encode(kEmpty)) {}
96 
I32Const(int32_t value)97   static ConstantExpression I32Const(int32_t value) {
98     return ConstantExpression(ValueField::encode(value) |
99                               KindField::encode(kI32Const));
100   }
RefFunc(uint32_t index)101   static ConstantExpression RefFunc(uint32_t index) {
102     return ConstantExpression(ValueField::encode(index) |
103                               KindField::encode(kRefFunc));
104   }
RefNull(HeapType::Representation repr)105   static ConstantExpression RefNull(HeapType::Representation repr) {
106     return ConstantExpression(ValueField::encode(repr) |
107                               KindField::encode(kRefNull));
108   }
WireBytes(uint32_t offset,uint32_t length)109   static ConstantExpression WireBytes(uint32_t offset, uint32_t length) {
110     return ConstantExpression(OffsetField::encode(offset) |
111                               LengthField::encode(length) |
112                               KindField::encode(kWireBytesRef));
113   }
114 
kind()115   Kind kind() const { return KindField::decode(bit_field_); }
116 
is_set()117   bool is_set() const { return kind() != kEmpty; }
118 
index()119   uint32_t index() const {
120     DCHECK_EQ(kind(), kRefFunc);
121     return ValueField::decode(bit_field_);
122   }
123 
repr()124   HeapType::Representation repr() const {
125     DCHECK_EQ(kind(), kRefNull);
126     return static_cast<HeapType::Representation>(
127         ValueField::decode(bit_field_));
128   }
129 
i32_value()130   int32_t i32_value() const {
131     DCHECK_EQ(kind(), kI32Const);
132     return ValueField::decode(bit_field_);
133   }
134 
wire_bytes_ref()135   WireBytesRef wire_bytes_ref() const {
136     DCHECK_EQ(kind(), kWireBytesRef);
137     return WireBytesRef(OffsetField::decode(bit_field_),
138                         LengthField::decode(bit_field_));
139   }
140 
141  private:
142   static constexpr int kValueBits = 32;
143   static constexpr int kLengthBits = 30;
144   static constexpr int kOffsetBits = 30;
145   static constexpr int kKindBits = 3;
146 
147   // There are two possible combinations of fields: offset + length + kind if
148   // kind = kWireBytesRef, or value + kind for anything else.
149   using ValueField = base::BitField<uint32_t, 0, kValueBits, uint64_t>;
150   using OffsetField = base::BitField<uint32_t, 0, kOffsetBits, uint64_t>;
151   using LengthField = OffsetField::Next<uint32_t, kLengthBits>;
152   using KindField = LengthField::Next<Kind, kKindBits>;
153 
154   // Make sure we reserve enough bits for a {WireBytesRef}'s length and offset.
155   STATIC_ASSERT(kV8MaxWasmModuleSize <= LengthField::kMax + 1);
156   STATIC_ASSERT(kV8MaxWasmModuleSize <= OffsetField::kMax + 1);
157   // Make sure kind fits in kKindBits.
158   STATIC_ASSERT(kLastKind <= KindField::kMax + 1);
159 
ConstantExpression(uint64_t bit_field)160   explicit ConstantExpression(uint64_t bit_field) : bit_field_(bit_field) {}
161 
162   uint64_t bit_field_;
163 };
164 
165 // We want to keep {ConstantExpression} small to reduce memory usage during
166 // compilation/instantiation.
167 STATIC_ASSERT(sizeof(ConstantExpression) <= 8);
168 
169 // Static representation of a wasm global variable.
170 struct WasmGlobal {
171   ValueType type;           // type of the global.
172   bool mutability;          // {true} if mutable.
173   ConstantExpression init;  // the initialization expression of the global.
174   union {
175     // Index of imported mutable global.
176     uint32_t index;
177     // Offset into global memory (if not imported & mutable). Expressed in bytes
178     // for value-typed globals, and in tagged words for reference-typed globals.
179     uint32_t offset;
180   };
181   bool imported;  // true if imported.
182   bool exported;  // true if exported.
183 };
184 
185 // Note: An exception tag signature only uses the params portion of a function
186 // signature.
187 using WasmTagSig = FunctionSig;
188 
189 // Static representation of a wasm tag type.
190 struct WasmTag {
WasmTagWasmTag191   explicit WasmTag(const WasmTagSig* sig) : sig(sig) {}
ToFunctionSigWasmTag192   const FunctionSig* ToFunctionSig() const { return sig; }
193 
194   const WasmTagSig* sig;  // type signature of the tag.
195 };
196 
197 // Static representation of a wasm data segment.
198 struct WasmDataSegment {
199   // Construct an active segment.
WasmDataSegmentWasmDataSegment200   explicit WasmDataSegment(ConstantExpression dest_addr)
201       : dest_addr(dest_addr), active(true) {}
202 
203   // Construct a passive segment, which has no dest_addr.
WasmDataSegmentWasmDataSegment204   WasmDataSegment() : active(false) {}
205 
206   ConstantExpression dest_addr;  // destination memory address of the data.
207   WireBytesRef source;           // start offset in the module bytes.
208   bool active = true;  // true if copied automatically during instantiation.
209 };
210 
211 // Static representation of wasm element segment (table initializer).
212 struct WasmElemSegment {
213   enum Status {
214     kStatusActive,      // copied automatically during instantiation.
215     kStatusPassive,     // copied explicitly after instantiation.
216     kStatusDeclarative  // purely declarative and never copied.
217   };
218   enum ElementType { kFunctionIndexElements, kExpressionElements };
219 
220   // Construct an active segment.
WasmElemSegmentWasmElemSegment221   WasmElemSegment(ValueType type, uint32_t table_index,
222                   ConstantExpression offset, ElementType element_type)
223       : status(kStatusActive),
224         type(type),
225         table_index(table_index),
226         offset(std::move(offset)),
227         element_type(element_type) {}
228 
229   // Construct a passive or declarative segment, which has no table index or
230   // offset.
WasmElemSegmentWasmElemSegment231   WasmElemSegment(ValueType type, Status status, ElementType element_type)
232       : status(status), type(type), table_index(0), element_type(element_type) {
233     DCHECK_NE(status, kStatusActive);
234   }
235 
236   // Default constructor. Constucts an invalid segment.
WasmElemSegmentWasmElemSegment237   WasmElemSegment()
238       : status(kStatusActive),
239         type(kWasmBottom),
240         table_index(0),
241         element_type(kFunctionIndexElements) {}
242 
243   WasmElemSegment(const WasmElemSegment&) = delete;
244   WasmElemSegment(WasmElemSegment&&) V8_NOEXCEPT = default;
245   WasmElemSegment& operator=(const WasmElemSegment&) = delete;
246   WasmElemSegment& operator=(WasmElemSegment&&) V8_NOEXCEPT = default;
247 
248   Status status;
249   ValueType type;
250   uint32_t table_index;
251   ConstantExpression offset;
252   ElementType element_type;
253   std::vector<ConstantExpression> entries;
254 };
255 
256 // Static representation of a wasm import.
257 struct WasmImport {
258   WireBytesRef module_name;   // module name.
259   WireBytesRef field_name;    // import name.
260   ImportExportKindCode kind;  // kind of the import.
261   uint32_t index;             // index into the respective space.
262 };
263 
264 // Static representation of a wasm export.
265 struct WasmExport {
266   WireBytesRef name;          // exported name.
267   ImportExportKindCode kind;  // kind of the export.
268   uint32_t index;             // index into the respective space.
269 };
270 
271 enum class WasmCompilationHintStrategy : uint8_t {
272   kDefault = 0,
273   kLazy = 1,
274   kEager = 2,
275   kLazyBaselineEagerTopTier = 3,
276 };
277 
278 enum class WasmCompilationHintTier : uint8_t {
279   kDefault = 0,
280   kBaseline = 1,
281   kOptimized = 2,
282 };
283 
284 // Static representation of a wasm compilation hint
285 struct WasmCompilationHint {
286   WasmCompilationHintStrategy strategy;
287   WasmCompilationHintTier baseline_tier;
288   WasmCompilationHintTier top_tier;
289 };
290 
291 enum ModuleOrigin : uint8_t {
292   kWasmOrigin,
293   kAsmJsSloppyOrigin,
294   kAsmJsStrictOrigin
295 };
296 
297 #define SELECT_WASM_COUNTER(counters, origin, prefix, suffix)     \
298   ((origin) == kWasmOrigin ? (counters)->prefix##_wasm_##suffix() \
299                            : (counters)->prefix##_asm_##suffix())
300 
301 struct ModuleWireBytes;
302 
303 class V8_EXPORT_PRIVATE LazilyGeneratedNames {
304  public:
305   WireBytesRef LookupFunctionName(const ModuleWireBytes& wire_bytes,
306                                   uint32_t function_index) const;
307 
308   void AddForTesting(int function_index, WireBytesRef name);
309 
310  private:
311   // {function_names_} are populated lazily after decoding, and
312   // therefore need a mutex to protect concurrent modifications
313   // from multiple {WasmModuleObject}.
314   mutable base::Mutex mutex_;
315   mutable std::unique_ptr<std::unordered_map<uint32_t, WireBytesRef>>
316       function_names_;
317 };
318 
319 class V8_EXPORT_PRIVATE AsmJsOffsetInformation {
320  public:
321   explicit AsmJsOffsetInformation(base::Vector<const byte> encoded_offsets);
322 
323   // Destructor defined in wasm-module.cc, where the definition of
324   // {AsmJsOffsets} is available.
325   ~AsmJsOffsetInformation();
326 
327   int GetSourcePosition(int func_index, int byte_offset,
328                         bool is_at_number_conversion);
329 
330   std::pair<int, int> GetFunctionOffsets(int func_index);
331 
332  private:
333   void EnsureDecodedOffsets();
334 
335   // The offset information table is decoded lazily, hence needs to be
336   // protected against concurrent accesses.
337   // Exactly one of the two fields below will be set at a time.
338   mutable base::Mutex mutex_;
339 
340   // Holds the encoded offset table bytes.
341   base::OwnedVector<const uint8_t> encoded_offsets_;
342 
343   // Holds the decoded offset table.
344   std::unique_ptr<AsmJsOffsets> decoded_offsets_;
345 };
346 
347 // Used as the supertype for a type at the top of the type hierarchy.
348 constexpr uint32_t kNoSuperType = std::numeric_limits<uint32_t>::max();
349 
350 struct TypeDefinition {
351   enum Kind { kFunction, kStruct, kArray };
352 
TypeDefinitionTypeDefinition353   TypeDefinition(const FunctionSig* sig, uint32_t supertype)
354       : function_sig(sig), supertype(supertype), kind(kFunction) {}
TypeDefinitionTypeDefinition355   TypeDefinition(const StructType* type, uint32_t supertype)
356       : struct_type(type), supertype(supertype), kind(kStruct) {}
TypeDefinitionTypeDefinition357   TypeDefinition(const ArrayType* type, uint32_t supertype)
358       : array_type(type), supertype(supertype), kind(kArray) {}
TypeDefinitionTypeDefinition359   TypeDefinition()
360       : function_sig(nullptr), supertype(kNoSuperType), kind(kFunction) {}
361 
362   union {
363     const FunctionSig* function_sig;
364     const StructType* struct_type;
365     const ArrayType* array_type;
366   };
367 
368   bool operator==(const TypeDefinition& other) const {
369     if (supertype != other.supertype || kind != other.kind) {
370       return false;
371     }
372     switch (kind) {
373       case kFunction:
374         return *function_sig == *other.function_sig;
375       case kStruct:
376         return *struct_type == *other.struct_type;
377       case kArray:
378         return *array_type == *other.array_type;
379     }
380   }
381 
382   bool operator!=(const TypeDefinition& other) const {
383     return !(*this == other);
384   }
385 
386   uint32_t supertype;
387   Kind kind;
388 };
389 
390 struct V8_EXPORT_PRIVATE WasmDebugSymbols {
391   enum class Type { None, SourceMap, EmbeddedDWARF, ExternalDWARF };
392   Type type = Type::None;
393   WireBytesRef external_url;
394 };
395 
396 struct CallSiteFeedback {
397   int function_index;
398   int absolute_call_frequency;
399 };
400 struct FunctionTypeFeedback {
401   std::vector<CallSiteFeedback> feedback_vector;
402   std::map<WasmCodePosition, int> positions;
403   int tierup_priority = 0;
404 };
405 struct TypeFeedbackStorage {
406   std::map<uint32_t, FunctionTypeFeedback> feedback_for_function;
407   // Accesses to {feedback_for_function} are guarded by this mutex.
408   base::Mutex mutex;
409 };
410 
411 struct WasmTable;
412 
413 // Static representation of a module.
414 struct V8_EXPORT_PRIVATE WasmModule {
415   std::unique_ptr<Zone> signature_zone;
416   uint32_t initial_pages = 0;      // initial size of the memory in 64k pages
417   uint32_t maximum_pages = 0;      // maximum size of the memory in 64k pages
418   bool has_shared_memory = false;  // true if memory is a SharedArrayBuffer
419   bool has_maximum_pages = false;  // true if there is a maximum memory size
420   bool is_memory64 = false;        // true if the memory is 64 bit
421   bool has_memory = false;         // true if the memory was defined or imported
422   bool mem_export = false;         // true if the memory is exported
423   int start_function_index = -1;   // start function, >= 0 if any
424 
425   // Size of the buffer required for all globals that are not imported and
426   // mutable.
427   uint32_t untagged_globals_buffer_size = 0;
428   uint32_t tagged_globals_buffer_size = 0;
429   uint32_t num_imported_mutable_globals = 0;
430   uint32_t num_imported_functions = 0;
431   uint32_t num_imported_tables = 0;
432   uint32_t num_declared_functions = 0;  // excluding imported
433   uint32_t num_exported_functions = 0;
434   uint32_t num_declared_data_segments = 0;  // From the DataCount section.
435   // Position and size of the code section (payload only, i.e. without section
436   // ID and length).
437   WireBytesRef code = {0, 0};
438   WireBytesRef name = {0, 0};
439 
add_typeWasmModule440   void add_type(TypeDefinition type) {
441     types.push_back(type);
442     uint32_t canonical_id = type.kind == TypeDefinition::kFunction
443                                 ? signature_map.FindOrInsert(*type.function_sig)
444                                 : 0;
445     canonicalized_type_ids.push_back(canonical_id);
446     // Canonical type will be computed later.
447     isorecursive_canonical_type_ids.push_back(kNoSuperType);
448   }
449 
has_typeWasmModule450   bool has_type(uint32_t index) const { return index < types.size(); }
451 
add_signatureWasmModule452   void add_signature(const FunctionSig* sig, uint32_t supertype) {
453     DCHECK_NOT_NULL(sig);
454     add_type(TypeDefinition(sig, supertype));
455   }
has_signatureWasmModule456   bool has_signature(uint32_t index) const {
457     return index < types.size() &&
458            types[index].kind == TypeDefinition::kFunction;
459   }
signatureWasmModule460   const FunctionSig* signature(uint32_t index) const {
461     DCHECK(has_signature(index));
462     return types[index].function_sig;
463   }
464 
add_struct_typeWasmModule465   void add_struct_type(const StructType* type, uint32_t supertype) {
466     DCHECK_NOT_NULL(type);
467     add_type(TypeDefinition(type, supertype));
468   }
has_structWasmModule469   bool has_struct(uint32_t index) const {
470     return index < types.size() && types[index].kind == TypeDefinition::kStruct;
471   }
struct_typeWasmModule472   const StructType* struct_type(uint32_t index) const {
473     DCHECK(has_struct(index));
474     return types[index].struct_type;
475   }
476 
add_array_typeWasmModule477   void add_array_type(const ArrayType* type, uint32_t supertype) {
478     DCHECK_NOT_NULL(type);
479     add_type(TypeDefinition(type, supertype));
480   }
has_arrayWasmModule481   bool has_array(uint32_t index) const {
482     return index < types.size() && types[index].kind == TypeDefinition::kArray;
483   }
array_typeWasmModule484   const ArrayType* array_type(uint32_t index) const {
485     DCHECK(has_array(index));
486     return types[index].array_type;
487   }
488 
supertypeWasmModule489   uint32_t supertype(uint32_t index) const {
490     DCHECK(index < types.size());
491     return types[index].supertype;
492   }
has_supertypeWasmModule493   bool has_supertype(uint32_t index) const {
494     return supertype(index) != kNoSuperType;
495   }
496 
497   std::vector<TypeDefinition> types;  // by type index
498   // TODO(7748): Unify the following two arrays.
499   // Maps each type index to a canonical index for purposes of call_indirect.
500   std::vector<uint32_t> canonicalized_type_ids;
501   // Maps each type index to its global (cross-module) canonical index as per
502   // isorecursive type canonicalization.
503   std::vector<uint32_t> isorecursive_canonical_type_ids;
504   // Canonicalizing map for signature indexes.
505   SignatureMap signature_map;
506   std::vector<WasmFunction> functions;
507   std::vector<WasmGlobal> globals;
508   std::vector<WasmDataSegment> data_segments;
509   std::vector<WasmTable> tables;
510   std::vector<WasmImport> import_table;
511   std::vector<WasmExport> export_table;
512   std::vector<WasmTag> tags;
513   std::vector<WasmElemSegment> elem_segments;
514   std::vector<WasmCompilationHint> compilation_hints;
515   BranchHintInfo branch_hints;
516   mutable TypeFeedbackStorage type_feedback;
517 
518   ModuleOrigin origin = kWasmOrigin;  // origin of the module
519   LazilyGeneratedNames lazily_generated_names;
520   WasmDebugSymbols debug_symbols;
521 
522   // Asm.js source position information. Only available for modules compiled
523   // from asm.js.
524   std::unique_ptr<AsmJsOffsetInformation> asm_js_offset_information;
525 
526   explicit WasmModule(std::unique_ptr<Zone> signature_zone = nullptr);
527   WasmModule(const WasmModule&) = delete;
528   WasmModule& operator=(const WasmModule&) = delete;
529 };
530 
531 // Static representation of a wasm indirect call table.
532 struct WasmTable {
533   MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(WasmTable);
534 
535   // 'module' can be nullptr
536   // TODO(9495): Update this function as more table types are supported, or
537   // remove it completely when all reference types are allowed.
IsValidTableTypeWasmTable538   static bool IsValidTableType(ValueType type, const WasmModule* module) {
539     if (!type.is_object_reference()) return false;
540     HeapType heap_type = type.heap_type();
541     return heap_type == HeapType::kFunc || heap_type == HeapType::kAny ||
542            (module != nullptr && heap_type.is_index() &&
543             module->has_signature(heap_type.ref_index()));
544   }
545 
546   ValueType type = kWasmVoid;     // table type.
547   uint32_t initial_size = 0;      // initial table size.
548   uint32_t maximum_size = 0;      // maximum table size.
549   bool has_maximum_size = false;  // true if there is a maximum size.
550   bool imported = false;          // true if imported.
551   bool exported = false;          // true if exported.
552   ConstantExpression initial_value;
553 };
554 
is_asmjs_module(const WasmModule * module)555 inline bool is_asmjs_module(const WasmModule* module) {
556   return module->origin != kWasmOrigin;
557 }
558 
559 size_t EstimateStoredSize(const WasmModule* module);
560 
561 // Returns the number of possible export wrappers for a given module.
562 V8_EXPORT_PRIVATE int MaxNumExportWrappers(const WasmModule* module);
563 
564 // Returns the wrapper index for a function in {module} with signature {sig}
565 // or {sig_index} and origin defined by {is_import}.
566 // Prefer to use the {sig_index} consuming version, as it is much faster.
567 int GetExportWrapperIndex(const WasmModule* module, const FunctionSig* sig,
568                           bool is_import);
569 int GetExportWrapperIndex(const WasmModule* module, uint32_t sig_index,
570                           bool is_import);
571 
572 // Return the byte offset of the function identified by the given index.
573 // The offset will be relative to the start of the module bytes.
574 // Returns -1 if the function index is invalid.
575 int GetWasmFunctionOffset(const WasmModule* module, uint32_t func_index);
576 
577 // Returns the function containing the given byte offset.
578 // Returns -1 if the byte offset is not contained in any
579 // function of this module.
580 int GetContainingWasmFunction(const WasmModule* module, uint32_t byte_offset);
581 
582 // Returns the function containing the given byte offset.
583 // Will return preceding function if the byte offset is not
584 // contained within a function.
585 int GetNearestWasmFunction(const WasmModule* module, uint32_t byte_offset);
586 
587 // Gets the explicitly defined subtyping depth for the given type.
588 // Returns 0 if the type has no explicit supertype.
589 // The result is capped to {kV8MaxRttSubtypingDepth + 1}.
590 // Invalid cyclic hierarchies will return -1.
591 V8_EXPORT_PRIVATE int GetSubtypingDepth(const WasmModule* module,
592                                         uint32_t type_index);
593 
594 // Interface to the storage (wire bytes) of a wasm module.
595 // It is illegal for anyone receiving a ModuleWireBytes to store pointers based
596 // on module_bytes, as this storage is only guaranteed to be alive as long as
597 // this struct is alive.
598 struct V8_EXPORT_PRIVATE ModuleWireBytes {
ModuleWireBytesModuleWireBytes599   explicit ModuleWireBytes(base::Vector<const byte> module_bytes)
600       : module_bytes_(module_bytes) {}
ModuleWireBytesModuleWireBytes601   ModuleWireBytes(const byte* start, const byte* end)
602       : module_bytes_(start, static_cast<int>(end - start)) {
603     DCHECK_GE(kMaxInt, end - start);
604   }
605 
606   // Get a string stored in the module bytes representing a name.
607   WasmName GetNameOrNull(WireBytesRef ref) const;
608 
609   // Get a string stored in the module bytes representing a function name.
610   WasmName GetNameOrNull(const WasmFunction* function,
611                          const WasmModule* module) const;
612 
613   // Checks the given reference is contained within the module bytes.
BoundsCheckModuleWireBytes614   bool BoundsCheck(WireBytesRef ref) const {
615     uint32_t size = static_cast<uint32_t>(module_bytes_.length());
616     return ref.offset() <= size && ref.length() <= size - ref.offset();
617   }
618 
GetFunctionBytesModuleWireBytes619   base::Vector<const byte> GetFunctionBytes(
620       const WasmFunction* function) const {
621     return module_bytes_.SubVector(function->code.offset(),
622                                    function->code.end_offset());
623   }
624 
module_bytesModuleWireBytes625   base::Vector<const byte> module_bytes() const { return module_bytes_; }
startModuleWireBytes626   const byte* start() const { return module_bytes_.begin(); }
endModuleWireBytes627   const byte* end() const { return module_bytes_.end(); }
lengthModuleWireBytes628   size_t length() const { return module_bytes_.length(); }
629 
630  private:
631   base::Vector<const byte> module_bytes_;
632 };
633 
634 // A helper for printing out the names of functions.
635 struct WasmFunctionName {
WasmFunctionNameWasmFunctionName636   WasmFunctionName(const WasmFunction* function, WasmName name)
637       : function_(function), name_(name) {}
638 
639   const WasmFunction* function_;
640   const WasmName name_;
641 };
642 
643 std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name);
644 
645 V8_EXPORT_PRIVATE bool IsWasmCodegenAllowed(Isolate* isolate,
646                                             Handle<Context> context);
647 
648 Handle<JSObject> GetTypeForFunction(Isolate* isolate, const FunctionSig* sig,
649                                     bool for_exception = false);
650 Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable,
651                                   ValueType type);
652 Handle<JSObject> GetTypeForMemory(Isolate* isolate, uint32_t min_size,
653                                   base::Optional<uint32_t> max_size,
654                                   bool shared);
655 Handle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type,
656                                  uint32_t min_size,
657                                  base::Optional<uint32_t> max_size);
658 Handle<JSArray> GetImports(Isolate* isolate, Handle<WasmModuleObject> module);
659 Handle<JSArray> GetExports(Isolate* isolate, Handle<WasmModuleObject> module);
660 Handle<JSArray> GetCustomSections(Isolate* isolate,
661                                   Handle<WasmModuleObject> module,
662                                   Handle<String> name, ErrorThrower* thrower);
663 
664 // Get the source position from a given function index and byte offset,
665 // for either asm.js or pure Wasm modules.
666 int GetSourcePosition(const WasmModule*, uint32_t func_index,
667                       uint32_t byte_offset, bool is_at_number_conversion);
668 
669 // Translate function index to the index relative to the first declared (i.e.
670 // non-imported) function.
declared_function_index(const WasmModule * module,int func_index)671 inline int declared_function_index(const WasmModule* module, int func_index) {
672   DCHECK_LE(module->num_imported_functions, func_index);
673   int declared_idx = func_index - module->num_imported_functions;
674   DCHECK_GT(module->num_declared_functions, declared_idx);
675   return declared_idx;
676 }
677 
678 // TruncatedUserString makes it easy to output names up to a certain length, and
679 // output a truncation followed by '...' if they exceed a limit.
680 // Use like this:
681 //   TruncatedUserString<> name (pc, len);
682 //   printf("... %.*s ...", name.length(), name.start())
683 template <int kMaxLen = 50>
684 class TruncatedUserString {
685   static_assert(kMaxLen >= 4, "minimum length is 4 (length of '...' plus one)");
686 
687  public:
688   template <typename T>
TruncatedUserString(base::Vector<T> name)689   explicit TruncatedUserString(base::Vector<T> name)
690       : TruncatedUserString(name.begin(), name.length()) {}
691 
TruncatedUserString(const byte * start,size_t len)692   TruncatedUserString(const byte* start, size_t len)
693       : TruncatedUserString(reinterpret_cast<const char*>(start), len) {}
694 
TruncatedUserString(const char * start,size_t len)695   TruncatedUserString(const char* start, size_t len)
696       : start_(start), length_(std::min(kMaxLen, static_cast<int>(len))) {
697     if (len > static_cast<size_t>(kMaxLen)) {
698       memcpy(buffer_, start, kMaxLen - 3);
699       memset(buffer_ + kMaxLen - 3, '.', 3);
700       start_ = buffer_;
701     }
702   }
703 
start()704   const char* start() const { return start_; }
705 
length()706   int length() const { return length_; }
707 
708  private:
709   const char* start_;
710   const int length_;
711   char buffer_[kMaxLen];
712 };
713 
714 // Print the signature into the given {buffer}, using {delimiter} as separator
715 // between parameter types and return types. If {buffer} is non-empty, it will
716 // be null-terminated, even if the signature is cut off. Returns the number of
717 // characters written, excluding the terminating null-byte.
718 size_t PrintSignature(base::Vector<char> buffer, const wasm::FunctionSig*,
719                       char delimiter = ':');
720 
721 }  // namespace wasm
722 }  // namespace internal
723 }  // namespace v8
724 
725 #endif  // V8_WASM_WASM_MODULE_H_
726