• 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 #include "src/wasm/wasm-module.h"
6 
7 #include <functional>
8 #include <memory>
9 
10 #include "src/api/api-inl.h"
11 #include "src/base/platform/wrappers.h"
12 #include "src/codegen/assembler-inl.h"
13 #include "src/compiler/wasm-compiler.h"
14 #include "src/debug/interface-types.h"
15 #include "src/execution/frames-inl.h"
16 #include "src/execution/simulator.h"
17 #include "src/init/v8.h"
18 #include "src/objects/js-array-inl.h"
19 #include "src/objects/objects.h"
20 #include "src/objects/property-descriptor.h"
21 #include "src/snapshot/snapshot.h"
22 #include "src/wasm/module-decoder.h"
23 #include "src/wasm/wasm-code-manager.h"
24 #include "src/wasm/wasm-init-expr.h"
25 #include "src/wasm/wasm-js.h"
26 #include "src/wasm/wasm-objects-inl.h"
27 #include "src/wasm/wasm-result.h"
28 #include "src/wasm/wasm-subtyping.h"
29 
30 namespace v8 {
31 namespace internal {
32 namespace wasm {
33 
LookupFunctionName(const ModuleWireBytes & wire_bytes,uint32_t function_index) const34 WireBytesRef LazilyGeneratedNames::LookupFunctionName(
35     const ModuleWireBytes& wire_bytes, uint32_t function_index) const {
36   base::MutexGuard lock(&mutex_);
37   if (!function_names_) {
38     function_names_.reset(new std::unordered_map<uint32_t, WireBytesRef>());
39     DecodeFunctionNames(wire_bytes.start(), wire_bytes.end(),
40                         function_names_.get());
41   }
42   auto it = function_names_->find(function_index);
43   if (it == function_names_->end()) return WireBytesRef();
44   return it->second;
45 }
46 
47 // static
MaxNumExportWrappers(const WasmModule * module)48 int MaxNumExportWrappers(const WasmModule* module) {
49   // For each signature there may exist a wrapper, both for imported and
50   // internal functions.
51   return static_cast<int>(module->signature_map.size()) * 2;
52 }
53 
GetExportWrapperIndexInternal(const WasmModule * module,int canonical_sig_index,bool is_import)54 int GetExportWrapperIndexInternal(const WasmModule* module,
55                                   int canonical_sig_index, bool is_import) {
56   if (is_import) canonical_sig_index += module->signature_map.size();
57   return canonical_sig_index;
58 }
59 
GetExportWrapperIndex(const WasmModule * module,const FunctionSig * sig,bool is_import)60 int GetExportWrapperIndex(const WasmModule* module, const FunctionSig* sig,
61                           bool is_import) {
62   int canonical_sig_index = module->signature_map.Find(*sig);
63   CHECK_GE(canonical_sig_index, 0);
64   return GetExportWrapperIndexInternal(module, canonical_sig_index, is_import);
65 }
66 
GetExportWrapperIndex(const WasmModule * module,uint32_t sig_index,bool is_import)67 int GetExportWrapperIndex(const WasmModule* module, uint32_t sig_index,
68                           bool is_import) {
69   uint32_t canonical_sig_index = module->canonicalized_type_ids[sig_index];
70   return GetExportWrapperIndexInternal(module, canonical_sig_index, is_import);
71 }
72 
73 // static
GetWasmFunctionOffset(const WasmModule * module,uint32_t func_index)74 int GetWasmFunctionOffset(const WasmModule* module, uint32_t func_index) {
75   const std::vector<WasmFunction>& functions = module->functions;
76   if (static_cast<uint32_t>(func_index) >= functions.size()) return -1;
77   DCHECK_GE(kMaxInt, functions[func_index].code.offset());
78   return static_cast<int>(functions[func_index].code.offset());
79 }
80 
81 // static
GetNearestWasmFunction(const WasmModule * module,uint32_t byte_offset)82 int GetNearestWasmFunction(const WasmModule* module, uint32_t byte_offset) {
83   const std::vector<WasmFunction>& functions = module->functions;
84 
85   // Binary search for a function containing the given position.
86   int left = 0;                                    // inclusive
87   int right = static_cast<int>(functions.size());  // exclusive
88   if (right == 0) return -1;
89   while (right - left > 1) {
90     int mid = left + (right - left) / 2;
91     if (functions[mid].code.offset() <= byte_offset) {
92       left = mid;
93     } else {
94       right = mid;
95     }
96   }
97 
98   return left;
99 }
100 
101 // static
GetContainingWasmFunction(const WasmModule * module,uint32_t byte_offset)102 int GetContainingWasmFunction(const WasmModule* module, uint32_t byte_offset) {
103   int func_index = GetNearestWasmFunction(module, byte_offset);
104 
105   if (func_index >= 0) {
106     // If the found function does not contain the given position, return -1.
107     const WasmFunction& func = module->functions[func_index];
108     if (byte_offset < func.code.offset() ||
109         byte_offset >= func.code.end_offset()) {
110       return -1;
111     }
112   }
113   return func_index;
114 }
115 
116 // TODO(7748): Measure whether this iterative implementation is fast enough.
117 // We could cache the result on the module, in yet another vector indexed by
118 // type index.
GetSubtypingDepth(const WasmModule * module,uint32_t type_index)119 int GetSubtypingDepth(const WasmModule* module, uint32_t type_index) {
120   uint32_t starting_point = type_index;
121   int depth = 0;
122   while ((type_index = module->supertype(type_index)) != kNoSuperType) {
123     if (type_index == starting_point) return -1;  // Cycle detected.
124     depth++;
125     if (depth > static_cast<int>(kV8MaxRttSubtypingDepth)) break;
126   }
127   return depth;
128 }
129 
AddForTesting(int function_index,WireBytesRef name)130 void LazilyGeneratedNames::AddForTesting(int function_index,
131                                          WireBytesRef name) {
132   base::MutexGuard lock(&mutex_);
133   if (!function_names_) {
134     function_names_.reset(new std::unordered_map<uint32_t, WireBytesRef>());
135   }
136   function_names_->insert(std::make_pair(function_index, name));
137 }
138 
AsmJsOffsetInformation(base::Vector<const byte> encoded_offsets)139 AsmJsOffsetInformation::AsmJsOffsetInformation(
140     base::Vector<const byte> encoded_offsets)
141     : encoded_offsets_(base::OwnedVector<const uint8_t>::Of(encoded_offsets)) {}
142 
143 AsmJsOffsetInformation::~AsmJsOffsetInformation() = default;
144 
GetSourcePosition(int declared_func_index,int byte_offset,bool is_at_number_conversion)145 int AsmJsOffsetInformation::GetSourcePosition(int declared_func_index,
146                                               int byte_offset,
147                                               bool is_at_number_conversion) {
148   EnsureDecodedOffsets();
149 
150   DCHECK_LE(0, declared_func_index);
151   DCHECK_GT(decoded_offsets_->functions.size(), declared_func_index);
152   std::vector<AsmJsOffsetEntry>& function_offsets =
153       decoded_offsets_->functions[declared_func_index].entries;
154 
155   auto byte_offset_less = [](const AsmJsOffsetEntry& a,
156                              const AsmJsOffsetEntry& b) {
157     return a.byte_offset < b.byte_offset;
158   };
159   SLOW_DCHECK(std::is_sorted(function_offsets.begin(), function_offsets.end(),
160                              byte_offset_less));
161   auto it =
162       std::lower_bound(function_offsets.begin(), function_offsets.end(),
163                        AsmJsOffsetEntry{byte_offset, 0, 0}, byte_offset_less);
164   DCHECK_NE(function_offsets.end(), it);
165   DCHECK_EQ(byte_offset, it->byte_offset);
166   return is_at_number_conversion ? it->source_position_number_conversion
167                                  : it->source_position_call;
168 }
169 
GetFunctionOffsets(int declared_func_index)170 std::pair<int, int> AsmJsOffsetInformation::GetFunctionOffsets(
171     int declared_func_index) {
172   EnsureDecodedOffsets();
173 
174   DCHECK_LE(0, declared_func_index);
175   DCHECK_GT(decoded_offsets_->functions.size(), declared_func_index);
176   AsmJsOffsetFunctionEntries& function_info =
177       decoded_offsets_->functions[declared_func_index];
178 
179   return {function_info.start_offset, function_info.end_offset};
180 }
181 
EnsureDecodedOffsets()182 void AsmJsOffsetInformation::EnsureDecodedOffsets() {
183   base::MutexGuard mutex_guard(&mutex_);
184   DCHECK_EQ(encoded_offsets_ == nullptr, decoded_offsets_ != nullptr);
185 
186   if (decoded_offsets_) return;
187   AsmJsOffsetsResult result =
188       wasm::DecodeAsmJsOffsets(encoded_offsets_.as_vector());
189   decoded_offsets_ = std::make_unique<AsmJsOffsets>(std::move(result).value());
190   encoded_offsets_.ReleaseData();
191 }
192 
193 // Get a string stored in the module bytes representing a name.
GetNameOrNull(WireBytesRef ref) const194 WasmName ModuleWireBytes::GetNameOrNull(WireBytesRef ref) const {
195   if (!ref.is_set()) return {nullptr, 0};  // no name.
196   DCHECK(BoundsCheck(ref));
197   return WasmName::cast(
198       module_bytes_.SubVector(ref.offset(), ref.end_offset()));
199 }
200 
201 // Get a string stored in the module bytes representing a function name.
GetNameOrNull(const WasmFunction * function,const WasmModule * module) const202 WasmName ModuleWireBytes::GetNameOrNull(const WasmFunction* function,
203                                         const WasmModule* module) const {
204   return GetNameOrNull(module->lazily_generated_names.LookupFunctionName(
205       *this, function->func_index));
206 }
207 
operator <<(std::ostream & os,const WasmFunctionName & name)208 std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name) {
209   os << "#" << name.function_->func_index;
210   if (!name.name_.empty()) {
211     if (name.name_.begin()) {
212       os << ":";
213       os.write(name.name_.begin(), name.name_.length());
214     }
215   } else {
216     os << "?";
217   }
218   return os;
219 }
220 
WasmModule(std::unique_ptr<Zone> signature_zone)221 WasmModule::WasmModule(std::unique_ptr<Zone> signature_zone)
222     : signature_zone(std::move(signature_zone)) {}
223 
IsWasmCodegenAllowed(Isolate * isolate,Handle<Context> context)224 bool IsWasmCodegenAllowed(Isolate* isolate, Handle<Context> context) {
225   // TODO(wasm): Once wasm has its own CSP policy, we should introduce a
226   // separate callback that includes information about the module about to be
227   // compiled. For the time being, pass an empty string as placeholder for the
228   // sources.
229   if (auto wasm_codegen_callback = isolate->allow_wasm_code_gen_callback()) {
230     return wasm_codegen_callback(
231         v8::Utils::ToLocal(context),
232         v8::Utils::ToLocal(isolate->factory()->empty_string()));
233   }
234   auto codegen_callback = isolate->allow_code_gen_callback();
235   return codegen_callback == nullptr ||
236          codegen_callback(
237              v8::Utils::ToLocal(context),
238              v8::Utils::ToLocal(isolate->factory()->empty_string()));
239 }
240 
241 namespace {
242 
243 // Converts the given {type} into a string representation that can be used in
244 // reflective functions. Should be kept in sync with the {GetValueType} helper.
ToValueTypeString(Isolate * isolate,ValueType type)245 Handle<String> ToValueTypeString(Isolate* isolate, ValueType type) {
246   return isolate->factory()->InternalizeUtf8String(base::VectorOf(type.name()));
247 }
248 }  // namespace
249 
GetTypeForFunction(Isolate * isolate,const FunctionSig * sig,bool for_exception)250 Handle<JSObject> GetTypeForFunction(Isolate* isolate, const FunctionSig* sig,
251                                     bool for_exception) {
252   Factory* factory = isolate->factory();
253 
254   // Extract values for the {ValueType[]} arrays.
255   int param_index = 0;
256   int param_count = static_cast<int>(sig->parameter_count());
257   Handle<FixedArray> param_values = factory->NewFixedArray(param_count);
258   for (ValueType type : sig->parameters()) {
259     Handle<String> type_value = ToValueTypeString(isolate, type);
260     param_values->set(param_index++, *type_value);
261   }
262 
263   // Create the resulting {FunctionType} object.
264   Handle<JSFunction> object_function = isolate->object_function();
265   Handle<JSObject> object = factory->NewJSObject(object_function);
266   Handle<JSArray> params = factory->NewJSArrayWithElements(param_values);
267   Handle<String> params_string = factory->InternalizeUtf8String("parameters");
268   Handle<String> results_string = factory->InternalizeUtf8String("results");
269   JSObject::AddProperty(isolate, object, params_string, params, NONE);
270 
271   // Now add the result types if needed.
272   if (for_exception) {
273     DCHECK_EQ(sig->returns().size(), 0);
274   } else {
275     int result_index = 0;
276     int result_count = static_cast<int>(sig->return_count());
277     Handle<FixedArray> result_values = factory->NewFixedArray(result_count);
278     for (ValueType type : sig->returns()) {
279       Handle<String> type_value = ToValueTypeString(isolate, type);
280       result_values->set(result_index++, *type_value);
281     }
282     Handle<JSArray> results = factory->NewJSArrayWithElements(result_values);
283     JSObject::AddProperty(isolate, object, results_string, results, NONE);
284   }
285 
286   return object;
287 }
288 
GetTypeForGlobal(Isolate * isolate,bool is_mutable,ValueType type)289 Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable,
290                                   ValueType type) {
291   Factory* factory = isolate->factory();
292 
293   Handle<JSFunction> object_function = isolate->object_function();
294   Handle<JSObject> object = factory->NewJSObject(object_function);
295   Handle<String> mutable_string = factory->InternalizeUtf8String("mutable");
296   Handle<String> value_string = factory->InternalizeUtf8String("value");
297   JSObject::AddProperty(isolate, object, mutable_string,
298                         factory->ToBoolean(is_mutable), NONE);
299   JSObject::AddProperty(isolate, object, value_string,
300                         ToValueTypeString(isolate, type), NONE);
301 
302   return object;
303 }
304 
GetTypeForMemory(Isolate * isolate,uint32_t min_size,base::Optional<uint32_t> max_size,bool shared)305 Handle<JSObject> GetTypeForMemory(Isolate* isolate, uint32_t min_size,
306                                   base::Optional<uint32_t> max_size,
307                                   bool shared) {
308   Factory* factory = isolate->factory();
309 
310   Handle<JSFunction> object_function = isolate->object_function();
311   Handle<JSObject> object = factory->NewJSObject(object_function);
312   Handle<String> minimum_string = factory->InternalizeUtf8String("minimum");
313   Handle<String> maximum_string = factory->InternalizeUtf8String("maximum");
314   Handle<String> shared_string = factory->InternalizeUtf8String("shared");
315   JSObject::AddProperty(isolate, object, minimum_string,
316                         factory->NewNumberFromUint(min_size), NONE);
317   if (max_size.has_value()) {
318     JSObject::AddProperty(isolate, object, maximum_string,
319                           factory->NewNumberFromUint(max_size.value()), NONE);
320   }
321   JSObject::AddProperty(isolate, object, shared_string,
322                         factory->ToBoolean(shared), NONE);
323 
324   return object;
325 }
326 
GetTypeForTable(Isolate * isolate,ValueType type,uint32_t min_size,base::Optional<uint32_t> max_size)327 Handle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type,
328                                  uint32_t min_size,
329                                  base::Optional<uint32_t> max_size) {
330   Factory* factory = isolate->factory();
331 
332   Handle<String> element =
333       factory->InternalizeUtf8String(base::VectorOf(type.name()));
334 
335   Handle<JSFunction> object_function = isolate->object_function();
336   Handle<JSObject> object = factory->NewJSObject(object_function);
337   Handle<String> element_string = factory->InternalizeUtf8String("element");
338   Handle<String> minimum_string = factory->InternalizeUtf8String("minimum");
339   Handle<String> maximum_string = factory->InternalizeUtf8String("maximum");
340   JSObject::AddProperty(isolate, object, element_string, element, NONE);
341   JSObject::AddProperty(isolate, object, minimum_string,
342                         factory->NewNumberFromUint(min_size), NONE);
343   if (max_size.has_value()) {
344     JSObject::AddProperty(isolate, object, maximum_string,
345                           factory->NewNumberFromUint(max_size.value()), NONE);
346   }
347 
348   return object;
349 }
350 
GetImports(Isolate * isolate,Handle<WasmModuleObject> module_object)351 Handle<JSArray> GetImports(Isolate* isolate,
352                            Handle<WasmModuleObject> module_object) {
353   auto enabled_features = i::wasm::WasmFeatures::FromIsolate(isolate);
354   Factory* factory = isolate->factory();
355 
356   Handle<String> module_string = factory->InternalizeUtf8String("module");
357   Handle<String> name_string = factory->InternalizeUtf8String("name");
358   Handle<String> kind_string = factory->InternalizeUtf8String("kind");
359   Handle<String> type_string = factory->InternalizeUtf8String("type");
360 
361   Handle<String> function_string = factory->InternalizeUtf8String("function");
362   Handle<String> table_string = factory->InternalizeUtf8String("table");
363   Handle<String> memory_string = factory->InternalizeUtf8String("memory");
364   Handle<String> global_string = factory->InternalizeUtf8String("global");
365   Handle<String> tag_string = factory->InternalizeUtf8String("tag");
366 
367   // Create the result array.
368   const WasmModule* module = module_object->module();
369   int num_imports = static_cast<int>(module->import_table.size());
370   Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
371   Handle<FixedArray> storage = factory->NewFixedArray(num_imports);
372   JSArray::SetContent(array_object, storage);
373   array_object->set_length(Smi::FromInt(num_imports));
374 
375   Handle<JSFunction> object_function =
376       Handle<JSFunction>(isolate->native_context()->object_function(), isolate);
377 
378   // Populate the result array.
379   for (int index = 0; index < num_imports; ++index) {
380     const WasmImport& import = module->import_table[index];
381 
382     Handle<JSObject> entry = factory->NewJSObject(object_function);
383 
384     Handle<String> import_kind;
385     Handle<JSObject> type_value;
386     switch (import.kind) {
387       case kExternalFunction:
388         if (enabled_features.has_type_reflection()) {
389           auto& func = module->functions[import.index];
390           type_value = GetTypeForFunction(isolate, func.sig);
391         }
392         import_kind = function_string;
393         break;
394       case kExternalTable:
395         if (enabled_features.has_type_reflection()) {
396           auto& table = module->tables[import.index];
397           base::Optional<uint32_t> maximum_size;
398           if (table.has_maximum_size) maximum_size.emplace(table.maximum_size);
399           type_value = GetTypeForTable(isolate, table.type, table.initial_size,
400                                        maximum_size);
401         }
402         import_kind = table_string;
403         break;
404       case kExternalMemory:
405         if (enabled_features.has_type_reflection()) {
406           DCHECK_EQ(0, import.index);  // Only one memory supported.
407           base::Optional<uint32_t> maximum_size;
408           if (module->has_maximum_pages) {
409             maximum_size.emplace(module->maximum_pages);
410           }
411           type_value =
412               GetTypeForMemory(isolate, module->initial_pages, maximum_size,
413                                module->has_shared_memory);
414         }
415         import_kind = memory_string;
416         break;
417       case kExternalGlobal:
418         if (enabled_features.has_type_reflection()) {
419           auto& global = module->globals[import.index];
420           type_value =
421               GetTypeForGlobal(isolate, global.mutability, global.type);
422         }
423         import_kind = global_string;
424         break;
425       case kExternalTag:
426         import_kind = tag_string;
427         break;
428     }
429     DCHECK(!import_kind->is_null());
430 
431     Handle<String> import_module =
432         WasmModuleObject::ExtractUtf8StringFromModuleBytes(
433             isolate, module_object, import.module_name, kInternalize);
434 
435     Handle<String> import_name =
436         WasmModuleObject::ExtractUtf8StringFromModuleBytes(
437             isolate, module_object, import.field_name, kInternalize);
438 
439     JSObject::AddProperty(isolate, entry, module_string, import_module, NONE);
440     JSObject::AddProperty(isolate, entry, name_string, import_name, NONE);
441     JSObject::AddProperty(isolate, entry, kind_string, import_kind, NONE);
442     if (!type_value.is_null()) {
443       JSObject::AddProperty(isolate, entry, type_string, type_value, NONE);
444     }
445 
446     storage->set(index, *entry);
447   }
448 
449   return array_object;
450 }
451 
GetExports(Isolate * isolate,Handle<WasmModuleObject> module_object)452 Handle<JSArray> GetExports(Isolate* isolate,
453                            Handle<WasmModuleObject> module_object) {
454   auto enabled_features = i::wasm::WasmFeatures::FromIsolate(isolate);
455   Factory* factory = isolate->factory();
456 
457   Handle<String> name_string = factory->InternalizeUtf8String("name");
458   Handle<String> kind_string = factory->InternalizeUtf8String("kind");
459   Handle<String> type_string = factory->InternalizeUtf8String("type");
460 
461   Handle<String> function_string = factory->InternalizeUtf8String("function");
462   Handle<String> table_string = factory->InternalizeUtf8String("table");
463   Handle<String> memory_string = factory->InternalizeUtf8String("memory");
464   Handle<String> global_string = factory->InternalizeUtf8String("global");
465   Handle<String> tag_string = factory->InternalizeUtf8String("tag");
466 
467   // Create the result array.
468   const WasmModule* module = module_object->module();
469   int num_exports = static_cast<int>(module->export_table.size());
470   Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
471   Handle<FixedArray> storage = factory->NewFixedArray(num_exports);
472   JSArray::SetContent(array_object, storage);
473   array_object->set_length(Smi::FromInt(num_exports));
474 
475   Handle<JSFunction> object_function =
476       Handle<JSFunction>(isolate->native_context()->object_function(), isolate);
477 
478   // Populate the result array.
479   for (int index = 0; index < num_exports; ++index) {
480     const WasmExport& exp = module->export_table[index];
481 
482     Handle<String> export_kind;
483     Handle<JSObject> type_value;
484     switch (exp.kind) {
485       case kExternalFunction:
486         if (enabled_features.has_type_reflection()) {
487           auto& func = module->functions[exp.index];
488           type_value = GetTypeForFunction(isolate, func.sig);
489         }
490         export_kind = function_string;
491         break;
492       case kExternalTable:
493         if (enabled_features.has_type_reflection()) {
494           auto& table = module->tables[exp.index];
495           base::Optional<uint32_t> maximum_size;
496           if (table.has_maximum_size) maximum_size.emplace(table.maximum_size);
497           type_value = GetTypeForTable(isolate, table.type, table.initial_size,
498                                        maximum_size);
499         }
500         export_kind = table_string;
501         break;
502       case kExternalMemory:
503         if (enabled_features.has_type_reflection()) {
504           DCHECK_EQ(0, exp.index);  // Only one memory supported.
505           base::Optional<uint32_t> maximum_size;
506           if (module->has_maximum_pages) {
507             maximum_size.emplace(module->maximum_pages);
508           }
509           type_value =
510               GetTypeForMemory(isolate, module->initial_pages, maximum_size,
511                                module->has_shared_memory);
512         }
513         export_kind = memory_string;
514         break;
515       case kExternalGlobal:
516         if (enabled_features.has_type_reflection()) {
517           auto& global = module->globals[exp.index];
518           type_value =
519               GetTypeForGlobal(isolate, global.mutability, global.type);
520         }
521         export_kind = global_string;
522         break;
523       case kExternalTag:
524         export_kind = tag_string;
525         break;
526       default:
527         UNREACHABLE();
528     }
529 
530     Handle<JSObject> entry = factory->NewJSObject(object_function);
531 
532     Handle<String> export_name =
533         WasmModuleObject::ExtractUtf8StringFromModuleBytes(
534             isolate, module_object, exp.name, kNoInternalize);
535 
536     JSObject::AddProperty(isolate, entry, name_string, export_name, NONE);
537     JSObject::AddProperty(isolate, entry, kind_string, export_kind, NONE);
538     if (!type_value.is_null()) {
539       JSObject::AddProperty(isolate, entry, type_string, type_value, NONE);
540     }
541 
542     storage->set(index, *entry);
543   }
544 
545   return array_object;
546 }
547 
GetCustomSections(Isolate * isolate,Handle<WasmModuleObject> module_object,Handle<String> name,ErrorThrower * thrower)548 Handle<JSArray> GetCustomSections(Isolate* isolate,
549                                   Handle<WasmModuleObject> module_object,
550                                   Handle<String> name, ErrorThrower* thrower) {
551   Factory* factory = isolate->factory();
552 
553   base::Vector<const uint8_t> wire_bytes =
554       module_object->native_module()->wire_bytes();
555   std::vector<CustomSectionOffset> custom_sections =
556       DecodeCustomSections(wire_bytes.begin(), wire_bytes.end());
557 
558   std::vector<Handle<Object>> matching_sections;
559 
560   // Gather matching sections.
561   for (auto& section : custom_sections) {
562     Handle<String> section_name =
563         WasmModuleObject::ExtractUtf8StringFromModuleBytes(
564             isolate, module_object, section.name, kNoInternalize);
565 
566     if (!name->Equals(*section_name)) continue;
567 
568     // Make a copy of the payload data in the section.
569     size_t size = section.payload.length();
570     MaybeHandle<JSArrayBuffer> result =
571         isolate->factory()->NewJSArrayBufferAndBackingStore(
572             size, InitializedFlag::kUninitialized);
573     Handle<JSArrayBuffer> array_buffer;
574     if (!result.ToHandle(&array_buffer)) {
575       thrower->RangeError("out of memory allocating custom section data");
576       return Handle<JSArray>();
577     }
578     memcpy(array_buffer->backing_store(),
579            wire_bytes.begin() + section.payload.offset(),
580            section.payload.length());
581 
582     matching_sections.push_back(array_buffer);
583   }
584 
585   int num_custom_sections = static_cast<int>(matching_sections.size());
586   Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
587   Handle<FixedArray> storage = factory->NewFixedArray(num_custom_sections);
588   JSArray::SetContent(array_object, storage);
589   array_object->set_length(Smi::FromInt(num_custom_sections));
590 
591   for (int i = 0; i < num_custom_sections; i++) {
592     storage->set(i, *matching_sections[i]);
593   }
594 
595   return array_object;
596 }
597 
598 // Get the source position from a given function index and byte offset,
599 // for either asm.js or pure Wasm modules.
GetSourcePosition(const WasmModule * module,uint32_t func_index,uint32_t byte_offset,bool is_at_number_conversion)600 int GetSourcePosition(const WasmModule* module, uint32_t func_index,
601                       uint32_t byte_offset, bool is_at_number_conversion) {
602   DCHECK_EQ(is_asmjs_module(module),
603             module->asm_js_offset_information != nullptr);
604   if (!is_asmjs_module(module)) {
605     // For non-asm.js modules, we just add the function's start offset
606     // to make a module-relative position.
607     return byte_offset + GetWasmFunctionOffset(module, func_index);
608   }
609 
610   // asm.js modules have an additional offset table that must be searched.
611   return module->asm_js_offset_information->GetSourcePosition(
612       declared_function_index(module, func_index), byte_offset,
613       is_at_number_conversion);
614 }
615 
616 namespace {
617 template <typename T>
VectorSize(const std::vector<T> & vector)618 inline size_t VectorSize(const std::vector<T>& vector) {
619   return sizeof(T) * vector.size();
620 }
621 }  // namespace
622 
EstimateStoredSize(const WasmModule * module)623 size_t EstimateStoredSize(const WasmModule* module) {
624   return sizeof(WasmModule) + VectorSize(module->globals) +
625          (module->signature_zone ? module->signature_zone->allocation_size()
626                                  : 0) +
627          VectorSize(module->types) +
628          VectorSize(module->canonicalized_type_ids) +
629          VectorSize(module->functions) + VectorSize(module->data_segments) +
630          VectorSize(module->tables) + VectorSize(module->import_table) +
631          VectorSize(module->export_table) + VectorSize(module->tags) +
632          VectorSize(module->elem_segments);
633 }
634 
PrintSignature(base::Vector<char> buffer,const wasm::FunctionSig * sig,char delimiter)635 size_t PrintSignature(base::Vector<char> buffer, const wasm::FunctionSig* sig,
636                       char delimiter) {
637   if (buffer.empty()) return 0;
638   size_t old_size = buffer.size();
639   auto append_char = [&buffer](char c) {
640     if (buffer.size() == 1) return;  // Keep last character for '\0'.
641     buffer[0] = c;
642     buffer += 1;
643   };
644   for (wasm::ValueType t : sig->parameters()) {
645     append_char(t.short_name());
646   }
647   append_char(delimiter);
648   for (wasm::ValueType t : sig->returns()) {
649     append_char(t.short_name());
650   }
651   buffer[0] = '\0';
652   return old_size - buffer.size();
653 }
654 
655 }  // namespace wasm
656 }  // namespace internal
657 }  // namespace v8
658