summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.current9
-rw-r--r--Examples/test-suite/null_pointer.i4
-rw-r--r--Examples/test-suite/tcl/null_pointer_runme.tcl21
-rw-r--r--Lib/tcl/tclapi.swg1
-rw-r--r--Lib/tcl/tclinit.swg23
-rw-r--r--Lib/tcl/tclrun.swg14
6 files changed, 64 insertions, 8 deletions
diff --git a/CHANGES.current b/CHANGES.current
index 4b1f2d840..f1078e5e0 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -5,6 +5,15 @@ See the RELEASENOTES file for a summary of changes in each release.
Version 2.0.3 (in progress)
===========================
+2011-03-29: wsfulton
+ [Tcl] Apply patch #3224663 from Christian Delbaere.
+ 1. Fix when function returns a NULL value, a "NULL" command will be created in the Tcl interpreter
+ and calling this command will cause a segmentation fault.
+
+ 2. Previous implementation searches for class methods using a linear search causing performance issues
+ in wrappers for classes with many member functions. The patch adds a method hash table to classes and
+ changes method name lookup to use the hash table instead of doing a linear search.
+
2011-03-26: wsfulton
[C#, Java] SF bug #3195112 - fix wrapping of enums that are type char, for example:
enum { X = 'X'; }
diff --git a/Examples/test-suite/null_pointer.i b/Examples/test-suite/null_pointer.i
index 0bd7a9b92..0da827f99 100644
--- a/Examples/test-suite/null_pointer.i
+++ b/Examples/test-suite/null_pointer.i
@@ -8,5 +8,9 @@
bool func(A* a) {
return !a;
}
+
+ A* getnull() {
+ return 0;
+ }
}
diff --git a/Examples/test-suite/tcl/null_pointer_runme.tcl b/Examples/test-suite/tcl/null_pointer_runme.tcl
new file mode 100644
index 000000000..be99c7166
--- /dev/null
+++ b/Examples/test-suite/tcl/null_pointer_runme.tcl
@@ -0,0 +1,21 @@
+if [ catch { load ./null_pointer[info sharedlibextension] null_pointer} err_msg ] {
+ puts stderr "Could not load shared object:\n$err_msg"
+}
+
+set a [A]
+if {[func $a] != 0} {
+ puts stderr "null_pointer test 1 failed"
+ exit 1
+}
+
+set null [getnull]
+if {$null != "NULL"} {
+ puts stderr "null_pointer test 2 failed"
+ exit 1
+}
+
+if {[llength [info commands "NULL"]] != 0} {
+ puts stderr "null_pointer test 3 failed"
+ exit 1
+}
+
diff --git a/Lib/tcl/tclapi.swg b/Lib/tcl/tclapi.swg
index 6b67327a2..33dc324d4 100644
--- a/Lib/tcl/tclapi.swg
+++ b/Lib/tcl/tclapi.swg
@@ -49,6 +49,7 @@ typedef struct swig_class {
struct swig_class **bases;
const char **base_names;
swig_module_info *module;
+ Tcl_HashTable hashtable;
} swig_class;
typedef struct swig_instance {
diff --git a/Lib/tcl/tclinit.swg b/Lib/tcl/tclinit.swg
index 6910d3c51..9b3224104 100644
--- a/Lib/tcl/tclinit.swg
+++ b/Lib/tcl/tclinit.swg
@@ -67,6 +67,28 @@ SWIG_Tcl_InstallConstants(Tcl_Interp *interp, swig_const_info constants[]) {
}
}
+/* Create fast method lookup tables */
+
+SWIGINTERN void
+SWIG_Tcl_InstallMethodLookupTables(Tcl_Interp *interp) {
+ int i;
+
+ for (i = 0; i < swig_module.size; ++i) {
+ swig_type_info *type = swig_module.type_initial[i];
+ if (type->clientdata) {
+ swig_class* klass = (swig_class*) type->clientdata;
+ Tcl_InitHashTable(&(klass->hashtable), TCL_STRING_KEYS);
+ swig_method* meth = klass->methods;
+ while (meth && meth->name) {
+ int newEntry;
+ Tcl_HashEntry* hashentry = Tcl_CreateHashEntry(&(klass->hashtable), meth->name, &newEntry);
+ Tcl_SetHashValue(hashentry, (ClientData)meth->method);
+ ++meth;
+ }
+ }
+ }
+}
+
#ifdef __cplusplus
}
#endif
@@ -113,6 +135,7 @@ SWIGEXPORT int SWIG_init(Tcl_Interp *interp) {
}
SWIG_Tcl_InstallConstants(interp, swig_constants);
+ SWIG_Tcl_InstallMethodLookupTables(interp);
%}
diff --git a/Lib/tcl/tclrun.swg b/Lib/tcl/tclrun.swg
index eb8bd253c..dd6458e90 100644
--- a/Lib/tcl/tclrun.swg
+++ b/Lib/tcl/tclrun.swg
@@ -367,19 +367,17 @@ SWIG_Tcl_MethodCommand(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_
}
cls_stack_bi[cls_stack_top]++;
- meth = cls->methods;
- /* Check for methods */
- while (meth && meth->name) {
- if (strcmp(meth->name,method) == 0) {
+ Tcl_HashEntry* hashentry = Tcl_FindHashEntry(&(cls->hashtable), method);
+ if (hashentry) {
+ ClientData cd = Tcl_GetHashValue(hashentry);
+ swig_wrapper method_wrapper = (swig_wrapper)cd;
oldarg = objv[1];
objv[1] = inst->thisptr;
Tcl_IncrRefCount(inst->thisptr);
- rcode = (*meth->method)(clientData,interp,objc,objv);
+ rcode = (method_wrapper)(clientData,interp,objc,objv);
objv[1] = oldarg;
Tcl_DecrRefCount(inst->thisptr);
return rcode;
- }
- meth++;
}
/* Check class methods for a match */
if (strcmp(method,"cget") == 0) {
@@ -486,7 +484,7 @@ SWIGRUNTIME Tcl_Obj *
SWIG_Tcl_NewInstanceObj(Tcl_Interp *interp, void *thisvalue, swig_type_info *type, int flags) {
Tcl_Obj *robj = SWIG_NewPointerObj(thisvalue, type,0);
/* Check to see if this pointer belongs to a class or not */
- if ((type->clientdata) && (interp)) {
+ if (thisvalue && (type->clientdata) && (interp)) {
Tcl_CmdInfo ci;
char *name;
name = Tcl_GetStringFromObj(robj,NULL);