Thu Feb 18 20:57:00 CET 2010 Tobias Rautenkranz * 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-30 06:22:29.000000000 +0100 +++ new-smoke/src/bindings.lisp 2014-10-30 06:22:29.000000000 +0100 @@ -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-30 06:22:29.000000000 +0100 +++ new-smoke/src/clos.lisp 2014-10-30 06:22:29.000000000 +0100 @@ -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-30 06:22:29.000000000 +0100 +++ new-smoke/src/libsmoke/cl_smoke.h 2014-10-30 06:22:29.000000000 +0100 @@ -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); -} - /** 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-30 06:22:29.000000000 +0100 +++ new-smoke/src/libsmoke/class.lisp 2014-10-30 06:22:29.000000000 +0100 @@ -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-30 06:22:29.000000000 +0100 +++ new-smoke/src/libsmoke/smoke.cpp 2014-10-30 06:22:29.000000000 +0100 @@ -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(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), - reinterpret_cast(destruct), - reinterpret_cast(dispatch)); + if (NULL == dispatch) + return new NoDispatchBinding(static_cast(smoke), + reinterpret_cast(destruct)); + else + return new Binding(static_cast(smoke), + reinterpret_cast(destruct), + reinterpret_cast(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(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-30 06:22:29.000000000 +0100 +++ new-smoke/src/libsmoke/smoke.lisp 2014-10-30 06:22:29.000000000 +0100 @@ -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-30 06:22:29.000000000 +0100 +++ new-smoke/src/libsmoke/smokebinding.cpp 2014-10-30 06:22:29.000000000 +0100 @@ -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(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(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-30 06:22:29.000000000 +0100 +++ new-smoke/src/libsmoke/smokebinding.h 2014-10-30 06:22:29.000000000 +0100 @@ -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-30 06:22:29.000000000 +0100 +++ new-smoke/src/smoke.lisp 2014-10-30 06:22:29.000000000 +0100 @@ -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)