Table.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
  3. * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibJS/Runtime/Realm.h>
  8. #include <LibJS/Runtime/VM.h>
  9. #include <LibWasm/Types.h>
  10. #include <LibWeb/Bindings/Intrinsics.h>
  11. #include <LibWeb/Bindings/TablePrototype.h>
  12. #include <LibWeb/WebAssembly/Table.h>
  13. #include <LibWeb/WebAssembly/WebAssembly.h>
  14. namespace Web::WebAssembly {
  15. GC_DEFINE_ALLOCATOR(Table);
  16. static Wasm::ValueType table_kind_to_value_type(Bindings::TableKind kind)
  17. {
  18. switch (kind) {
  19. case Bindings::TableKind::Externref:
  20. return Wasm::ValueType { Wasm::ValueType::ExternReference };
  21. case Bindings::TableKind::Anyfunc:
  22. return Wasm::ValueType { Wasm::ValueType::FunctionReference };
  23. }
  24. VERIFY_NOT_REACHED();
  25. }
  26. WebIDL::ExceptionOr<GC::Ref<Table>> Table::construct_impl(JS::Realm& realm, TableDescriptor& descriptor, JS::Value value)
  27. {
  28. auto& vm = realm.vm();
  29. auto reference_type = table_kind_to_value_type(descriptor.element);
  30. auto reference_value = vm.argument_count() == 1
  31. ? Detail::default_webassembly_value(vm, reference_type)
  32. : TRY(Detail::to_webassembly_value(vm, value, reference_type));
  33. if (descriptor.maximum.has_value() && descriptor.maximum.value() < descriptor.initial)
  34. return vm.throw_completion<JS::RangeError>("Maximum should not be less than initial in table type"sv);
  35. Wasm::Limits limits { descriptor.initial, move(descriptor.maximum) };
  36. Wasm::TableType table_type { reference_type, move(limits) };
  37. auto& cache = Detail::get_cache(realm);
  38. auto address = cache.abstract_machine().store().allocate(table_type);
  39. if (!address.has_value())
  40. return vm.throw_completion<JS::TypeError>("Wasm Table allocation failed"sv);
  41. auto const& reference = reference_value.to<Wasm::Reference>();
  42. auto& table = *cache.abstract_machine().store().get(*address);
  43. for (auto& element : table.elements())
  44. element = reference;
  45. return realm.create<Table>(realm, *address);
  46. }
  47. Table::Table(JS::Realm& realm, Wasm::TableAddress address)
  48. : Bindings::PlatformObject(realm)
  49. , m_address(address)
  50. {
  51. }
  52. void Table::initialize(JS::Realm& realm)
  53. {
  54. Base::initialize(realm);
  55. WEB_SET_PROTOTYPE_FOR_INTERFACE_WITH_CUSTOM_NAME(Table, WebAssembly.Table);
  56. }
  57. // https://webassembly.github.io/spec/js-api/#dom-table-grow
  58. WebIDL::ExceptionOr<u32> Table::grow(u32 delta, JS::Value value)
  59. {
  60. auto& vm = this->vm();
  61. auto& cache = Detail::get_cache(realm());
  62. auto* table = cache.abstract_machine().store().get(address());
  63. if (!table)
  64. return vm.throw_completion<JS::RangeError>("Could not find the memory table to grow"sv);
  65. auto initial_size = table->elements().size();
  66. auto reference_value = vm.argument_count() == 1
  67. ? Detail::default_webassembly_value(vm, table->type().element_type())
  68. : TRY(Detail::to_webassembly_value(vm, value, table->type().element_type()));
  69. auto const& reference = reference_value.to<Wasm::Reference>();
  70. if (!table->grow(delta, reference))
  71. return vm.throw_completion<JS::RangeError>("Failed to grow table"sv);
  72. return initial_size;
  73. }
  74. // https://webassembly.github.io/spec/js-api/#dom-table-get
  75. WebIDL::ExceptionOr<JS::Value> Table::get(u32 index) const
  76. {
  77. auto& vm = this->vm();
  78. auto& cache = Detail::get_cache(realm());
  79. auto* table = cache.abstract_machine().store().get(address());
  80. if (!table)
  81. return vm.throw_completion<JS::RangeError>("Could not find the memory table"sv);
  82. if (table->elements().size() <= index)
  83. return vm.throw_completion<JS::RangeError>("Table element index out of range"sv);
  84. auto& ref = table->elements()[index];
  85. Wasm::Value wasm_value { ref };
  86. return Detail::to_js_value(vm, wasm_value, table->type().element_type());
  87. }
  88. // https://webassembly.github.io/spec/js-api/#dom-table-set
  89. WebIDL::ExceptionOr<void> Table::set(u32 index, JS::Value value)
  90. {
  91. auto& vm = this->vm();
  92. auto& cache = Detail::get_cache(realm());
  93. auto* table = cache.abstract_machine().store().get(address());
  94. if (!table)
  95. return vm.throw_completion<JS::RangeError>("Could not find the memory table"sv);
  96. if (table->elements().size() <= index)
  97. return vm.throw_completion<JS::RangeError>("Table element index out of range"sv);
  98. auto reference_value = vm.argument_count() == 1
  99. ? Detail::default_webassembly_value(vm, table->type().element_type())
  100. : TRY(Detail::to_webassembly_value(vm, value, table->type().element_type()));
  101. auto const& reference = reference_value.to<Wasm::Reference>();
  102. table->elements()[index] = reference;
  103. return {};
  104. }
  105. // https://webassembly.github.io/spec/js-api/#dom-table-length
  106. WebIDL::ExceptionOr<u32> Table::length() const
  107. {
  108. auto& vm = this->vm();
  109. auto& cache = Detail::get_cache(realm());
  110. auto* table = cache.abstract_machine().store().get(address());
  111. if (!table)
  112. return vm.throw_completion<JS::RangeError>("Could not find the memory table"sv);
  113. return table->elements().size();
  114. }
  115. }