mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-24 18:02:20 +00:00
LibWeb/WebAssembly: Define the hacky 'native' errors given in the spec
These cannot be implemented "correctly" as the set of native errors as defined by ecma262 is closed, but we can get pretty close.
This commit is contained in:
parent
fbfd3e2538
commit
333ba93d49
Notes:
github-actions[bot]
2025-05-08 09:36:39 +00:00
Author: https://github.com/alimpfard
Commit: 333ba93d49
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4567
Reviewed-by: https://github.com/ADKaster ✅
3 changed files with 238 additions and 1 deletions
|
@ -12,12 +12,15 @@
|
|||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/ArrayBuffer.h>
|
||||
#include <LibJS/Runtime/BigInt.h>
|
||||
#include <LibJS/Runtime/ErrorConstructor.h>
|
||||
#include <LibJS/Runtime/Intrinsics.h>
|
||||
#include <LibJS/Runtime/Iterator.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibJS/Runtime/ValueInlines.h>
|
||||
#include <LibWasm/AbstractMachine/Validator.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/Bindings/ResponsePrototype.h>
|
||||
#include <LibWeb/Fetch/Response.h>
|
||||
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
|
||||
|
@ -72,6 +75,35 @@ void finalize(JS::Object& object)
|
|||
Detail::s_caches.remove(global_object);
|
||||
}
|
||||
|
||||
// https://webassembly.github.io/spec/js-api/#error-objects
|
||||
void initialize(JS::Object& self, JS::Realm& realm)
|
||||
{
|
||||
// 1. Let namespaceObject be the namespace object.
|
||||
auto& namespace_object = self;
|
||||
|
||||
// 2. For each error of « "CompileError", "LinkError", "RuntimeError" »,
|
||||
// 2.1. Let constructor be a new object, implementing the NativeError Object Structure, with NativeError set to error.
|
||||
// 2.2. ! DefineMethodProperty(namespaceObject, error, constructor, false).
|
||||
|
||||
// 2..2.2 for error=CompileError:
|
||||
auto descriptor = JS::PropertyDescriptor {
|
||||
.writable = true,
|
||||
.enumerable = false,
|
||||
.configurable = true,
|
||||
};
|
||||
|
||||
descriptor.value = &Bindings::ensure_web_constructor<CompileErrorPrototype>(realm, "CompileError"_fly_string);
|
||||
MUST(namespace_object.define_property_or_throw("CompileError"_string, descriptor));
|
||||
|
||||
// 2..2.2 for error=LinkError:
|
||||
descriptor.value = &Bindings::ensure_web_constructor<LinkErrorPrototype>(realm, "LinkError"_fly_string);
|
||||
MUST(namespace_object.define_property_or_throw("LinkError"_string, descriptor));
|
||||
|
||||
// 2..2.2 for error=RuntimeError:
|
||||
descriptor.value = &Bindings::ensure_web_constructor<RuntimeErrorPrototype>(realm, "RuntimeError"_fly_string);
|
||||
MUST(namespace_object.define_property_or_throw("RuntimeError"_string, descriptor));
|
||||
}
|
||||
|
||||
// https://webassembly.github.io/spec/js-api/#dom-webassembly-validate
|
||||
bool validate(JS::VM& vm, GC::Root<WebIDL::BufferSource>& bytes)
|
||||
{
|
||||
|
@ -851,4 +883,142 @@ GC::Ref<WebIDL::Promise> compile_potential_webassembly_response(JS::VM& vm, GC::
|
|||
return return_value;
|
||||
}
|
||||
|
||||
#define DEFINE_WASM_NATIVE_ERROR(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
GC_DEFINE_ALLOCATOR(ClassName); \
|
||||
GC::Ref<ClassName> ClassName::create(JS::Realm& realm) \
|
||||
{ \
|
||||
return realm.create<ClassName>(Bindings::ensure_web_prototype<PrototypeName>(realm, #ClassName##_fly_string)); \
|
||||
} \
|
||||
\
|
||||
GC::Ref<ClassName> ClassName::create(JS::Realm& realm, String message) \
|
||||
{ \
|
||||
auto& vm = realm.vm(); \
|
||||
auto error = ClassName::create(realm); \
|
||||
u8 const attr = JS::Attribute::Writable | JS::Attribute::Configurable; \
|
||||
error->define_direct_property(vm.names.message, JS::PrimitiveString::create(vm, move(message)), attr); \
|
||||
return error; \
|
||||
} \
|
||||
\
|
||||
GC::Ref<ClassName> ClassName::create(JS::Realm& realm, StringView message) \
|
||||
{ \
|
||||
return create(realm, MUST(String::from_utf8(message))); \
|
||||
} \
|
||||
\
|
||||
ClassName::ClassName(JS::Object& prototype) \
|
||||
: Error(prototype) \
|
||||
{ \
|
||||
}
|
||||
|
||||
DEFINE_WASM_NATIVE_ERROR(CompileError, compile_error, CompileErrorPrototype, CompileErrorConstructor)
|
||||
DEFINE_WASM_NATIVE_ERROR(LinkError, link_error, LinkErrorPrototype, LinkErrorConstructor)
|
||||
DEFINE_WASM_NATIVE_ERROR(RuntimeError, runtime_error, RuntimeErrorPrototype, RuntimeErrorConstructor)
|
||||
|
||||
#undef DEFINE_WASM_NATIVE_ERROR
|
||||
|
||||
#define DEFINE_WASM_NATIVE_ERROR_CONSTRUCTOR(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
GC_DEFINE_ALLOCATOR(ConstructorName); \
|
||||
ConstructorName::ConstructorName(JS::Realm& realm) \
|
||||
: NativeFunction(#ClassName##_string, *realm.intrinsics().error_constructor()) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
void ConstructorName::initialize(JS::Realm& realm) \
|
||||
{ \
|
||||
auto& vm = this->vm(); \
|
||||
Base::initialize(realm); \
|
||||
\
|
||||
/* 20.5.6.2.1 NativeError.prototype, https://tc39.es/ecma262/#sec-nativeerror.prototype */ \
|
||||
define_direct_property(vm.names.prototype, &Bindings::ensure_web_prototype<PrototypeName>(realm, #ClassName##_fly_string), 0); \
|
||||
\
|
||||
define_direct_property(vm.names.length, JS::Value(1), JS::Attribute::Configurable); \
|
||||
} \
|
||||
\
|
||||
ConstructorName::~ConstructorName() = default; \
|
||||
\
|
||||
/* 20.5.6.1.1 NativeError ( message [ , options ] ), https://tc39.es/ecma262/#sec-nativeerror */ \
|
||||
JS::ThrowCompletionOr<JS::Value> ConstructorName::call() \
|
||||
{ \
|
||||
/* 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget. */ \
|
||||
return TRY(construct(*this)); \
|
||||
} \
|
||||
\
|
||||
/* 20.5.6.1.1 NativeError ( message [ , options ] ), https://tc39.es/ecma262/#sec-nativeerror */ \
|
||||
JS::ThrowCompletionOr<GC::Ref<JS::Object>> ConstructorName::construct(JS::FunctionObject& new_target) \
|
||||
{ \
|
||||
auto& vm = this->vm(); \
|
||||
\
|
||||
auto message = vm.argument(0); \
|
||||
auto options = vm.argument(1); \
|
||||
\
|
||||
/* 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%NativeError.prototype%", « [[ErrorData]] »). */ \
|
||||
auto error = TRY(ordinary_create_from_constructor<ClassName>(vm, new_target, &JS::Intrinsics::error_prototype)); \
|
||||
\
|
||||
/* 3. If message is not undefined, then */ \
|
||||
if (!message.is_undefined()) { \
|
||||
/* a. Let msg be ? ToString(message). */ \
|
||||
auto msg = TRY(message.to_string(vm)); \
|
||||
\
|
||||
/* b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). */ \
|
||||
error->create_non_enumerable_data_property_or_throw(vm.names.message, JS::PrimitiveString::create(vm, move(msg))); \
|
||||
} \
|
||||
\
|
||||
/* 4. Perform ? InstallErrorCause(O, options). */ \
|
||||
TRY(error->install_error_cause(options)); \
|
||||
\
|
||||
/* 5. Return O. */ \
|
||||
return error; \
|
||||
}
|
||||
|
||||
DEFINE_WASM_NATIVE_ERROR_CONSTRUCTOR(CompileError, compile_error, CompileErrorPrototype, CompileErrorConstructor)
|
||||
DEFINE_WASM_NATIVE_ERROR_CONSTRUCTOR(LinkError, link_error, LinkErrorPrototype, LinkErrorConstructor)
|
||||
DEFINE_WASM_NATIVE_ERROR_CONSTRUCTOR(RuntimeError, runtime_error, RuntimeErrorPrototype, RuntimeErrorConstructor)
|
||||
|
||||
#undef DEFINE_WASM_NATIVE_ERROR_CONSTRUCTOR
|
||||
|
||||
#define DEFINE_WASM_NATIVE_ERROR_PROTOTYPE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
GC_DEFINE_ALLOCATOR(PrototypeName); \
|
||||
\
|
||||
PrototypeName::PrototypeName(JS::Realm& realm) \
|
||||
: PrototypeObject(realm.intrinsics().error_prototype()) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
void PrototypeName::initialize(JS::Realm& realm) \
|
||||
{ \
|
||||
auto& vm = this->vm(); \
|
||||
Base::initialize(realm); \
|
||||
u8 const attr = JS::Attribute::Writable | JS::Attribute::Configurable; \
|
||||
define_direct_property(vm.names.name, JS::PrimitiveString::create(vm, #ClassName##_string), attr); \
|
||||
define_direct_property(vm.names.message, JS::PrimitiveString::create(vm, String {}), attr); \
|
||||
}
|
||||
|
||||
DEFINE_WASM_NATIVE_ERROR_PROTOTYPE(CompileError, compile_error, CompileErrorPrototype, CompileErrorConstructor)
|
||||
DEFINE_WASM_NATIVE_ERROR_PROTOTYPE(LinkError, link_error, LinkErrorPrototype, LinkErrorConstructor)
|
||||
DEFINE_WASM_NATIVE_ERROR_PROTOTYPE(RuntimeError, runtime_error, RuntimeErrorPrototype, RuntimeErrorConstructor)
|
||||
|
||||
#undef DEFINE_WASM_NATIVE_ERROR_PROTOTYPE
|
||||
|
||||
}
|
||||
|
||||
#define DEFINE_WASM_ERROR_PROTOTYPE_AND_CONSTRUCTOR_WEB_INTRINSIC(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
template<> \
|
||||
void Intrinsics::create_web_prototype_and_constructor<WebAssembly::PrototypeName>(JS::Realm & realm) \
|
||||
{ \
|
||||
auto& vm = realm.vm(); \
|
||||
auto prototype = heap().allocate<WebAssembly::PrototypeName>(realm); \
|
||||
m_prototypes.set(#ClassName##_string, prototype); \
|
||||
\
|
||||
auto constructor = heap().allocate<WebAssembly::ConstructorName>(realm); \
|
||||
m_constructors.set(#ClassName##_string, constructor); \
|
||||
\
|
||||
prototype->define_direct_property(vm.names.constructor, constructor.ptr(), JS::Attribute::Writable | JS::Attribute::Configurable); \
|
||||
constructor->define_direct_property(vm.names.name, JS::PrimitiveString::create(vm, #ClassName##_string), JS::Attribute::Configurable); \
|
||||
}
|
||||
|
||||
namespace Web::Bindings {
|
||||
DEFINE_WASM_ERROR_PROTOTYPE_AND_CONSTRUCTOR_WEB_INTRINSIC(CompileError, compile_error, CompileErrorPrototype, CompileErrorConstructor)
|
||||
DEFINE_WASM_ERROR_PROTOTYPE_AND_CONSTRUCTOR_WEB_INTRINSIC(LinkError, link_error, LinkErrorPrototype, LinkErrorConstructor)
|
||||
DEFINE_WASM_ERROR_PROTOTYPE_AND_CONSTRUCTOR_WEB_INTRINSIC(RuntimeError, runtime_error, RuntimeErrorPrototype, RuntimeErrorConstructor)
|
||||
}
|
||||
|
||||
#undef DEFINE_WASM_ERROR_PROTOTYPE_AND_CONSTRUCTOR_WEB_INTRINSIC
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue