Skip to content

Commit

Permalink
gc: add finalization for URL (#105)
Browse files Browse the repository at this point in the history
  • Loading branch information
guybedford authored Sep 27, 2024
1 parent afcb458 commit 3c2d7ff
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 34 deletions.
5 changes: 5 additions & 0 deletions builtins/web/url.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,11 @@ JSObject *URL::create(JSContext *cx, JS::HandleObject self, JS::HandleValue url_
return create(cx, self, url_val, base);
}

void URL::finalize(JS::GCContext *gcx, JSObject *self) {
jsurl::JSUrl* url = static_cast<jsurl::JSUrl *>(JS::GetReservedSlot(self, Slots::Url).toPrivate());
free(url);
}

JSObject *URL::create(JSContext *cx, JS::HandleObject self, JS::HandleValue url_val,
JS::HandleValue base_val) {
if (is_instance(base_val)) {
Expand Down
3 changes: 2 additions & 1 deletion builtins/web/url.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class URLSearchParams : public BuiltinNoConstructor<URLSearchParams> {
static bool constructor(JSContext *cx, unsigned argc, JS::Value *vp);
};

class URL : public BuiltinImpl<URL> {
class URL : public FinalizableBuiltinImpl<URL> {
static bool hash_set(JSContext *cx, unsigned argc, JS::Value *vp);
static bool host_set(JSContext *cx, unsigned argc, JS::Value *vp);
static bool hostname_set(JSContext *cx, unsigned argc, JS::Value *vp);
Expand Down Expand Up @@ -131,6 +131,7 @@ class URL : public BuiltinImpl<URL> {

static bool init_class(JSContext *cx, JS::HandleObject global);
static bool constructor(JSContext *cx, unsigned argc, JS::Value *vp);
static void finalize(JS::GCContext *gcx, JSObject *obj);
};

bool install(api::Engine *engine);
Expand Down
84 changes: 51 additions & 33 deletions include/builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ using JS::PersistentRooted;
std::optional<std::span<uint8_t>> value_to_buffer(JSContext *cx, HandleValue val,
const char *val_desc);

#define DEF_ERR(name, exception, format, count) \
static constexpr JSErrorFormatString name = { #name, format, count, exception };
#define DEF_ERR(name, exception, format, count) \
static constexpr JSErrorFormatString name = {#name, format, count, exception};

namespace api {
#include "errors.h"
Expand Down Expand Up @@ -123,39 +123,39 @@ void markWizeningAsFinished();
BUILTIN_ITERATOR_METHOD(class_name, keys, ITER_TYPE_KEYS) \
BUILTIN_ITERATOR_METHOD(class_name, values, ITER_TYPE_VALUES) \
\
bool class_name::forEach(JSContext *cx, unsigned argc, JS::Value *vp) { \
METHOD_HEADER(1) \
if (!args[0].isObject() || !JS::IsCallable(&args[0].toObject())) { \
return api::throw_error(cx, api::Errors::ForEachCallback, #class_name); \
} \
JS::RootedValueArray<3> newArgs(cx); \
newArgs[2].setObject(*self); \
JS::RootedValue rval(cx); \
JS::RootedObject iter(cx, class_name##Iterator::create(cx, self, ITER_TYPE_ENTRIES)); \
if (!iter) \
return false; \
JS::RootedValue iterable(cx, ObjectValue(*iter)); \
JS::ForOfIterator it(cx); \
if (!it.init(iterable)) \
return false; \
\
JS::RootedValue entry_val(cx); \
JS::RootedObject entry(cx); \
while (true) { \
bool done; \
if (!it.next(&entry_val, &done)) \
bool class_name::forEach(JSContext *cx, unsigned argc, JS::Value *vp) { \
METHOD_HEADER(1) \
if (!args[0].isObject() || !JS::IsCallable(&args[0].toObject())) { \
return api::throw_error(cx, api::Errors::ForEachCallback, #class_name); \
} \
JS::RootedValueArray<3> newArgs(cx); \
newArgs[2].setObject(*self); \
JS::RootedValue rval(cx); \
JS::RootedObject iter(cx, class_name##Iterator::create(cx, self, ITER_TYPE_ENTRIES)); \
if (!iter) \
return false; \
if (done) \
break; \
\
entry = &entry_val.toObject(); \
JS_GetElement(cx, entry, 1, newArgs[0]); \
JS_GetElement(cx, entry, 0, newArgs[1]); \
if (!JS::Call(cx, args.thisv(), args[0], newArgs, &rval)) \
JS::RootedValue iterable(cx, ObjectValue(*iter)); \
JS::ForOfIterator it(cx); \
if (!it.init(iterable)) \
return false; \
} \
return true; \
}
\
JS::RootedValue entry_val(cx); \
JS::RootedObject entry(cx); \
while (true) { \
bool done; \
if (!it.next(&entry_val, &done)) \
return false; \
if (done) \
break; \
\
entry = &entry_val.toObject(); \
JS_GetElement(cx, entry, 1, newArgs[0]); \
JS_GetElement(cx, entry, 0, newArgs[1]); \
if (!JS::Call(cx, args.thisv(), args[0], newArgs, &rval)) \
return false; \
} \
return true; \
}

#define REQUEST_HANDLER_ONLY(name) \
if (isWizening()) { \
Expand Down Expand Up @@ -228,6 +228,24 @@ template <typename Impl> class BuiltinImpl {

return proto_obj != nullptr;
}

static void finalize(JS::GCContext *gcx, JSObject *obj) {}
};

template <typename Impl> class FinalizableBuiltinImpl : public BuiltinImpl<Impl> {
static constexpr JSClassOps class_ops{
nullptr, // addProperty
nullptr, // delProperty
nullptr, // enumerate
nullptr, // newEnumerate
nullptr, // resolve
nullptr, // mayResolve
Impl::finalize, // finalize
nullptr, // call
nullptr, // construct
nullptr, // trace
};
static constexpr uint32_t class_flags = JSCLASS_BACKGROUND_FINALIZE;
};

template <typename Impl> PersistentRooted<JSObject *> BuiltinImpl<Impl>::proto_obj{};
Expand Down

0 comments on commit 3c2d7ff

Please sign in to comment.