Don't dispatch virtual methods for builtin classes (reduces overhead).
Thu Feb 18 20:57:00 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Don't dispatch virtual methods for builtin classes (reduces overhead).
diff -rN -u old-smoke/src/bindings.lisp new-smoke/src/bindings.lisp
--- old-smoke/src/bindings.lisp 2014-10-16 03:57:10.000000000 +0200
+++ new-smoke/src/bindings.lisp 2014-10-16 03:57:10.000000000 +0200
@@ -9,6 +9,7 @@
(defstruct smoke-module
(pointer (null-pointer) :type foreign-pointer)
(binding (null-pointer) :type foreign-pointer)
+ (no-dispatch-binding (null-pointer) :type foreign-pointer)
(classes (make-smoke-array) :type smoke-array)
(methods (make-smoke-array) :type smoke-array)
diff -rN -u old-smoke/src/clos.lisp new-smoke/src/clos.lisp
--- old-smoke/src/clos.lisp 2014-10-16 03:57:10.000000000 +0200
+++ new-smoke/src/clos.lisp 2014-10-16 03:57:10.000000000 +0200
@@ -347,9 +347,7 @@
;; The Lisp OBJECT can be gc'ed but we might still receive a
;; QObject destructed event when the C++ instance is deleted in
;; the finalizer. Thus OBJECT might be NIL.
- (when (and object (typep (class-of object) 'cxx:class))
- ;; Do not allow overwriting methods of classes the users has
- ;; not derived from (like in C++), to reduce overhead.
+ (unless (null object)
(let* ((method (make-smoke-method
:smoke (gethash (pointer-address
(smoke-get-smoke binding))
diff -rN -u old-smoke/src/libsmoke/cl_smoke.h new-smoke/src/libsmoke/cl_smoke.h
--- old-smoke/src/libsmoke/cl_smoke.h 2014-10-16 03:57:10.000000000 +0200
+++ new-smoke/src/libsmoke/cl_smoke.h 2014-10-16 03:57:10.000000000 +0200
@@ -34,18 +34,6 @@
/** A Binding */
typedef void* smoke_binding;
-/** Casts the void pointer smoke_binding to the Binding class.
- * @param smoke the smoke binding
- *
- * @return pointer to the Binding instance
- */
-static inline
-Binding*
-get_smoke_binding(smoke_binding binding)
-{
- return static_cast<Binding*>(binding);
-}
-
/** Casts the void pointer smoke to the Smoke class.
* @param smoke the Smoke module
*
diff -rN -u old-smoke/src/libsmoke/class.lisp new-smoke/src/libsmoke/class.lisp
--- old-smoke/src/libsmoke/class.lisp 2014-10-16 03:57:10.000000000 +0200
+++ new-smoke/src/libsmoke/class.lisp 2014-10-16 03:57:10.000000000 +0200
@@ -5,6 +5,7 @@
(:constructor #x01)
(:copy-constructor #x02)
(:virtual-destructor #x04)
+ (:namespace #x08)
(:undefined #x10))
(defcstruct smoke-class
@@ -21,6 +22,7 @@
(m :pointer smoke-module-index)
(name :string))
+(declaim (inline smoke-class-id))
(defcfun (smoke-class-id "cl_smoke_class_id") smoke-index
(smoke :pointer)
(name :string))
diff -rN -u old-smoke/src/libsmoke/smoke.cpp new-smoke/src/libsmoke/smoke.cpp
--- old-smoke/src/libsmoke/smoke.cpp 2014-10-16 03:57:10.000000000 +0200
+++ new-smoke/src/libsmoke/smoke.cpp 2014-10-16 03:57:10.000000000 +0200
@@ -21,12 +21,15 @@
CL_SMOKE_EXPORT void*
cl_smoke_get_smoke(smoke_binding binding)
{
- return get_smoke_binding(binding)->get_smoke();
+ return static_cast<NoDispatchBinding*>(binding)->get_smoke();
}
/** Creates a new Smoke binding.
* The binding is allocated on the heap an can be freed with smoke_destruct().
+ * When method dispatching is not needed, a null pointer can be passed for @a dispatch.
* @related cl_smoke::Binding
+ * @related cl_smoke::NoDispatchBinding
+ * @related cl_smoke_destruct_binding
* @param smoke pointer to a Smoke module instance
* @param destruct callback for object destruction
* @param dispatch method dispatch callback
@@ -34,24 +37,28 @@
* @return a pointer to a new Smoke binding.
*/
CL_SMOKE_EXPORT smoke_binding
-cl_smoke_init(void* smoke, void* destruct, void* dispatch)
+cl_smoke_construct_binding(void* smoke, void* destruct, void* dispatch)
{
- return new Binding(static_cast<Smoke*>(smoke),
- reinterpret_cast<Binding::destructed>(destruct),
- reinterpret_cast<Binding::dispatch_method>(dispatch));
+ if (NULL == dispatch)
+ return new NoDispatchBinding(static_cast<Smoke*>(smoke),
+ reinterpret_cast<NoDispatchBinding::destructed>(destruct));
+ else
+ return new Binding(static_cast<Smoke*>(smoke),
+ reinterpret_cast<NoDispatchBinding::destructed>(destruct),
+ reinterpret_cast<Binding::dispatch_method>(dispatch));
}
-/** Deletes the smoke binding.
- * @related cl_smoke::Binding
+/** Deletes the Smoke binding.
+ * @related cl_smoke_construct_binding
*/
CL_SMOKE_EXPORT void
-cl_smoke_destruct(smoke_binding binding)
+cl_smoke_destruct_binding(smoke_binding binding)
{
- delete get_smoke_binding(binding)->get_smoke();
- delete get_smoke_binding(binding);
+ // Destructor is virtual; thus we can do this.
+ delete static_cast<SmokeBinding*>(binding);
}
-/** Gets a Smoke modules name.
+/** Gets a Smoke module name.
* @param smoke the Smoke module
*
* @return the module name
@@ -199,8 +206,11 @@
cl_smoke_find_method(Smoke::ModuleIndex* m, void* smoke,
Smoke::Index class_index, const char* method_name)
{
- *m = get_smoke(smoke)->findMethod(get_smoke(smoke)->className(class_index),
- method_name);
+ Q_ASSERT(class_index >= 0 && class_index <= get_smoke(smoke)->numClasses);
+
+ const char* class_name = get_smoke(smoke)->className(class_index);
+ *m = get_smoke(smoke)->findMethod(class_name, method_name);
+
if(m->index > 0)
m->index = m->smoke->methodMaps[m->index].method;
}
@@ -223,7 +233,7 @@
/** Casts an object.
* @param smoke the Smoke module
- * @param object the objec
+ * @param object the object
* @param from the class index of @a object
* @param to the class index to cast to
*
diff -rN -u old-smoke/src/libsmoke/smoke.lisp new-smoke/src/libsmoke/smoke.lisp
--- old-smoke/src/libsmoke/smoke.lisp 2014-10-16 03:57:10.000000000 +0200
+++ new-smoke/src/libsmoke/smoke.lisp 2014-10-16 03:57:10.000000000 +0200
@@ -37,12 +37,12 @@
"Smoke index."
`(integer ,lower ,upper))
-(defcfun (smoke-init "cl_smoke_init") smoke-binding
+(defcfun (smoke-construct-binding "cl_smoke_construct_binding") smoke-binding
(smoke :pointer)
(destruct :pointer)
(dispatch :pointer))
-(defcfun (smoke-destruct "cl_smoke_destruct") :void
+(defcfun (smoke-destruct-destruct "cl_smoke_destruct_binding") :void
(smoke smoke-binding))
;; Smoke::ModuleIndex is a POD-struct.
diff -rN -u old-smoke/src/libsmoke/smokebinding.cpp new-smoke/src/libsmoke/smokebinding.cpp
--- old-smoke/src/libsmoke/smokebinding.cpp 2014-10-16 03:57:10.000000000 +0200
+++ new-smoke/src/libsmoke/smokebinding.cpp 2014-10-16 03:57:10.000000000 +0200
@@ -6,18 +6,67 @@
namespace cl_smoke
{
-/** @class Binding
- * @brief The Smoke binding.
+/** @class NoDispatchBinding
+ * @brief The Smoke binding for classes we need no dispatching.
+ * This saves some overhead, since it does not call into Lisp.
+ * Idea stolen from CommonQt ;)
+ *
+ * Dispatches for non extended classes (not of class CXX:CLASS) are between
+ * 20% - 40% (for qt.examples:colliding-mice - qt.examples:class-browser). (18 February 2010)
*/
-
-/** @typedef Binding::destructed
+/** @typedef NoDispatchBinding::destructed
* Callback when a Smoke object is destructed.
*
* @param class_index Index of the object's class.
* @param object pointer to the object
*/
+/** Constructor.
+ * @param smoke the Smoke module
+ * @param destruct destruct callback
+ */
+NoDispatchBinding::NoDispatchBinding(Smoke *smoke, destructed destruct)
+ : SmokeBinding(smoke),
+ destruct(destruct)
+{
+ Q_ASSERT(destruct);
+}
+
+/** Invoked when a Smoke object is destructed. */
+void
+NoDispatchBinding::deleted(Smoke::Index, void *object)
+{
+ destruct(object);
+}
+
+/** Invoked when a Smoke method gets called. */
+bool
+NoDispatchBinding::callMethod(Smoke::Index method, void* object,
+ Smoke::Stack stack, bool abstract)
+{
+ Q_ASSERT(!abstract);
+ return false;
+}
+
+/**
+ * @todo Returning a const char* would be better
+ */
+char*
+NoDispatchBinding::className(Smoke::Index classId)
+{
+ Q_ASSERT(classId >= 0 && classId <= smoke->numClasses);
+ return const_cast<char*>(smoke->classes[classId].className);
+}
+
+/** @function NoDispatchBinding::get_smoke()
+ * Gets the Smoke instance associated with the binding.
+ * @return a pointer to the Smoke instance
+ */
+
+/** @class Binding
+ * @brief The Smoke binding.
+ */
/** @typedef Binding::dispatch_method
* Callback when a Smoke method gets called.
@@ -39,21 +88,12 @@
*/
Binding::Binding(Smoke *smoke, destructed destruct,
dispatch_method dispatch)
- : SmokeBinding(smoke),
- destruct(destruct),
+ : NoDispatchBinding(smoke, destruct),
dispatch(dispatch)
{
- Q_ASSERT(smoke);
- Q_ASSERT(destruct);
Q_ASSERT(dispatch);
}
-/** Invoked when a Smoke object is destructed. */
-void
-Binding::deleted(Smoke::Index, void *object)
-{
- destruct(object);
-}
/** Invoked when a Smoke method gets called. */
bool
@@ -66,22 +106,4 @@
return ret;
}
-/**
- * @todo Returning a const char* would be better
- */
-char*
-Binding::className(Smoke::Index classId)
-{
- return const_cast<char*>(smoke->classes[classId].className);
-}
-
-/** Gets the Smoke instance associated with the binding.
- * @return a pointer to the Smoke instance
- */
-Smoke*
-Binding::get_smoke() const
-{
- return smoke;
-}
-
} // namespace cl_smoke
diff -rN -u old-smoke/src/libsmoke/smokebinding.h new-smoke/src/libsmoke/smokebinding.h
--- old-smoke/src/libsmoke/smokebinding.h 2014-10-16 03:57:10.000000000 +0200
+++ new-smoke/src/libsmoke/smokebinding.h 2014-10-16 03:57:10.000000000 +0200
@@ -6,15 +6,12 @@
namespace cl_smoke
{
-class Binding : public SmokeBinding
+class NoDispatchBinding : public SmokeBinding
{
public:
typedef void (*destructed)(void* object);
- typedef int (*dispatch_method)(Binding* binding, Smoke::Index method,
- void* object, Smoke::Stack args, int abstract);
-
- Binding(Smoke *smoke, destructed destruct, dispatch_method dispatch);
+ NoDispatchBinding(Smoke *smoke, destructed destruct);
virtual void
deleted(Smoke::Index classId, void *object);
@@ -27,10 +24,28 @@
className(Smoke::Index classId);
Smoke*
- get_smoke() const;
+ get_smoke() const
+ { return smoke; }
private:
const destructed destruct;
+};
+
+class Binding : public NoDispatchBinding
+{
+ public:
+ typedef int (*dispatch_method)(Binding* binding, Smoke::Index method,
+ void* object, Smoke::Stack args, int abstract);
+
+ Binding(Smoke *smoke, destructed destruct, dispatch_method dispatch);
+
+
+ virtual bool
+ callMethod(Smoke::Index method, void* object,
+ Smoke::Stack stack, bool abstract);
+
+
+ private:
const dispatch_method dispatch;
};
diff -rN -u old-smoke/src/smoke.lisp new-smoke/src/smoke.lisp
--- old-smoke/src/smoke.lisp 2014-10-16 03:57:10.000000000 +0200
+++ new-smoke/src/smoke.lisp 2014-10-16 03:57:10.000000000 +0200
@@ -82,25 +82,31 @@
(defun set-binding (object)
"Sets the Smoke binding for OBJECT, that receives its callbacks."
(declare (optimize (speed 3)))
- (with-foreign-object (stack 'smoke-stack-item 2)
- (setf (foreign-slot-value (mem-aref stack 'smoke-stack-item 1)
- 'smoke-stack-item 'voidp)
- (smoke-module-binding (smoke (class-of object))))
- (foreign-funcall-pointer
- (foreign-slot-value (smoke-class-pointer (class-of object))
- 'smoke-class 'class-function)
- ()
- smoke-index 0 ;; set binding method index
- :pointer (pointer object)
- smoke-stack stack
- :void)))
+ (let ((class (class-of object)))
+ (with-foreign-object (stack 'smoke-stack-item 2)
+ (setf (foreign-slot-value (mem-aref stack 'smoke-stack-item 1)
+ 'smoke-stack-item 'voidp)
+ (if (typep class 'cxx:class)
+ (smoke-module-binding (smoke class))
+ (smoke-module-no-dispatch-binding (smoke class))))
+ (foreign-funcall-pointer
+ (foreign-slot-value (smoke-class-pointer class)
+ 'smoke-class 'class-function)
+ ()
+ smoke-index 0 ;; set binding method index
+ :pointer (pointer object)
+ smoke-stack stack
+ :void))))
(defun init (smoke module)
"Returns the a new Smoke binding for the Smoke module SMOKE."
(use-foreign-library libclsmoke)
- (let* ((binding (smoke-init smoke (callback destructed)
- (callback dispatch-method))))
+ (let ((no-dispatch-binding
+ (smoke-construct-binding smoke (callback destructed) (null-pointer)))
+ (binding (smoke-construct-binding smoke (callback destructed)
+ (callback dispatch-method))))
(setf (smoke-module-pointer module) smoke
+ (smoke-module-no-dispatch-binding module) no-dispatch-binding
(smoke-module-binding module) binding)
(init-smoke-module module)
(setf (gethash (pointer-address smoke) *smoke-modules*) module)