diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2018-10-19 10:06:23 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2018-10-19 10:06:23 (GMT) |
commit | fca6e38924437639527aca6bdeb434a00f3169ea (patch) | |
tree | ec57c10036ec449293a55d7ec8f2d213539ca2d1 /generic | |
parent | e7392a5c2218ae1a8c95f1172fba911c9e7b110a (diff) | |
parent | 09446c7544e32d0eca9c0c68d7917729e6c33ee8 (diff) | |
download | tcl-fca6e38924437639527aca6bdeb434a00f3169ea.zip tcl-fca6e38924437639527aca6bdeb434a00f3169ea.tar.gz tcl-fca6e38924437639527aca6bdeb434a00f3169ea.tar.bz2 |
merge core-8-6-branch
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclOO.c | 96 | ||||
-rw-r--r-- | generic/tclOOCall.c | 1 | ||||
-rw-r--r-- | generic/tclOODefineCmds.c | 32 | ||||
-rw-r--r-- | generic/tclOOInt.h | 11 |
4 files changed, 105 insertions, 35 deletions
diff --git a/generic/tclOO.c b/generic/tclOO.c index c8471d5..0c18390 100644 --- a/generic/tclOO.c +++ b/generic/tclOO.c @@ -59,7 +59,6 @@ static const struct { * Function declarations for things defined in this file. */ -static Class * AllocClass(Tcl_Interp *interp, Object *useThisObj); static Object * AllocObject(Tcl_Interp *interp, const char *nameStr, Namespace *nsPtr, const char *nsNameStr); static int CloneClassMethod(Tcl_Interp *interp, Class *clsPtr, @@ -84,8 +83,6 @@ static void ObjectNamespaceDeleted(ClientData clientData); static void ObjectRenamedTrace(ClientData clientData, Tcl_Interp *interp, const char *oldName, const char *newName, int flags); -static void ReleaseClassContents(Tcl_Interp *interp,Object *oPtr); -static void DeleteDescendants(Tcl_Interp *interp,Object *oPtr); static inline void RemoveClass(Class **list, int num, int idx); static inline void RemoveObject(Object **list, int num, int idx); static inline void SquelchCachedName(Object *oPtr); @@ -451,10 +448,10 @@ InitClassSystemRoots( /* Stand up a phony class for bootstrapping. */ fPtr->objectCls = &fakeCls; - /* referenced in AllocClass to increment the refCount. */ + /* referenced in TclOOAllocClass to increment the refCount. */ fakeCls.thisPtr = &fakeObject; - fPtr->objectCls = AllocClass(interp, + fPtr->objectCls = TclOOAllocClass(interp, AllocObject(interp, "object", (Namespace *)fPtr->ooNs, NULL)); /* Corresponding TclOODecrRefCount in KillFoudation */ AddRef(fPtr->objectCls->thisPtr); @@ -470,7 +467,7 @@ InitClassSystemRoots( fPtr->objectCls->thisPtr->flags |= ROOT_OBJECT; fPtr->objectCls->flags |= ROOT_OBJECT; - fPtr->classCls = AllocClass(interp, + fPtr->classCls = TclOOAllocClass(interp, AllocObject(interp, "class", (Namespace *)fPtr->ooNs, NULL)); /* Corresponding TclOODecrRefCount in KillFoudation */ AddRef(fPtr->classCls->thisPtr); @@ -839,15 +836,15 @@ ObjectRenamedTrace( /* * ---------------------------------------------------------------------- * - * DeleteDescendants -- + * TclOODeleteDescendants -- * * Delete all descendants of a particular class. * * ---------------------------------------------------------------------- */ -static void -DeleteDescendants( +void +TclOODeleteDescendants( Tcl_Interp *interp, /* The interpreter containing the class. */ Object *oPtr) /* The object representing the class. */ { @@ -864,7 +861,8 @@ DeleteDescendants( /* This condition also covers the case where mixinSubclassPtr == * clsPtr */ - if (!Deleted(mixinSubclassPtr->thisPtr)) { + if (!Deleted(mixinSubclassPtr->thisPtr) + && !(mixinSubclassPtr->thisPtr->flags & DONT_DELETE)) { Tcl_DeleteCommandFromToken(interp, mixinSubclassPtr->thisPtr->command); } @@ -883,8 +881,10 @@ DeleteDescendants( if (clsPtr->subclasses.num > 0) { while (clsPtr->subclasses.num > 0) { subclassPtr = clsPtr->subclasses.list[clsPtr->subclasses.num-1]; - if (!Deleted(subclassPtr->thisPtr) && !IsRoot(subclassPtr)) { - Tcl_DeleteCommandFromToken(interp, subclassPtr->thisPtr->command); + if (!Deleted(subclassPtr->thisPtr) && !IsRoot(subclassPtr) + && !(subclassPtr->thisPtr->flags & DONT_DELETE)) { + Tcl_DeleteCommandFromToken(interp, + subclassPtr->thisPtr->command); } TclOORemoveFromSubclasses(subclassPtr, clsPtr); } @@ -906,7 +906,8 @@ DeleteDescendants( * This condition also covers the case where instancePtr == oPtr */ - if (!Deleted(instancePtr) && !IsRoot(instancePtr)) { + if (!Deleted(instancePtr) && !IsRoot(instancePtr) && + !(instancePtr->flags & DONT_DELETE)) { Tcl_DeleteCommandFromToken(interp, instancePtr->command); } TclOORemoveFromInstances(instancePtr, clsPtr); @@ -922,7 +923,7 @@ DeleteDescendants( /* * ---------------------------------------------------------------------- * - * ReleaseClassContents -- + * TclOOReleaseClassContents -- * * Tear down the special class data structure, including deleting all * dependent classes and objects. @@ -930,8 +931,8 @@ DeleteDescendants( * ---------------------------------------------------------------------- */ -static void -ReleaseClassContents( +void +TclOOReleaseClassContents( Tcl_Interp *interp, /* The interpreter containing the class. */ Object *oPtr) /* The object representing the class. */ { @@ -954,9 +955,6 @@ ReleaseClassContents( } else if (IsRootObject(oPtr)) { Tcl_Panic("deleting class structure for non-deleted %s", "::oo::object"); - } else { - Tcl_Panic("deleting class structure for non-deleted %s", - "general object"); } } @@ -1059,6 +1057,7 @@ ReleaseClassContents( if (IsRootClass(oPtr) && !Deleted(fPtr->objectCls->thisPtr)) { Tcl_DeleteCommandFromToken(interp, fPtr->objectCls->thisPtr->command); } + oPtr->classPtr = NULL; } /* @@ -1108,7 +1107,7 @@ ObjectNamespaceDeleted( /* Let the dominoes fall */ if (oPtr->classPtr) { - DeleteDescendants(interp, oPtr); + TclOODeleteDescendants(interp, oPtr); } /* @@ -1237,8 +1236,8 @@ ObjectNamespaceDeleted( /* * Because an object can be a class that is an instance of itself, the - * class object's class structure should only be cleaned after most of the - * cleanup on the object is done. + * class object's class structure should only be cleaned after most of + * the cleanup on the object is done. * * The class of objects needs some special care; if it is deleted (and * we're not killing the whole interpreter) we force the delete of the @@ -1253,7 +1252,7 @@ ObjectNamespaceDeleted( } if (oPtr->classPtr != NULL) { - ReleaseClassContents(interp, oPtr); + TclOOReleaseClassContents(interp, oPtr); } /* @@ -1360,6 +1359,37 @@ TclOOAddToInstances( /* * ---------------------------------------------------------------------- * + * TclOORemoveFromMixins -- + * + * Utility function to remove a class from the list of mixins within an + * object. + * + * ---------------------------------------------------------------------- + */ + +int +TclOORemoveFromMixins( + Class *mixinPtr, /* The mixin to remove. */ + Object *oPtr) /* The object (possibly) containing the + * reference to the mixin. */ +{ + int i, res = 0; + Class *mixPtr; + + FOREACH(mixPtr, oPtr->mixins) { + if (mixinPtr == mixPtr) { + RemoveItem(Class, oPtr->mixins, i); + TclOODecrRefCount(mixPtr->thisPtr); + res++; + break; + } + } + return res; +} + +/* + * ---------------------------------------------------------------------- + * * TclOORemoveFromSubclasses -- * * Utility function to remove a class from the list of subclasses within @@ -1489,10 +1519,10 @@ TclOOAddToMixinSubs( /* * ---------------------------------------------------------------------- * - * AllocClass -- + * TclOOAllocClass -- * - * Allocate a basic class. Does not add class to its - * class's instance list. + * Allocate a basic class. Does not add class to its class's instance + * list. * * ---------------------------------------------------------------------- */ @@ -1516,8 +1546,8 @@ InitClassPath( } } -static Class * -AllocClass( +Class * +TclOOAllocClass( Tcl_Interp *interp, /* Interpreter within which to allocate the * class. */ Object *useThisObj) /* Object that is to act as the class @@ -1758,13 +1788,13 @@ TclNewObjectInstanceCommon( if (TclOOIsReachable(fPtr->classCls, classPtr)) { /* - * Is a class, so attach a class structure. Note that the AllocClass - * function splices the structure into the object, so we don't have - * to. Once that's done, we need to repatch the object to have the - * right class since AllocClass interferes with that. + * Is a class, so attach a class structure. Note that the + * TclOOAllocClass function splices the structure into the object, so + * we don't have to. Once that's done, we need to repatch the object + * to have the right class since TclOOAllocClass interferes with that. */ - AllocClass(interp, oPtr); + TclOOAllocClass(interp, oPtr); TclOOAddToSubclasses(oPtr->classPtr, fPtr->objectCls); } else { oPtr->classPtr = NULL; diff --git a/generic/tclOOCall.c b/generic/tclOOCall.c index bc84da0..9d5312c 100644 --- a/generic/tclOOCall.c +++ b/generic/tclOOCall.c @@ -1704,7 +1704,6 @@ AddSimpleClassChainToCallContext( if (flags & CONSTRUCTOR) { AddMethodToCallChain(classPtr->constructorPtr, cbPtr, doneFilters, filterDecl, flags); - } else if (flags & DESTRUCTOR) { AddMethodToCallChain(classPtr->destructorPtr, cbPtr, doneFilters, filterDecl, flags); diff --git a/generic/tclOODefineCmds.c b/generic/tclOODefineCmds.c index 17680a0..b4ff283 100644 --- a/generic/tclOODefineCmds.c +++ b/generic/tclOODefineCmds.c @@ -1375,6 +1375,8 @@ TclOODefineClassObjCmd( { Object *oPtr; Class *clsPtr; + Foundation *fPtr = TclOOGetFoundation(interp); + int wasClass, willBeClass; /* * Parse the context to get the object to operate on. @@ -1410,12 +1412,20 @@ TclOODefineClassObjCmd( if (clsPtr == NULL) { return TCL_ERROR; } - + if (oPtr == clsPtr->thisPtr) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "may not change classes into an instance of themselves", -1)); + Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); + return TCL_ERROR; + } /* * Set the object's class. */ + wasClass = (oPtr->classPtr != NULL); + willBeClass = (TclOOIsReachable(fPtr->classCls, clsPtr)); + if (oPtr->selfCls != clsPtr) { TclOORemoveFromInstances(oPtr, oPtr->selfCls); TclOODecrRefCount(oPtr->selfCls->thisPtr); @@ -1423,6 +1433,26 @@ TclOODefineClassObjCmd( AddRef(oPtr->selfCls->thisPtr); TclOOAddToInstances(oPtr, oPtr->selfCls); + /* + * Create or delete the class guts if necessary. + */ + + if (wasClass && !willBeClass) { + /* + * This is the most global of all epochs. Bump it! No cache can be + * trusted! + */ + + TclOORemoveFromMixins(oPtr->classPtr, oPtr); + oPtr->fPtr->epoch++; + oPtr->flags |= DONT_DELETE; + TclOODeleteDescendants(interp, oPtr); + oPtr->flags &= ~DONT_DELETE; + TclOOReleaseClassContents(interp, oPtr); + } else if (!wasClass && willBeClass) { + TclOOAllocClass(interp, oPtr); + } + if (oPtr->classPtr != NULL) { BumpGlobalEpoch(interp, oPtr->classPtr); } else { diff --git a/generic/tclOOInt.h b/generic/tclOOInt.h index 1f30fed..47e5cf0 100644 --- a/generic/tclOOInt.h +++ b/generic/tclOOInt.h @@ -242,6 +242,10 @@ typedef struct Object { /* Object/class has (or had) private methods, * and so shouldn't be cached so * aggressively. */ +#define DONT_DELETE 0x40000 /* Inhibit deletion of this object. Used + * during fundamental object type mutation to + * make sure that the object actually survives + * to the end of the operation. */ /* * And the definition of a class. Note that every class also has an associated @@ -526,6 +530,8 @@ MODULE_SCOPE int TclOO_Object_VarName(ClientData clientData, MODULE_SCOPE void TclOOAddToInstances(Object *oPtr, Class *clsPtr); MODULE_SCOPE void TclOOAddToMixinSubs(Class *subPtr, Class *mixinPtr); MODULE_SCOPE void TclOOAddToSubclasses(Class *subPtr, Class *superPtr); +MODULE_SCOPE Class * TclOOAllocClass(Tcl_Interp *interp, + Object *useThisObj); MODULE_SCOPE int TclNRNewObjectInstance(Tcl_Interp *interp, Tcl_Class cls, const char *nameStr, const char *nsNameStr, int objc, @@ -540,6 +546,8 @@ MODULE_SCOPE int TclOODefineSlots(Foundation *fPtr); MODULE_SCOPE void TclOODeleteChain(CallChain *callPtr); MODULE_SCOPE void TclOODeleteChainCache(Tcl_HashTable *tablePtr); MODULE_SCOPE void TclOODeleteContext(CallContext *contextPtr); +MODULE_SCOPE void TclOODeleteDescendants(Tcl_Interp *interp, + Object *oPtr); MODULE_SCOPE void TclOODelMethodRef(Method *method); MODULE_SCOPE CallContext *TclOOGetCallContext(Object *oPtr, Tcl_Obj *methodNameObj, int flags, @@ -567,7 +575,10 @@ MODULE_SCOPE int TclNRObjectContextInvokeNext(Tcl_Interp *interp, MODULE_SCOPE void TclOONewBasicMethod(Tcl_Interp *interp, Class *clsPtr, const DeclaredClassMethod *dcm); MODULE_SCOPE Tcl_Obj * TclOOObjectName(Tcl_Interp *interp, Object *oPtr); +MODULE_SCOPE void TclOOReleaseClassContents(Tcl_Interp *interp, + Object *oPtr); MODULE_SCOPE int TclOORemoveFromInstances(Object *oPtr, Class *clsPtr); +MODULE_SCOPE int TclOORemoveFromMixins(Class *mixinPtr, Object *oPtr); MODULE_SCOPE int TclOORemoveFromMixinSubs(Class *subPtr, Class *mixinPtr); MODULE_SCOPE int TclOORemoveFromSubclasses(Class *subPtr, |