/* * nsfInt.h -- * * Declarations of the internally used API Functions of the Next * Scripting Framework. * * Copyright (C) 1999-2014 Gustaf Neumann (a, b) * Copyright (C) 1999-2007 Uwe Zdun (a, b) * Copyright (C) 2011 Stefan Sobernig (b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License * http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifndef _nsf_int_h_ #define _nsf_int_h_ #if defined(HAVE_STDINT_H) # define HAVE_INTPTR_T # define HAVE_UINTPTR_T #endif /* * MinGW and MinGW-w64 provide both MSCRT-compliant and ANSI-compliant * implementations of certain I/O operations (e.g., *printf()). By * setting __USE_MINGW_ANSI_STDIO to 1 explicitly, we can assume the * ANSI versions. * * Note: It is sufficient to test for __MINGW32__ to trap all MinGW * tool chains, including 64bit versions. See * http://sourceforge.net/p/predef/wiki/Compilers/#mingw-and-mingw-w64 */ #if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO) #define __USE_MINGW_ANSI_STDIO 1 #endif #include #include "nsf.h" #include #include #include #if defined(HAVE_TCL_COMPILE_H) # include #endif #if defined(NSF_PROFILE) # include #endif #if __GNUC_PREREQ(2, 95) /* Use gcc branch prediction hint to minimize cost of e.g. DTrace * ENABLED checks. */ # define unlikely(x) (__builtin_expect((x), 0)) # define likely(x) (__builtin_expect((x), 1)) #else # define unlikely(x) (x) # define likely(x) (x) #endif #if __GNUC_PREREQ(2, 96) # define pure __attribute__((pure)) #else # define pure #endif #if __GNUC_PREREQ(3, 3) # define nonnull(ARGS) __attribute__((__nonnull__(ARGS))) #else # define nonnull(ARGS) #endif #if __GNUC_PREREQ(4, 9) # define returns_nonnull __attribute__((returns_nonnull)) #else # define returns_nonnull #endif /* * Tries to use gcc __attribute__ unused and mangles the name, so the * attribute could not be used, if declared as unused. */ #ifdef UNUSED #elif __GNUC_PREREQ(2, 7) # define UNUSED(x) UNUSED_ ## x __attribute__((unused)) #elif defined(__LCLINT__) # define UNUSED(x) /*@unused@*/ (x) #else # define UNUSED(x) (x) #endif #if defined(NSF_DTRACE) # include "nsfDTrace.h" # define NSF_DTRACE_METHOD_ENTRY_ENABLED() unlikely(NSF_METHOD_ENTRY_ENABLED()) # define NSF_DTRACE_METHOD_RETURN_ENABLED() unlikely(NSF_METHOD_RETURN_ENABLED()) # define NSF_DTRACE_OBJECT_ALLOC_ENABLED() unlikely(NSF_OBJECT_ALLOC_ENABLED()) # define NSF_DTRACE_OBJECT_FREE_ENABLED() unlikely(NSF_OBJECT_FREE_ENABLED()) # define NSF_DTRACE_CONFIGURE_PROBE_ENABLED() unlikely(NSF_CONFIGURE_PROBE_ENABLED()) # define NSF_DTRACE_METHOD_ENTRY(a0, a1, a2, a3, a4) NSF_METHOD_ENTRY((a0), (a1), (a2), (a3), (a4)) # define NSF_DTRACE_METHOD_RETURN(a0, a1, a2, a3) NSF_METHOD_RETURN((a0), (a1), (a2), (a3)) # define NSF_DTRACE_OBJECT_ALLOC(a0, a1) NSF_OBJECT_ALLOC((a0), (a1)) # define NSF_DTRACE_OBJECT_FREE(a0, a1) NSF_OBJECT_FREE((a0), (a1)) # define NSF_DTRACE_CONFIGURE_PROBE(a0, a1) NSF_CONFIGURE_PROBE((a0), (a1)) #else # define NSF_DTRACE_METHOD_ENTRY_ENABLED() 0 # define NSF_DTRACE_METHOD_RETURN_ENABLED() 0 # define NSF_DTRACE_OBJECT_ALLOC_ENABLED() 0 # define NSF_DTRACE_OBJECT_FREE_ENABLED() 0 # define NSF_DTRACE_CONFIGURE_PROBE_ENABLED() 0 # define NSF_DTRACE_METHOD_ENTRY(a0, a1, a2, a3, a4) {} # define NSF_DTRACE_METHOD_RETURN(a0, a1, a2, a3) {} # define NSF_DTRACE_OBJECT_ALLOC(a0, a1) {} # define NSF_DTRACE_OBJECT_FREE(a0, a1) {} # define NSF_DTRACE_CONFIGURE_PROBE(a0, a1) {} #endif #ifdef DMALLOC # include "dmalloc.h" #endif /* * Makros */ #if defined(PRE86) # define Tcl_NRCallObjProc(interp, proc, cd, objc, objv) \ (*(proc))((cd), (interp), (objc), (objv)) #endif #ifdef NSF_MEM_COUNT EXTERN int nsfMemCountInterpCounter; typedef struct NsfMemCounter { int peak; int count; } NsfMemCounter; # define MEM_COUNT_ALLOC(id,p) NsfMemCountAlloc((id), (p)) # define MEM_COUNT_FREE(id,p) NsfMemCountFree((id), (p)) # define MEM_COUNT_INIT() NsfMemCountInit() # define MEM_COUNT_RELEASE() NsfMemCountRelease() #else # define MEM_COUNT_ALLOC(id,p) # define MEM_COUNT_FREE(id,p) # define MEM_COUNT_INIT() # define MEM_COUNT_RELEASE() #endif # define STRING_NEW(target, p, l) (target) = ckalloc((l)+1); strncpy((target), (p), (l)); *((target)+(l)) = '\0'; \ MEM_COUNT_ALLOC(#target, (target)) # define STRING_FREE(key, p) MEM_COUNT_FREE((key), (p)); ckfree((p)) #define DSTRING_INIT(dsPtr) Tcl_DStringInit(dsPtr); MEM_COUNT_ALLOC("DString",(dsPtr)) #define DSTRING_FREE(dsPtr) \ if ((dsPtr)->string != (dsPtr)->staticSpace) {Tcl_DStringFree(dsPtr);} MEM_COUNT_FREE("DString",(dsPtr)) #if USE_ASSOC_DATA # define RUNTIME_STATE(interp) ((NsfRuntimeState*)Tcl_GetAssocData((interp), "NsfRuntimeState", NULL)) #else # define RUNTIME_STATE(interp) ((NsfRuntimeState*)((Interp*)(interp))->globalNsPtr->clientData) #endif #define nr_elements(arr) ((int) (sizeof(arr) / sizeof((arr)[0]))) # define NEW(type) \ (type *)ckalloc(sizeof(type)); MEM_COUNT_ALLOC(#type, NULL) # define NEW_ARRAY(type,n) \ (type *)ckalloc(sizeof(type)*(n)); MEM_COUNT_ALLOC(#type "*", NULL) # define FREE(type, var) \ ckfree((char*) (var)); MEM_COUNT_FREE(#type,(var)) #define isAbsolutePath(m) (*(m) == ':' && (m)[1] == ':') #define isArgsString(m) (\ *(m) == 'a' && (m)[1] == 'r' && (m)[2] == 'g' && (m)[3] == 's' && \ (m)[4] == '\0') #define isBodyString(m) (\ *(m) == 'b' && (m)[1] == 'o' && (m)[2] == 'd' && (m)[3] == 'y' && \ (m)[4] == '\0') #define isCheckString(m) (\ *(m) == 'c' && (m)[1] == 'h' && (m)[2] == 'e' && (m)[3] == 'c' && \ (m)[4] == 'k' && (m)[5] == '\0') #define isCheckObjString(m) (\ *(m) == 'c' && (m)[1] == 'h' && (m)[2] == 'e' && (m)[3] == 'c' && \ (m)[4] == 'k' && (m)[5] == 'o' && (m)[6] == 'b' && (m)[7] == 'j' && \ (m)[8] == '\0') #define isCreateString(m) (\ *(m) == 'c' && (m)[1] == 'r' && (m)[2] == 'e' && (m)[3] == 'a' && \ (m)[4] == 't' && (m)[5] == 'e' && (m)[6] == '\0') #define isTypeString(m) (\ *(m) == 't' && (m)[1] == 'y' && (m)[2] == 'p' && (m)[3] == 'e' && \ (m)[4] == '\0') #define isObjectString(m) (\ *(m) == 'o' && (m)[1] == 'b' && (m)[2] == 'j' && (m)[3] == 'e' && \ (m)[4] == 'c' && (m)[5] == 't' && (m)[6] == '\0') #define isClassString(m) (\ *(m) == 'c' && (m)[1] == 'l' && (m)[2] == 'a' && (m)[3] == 's' && \ (m)[4] == 's' && (m)[5] == '\0') #if (defined(sun) || defined(__hpux)) && !defined(__GNUC__) # define USE_ALLOCA #endif #if defined(__IBMC__) && !defined(__GNUC__) # if __IBMC__ >= 0x0306 # define USE_ALLOCA # else # define USE_MALLOC # endif #endif #if defined(VISUAL_CC) # define USE_MALLOC #endif #if defined(__GNUC__) && !defined(USE_ALLOCA) && !defined(USE_MALLOC) # if !defined(NDEBUG) # define ALLOC_ON_STACK(type,n,var) \ int __##var##_count = (n); type __##var[(n)+2]; \ type *(var) = __##var + 1; (var)[-1] = var[__##var##_count] = (type)0xdeadbeaf # define FREE_ON_STACK(type,var) \ assert((var)[-1] == (var)[__##var##_count] && (var)[-1] == (type)0xdeadbeaf) # else # define ALLOC_ON_STACK(type,n,var) type (var)[(n)] # define FREE_ON_STACK(type,var) # endif #elif defined(USE_ALLOCA) # define ALLOC_ON_STACK(type,n,var) type *(var) = (type *)alloca((n)*sizeof(type)) # define FREE_ON_STACK(type,var) #else # define ALLOC_ON_STACK(type,n,var) type *(var) = (type *)ckalloc((n)*sizeof(type)) # define FREE_ON_STACK(type,var) ckfree((char*)(var)) #endif #ifdef USE_ALLOCA # include #endif #if !defined(NDEBUG) # if defined(PRE86) # define ISOBJ(o) ((o) != NULL && (o) != (void*)0xdeadbeaf && ((o)->typePtr ? (o)->typePtr->name != NULL : 1) && (o)->length >= -1 && ((o)->length > 0 ? (o)->bytes!= NULL : 1) && (o)->refCount >= 0) # else # define ISOBJ(o) ((o) != NULL && (o) != (void*)0xdeadbeaf && ((o)->typePtr ? (o)->typePtr->name != NULL : 1) && ((o)->bytes != NULL ? (o)->length >= 0 : 1) && (o)->refCount >= 0) # endif #else # define ISOBJ(o) ((o) != NULL) #endif #define NSF_ABBREV_MIN_CHARS 4 /* * This was defined to be inline for anything !sun or __IBMC__ >= 0x0306, * but __hpux should also be checked - switched to only allow in gcc - JH */ #if defined(__GNUC__) && !defined(__STRICT_ANSI__) # define NSF_INLINE inline #else # define NSF_INLINE #endif #ifdef USE_TCL_STUBS # define DECR_REF_COUNT(A) \ MEM_COUNT_FREE("INCR_REF_COUNT" #A,(A)); assert((A)->refCount > -1); \ Tcl_DecrRefCount(A) # define DECR_REF_COUNT2(name,A) \ MEM_COUNT_FREE("INCR_REF_COUNT-" name,(A)); assert((A)->refCount > -1); \ Tcl_DecrRefCount(A) #else # define DECR_REF_COUNT(A) \ MEM_COUNT_FREE("INCR_REF_COUNT" #A,(A)); TclDecrRefCount(A) # define DECR_REF_COUNT2(name,A) \ MEM_COUNT_FREE("INCR_REF_COUNT-" name,(A)); TclDecrRefCount(A) #endif #define INCR_REF_COUNT(A) MEM_COUNT_ALLOC("INCR_REF_COUNT" #A,(A)); Tcl_IncrRefCount((A)) #define INCR_REF_COUNT2(name,A) \ /*fprintf(stderr, "c '%s'\n", ObjStr(A));*/ \ MEM_COUNT_ALLOC("INCR_REF_COUNT-" name,(A)); Tcl_IncrRefCount((A)) #define ObjStr(obj) ((obj)->bytes) ? ((obj)->bytes) : Tcl_GetString(obj) #define ClassName(cl) (((cl) ? ObjStr((cl)->object.cmdName) : "NULL")) #define ObjectName(obj) (((obj) ? ObjStr((obj)->cmdName) : "NULL")) #ifdef OBJDELETION_TRACE # define PRINTOBJ(ctx,obj) \ fprintf(stderr, " %s %p %s oid=%p teardown=%p destroyCalled=%d\n", \ (ctx),(obj),(obj)->teardown?ObjStr((obj)->cmdName):"(deleted)", \ (obj)->id, (obj)->teardown, \ ((obj)->flags & NSF_DESTROY_CALLED)) #else # define PRINTOBJ(ctx,obj) #endif /* * When an integer is printed, it might take so many digits */ #define LONG_AS_STRING 32 /* TCL_CONTINUE is defined as 4, from 5 on we can use app-specific return codes */ #define NSF_CHECK_FAILED 6 /* The NsfConfigEnabled() macro allows for querying whether a configuration macro (see above) is actually defined (and whether it expands to 1). This macro can be used both in CPP expressions (e.g., "#if NsfConfigEnabled(...)") and in C expressions (e.g., "if(NsfConfigEnabled(...))") Adapted from https://plus.google.com/+LinusTorvalds/posts/9gntjh57dXt */ #define NsfConfigEnabled(macro) NsfConfigEnabled_(macro) #define NsfMacroTest_1 , #define NsfConfigEnabled_(value) NsfConfigEnabled__(NsfMacroTest_##value) #define NsfConfigEnabled__(comma) NsfConfigEnabled___(comma 1, 0) #define NsfConfigEnabled___(_, v, ...) v /* * * Next Scripting Structures * */ /* * Filter structures */ typedef struct NsfFilterStack { Tcl_Command currentCmdPtr; Tcl_Obj *calledProc; struct NsfFilterStack *nextPtr; } NsfFilterStack; /* * Assertion structures */ typedef struct NsfTclObjList { Tcl_Obj *content; Tcl_Obj *payload; struct NsfTclObjList *nextPtr; } NsfTclObjList; typedef struct NsfProcAssertion { NsfTclObjList *pre; NsfTclObjList *post; } NsfProcAssertion; typedef struct NsfAssertionStore { NsfTclObjList *invariants; Tcl_HashTable procs; } NsfAssertionStore; typedef enum { /* powers of 2; add to ALL, if default; */ CHECK_NONE = 0, CHECK_CLINVAR = 1, CHECK_OBJINVAR = 2, CHECK_PRE = 4, CHECK_POST = 8, CHECK_INVAR = CHECK_CLINVAR + CHECK_OBJINVAR, CHECK_ALL = CHECK_INVAR + CHECK_PRE + CHECK_POST } CheckOptions; void NsfAssertionRename(Tcl_Interp *interp, Tcl_Command cmd, NsfAssertionStore *as, char *oldSimpleCmdName, char *newName); /* * mixins */ typedef struct NsfMixinStack { Tcl_Command currentCmdPtr; struct NsfMixinStack *nextPtr; } NsfMixinStack; /* * Generic command pointer list */ typedef struct NsfCmdList { Tcl_Command cmdPtr; ClientData clientData; struct NsfClass *clorobj; struct NsfCmdList *nextPtr; } NsfCmdList; typedef void (NsfFreeCmdListClientData) _ANSI_ARGS_((NsfCmdList*)); /* for incr string */ typedef struct NsfStringIncrStruct { char *buffer; char *start; size_t bufSize; int length; } NsfStringIncrStruct; /* * cmd flags */ #define NSF_CMD_CALL_PROTECTED_METHOD 0x00010000 #define NSF_CMD_CALL_PRIVATE_METHOD 0x00020000 #define NSF_CMD_REDEFINE_PROTECTED_METHOD 0x00040000 /* NSF_CMD_NONLEAF_METHOD is used to flag, if a Method implemented via cmd calls "next" */ #define NSF_CMD_NONLEAF_METHOD 0x00080000 #define NSF_CMD_CLASS_ONLY_METHOD 0x00100000 /* * object flags ... */ /* DESTROY_CALLED indicates that destroy was called on obj */ #define NSF_DESTROY_CALLED 0x0001 /* INIT_CALLED indicates that init was called on obj */ #define NSF_INIT_CALLED 0x0002 /* MIXIN_ORDER_VALID set when mixin order is valid */ #define NSF_MIXIN_ORDER_VALID 0x0004 /* MIXIN_ORDER_DEFINED set, when mixins are defined for obj */ #define NSF_MIXIN_ORDER_DEFINED 0x0008 #define NSF_MIXIN_ORDER_DEFINED_AND_VALID 0x000c /* FILTER_ORDER_VALID set, when filter order is valid */ #define NSF_FILTER_ORDER_VALID 0x0010 /* FILTER_ORDER_DEFINED set, when filters are defined for obj */ #define NSF_FILTER_ORDER_DEFINED 0x0020 #define NSF_FILTER_ORDER_DEFINED_AND_VALID 0x0030 /* class and object properties for objects */ #define NSF_IS_CLASS 0x0040 #define NSF_IS_ROOT_META_CLASS 0x0080 #define NSF_IS_ROOT_CLASS 0x0100 #define NSF_IS_SLOT_CONTAINER 0x0200 #define NSF_KEEP_CALLER_SELF 0x0400 #define NSF_PER_OBJECT_DISPATCH 0x0800 #define NSF_HAS_PER_OBJECT_SLOTS 0x1000 /* deletion states */ #define NSF_DESTROY_CALLED_SUCCESS 0x010000 /* requires flags to be int, not short */ #define NSF_DURING_DELETE 0x020000 #define NSF_DELETED 0x040000 #define NSF_RECREATE 0x080000 #define NSF_TCL_DELETE 0x100000 /* method invocations */ #define NSF_ARG_METHOD_INVOCATION (NSF_ARG_ALIAS|NSF_ARG_FORWARD|NSF_ARG_INITCMD|NSF_ARG_CMD) #define NSF_ARG_METHOD_CALL (NSF_ARG_ALIAS|NSF_ARG_FORWARD) /* Disallowed parameter options */ #define NSF_DISALLOWED_ARG_METHOD_PARAMETER (NSF_ARG_METHOD_INVOCATION|NSF_ARG_NOCONFIG|NSF_ARG_SLOTSET|NSF_ARG_SLOTINITIALIZE) #define NSF_DISALLOWED_ARG_SETTER (NSF_ARG_SWITCH|NSF_ARG_SUBST_DEFAULT|NSF_DISALLOWED_ARG_METHOD_PARAMETER) /*#define NSF_DISALLOWED_ARG_OBJECT_PARAMETER (NSF_ARG_SWITCH)*/ #define NSF_DISALLOWED_ARG_OBJECT_PARAMETER 0 #define NSF_DISALLOWED_ARG_VALUECHECK (NSF_ARG_SUBST_DEFAULT|NSF_ARG_METHOD_INVOCATION|NSF_ARG_SWITCH|NSF_ARG_CURRENTLY_UNKNOWN|NSF_ARG_SLOTSET|NSF_ARG_SLOTINITIALIZE) /* flags for ParseContext */ #define NSF_PC_MUST_DECR 0x0001 #define NSF_PC_IS_DEFAULT 0x0002 #define NSF_PC_INVERT_DEFAULT 0x0010 #define NSF_PC_STATUS_MUST_DECR 0x0001 #define NSF_PC_STATUS_FREE_OBJV 0x0002 #define NSF_PC_STATUS_FREE_CD 0x0004 /* method types */ #define NSF_METHODTYPE_ALIAS 0x0001 #define NSF_METHODTYPE_SCRIPTED 0x0002 #define NSF_METHODTYPE_SETTER 0x0004 #define NSF_METHODTYPE_FORWARDER 0x0008 #define NSF_METHODTYPE_OBJECT 0x0010 #define NSF_METHODTYPE_NSFPROC 0x0020 #define NSF_METHODTYPE_OTHER 0x0100 #define NSF_METHODTYPE_BUILTIN NSF_METHODTYPE_ALIAS|NSF_METHODTYPE_SETTER|NSF_METHODTYPE_FORWARDER|NSF_METHODTYPE_OTHER #define NSF_METHODTYPE_ALL NSF_METHODTYPE_SCRIPTED|NSF_METHODTYPE_BUILTIN|NSF_METHODTYPE_OBJECT #define NsfObjectSetClass(obj) \ (obj)->flags |= NSF_IS_CLASS #define NsfObjectClearClass(obj) \ (obj)->flags &= ~NSF_IS_CLASS #define NsfObjectIsClass(obj) \ ((obj)->flags & NSF_IS_CLASS) #define NsfObjectToClass(obj) \ (NsfClass*)((((NsfObject*)obj)->flags & NSF_IS_CLASS)?obj:NULL) /* * object and class internals */ typedef struct NsfParamDefs { Nsf_Param *paramsPtr; int nrParams; int refCount; int serial; Tcl_Obj *slotObj; Tcl_Obj *returns; } NsfParamDefs; typedef struct NsfParsedParam { NsfParamDefs *paramDefs; int possibleUnknowns; } NsfParsedParam; typedef struct NsfObjectOpt { NsfAssertionStore *assertions; NsfCmdList *objFilters; NsfCmdList *objMixins; ClientData clientData; #if defined(PER_OBJECT_PARAMETER_CACHING) NsfParsedParam *parsedParamPtr; int classParamPtrEpoch; #endif CONST char *volatileVarName; short checkoptions; } NsfObjectOpt; typedef struct NsfObject { Tcl_Obj *cmdName; Tcl_Command id; Tcl_Interp *teardown; struct NsfClass *cl; TclVarHashTable *varTablePtr; Tcl_Namespace *nsPtr; NsfObjectOpt *opt; struct NsfCmdList *filterOrder; struct NsfCmdList *mixinOrder; NsfFilterStack *filterStack; NsfMixinStack *mixinStack; int refCount; unsigned int flags; short activationCount; } NsfObject; typedef struct NsfClassOpt { NsfCmdList *classFilters; NsfCmdList *classMixins; NsfCmdList *isObjectMixinOf; NsfCmdList *isClassMixinOf; NsfAssertionStore *assertions; Tcl_Obj *mixinRegObjs; #ifdef NSF_OBJECTDATA Tcl_HashTable *objectdata; #endif Tcl_Command id; ClientData clientData; } NsfClassOpt; typedef struct NsfClass { struct NsfObject object; struct NsfClasses *super; struct NsfClasses *sub; struct NsfObjectSystem *osPtr; struct NsfClasses *order; Tcl_HashTable instances; Tcl_Namespace *nsPtr; NsfParsedParam *parsedParamPtr; NsfClassOpt *opt; short color; } NsfClass; typedef struct NsfClasses { struct NsfClass *cl; ClientData clientData; struct NsfClasses *nextPtr; } NsfClasses; /* * needed in nsf.c and in nsfShadow */ typedef struct NsfProcClientData { Tcl_Obj *procName; Tcl_Command cmd; NsfParamDefs *paramDefs; int with_ad; int checkAlwaysFlag; } NsfProcClientData; typedef enum SystemMethodsIdx { NSF_c_alloc_idx, NSF_c_create_idx, NSF_c_dealloc_idx, NSF_c_configureparameter_idx, NSF_c_recreate_idx, NSF_o_cleanup_idx, NSF_o_configure_idx, NSF_o_configureparameter_idx, NSF_o_defaultmethod_idx, NSF_o_destroy_idx, NSF_o_init_idx, NSF_o_move_idx, NSF_o_unknown_idx, NSF_s_get_idx, NSF_s_set_idx } SystemMethodsIdx; #if !defined(NSF_C) EXTERN CONST char *Nsf_SystemMethodOpts[]; #else CONST char *Nsf_SystemMethodOpts[] = { "-class.alloc", "-class.create", "-class.dealloc", "-class.configureparameter", "-class.recreate", "-object.cleanup", "-object.configure", "-object.configureparameter", "-object.defaultmethod", "-object.destroy", "-object.init", "-object.move", "-object.unknown", "-slot.get", "-slot.set", NULL }; #endif typedef struct NsfObjectSystem { NsfClass *rootClass; NsfClass *rootMetaClass; int overloadedMethods; int definedMethods; Tcl_Obj *methods[NSF_s_set_idx+1]; Tcl_Obj *handles[NSF_s_set_idx+1]; struct NsfObjectSystem *nextPtr; char protected[NSF_s_set_idx+1]; } NsfObjectSystem; /* * Next Scripting global names and strings * * We provide enums for efficient lookup for corresponding string * names and Tcl_Objs via global arrays. The "constant" Tcl_Objs are * built at start-up-time via Nsf_Init(). */ typedef enum { NSF_EMPTY, NSF_ZERO, NSF_ONE, /* methods called internally */ NSF_CONFIGURE, NSF_INITIALIZE, NSF_GET_PARAMETER_SPEC, NSF_SLOT_GET, NSF_SLOT_SET, /* var names */ NSF_AUTONAMES, NSF_DEFAULTMETACLASS, NSF_DEFAULTSUPERCLASS, NSF_ARRAY_INITCMD, NSF_ARRAY_CMD, NSF_ARRAY_ALIAS, NSF_ARRAY_PARAMETERSYNTAX, NSF_POSITION, NSF_POSITIONAL, NSF_CONFIGURABLE, NSF_PARAMETERSPEC, /* object/class names */ NSF_METHOD_PARAMETER_SLOT_OBJ, /* constants */ NSF_ALIAS, NSF_ARGS, NSF_CMD, NSF_FILTER, NSF_FORWARD, NSF_METHOD, NSF_OBJECT, NSF_SETTER, NSF_SETTERNAME, NSF_VALUECHECK, NSF_GUARD_OPTION, NSF___UNKNOWN__, NSF_ARRAY, NSF_GET, NSF_SET, NSF_OPTION_STRICT, NSF_OBJECT_UNKNOWN_HANDLER, NSF_ARGUMENT_UNKNOWN_HANDLER, /* Partly redefined Tcl commands; leave them together at the end */ NSF_EXPR, NSF_FORMAT, NSF_INFO_BODY, NSF_INFO_FRAME, NSF_INTERP, NSF_STRING_IS, NSF_EVAL, NSF_RENAME } NsfGlobalNames; #if !defined(NSF_C) EXTERN char *NsfGlobalStrings[]; #else char *NsfGlobalStrings[] = { "", "0", "1", /* methods called internally */ "configure", "initialize", "getParameterSpec", "value=get", "value=set", /* var names */ "__autonames", "__default_metaclass", "__default_superclass", "__initcmd", "__cmd", "::nsf::alias", "::nsf::parameter::syntax", "position", "positional", "configurable", "parameterSpec", /* object/class names */ "::nx::methodParameterSlot", /* constants */ "alias", "args", "cmd", "filter", "forward", "method", "object", "setter", "settername", "valuecheck", "-guard", "__unknown__", "::array", "get", "set", "-strict", /* nsf tcl commands */ "::nsf::object::unknown", "::nsf::argument::unknown", /* tcl commands */ "expr", "format", "::tcl::info::body", "::tcl::info::frame", "interp", "::tcl::string::is", "::eval", "rename" }; #endif #define NsfGlobalObjs RUNTIME_STATE(interp)->methodObjNames /* obj types */ EXTERN Tcl_ObjType NsfMixinregObjType; EXTERN int NsfMixinregGet(Tcl_Interp *interp, Tcl_Obj *obj, NsfClass **clPtr, Tcl_Obj **guardObj) nonnull(1) nonnull(2) nonnull(3) nonnull(4); EXTERN int NsfMixinregInvalidate(Tcl_Interp *interp, Tcl_Obj *obj) nonnull(1) nonnull(2); EXTERN Tcl_ObjType NsfFilterregObjType; EXTERN int NsfFilterregGet(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_Obj **filterObj, Tcl_Obj **guardObj) nonnull(1) nonnull(2) nonnull(3) nonnull(4); EXTERN NsfClassOpt *NsfRequireClassOpt(/*@notnull@*/ NsfClass *cl) nonnull(1) returns_nonnull; /* Next Scripting ShadowTclCommands */ typedef struct NsfShadowTclCommandInfo { TclObjCmdProcType proc; ClientData clientData; } NsfShadowTclCommandInfo; typedef enum {SHADOW_LOAD=1, SHADOW_UNLOAD=0, SHADOW_REFETCH=2} NsfShadowOperations; typedef enum {NSF_PARAMS_NAMES, NSF_PARAMS_LIST, NSF_PARAMS_PARAMETER, NSF_PARAMS_SYNTAX} NsfParamsPrintStyle; int NsfCallCommand(Tcl_Interp *interp, NsfGlobalNames name, int objc, Tcl_Obj *CONST objv[]) nonnull(1) nonnull(4); int NsfShadowTclCommands(Tcl_Interp *interp, NsfShadowOperations load) nonnull(1); Tcl_Obj *NsfMethodObj(NsfObject *object, int methodIdx) nonnull(1); /* * Next Scripting CallStack */ typedef struct NsfCallStackContent { NsfObject *self; NsfClass *cl; Tcl_Command cmdPtr; NsfFilterStack *filterStackEntry; Tcl_Obj *CONST* objv; int objc; unsigned int flags; unsigned short frameType; #if defined(NSF_PROFILE) || defined(NSF_DTRACE) long int startUsec; long int startSec; CONST char *methodName; #endif } NsfCallStackContent; #define NSF_CSC_TYPE_PLAIN 0U #define NSF_CSC_TYPE_ACTIVE_MIXIN 1U #define NSF_CSC_TYPE_ACTIVE_FILTER 2U #define NSF_CSC_TYPE_INACTIVE 4U #define NSF_CSC_TYPE_INACTIVE_MIXIN 5U #define NSF_CSC_TYPE_INACTIVE_FILTER 6U #define NSF_CSC_TYPE_GUARD 0x10U #define NSF_CSC_TYPE_ENSEMBLE 0x20U #define NSF_CSC_CALL_IS_NEXT 1U #define NSF_CSC_CALL_IS_GUARD 2U #define NSF_CSC_CALL_IS_ENSEMBLE 4U #define NSF_CSC_CALL_IS_COMPILE 8U #define NSF_CSC_IMMEDIATE 0x000000100U #define NSF_CSC_FORCE_FRAME 0x000000200U #define NSF_CSC_CALL_NO_UNKNOWN 0x000000400U #define NSF_CSC_CALL_IS_NRE 0x000002000U #define NSF_CSC_MIXIN_STACK_PUSHED 0x000004000U #define NSF_CSC_FILTER_STACK_PUSHED 0x000008000U #define NSF_CSC_METHOD_IS_UNKNOWN 0x000010000U /* flags for call method */ #define NSF_CM_NO_UNKNOWN 0x000000001U #define NSF_CM_NO_SHIFT 0x000000002U #define NSF_CM_IGNORE_PERMISSIONS 0x000000004U #define NSF_CM_NO_OBJECT_METHOD 0x000000008U #define NSF_CM_SYSTEM_METHOD 0x000000010U #define NSF_CM_LOCAL_METHOD 0x000000020U #define NSF_CM_INTRINSIC_METHOD 0x000000040U #define NSF_CM_KEEP_CALLER_SELF 0x000000080U #define NSF_CM_ENSEMBLE_UNKNOWN 0x008000000U #define NSF_CSC_COPY_FLAGS (NSF_CSC_MIXIN_STACK_PUSHED|NSF_CSC_FILTER_STACK_PUSHED|NSF_CSC_IMMEDIATE|NSF_CSC_FORCE_FRAME|NSF_CM_LOCAL_METHOD) #define NSF_VAR_TRIGGER_TRACE 1 #define NSF_VAR_REQUIRE_DEFINED 2 #define NSF_VAR_ISARRAY 4 /* * Tcl uses 01 and 02, TclOO uses 04 and 08, so leave some space free * for further extensions of tcl and tcloo... */ #define FRAME_IS_NSF_OBJECT 0x10000U #define FRAME_IS_NSF_METHOD 0x20000U #define FRAME_IS_NSF_CMETHOD 0x40000U #if defined(NRE) # define NRE_SANE_PATCH 1 # define NsfImmediateFromCallerFlags(flags) \ (((flags) & (NSF_CSC_CALL_IS_NRE|NSF_CSC_IMMEDIATE)) == NSF_CSC_CALL_IS_NRE ? 0 : NSF_CSC_IMMEDIATE) # if defined(NRE_SANE_PATCH) # define NsfNRRunCallbacks(interp, result, rootPtr) TclNRRunCallbacks(interp, result, rootPtr) # if !defined(TclStackFree) # define TclStackFree(interp, ptr) ckfree(ptr) # define TclStackAlloc(interp, size) ckalloc(size) # endif # else # define NsfNRRunCallbacks(interp, result, rootPtr) TclNRRunCallbacks(interp, result, rootPtr, 0) # define TEOV_callback NRE_callback # endif #endif #if defined(NSF_PROFILE) typedef struct NsfProfile { long int overallTime; long int startSec; long int startUSec; Tcl_HashTable objectData; Tcl_HashTable methodData; Tcl_HashTable procData; } NsfProfile; #endif typedef struct NsfRuntimeState { /* * The defined object systems */ struct NsfObjectSystem *objectSystems; /* * namespaces and cmds */ Tcl_Namespace *NsfNS; /* the ::nsf namespace */ Tcl_Namespace *NsfClassesNS; /* the ::nsf::classes namespace, where classes are created physically */ Tcl_ObjCmdProc *objInterpProc; /* cached result of TclGetObjInterpProc() */ Tcl_Command colonCmd; /* cmdPtr of cmd ":" to dispatch via cmdResolver */ Proc fakeProc; /* dummy proc strucure, used for C-implemented methods with local scope */ Tcl_Command currentMixinCmdPtr; /* cmdPtr of currently active mixin, used for "info activemixin" */ int objectMethodEpoch; int instanceMethodEpoch; #if defined(PER_OBJECT_PARAMETER_CACHING) int classParamPtrEpoch; #endif Tcl_Obj **methodObjNames; /* global objects of nsf */ struct NsfShadowTclCommandInfo *tclCommands; /* shadowed Tcl commands */ #if defined(CHECK_ACTIVATION_COUNTS) NsfClasses *cscList; #endif int errorCount; /* keep track of number of errors to avoid potential error loops */ int unknown; /* keep track whether an unknown method is currently called */ int overloadedMethods; /* bitarray for tracking overloaded methods */ /* * Configure options. The following do*-flags could be moved into a * bitarray, but we have only one state per interp, so the win on * memory is very little. */ int debugLevel; int doCheckArguments; int doCheckResults; int doFilters; int doKeepcmds; int doProfile; int doSoftrecreate; /* keep track of defined filters */ Tcl_HashTable activeFilterTablePtr; /* * shutdown handling */ int exitHandlerDestroyRound; #if defined(NSF_PROFILE) NsfProfile profile; #endif #if defined(NSF_STACKCHECK) void *bottomOfStack; void *maxStack; #endif NsfStringIncrStruct iss; /* used for new to create new symbols */ short guardCount; /* keep track of guard invocations */ ClientData clientData; } NsfRuntimeState; #define NSF_EXITHANDLER_OFF 0 #define NSF_EXITHANDLER_ON_SOFT_DESTROY 1 #define NSF_EXITHANDLER_ON_PHYSICAL_DESTROY 2 #ifdef NSF_OBJECTDATA EXTERN void NsfSetObjectData(struct NsfObject *obj, struct NsfClass *cl, ClientData data) nonnull(1) nonnull(2) nonnull(3); EXTERN int NsfGetObjectData(struct NsfObject *obj, struct NsfClass *cl, ClientData *data) nonnull(1) nonnull(2) nonnull(3); EXTERN int NsfUnsetObjectData(struct NsfObject *obj, struct NsfClass *cl) nonnull(1) nonnull(2); EXTERN void NsfFreeObjectData(NsfClass *cl) nonnull(1); #endif /* * NsfObject Reference Accounting */ EXTERN void NsfCleanupObject_(NsfObject *object) nonnull(1); #if defined(NSFOBJ_TRACE) # define NsfObjectRefCountIncr(obj) \ ((NsfObject *)obj)->refCount++; \ fprintf(stderr, "RefCountIncr %p count=%d %s\n", obj, ((NsfObject *)obj)->refCount, \ ((NsfObject *)obj)->cmdName?ObjStr(((NsfObject *)obj)->cmdName):"no name"); \ MEM_COUNT_ALLOC("NsfObject.refCount", obj) # define NsfObjectRefCountDecr(obj) \ (obj)->refCount--; \ fprintf(stderr, "RefCountDecr %p count=%d\n", obj, obj->refCount); \ MEM_COUNT_FREE("NsfObject.refCount", obj) #else # define NsfObjectRefCountIncr(obj) \ (obj)->refCount++; \ MEM_COUNT_ALLOC("NsfObject.refCount", obj) # define NsfObjectRefCountDecr(obj) \ (obj)->refCount--; \ MEM_COUNT_FREE("NsfObject.refCount", obj) #endif /* * * internally used API functions * */ #include "nsfIntDecls.h" /* * Profiling functions */ #if defined(NSF_PROFILE) EXTERN void NsfProfileRecordMethodData(Tcl_Interp* interp, NsfCallStackContent *cscPtr) nonnull(1) nonnull(2); EXTERN void NsfProfileRecordProcData(Tcl_Interp *interp, char *methodName, long startSec, long startUsec) nonnull(1) nonnull(2); EXTERN void NsfProfileInit(Tcl_Interp *interp) nonnull(1); EXTERN void NsfProfileFree(Tcl_Interp *interp) nonnull(1); EXTERN void NsfProfileClearData(Tcl_Interp *interp) nonnull(1); EXTERN void NsfProfileGetData(Tcl_Interp *interp) nonnull(1); EXTERN NsfCallStackContent *NsfCallStackGetTopFrame(Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr) nonnull(1); #endif /* * MEM Counting */ #ifdef NSF_MEM_COUNT void NsfMemCountAlloc(char *id, void *); void NsfMemCountFree(char *id, void *); void NsfMemCountInit(void); void NsfMemCountRelease(void); #endif /* NSF_MEM_COUNT */ /* * TCL_STACK_ALLOC_TRACE */ #if defined(TCL_STACK_ALLOC_TRACE) # define NsfTclStackFree(interp,ptr,msg) \ fprintf(stderr, "---- TclStackFree %p %s\n", ptr, msg);\ TclStackFree(interp,ptr) static char * NsfTclStackAlloc(Tcl_Interp *interp, size_t size, char *msg) { char *ptr = TclStackAlloc(interp, size); fprintf(stderr, "---- TclStackAlloc %p %s\n", ptr, msg); return ptr; } #else # define NsfTclStackFree(interp,ptr,msg) TclStackFree(interp,ptr) # define NsfTclStackAlloc(interp,size,msg) TclStackAlloc(interp,size) #endif /* * bytecode support */ #ifdef NSF_BYTECODE typedef struct NsfCompEnv { int bytecode; Command *cmdPtr; CompileProc *compileProc; Tcl_ObjCmdProc *callProc; } NsfCompEnv; typedef enum {INST_INITPROC, INST_NEXT, INST_SELF, INST_SELF_DISPATCH, LAST_INSTRUCTION} NsfByteCodeInstructions; Tcl_ObjCmdProc NsfInitProcNSCmd, NsfSelfDispatchCmd, NsfNextObjCmd, NsfGetSelfObjCmd; EXTERN NsfCompEnv *NsfGetCompEnv(void); int NsfDirectSelfDispatch(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) nonnull(1) nonnull(2); #endif EXTERN int NsfGetClassFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, NsfClass **clPtr, int withUnknown) nonnull(1) nonnull(2) nonnull(3); EXTERN int NsfObjDispatch(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) nonnull(1) nonnull(2) nonnull(4); EXTERN int NsfObjWrongArgs(Tcl_Interp *interp, CONST char *msg, Tcl_Obj *cmdName, Tcl_Obj *methodName, char *arglist) nonnull(1) nonnull(2); EXTERN CONST char *NsfMethodName(Tcl_Obj *methodObj) nonnull(1) returns_nonnull; EXTERN void NsfReportVars(Tcl_Interp *interp) nonnull(1); EXTERN void NsfDStringArgv(Tcl_DString *dsPtr, int objc, Tcl_Obj *CONST objv[]) nonnull(1) nonnull(3); EXTERN Tcl_Obj *NsfMethodNamePath(Tcl_Interp *interp, Tcl_CallFrame *framePtr, CONST char *methodName) nonnull(1) nonnull(3) returns_nonnull; /* * Definition of methodEpoch macros */ #if defined(METHOD_OBJECT_TRACE) # define NsfInstanceMethodEpochIncr(msg) \ RUNTIME_STATE(interp)->instanceMethodEpoch++; \ fprintf(stderr, "+++ instanceMethodEpoch %d %s\n", RUNTIME_STATE(interp)->instanceMethodEpoch, msg) # define NsfObjectMethodEpochIncr(msg) \ RUNTIME_STATE(interp)->objectMethodEpoch++; \ fprintf(stderr, "+++ objectMethodEpoch %d %s\n", RUNTIME_STATE(interp)->objectMethodEpoch, msg) #else # define NsfInstanceMethodEpochIncr(msg) RUNTIME_STATE(interp)->instanceMethodEpoch++ # define NsfObjectMethodEpochIncr(msg) RUNTIME_STATE(interp)->objectMethodEpoch++ #endif #if defined(PER_OBJECT_PARAMETER_CACHING) # define NsfClassParamPtrEpochIncr(msg) RUNTIME_STATE(interp)->classParamPtrEpoch++ #else # define NsfClassParamPtrEpochIncr(msg) #endif /* * NsfFlag type */ EXTERN Tcl_ObjType NsfFlagObjType; EXTERN int NsfFlagObjSet(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *baseParamPtr, int serial, Nsf_Param CONST *paramPtr, Tcl_Obj *payload, int flags); typedef struct { CONST Nsf_Param *signature; int serial; Nsf_Param CONST *paramPtr; Tcl_Obj *payload; unsigned int flags; } NsfFlag; #define NSF_FLAG_DASHDAH 0x01 #define NSF_FLAG_CONTAINS_VALUE 0x02 /* * NsfMethodContext type */ EXTERN Tcl_ObjType NsfInstanceMethodObjType; EXTERN Tcl_ObjType NsfObjectMethodObjType; EXTERN int NsfMethodObjSet(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_ObjType *objectType, void *context, int methodEpoch, Tcl_Command cmd, NsfClass *cl, unsigned int flags) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(6); typedef struct { void *context; int methodEpoch; Tcl_Command cmd; NsfClass *cl; unsigned int flags; } NsfMethodContext; /* functions from nsfUtil.c */ char *Nsf_ltoa(char *buf, long i, int *len) nonnull(1) nonnull(3); char *NsfStringIncr(NsfStringIncrStruct *iss) nonnull(1); void NsfStringIncrInit(NsfStringIncrStruct *iss) nonnull(1); void NsfStringIncrFree(NsfStringIncrStruct *iss) nonnull(1); /* * Nsf Enumeration type interface */ EXTERN void Nsf_EnumerationTypeInit(Tcl_Interp *interp) nonnull(1); EXTERN CONST char *Nsf_EnumerationTypeGetDomain(Nsf_TypeConverter *converter) nonnull(1); /* * Nsf Cmd definition interface */ EXTERN void Nsf_CmdDefinitionInit(Tcl_Interp *interp) nonnull(1); EXTERN Nsf_methodDefinition *Nsf_CmdDefinitionGet(Tcl_ObjCmdProc *proc) nonnull(1); #ifndef HAVE_STRNSTR char *strnstr(const char *buffer, const char *needle, size_t buffer_len); #endif /* In ANSI mode (ISO C89/90) compilers such as gcc and clang do not define the va_copy macro. However, they *do* in reasonably recent versions provide a prefixed (__*) one. The by-feature test below falls back to the prefixed version, if available, and provides a more general fallback to a simple assignment; this is primarily for MSVC; admittedly, this simplifcation is not generally portable to platform/compiler combos other then x86, but the best I can think of right now. One might constrain the assignment-fallback to a platform and leave va_copy undefined in uncaught platform cases (?). */ #ifndef va_copy #ifdef __va_copy #define va_copy(dest,src) __va_copy((dest),(src)) #else #define va_copy(dest,src) ((dest) = (src)) #endif #endif #endif /* _nsf_int_h_ */