wasm-module.cc 25.7 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include <functional>
6 7
#include <memory>

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 13
#include "src/execution/frames-inl.h"
#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 25
#include "src/wasm/wasm-result.h"

26 27 28
namespace v8 {
namespace internal {
namespace wasm {
29

30 31 32
// static
const uint32_t WasmElemSegment::kNullIndex;

33
WireBytesRef LazilyGeneratedNames::LookupFunctionName(
34 35
    const ModuleWireBytes& wire_bytes, uint32_t function_index,
    Vector<const WasmExport> export_table) const {
36 37 38
  base::MutexGuard lock(&mutex_);
  if (!function_names_) {
    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 43
  auto it = function_names_->find(function_index);
  if (it == function_names_->end()) return WireBytesRef();
44 45 46
  return it->second;
}

47 48 49 50
std::pair<WireBytesRef, WireBytesRef>
LazilyGeneratedNames::LookupNameFromImportsAndExports(
    ImportExportKindCode kind, uint32_t index,
    Vector<const WasmImport> import_table,
51 52
    Vector<const WasmExport> export_table) const {
  base::MutexGuard lock(&mutex_);
53 54 55 56 57
  DCHECK(kind == kExternalGlobal || kind == kExternalMemory ||
         kind == kExternalTable);
  auto& names = kind == kExternalGlobal
                    ? global_names_
                    : kind == kExternalMemory ? memory_names_ : table_names_;
58 59
  if (!names) {
    names.reset(
60 61
        new std::unordered_map<uint32_t,
                               std::pair<WireBytesRef, WireBytesRef>>());
62 63
    GenerateNamesFromImportsAndExports(kind, import_table, export_table,
                                       names.get());
64
  }
65 66
  auto it = names->find(index);
  if (it == names->end()) return {};
67 68 69
  return it->second;
}

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
// static
int MaxNumExportWrappers(const WasmModule* module) {
  // For each signature there may exist a wrapper, both for imported and
  // internal functions.
  return static_cast<int>(module->signature_map.size()) * 2;
}

// static
int GetExportWrapperIndex(const WasmModule* module, const FunctionSig* sig,
                          bool is_import) {
  int result = module->signature_map.Find(*sig);
  CHECK_GE(result, 0);
  result += is_import ? module->signature_map.size() : 0;
  return result;
}

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
// static
int GetCanonicalRttIndex(const WasmModule* module, uint32_t type_index) {
  int rtt_index = 0;
  const std::vector<uint8_t>& type_kinds = module->type_kinds;
  // This logic must be in sync with the code in module-instantiate.cc that
  // initializes the "managed_object_maps" list on the instance.
  for (uint32_t i = 0; i < type_index; i++) {
    if (type_kinds[i] == wasm::kWasmStructTypeCode ||
        type_kinds[i] == wasm::kWasmArrayTypeCode) {
      rtt_index++;
    }
  }
  return rtt_index;
}

101 102 103 104 105 106 107 108
// static
int GetWasmFunctionOffset(const WasmModule* module, uint32_t func_index) {
  const std::vector<WasmFunction>& functions = module->functions;
  if (static_cast<uint32_t>(func_index) >= functions.size()) return -1;
  DCHECK_GE(kMaxInt, functions[func_index].code.offset());
  return static_cast<int>(functions[func_index].code.offset());
}

109
// static
110
int GetNearestWasmFunction(const WasmModule* module, uint32_t byte_offset) {
111 112 113 114 115
  const std::vector<WasmFunction>& functions = module->functions;

  // Binary search for a function containing the given position.
  int left = 0;                                    // inclusive
  int right = static_cast<int>(functions.size());  // exclusive
116
  if (right == 0) return -1;
117 118 119 120 121 122 123 124 125 126 127 128
  while (right - left > 1) {
    int mid = left + (right - left) / 2;
    if (functions[mid].code.offset() <= byte_offset) {
      left = mid;
    } else {
      right = mid;
    }
  }

  return left;
}

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
// static
int GetContainingWasmFunction(const WasmModule* module, uint32_t byte_offset) {
  int func_index = GetNearestWasmFunction(module, byte_offset);

  if (func_index >= 0) {
    // If the found function does not contain the given position, return -1.
    const WasmFunction& func = module->functions[func_index];
    if (byte_offset < func.code.offset() ||
        byte_offset >= func.code.end_offset()) {
      return -1;
    }
  }
  return func_index;
}

144
void LazilyGeneratedNames::AddForTesting(int function_index,
145 146 147 148
                                         WireBytesRef name) {
  base::MutexGuard lock(&mutex_);
  if (!function_names_) {
    function_names_.reset(new std::unordered_map<uint32_t, WireBytesRef>());
149
  }
150
  function_names_->insert(std::make_pair(function_index, name));
151 152
}

153 154 155 156 157 158
AsmJsOffsetInformation::AsmJsOffsetInformation(
    Vector<const byte> encoded_offsets)
    : encoded_offsets_(OwnedVector<const uint8_t>::Of(encoded_offsets)) {}

AsmJsOffsetInformation::~AsmJsOffsetInformation() = default;

159 160
int AsmJsOffsetInformation::GetSourcePosition(int declared_func_index,
                                              int byte_offset,
161
                                              bool is_at_number_conversion) {
162
  EnsureDecodedOffsets();
163

164 165
  DCHECK_LE(0, declared_func_index);
  DCHECK_GT(decoded_offsets_->functions.size(), declared_func_index);
166
  std::vector<AsmJsOffsetEntry>& function_offsets =
167
      decoded_offsets_->functions[declared_func_index].entries;
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183

  auto byte_offset_less = [](const AsmJsOffsetEntry& a,
                             const AsmJsOffsetEntry& b) {
    return a.byte_offset < b.byte_offset;
  };
  SLOW_DCHECK(std::is_sorted(function_offsets.begin(), function_offsets.end(),
                             byte_offset_less));
  auto it =
      std::lower_bound(function_offsets.begin(), function_offsets.end(),
                       AsmJsOffsetEntry{byte_offset, 0, 0}, byte_offset_less);
  DCHECK_NE(function_offsets.end(), it);
  DCHECK_EQ(byte_offset, it->byte_offset);
  return is_at_number_conversion ? it->source_position_number_conversion
                                 : it->source_position_call;
}

184 185
std::pair<int, int> AsmJsOffsetInformation::GetFunctionOffsets(
    int declared_func_index) {
186 187
  EnsureDecodedOffsets();

188 189
  DCHECK_LE(0, declared_func_index);
  DCHECK_GT(decoded_offsets_->functions.size(), declared_func_index);
190
  AsmJsOffsetFunctionEntries& function_info =
191
      decoded_offsets_->functions[declared_func_index];
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206

  return {function_info.start_offset, function_info.end_offset};
}

void AsmJsOffsetInformation::EnsureDecodedOffsets() {
  base::MutexGuard mutex_guard(&mutex_);
  DCHECK_EQ(encoded_offsets_ == nullptr, decoded_offsets_ != nullptr);

  if (decoded_offsets_) return;
  AsmJsOffsetsResult result =
      wasm::DecodeAsmJsOffsets(encoded_offsets_.as_vector());
  decoded_offsets_ = std::make_unique<AsmJsOffsets>(std::move(result).value());
  encoded_offsets_.ReleaseData();
}

207 208 209
// Get a string stored in the module bytes representing a name.
WasmName ModuleWireBytes::GetNameOrNull(WireBytesRef ref) const {
  if (!ref.is_set()) return {nullptr, 0};  // no name.
210
  DCHECK(BoundsCheck(ref));
211
  return WasmName::cast(
212 213 214 215 216 217
      module_bytes_.SubVector(ref.offset(), ref.end_offset()));
}

// Get a string stored in the module bytes representing a function name.
WasmName ModuleWireBytes::GetNameOrNull(const WasmFunction* function,
                                        const WasmModule* module) const {
218
  return GetNameOrNull(module->lazily_generated_names.LookupFunctionName(
219
      *this, function->func_index, VectorOf(module->export_table)));
220 221
}

222
std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name) {
223
  os << "#" << name.function_->func_index;
224
  if (!name.name_.empty()) {
225
    if (name.name_.begin()) {
226
      os << ":";
227
      os.write(name.name_.begin(), name.name_.length());
228 229 230 231 232 233 234
    }
  } else {
    os << "?";
  }
  return os;
}

235
WasmModule::WasmModule(std::unique_ptr<Zone> signature_zone)
236 237 238 239 240 241 242 243 244 245
    : signature_zone(std::move(signature_zone)),
      subtyping_cache(this->signature_zone.get() == nullptr
                          ? nullptr
                          : new ZoneUnorderedSet<std::pair<uint32_t, uint32_t>>(
                                this->signature_zone.get())),
      type_equivalence_cache(
          this->signature_zone.get() == nullptr
              ? nullptr
              : new ZoneUnorderedSet<std::pair<uint32_t, uint32_t>>(
                    this->signature_zone.get())) {}
246

247
bool IsWasmCodegenAllowed(Isolate* isolate, Handle<Context> context) {
248 249 250 251
  // TODO(wasm): Once wasm has its own CSP policy, we should introduce a
  // separate callback that includes information about the module about to be
  // compiled. For the time being, pass an empty string as placeholder for the
  // sources.
252 253 254 255 256 257 258 259
  if (auto wasm_codegen_callback = isolate->allow_wasm_code_gen_callback()) {
    return wasm_codegen_callback(
        v8::Utils::ToLocal(context),
        v8::Utils::ToLocal(isolate->factory()->empty_string()));
  }
  auto codegen_callback = isolate->allow_code_gen_callback();
  return codegen_callback == nullptr ||
         codegen_callback(
260 261
             v8::Utils::ToLocal(context),
             v8::Utils::ToLocal(isolate->factory()->empty_string()));
262 263
}

264 265 266 267 268
namespace {

// Converts the given {type} into a string representation that can be used in
// reflective functions. Should be kept in sync with the {GetValueType} helper.
Handle<String> ToValueTypeString(Isolate* isolate, ValueType type) {
269
  return isolate->factory()->InternalizeUtf8String(
270
      type == kWasmFuncRef ? CStrVector("anyfunc") : VectorOf(type.name()));
271 272 273
}
}  // namespace

274
Handle<JSObject> GetTypeForFunction(Isolate* isolate, const FunctionSig* sig) {
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
  Factory* factory = isolate->factory();

  // Extract values for the {ValueType[]} arrays.
  int param_index = 0;
  int param_count = static_cast<int>(sig->parameter_count());
  Handle<FixedArray> param_values = factory->NewFixedArray(param_count);
  for (ValueType type : sig->parameters()) {
    Handle<String> type_value = ToValueTypeString(isolate, type);
    param_values->set(param_index++, *type_value);
  }
  int result_index = 0;
  int result_count = static_cast<int>(sig->return_count());
  Handle<FixedArray> result_values = factory->NewFixedArray(result_count);
  for (ValueType type : sig->returns()) {
    Handle<String> type_value = ToValueTypeString(isolate, type);
    result_values->set(result_index++, *type_value);
  }

  // Create the resulting {FunctionType} object.
  Handle<JSFunction> object_function = isolate->object_function();
  Handle<JSObject> object = factory->NewJSObject(object_function);
  Handle<JSArray> params = factory->NewJSArrayWithElements(param_values);
  Handle<JSArray> results = factory->NewJSArrayWithElements(result_values);
  Handle<String> params_string = factory->InternalizeUtf8String("parameters");
  Handle<String> results_string = factory->InternalizeUtf8String("results");
  JSObject::AddProperty(isolate, object, params_string, params, NONE);
  JSObject::AddProperty(isolate, object, results_string, results, NONE);

  return object;
}

306 307 308 309 310 311
Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable,
                                  ValueType type) {
  Factory* factory = isolate->factory();

  Handle<JSFunction> object_function = isolate->object_function();
  Handle<JSObject> object = factory->NewJSObject(object_function);
312 313
  Handle<String> mutable_string = factory->InternalizeUtf8String("mutable");
  Handle<String> value_string = factory->InternalizeUtf8String("value");
314 315 316 317 318 319 320 321
  JSObject::AddProperty(isolate, object, mutable_string,
                        factory->ToBoolean(is_mutable), NONE);
  JSObject::AddProperty(isolate, object, value_string,
                        ToValueTypeString(isolate, type), NONE);

  return object;
}

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
Handle<JSObject> GetTypeForMemory(Isolate* isolate, uint32_t min_size,
                                  base::Optional<uint32_t> max_size) {
  Factory* factory = isolate->factory();

  Handle<JSFunction> object_function = isolate->object_function();
  Handle<JSObject> object = factory->NewJSObject(object_function);
  Handle<String> minimum_string = factory->InternalizeUtf8String("minimum");
  Handle<String> maximum_string = factory->InternalizeUtf8String("maximum");
  JSObject::AddProperty(isolate, object, minimum_string,
                        factory->NewNumberFromUint(min_size), NONE);
  if (max_size.has_value()) {
    JSObject::AddProperty(isolate, object, maximum_string,
                          factory->NewNumberFromUint(max_size.value()), NONE);
  }

  return object;
}

340 341 342 343 344 345
Handle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type,
                                 uint32_t min_size,
                                 base::Optional<uint32_t> max_size) {
  Factory* factory = isolate->factory();

  Handle<String> element;
346
  if (type.is_reference_to(HeapType::kFunc)) {
347 348
    // TODO(wasm): We should define the "anyfunc" string in one central
    // place and then use that constant everywhere.
349 350
    element = factory->InternalizeUtf8String("anyfunc");
  } else {
351
    DCHECK(WasmFeatures::FromFlags().has_reftypes() &&
352
           type.is_reference_to(HeapType::kExtern));
353
    element = factory->InternalizeUtf8String("externref");
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
  }

  Handle<JSFunction> object_function = isolate->object_function();
  Handle<JSObject> object = factory->NewJSObject(object_function);
  Handle<String> element_string = factory->InternalizeUtf8String("element");
  Handle<String> minimum_string = factory->InternalizeUtf8String("minimum");
  Handle<String> maximum_string = factory->InternalizeUtf8String("maximum");
  JSObject::AddProperty(isolate, object, element_string, element, NONE);
  JSObject::AddProperty(isolate, object, minimum_string,
                        factory->NewNumberFromUint(min_size), NONE);
  if (max_size.has_value()) {
    JSObject::AddProperty(isolate, object, maximum_string,
                          factory->NewNumberFromUint(max_size.value()), NONE);
  }

  return object;
}

372 373
Handle<JSArray> GetImports(Isolate* isolate,
                           Handle<WasmModuleObject> module_object) {
374
  auto enabled_features = i::wasm::WasmFeatures::FromIsolate(isolate);
375 376 377 378 379
  Factory* factory = isolate->factory();

  Handle<String> module_string = factory->InternalizeUtf8String("module");
  Handle<String> name_string = factory->InternalizeUtf8String("name");
  Handle<String> kind_string = factory->InternalizeUtf8String("kind");
380
  Handle<String> type_string = factory->InternalizeUtf8String("type");
381 382 383 384 385

  Handle<String> function_string = factory->InternalizeUtf8String("function");
  Handle<String> table_string = factory->InternalizeUtf8String("table");
  Handle<String> memory_string = factory->InternalizeUtf8String("memory");
  Handle<String> global_string = factory->InternalizeUtf8String("global");
386
  Handle<String> exception_string = factory->InternalizeUtf8String("exception");
387 388

  // Create the result array.
389
  const WasmModule* module = module_object->module();
390
  int num_imports = static_cast<int>(module->import_table.size());
391
  Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
392 393 394 395 396 397 398 399 400
  Handle<FixedArray> storage = factory->NewFixedArray(num_imports);
  JSArray::SetContent(array_object, storage);
  array_object->set_length(Smi::FromInt(num_imports));

  Handle<JSFunction> object_function =
      Handle<JSFunction>(isolate->native_context()->object_function(), isolate);

  // Populate the result array.
  for (int index = 0; index < num_imports; ++index) {
401
    const WasmImport& import = module->import_table[index];
402

403
    Handle<JSObject> entry = factory->NewJSObject(object_function);
404 405

    Handle<String> import_kind;
406
    Handle<JSObject> type_value;
407 408
    switch (import.kind) {
      case kExternalFunction:
409
        if (enabled_features.has_type_reflection()) {
410 411 412
          auto& func = module->functions[import.index];
          type_value = GetTypeForFunction(isolate, func.sig);
        }
413 414 415
        import_kind = function_string;
        break;
      case kExternalTable:
416
        if (enabled_features.has_type_reflection()) {
417 418 419 420 421 422
          auto& table = module->tables[import.index];
          base::Optional<uint32_t> maximum_size;
          if (table.has_maximum_size) maximum_size.emplace(table.maximum_size);
          type_value = GetTypeForTable(isolate, table.type, table.initial_size,
                                       maximum_size);
        }
423 424 425
        import_kind = table_string;
        break;
      case kExternalMemory:
426
        if (enabled_features.has_type_reflection()) {
427 428 429 430 431 432 433 434
          DCHECK_EQ(0, import.index);  // Only one memory supported.
          base::Optional<uint32_t> maximum_size;
          if (module->has_maximum_pages) {
            maximum_size.emplace(module->maximum_pages);
          }
          type_value =
              GetTypeForMemory(isolate, module->initial_pages, maximum_size);
        }
435 436 437
        import_kind = memory_string;
        break;
      case kExternalGlobal:
438
        if (enabled_features.has_type_reflection()) {
439 440 441 442
          auto& global = module->globals[import.index];
          type_value =
              GetTypeForGlobal(isolate, global.mutability, global.type);
        }
443 444
        import_kind = global_string;
        break;
445 446 447
      case kExternalException:
        import_kind = exception_string;
        break;
448
    }
449
    DCHECK(!import_kind->is_null());
450

451
    Handle<String> import_module =
452
        WasmModuleObject::ExtractUtf8StringFromModuleBytes(
453
            isolate, module_object, import.module_name, kInternalize);
454

455
    Handle<String> import_name =
456
        WasmModuleObject::ExtractUtf8StringFromModuleBytes(
457
            isolate, module_object, import.field_name, kInternalize);
458

459 460
    JSObject::AddProperty(isolate, entry, module_string, import_module, NONE);
    JSObject::AddProperty(isolate, entry, name_string, import_name, NONE);
461
    JSObject::AddProperty(isolate, entry, kind_string, import_kind, NONE);
462 463 464
    if (!type_value.is_null()) {
      JSObject::AddProperty(isolate, entry, type_string, type_value, NONE);
    }
465 466 467 468 469 470

    storage->set(index, *entry);
  }

  return array_object;
}
471

472 473
Handle<JSArray> GetExports(Isolate* isolate,
                           Handle<WasmModuleObject> module_object) {
474
  auto enabled_features = i::wasm::WasmFeatures::FromIsolate(isolate);
475 476 477 478
  Factory* factory = isolate->factory();

  Handle<String> name_string = factory->InternalizeUtf8String("name");
  Handle<String> kind_string = factory->InternalizeUtf8String("kind");
479
  Handle<String> type_string = factory->InternalizeUtf8String("type");
480 481 482 483 484

  Handle<String> function_string = factory->InternalizeUtf8String("function");
  Handle<String> table_string = factory->InternalizeUtf8String("table");
  Handle<String> memory_string = factory->InternalizeUtf8String("memory");
  Handle<String> global_string = factory->InternalizeUtf8String("global");
485
  Handle<String> exception_string = factory->InternalizeUtf8String("exception");
486 487

  // Create the result array.
488
  const WasmModule* module = module_object->module();
489
  int num_exports = static_cast<int>(module->export_table.size());
490
  Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
491 492 493 494 495 496 497 498 499
  Handle<FixedArray> storage = factory->NewFixedArray(num_exports);
  JSArray::SetContent(array_object, storage);
  array_object->set_length(Smi::FromInt(num_exports));

  Handle<JSFunction> object_function =
      Handle<JSFunction>(isolate->native_context()->object_function(), isolate);

  // Populate the result array.
  for (int index = 0; index < num_exports; ++index) {
500
    const WasmExport& exp = module->export_table[index];
501 502

    Handle<String> export_kind;
503
    Handle<JSObject> type_value;
504 505
    switch (exp.kind) {
      case kExternalFunction:
506
        if (enabled_features.has_type_reflection()) {
507 508 509
          auto& func = module->functions[exp.index];
          type_value = GetTypeForFunction(isolate, func.sig);
        }
510 511 512
        export_kind = function_string;
        break;
      case kExternalTable:
513
        if (enabled_features.has_type_reflection()) {
514 515 516 517 518 519
          auto& table = module->tables[exp.index];
          base::Optional<uint32_t> maximum_size;
          if (table.has_maximum_size) maximum_size.emplace(table.maximum_size);
          type_value = GetTypeForTable(isolate, table.type, table.initial_size,
                                       maximum_size);
        }
520 521 522
        export_kind = table_string;
        break;
      case kExternalMemory:
523
        if (enabled_features.has_type_reflection()) {
524 525 526 527 528 529 530 531
          DCHECK_EQ(0, exp.index);  // Only one memory supported.
          base::Optional<uint32_t> maximum_size;
          if (module->has_maximum_pages) {
            maximum_size.emplace(module->maximum_pages);
          }
          type_value =
              GetTypeForMemory(isolate, module->initial_pages, maximum_size);
        }
532 533 534
        export_kind = memory_string;
        break;
      case kExternalGlobal:
535
        if (enabled_features.has_type_reflection()) {
536 537 538 539
          auto& global = module->globals[exp.index];
          type_value =
              GetTypeForGlobal(isolate, global.mutability, global.type);
        }
540 541
        export_kind = global_string;
        break;
542 543 544
      case kExternalException:
        export_kind = exception_string;
        break;
545 546 547 548
      default:
        UNREACHABLE();
    }

549 550
    Handle<JSObject> entry = factory->NewJSObject(object_function);

551
    Handle<String> export_name =
552
        WasmModuleObject::ExtractUtf8StringFromModuleBytes(
553
            isolate, module_object, exp.name, kNoInternalize);
554

555
    JSObject::AddProperty(isolate, entry, name_string, export_name, NONE);
556
    JSObject::AddProperty(isolate, entry, kind_string, export_kind, NONE);
557 558 559
    if (!type_value.is_null()) {
      JSObject::AddProperty(isolate, entry, type_string, type_value, NONE);
    }
560 561 562 563 564 565

    storage->set(index, *entry);
  }

  return array_object;
}
566

567 568 569
Handle<JSArray> GetCustomSections(Isolate* isolate,
                                  Handle<WasmModuleObject> module_object,
                                  Handle<String> name, ErrorThrower* thrower) {
570 571
  Factory* factory = isolate->factory();

572 573 574
  Vector<const uint8_t> wire_bytes =
      module_object->native_module()->wire_bytes();
  std::vector<CustomSectionOffset> custom_sections =
575
      DecodeCustomSections(wire_bytes.begin(), wire_bytes.end());
576 577 578 579

  std::vector<Handle<Object>> matching_sections;

  // Gather matching sections.
580
  for (auto& section : custom_sections) {
581
    Handle<String> section_name =
582
        WasmModuleObject::ExtractUtf8StringFromModuleBytes(
583
            isolate, module_object, section.name, kNoInternalize);
584

585
    if (!name->Equals(*section_name)) continue;
586 587

    // Make a copy of the payload data in the section.
588
    size_t size = section.payload.length();
589 590 591 592 593
    MaybeHandle<JSArrayBuffer> result =
        isolate->factory()->NewJSArrayBufferAndBackingStore(
            size, InitializedFlag::kUninitialized);
    Handle<JSArrayBuffer> array_buffer;
    if (!result.ToHandle(&array_buffer)) {
594 595 596
      thrower->RangeError("out of memory allocating custom section data");
      return Handle<JSArray>();
    }
597 598
    memcpy(array_buffer->backing_store(),
           wire_bytes.begin() + section.payload.offset(),
599
           section.payload.length());
600

601
    matching_sections.push_back(array_buffer);
602 603 604
  }

  int num_custom_sections = static_cast<int>(matching_sections.size());
605
  Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
606 607 608 609 610 611 612 613 614 615
  Handle<FixedArray> storage = factory->NewFixedArray(num_custom_sections);
  JSArray::SetContent(array_object, storage);
  array_object->set_length(Smi::FromInt(num_custom_sections));

  for (int i = 0; i < num_custom_sections; i++) {
    storage->set(i, *matching_sections[i]);
  }

  return array_object;
}
616

617 618 619 620 621 622 623
// Get the source position from a given function index and byte offset,
// for either asm.js or pure Wasm modules.
int GetSourcePosition(const WasmModule* module, uint32_t func_index,
                      uint32_t byte_offset, bool is_at_number_conversion) {
  DCHECK_EQ(is_asmjs_module(module),
            module->asm_js_offset_information != nullptr);
  if (!is_asmjs_module(module)) {
624
    // For non-asm.js modules, we just add the function's start offset
625 626 627 628 629 630
    // to make a module-relative position.
    return byte_offset + GetWasmFunctionOffset(module, func_index);
  }

  // asm.js modules have an additional offset table that must be searched.
  return module->asm_js_offset_information->GetSourcePosition(
631
      declared_function_index(module, func_index), byte_offset,
632 633 634
      is_at_number_conversion);
}

635 636 637 638 639 640 641
namespace {
template <typename T>
inline size_t VectorSize(const std::vector<T>& vector) {
  return sizeof(T) * vector.size();
}
}  // namespace

642 643 644 645
size_t EstimateStoredSize(const WasmModule* module) {
  return sizeof(WasmModule) + VectorSize(module->globals) +
         (module->signature_zone ? module->signature_zone->allocation_size()
                                 : 0) +
646 647 648 649 650
         VectorSize(module->types) + VectorSize(module->type_kinds) +
         VectorSize(module->signature_ids) + VectorSize(module->functions) +
         VectorSize(module->data_segments) + VectorSize(module->tables) +
         VectorSize(module->import_table) + VectorSize(module->export_table) +
         VectorSize(module->exceptions) + VectorSize(module->elem_segments);
651
}
652

653
size_t PrintSignature(Vector<char> buffer, const wasm::FunctionSig* sig) {
654 655 656 657 658 659 660 661
  if (buffer.empty()) return 0;
  size_t old_size = buffer.size();
  auto append_char = [&buffer](char c) {
    if (buffer.size() == 1) return;  // Keep last character for '\0'.
    buffer[0] = c;
    buffer += 1;
  };
  for (wasm::ValueType t : sig->parameters()) {
662
    append_char(t.short_name());
663 664 665
  }
  append_char(':');
  for (wasm::ValueType t : sig->returns()) {
666
    append_char(t.short_name());
667 668 669 670 671
  }
  buffer[0] = '\0';
  return old_size - buffer.size();
}

672 673 674
}  // namespace wasm
}  // namespace internal
}  // namespace v8