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