[gjs: 10/16] object: Make ObjectPrototype constructor fallible



commit cf857bcd9fc83ad37fd2afd6b39449311c9729df
Author: Philip Chimento <philip chimento gmail com>
Date:   Sun Oct 28 16:53:12 2018 -0400

    object: Make ObjectPrototype constructor fallible
    
    ObjectPrototype has two GC hash tables whose construction is also
    fallible, so it needs to be fallible itself. The usual pattern in
    SpiderMonkey for this is to add an `init()` method that must be called
    after construction, which is fallible.

 gi/object.cpp | 24 ++++++++++++++++--------
 gi/object.h   |  4 +++-
 2 files changed, 19 insertions(+), 9 deletions(-)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index 4e2acbb9..30d57d24 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -1409,10 +1409,13 @@ ObjectInstance::ObjectInstance(JSContext* cx, JS::HandleObject object)
     debug_lifecycle("Instance constructor");
 }
 
-ObjectPrototype* ObjectPrototype::new_for_js_object(GIObjectInfo* info,
+ObjectPrototype* ObjectPrototype::new_for_js_object(JSContext* cx,
+                                                    GIObjectInfo* info,
                                                     GType gtype) {
     auto* priv = g_slice_new0(ObjectPrototype);
     new (priv) ObjectPrototype(info, gtype);
+    if (!priv->init(cx))
+        return nullptr;
     return priv;
 }
 
@@ -1423,16 +1426,18 @@ ObjectPrototype::ObjectPrototype(GIObjectInfo* info, GType gtype)
 
     g_type_class_ref(gtype);
 
-    if (!m_property_cache.init())
-        g_error("Out of memory for property cache of %s", type_name());
-
-    if (!m_field_cache.init())
-        g_error("Out of memory for field cache of %s", type_name());
-
     GJS_INC_COUNTER(object_prototype);
     debug_lifecycle("Prototype constructor");
 }
 
+bool ObjectPrototype::init(JSContext* cx) {
+    if (!m_property_cache.init() || !m_field_cache.init()) {
+        JS_ReportOutOfMemory(cx);
+        return false;
+    }
+    return true;
+}
+
 static void
 update_heap_wrapper_weak_pointers(JSContext     *cx,
                                   JSCompartment *compartment,
@@ -2237,7 +2242,10 @@ gjs_define_object_class(JSContext              *context,
                                GJS_MODULE_PROP_FLAGS))
         return false;
 
-    JS_SetPrivate(prototype, ObjectPrototype::new_for_js_object(info, gtype));
+    auto* priv = ObjectPrototype::new_for_js_object(context, info, gtype);
+    if (!priv)
+        return false;
+    JS_SetPrivate(prototype, priv);
 
     gjs_debug(GJS_DEBUG_GOBJECT, "Defined class for %s (%s), prototype %p, "
               "JSClass %p, in object %p", constructor_name, g_type_name(gtype),
diff --git a/gi/object.h b/gi/object.h
index babf36d5..536aea87 100644
--- a/gi/object.h
+++ b/gi/object.h
@@ -285,12 +285,14 @@ class ObjectPrototype : public ObjectBase {
     FieldCache m_field_cache;
 
     ObjectPrototype(GIObjectInfo* info, GType gtype);
+    GJS_JSAPI_RETURN_CONVENTION bool init(JSContext* cx);
     ~ObjectPrototype();
 
  public:
     /* Public constructor for instances (uses GSlice allocator) */
     GJS_USE
-    static ObjectPrototype* new_for_js_object(GIObjectInfo* info, GType gtype);
+    static ObjectPrototype* new_for_js_object(JSContext* cx, GIObjectInfo* info,
+                                              GType gtype);
 
     GJS_USE
     static ObjectPrototype* for_js(JSContext* cx, JS::HandleObject obj) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]