[gjs: 1/2] object: Avoid looking up predefined methods in GI



commit b95e9a1f374b921f6ff867e0f971bc4f704cb50d
Author: Colin Walters <walters verbum org>
Date:   Tue Oct 19 06:13:24 2010 -0700

    object: Avoid looking up predefined methods in GI
    
    SpiderMonkey will call the property resolve operation every time we
    try to call one of the predefined override functions like "emit".
    This is particularly problematic because the code to loop over
    interfaces for a given class is hit badly by introspections' lack
    of indexing in the typelib directory.
    
    Concretely, every time we were calling foo.emit("blah", param), we'd scan
    typelibs multiple times (e.g. for an object implementing an interface in
    both Atk and Gtk).
    
    Sadly, because of methods like Gio.Cancellable.connect(), we can't do the
    same thing for "connect()" which is probably the worst case.
    
    (Patch originally by Colin Walters, rewritten by Philip Chimento)
    
    Closes #54.

 gi/object.cpp | 18 ++++++++++++++++++
 gjs/atoms.h   |  2 ++
 2 files changed, 20 insertions(+)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index fcc58be4..d98419c5 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -838,10 +838,28 @@ bool ObjectBase::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
     return priv->to_prototype()->resolve_impl(cx, obj, id, resolved);
 }
 
+/* The JSResolveOp for an instance is called for every property not
+ * defined, even if it's one of the functions or properties we're
+ * adding to the proto manually.
+ */
+static bool name_is_overridden(jsid name, const GjsAtoms& atoms) {
+    // Keep this list in sync with gjs_object_instance_proto_props and
+    // gjs_object_instance_proto_funcs. However, explicitly do not include
+    // connect() in it, because there are a few cases where the lazy property
+    // should override the predefined one, such as Gio.Cancellable.connect().
+    return name == atoms.init() || name == atoms.connect_after() ||
+           name == atoms.emit() || name == atoms.to_string();
+}
+
 bool ObjectPrototype::resolve_impl(JSContext* context, JS::HandleObject obj,
                                    JS::HandleId id, bool* resolved) {
     debug_jsprop("Resolve hook", id, obj);
 
+    if (name_is_overridden(id, GjsContextPrivate::atoms(context))) {
+        *resolved = false;
+        return true;
+    }
+
     JS::UniqueChars name;
     if (!gjs_get_string_id(context, id, &name))
         return false;
diff --git a/gjs/atoms.h b/gjs/atoms.h
index 674a2289..ed8e4fe7 100644
--- a/gjs/atoms.h
+++ b/gjs/atoms.h
@@ -32,8 +32,10 @@
 #define FOR_EACH_ATOM(macro) \
     macro(code, "code") \
     macro(column_number, "columnNumber") \
+    macro(connect_after, "connect_after") \
     macro(constructor, "constructor") \
     macro(debuggee, "debuggee") \
+    macro(emit, "emit") \
     macro(file, "__file__") \
     macro(file_name, "fileName") \
     macro(gi, "gi") \


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