Index: generic/predefined.h =================================================================== diff -u -r2252fd2633d5547530210a14fe47ff471b2cdbea -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- generic/predefined.h (.../predefined.h) (revision 2252fd2633d5547530210a14fe47ff471b2cdbea) +++ generic/predefined.h (.../predefined.h) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -161,8 +161,7 @@ "if {![::xotcl::my multivalued]} {\n" "error \"Property $prop of [::xotcl::my domain]->$obj ist not multivalued\"}\n" "$obj $prop [linsert [$obj info $prop -guards] $pos $value]}\n" -"namespace eval ::xotcl::Object::slot {}\n" -"::xotcl::Object alloc ::xotcl::Class::slot\n" +"::xotcl::Object alloc ::xotcl::Class::slot ;# already created through createBootstrapAttributeSlots\n" "::xotcl::Object alloc ::xotcl::Object::slot\n" "::xotcl::InfoSlot create ::xotcl::Class::slot::superclass\n" "::xotcl::alias ::xotcl::Class::slot::superclass assign ::xotcl::relation\n" @@ -404,12 +403,13 @@ "if {[lindex $def 0] eq $origin} {\n" "set def [concat $dest [lrange $def 1 end]]}\n" "$dest trace add variable $var $op $def}}}}\n" -"set origin [lindex [::xotcl::my set targetList] 0]\n" +"foreach origin [::xotcl::my set targetList] {\n" "if {[::xotcl::my isclass $origin]} {\n" +"set dest [::xotcl::my getDest $origin]\n" "foreach oldslot [$origin info slots] {\n" -"set newslot ${cl}::slot::[namespace tail $oldslot]\n" +"set newslot ${dest}::slot::[namespace tail $oldslot]\n" "if {[$oldslot domain] eq $origin} {$newslot domain $cl}\n" -"if {[$oldslot manager] eq $oldslot} {$newslot manager $newslot}}}}\n" +"if {[$oldslot manager] eq $oldslot} {$newslot manager $newslot}}}}}\n" "::xotcl::Object::CopyHandler instproc copy {obj dest} {\n" "::xotcl::my set objLength [string length $obj]\n" "::xotcl::my set dest $dest\n" Index: generic/predefined.xotcl =================================================================== diff -u -r26a70d9d268d8d827ec0ed631549fa6c5217d832 -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- generic/predefined.xotcl (.../predefined.xotcl) (revision 26a70d9d268d8d827ec0ed631549fa6c5217d832) +++ generic/predefined.xotcl (.../predefined.xotcl) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -337,11 +337,8 @@ ###################### # system slots ###################### - #namespace eval ::xotcl::Class::slot {} - namespace eval ::xotcl::Object::slot {} - ::xotcl::Object alloc ::xotcl::Class::slot + ::xotcl::Object alloc ::xotcl::Class::slot ;# already created through createBootstrapAttributeSlots ::xotcl::Object alloc ::xotcl::Object::slot - ::xotcl::InfoSlot create ::xotcl::Class::slot::superclass ::xotcl::alias ::xotcl::Class::slot::superclass assign ::xotcl::relation ::xotcl::InfoSlot create ::xotcl::Object::slot::class @@ -699,7 +696,7 @@ } ::xotcl::Object::CopyHandler instproc copyTargets {} { - #puts stderr "copy targetList = [::xotcl::my set targetList]" + #puts stderr "COPY will copy targetList = [::xotcl::my set targetList]" foreach origin [::xotcl::my set targetList] { set dest [::xotcl::my getDest $origin] if {[::xotcl::my isobject $origin]} { @@ -713,7 +710,7 @@ $cl instinvar [$origin info instinvar] $cl instfilter [$origin info instfilter -guards] $cl instmixin [$origin info instmixin] - my copyNSVarsAndCmds ::xotcl::classes$origin ::xotcl::classes$dest + my copyNSVarsAndCmds ::xotcl::classes$origin ::xotcl::classes$dest #$cl parameter [$origin info parameter] } else { # create obj @@ -748,22 +745,25 @@ if {$cmds ne ""} { foreach cmd $cmds { foreach {op def} $cmd break - #$origin trace remove variable $var $op $def + #$origin trace remove variable $var $op $def if {[lindex $def 0] eq $origin} { set def [concat $dest [lrange $def 1 end]] } $dest trace add variable $var $op $def } } } + #puts stderr "=====" } - # alter 'domain' and 'manager' in slot objects - set origin [lindex [::xotcl::my set targetList] 0] - if {[::xotcl::my isclass $origin]} { - foreach oldslot [$origin info slots] { - set newslot ${cl}::slot::[namespace tail $oldslot] - if {[$oldslot domain] eq $origin} {$newslot domain $cl} - if {[$oldslot manager] eq $oldslot} {$newslot manager $newslot} + # alter 'domain' and 'manager' in slot objects for classes + foreach origin [::xotcl::my set targetList] { + if {[::xotcl::my isclass $origin]} { + set dest [::xotcl::my getDest $origin] + foreach oldslot [$origin info slots] { + set newslot ${dest}::slot::[namespace tail $oldslot] + if {[$oldslot domain] eq $origin} {$newslot domain $cl} + if {[$oldslot manager] eq $oldslot} {$newslot manager $newslot} + } } } } Index: generic/xotcl.c =================================================================== diff -u -r5ec6a6f960964d861d68c052d8e2e7d68b711449 -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- generic/xotcl.c (.../xotcl.c) (revision 5ec6a6f960964d861d68c052d8e2e7d68b711449) +++ generic/xotcl.c (.../xotcl.c) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -808,7 +808,7 @@ if (obj->refCount <= 0) { assert(obj->refCount == 0); - assert(obj->flags & XOTCL_DESTROYED); + assert(obj->flags & XOTCL_DELETED); MEM_COUNT_FREE("XOTclObject/XOTclClass", obj); #if defined(XOTCLOBJ_TRACE) @@ -940,7 +940,7 @@ /* Here we use GetCommandName, because it doesnt need Interp*, but Tcl_GetCommandFullName(interp, obj->id, ObjName); does*/ - if (obj && !(obj->flags & XOTCL_DESTROY_CALLED)) { + if (obj && !(obj->flags & XOTCL_DURING_DELETE)) { Tcl_DString ds, *dsp = &ds; unsigned l; DSTRING_INIT(dsp); @@ -972,27 +972,13 @@ */ } -#ifdef NOTUSED static Tcl_Obj * -NewXOTclObjectObj(register XOTclObject *obj) { - register Tcl_Obj *objPtr; - - XOTclNewObj(objPtr); - objPtr->bytes = NULL; - objPtr->internalRep.otherValuePtr = obj; - objPtr->typePtr = &XOTclObjectType; -#ifdef XOTCLOBJ_TRACE - fprintf(stderr,"NewXOTclObjectObj %p\n", objPtr); -#endif - return objPtr; -} -#endif - -static Tcl_Obj * NewXOTclObjectObjName(register XOTclObject *obj, char *name, unsigned l) { register Tcl_Obj *objPtr; + fprintf(stderr,"NewXOTclObjectObjName %s\n",name); + XOTclNewObj(objPtr); objPtr->length = l; objPtr->bytes = ckalloc(l+1); @@ -1035,7 +1021,7 @@ if (cmdType == &XOTclObjectType) { o = (XOTclObject*) objPtr->internalRep.otherValuePtr; - if (!(o->flags & XOTCL_DESTROYED)) { + if (!(o->flags & XOTCL_DELETED)) { *obj = o; return TCL_OK; } @@ -1100,14 +1086,14 @@ if (obj) { XOTclObject *o = (XOTclObject*) objPtr->internalRep.otherValuePtr; int refetch = 0; - if (o->flags & XOTCL_DESTROYED) { + if (o->flags & XOTCL_DELETED) { /* fprintf(stderr,"????? calling free by hand\n"); */ FreeXOTclObjectInternalRep(objPtr); refetch = 1; result = SetXOTclObjectFromAny(interp, objPtr); if (result == TCL_OK) { o = (XOTclObject*) objPtr->internalRep.otherValuePtr; - assert(o && !(o->flags & XOTCL_DESTROYED)); + assert(o && !(o->flags & XOTCL_DELETED)); } } else { result = TCL_OK; @@ -1549,6 +1535,7 @@ /* we don't call destroy, if we're in the exit handler during destruction of Object and Class */ if (!RUNTIME_STATE(interp)->callDestroy) { + /*fprintf(stderr, " callDestroyMethod sets XOTCL_DESTROY_CALLED for %p %.6x\n",obj,obj->flags); TODO flags*/ obj->flags |= XOTCL_DESTROY_CALLED; /* return TCL_ERROR so that clients know we haven't deleted the associated command yet */ @@ -1569,11 +1556,12 @@ } #endif - #ifdef OBJDELETION_TRACE - fprintf(stderr, " command found\n"); PRINTOBJ("callDestroy", obj); + fprintf(stderr, " callDestroy sets destroy_called_flag\n"); #endif + /*fprintf(stderr, " callDestroyMethod 2 sets XOTCL_DESTROY_CALLED for %p %.6x\n",obj,obj->flags); todo flags*/ + obj->flags |= XOTCL_DESTROY_CALLED; result = callMethod(clientData, interp, XOTclGlobalObjects[XOTE_DESTROY], 2, 0, flags); if (result != TCL_OK) { static char cmd[] = @@ -1797,12 +1785,10 @@ return -1; } -static void -CallStackDestroyObject(Tcl_Interp *interp, XOTclObject *obj); -static void -PrimitiveCDestroy(ClientData clientData); -static void -PrimitiveODestroy(ClientData clientData); +static void CallStackDestroyObject(Tcl_Interp *interp, XOTclObject *obj); +static void PrimitiveCDestroy(ClientData clientData); +static void PrimitiveODestroy(ClientData clientData); +static void PrimitiveDestroy(ClientData clientData); static void NSDeleteChildren(Tcl_Interp *interp, Tcl_Namespace *ns) { @@ -1834,13 +1820,9 @@ /* in the exit handler physical destroy --> directly call destroy */ if (RUNTIME_STATE(interp)->exitHandlerDestroyRound == XOTCL_EXITHANDLER_ON_PHYSICAL_DESTROY) { - if (XOTclObjectIsClass(obj)) - PrimitiveCDestroy((ClientData) obj); - else - PrimitiveODestroy((ClientData) obj); + PrimitiveDestroy((ClientData) obj); } else { - if (obj->teardown && obj->id && - !(obj->flags & XOTCL_DESTROY_CALLED)) { + if (obj->teardown && !(obj->flags & XOTCL_DESTROY_CALLED)) { if (callDestroyMethod((ClientData)obj, interp, obj, 0) != TCL_OK) { /* destroy method failed, but we have to remove the command @@ -1894,7 +1876,7 @@ Tcl_Command cmd; #ifdef OBJDELETION_TRACE - fprintf(stderr, "NSCleanupNamespace %p\n", ns); + fprintf(stderr, "NSCleanupNamespace %p varTable %p\n", ns, varTable); #endif /* * Delete all variables and initialize var table again @@ -2344,42 +2326,48 @@ Tcl_Command oid; PRINTOBJ("CallStackDoDestroy", obj); + + if (obj->flags & XOTCL_DURING_DELETE) { + /* fprintf(stderr, " CallStackDoDestroy already XOTCL_DURING_DELETE for %p %.6x\n",obj,obj->flags);*/ + return; + } + oid = obj->id; - obj->id = NULL; + /* fprintf(stderr, " CallStackDoDestroy sets XOTCL_DURING_DELETE for %p %.6x\n",obj,obj->flags); TODO check*/ + obj->flags |= XOTCL_DURING_DELETE; if (obj->teardown && oid) { Tcl_Obj *savedObjResult = Tcl_GetObjResult(interp); INCR_REF_COUNT(savedObjResult); + PrimitiveDestroy((ClientData) obj); + + /*fprintf(stderr, " before DeleteCommandFromToken %p %.6x\n",oid,((Command*)oid)->flags);*/ Tcl_DeleteCommandFromToken(interp, oid); /* this can change the result */ -#if !defined(OLD_DELETE) - if (XOTclObjectIsClass(obj)) - PrimitiveCDestroy((ClientData) obj); - else - PrimitiveODestroy((ClientData) obj); -#endif + /*fprintf(stderr, " after DeleteCommandFromToken %p %.6x\n",oid,((Command*)oid)->flags);*/ + Tcl_SetObjResult(interp, savedObjResult); DECR_REF_COUNT(savedObjResult); } } static void CallStackDestroyObject(Tcl_Interp *interp, XOTclObject *obj) { - int marked = CallStackMarkDestroyed(interp, obj); + if ((obj->flags & XOTCL_DESTROY_CALLED) == 0) { + /* if the destroy method was not called yet, do it now */ #ifdef OBJDELETION_TRACE - fprintf(stderr, " CallStackDestroyObject %s marked %d\n", objectName(obj), marked); + fprintf(stderr, " CallStackDestroyObject has to call destroy method for %p\n",obj); #endif + callDestroyMethod((ClientData)obj, interp, obj, 0); + /*fprintf(stderr, " CallStackDestroyObject after callDestroyMethod %p\n",obj);*/ + } - obj->flags |= XOTCL_DESTROY_CALLED; - /* if the object is not referenced on the callstack anymore we have to destroy it directly, because CallStackPop won't find the object destroy */ - if (marked == 0) { - /*fprintf(stderr,"direct destroy %p\n", obj);*/ + if (obj->activationCount == 0) { CallStackDoDestroy(interp, obj); } else { - /*fprintf(stderr,"selfcount for %p = %d\n", obj, marked);*/ /* to prevail the deletion order call delete children now -> children destructors are called before parent's destructor */ @@ -2998,7 +2986,6 @@ *checker, *guardChecker; if (obj->mixinOrder) MixinResetOrder(obj); - /*fprintf(stderr, "Mixin Order:\n First List: ");*/ /* append per-obj mixins */ if (obj->opt) { @@ -3507,7 +3494,7 @@ for (; hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { XOTclObject *obj = (XOTclObject *)Tcl_GetHashKey(&cl->instances, hPtr); if (obj - && !(obj->flags & XOTCL_DESTROY_CALLED) + && !(obj->flags & XOTCL_DURING_DELETE) && (obj->flags & XOTCL_MIXIN_ORDER_DEFINED_AND_VALID)) { MixinResetOrder(obj); obj->flags &= ~XOTCL_MIXIN_ORDER_VALID; @@ -5017,8 +5004,11 @@ */ #if defined(TCL85STACK_TRACE) - fprintf(stderr,"PUSH METHOD_FRAME (PushProcCallFrame) frame %p csc %p %s\n", framePtr,csc, - csc ? Tcl_GetCommandName(interp, csc->cmdPtr) : NULL); + fprintf(stderr,"PUSH METHOD_FRAME (PushProcCallFrame) csc %p %s obj %s obj refcount %d\n",csc, + csc ? Tcl_GetCommandName(interp, csc->cmdPtr) : NULL, + objectName(csc->self), + csc && csc->self->id ? Tcl_Command_refCount(csc->self->id) : -100 + ); #endif /* TODO: we could use Tcl_PushCallFrame(), if we would allocate the tcl stack frame earlier */ result = TclPushStackFrame(interp, (Tcl_CallFrame **)&framePtr, @@ -5127,7 +5117,6 @@ invokeProcMethod(ClientData cp, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], char *methodName, XOTclObject *obj, XOTclClass *cl, Tcl_Command cmdPtr, XOTclCallStackContent *csc) { - XOTclRuntimeState *rst = RUNTIME_STATE(interp); int result; XOTclObjectOpt *opt = obj->opt; #if defined(PRE85) @@ -5137,11 +5126,9 @@ assert(obj); assert(!obj->teardown); - rst->callIsDestroy = 0; - #if defined(TCL85STACK_TRACE) - fprintf(stderr, "+++ invokeProcMethod %s, isTclProc %d csc %p, frametype %d, teardown %p\n", - methodName, isTclProc, csc, csc->frameType, obj->teardown); + fprintf(stderr, "+++ invokeProcMethod %s, csc %p, frametype %d, teardown %p\n", + methodName, csc, csc->frameType, obj->teardown); #endif /* @@ -5172,13 +5159,13 @@ * we may not be in a method, thus there may be wrong or * no callstackobjs */ - /*fprintf(stderr, "... calling nextmethod csc %p\n", csc); XOTclCallStackDump(interp);*/ + /*fprintf(stderr, "... calling nextmethod csc %p\n", csc); */ /* the call stack content is not jet pushed to the tcl stack, so we pass it here explicitely */ rc = XOTclNextMethod(obj, interp, cl, methodName, objc, objv, /*useCallStackObjs*/ 0, csc); - /*fprintf(stderr, "... after nextmethod\n"); XOTclCallStackDump(interp);*/ + /*fprintf(stderr, "... after nextmethod\n");*/ } return rc; @@ -5255,14 +5242,18 @@ */ if (result == TCL_OK) { #if !defined(TCL85STACK) - rst->cs.top->currentFramePtr = (Tcl_CallFrame *) Tcl_Interp_varFramePtr(interp); + RUNTIME_STATE(interp)->cs.top->currentFramePtr = (Tcl_CallFrame *) Tcl_Interp_varFramePtr(interp); #endif result = TclObjInterpProcCore(interp, objv[0], 1, &MakeProcError); } else { result = TCL_ERROR; } # if defined(TCL85STACK_TRACE) - fprintf(stderr,"POP OBJECT_FRAME (implicit) frame %p csc %p\n", NULL, csc); + fprintf(stderr,"POP OBJECT_FRAME (implicit) frame %p csc %p obj %s obj refcount %d %d\n", NULL, csc, + objectName(obj), + obj->id ? Tcl_Command_refCount(obj->id) : -100, + obj->refCount + ); # endif #else /* BEFORE TCL85 */ result = (*Tcl_Command_objProc(cmdPtr))(cp, interp, objc, objv); @@ -5276,16 +5267,8 @@ /* fprintf(stderr, "dispatch returned %d rst = %d\n", result, rst->returnCode);*/ - /* we give the information whether the call has destroyed the - object back to the caller via the runtime state, because after CallStackPop it - cannot be retrieved via the call stack */ - if (csc->callType & XOTCL_CSC_CALL_IS_DESTROY) { - rst->callIsDestroy = 1; - /*fprintf(stderr,"invokeProcMethod: setting callIsDestroy = 1 method = %s\n", - methodName);*/ - } - - if (opt && !rst->callIsDestroy && obj->teardown && + opt = obj->opt; + if (opt && obj->teardown && (opt->checkoptions & CHECK_POST)) { result = AssertionCheck(interp, obj, cl, methodName, CHECK_POST); } @@ -5299,7 +5282,6 @@ invokeCmdMethod(ClientData cp, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], char *methodName, XOTclObject *obj, Tcl_Command cmdPtr, XOTclCallStackContent *csc) { - XOTclRuntimeState *rst = RUNTIME_STATE(interp); CheckOptions co; int result; #if defined(TCL85STACK) @@ -5309,11 +5291,9 @@ assert(obj); assert(!obj->teardown); - rst->callIsDestroy = 0; - #if defined(TCL85STACK_TRACE) - fprintf(stderr, "+++ invokeCmdMethodCheck %s, isTclProc %d csc %p, teardown %p\n", - methodName, isTclProc, csc, obj->teardown); + fprintf(stderr, "+++ invokeCmdMethodCheck %s, obj %p %s, csc %p, teardown %p\n", + methodName, obj, objectName(obj), csc, obj->teardown); #endif /*fprintf(stderr,".. calling cmd %s isTclProc %d tearDown %p csc %p\n",methodName,isTclProc,obj->teardown,csc);*/ @@ -5346,8 +5326,6 @@ result = (*Tcl_Command_objProc(cmdPtr))(cp, interp, objc, objv); #ifdef DISPATCH_TRACE printExit(interp,"invokeCmdMethod cmd", objc, objv, result); - /*fprintf(stderr, " returnCode %d xotcl rc %d\n", - Tcl_Interp_returnCode(interp), rst->returnCode);*/ #endif #if defined(TCL85STACK) @@ -5358,7 +5336,7 @@ /* The order of the if-condition below is important, since obj might be already freed in case the call was a "dealloc" */ - if (!rst->callIsDestroy && obj->opt) { + if (obj->opt) { co = obj->opt->checkoptions; if ((co & CHECK_INVAR) && ((result = AssertionCheckInvars(interp, obj, methodName, co)) == TCL_ERROR)) { @@ -5377,13 +5355,9 @@ char *methodName, int frameType) { struct timeval trt; long int startUsec = (gettimeofday(&trt, NULL), trt.tv_usec), startSec = trt.tv_sec; - XOTclRuntimeState *rst = RUNTIME_STATE(interp); result = __InvokeMethod__(clientData, interp, objc, objv, cmd, obj, cl, methodName, frameType); - - if (rst->callIsDestroy == 0) { - XOTclProfileEvaluateData(interp, startSec, startUsec, obj, cl, methodName); - } + XOTclProfileEvaluateData(interp, startSec, startUsec, obj, cl, methodName); return result; } # define InvokeMethod __InvokeMethod__ @@ -5486,18 +5460,6 @@ printCall(interp,"DISPATCH", objc, objv); #endif -#ifdef OBJDELETION_TRACE - { - Tcl_Obj *method = objv[1]; - if (method == XOTclGlobalObjects[XOTE_CLEANUP] || - method == XOTclGlobalObjects[XOTE_DESTROY]) { - fprintf(stderr, "%s->%s id=%p destroyCalled=%d\n", - ObjStr(cmdName), methodName, obj, - (obj->flags & XOTCL_DESTROY_CALLED)); - } - } -#endif - objflags = obj->flags; /* avoid stalling */ INCR_REF_COUNT(cmdName); @@ -5662,31 +5624,15 @@ #ifdef DISPATCH_TRACE printExit(interp,"DISPATCH", objc, objv, result); - fprintf(stderr,"obj=%p isDestroy %d\n",obj, rst->callIsDestroy); - if (!rst->callIsDestroy) { - fprintf(stderr,"obj %p mixinStackPushed %d mixinStack %p\n", - obj, mixinStackPushed, obj->mixinStack); - } #endif + /*!(obj->flags & XOTCL_DESTROY_CALLED)) */ + if (mixinStackPushed && obj->mixinStack) + MixinStackPop(obj); - /*if (!rst->callIsDestroy) - fprintf(stderr, "obj freed? %p destroy %p self %p %s %d [%d] reference=%d,%d\n", obj, - cs->top->destroyedCmd, cs->top->self, ObjStr(objv[1]), - rst->callIsDestroy, - cs->top->callType & XOTCL_CSC_CALL_IS_DESTROY, - !rst->callIsDestroy, - isdestroy);*/ + if (filterStackPushed && obj->filterStack) + FilterStackPop(obj); - if (!rst->callIsDestroy) { - /*!(obj->flags & XOTCL_DESTROY_CALLED)) {*/ - if (mixinStackPushed && obj->mixinStack) - MixinStackPop(obj); - - if (filterStackPushed && obj->filterStack) - FilterStackPop(obj); - } - DECR_REF_COUNT(cmdName); /* must be after last dereferencing of obj */ return result; } @@ -7349,25 +7295,29 @@ } static void -tclDeletesObject(ClientData clientData) { +PrimitiveDestroy(ClientData clientData) { XOTclObject *obj = (XOTclObject*)clientData; - Tcl_Interp *interp; -#if defined(OLD_DELETE) + if (XOTclObjectIsClass(obj)) PrimitiveCDestroy((ClientData) obj); else PrimitiveODestroy((ClientData) obj); -#else -# ifdef OBJDELETION_TRACE - fprintf(stderr,"tclDeletesObject %p\n",obj); -# endif - if (!obj || !obj->teardown) return; +} + +static void +tclDeletesObject(ClientData clientData) { + XOTclObject *obj = (XOTclObject*)clientData; + Tcl_Interp *interp; + +#ifdef OBJDELETION_TRACE + fprintf(stderr,"tclDeletesObject %p obj->id %p\n",obj, obj->id); +#endif + if ((obj->flags & XOTCL_DURING_DELETE) || !obj->teardown) return; interp = obj->teardown; # ifdef OBJDELETION_TRACE fprintf(stderr,"... %p %s\n",obj,objectName(obj)); # endif CallStackDestroyObject(interp,obj); -#endif } /* @@ -7379,7 +7329,7 @@ Tcl_Interp *interp; /* fprintf(stderr, "****** PrimitiveODestroy %p\n", obj);*/ - assert(obj && !(obj->flags & XOTCL_DESTROYED)); + assert(obj && !(obj->flags & XOTCL_DELETED)); /* * check and latch against recurrent calls with obj->teardown @@ -7398,15 +7348,15 @@ * call and latch user destroy with obj->id if we haven't */ if (!(obj->flags & XOTCL_DESTROY_CALLED)) { + fprintf(stderr, "--- final chance to call destroy ******* NEVER CALLED\n"); callDestroyMethod(clientData, interp, obj, 0); - obj->id = NULL; + /*obj->id = NULL;*/ } #ifdef OBJDELETION_TRACE fprintf(stderr," physical delete of %p id=%p destroyCalled=%d '%s'\n", obj, obj->id, (obj->flags & XOTCL_DESTROY_CALLED), objectName(obj)); #endif - CleanupDestroyObject(interp, obj, 0); while (obj->mixinStack) @@ -7417,20 +7367,6 @@ obj->teardown = NULL; -#if 0 - { - /* Prevent that PrimitiveODestroy is called more than once. - This code was used in earlier versions of XOTcl - but does not seem necessary any more. If it has to be used - again in the future, don't use Tcl_GetCommandFromObj() - in Tcl 8.4.* versions. - */ - Tcl_Command cmd = Tcl_FindCommand(interp, objectName(obj), 0, 0); - if (cmd) - Tcl_Command_deleteProc(cmd) = NULL; - } -#endif - if (obj->nsPtr) { /*fprintf(stderr,"primitive odestroy calls deletenamespace for obj %p\n", obj);*/ XOTcl_DeleteNamespace(interp, obj->nsPtr); @@ -7439,7 +7375,7 @@ /*fprintf(stderr, " +++ OBJ/CLS free: %s\n", objectName(obj));*/ - obj->flags |= XOTCL_DESTROYED; + obj->flags |= XOTCL_DELETED; objTrace("ODestroy", obj); DECR_REF_COUNT(obj->cmdName); @@ -7451,7 +7387,15 @@ #endif } +/* + * reset the object to a fresh, undestroyed state + */ static void +MarkUndestroyed(XOTclObject *obj) { + obj->flags &= ~XOTCL_DESTROY_CALLED; +} + +static void PrimitiveOInit(void *mem, Tcl_Interp *interp, char *name, XOTclClass *cl) { XOTclObject *obj = (XOTclObject*)mem; Tcl_Namespace *nsPtr = NULL; @@ -7464,12 +7408,8 @@ fprintf(stderr, "OINIT %s = %p\n", name, obj); #endif XOTclObjectRefCountIncr(obj); + MarkUndestroyed(obj); - /* if the command of the obj was used before, we have to clean - * up the callstack from set "destroyedCmd" flags - */ - CallStackMarkUndestroyed(interp, obj); - if (Tcl_FindNamespace(interp, name, NULL, 0)) { nsPtr = NSGetFreshNamespace(interp, (ClientData)obj, name); } @@ -7510,7 +7450,6 @@ PrimitiveOInit(obj, interp, name, cl); #if defined(KEEP_TCL_CMD_TYPE) - /*defined(KEEP_TCL_CMD_TYPE)*/ obj->cmdName = Tcl_NewStringObj(name, length); Tcl_GetCommandFromObj(interp,obj->cmdName); /*TclSetCmdNameObj(interp, obj->cmdName, (Command*)obj->id);*/ @@ -7600,6 +7539,7 @@ XOTclClassOpt *clopt = cl->opt; XOTclClass *defaultClass = NULL; + PRINTOBJ("CleanupDestroyClass", (XOTclObject *)cl); assert(softrecreate? recreate == 1 : 1); /*fprintf(stderr, "CleanupDestroyClass softrecreate=%d,recreate=%d, %p\n", @@ -7651,6 +7591,8 @@ NSCleanupNamespace(interp, cl->nsPtr); NSDeleteChildren(interp, cl->nsPtr); + /*fprintf(stderr, " CleanupDestroyClass softrecreate %d\n",softrecreate);*/ + if (!softrecreate) { defaultClass = DefaultSuperClass(interp, cl, cl->object.cl, 0); @@ -7669,24 +7611,13 @@ DefaultSuperClass(interp, cl, cl->object.cl, 1) : defaultClass; -#if 0 - if (baseClass == cl) { - XOTclClass *theobj = RUNTIME_STATE(interp)->theObject; + /*fprintf(stderr," baseclass = %s\n",className(baseClass));*/ - /* During final cleanup, we delete ::xotcl::Class; there are - no more Classes or user objects available at that time, so - we reclass to ::xotcl::Object. - */ - baseClass = theobj; - } -#endif - - /* fprintf(stderr,"baseclass = %s\n",className(baseClass));*/ - hPtr = &cl->instances ? Tcl_FirstHashEntry(&cl->instances, &hSrch) : 0; for (; hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { XOTclObject *inst = (XOTclObject*)Tcl_GetHashKey(&cl->instances, hPtr); - if (inst && inst != (XOTclObject*)cl && inst->id) { + /*fprintf(stderr, " inst %p %s flags %.6x id %p\n",inst,objectName(inst),inst->flags,inst->id);*/ + if (inst && inst != (XOTclObject*)cl && !(inst->flags & XOTCL_DURING_DELETE) /*inst->id*/) { if (inst != &(baseClass->object)) { (void)RemoveInstance(inst, cl->object.cl); AddInstance(inst, baseClass); @@ -7806,6 +7737,8 @@ Tcl_Interp *interp; Tcl_Namespace *saved; + PRINTOBJ("PrimitiveCDestroy", obj); + /* * check and latch against recurrent calls with obj->teardown */ @@ -7824,7 +7757,7 @@ /*fprintf(stderr,"PrimitiveCDestroy %s flags %x\n", objectName(obj), obj->flags);*/ if (!(obj->flags & XOTCL_DESTROY_CALLED)) - /*fprintf(stderr,"PrimitiveCDestroy call destroy\n");*/ + fprintf(stderr,"???? PrimitiveCDestroy call destroy\n"); callDestroyMethod(clientData, interp, obj, 0); obj->teardown = 0; @@ -7906,7 +7839,15 @@ PrimitiveOInit(obj, interp, name, class); +#if defined(KEEP_TCL_CMD_TYPE) + obj->cmdName = Tcl_NewStringObj(name, length); + Tcl_GetCommandFromObj(interp,obj->cmdName); + /*TclSetCmdNameObj(interp, obj->cmdName, (Command*)obj->id);*/ + /*fprintf(stderr, "new command has name '%s'\n", objectName(obj));*/ +#else obj->cmdName = NewXOTclObjectObjName(obj, name, length); +#endif + INCR_REF_COUNT(obj->cmdName); PrimitiveCInit(cl, interp, name+2); @@ -7966,22 +7907,17 @@ static int doCleanup(Tcl_Interp *interp, XOTclObject *newObj, XOTclObject *classobj, int objc, Tcl_Obj *CONST objv[]) { - XOTclCallStackContent *csc; int result; /* - * Check whether the object to be re-created is already marked on - * the stack as destroyed. + * Check whether we have a pending destroy on the object; if yes, clear it, + * such that the recreated object and won't be destroyed on a POP */ - csc = CallStackGetObjectFrame(interp, newObj); - if (csc && csc->destroyedCmd != NULL) { - CallStackMarkUndestroyed(interp, newObj); - } + MarkUndestroyed(newObj); /* * re-create, first ensure correct class for newObj */ - result = changeClass(interp, newObj, (XOTclClass*) classobj); if (result == TCL_OK) { @@ -9571,7 +9507,7 @@ XOTcl_PushFrame(interp, obj); if ((childobj = XOTclpGetObject(interp, pattern)) && (!classesOnly || XOTclObjectIsClass(childobj)) && - (childobj->id && Tcl_Command_nsPtr(childobj->id) == obj->nsPtr) /* true children */ + (Tcl_Command_nsPtr(childobj->id) == obj->nsPtr) /* true children */ ) { Tcl_SetObjResult(interp, childobj->cmdName); } else { @@ -9589,7 +9525,7 @@ if (!pattern || Tcl_StringMatch(key, pattern)) { if ((childobj = XOTclpGetObject(interp, key)) && (!classesOnly || XOTclObjectIsClass(childobj)) && - (childobj->id && Tcl_Command_nsPtr(childobj->id) == obj->nsPtr) /* true children */ + (Tcl_Command_nsPtr(childobj->id) == obj->nsPtr) /* true children */ ) { Tcl_ListObjAppendElement(interp, list, childobj->cmdName); } @@ -10383,9 +10319,20 @@ static int XOTclODestroyMethod(Tcl_Interp *interp, XOTclObject *obj) { PRINTOBJ("XOTclODestroyMethod", obj); - return XOTclCallMethodWithArgs((ClientData)obj->cl, interp, - XOTclGlobalObjects[XOTE_DEALLOC], obj->cmdName, - 1, NULL, 0); + if (!(obj->flags & XOTCL_DESTROY_CALLED)) { + /*fprintf(stderr, " Object->destroy sets XOTCL_DESTROY_CALLED flag for %p %.6x\n", obj, obj->flags); todo flags*/ + obj->flags |= XOTCL_DESTROY_CALLED; + } + if (!(obj->flags & XOTCL_DURING_DELETE)) { + return XOTclCallMethodWithArgs((ClientData)obj->cl, interp, + XOTclGlobalObjects[XOTE_DEALLOC], obj->cmdName, + 1, NULL, 0); + } else { +#if defined(OBJDELETION_TRACE) + fprintf(stderr, " Object->destroy already during delete, don't call dealloc %p\n", obj); +#endif + return TCL_OK; + } } static int XOTclOExistsMethod(Tcl_Interp *interp, XOTclObject *obj, char *var) { @@ -11012,6 +10959,8 @@ XOTclObject *delobj; int rc; + /*fprintf(stderr," dealloc %s\n",ObjStr(object));*/ + if (XOTclObjConvertObject(interp, object, &delobj) != TCL_OK) return XOTclVarErrMsg(interp, "Can't destroy object ", ObjStr(object), " that does not exist.", @@ -11027,11 +10976,11 @@ * latch, and call delete command if not already in progress */ /*delobj->flags |= XOTCL_DESTROY_CALLED;*/ - RUNTIME_STATE(interp)->callIsDestroy = 1; - /*fprintf(stderr,"dealloc %s : setting callIsDestroy = 1\n", ObjStr(object);*/ + if (RUNTIME_STATE(interp)->exitHandlerDestroyRound != XOTCL_EXITHANDLER_ON_SOFT_DESTROY) { CallStackDestroyObject(interp, delobj); + /*Tcl_DeleteCommandFromToken(interp, delobj->id);*/ } return TCL_OK; Index: generic/xotcl.h =================================================================== diff -u -r5ec6a6f960964d861d68c052d8e2e7d68b711449 -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- generic/xotcl.h (.../xotcl.h) (revision 5ec6a6f960964d861d68c052d8e2e7d68b711449) +++ generic/xotcl.h (.../xotcl.h) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -82,19 +82,16 @@ #define PARSE_TRACE_FULL 1 */ +/*#define OBJDELETION_TRACE 1*/ /* -#define OBJDELETION_TRACE 1 -*/ -#define OLD_DELETE -/* #define TCL85STACK_TRACE 1 #define TCL85STACK 1 #define CANONICAL_ARGS 1 */ #define CANONICAL_ARGS 1 #define TCL85STACK 1 -#if defined PARSE_TRACE_FULL +#if defined(PARSE_TRACE_FULL) # define PARSE_TRACE 1 #endif Index: generic/xotclError.c =================================================================== diff -u -r072e1c7c091c1370fc2fe26f66acf7a7cbd4a66f -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- generic/xotclError.c (.../xotclError.c) (revision 072e1c7c091c1370fc2fe26f66acf7a7cbd4a66f) +++ generic/xotclError.c (.../xotclError.c) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -41,26 +41,26 @@ int -XOTclErrInProc (Tcl_Interp *interp, Tcl_Obj *objName, - Tcl_Obj *clName, char *procName) { - Tcl_DString errMsg; - char *cName, *space; - ALLOC_DSTRING(&errMsg, "\n "); - if (clName) { - cName = ObjStr(clName); - space = " "; - } else { - cName = ""; - space =""; - } - Tcl_DStringAppend(&errMsg, ObjStr(objName),-1); - Tcl_DStringAppend(&errMsg, space, -1); - Tcl_DStringAppend(&errMsg, cName, -1); - Tcl_DStringAppend(&errMsg, "->", 2); - Tcl_DStringAppend(&errMsg, procName, -1); - Tcl_AddErrorInfo (interp, Tcl_DStringValue(&errMsg)); - DSTRING_FREE(&errMsg); - return TCL_ERROR; +XOTclErrInProc(Tcl_Interp *interp, Tcl_Obj *objName, + Tcl_Obj *clName, char *procName) { + Tcl_DString errMsg; + char *cName, *space; + ALLOC_DSTRING(&errMsg, "\n "); + if (clName) { + cName = ObjStr(clName); + space = " "; + } else { + cName = ""; + space =""; + } + Tcl_DStringAppend(&errMsg, ObjStr(objName),-1); + Tcl_DStringAppend(&errMsg, space, -1); + Tcl_DStringAppend(&errMsg, cName, -1); + Tcl_DStringAppend(&errMsg, "->", 2); + Tcl_DStringAppend(&errMsg, procName, -1); + Tcl_AddErrorInfo (interp, Tcl_DStringValue(&errMsg)); + DSTRING_FREE(&errMsg); + return TCL_ERROR; } int Index: generic/xotclInt.h =================================================================== diff -u -r5ec6a6f960964d861d68c052d8e2e7d68b711449 -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- generic/xotclInt.h (.../xotclInt.h) (revision 5ec6a6f960964d861d68c052d8e2e7d68b711449) +++ generic/xotclInt.h (.../xotclInt.h) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -304,8 +304,9 @@ #ifdef OBJDELETION_TRACE # define PRINTOBJ(ctx,obj) \ fprintf(stderr, " %s %p %s oid=%p teardown=%p destroyCalled=%d\n", \ - ctx,obj,ObjStr(obj->cmdName), obj->id, obj->teardown, \ - (obj->flags & XOTCL_DESTROY_CALLED)) + ctx,obj,(obj)->teardown?ObjStr((obj)->cmdName):"(deleted)", \ + (obj)->id, (obj)->teardown, \ + ((obj)->flags & XOTCL_DESTROY_CALLED)) #else # define PRINTOBJ(ctx,obj) #endif @@ -418,9 +419,11 @@ #define XOTCL_IS_ROOT_META_CLASS 0x0080 #define XOTCL_IS_ROOT_CLASS 0x0100 /* DESTROYED set, when object is physically destroyed with PrimitiveODestroy */ -#define XOTCL_DESTROYED 0x1000 -#define XOTCL_RECREATE 0x4000 -#define XOTCL_NS_DESTROYED 0x8000 +#define XOTCL_MUST_DELETE 0x1000 +#define XOTCL_DURING_DELETE 0x2000 +#define XOTCL_DELETED 0x4000 +#define XOTCL_RECREATE 0x8000 +#define XOTCL_NS_DESTROYED 0xc000 #define XOTclObjectSetClass(obj) \ (obj)->flags |= XOTCL_IS_CLASS @@ -484,6 +487,7 @@ XOTclMixinStack *mixinStack; int refCount; short flags; + short activationCount; } XOTclObject; typedef struct XOTclObjects { @@ -586,7 +590,6 @@ XOTclObject *self; XOTclClass *cl; Tcl_Command cmdPtr; - Tcl_Command destroyedCmd; #if !defined(TCL85STACK) Tcl_CallFrame *currentFramePtr; #endif @@ -604,8 +607,7 @@ #define XOTCL_CSC_TYPE_GUARD 16 #define XOTCL_CSC_CALL_IS_NEXT 1 -#define XOTCL_CSC_CALL_IS_DESTROY 2 -#define XOTCL_CSC_CALL_IS_GUARD 4 +#define XOTCL_CSC_CALL_IS_GUARD 2 #if !defined(TCL85STACK) typedef struct XOTclCallStack { @@ -641,7 +643,6 @@ int errorCount; /* these flags could move into a bitarray, but are used only once per interp*/ int callDestroy; - int callIsDestroy; int unknown; int doFilters; int doSoftrecreate; Index: generic/xotclStack.c =================================================================== diff -u -r6ad5c75139b83b9bf0c180d2b2ceceafa8bf69f4 -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- generic/xotclStack.c (.../xotclStack.c) (revision 6ad5c75139b83b9bf0c180d2b2ceceafa8bf69f4) +++ generic/xotclStack.c (.../xotclStack.c) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -11,11 +11,11 @@ TCL_STATIC); return NULL; } + obj->activationCount ++; csc = ++cs->top; csc->self = obj; csc->cl = cl; csc->cmdPtr = cmd; - csc->destroyedCmd = NULL; csc->frameType = frameType; csc->callType = 0; #if !defined(TCL85STACK) @@ -37,31 +37,18 @@ XOTCLINLINE static void CallStackPop(Tcl_Interp *interp, XOTclCallStackContent *cscPtr) { XOTclCallStack *cs = &RUNTIME_STATE(interp)->cs; - XOTclCallStackContent *csc; - XOTclCallStackContent *h = cs->top; + XOTclCallStackContent *csc = cs->top; + XOTclObject *obj = csc->self; assert(cs->top > cs->content); - csc = cs->top; #if defined(TCL85STACK_TRACE) fprintf(stderr, "POP csc=%p, frame %p\n", csc, Tcl_Interp_framePtr(interp)); #endif + obj->activationCount --; - if (csc->destroyedCmd) { - int destroy = 1; - TclCleanupCommand((Command *)csc->destroyedCmd); - MEM_COUNT_FREE("command refCount", csc->destroyedCmd); - /* do not physically destroy, when callstack still contains "self" - entries of the object */ - while (--h > cs->content) { - if (h->self == csc->self) { - destroy = 0; - break; - } - } - if (destroy) { - CallStackDoDestroy(interp, csc->self); - } + if (obj->activationCount < 1 && obj->flags & XOTCL_DESTROY_CALLED) { + CallStackDoDestroy(interp, obj); } cs->top--; @@ -261,57 +248,7 @@ return NULL; } -static int -CallStackMarkDestroyed(Tcl_Interp *interp, XOTclObject *obj) { - XOTclCallStack *cs = &RUNTIME_STATE(interp)->cs; - XOTclCallStackContent *csc; - int countSelfs = 0; - Tcl_Command oid = obj->id; - - for (csc = &cs->content[1]; csc <= cs->top; csc++) { - if (csc->self == obj) { - csc->destroyedCmd = oid; - csc->callType |= XOTCL_CSC_CALL_IS_DESTROY; - /*fprintf(stderr,"setting destroy on csc %p for obj %p\n", csc, obj);*/ - if (csc->destroyedCmd) { - Tcl_Command_refCount(csc->destroyedCmd)++; - MEM_COUNT_ALLOC("command refCount", csc->destroyedCmd); - } - countSelfs++; - } - } - return countSelfs; -} - /* - * Mark the given obj existing in the callstack as "not destroyed" - */ -static void -CallStackMarkUndestroyed(Tcl_Interp *interp, XOTclObject *obj) { - XOTclCallStack *cs = &RUNTIME_STATE(interp)->cs; - XOTclCallStackContent *csc; - - for (csc = &cs->content[1]; csc <= cs->top; csc++) { - if (obj == csc->self && csc->destroyedCmd) { - /* - * The ref count was incremented, when csc->destroyedCmd - * was set. We revert this first before clearing the - * destroyedCmd. - */ - if (Tcl_Command_refCount(csc->destroyedCmd) > 1) { - Tcl_Command_refCount(csc->destroyedCmd)--; - MEM_COUNT_FREE("command refCount", csc->destroyedCmd); - } - csc->destroyedCmd = 0; - } - } - /* - * mark obj->flags XOTCL_DESTROY_CALLED as NOT CALLED - */ - obj->flags &= ~XOTCL_DESTROY_CALLED; -} - -/* * Pop any callstack entry that is still alive (e.g. * if "exit" is called and we were jumping out of the * callframe Index: generic/xotclStack85.c =================================================================== diff -u -r5ec6a6f960964d861d68c052d8e2e7d68b711449 -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- generic/xotclStack85.c (.../xotclStack85.c) (revision 5ec6a6f960964d861d68c052d8e2e7d68b711449) +++ generic/xotclStack85.c (.../xotclStack85.c) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -15,13 +15,17 @@ }*/ framePtr = (Tcl_CallFrame *)Tcl_Interp_framePtr(interp); for (; framePtr; framePtr = Tcl_CallFrame_callerPtr(framePtr)) { - fprintf(stderr, "... var frame %p flags %.6x cd %.8x lvl %d frameType %d ns %p %s objv[0] %s\n", + XOTclCallStackContent *csc = Tcl_CallFrame_isProcCallFrame(framePtr) + & (FRAME_IS_XOTCL_METHOD|FRAME_IS_XOTCL_CMETHOD) ? + ((XOTclCallStackContent *)Tcl_CallFrame_clientData(framePtr)) : NULL; + + fprintf(stderr, "... var frame %p flags %.6x cd %.8x lvl %d frameType %d ns %p %s, %p %s %s\n", framePtr, Tcl_CallFrame_isProcCallFrame(framePtr), (int)Tcl_CallFrame_clientData(framePtr), Tcl_CallFrame_level(framePtr), - Tcl_CallFrame_isProcCallFrame(framePtr) & (FRAME_IS_XOTCL_METHOD|FRAME_IS_XOTCL_CMETHOD) - ? ((XOTclCallStackContent *)Tcl_CallFrame_clientData(framePtr))->frameType : -1, + csc ? csc->frameType : -1, Tcl_CallFrame_nsPtr(framePtr), Tcl_CallFrame_nsPtr(framePtr)->fullName, + csc ? csc->self : NULL, csc ? objectName(csc->self) : "", Tcl_CallFrame_objc(framePtr) ? ObjStr(Tcl_CallFrame_objv(framePtr)[0]) : "(null)"); } } @@ -271,76 +275,7 @@ return NULL; } -/* - TODO: we have a small divergence in the test "filterGuards" due to - different lifetime of stack entries, so we keep for reference and - for potential mor digging the following function, which can be used - in xotcl.c in CallStackDestroyObject() like - - int marked = CallStackMarkDestroyed(interp, obj); - int mm2 = CallStackMarkDestroyed84dummy(interp, obj); - - fprintf(stderr, "84 => %d marked, 85 => %d marked, ok = %d\n",marked, m2, marked == m2); - if (marked != m2) { - tcl85showStack(interp); - } -*/ - -static int -CallStackMarkDestroyed(Tcl_Interp *interp, XOTclObject *obj) { - register Tcl_CallFrame *varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); - int marked = 0; - Tcl_Command oid = obj->id; - - for (; varFramePtr; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { - if (Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_XOTCL_METHOD|FRAME_IS_XOTCL_CMETHOD)) { - XOTclCallStackContent *csc = (XOTclCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); - if (csc->self == obj) { - csc->destroyedCmd = oid; - csc->callType |= XOTCL_CSC_CALL_IS_DESTROY; - /*fprintf(stderr,"setting destroy on csc %p for obj %p\n", csc, obj);*/ - if (csc->destroyedCmd) { - Tcl_Command_refCount(csc->destroyedCmd)++; - MEM_COUNT_ALLOC("command refCount", csc->destroyedCmd); - } - marked++; - } - } - } - return marked; -} - /* - * Mark the given obj existing in the callstack as "not destroyed" - */ -static void -CallStackMarkUndestroyed(Tcl_Interp *interp, XOTclObject *obj) { - register Tcl_CallFrame *varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); - - for (; varFramePtr; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { - if (Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_XOTCL_METHOD|FRAME_IS_XOTCL_CMETHOD)) { - XOTclCallStackContent *csc = (XOTclCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); - if (obj == csc->self && csc->destroyedCmd) { - /* - * The ref count was incremented, when csc->destroyedCmd - * was set. We revert this first before clearing the - * destroyedCmd. - */ - if (Tcl_Command_refCount(csc->destroyedCmd) > 1) { - Tcl_Command_refCount(csc->destroyedCmd)--; - MEM_COUNT_FREE("command refCount", csc->destroyedCmd); - } - csc->destroyedCmd = 0; - } - } - } - /* - * mark obj->flags XOTCL_DESTROY_CALLED as NOT CALLED - */ - obj->flags &= ~XOTCL_DESTROY_CALLED; -} - -/* * Pop any callstack entry that is still alive (e.g. * if "exit" is called and we were jumping out of the * callframe @@ -351,10 +286,11 @@ Tcl_CallFrame *framePtr = Tcl_Interp_framePtr(interp); if (!framePtr) break; if (Tcl_CallFrame_level(framePtr) == 0) break; -#if 0 +#if 1 if (Tcl_CallFrame_isProcCallFrame(framePtr) & (FRAME_IS_XOTCL_METHOD|FRAME_IS_XOTCL_CMETHOD)) { - /* free the call stack content; for now, we pop it from the allocation stack */ - CallStackPop(interp); + /* free the call stack content; we need this just for decr activation count */ + XOTclCallStackContent *csc = ((XOTclCallStackContent *)Tcl_CallFrame_clientData(framePtr)); + CallStackPop(interp, csc); } #endif /* pop the Tcl frame */ @@ -364,48 +300,39 @@ XOTCLINLINE static void CallStackPush(XOTclCallStackContent *csc, XOTclObject *obj, XOTclClass *cl, Tcl_Command cmd, int frameType) { + obj->activationCount ++; + /*fprintf(stderr, "incr activationCount for %s to %d\n", objectName(obj), obj->activationCount);*/ csc->self = obj; csc->cl = cl; csc->cmdPtr = cmd; - csc->destroyedCmd = NULL; csc->frameType = frameType; csc->callType = 0; csc->filterStackEntry = frameType == XOTCL_CSC_TYPE_ACTIVE_FILTER ? obj->filterStack : NULL; +#if 0 #if defined(TCL85STACK_TRACE) - fprintf(stderr, "PUSH csc %p type %d frame %p, obj %s, self=%p cmd=%p (%s) id=%p (%s)\n", - csc, frameType, Tcl_Interp_framePtr(interp), objectName(obj), obj, - cmd, (char *) Tcl_GetCommandName(interp, cmd), - obj->id, Tcl_GetCommandName(interp, obj->id)); + fprintf(stderr, "PUSH csc %p type %d obj %s, self=%p cmd=%p (%s) id=%p (%s) obj refcount %d name refcount %d\n", + csc, frameType, objectName(obj), obj, + cmd, (char *) Tcl_GetCommandName(obj->teardown, cmd), + obj->id, obj->id ? Tcl_GetCommandName(obj->teardown, obj->id) : "(deleted)", + obj->id ? Tcl_Command_refCount(obj->id) : -100, obj->cmdName->refCount + ); #endif +#endif } XOTCLINLINE static void CallStackPop(Tcl_Interp *interp, XOTclCallStackContent *csc) { + XOTclObject *obj = csc->self; #if defined(TCL85STACK_TRACE) - fprintf(stderr, "POP csc=%p\n", csc); + fprintf(stderr, "POP csc=%p, obj %s\n", csc, objectName(obj)); #endif + obj->activationCount --; + /*fprintf(stderr, "decr activationCount for %s to %d\n", objectName(csc->self), csc->self->activationCount);*/ -#ifdef OBJDELETION_TRACE - fprintf(stderr, "POP csc=%p, obj %s, destroyed %p\n", csc, objectName(csc->self), csc->destroyedCmd); -#endif - if (csc->destroyedCmd) { - int destroy = 1; - TclCleanupCommand((Command *)csc->destroyedCmd); - MEM_COUNT_FREE("command refCount", csc->destroyedCmd); - /* do not physically destroy, when callstack still contains "self" - entries of the object */ - - if (CallStackGetObjectFrame(interp, csc->self)) { - destroy = 0; - } -#ifdef OBJDELETION_TRACE - fprintf(stderr, " callDoDestroy ?%d\n",destroy); -#endif - if (destroy) { - CallStackDoDestroy(interp, csc->self); - } + if (obj->activationCount < 1 && obj->flags & XOTCL_DESTROY_CALLED) { + CallStackDoDestroy(interp, obj); } } #endif /* TCL85STACK */ Index: generic/xotclTrace.c =================================================================== diff -u -r6ad5c75139b83b9bf0c180d2b2ceceafa8bf69f4 -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- generic/xotclTrace.c (.../xotclTrace.c) (revision 6ad5c75139b83b9bf0c180d2b2ceceafa8bf69f4) +++ generic/xotclTrace.c (.../xotclTrace.c) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -80,7 +80,7 @@ fprintf(stderr, " cmd %p, obj %p, epoch %d, ", csc->cmdPtr, csc->self, csc->cmdPtr ? Tcl_Command_cmdEpoch(csc->cmdPtr) : -1); */ - if (csc->cmdPtr && !csc->destroyedCmd && !Tcl_Command_cmdEpoch(csc->cmdPtr)) + if (csc->cmdPtr && !Tcl_Command_cmdEpoch(csc->cmdPtr)) fprintf(stderr, "%s (%p), ", Tcl_GetCommandName(interp, (Tcl_Command)csc->cmdPtr), csc->cmdPtr); else @@ -94,8 +94,6 @@ if (csc->currentFramePtr) fprintf(stderr,"l=%d ",Tcl_CallFrame_level(csc->currentFramePtr)); #endif - if (csc->destroyedCmd) - fprintf(stderr, "--destroyed cmd set (%p) ", csc->destroyedCmd); fprintf(stderr, "\n"); } Index: tests/object-system.xotcl =================================================================== diff -u -r200940690a99e5cd234e83fe6acc234477bf879c -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- tests/object-system.xotcl (.../object-system.xotcl) (revision 200940690a99e5cd234e83fe6acc234477bf879c) +++ tests/object-system.xotcl (.../object-system.xotcl) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -43,7 +43,7 @@ ? {C0 ismetaclass} 0 ? {C0 info superclass} ::xotcl::Object ? {C0 info class} ::xotcl::Class -? {lsort [Class info vars]} "__default_metaclass __default_superclass" +#? {lsort [Class info vars]} "__default_metaclass __default_superclass" Class M -superclass ::xotcl::Class ? {Object isobject M} 1 @@ -68,6 +68,7 @@ # destroy meta-class M, reclass meta-class instances to the base meta-class M destroy ? {Object isobject C} 1 +puts stderr XXX ? {C isclass} 1 ? {C ismetaclass} 0 ? {C info superclass} ::xotcl::Object Index: tests/testo.xotcl =================================================================== diff -u -r2111020b49da8ce57758e51accf0b6073037f0d2 -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- tests/testo.xotcl (.../testo.xotcl) (revision 2111020b49da8ce57758e51accf0b6073037f0d2) +++ tests/testo.xotcl (.../testo.xotcl) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -491,14 +491,23 @@ # trace variables # Variables avar2 + + proc ::traceproc {maj min op} { + set majTmp [namespace tail "$maj"] + puts stderr ...TRACE + global trail; lappend trail [list $majTmp $min $op] + } + avar2 proc trace {var ops} { my instvar $var ::trace variable $var $ops "avar2 traceproc" + #::trace variable $var $ops "traceproc" } avar2 proc traceproc {maj min op} { set majTmp [namespace tail "$maj"] + puts stderr ...TRACE global trail; lappend trail [list $majTmp $min $op] } @@ -533,9 +542,11 @@ for {set i 0} {$i < $n} {incr i} { lappend guide [list scalar$i {} u] } - +puts stderr KILLSELF avar2 killSelf - + puts stderr KILLSELF-done +puts stderr guide=$guide +puts stderr trail=$trail if {[lsort $guide] != [lsort $trail]} then { error "FAILED [self] - trace: expected $guide, got $trail" } Index: tests/testx.xotcl =================================================================== diff -u -r2198228db95e35c248720652c69f53a21eb718e6 -r7cb7c751d63fe0eece5756910e3f0b18e61a4d16 --- tests/testx.xotcl (.../testx.xotcl) (revision 2198228db95e35c248720652c69f53a21eb718e6) +++ tests/testx.xotcl (.../testx.xotcl) (revision 7cb7c751d63fe0eece5756910e3f0b18e61a4d16) @@ -616,13 +616,14 @@ } set filterResult "" B b - +puts stderr ====b-created ::errorCheck $filterResult "" \ "Filter guard: Filter never to be applied + filter inheritance on this filter" # filter w/o guard -> has to be applied A instfilter f1 +puts stderr ====b-instfilter-set b destroy - +puts stderr ====b-destroyed2 set filterResult "" B b # TODO: with tcl85stack, we get here @@ -2505,6 +2506,7 @@ # class hierarchy copy Class O X copy O::X + O::X x1; O::X::Y y1; O::X::Y::Z z1 ::errorCheck "[x1 q 1 2 3]--[y1 q 1 2 3]--[z1 q 1 2 3]" \ "::x1--::O::X--q------::y1--::O::X::Y--q------::z1--::O::X::Y::Z--q----"\ @@ -2516,6 +2518,7 @@ proc ::x::tclProc args {return tclProc} x proc q {a b c} {return [self]--[self class]--[self proc]--[next]--} x copy y + ::errorCheck "[::y::tclProc]--[x q 1 2 3]--[y q 1 2 3]" \ "tclProc--::x----q--::x--::X--q--------::y----q--::y--::X--q------"\ "object copy" @@ -2540,6 +2543,7 @@ x set var1 12 x proc p1 {} {return [self]-p1} x copy y + ::errorCheck "[x p1]--[x set var1]--[::x info class]" "::x-p1--12--::O"\ "Simple Copy - Origin" ::errorCheck "[y p1]--[y set var1]--[::y info class]" "::y-p1--12--::O"\ @@ -2608,6 +2612,7 @@ commands::cellcmd setproc {return "coucou" } commands::cellcmd proc x args {return xxx} commands::cellcmd copy toto + ::errorCheck [::toto info class] ::Command "Copy with Filter: info class" ::errorCheck [toto set label] cell "Copy with Filter: set var" ::errorCheck [toto x] xxx "Copy with Filter: call proc" @@ -2620,6 +2625,7 @@ Class B -superclass A Class B1 -superclass {V A Z} A move X + ::errorCheck [B info superclass]-[B1 info superclass]-[X info subclass] \ "::X-::V ::X ::Z-::B ::B1" \ "Move of subclass relationship" @@ -2638,8 +2644,10 @@ X proc do5 {{-arg1 d3} {arg2 d4}} {puts "$arg1 $arg2"} X instproc do6 {{-arg1 d3} {arg2 d4}} {puts "$arg1 $arg2"} +puts stderr "**** call copy Y" X copy Y - + puts stderr "**** copy to Y done (nonpos)" + ::errorCheck [lsort [X info procs]] "do0 do1 do2 do3 do4 do5" "check procs to be copied" ::errorCheck [lsort [Y info procs]] "do0 do1 do2 do3 do4 do5" "check copied procs" ::errorCheck [lsort [X info instprocs]] "do6" "check instprocs to be copied"