Table.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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/WebAssembly/Table.h>
  12. #include <LibWeb/WebAssembly/WebAssembly.h>
  13. namespace Web::WebAssembly {
  14. static Wasm::ValueType table_kind_to_value_type(Bindings::TableKind kind)
  15. {
  16. switch (kind) {
  17. case Bindings::TableKind::Externref:
  18. return Wasm::ValueType { Wasm::ValueType::ExternReference };
  19. case Bindings::TableKind::Anyfunc:
  20. return Wasm::ValueType { Wasm::ValueType::FunctionReference };
  21. }
  22. VERIFY_NOT_REACHED();
  23. }
  24. static JS::ThrowCompletionOr<Wasm::Value> value_to_reference(JS::VM& vm, JS::Value value, Wasm::ValueType const& reference_type)
  25. {
  26. if (value.is_undefined())
  27. return Wasm::Value(reference_type, 0ull);
  28. return Detail::to_webassembly_value(vm, value, reference_type);
  29. }
  30. WebIDL::ExceptionOr<JS::NonnullGCPtr<Table>> Table::construct_impl(JS::Realm& realm, TableDescriptor& descriptor, JS::Value value)
  31. {
  32. auto& vm = realm.vm();
  33. auto reference_type = table_kind_to_value_type(descriptor.element);
  34. auto reference_value = TRY(value_to_reference(vm, value, reference_type));
  35. Wasm::Limits limits { descriptor.initial, move(descriptor.maximum) };
  36. Wasm::TableType table_type { reference_type, move(limits) };
  37. auto address = Detail::s_abstract_machine.store().allocate(table_type);
  38. if (!address.has_value())
  39. return vm.throw_completion<JS::TypeError>("Wasm Table allocation failed"sv);
  40. auto const& reference = reference_value.value().get<Wasm::Reference>();
  41. auto& table = *Detail::s_abstract_machine.store().get(*address);
  42. for (auto& element : table.elements())
  43. element = reference;
  44. return MUST_OR_THROW_OOM(vm.heap().allocate<Table>(realm, realm, *address));
  45. }
  46. Table::Table(JS::Realm& realm, Wasm::TableAddress address)
  47. : Bindings::PlatformObject(realm)
  48. , m_address(address)
  49. {
  50. }
  51. JS::ThrowCompletionOr<void> Table::initialize(JS::Realm& realm)
  52. {
  53. MUST_OR_THROW_OOM(Base::initialize(realm));
  54. set_prototype(&Bindings::ensure_web_prototype<Bindings::TablePrototype>(realm, "WebAssembly.Table"sv));
  55. return {};
  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* table = Detail::s_abstract_machine.store().get(address());
  62. if (!table)
  63. return vm.throw_completion<JS::RangeError>("Could not find the memory table to grow"sv);
  64. auto initial_size = table->elements().size();
  65. auto reference_value = TRY(value_to_reference(vm, value, table->type().element_type()));
  66. auto const& reference = reference_value.value().get<Wasm::Reference>();
  67. if (!table->grow(delta, reference))
  68. return vm.throw_completion<JS::RangeError>("Failed to grow table"sv);
  69. return initial_size;
  70. }
  71. // https://webassembly.github.io/spec/js-api/#dom-table-get
  72. WebIDL::ExceptionOr<JS::Value> Table::get(u32 index) const
  73. {
  74. auto& vm = this->vm();
  75. auto* table = Detail::s_abstract_machine.store().get(address());
  76. if (!table)
  77. return vm.throw_completion<JS::RangeError>("Could not find the memory table"sv);
  78. if (table->elements().size() <= index)
  79. return vm.throw_completion<JS::RangeError>("Table element index out of range"sv);
  80. auto& ref = table->elements()[index];
  81. if (!ref.has_value())
  82. return JS::js_undefined();
  83. Wasm::Value wasm_value { ref.value() };
  84. return Detail::to_js_value(vm, wasm_value);
  85. }
  86. // https://webassembly.github.io/spec/js-api/#dom-table-set
  87. WebIDL::ExceptionOr<void> Table::set(u32 index, JS::Value value)
  88. {
  89. auto& vm = this->vm();
  90. auto* table = Detail::s_abstract_machine.store().get(address());
  91. if (!table)
  92. return vm.throw_completion<JS::RangeError>("Could not find the memory table"sv);
  93. if (table->elements().size() <= index)
  94. return vm.throw_completion<JS::RangeError>("Table element index out of range"sv);
  95. auto reference_value = TRY(value_to_reference(vm, value, table->type().element_type()));
  96. auto const& reference = reference_value.value().get<Wasm::Reference>();
  97. table->elements()[index] = reference;
  98. return {};
  99. }
  100. // https://webassembly.github.io/spec/js-api/#dom-table-length
  101. WebIDL::ExceptionOr<u32> Table::length() const
  102. {
  103. auto& vm = this->vm();
  104. auto* table = Detail::s_abstract_machine.store().get(address());
  105. if (!table)
  106. return vm.throw_completion<JS::RangeError>("Could not find the memory table"sv);
  107. return table->elements().size();
  108. }
  109. }