Index: TODO =================================================================== diff -u -rde5093e2960746e5727c31f6ef370f6389dbb51a -rb9000cff9206c8621e46524c2f12f8fc8fcb6f86 --- TODO (.../TODO) (revision de5093e2960746e5727c31f6ef370f6389dbb51a) +++ TODO (.../TODO) (revision b9000cff9206c8621e46524c2f12f8fc8fcb6f86) @@ -3726,6 +3726,12 @@ of an extra method. By this change, the serializer works in constant time independent on the number of existing objects. +nsf.c: +- reduce number of RUNTIME_STATE(interp) in favor of a variable. +- make time of the definition of a method independent on the + number of defined instances (unless, when filters are defined) + + ======================================================================== TODO: @@ -3975,12 +3981,8 @@ - currently, there are potential conflicts between slots and ensemble objects - provide a different place in the namesspaces could simplify this - * The speed of method definiton depends on the number of objects, - since every defined method might be a filter, so FilterInvalidateObjOrders() - is called on each filter. It would be useful to keep a list of currently - defined filter names to perform the invalidation only when a method is defined - with the same name as the currently registered filter (that should be always - a small number). + * Cleanup the set of active filters when filters are removed (only relevant + for the speed of scripts with filters and a high number of instances) * Ensembles - It could be possible to reduce stack frames in ensembles. Just a Index: generic/nsf.c =================================================================== diff -u -r120b838888f00fe1a3130bf184fd079d06d89fa6 -rb9000cff9206c8621e46524c2f12f8fc8fcb6f86 --- generic/nsf.c (.../nsf.c) (revision 120b838888f00fe1a3130bf184fd079d06d89fa6) +++ generic/nsf.c (.../nsf.c) (revision b9000cff9206c8621e46524c2f12f8fc8fcb6f86) @@ -7368,6 +7368,63 @@ } /* + *---------------------------------------------------------------------- + * FilterAddActive -- + * + * Add a method name to the set of methods, which were used as filters in + * the current interp. + * + * TODO: let the set shrink, when filters are removed. + * + * Results: + * None. + * + * Side effects: + * Adding or updating of a hash entry + * + *---------------------------------------------------------------------- + */ +static void +FilterAddActive(Tcl_Interp *interp, CONST char *methodName) { + NsfRuntimeState *rst = RUNTIME_STATE(interp); + Tcl_HashEntry *hPtr; + int new, count; + + hPtr = Tcl_CreateHashEntry(&rst->activeFilterTablePtr, methodName, &new); + + if (new) { + Tcl_SetHashValue(hPtr, INT2PTR(1)); + } else { + count = PTR2INT(Tcl_GetHashValue(hPtr)); + Tcl_SetHashValue(hPtr, INT2PTR(count+1)); + } +} + +/* + *---------------------------------------------------------------------- + * FilterIsActive -- + * + * Check, wether a method name is in the set of methods, which were used as + * filters in the current interp. + * + * Results: + * Boolean + * + * Side effects: + * none + * + *---------------------------------------------------------------------- + */ +static int +FilterIsActive(Tcl_Interp *interp, CONST char *methodName) { + NsfRuntimeState *rst = RUNTIME_STATE(interp); + Tcl_HashEntry *hPtr; + + hPtr = Tcl_CreateHashEntry(&rst->activeFilterTablePtr, methodName, NULL); + return (hPtr != NULL); +} + +/* * append a filter command to the 'filterList' of an obj/class */ static int @@ -7407,6 +7464,7 @@ /*fprintf(stderr, " +++ adding filter %s cl %p\n", ObjStr(nameObj), cl);*/ new = CmdListAdd(filterList, cmd, cl, /*noDuplicates*/ 1); + FilterAddActive(interp, ObjStr(filterObj)); if (guardObj) { GuardAdd(new, guardObj); @@ -11753,7 +11811,9 @@ if (cl) { NsfInstanceMethodEpochIncr("MakeMethod"); /* could be a filter or filter inheritance ... update filter orders */ - FilterInvalidateObjOrders(interp, cl); + if (FilterIsActive(interp, nameStr)) { + FilterInvalidateObjOrders(interp, cl); + } } else { NsfObjectMethodEpochIncr("MakeMethod"); /* could be a filter => recompute filter order */ @@ -13874,7 +13934,6 @@ /*MixinInvalidateObjOrders(interp, cl);*/ CmdListRemoveList(&clopt->classFilters, GuardDel); - /*FilterInvalidateObjOrders(interp, cl);*/ if (!recreate) { /* @@ -23113,6 +23172,7 @@ ExitHandler(ClientData clientData) { Tcl_Interp *interp = (Tcl_Interp *)clientData; int i, flags; + NsfRuntimeState *rst = RUNTIME_STATE(interp); /*fprintf(stderr, "ExitHandler\n");*/ @@ -23144,18 +23204,21 @@ CallStackPopAll(interp); - if (RUNTIME_STATE(interp)->exitHandlerDestroyRound == NSF_EXITHANDLER_OFF) { + if (rst->exitHandlerDestroyRound == NSF_EXITHANDLER_OFF) { NsfFinalizeCmd(interp, 0); } - /* must be before freeing of NsfGlobalObjs */ + /* Must be before freeing of NsfGlobalObjs */ NsfShadowTclCommands(interp, SHADOW_UNLOAD); + MEM_COUNT_FREE("Tcl_InitHashTable", &rst->activeFilterTablePtr); + Tcl_DeleteHashTable(&rst->activeFilterTablePtr); + /* free global objects */ for (i = 0; i < nr_elements(NsfGlobalStrings); i++) { DECR_REF_COUNT(NsfGlobalObjs[i]); } - NsfStringIncrFree(&RUNTIME_STATE(interp)->iss); + NsfStringIncrFree(&rst->iss); /* * Free all data in the pointer converter @@ -23264,6 +23327,8 @@ Nsf_Init(Tcl_Interp *interp) { ClientData runtimeState; int result, i; + NsfRuntimeState *rst; + #ifdef NSF_BYTECODE /*NsfCompEnv *interpstructions = NsfGetCompEnv();*/ #endif @@ -23340,39 +23405,38 @@ #if defined(NSF_PROFILE) NsfProfileInit(interp); #endif + rst = RUNTIME_STATE(interp); + rst->doFilters = 1; + rst->doCheckResults = 1; + rst->doCheckArguments = 1; - RUNTIME_STATE(interp)->doFilters = 1; - RUNTIME_STATE(interp)->doCheckResults = 1; - RUNTIME_STATE(interp)->doCheckArguments = 1; - /* create nsf namespace */ - RUNTIME_STATE(interp)->NsfNS = - Tcl_CreateNamespace(interp, "::nsf", NULL, (Tcl_NamespaceDeleteProc *)NULL); + rst->NsfNS = Tcl_CreateNamespace(interp, "::nsf", NULL, (Tcl_NamespaceDeleteProc *)NULL); MEM_COUNT_ALLOC("TclNamespace", RUNTIME_STATE(interp)->NsfNS); /* * init an empty, faked proc structure in the RUNTIME state */ - RUNTIME_STATE(interp)->fakeProc.iPtr = (Interp *)interp; - RUNTIME_STATE(interp)->fakeProc.refCount = 1; - RUNTIME_STATE(interp)->fakeProc.cmdPtr = NULL; - RUNTIME_STATE(interp)->fakeProc.bodyPtr = NULL; - RUNTIME_STATE(interp)->fakeProc.numArgs = 0; - RUNTIME_STATE(interp)->fakeProc.numCompiledLocals = 0; - RUNTIME_STATE(interp)->fakeProc.firstLocalPtr = NULL; - RUNTIME_STATE(interp)->fakeProc.lastLocalPtr = NULL; + rst->fakeProc.iPtr = (Interp *)interp; + rst->fakeProc.refCount = 1; + rst->fakeProc.cmdPtr = NULL; + rst->fakeProc.bodyPtr = NULL; + rst->fakeProc.numArgs = 0; + rst->fakeProc.numCompiledLocals = 0; + rst->fakeProc.firstLocalPtr = NULL; + rst->fakeProc.lastLocalPtr = NULL; /* NsfClasses in separate Namespace / Objects */ - RUNTIME_STATE(interp)->NsfClassesNS = + rst->NsfClassesNS = Tcl_CreateNamespace(interp, "::nsf::classes", NULL, (Tcl_NamespaceDeleteProc *)NULL); MEM_COUNT_ALLOC("TclNamespace", RUNTIME_STATE(interp)->NsfClassesNS); /* cache interpreters proc interpretation functions */ - RUNTIME_STATE(interp)->objInterpProc = TclGetObjInterpProc(); - RUNTIME_STATE(interp)->exitHandlerDestroyRound = NSF_EXITHANDLER_OFF; + rst->objInterpProc = TclGetObjInterpProc(); + rst->exitHandlerDestroyRound = NSF_EXITHANDLER_OFF; RegisterExitHandlers(interp); NsfStringIncrInit(&RUNTIME_STATE(interp)->iss); @@ -23384,6 +23448,9 @@ INCR_REF_COUNT(NsfGlobalObjs[i]); } + Tcl_InitHashTable(&rst->activeFilterTablePtr, TCL_STRING_KEYS); + MEM_COUNT_ALLOC("Tcl_InitHashTable", &rst->activeFilterTablePtr); + /* create namespaces for the different command types */ Tcl_CreateNamespace(interp, "::nsf::cmd", 0, (Tcl_NamespaceDeleteProc *)NULL); for (i=0; i < nr_elements(method_command_namespace_names); i++) { @@ -23396,7 +23463,7 @@ } /* - * overwritten Tcl cmds + * shadowed Tcl cmds */ result = NsfShadowTclCommands(interp, SHADOW_LOAD); if (result != TCL_OK) { @@ -23424,8 +23491,7 @@ (Tcl_ResolveCmdProc *)InterpColonCmdResolver, InterpColonVarResolver, (Tcl_ResolveCompiledVarProc *)InterpCompiledColonVarResolver); - RUNTIME_STATE(interp)->colonCmd = - Tcl_FindCommand(interp, "::nsf::colon", NULL, TCL_GLOBAL_ONLY); + rst->colonCmd = Tcl_FindCommand(interp, "::nsf::colon", NULL, TCL_GLOBAL_ONLY); /* * SS: Tcl occassionally resolves a proc's cmd structure (e.g., in @@ -23438,7 +23504,7 @@ * indicating "::nsf::colon" (which is sufficiently misleading and * reveals internals not to be revealed ...). */ - RUNTIME_STATE(interp)->fakeProc.cmdPtr = (Command *)RUNTIME_STATE(interp)->colonCmd; + rst->fakeProc.cmdPtr = (Command *)RUNTIME_STATE(interp)->colonCmd; { /* Index: generic/nsfInt.h =================================================================== diff -u -r120b838888f00fe1a3130bf184fd079d06d89fa6 -rb9000cff9206c8621e46524c2f12f8fc8fcb6f86 --- generic/nsfInt.h (.../nsfInt.h) (revision 120b838888f00fe1a3130bf184fd079d06d89fa6) +++ generic/nsfInt.h (.../nsfInt.h) (revision b9000cff9206c8621e46524c2f12f8fc8fcb6f86) @@ -783,6 +783,9 @@ int doKeepinitcmd; int doProfile; int doSoftrecreate; + /* keep track of defined filters */ + Tcl_HashTable activeFilterTablePtr; + /* * shutdown handling */