Index: TODO =================================================================== diff -u -r25023d3c048b369645973fdfa125a3705c7f1898 -rd66258cafa0a21e1b10fa42951de7e71f63a1817 --- TODO (.../TODO) (revision 25023d3c048b369645973fdfa125a3705c7f1898) +++ TODO (.../TODO) (revision d66258cafa0a21e1b10fa42951de7e71f63a1817) @@ -4951,14 +4951,17 @@ nx-mongo: - added command "::mongo::status /mongoConn/" - extended regression test + +nsf.c: +- invalidate paramter caches of subclasses on + NsfParameterInvalidateClassCacheCmd unless during + shutdown. Otherwise some classes might not become aware of + properties added later to superclasses. +- extended regression test + ======================================================================== TODO: -- Why do we still have a method volatile in nx? Why not leave it as - configure/cget configuration option only?! At least, I cannot recall the - rationale behind keeping the method anymore :/ - * why the question ... now? - - remove / rephrase "//"-comments - ParamGetDomain(Nsf_Param CONST *paramPtr) does not work for enumeration types defined in derived packages, having Index: generic/nsf.c =================================================================== diff -u -r74b7a4066526ff5f5a8080ed907f71c9ed5c7700 -rd66258cafa0a21e1b10fa42951de7e71f63a1817 --- generic/nsf.c (.../nsf.c) (revision 74b7a4066526ff5f5a8080ed907f71c9ed5c7700) +++ generic/nsf.c (.../nsf.c) (revision d66258cafa0a21e1b10fa42951de7e71f63a1817) @@ -21412,9 +21412,29 @@ ParsedParamFree(cl->parsedParamPtr); cl->parsedParamPtr = NULL; } + + /* + * Omit storm of invalidations on shutdown. + */ + if (unlikely(RUNTIME_STATE(interp)->exitHandlerDestroyRound == NSF_EXITHANDLER_OFF)) { + NsfClasses *subClasses = TransitiveSubClasses(cl), *clPtr; + /* + * invalidate cached parameters in subclasses + */ + for (clPtr = subClasses; clPtr; clPtr = clPtr->nextPtr) { + NsfClass *subClass = clPtr->cl; + if (subClass->parsedParamPtr) { + ParsedParamFree(subClass->parsedParamPtr); + subClass->parsedParamPtr = NULL; + } + } + NsfClassListFree(subClasses); + } + return TCL_OK; } + /* cmd parameter:invalidate::objectcache NsfParameterInvalidateObjectCacheCmd { {-argName "object" -required 1 -type object} @@ -22344,6 +22364,7 @@ if (likely(class && class->parsedParamPtr)) { NsfParsedParam *clParsedParamPtr = class->parsedParamPtr; + parsedParamPtr->paramDefs = clParsedParamPtr->paramDefs; parsedParamPtr->possibleUnknowns = clParsedParamPtr->possibleUnknowns; result = TCL_OK; @@ -22391,6 +22412,7 @@ ppDefPtr->paramDefs = parsedParamPtr->paramDefs; ppDefPtr->possibleUnknowns = parsedParamPtr->possibleUnknowns; if (class) { + assert(class->parsedParamPtr == NULL); class->parsedParamPtr = ppDefPtr; #if defined(PER_OBJECT_PARAMETER_CACHING) } else { @@ -23781,11 +23803,11 @@ } /* -classMethod getCachedParameters NsfCGetCachendParameters { +classMethod getCachedParameters NsfCGetCachendParametersMethod { } */ static int -NsfCGetCachendParameters(Tcl_Interp *interp, NsfClass *class) { +NsfCGetCachendParametersMethod(Tcl_Interp *interp, NsfClass *class) { if (likely(class && class->parsedParamPtr && class->parsedParamPtr->paramDefs)) { Tcl_Obj *listObj; Index: generic/nsfAPI.decls =================================================================== diff -u -r4bc60e16c10fdbbb640b3019d4bdebdc469fdf55 -rd66258cafa0a21e1b10fa42951de7e71f63a1817 --- generic/nsfAPI.decls (.../nsfAPI.decls) (revision 4bc60e16c10fdbbb640b3019d4bdebdc469fdf55) +++ generic/nsfAPI.decls (.../nsfAPI.decls) (revision d66258cafa0a21e1b10fa42951de7e71f63a1817) @@ -345,7 +345,7 @@ {-argName "guard" -required 1 -type tclobj} } -classMethod getCachedParameters NsfCGetCachendParameters { +classMethod getCachedParameters NsfCGetCachendParametersMethod { } classMethod mixinguard NsfCMixinGuardMethod { Index: generic/nsfAPI.h =================================================================== diff -u -r4bc60e16c10fdbbb640b3019d4bdebdc469fdf55 -rd66258cafa0a21e1b10fa42951de7e71f63a1817 --- generic/nsfAPI.h (.../nsfAPI.h) (revision 4bc60e16c10fdbbb640b3019d4bdebdc469fdf55) +++ generic/nsfAPI.h (.../nsfAPI.h) (revision d66258cafa0a21e1b10fa42951de7e71f63a1817) @@ -293,7 +293,7 @@ static int NsfCCreateMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfCDeallocMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfCFilterGuardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); -static int NsfCGetCachendParametersStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfCGetCachendParametersMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfCMixinGuardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfCNewMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfCRecreateMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); @@ -399,7 +399,7 @@ static int NsfCCreateMethod(Tcl_Interp *interp, NsfClass *cl, CONST char *objectName, int objc, Tcl_Obj *CONST objv[]); static int NsfCDeallocMethod(Tcl_Interp *interp, NsfClass *cl, Tcl_Obj *object); static int NsfCFilterGuardMethod(Tcl_Interp *interp, NsfClass *cl, CONST char *filter, Tcl_Obj *guard); -static int NsfCGetCachendParameters(Tcl_Interp *interp, NsfClass *cl); +static int NsfCGetCachendParametersMethod(Tcl_Interp *interp, NsfClass *cl); static int NsfCMixinGuardMethod(Tcl_Interp *interp, NsfClass *cl, Tcl_Obj *mixin, Tcl_Obj *guard); static int NsfCNewMethod(Tcl_Interp *interp, NsfClass *cl, Tcl_Obj *withChildof, int nobjc, Tcl_Obj *CONST nobjv[]); static int NsfCRecreateMethod(Tcl_Interp *interp, NsfClass *cl, Tcl_Obj *objectName, int objc, Tcl_Obj *CONST objv[]); @@ -506,7 +506,7 @@ NsfCCreateMethodIdx, NsfCDeallocMethodIdx, NsfCFilterGuardMethodIdx, - NsfCGetCachendParametersIdx, + NsfCGetCachendParametersMethodIdx, NsfCMixinGuardMethodIdx, NsfCNewMethodIdx, NsfCRecreateMethodIdx, @@ -686,19 +686,19 @@ } static int -NsfCGetCachendParametersStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { +NsfCGetCachendParametersMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { NsfClass *cl = NsfObjectToClass(clientData); assert(objc > 0); if (unlikely(cl == NULL)) return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", - method_definitions[NsfCGetCachendParametersIdx].paramDefs, + method_definitions[NsfCGetCachendParametersMethodIdx].paramDefs, NULL, objv[0]); } - return NsfCGetCachendParameters(interp, cl); + return NsfCGetCachendParametersMethod(interp, cl); } @@ -2739,7 +2739,7 @@ {"filter", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"guard", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, -{"::nsf::methods::class::getCachedParameters", NsfCGetCachendParametersStub, 0, { +{"::nsf::methods::class::getCachedParameters", NsfCGetCachendParametersMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::mixinguard", NsfCMixinGuardMethodStub, 2, { Index: tests/properties.test =================================================================== diff -u -r74b7a4066526ff5f5a8080ed907f71c9ed5c7700 -rd66258cafa0a21e1b10fa42951de7e71f63a1817 --- tests/properties.test (.../properties.test) (revision 74b7a4066526ff5f5a8080ed907f71c9ed5c7700) +++ tests/properties.test (.../properties.test) (revision d66258cafa0a21e1b10fa42951de7e71f63a1817) @@ -832,6 +832,48 @@ ? {o1 cget -class} ::nx::Object } +nx::test case extend-parent-class-info { + + nx::Class create Foo + nx::Class create Bar -superclass Foo + ? {llength [Bar info configure parameters]} 4 + # + # extend the superclass, subclass should become aware of this + # + Foo property y + ? {llength [Bar info configure parameters]} 5 +} + +nx::test case extend-parent-class-info-cache { + + nx::Class create Foo + nx::Class create Bar -superclass Foo + ? {llength [Bar info configure parameters]} 4 + # + # Let Bar cache the objectparameters, and extend later the + # superclass + # + Bar new + Foo property y + ? {llength [Bar info configure parameters]} 5 +} + +nx::test case extend-parent-class-info-cache-configure { + + nx::Class create Foo + nx::Class create Bar -superclass Foo + ? {llength [Bar info configure parameters]} 4 + # + # Let Bar cache the objectparameters, and extend later the + # superclass + # + Bar create b1 + Foo property y + # access obejctparamter indirectly via configure + ? {b1 configure -y 2} "" +} + + # # Local variables: # mode: tcl