Index: TODO =================================================================== diff -u -rf7e7dd532f08b253e4b81e73074e216674685d60 -r991f6b6fde382a9bb5c3c9232206988813a3eb37 --- TODO (.../TODO) (revision f7e7dd532f08b253e4b81e73074e216674685d60) +++ TODO (.../TODO) (revision 991f6b6fde382a9bb5c3c9232206988813a3eb37) @@ -2308,6 +2308,9 @@ deletes its grandparents namespace, containing also this class of o (and its methods). Significantly eased by the change above. +- use NsfCommandPreserve/NsfCommandRelease for tcd->aliasCmd as well. + In case of epoched cmdPointers, refetch the cmd and it client data. + TODO: - document value added replacements of Tcl functions Index: generic/nsf.c =================================================================== diff -u -rf7e7dd532f08b253e4b81e73074e216674685d60 -r991f6b6fde382a9bb5c3c9232206988813a3eb37 --- generic/nsf.c (.../nsf.c) (revision f7e7dd532f08b253e4b81e73074e216674685d60) +++ generic/nsf.c (.../nsf.c) (revision 991f6b6fde382a9bb5c3c9232206988813a3eb37) @@ -282,6 +282,7 @@ static void NsfCommandPreserve(Tcl_Command cmd); static void NsfCommandRelease(Tcl_Command cmd); +static Tcl_Command GetOriginalCommand(Tcl_Command cmd); void NsfDStringArgv(Tcl_DString *dsPtr, int objc, Tcl_Obj *CONST objv[]); @@ -673,6 +674,7 @@ */ static void NsfCommandRelease(Tcl_Command cmd) { + /*fprintf(stderr,"NsfCommandRelease %p\n", cmd);*/ TclCleanupCommandMacro((Command *)cmd); MEM_COUNT_FREE("command refCount", cmd); } @@ -12357,6 +12359,9 @@ return result; } +static int NsfAliasCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, + CONST char *methodName, int withFrame, Tcl_Obj *cmdName); + static int NsfProcAliasMethod(ClientData clientData, Tcl_Interp *interp, int objc, @@ -12372,6 +12377,52 @@ "don't call aliased methods via namespace paths", Tcl_GetCommandName(interp, tcd->aliasCmd)); } + + if (Tcl_Command_cmdEpoch(tcd->aliasedCmd)) { + NsfObject *defObject = tcd->class ? &(tcd->class->object) : tcd->object; + Tcl_Obj **listElements, *entryObj, *targetObj; + int nrElements, withPer_object; + Tcl_Command cmd; + //int result, withFrame; + + /* + * Get the targetObject. Currently, we can get it just via the + * alias array. + */ + withPer_object = tcd->class ? 0 : 1; + //withFrame = (tcd->objProc == NsfObjscopedMethod); + entryObj = AliasGet(interp, defObject->cmdName, methodName, withPer_object); + + Tcl_ListObjGetElements(interp, entryObj, &nrElements, &listElements); + targetObj = listElements[nrElements-1]; + + //result = NsfAliasCmd(interp, defObject, withPer_object, methodName, withFrame, targetObj); + + fprintf(stderr, "trying to dispatch an epoched cmd %p as %s -- cmdName %s\n", + tcd->aliasedCmd, methodName, ObjStr(targetObj)); + /* + * Replace cmd and its objProc and clientData with a newly fetched + * version. + */ + cmd = Tcl_GetCommandFromObj(interp, targetObj); + if (cmd == NULL) { + return NsfPrintError(interp, "target \"%s\" of alias %s apparently disappeared", + ObjStr(targetObj), methodName); + } + cmd = GetOriginalCommand(cmd); + + NsfCommandRelease(tcd->aliasedCmd); + tcd->objProc = Tcl_Command_objProc(cmd); + tcd->aliasedCmd = cmd; + tcd->clientData = Tcl_Command_objClientData(cmd); + NsfCommandPreserve(tcd->aliasedCmd); + + DECR_REF_COUNT(entryObj); + /* + * Now, we should be able to proceed as plannded, we have an + * non-epoched aliasCmd. + */ + } return MethodDispatch((ClientData)self, interp, objc, objv, tcd->aliasedCmd, self, tcd->class, methodName, 0, 0); } @@ -12420,7 +12471,7 @@ AliasDelete(tcd->interp, tcd->cmdName, methodName, tcd->class == NULL); } - /*fprintf(stderr, "AliasCmdDeleteProc\n");*/ + /*fprintf(stderr, "AliasCmdDeleteProc aliasedCmd %p\n", tcd->aliasedCmd);*/ if (tcd->cmdName) {DECR_REF_COUNT(tcd->cmdName);} if (tcd->aliasedCmd) { Command *aliasedCmd = (Command *)(tcd->aliasedCmd); @@ -12443,8 +12494,8 @@ } prevPtr = refPtr; } + NsfCommandRelease(tcd->aliasedCmd); } - FREE(AliasCmdClientData, tcd); } @@ -14431,6 +14482,8 @@ if (newObjProc) { /* add a wrapper */ + /*fprintf(stderr, "NsfAliasCmd cmd %p\n", cmd);*/ + NsfCommandPreserve(cmd); tcd = NEW(AliasCmdClientData); tcd->cmdName = object->cmdName; tcd->interp = interp; /* just for deleting the associated variable */ Index: tests/alias.test =================================================================== diff -u -rbd1cce484140aaf66113cf647f060ae48d32b24f -r991f6b6fde382a9bb5c3c9232206988813a3eb37 --- tests/alias.test (.../alias.test) (revision bd1cce484140aaf66113cf647f060ae48d32b24f) +++ tests/alias.test (.../alias.test) (revision 991f6b6fde382a9bb5c3c9232206988813a3eb37) @@ -394,13 +394,15 @@ ::nsf::alias C FOO ::foo ? {info exists ::nsf::alias(::C,FOO,0)} 1 ? {C info methods -methodtype alias} FOO +# Rename target, such that alias points to an invalid item +# Note that removing the target works differently (makes cleanup) +# rename ::foo "" rename ::foo ::foo2 ? {info exists ::nsf::alias(::C,FOO,0)} 1 ? {C info methods -methodtype alias} FOO -? {c FOO} ::c->foo2 -? {C info method definition FOO} "::C public alias FOO ::foo"; # should be ::foo2 (!) +? {c FOO} {target "::foo" of alias FOO apparently disappeared} +? {C info method definition FOO} "::C public alias FOO ::foo" - # # Check resolving of namespace imported classes # and when a class is aliased via "interp alias" @@ -517,7 +519,7 @@ } # - # by calling "foo" outside the obejct/method context, we get a + # by calling "foo" outside the object/method context, we get a # byte-code without the compiled-local handler, colon-vars are not # recognized, :a refers to the argument ? {foo 1 2} 1 @@ -543,4 +545,6 @@ # the variable in the test scope does not influence result set :d 200 ? {bar 3 4} 0-3-47 -} \ No newline at end of file +} + +puts stderr ===EXIT \ No newline at end of file