Index: TODO =================================================================== diff -u -r143ac569e197689119f0e355bfa4a7fd7e4ee8fb -race51b03d7e2b835c6867943f49c6ad5fa4c1b65 --- TODO (.../TODO) (revision 143ac569e197689119f0e355bfa4a7fd7e4ee8fb) +++ TODO (.../TODO) (revision ace51b03d7e2b835c6867943f49c6ad5fa4c1b65) @@ -3128,9 +3128,62 @@ * provide debug-refcounts for "pcPtr.objv" * provide debug-refcounts for "pcPtr.clientData" +nsf.c: + * provide debug-refcounts for "class.activationCount" + * provide debug-refcounts for "object.activationCount" + * deactivated CHECK_ACTIVATION_COUNTS oer default + * tested refcounts with Tcl 8.6b2, found bug in Tcl and submitted patch to sourceforge + + TODO: + - zzz why is the method recompiled for /tmp/sp.tcl ? + debug output with VAR_RESOLVER_TRACE +================================================= +# -*- Tcl -*- +package require XOTcl; namespace import ::xotcl::* +package require nx::test; namespace import nx::Test +Class C; C c +Class D -superclass C +D instproc init args {} + +Test new \ + -count 100 \ + -pre {Class D; Class E; Class E1; Class X -instmixin {D E E1}} \ + -cmd {X info instmixin ::E*} \ + -expected {::E ::E1} \ + -post {foreach o {D E E1 X} {$o destroy}} + +Test new \ + -count 100 \ + -pre {Class D; Class E; Class X -instmixin {D E}} \ + -cmd {X info instmixin ::E*} \ + -expected {::E} \ + -post {foreach o {D E X} {$o destroy}} + +Test run; exit +================================================= + + - strange refcounting bug in 8.6b2 bug-is-86.tcl + where 2 refcounted items are not freed (value:class, + issued from nx.tcl around line 120). Compile for more + info with DEBUG86B2 +================================================= +# -*- Tcl -*- +package req nx +package require nx::test + +nx::Test case ensemble-next-with-colon-prefix { + nx::Object create obj { + :public method foo {} { return [:info class] } + #:public method bar {} { return [:info] } + :method info {} {;} + } + ? {obj foo} {wrong # args: should be ":info"} +} +================================================= + - from parameters.test # TODO: currently, we need two converters (or a converter on nx::Slot), since # variable uses nsf::is and attribute uses the slot obj. method variable should Index: generic/nsf.c =================================================================== diff -u -r143ac569e197689119f0e355bfa4a7fd7e4ee8fb -race51b03d7e2b835c6867943f49c6ad5fa4c1b65 --- generic/nsf.c (.../nsf.c) (revision 143ac569e197689119f0e355bfa4a7fd7e4ee8fb) +++ generic/nsf.c (.../nsf.c) (revision ace51b03d7e2b835c6867943f49c6ad5fa4c1b65) @@ -2748,6 +2748,7 @@ static void MakeObjNamespace(Tcl_Interp *interp, NsfObject *object) { + #ifdef NAMESPACE_TRACE fprintf(stderr, "+++ MakeObjNamespace for %s\n", ObjectName(object)); #endif @@ -3144,6 +3145,11 @@ CompiledColonVarFree(Tcl_ResolvedVarInfo *vInfoPtr) { NsfResolvedVarInfo *resVarInfo = (NsfResolvedVarInfo *)vInfoPtr; +#if defined(VAR_RESOLVER_TRACE) + fprintf(stderr, "CompiledColonVarFree %p for variable '%s'\n", + resVarInfo, ObjStr(resVarInfo->nameObj)); +#endif + DECR_REF_COUNT(resVarInfo->nameObj); if (resVarInfo->var) {HashVarFree(resVarInfo->var);} FREE(NsfResolvedVarInfo, vInfoPtr); @@ -3198,11 +3204,18 @@ NsfResolvedVarInfo *resVarInfo = NEW(NsfResolvedVarInfo); resVarInfo->vInfo.fetchProc = CompiledColonVarFetch; - resVarInfo->vInfo.deleteProc = CompiledColonVarFree; /* if NULL, tcl does a ckfree on proc clean up */ + resVarInfo->vInfo.deleteProc = CompiledColonVarFree; /* if NULL, Tcl does a ckfree on proc clean up */ resVarInfo->lastObject = NULL; resVarInfo->var = NULL; resVarInfo->nameObj = Tcl_NewStringObj(name+1, length-1); INCR_REF_COUNT(resVarInfo->nameObj); + +#if defined(VAR_RESOLVER_TRACE) + fprintf(stderr, "... resVarInfo %p nameObj %p '%s' obj %p %s\n", + resVarInfo, resVarInfo->nameObj, ObjStr(resVarInfo->nameObj), + object, ObjectName(object)); +#endif + *rPtr = (Tcl_ResolvedVarInfo *)resVarInfo; return TCL_OK; @@ -7534,6 +7547,18 @@ || (codePtr->nsPtr != nsPtr) || (codePtr->nsEpoch != nsPtr->resolverEpoch)) { +#if defined (VAR_RESOLVER_TRACE) + fprintf(stderr, "ByteCompiled bytecode not valid proc %p cmd %p method %s\n", + procPtr, procPtr->cmdPtr, Tcl_GetCommandName(interp, procPtr->cmdPtr)); + { + CompiledLocal *localPtr = procPtr->firstLocalPtr; + for (; localPtr != NULL; localPtr = localPtr->nextPtr) { + fprintf(stderr, "... local %p '%s' resolveInfo %p deleteProc %p\n", + localPtr, localPtr->name, localPtr->resolveInfo, + localPtr->resolveInfo ? localPtr->resolveInfo->deleteProc : NULL); + } + } +#endif goto doCompilation; } return TCL_OK; @@ -7543,6 +7568,7 @@ # if defined(HAVE_TCL_COMPILE_H) doCompilation: # endif + *flagsPtr |= NSF_CSC_CALL_IS_COMPILE; result = TclProcCompileProc(interp, procPtr, bodyObj, (Namespace *) nsPtr, "body of proc", @@ -7596,6 +7622,9 @@ Tcl_CallFrame_procPtr(framePtr) = procPtr; Tcl_CallFrame_clientData(framePtr) = cscPtr; + /*fprintf(stderr, "Stack Frame %p procPtr %p compiledLocals %p firstLocal %p\n", + framePtr, procPtr, Tcl_CallFrame_compiledLocals(framePtr), procPtr->firstLocalPtr);*/ + return ByteCompiled(interp, &cscPtr->flags, procPtr, ObjStr(objv[0])); } @@ -11339,7 +11368,6 @@ * We could not define the shadowed proc. In this case, cleanup by * removing the stub cmd. */ - fprintf(stderr, "Delete token\n"); Tcl_DeleteCommandFromToken(interp, cmd); } @@ -12584,8 +12612,24 @@ /* * bring an object into a state, as after initialization */ +/* + *---------------------------------------------------------------------- + * CleanupDestroyObject -- + * + * Perform cleanup of object; after the function is executed, the object is + * in the same fresh state as after initialization. + * + * Results: + * None. + * + * Side effects: + * Possibly freeing memory. + * + *---------------------------------------------------------------------- + */ static void CleanupDestroyObject(Tcl_Interp *interp, NsfObject *object, int softrecreate) { + /*fprintf(stderr, "CleanupDestroyObject obj %p softrecreate %d nsPtr %p\n", object, softrecreate, object->nsPtr);*/ @@ -18886,6 +18930,11 @@ NSF_DISALLOWED_ARG_VALUECHECK /* disallowed options */, paramWrapperPtr->paramPtr, &possibleUnknowns, &plainParams, &nrNonposArgs); +#if defined(DEBUG86B2) + fprintf(stderr, "ParamParse3 %s paramPtr %p returned ok? %d\n", + ObjStr(fullParamObj), + paramWrapperPtr->paramPtr, result==TCL_OK); +#endif /* * We treat currently unknown user level converters as error. */ @@ -18901,8 +18950,6 @@ paramWrapperPtr->paramPtr->flags |= NSF_ARG_UNNAMED; if (*(paramWrapperPtr->paramPtr->name) == 'r') { paramWrapperPtr->paramPtr->flags |= NSF_ARG_IS_RETURNVALUE; - /*fprintf(stderr, "ParamSetFromAny2 sets returnvalue %p\n", - paramWrapperPtr->paramPtr);*/ } TclFreeIntRep(objPtr); objPtr->internalRep.twoPtrValue.ptr1 = (void *)paramWrapperPtr; @@ -19052,7 +19099,7 @@ ClientData checkedData; int result, flags = 0; - /*fprintf(stderr, "ParamSetFromAny %s value %p %s\n", + /*fprintf(stderr, "ParameterCheck %s value %p %s\n", ObjStr(paramObjPtr), valueObj, ObjStr(valueObj));*/ if (paramObjPtr->typePtr == ¶mObjType) { @@ -19078,7 +19125,7 @@ paramPtr, paramWrapperPtr->refCount, paramWrapperPtr->canFree, flags);*/ if (paramWrapperPtr->refCount == 0) { - fprintf(stderr, "#### ParamSetFromAny paramPtr %p manual free\n", paramPtr); + fprintf(stderr, "#### ParamSetFromAny2 paramPtr %p manual free\n", paramPtr); ParamsFree(paramWrapperPtr->paramPtr); FREE(NsfParamWrapper, paramWrapperPtr); } else { @@ -21743,6 +21790,10 @@ AliasDeleteObjectReference(interp, cmd); continue; } + /*fprintf(stderr, "Class %p %s deletes cmd %p %s\n", + object, ObjectName(object), cmd, Tcl_GetCommandName(interp, cmd));*/ + /*Tcl_DeleteCommandFromToken(interp, cmd); + deleted ++; */ } } } @@ -21769,8 +21820,8 @@ object = GetObjectFromString(interp, key); if (object && !NsfObjectIsClass(object) && !ObjectHasChildren(object)) { /*if (object->id) { - fprintf(stderr, " ... delete object %s %p, class=%s id %p\n", key, object, - ClassName(object->cl), object->id); + fprintf(stderr, " ... delete object %s %p, class=%s id %p ns %p\n", key, object, + ClassName(object->cl), object->id, object->nsPtr); }*/ FreeUnsetTraceVariable(interp, object); if (object->id) FinalObjectDeletion(interp, object); @@ -21799,9 +21850,11 @@ && !IsBaseClass(cl) ) { /*fprintf(stderr, " ... delete class %s %p\n", key, cl); */ - FreeUnsetTraceVariable(interp, &cl->object); - if (cl->object.id) FinalObjectDeletion(interp, &cl->object); + FreeUnsetTraceVariable(interp, &cl->object); + if (cl->object.id) { + FinalObjectDeletion(interp, &cl->object); + } Tcl_DeleteHashEntry(hPtr); deleted++; } Index: generic/nsf.h =================================================================== diff -u -r9addecef4701fd68a81b54714a370a9de3eb25f3 -race51b03d7e2b835c6867943f49c6ad5fa4c1b65 --- generic/nsf.h (.../nsf.h) (revision 9addecef4701fd68a81b54714a370a9de3eb25f3) +++ generic/nsf.h (.../nsf.h) (revision ace51b03d7e2b835c6867943f49c6ad5fa4c1b65) @@ -153,7 +153,14 @@ #endif #ifdef NSF_DEVELOPMENT -# define CHECK_ACTIVATION_COUNTS 1 +/* + * The activation counts checking is best performed via the MEM_COUNT + * macros. In case, the MEM_COUNT macros indicate a problem, setting + * CHECK_ACTIVATION_COUNTS might help to locate the problem more + * precisely. The CHECK_ACTIVATION_COUNTS tester might however still + * report false positives. + */ +/*# define CHECK_ACTIVATION_COUNTS 1*/ # define NsfCleanupObject(object,string) \ /*fprintf(stderr, "NsfCleanupObject %p %s\n",object,string);*/ \ NsfCleanupObject_(object) @@ -180,7 +187,7 @@ #if !defined(CHECK_ACTIVATION_COUNTS) # define CscListAdd(interp, cscPtr) -# define CscListRemove(interp, cscPtr) +# define CscListRemove(interp, cscPtr, cscListPtr) #endif #if defined(TCL_THREADS) Index: generic/nsfStack.c =================================================================== diff -u -r9addecef4701fd68a81b54714a370a9de3eb25f3 -race51b03d7e2b835c6867943f49c6ad5fa4c1b65 --- generic/nsfStack.c (.../nsfStack.c) (revision 9addecef4701fd68a81b54714a370a9de3eb25f3) +++ generic/nsfStack.c (.../nsfStack.c) (revision ace51b03d7e2b835c6867943f49c6ad5fa4c1b65) @@ -38,14 +38,14 @@ *---------------------------------------------------------------------- */ static int -CscListRemove(Tcl_Interp *interp, NsfCallStackContent *cscPtr, NsfClasses **cscListPtrPtr) { +CscListRemove(Tcl_Interp *interp, NsfCallStackContent *cscPtr, NsfClasses **cscListPtr) { NsfClasses *entryPtr, **cscList = &RUNTIME_STATE(interp)->cscList; entryPtr = NsfClassListUnlink(cscList, cscPtr); if (entryPtr) { FREE(NsfClasses, entryPtr); } - if (cscListPtrPtr != NULL) { - *cscListPtrPtr = *cscList; + if (cscListPtr != NULL) { + *cscListPtr = *cscList; } return (entryPtr != NULL); } @@ -896,6 +896,7 @@ * Track object activations */ object->activationCount ++; + MEM_COUNT_ALLOC("object.activationCount",object); /*fprintf(stderr, "CscInit %p method %s activationCount ++ (%s) --> %d (cl %p)\n", cscPtr, cmd ? Tcl_GetCommandName(object->teardown, cmd) : "UNK", ObjectName(object), object->activationCount, cl);*/ @@ -907,6 +908,7 @@ * handle class activation count */ cl->object.activationCount ++; + MEM_COUNT_ALLOC("class.activationCount", cl); /* * Incremement the namespace ptr in case Tcl tries to delete * this namespace during the invocation @@ -975,6 +977,7 @@ * Track object activations */ object->activationCount --; + MEM_COUNT_FREE("object.activationCount", object); /*fprintf(stderr, "CscFinish decr activationCount for %s to %d object->flags %.6x dc %.6x succ %.6x\n", ObjectName(cscPtr->self), cscPtr->self->activationCount, object->flags, @@ -995,7 +998,8 @@ if (cscPtr->cl) { NsfObject *clObject = &cscPtr->cl->object; clObject->activationCount --; - + MEM_COUNT_FREE("class.activationCount", clObject); + /*fprintf(stderr, "CscFinish class %p %s check ac %d flags destroy %.6x success %.6x\n", clObject, ObjectName(clObject), clObject->activationCount,