summaryrefslogtreecommitdiffstats
path: root/generic/tclOO.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclOO.c')
-rw-r--r--generic/tclOO.c143
1 files changed, 94 insertions, 49 deletions
diff --git a/generic/tclOO.c b/generic/tclOO.c
index 84bb85a..ef0c987 100644
--- a/generic/tclOO.c
+++ b/generic/tclOO.c
@@ -58,6 +58,8 @@ static const struct {
static Class * AllocClass(Tcl_Interp *interp, Object *useThisObj);
static Object * AllocObject(Tcl_Interp *interp, const char *nameStr,
const char *nsNameStr);
+static void ClearMixins(Class *clsPtr);
+static void ClearSuperclasses(Class *clsPtr);
static int CloneClassMethod(Tcl_Interp *interp, Class *clsPtr,
Method *mPtr, Tcl_Obj *namePtr,
Method **newMPtrPtr);
@@ -66,12 +68,9 @@ static int CloneObjectMethod(Tcl_Interp *interp, Object *oPtr,
static void DeletedDefineNamespace(ClientData clientData);
static void DeletedObjdefNamespace(ClientData clientData);
static void DeletedHelpersNamespace(ClientData clientData);
-static int FinalizeAlloc(ClientData data[],
- Tcl_Interp *interp, int result);
-static int FinalizeNext(ClientData data[],
- Tcl_Interp *interp, int result);
-static int FinalizeObjectCall(ClientData data[],
- Tcl_Interp *interp, int result);
+static Tcl_NRPostProc FinalizeAlloc;
+static Tcl_NRPostProc FinalizeNext;
+static Tcl_NRPostProc FinalizeObjectCall;
static int InitFoundation(Tcl_Interp *interp);
static void KillFoundation(ClientData clientData,
Tcl_Interp *interp);
@@ -267,7 +266,7 @@ TclOOInit(
* to be fully provided.
*/
- if (Tcl_Eval(interp, initScript) != TCL_OK) {
+ if (Tcl_EvalEx(interp, initScript, -1, 0) != TCL_OK) {
return TCL_ERROR;
}
@@ -461,7 +460,7 @@ InitFoundation(
if (TclOODefineSlots(fPtr) != TCL_OK) {
return TCL_ERROR;
}
- return Tcl_Eval(interp, slotScript);
+ return Tcl_EvalEx(interp, slotScript, -1, 0);
}
/*
@@ -896,6 +895,55 @@ ObjectRenamedTrace(
/*
* ----------------------------------------------------------------------
*
+ * ClearMixins, ClearSuperclasses --
+ *
+ * Utility functions for correctly clearing the list of mixins or
+ * superclasses of a class. Will ckfree() the list storage.
+ *
+ * ----------------------------------------------------------------------
+ */
+
+static void
+ClearMixins(
+ Class *clsPtr)
+{
+ int i;
+ Class *mixinPtr;
+
+ if (clsPtr->mixins.num == 0) {
+ return;
+ }
+
+ FOREACH(mixinPtr, clsPtr->mixins) {
+ TclOORemoveFromMixinSubs(clsPtr, mixinPtr);
+ }
+ ckfree(clsPtr->mixins.list);
+ clsPtr->mixins.list = NULL;
+ clsPtr->mixins.num = 0;
+}
+
+static void
+ClearSuperclasses(
+ Class *clsPtr)
+{
+ int i;
+ Class *superPtr;
+
+ if (clsPtr->superclasses.num == 0) {
+ return;
+ }
+
+ FOREACH(superPtr, clsPtr->superclasses) {
+ TclOORemoveFromSubclasses(clsPtr, superPtr);
+ }
+ ckfree(clsPtr->superclasses.list);
+ clsPtr->superclasses.list = NULL;
+ clsPtr->superclasses.num = 0;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
* ReleaseClassContents --
*
* Tear down the special class data structure, including deleting all
@@ -951,6 +999,16 @@ ReleaseClassContents(
}
if (!IsRootClass(oPtr)) {
FOREACH(instancePtr, clsPtr->instances) {
+ int j;
+ if (instancePtr->selfCls == clsPtr) {
+ instancePtr->flags |= CLASS_GONE;
+ }
+ for(j=0 ; j<instancePtr->mixins.num ; j++) {
+ Class *mixin = instancePtr->mixins.list[j];
+ if (mixin == clsPtr) {
+ instancePtr->mixins.list[j] = NULL;
+ }
+ }
if (instancePtr != NULL && !IsRoot(instancePtr)) {
AddRef(instancePtr);
}
@@ -962,13 +1020,11 @@ ReleaseClassContents(
*/
FOREACH(mixinSubclassPtr, clsPtr->mixinSubs) {
- if (mixinSubclassPtr == NULL) {
- continue;
- }
if (!Deleted(mixinSubclassPtr->thisPtr)) {
Tcl_DeleteCommandFromToken(interp,
mixinSubclassPtr->thisPtr->command);
}
+ ClearMixins(mixinSubclassPtr);
DelRef(mixinSubclassPtr->thisPtr);
DelRef(mixinSubclassPtr);
}
@@ -983,12 +1039,13 @@ ReleaseClassContents(
*/
FOREACH(subclassPtr, clsPtr->subclasses) {
- if (subclassPtr == NULL || IsRoot(subclassPtr)) {
+ if (IsRoot(subclassPtr)) {
continue;
}
if (!Deleted(subclassPtr->thisPtr)) {
Tcl_DeleteCommandFromToken(interp, subclassPtr->thisPtr->command);
}
+ ClearSuperclasses(subclassPtr);
DelRef(subclassPtr->thisPtr);
DelRef(subclassPtr);
}
@@ -1131,12 +1188,14 @@ ObjectNamespaceDeleted(
* methods on the object.
*/
- if (!IsRootObject(oPtr)) {
+ if (!IsRootObject(oPtr) && !(oPtr->flags & CLASS_GONE)) {
TclOORemoveFromInstances(oPtr, oPtr->selfCls);
}
FOREACH(mixinPtr, oPtr->mixins) {
- TclOORemoveFromInstances(oPtr, mixinPtr);
+ if (mixinPtr) {
+ TclOORemoveFromInstances(oPtr, mixinPtr);
+ }
}
if (i) {
ckfree(oPtr->mixins.list);
@@ -1182,8 +1241,11 @@ ObjectNamespaceDeleted(
oPtr->metadataPtr = NULL;
}
+ /*
+ * If this was a class, there's additional deletion work to do.
+ */
+
if (clsPtr != NULL) {
- Class *superPtr;
Tcl_ObjectMetadataType *metadataTypePtr;
ClientData value;
@@ -1203,24 +1265,11 @@ ObjectNamespaceDeleted(
ckfree(clsPtr->filters.list);
clsPtr->filters.num = 0;
}
- FOREACH(mixinPtr, clsPtr->mixins) {
- if (!Deleted(mixinPtr->thisPtr)) {
- TclOORemoveFromMixinSubs(clsPtr, mixinPtr);
- }
- }
- if (i) {
- ckfree(clsPtr->mixins.list);
- clsPtr->mixins.num = 0;
- }
- FOREACH(superPtr, clsPtr->superclasses) {
- if (!Deleted(superPtr->thisPtr)) {
- TclOORemoveFromSubclasses(clsPtr, superPtr);
- }
- }
- if (i) {
- ckfree(clsPtr->superclasses.list);
- clsPtr->superclasses.num = 0;
- }
+
+ ClearMixins(clsPtr);
+
+ ClearSuperclasses(clsPtr);
+
if (clsPtr->subclasses.list) {
ckfree(clsPtr->subclasses.list);
clsPtr->subclasses.num = 0;
@@ -1362,9 +1411,7 @@ TclOORemoveFromSubclasses(
return;
removeSubclass:
- if (Deleted(superPtr->thisPtr)) {
- superPtr->subclasses.list[i] = NULL;
- } else {
+ if (!Deleted(superPtr->thisPtr)) {
superPtr->subclasses.num--;
if (i < superPtr->subclasses.num) {
superPtr->subclasses.list[i] =
@@ -1435,9 +1482,7 @@ TclOORemoveFromMixinSubs(
return;
removeSubclass:
- if (Deleted(superPtr->thisPtr)) {
- superPtr->mixinSubs.list[i] = NULL;
- } else {
+ if (!Deleted(superPtr->thisPtr)) {
superPtr->mixinSubs.num--;
if (i < superPtr->mixinSubs.num) {
superPtr->mixinSubs.list[i] =
@@ -1639,7 +1684,7 @@ Tcl_NewObjectInstance(
TclOOGetCallContext(oPtr, NULL, CONSTRUCTOR, NULL);
if (contextPtr != NULL) {
- int result;
+ int isRoot, result;
Tcl_InterpState state;
state = Tcl_SaveInterpState(interp, TCL_OK);
@@ -1650,13 +1695,14 @@ Tcl_NewObjectInstance(
* Adjust the ensmble tracking record if necessary. [Bug 3514761]
*/
- if (((Interp*) interp)->ensembleRewrite.sourceObjs) {
- ((Interp*) interp)->ensembleRewrite.numInsertedObjs += skip-1;
- ((Interp*) interp)->ensembleRewrite.numRemovedObjs += skip-1;
- }
+ isRoot = TclInitRewriteEnsemble(interp, skip, skip, objv);
result = Tcl_NRCallObjProc(interp, TclOOInvokeContext, contextPtr,
objc, objv);
+ if (isRoot) {
+ TclResetRewriteEnsemble(interp, 1);
+ }
+
/*
* It's an error if the object was whacked in the constructor.
* Force this if it isn't already an error (don't want to lose
@@ -1779,9 +1825,8 @@ TclNRNewObjectInstance(
* Adjust the ensmble tracking record if necessary. [Bug 3514761]
*/
- if (((Interp *) interp)->ensembleRewrite.sourceObjs) {
- ((Interp *) interp)->ensembleRewrite.numInsertedObjs += skip - 1;
- ((Interp *) interp)->ensembleRewrite.numRemovedObjs += skip - 1;
+ if (TclInitRewriteEnsemble(interp, skip, skip, objv)) {
+ TclNRAddCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL, NULL);
}
/*
@@ -1908,13 +1953,13 @@ Tcl_CopyObjectInstance(
*/
FOREACH(mixinPtr, o2Ptr->mixins) {
- if (mixinPtr != o2Ptr->selfCls) {
+ if (mixinPtr && mixinPtr != o2Ptr->selfCls) {
TclOORemoveFromInstances(o2Ptr, mixinPtr);
}
}
DUPLICATE(o2Ptr->mixins, oPtr->mixins, Class *);
FOREACH(mixinPtr, o2Ptr->mixins) {
- if (mixinPtr != o2Ptr->selfCls) {
+ if (mixinPtr && mixinPtr != o2Ptr->selfCls) {
TclOOAddToInstances(o2Ptr, mixinPtr);
}
}