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