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