summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp32
-rw-r--r--Userland/Libraries/LibWeb/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp84
-rw-r--r--Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.h33
-rw-r--r--Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObjectPrototype.cpp32
-rw-r--r--Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObjectPrototype.h32
6 files changed, 169 insertions, 45 deletions
diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp
index 27d458b11c..6e789c8671 100644
--- a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp
+++ b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp
@@ -14,10 +14,19 @@
namespace Wasm {
-#define TRAP_IF_NOT(x) \
- do { \
- if (trap_if_not(x)) \
- return; \
+#define TRAP_IF_NOT(x) \
+ do { \
+ if (trap_if_not(x)) { \
+ dbgln_if(WASM_TRACE_DEBUG, "Trapped because {} failed, at line {}", #x, __LINE__); \
+ return; \
+ } \
+ } while (false)
+
+#define TRAP_IF_NOT_NORETURN(x) \
+ do { \
+ if (trap_if_not(x)) { \
+ dbgln_if(WASM_TRACE_DEBUG, "Trapped because {} failed, at line {}", #x, __LINE__); \
+ } \
} while (false)
void Interpreter::interpret(Configuration& configuration)
@@ -56,9 +65,8 @@ void Interpreter::branch_to_label(Configuration& configuration, LabelIndex index
configuration.stack().pop();
}
- // Push results in reverse
- for (size_t i = results.size(); i > 0; --i)
- configuration.stack().push(move(static_cast<Vector<NonnullOwnPtr<Value>>&>(results)[i - 1]));
+ for (auto& result : results)
+ configuration.stack().push(move(result));
configuration.ip() = label->continuation();
}
@@ -269,13 +277,12 @@ struct ConvertToRaw<double> {
Vector<NonnullOwnPtr<Value>> Interpreter::pop_values(Configuration& configuration, size_t count)
{
Vector<NonnullOwnPtr<Value>> results;
- // Pop results in order
for (size_t i = 0; i < count; ++i) {
auto top_of_stack = configuration.stack().pop();
if (auto value = top_of_stack.get_pointer<NonnullOwnPtr<Value>>())
- results.append(move(*value));
+ results.prepend(move(*value));
else
- trap_if_not(value);
+ TRAP_IF_NOT_NORETURN(value);
}
return results;
}
@@ -361,9 +368,8 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
break;
}
- // Push results in reverse
- for (size_t i = 1; i < results.size() + 1; ++i)
- configuration.stack().push(move(static_cast<Vector<NonnullOwnPtr<Value>>&>(results)[results.size() - i]));
+ for (auto& result : results)
+ configuration.stack().push(move(result));
if (instruction.opcode() == Instructions::structured_end)
return;
diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt
index f9d370f7bb..bc9123ed83 100644
--- a/Userland/Libraries/LibWeb/CMakeLists.txt
+++ b/Userland/Libraries/LibWeb/CMakeLists.txt
@@ -222,6 +222,7 @@ set(SOURCES
UIEvents/MouseEvent.cpp
URLEncoder.cpp
WebAssembly/WebAssemblyObject.cpp
+ WebAssembly/WebAssemblyObjectPrototype.cpp
WebContentClient.cpp
XHR/EventNames.cpp
XHR/XMLHttpRequest.cpp
diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp
index 1fcf7ef73c..a8e8f82c8c 100644
--- a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp
+++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.cpp
@@ -4,11 +4,13 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include <AK/ScopeGuard.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/ArrayBuffer.h>
#include <LibJS/Runtime/BigInt.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibWasm/AbstractMachine/Interpreter.h>
+#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/WebAssembly/WebAssemblyObject.h>
namespace Web::Bindings {
@@ -57,6 +59,11 @@ static Result<size_t, JS::Value> parse_module(JS::GlobalObject& global_object, J
}
InputMemoryStream stream { *bytes };
auto module_result = Wasm::Module::parse(stream);
+ ScopeGuard drain_errors {
+ [&] {
+ stream.handle_any_error();
+ }
+ };
if (module_result.is_error()) {
// FIXME: Throw CompileError instead.
auto error = JS::TypeError::create(global_object, Wasm::parse_error_to_string(module_result.error()));
@@ -192,7 +199,11 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyObject::instantiate)
},
[&](const auto&) {
// FIXME: Implement these.
+ dbgln("Unimplemented import of non-function attempted");
+ vm.throw_exception<JS::TypeError>(global_object, "LinkError: Not Implemented");
});
+ if (vm.exception())
+ break;
}
if (take_exception_and_reject_if_needed())
@@ -231,7 +242,7 @@ WebAssemblyModuleObject::WebAssemblyModuleObject(JS::GlobalObject& global_object
}
WebAssemblyInstanceObject::WebAssemblyInstanceObject(JS::GlobalObject& global_object, size_t index)
- : Object(*global_object.object_prototype())
+ : Object(static_cast<WindowObject&>(global_object).ensure_web_prototype<WebAssemblyInstancePrototype>(class_name()))
, m_index(index)
{
}
@@ -341,12 +352,6 @@ JS::NativeFunction* create_native_function(Wasm::FunctionAddress address, String
});
}
-void WebAssemblyInstancePrototype::initialize(JS::GlobalObject& global_object)
-{
- Object::initialize(global_object);
- define_native_property("exports", exports_getter, nullptr);
-}
-
void WebAssemblyInstanceObject::initialize(JS::GlobalObject& global_object)
{
Object::initialize(global_object);
@@ -361,6 +366,11 @@ void WebAssemblyInstanceObject::initialize(JS::GlobalObject& global_object)
auto function = create_native_function(address, export_.name(), global_object);
m_exports_object->define_property(export_.name(), function);
},
+ [&](const Wasm::MemoryAddress& address) {
+ // FIXME: Cache this.
+ auto memory = heap().allocate<WebAssemblyMemoryObject>(global_object, global_object, address);
+ m_exports_object->define_property(export_.name(), memory);
+ },
[&](const auto&) {
// FIXME: Implement other exports!
});
@@ -369,24 +379,64 @@ void WebAssemblyInstanceObject::initialize(JS::GlobalObject& global_object)
m_exports_object->set_integrity_level(IntegrityLevel::Frozen);
}
-JS_DEFINE_NATIVE_GETTER(WebAssemblyInstancePrototype::exports_getter)
+void WebAssemblyInstanceObject::visit_edges(Cell::Visitor& visitor)
+{
+ Object::visit_edges(visitor);
+ visitor.visit(m_exports_object);
+}
+
+WebAssemblyMemoryObject::WebAssemblyMemoryObject(JS::GlobalObject& global_object, Wasm::MemoryAddress address)
+ : JS::Object(global_object)
+ , m_address(address)
{
- auto this_value = vm.this_value(global_object);
- auto this_object = this_value.to_object(global_object);
+}
+
+void WebAssemblyMemoryObject::initialize(JS::GlobalObject& global_object)
+{
+ Object::initialize(global_object);
+ define_native_function("grow", grow, 1);
+ define_native_property("buffer", buffer, nullptr);
+}
+
+JS_DEFINE_NATIVE_FUNCTION(WebAssemblyMemoryObject::grow)
+{
+ auto page_count = vm.argument(0).to_u32(global_object);
if (vm.exception())
return {};
- if (!is<WebAssemblyInstanceObject>(this_object)) {
- vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotAn, "WebAssemblyInstance");
+ auto* this_object = vm.this_value(global_object).to_object(global_object);
+ if (!this_object || !is<WebAssemblyMemoryObject>(this_object)) {
+ vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "Memory");
+ return {};
+ }
+ auto* memory_object = static_cast<WebAssemblyMemoryObject*>(this_object);
+ auto address = memory_object->m_address;
+ auto* memory = WebAssemblyObject::s_abstract_machine.store().get(address);
+ if (!memory)
+ return JS::js_undefined();
+
+ auto previous_size = memory->size() / Wasm::Constants::page_size;
+ if (!memory->grow(page_count * Wasm::Constants::page_size)) {
+ vm.throw_exception<JS::TypeError>(global_object, "Memory.grow() grows past the stated limit of the memory instance");
return {};
}
- auto object = static_cast<WebAssemblyInstanceObject*>(this_object);
- return object->m_exports_object;
+
+ return JS::Value(static_cast<u32>(previous_size));
}
-void WebAssemblyInstanceObject::visit_edges(Cell::Visitor& visitor)
+JS_DEFINE_NATIVE_GETTER(WebAssemblyMemoryObject::buffer)
{
- Object::visit_edges(visitor);
- visitor.visit(m_exports_object);
+ auto* this_object = vm.this_value(global_object).to_object(global_object);
+ if (!this_object || !is<WebAssemblyMemoryObject>(this_object)) {
+ vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "Memory");
+ return {};
+ }
+ auto* memory_object = static_cast<WebAssemblyMemoryObject*>(this_object);
+ auto address = memory_object->m_address;
+ auto* memory = WebAssemblyObject::s_abstract_machine.store().get(address);
+ if (!memory)
+ return JS::js_undefined();
+
+ return JS::ArrayBuffer::create(global_object, &memory->data());
}
}
diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.h b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.h
index 35b3aa3094..173cf4df7d 100644
--- a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.h
+++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObject.h
@@ -9,6 +9,7 @@
#include <LibJS/Runtime/Object.h>
#include <LibWasm/AbstractMachine/AbstractMachine.h>
#include <LibWeb/Forward.h>
+#include <LibWeb/WebAssembly/WebAssemblyObjectPrototype.h>
namespace Web::Bindings {
@@ -58,21 +59,6 @@ private:
size_t m_index { 0 };
};
-class WebAssemblyInstancePrototype final : public JS::Object {
- JS_OBJECT(WebAssemblyInstancePrototype, JS::Object);
-
-public:
- explicit WebAssemblyInstancePrototype(JS::GlobalObject& global_object)
- : JS::Object(global_object)
- {
- }
-
- virtual void initialize(JS::GlobalObject&) override;
-
-private:
- JS_DECLARE_NATIVE_GETTER(exports_getter);
-};
-
class WebAssemblyInstanceObject final : public JS::Object {
JS_OBJECT(WebAssemblyInstanceObject, JS::Object);
@@ -93,4 +79,21 @@ private:
JS::Object* m_exports_object { nullptr };
};
+class WebAssemblyMemoryObject final : public JS::Object {
+ JS_OBJECT(WebAssemblyModuleObject, JS::Object);
+
+public:
+ explicit WebAssemblyMemoryObject(JS::GlobalObject&, Wasm::MemoryAddress);
+ virtual void initialize(JS::GlobalObject&) override;
+ virtual ~WebAssemblyMemoryObject() override = default;
+
+ auto address() const { return m_address; }
+
+private:
+ JS_DECLARE_NATIVE_FUNCTION(grow);
+ JS_DECLARE_NATIVE_GETTER(buffer);
+
+ Wasm::MemoryAddress m_address;
+};
+
}
diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObjectPrototype.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObjectPrototype.cpp
new file mode 100644
index 0000000000..978c2dcad9
--- /dev/null
+++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObjectPrototype.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibWeb/WebAssembly/WebAssemblyObject.h>
+#include <LibWeb/WebAssembly/WebAssemblyObjectPrototype.h>
+
+namespace Web::Bindings {
+
+void WebAssemblyInstancePrototype::initialize(JS::GlobalObject& global_object)
+{
+ Object::initialize(global_object);
+ define_native_property("exports", exports_getter, nullptr);
+}
+
+JS_DEFINE_NATIVE_GETTER(WebAssemblyInstancePrototype::exports_getter)
+{
+ auto this_value = vm.this_value(global_object);
+ auto this_object = this_value.to_object(global_object);
+ if (vm.exception())
+ return {};
+ if (!is<WebAssemblyInstanceObject>(this_object)) {
+ vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotAn, "WebAssemblyInstance");
+ return {};
+ }
+ auto object = static_cast<WebAssemblyInstanceObject*>(this_object);
+ return object->m_exports_object;
+}
+
+}
diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObjectPrototype.h b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObjectPrototype.h
new file mode 100644
index 0000000000..b65759598b
--- /dev/null
+++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyObjectPrototype.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/GlobalObject.h>
+#include <LibJS/Runtime/Object.h>
+#include <LibJS/Runtime/VM.h>
+#include <LibWeb/Forward.h>
+
+namespace Web::Bindings {
+
+class WebAssemblyInstancePrototype final : public JS::Object {
+ JS_OBJECT(WebAssemblyInstancePrototype, JS::Object);
+
+public:
+ explicit WebAssemblyInstancePrototype(JS::GlobalObject& global_object)
+ : JS::Object(global_object)
+ {
+ }
+
+ virtual void initialize(JS::GlobalObject&) override;
+
+private:
+ JS_DECLARE_NATIVE_GETTER(exports_getter);
+ static JS::Handle<WebAssemblyInstancePrototype> s_instance;
+};
+
+}