1 /*
2 * nsfInt.h --
3 *
4 * Declarations of the internally used API Functions of the Next
5 * Scripting Framework.
6 *
7 * Copyright (C) 1999-2018 Gustaf Neumann (a, b)
8 * Copyright (C) 1999-2007 Uwe Zdun (a, b)
9 * Copyright (C) 2011-2018 Stefan Sobernig (b)
10 *
11 * (a) University of Essen
12 * Specification of Software Systems
13 * Altendorferstrasse 97-101
14 * D-45143 Essen, Germany
15 *
16 * (b) Vienna University of Economics and Business
17 * Institute of Information Systems and New Media
18 * A-1020, Welthandelsplatz 1
19 * Vienna, Austria
20 *
21 * This work is licensed under the MIT License
22 * https://www.opensource.org/licenses/MIT
23 *
24 * Copyright:
25 *
26 * Permission is hereby granted, free of charge, to any person obtaining a
27 * copy of this software and associated documentation files (the "Software"),
28 * to deal in the Software without restriction, including without limitation
29 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
30 * and/or sell copies of the Software, and to permit persons to whom the
31 * Software is furnished to do so, subject to the following conditions:
32 *
33 * The above copyright notice and this permission notice shall be included in
34 * all copies or substantial portions of the Software.
35 *
36 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
41 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
42 * DEALINGS IN THE SOFTWARE.
43 *
44 */
45
46 #ifndef _nsf_int_h_
47 #define _nsf_int_h_
48
49 /*
50 * Well behaved compiler with C99 support should define __STDC_VERSION__
51 */
52 #if defined(__STDC_VERSION__)
53 # if __STDC_VERSION__ >= 199901L
54 # define NSF_HAVE_C99
55 # endif
56 #endif
57
58 /*
59 * Starting with Visual Studio 2013, Microsoft provides C99 library support.
60 */
61 #if (!defined(NSF_HAVE_C99)) && defined(_MSC_VER) && (_MSC_VER >= 1800)
62 # define NSF_HAVE_C99
63 #endif
64
65 #if defined(_MSC_VER) && _MSC_VER < 1800
66 # undef HAVE_INTTYPES_H
67 #else
68 # define HAVE_INTTYPES_H 1
69 #include <inttypes.h>
70 #endif
71
72 #if !defined(HAVE_INTTYPES_H)
73 # if !defined(__PRIPTR_PREFIX)
74 # if defined(_LP64) || defined(_I32LPx) || defined(HAVE_64BIT) || defined(_WIN64) || defined(_WIN32)
75 # if defined(_WIN32)
76 # define __PRIPTR_PREFIX "ll"
77 # else
78 # define __PRIPTR_PREFIX "l"
79 # endif
80 # else
81 # define __PRIPTR_PREFIX
82 # endif
83 # endif
84 # ifndef PRIxPTR
85 # define PRIxPTR __PRIPTR_PREFIX "x"
86 # endif
87 #endif
88
89
90 /*
91 * Boolean type "bool" and constants
92 */
93 #ifdef NSF_HAVE_C99
94 /*
95 * C99
96 */
97 # include <stdbool.h>
98 # define NSF_TRUE true
99 # define NSF_FALSE false
100 #else
101 /*
102 * Not C99
103 */
104 # if defined(__cplusplus)
105 /*
106 * C++ is similar to C99, but no include necessary
107 */
108 # define NSF_TRUE true
109 # define NSF_FALSE false
110 # else
111 /*
112 * If everything fails, use int type and int values for bool
113 */
114 typedef int bool;
115 # define NSF_TRUE 1
116 # define NSF_FALSE 0
117 # endif
118 #endif
119
120
121 /*
122 * MinGW and MinGW-w64 provide both MSCRT-compliant and ANSI-compliant
123 * implementations of certain I/O operations (e.g., *printf()). By
124 * setting __USE_MINGW_ANSI_STDIO to 1 explicitly, we can assume the
125 * ANSI versions.
126 *
127 * Note: It is sufficient to test for __MINGW32__ to trap all MinGW
128 * tool chains, including 64bit versions. See
129 * https://sourceforge.net/p/predef/wiki/Compilers/#mingw-and-mingw-w64
130 */
131
132 #if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO)
133 # define __USE_MINGW_ANSI_STDIO 1
134 #endif
135
136 #include <tclInt.h>
137 #include "nsf.h"
138
139 #include <stdlib.h>
140 #include <string.h>
141 #include <assert.h>
142
143 #if defined(HAVE_TCL_COMPILE_H)
144 # include <tclCompile.h>
145 #endif
146
147 #if __GNUC_PREREQ(2, 95)
148 /* Use gcc branch prediction hint to minimize cost of e.g. DTrace
149 * ENABLED checks.
150 */
151 # define unlikely(x) (__builtin_expect((x), 0))
152 # define likely(x) (__builtin_expect((x), 1))
153 #else
154 # define unlikely(x) (x)
155 # define likely(x) (x)
156 #endif
157
158 #if __GNUC_PREREQ(2, 96)
159 # define pure __attribute__((pure))
160 #else
161 # define pure
162 #endif
163
164 #if __GNUC_PREREQ(3, 3)
165 # define nonnull(ARGS) __attribute__((__nonnull__(ARGS)))
166 #else
167 # define nonnull(ARGS)
168 #endif
169
170 #if __GNUC_PREREQ(4, 9)
171 # define returns_nonnull __attribute__((returns_nonnull))
172 #else
173 # define returns_nonnull
174 #endif
175
176 #define nonnull_assert(assertion) assert((assertion))
177 /*
178 * Tries to use gcc __attribute__ unused and mangles the name, so the
179 * attribute could not be used, if declared as unused.
180 */
181 #ifdef UNUSED
182 #elif __GNUC_PREREQ(2, 7)
183 # define UNUSED(x) UNUSED_ ## x __attribute__((unused))
184 #elif defined(__LCLINT__)
185 # define UNUSED(x) /*@unused@*/ (x)
186 #else
187 # define UNUSED(x) (x)
188 #endif
189
190 #if defined(NSF_DTRACE)
191 # include "nsfDTrace.h"
192 # define NSF_DTRACE_METHOD_ENTRY_ENABLED() unlikely(NSF_METHOD_ENTRY_ENABLED())
193 # define NSF_DTRACE_METHOD_RETURN_ENABLED() unlikely(NSF_METHOD_RETURN_ENABLED())
194 # define NSF_DTRACE_OBJECT_ALLOC_ENABLED() unlikely(NSF_OBJECT_ALLOC_ENABLED())
195 # define NSF_DTRACE_OBJECT_FREE_ENABLED() unlikely(NSF_OBJECT_FREE_ENABLED())
196 # define NSF_DTRACE_CONFIGURE_PROBE_ENABLED() unlikely(NSF_CONFIGURE_PROBE_ENABLED())
197 # define NSF_DTRACE_METHOD_ENTRY(a0, a1, a2, a3, a4) NSF_METHOD_ENTRY((a0), (a1), (a2), (a3), (a4))
198 # define NSF_DTRACE_METHOD_RETURN(a0, a1, a2, a3) NSF_METHOD_RETURN((a0), (a1), (a2), (a3))
199 # define NSF_DTRACE_OBJECT_ALLOC(a0, a1) NSF_OBJECT_ALLOC((a0), (a1))
200 # define NSF_DTRACE_OBJECT_FREE(a0, a1) NSF_OBJECT_FREE((a0), (a1))
201 # define NSF_DTRACE_CONFIGURE_PROBE(a0, a1) NSF_CONFIGURE_PROBE((a0), (a1))
202 #else
203 # define NSF_DTRACE_METHOD_ENTRY_ENABLED() 0
204 # define NSF_DTRACE_METHOD_RETURN_ENABLED() 0
205 # define NSF_DTRACE_OBJECT_ALLOC_ENABLED() 0
206 # define NSF_DTRACE_OBJECT_FREE_ENABLED() 0
207 # define NSF_DTRACE_CONFIGURE_PROBE_ENABLED() 0
208 # define NSF_DTRACE_METHOD_ENTRY(a0, a1, a2, a3, a4) {}
209 # define NSF_DTRACE_METHOD_RETURN(a0, a1, a2, a3) {}
210 # define NSF_DTRACE_OBJECT_ALLOC(a0, a1) {}
211 # define NSF_DTRACE_OBJECT_FREE(a0, a1) {}
212 # define NSF_DTRACE_CONFIGURE_PROBE(a0, a1) {}
213 #endif
214
215
216 #ifdef DMALLOC
217 # include "dmalloc.h"
218 #endif
219
220 /*
221 * Makros
222 */
223
224 #if defined(PRE86)
225 # define Tcl_NRCallObjProc(interp, proc, cd, objc, objv) \
226 (*(proc))((cd), (interp), (objc), (objv))
227 #endif
228
229 #ifdef NSF_MEM_COUNT
230 EXTERN int nsfMemCountInterpCounter;
231 typedef struct NsfMemCounter {
232 int peak;
233 int count;
234 } NsfMemCounter;
235 # define MEM_COUNT_ALLOC(id,p) NsfMemCountAlloc((id), (p))
236 # define MEM_COUNT_FREE(id,p) NsfMemCountFree((id), (p))
237 # define MEM_COUNT_INIT() NsfMemCountInit()
238 # define MEM_COUNT_RELEASE() NsfMemCountRelease()
239 #else
240 # define MEM_COUNT_ALLOC(id,p)
241 # define MEM_COUNT_FREE(id,p)
242 # define MEM_COUNT_INIT()
243 # define MEM_COUNT_RELEASE()
244 #endif
245
246 # define STRING_NEW(target, p, l) {char *tempValue = ckalloc((unsigned)(l)+1u); strncpy((tempValue), (p), (l)+1u); *((tempValue)+(l)) = '\0'; target = tempValue; MEM_COUNT_ALLOC(#target, (target));}
247 # define STRING_FREE(key, p) MEM_COUNT_FREE((key), (p)); ckfree((char*)(p))
248
249 #define DSTRING_INIT(dsPtr) Tcl_DStringInit(dsPtr); MEM_COUNT_ALLOC("DString",(dsPtr))
250 #define DSTRING_FREE(dsPtr) \
251 if ((dsPtr)->string != (dsPtr)->staticSpace) {Tcl_DStringFree(dsPtr);} MEM_COUNT_FREE("DString",(dsPtr))
252
253 #if defined(USE_ASSOC_DATA)
254 # define RUNTIME_STATE(interp) ((NsfRuntimeState*)Tcl_GetAssocData((interp), "NsfRuntimeState", NULL))
255 #else
256 # define RUNTIME_STATE(interp) ((NsfRuntimeState*)((Interp*)(interp))->globalNsPtr->clientData)
257 #endif
258
259 #define nr_elements(arr) ((int) (sizeof(arr) / sizeof((arr)[0])))
260
261 /*
262 * Tcl 8.6 uses (unsigned) per default
263 */
264 # define NEW(type) \
265 (type *)ckalloc((unsigned)sizeof(type)); MEM_COUNT_ALLOC(#type, NULL)
266 # define NEW_ARRAY(type,n) \
267 (type *)ckalloc((unsigned)sizeof(type)*(unsigned)(n)); MEM_COUNT_ALLOC(#type "*", NULL)
268 # define FREE(type, var) \
269 ckfree((char*) (var)); MEM_COUNT_FREE(#type,(var))
270
271 #define isAbsolutePath(m) (*(m) == ':' && (m)[1] == ':')
272 #define isArgsString(m) (\
273 *(m) == 'a' && (m)[1] == 'r' && (m)[2] == 'g' && (m)[3] == 's' && \
274 (m)[4] == '\0')
275 #define isBodyString(m) (\
276 *(m) == 'b' && (m)[1] == 'o' && (m)[2] == 'd' && (m)[3] == 'y' && \
277 (m)[4] == '\0')
278 #define isCheckString(m) (\
279 *(m) == 'c' && (m)[1] == 'h' && (m)[2] == 'e' && (m)[3] == 'c' && \
280 (m)[4] == 'k' && (m)[5] == '\0')
281 #define isCheckObjString(m) (\
282 *(m) == 'c' && (m)[1] == 'h' && (m)[2] == 'e' && (m)[3] == 'c' && \
283 (m)[4] == 'k' && (m)[5] == 'o' && (m)[6] == 'b' && (m)[7] == 'j' && \
284 (m)[8] == '\0')
285 #define isCreateString(m) (\
286 *(m) == 'c' && (m)[1] == 'r' && (m)[2] == 'e' && (m)[3] == 'a' && \
287 (m)[4] == 't' && (m)[5] == 'e' && (m)[6] == '\0')
288 #define isTypeString(m) (\
289 *(m) == 't' && (m)[1] == 'y' && (m)[2] == 'p' && (m)[3] == 'e' && \
290 (m)[4] == '\0')
291 #define isObjectString(m) (\
292 *(m) == 'o' && (m)[1] == 'b' && (m)[2] == 'j' && (m)[3] == 'e' && \
293 (m)[4] == 'c' && (m)[5] == 't' && (m)[6] == '\0')
294 #define isClassString(m) (\
295 *(m) == 'c' && (m)[1] == 'l' && (m)[2] == 'a' && (m)[3] == 's' && \
296 (m)[4] == 's' && (m)[5] == '\0')
297
298 #if (defined(sun) || defined(__hpux)) && !defined(__GNUC__)
299 # define USE_ALLOCA
300 #endif
301
302 #if defined(__IBMC__) && !defined(__GNUC__)
303 # if __IBMC__ >= 0x0306
304 # define USE_ALLOCA
305 # else
306 # define USE_MALLOC
307 # endif
308 #endif
309
310 #if defined(VISUAL_CC)
311 # define USE_MALLOC
312 #endif
313
314 #if 1
315 # define NSF_STACK_ALLOCATED_OBJV 32
316 # define ALLOC_ON_STACK(type,n,var) \
317 type *(var); type stack_allocated_##var[NSF_STACK_ALLOCATED_OBJV]; \
318 if (likely((n) < NSF_STACK_ALLOCATED_OBJV)) { (var) = &stack_allocated_##var[0]; } else { (var) = NEW_ARRAY(type, (n)); }
319 # define FREE_ON_STACK(type, var) \
320 if ((var) != &stack_allocated_##var[0]) { FREE(type *, var);}
321 #elif defined(__GNUC__) && !defined(USE_ALLOCA) && !defined(USE_MALLOC)
322 # if !defined(NDEBUG)
323 # define ALLOC_ON_STACK(type,n,var) \
324 int __##var##_count = (n); type __##var[(n)+2]; \
325 type *(var) = __##var + 1; (var)[-1] = var[__##var##_count] = (type)0xdeadbeaf
326 # define FREE_ON_STACK(type,var) \
327 assert((var)[-1] == (var)[__##var##_count] && (var)[-1] == (type)0xdeadbeaf)
328 # else
329 # define ALLOC_ON_STACK(type,n,var) type (var)[(n)]
330 # define FREE_ON_STACK(type,var)
331 # endif
332 #elif defined(USE_ALLOCA)
333 # define ALLOC_ON_STACK(type,n,var) type *(var) = (type *)alloca((n)*sizeof(type))
334 # define FREE_ON_STACK(type,var)
335 #else
336 # define ALLOC_ON_STACK(type,n,var) type *(var) = (type *)ckalloc((n)*sizeof(type))
337 # define FREE_ON_STACK(type,var) ckfree((char*)(var))
338 #endif
339
340 #ifdef USE_ALLOCA
341 # include <alloca.h>
342 #endif
343
344 #if !defined(NDEBUG)
345 # define ISOBJ(o) ((o) != NULL && ISOBJ_(o))
346 # define ISOBJ_(o) ((o) != (void*)0xdeadbeaf && (((o)->typePtr != NULL) ? ((o)->typePtr->name != NULL) : ((o)->bytes != NULL)) && (((o)->bytes != NULL) ? (o)->length >= -1 : 1) && (o)->refCount >= 0)
347 #else
348 # define ISOBJ(o)
349 #endif
350
351 #define NSF_ABBREV_MIN_CHARS 4
352 /*
353 * This was defined to be inline for anything !sun or __IBMC__ >= 0x0306,
354 * but __hpux should also be checked - switched to only allow in gcc - JH
355 */
356 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
357 # define NSF_INLINE inline
358 #else
359 # define NSF_INLINE
360 #endif
361
362 #ifdef USE_TCL_STUBS
363 # define DECR_REF_COUNT(A) \
364 MEM_COUNT_FREE("INCR_REF_COUNT" #A,(A)); assert((A)->refCount > -1); \
365 Tcl_DecrRefCount(A)
366 # define DECR_REF_COUNT2(name,A) \
367 MEM_COUNT_FREE("INCR_REF_COUNT-" name,(A)); assert((A)->refCount > -1); \
368 Tcl_DecrRefCount(A)
369 #else
370 # define DECR_REF_COUNT(A) \
371 MEM_COUNT_FREE("INCR_REF_COUNT" #A,(A)); TclDecrRefCount(A)
372 # define DECR_REF_COUNT2(name,A) \
373 MEM_COUNT_FREE("INCR_REF_COUNT-" name,(A)); TclDecrRefCount(A)
374 #endif
375
376 #define INCR_REF_COUNT(A) MEM_COUNT_ALLOC("INCR_REF_COUNT" #A,(A)); Tcl_IncrRefCount((A))
377 #define INCR_REF_COUNT2(name,A) \
378 /*fprintf(stderr, "c '%s'\n", ObjStr(A));*/ \
379 MEM_COUNT_ALLOC("INCR_REF_COUNT-" name,(A)); Tcl_IncrRefCount((A))
380
381 #define ObjStr(obj) ((obj)->bytes) ? ((obj)->bytes) : Tcl_GetString(obj)
382 #define ObjTypeStr(obj) (((obj)->typePtr != NULL) ? ((obj)->typePtr->name) : "NONE")
383 #define ClassName(cl) (((cl) != NULL) ? ObjStr((cl)->object.cmdName) : "NULL")
384 #define ClassName_(cl) (ObjStr((cl)->object.cmdName))
385 #define ObjectName(object) (((object) != NULL) ? ObjStr((object)->cmdName) : "NULL")
386 #define ObjectName_(object) (ObjStr((object)->cmdName))
387
388 #ifdef OBJDELETION_TRACE
389 # define PRINTOBJ(ctx,object) \
390 fprintf(stderr, " %s %p %s oid=%p teardown=%p destroyCalled=%d\n", \
391 (ctx),(object),(object)->teardown?ObjStr((object)->cmdName):"(deleted)", \
392 (object)->id, (object)->teardown, \
393 ((object)->flags & NSF_DESTROY_CALLED))
394 #else
395 # define PRINTOBJ(ctx,object)
396 #endif
397
398 /*
399 * When an integer is printed, it might take so many digits
400 */
401 #define LONG_AS_STRING 32
402
403 /* TCL_CONTINUE is defined as 4, from 5 on we can
404 use app-specific return codes */
405 #define NSF_CHECK_FAILED 6
406
407
408 /*
409 The NsfConfigEnabled() macro allows for querying whether a
410 configuration macro (NSF_*; see above) is actually defined (and
411 whether it expands to 1). This macro can be used both in CPP
412 expressions (e.g., "#if NsfConfigEnabled(...)") and in C expressions
413 (e.g., "if(NsfConfigEnabled(...))")
414 */
415
416 #define NsfConfigEnabled__NOOP(...)
417 #define NsfConfigEnabled__open (
418 #define NsfConfigEnabled__close )
419 #define NsfConfigEnabled__caller(macro, args) macro args
420 #define NsfConfigEnabled__helper_1 NsfConfigEnabled__close NsfConfigEnabled__open 1
421 #define NsfConfigEnabled__(x) (NsfConfigEnabled__caller(NsfConfigEnabled__NOOP, \
422 NsfConfigEnabled__open \
423 NsfConfigEnabled__helper_##x \
424 NsfConfigEnabled__close) + 0)
425 #define NsfConfigEnabled_(x) NsfConfigEnabled__(x)
426 #define NsfConfigEnabled(x) NsfConfigEnabled_(NSF_##x)
427
428
429 /*
430 *
431 * Next Scripting Structures
432 *
433 */
434
435 /*
436 * Filter structures
437 */
438 typedef struct NsfFilterStack {
439 Tcl_Command currentCmdPtr;
440 Tcl_Obj *calledProc;
441 struct NsfFilterStack *nextPtr;
442 } NsfFilterStack;
443
444
445 /*
446 * Assertion structures
447 */
448
449 typedef struct NsfTclObjList {
450 Tcl_Obj *content;
451 Tcl_Obj *payload;
452 struct NsfTclObjList *nextPtr;
453 } NsfTclObjList;
454
455 typedef struct NsfProcAssertion {
456 NsfTclObjList *pre;
457 NsfTclObjList *post;
458 } NsfProcAssertion;
459
460 typedef struct NsfAssertionStore {
461 NsfTclObjList *invariants;
462 Tcl_HashTable procs;
463 } NsfAssertionStore;
464
465 typedef enum { /* powers of 2; add to ALL, if default; */
466 CHECK_NONE = 0,
467 CHECK_CLINVAR = 1,
468 CHECK_OBJINVAR = 2,
469 CHECK_PRE = 4,
470 CHECK_POST = 8,
471 CHECK_INVAR = CHECK_CLINVAR + CHECK_OBJINVAR,
472 CHECK_ALL = CHECK_INVAR + CHECK_PRE + CHECK_POST
473 } CheckOptions;
474
475 void NsfAssertionRename(Tcl_Interp *interp, Tcl_Command cmd,
476 NsfAssertionStore *as,
477 char *oldSimpleCmdName, char *newName);
478 /*
479 * mixins
480 */
481 typedef struct NsfMixinStack {
482 Tcl_Command currentCmdPtr;
483 struct NsfMixinStack *nextPtr;
484 } NsfMixinStack;
485
486 /*
487 * Generic command pointer list
488 */
489 typedef struct NsfCmdList {
490 Tcl_Command cmdPtr;
491 ClientData clientData;
492 struct NsfClass *clorobj;
493 struct NsfCmdList *nextPtr;
494 } NsfCmdList;
495
496 typedef void (NsfFreeCmdListClientData) (NsfCmdList*);
497
498 /* for incr string */
499 typedef struct NsfStringIncrStruct {
500 char *buffer;
501 char *start;
502 size_t bufSize;
503 size_t length;
504 } NsfStringIncrStruct;
505
506
507 /*
508 * cmd flags
509 */
510
511 #define NSF_CMD_CALL_PROTECTED_METHOD 0x00010000
512 #define NSF_CMD_CALL_PRIVATE_METHOD 0x00020000
513 #define NSF_CMD_REDEFINE_PROTECTED_METHOD 0x00040000
514 /* NSF_CMD_NONLEAF_METHOD is used to flag, if a Method implemented via cmd calls "next" */
515 #define NSF_CMD_NONLEAF_METHOD 0x00080000
516 #define NSF_CMD_CLASS_ONLY_METHOD 0x00100000
517 #define NSF_CMD_DEPRECATED_METHOD 0x00200000
518 #define NSF_CMD_DEBUG_METHOD 0x00400000
519
520 /*
521 * traceEvalFlags controlling NsfDStringEval
522 */
523 #define NSF_EVAL_SAVE 0x01u /* save interp context */
524 #define NSF_EVAL_NOPROFILE 0x02u /* no profile below this call */
525 #define NSF_EVAL_DEBUG 0x04u /* call is a debug call, prevent recursion */
526 #define NSF_EVAL_LOG 0x08u /* call is a log call, prevent recursion */
527 #define NSF_EVAL_DEPRECATED 0x10u /* call is a deprecated call, prevent recursion */
528
529 #define NSF_EVAL_PREVENT_RECURSION (NSF_EVAL_DEBUG|NSF_EVAL_LOG|NSF_EVAL_DEPRECATED)
530
531 /*
532 * object flags ...
533 */
534
535 /* DESTROY_CALLED indicates that destroy was called on obj */
536 #define NSF_DESTROY_CALLED 0x0001u
537 /* INIT_CALLED indicates that init was called on obj */
538 #define NSF_INIT_CALLED 0x0002u
539 /* MIXIN_ORDER_VALID set when mixin order is valid */
540 #define NSF_MIXIN_ORDER_VALID 0x0004u
541 /* MIXIN_ORDER_DEFINED set, when mixins are defined for obj */
542 #define NSF_MIXIN_ORDER_DEFINED 0x0008u
543 #define NSF_MIXIN_ORDER_DEFINED_AND_VALID 0x000cu
544 /* FILTER_ORDER_VALID set, when filter order is valid */
545 #define NSF_FILTER_ORDER_VALID 0x0010u
546 /* FILTER_ORDER_DEFINED set, when filters are defined for obj */
547 #define NSF_FILTER_ORDER_DEFINED 0x0020u
548 #define NSF_FILTER_ORDER_DEFINED_AND_VALID 0x0030u
549 /* class and object properties for objects */
550 #define NSF_IS_CLASS 0x0040u
551 #define NSF_IS_ROOT_META_CLASS 0x0080u
552 #define NSF_IS_ROOT_CLASS 0x0100u
553 #define NSF_IS_SLOT_CONTAINER 0x0200u
554 #define NSF_KEEP_CALLER_SELF 0x0400u
555 #define NSF_PER_OBJECT_DISPATCH 0x0800u
556 #define NSF_HAS_PER_OBJECT_SLOTS 0x1000u
557 #define NSF_IS_AUTONAMED 0x2000u
558 /* deletion states */
559 #define NSF_DESTROY_CALLED_SUCCESS 0x010000u /* requires flags to be int, not short */
560 #define NSF_DURING_DELETE 0x020000u
561 #define NSF_DELETED 0x040000u
562 #define NSF_RECREATE 0x080000u
563 #define NSF_TCL_DELETE 0x100000u
564
565
566 /* method invocations */
567 #define NSF_ARG_METHOD_INVOCATION (NSF_ARG_ALIAS|NSF_ARG_FORWARD|NSF_ARG_INITCMD|NSF_ARG_CMD)
568 #define NSF_ARG_METHOD_CALL (NSF_ARG_ALIAS|NSF_ARG_FORWARD)
569
570 /* Disallowed parameter options */
571 #define NSF_DISALLOWED_ARG_METHOD_PARAMETER (NSF_ARG_METHOD_INVOCATION|NSF_ARG_NOCONFIG|NSF_ARG_SLOTSET|NSF_ARG_SLOTINITIALIZE)
572 #define NSF_DISALLOWED_ARG_SETTER (NSF_ARG_SWITCH|NSF_ARG_SUBST_DEFAULT|NSF_DISALLOWED_ARG_METHOD_PARAMETER)
573 /*#define NSF_DISALLOWED_ARG_OBJECT_PARAMETER (NSF_ARG_SWITCH)*/
574 #define NSF_DISALLOWED_ARG_OBJECT_PARAMETER 0
575 #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)
576
577 /* flags for ParseContext */
578 #define NSF_PC_MUST_DECR 0x0001u
579 #define NSF_PC_IS_DEFAULT 0x0002u
580 #define NSF_PC_INVERT_DEFAULT 0x0010u
581
582 #define NSF_PC_STATUS_MUST_DECR 0x0001u
583 #define NSF_PC_STATUS_FREE_OBJV 0x0002u
584 #define NSF_PC_STATUS_FREE_CD 0x0004u
585
586
587 /* method types */
588 #define NSF_METHODTYPE_ALIAS 0x0001
589 #define NSF_METHODTYPE_SCRIPTED 0x0002
590 #define NSF_METHODTYPE_SETTER 0x0004
591 #define NSF_METHODTYPE_FORWARDER 0x0008
592 #define NSF_METHODTYPE_OBJECT 0x0010
593 #define NSF_METHODTYPE_NSFPROC 0x0020
594 #define NSF_METHODTYPE_OTHER 0x0100
595 #define NSF_METHODTYPE_BUILTIN NSF_METHODTYPE_ALIAS|NSF_METHODTYPE_SETTER|NSF_METHODTYPE_FORWARDER|NSF_METHODTYPE_OTHER
596 #define NSF_METHODTYPE_ALL NSF_METHODTYPE_SCRIPTED|NSF_METHODTYPE_BUILTIN|NSF_METHODTYPE_OBJECT
597
598
599 #define NsfObjectSetClass(object) \
600 (object)->flags |= NSF_IS_CLASS
601 #define NsfObjectClearClass(object) \
602 (object)->flags &= ~NSF_IS_CLASS
603 #define NsfObjectIsClass(object) \
604 ((object)->flags & NSF_IS_CLASS)
605 #define NsfObjectToClass(object) \
606 (NsfClass *)((((NsfObject *)object)->flags & NSF_IS_CLASS) ? object : NULL)
607
608
609 /*
610 * object and class internals
611 */
612
613 typedef struct NsfParamDefs {
614 Nsf_Param *paramsPtr;
615 int nrParams;
616 int refCount;
617 int serial;
618 } NsfParamDefs;
619
620 typedef struct NsfParsedParam {
621 NsfParamDefs *paramDefs;
622 int possibleUnknowns;
623 } NsfParsedParam;
624
625 typedef struct NsfObjectOpt {
626 NsfAssertionStore *assertions;
627 NsfCmdList *objFilters;
628 NsfCmdList *objMixins;
629 ClientData clientData;
630 const char *volatileVarName;
631 #if defined(PER_OBJECT_PARAMETER_CACHING)
632 NsfParsedParam *parsedParamPtr;
633 unsigned int classParamPtrEpoch;
634 #endif
635 CheckOptions checkoptions;
636 } NsfObjectOpt;
637
638 typedef struct NsfObject {
639 Tcl_Obj *cmdName;
640 Tcl_Command id;
641 Tcl_Interp *teardown;
642 struct NsfClass *cl;
643 TclVarHashTable *varTablePtr;
644 Tcl_Namespace *nsPtr;
645 NsfObjectOpt *opt;
646 struct NsfCmdList *filterOrder;
647 struct NsfCmdList *mixinOrder;
648 NsfFilterStack *filterStack;
649 NsfMixinStack *mixinStack;
650 int refCount;
651 unsigned int flags;
652 short activationCount;
653 } NsfObject;
654
655 typedef struct NsfClassOpt {
656 NsfCmdList *classFilters;
657 NsfCmdList *classMixins;
658 NsfCmdList *isObjectMixinOf;
659 NsfCmdList *isClassMixinOf;
660 NsfAssertionStore *assertions;
661 Tcl_Obj *mixinRegObjs;
662 #ifdef NSF_OBJECTDATA
663 Tcl_HashTable *objectdata;
664 #endif
665 Tcl_Command id;
666 ClientData clientData;
667 } NsfClassOpt;
668
669 typedef struct NsfClass {
670 struct NsfObject object;
671 struct NsfClasses *super;
672 struct NsfClasses *sub;
673 struct NsfObjectSystem *osPtr;
674 struct NsfClasses *order;
675 Tcl_HashTable instances;
676 Tcl_Namespace *nsPtr;
677 NsfParsedParam *parsedParamPtr;
678 NsfClassOpt *opt;
679 short color;
680 } NsfClass;
681
682 typedef struct NsfClasses {
683 struct NsfClass *cl;
684 ClientData clientData;
685 struct NsfClasses *nextPtr;
686 } NsfClasses;
687
688 /*
689 * needed in nsf.c and in nsfShadow
690 */
691 #define NSF_PROC_FLAG_AD 0x01u
692 #define NSF_PROC_FLAG_CHECK_ALWAYS 0x02u
693
694 typedef struct NsfProcClientData {
695 Tcl_Obj *procName;
696 Tcl_Command cmd;
697 Tcl_Command wrapperCmd;
698 NsfParamDefs *paramDefs;
699 unsigned int flags;
700 Tcl_Interp *interp;
701 } NsfProcClientData;
702
703 typedef enum SystemMethodsIdx {
704 NSF_c_alloc_idx,
705 NSF_c_create_idx,
706 NSF_c_dealloc_idx,
707 NSF_c_configureparameter_idx,
708 NSF_c_recreate_idx,
709 NSF_o_cleanup_idx,
710 NSF_o_configure_idx,
711 NSF_o_configureparameter_idx,
712 NSF_o_defaultmethod_idx,
713 NSF_o_destroy_idx,
714 NSF_o_init_idx,
715 NSF_o_move_idx,
716 NSF_o_unknown_idx,
717 NSF_s_get_idx,
718 NSF_s_set_idx
719 } SystemMethodsIdx;
720
721 #if !defined(NSF_C)
722 EXTERN const char *Nsf_SystemMethodOpts[];
723 #else
724 const char *Nsf_SystemMethodOpts[] = {
725 "-class.alloc",
726 "-class.create",
727 "-class.dealloc",
728 "-class.configureparameter",
729 "-class.recreate",
730 "-object.cleanup",
731 "-object.configure",
732 "-object.configureparameter",
733 "-object.defaultmethod",
734 "-object.destroy",
735 "-object.init",
736 "-object.move",
737 "-object.unknown",
738 "-slot.get",
739 "-slot.set",
740 NULL
741 };
742 #endif
743
744 typedef struct NsfObjectSystem {
745 NsfClass *rootClass;
746 NsfClass *rootMetaClass;
747 unsigned int overloadedMethods;
748 unsigned int definedMethods;
749 Tcl_Obj *methods[NSF_s_set_idx+2];
750 const char *methodNames[NSF_s_set_idx+2];
751 Tcl_Obj *handles[NSF_s_set_idx+2];
752 struct NsfObjectSystem *nextPtr;
753 char protected[NSF_s_set_idx+2];
754 } NsfObjectSystem;
755
756
757 /*
758 * Next Scripting global names and strings
759 *
760 * We provide enums for efficient lookup for corresponding string
761 * names and Tcl_Objs via global arrays. The "constant" Tcl_Objs are
762 * built at start-up-time via Nsf_Init().
763 */
764
765 typedef enum {
766 NSF_EMPTY, NSF_ZERO, NSF_ONE,
767 /* methods called internally */
768 NSF_CONFIGURE, NSF_INITIALIZE, NSF_GET_PARAMETER_SPEC,
769 NSF_SLOT_GET, NSF_SLOT_SET,
770 /* var names */
771 NSF_AUTONAMES, NSF_DEFAULTMETACLASS, NSF_DEFAULTSUPERCLASS,
772 NSF_ARRAY_INITCMD, NSF_ARRAY_CMD,
773 NSF_ARRAY_ALIAS, NSF_ARRAY_PARAMETERSYNTAX,
774 NSF_POSITION, NSF_POSITIONAL, NSF_CONFIGURABLE, NSF_PARAMETERSPEC,
775 /* object/class names */
776 NSF_METHOD_PARAMETER_SLOT_OBJ,
777 /* constants */
778 NSF_ALIAS, NSF_ARGS, NSF_CMD, NSF_FILTER, NSF_FORWARD,
779 NSF_METHOD, NSF_OBJECT, NSF_SETTER, NSF_SETTERNAME, NSF_VALUECHECK,
780 NSF_GUARD_OPTION, NSF___UNKNOWN__, NSF_ARRAY, NSF_GET, NSF_SET, NSF_OPTION_STRICT, NSF_SCRIPT,
781 NSF_OBJECT_UNKNOWN_HANDLER, NSF_ARGUMENT_UNKNOWN_HANDLER,
782 NSF_PARSE_ARGS,
783 /* Partly redefined Tcl commands; leave them together at the end */
784 NSF_EXPR, NSF_FORMAT, NSF_INFO_BODY, NSF_INFO_FRAME, NSF_INTERP,
785 NSF_STRING_IS, NSF_EVAL, NSF_DISASSEMBLE,
786 NSF_RENAME
787 } NsfGlobalNames;
788 #if !defined(NSF_C)
789 EXTERN const char *NsfGlobalStrings[];
790 #else
791 const char *NsfGlobalStrings[] = {
792 "", "0", "1",
793 /* methods called internally */
794 "configure", "initialize", "getParameterSpec",
795 "value=get", "value=set",
796 /* var names */
797 "__autonames", "__default_metaclass", "__default_superclass", "__initcmd", "__cmd",
798 "::nsf::alias", "::nsf::parameter::syntax",
799 "position", "positional", "configurable", "parameterSpec",
800 /* object/class names */
801 "::nx::methodParameterSlot",
802 /* constants */
803 "alias", "args", "cmd", "filter", "forward",
804 "method", "object", "setter", "settername", "valuecheck",
805 "-guard", "__unknown__", "::array", "get", "set", "-strict", "script",
806 /* nsf Tcl commands */
807 "::nsf::object::unknown",
808 "::nsf::argument::unknown",
809 "::nsf::parseargs",
810 /* Tcl commands */
811 "expr", "format", "::tcl::info::body", "::tcl::info::frame", "interp",
812 "::tcl::string::is", "::eval", "::tcl::unsupported::disassemble",
813 "rename"
814 };
815 #endif
816
817 #define NsfGlobalObjs RUNTIME_STATE(interp)->methodObjNames
818
819 /*
820 * Interface for Tcl_Obj types
821 */
822 EXTERN Tcl_ObjType NsfMixinregObjType;
823 EXTERN int NsfMixinregGet(Tcl_Interp *interp, Tcl_Obj *obj, NsfClass **classPtr, Tcl_Obj **guardObj)
824 nonnull(1) nonnull(2) nonnull(3) nonnull(4);
825 EXTERN int NsfMixinregInvalidate(Tcl_Interp *interp, Tcl_Obj *obj)
826 nonnull(1) nonnull(2);
827
828 EXTERN Tcl_ObjType NsfFilterregObjType;
829 EXTERN int NsfFilterregGet(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_Obj **filterObj, Tcl_Obj **guardObj)
830 nonnull(1) nonnull(2) nonnull(3) nonnull(4);
831
832 EXTERN NsfClassOpt *NsfRequireClassOpt(NsfClass *class)
833 nonnull(1) returns_nonnull;
834
835
836 /*
837 * Next Scripting ShadowTclCommands
838 */
839 typedef struct NsfShadowTclCommandInfo {
840 TclObjCmdProcType proc;
841 ClientData clientData;
842 int nrArgs;
843 } NsfShadowTclCommandInfo;
844 typedef enum {SHADOW_LOAD=1, SHADOW_UNLOAD=0, SHADOW_REFETCH=2} NsfShadowOperations;
845
846
847 typedef enum {NSF_PARAMS_NAMES, NSF_PARAMS_LIST,
848 NSF_PARAMS_PARAMETER, NSF_PARAMS_SYNTAX} NsfParamsPrintStyle;
849
850 int NsfCallCommand(Tcl_Interp *interp, NsfGlobalNames name,
851 int objc, Tcl_Obj *const objv[])
852 nonnull(1) nonnull(4);
853
854 int NsfShadowTclCommands(Tcl_Interp *interp, NsfShadowOperations load)
855 nonnull(1);
856
857 Tcl_Obj *NsfMethodObj(const NsfObject *object, int methodIdx)
858 nonnull(1) pure;
859
860 int NsfReplaceCommandCleanup(Tcl_Interp *interp, Tcl_Obj *nameObj, NsfShadowTclCommandInfo *ti)
861 nonnull(1) nonnull(2) nonnull(3);
862
863 int NsfReplaceCommand(Tcl_Interp *interp, Tcl_Obj *nameObj,
864 Tcl_ObjCmdProc *nsfReplacementProc,
865 ClientData cd,
866 NsfShadowTclCommandInfo *ti)
867 nonnull(1) nonnull(2) nonnull(5);
868
869
870 /*
871 * Next Scripting CallStack
872 */
873 typedef struct NsfCallStackContent {
874 NsfObject *self;
875 NsfClass *cl;
876 Tcl_Command cmdPtr;
877 NsfFilterStack *filterStackEntry;
878 Tcl_Obj *const* objv;
879 int objc;
880 unsigned int flags;
881 #if defined(NSF_PROFILE) || defined(NSF_DTRACE)
882 long int startUsec;
883 long int startSec;
884 const char *methodName;
885 #endif
886 unsigned short frameType;
887 } NsfCallStackContent;
888
889 #define NSF_CSC_TYPE_PLAIN 0u
890 #define NSF_CSC_TYPE_ACTIVE_MIXIN 1u
891 #define NSF_CSC_TYPE_ACTIVE_FILTER 2u
892 #define NSF_CSC_TYPE_INACTIVE 4u
893 #define NSF_CSC_TYPE_INACTIVE_MIXIN 5u
894 #define NSF_CSC_TYPE_INACTIVE_FILTER 6u
895 #define NSF_CSC_TYPE_GUARD 0x10u
896 #define NSF_CSC_TYPE_ENSEMBLE 0x20u
897
898 #define NSF_CSC_CALL_IS_NEXT 1u
899 #define NSF_CSC_CALL_IS_GUARD 2u
900 #define NSF_CSC_CALL_IS_ENSEMBLE 4u
901 #define NSF_CSC_CALL_IS_COMPILE 8u
902
903
904 #define NSF_CSC_IMMEDIATE 0x000000100u
905 #define NSF_CSC_FORCE_FRAME 0x000000200u
906 #define NSF_CSC_CALL_NO_UNKNOWN 0x000000400u
907 #define NSF_CSC_CALL_IS_NRE 0x000002000u
908 #define NSF_CSC_MIXIN_STACK_PUSHED 0x000004000u
909 #define NSF_CSC_FILTER_STACK_PUSHED 0x000008000u
910 #define NSF_CSC_METHOD_IS_UNKNOWN 0x000010000u
911
912 /* flags for call method */
913 #define NSF_CM_NO_UNKNOWN 0x000000001u
914 #define NSF_CM_NO_SHIFT 0x000000002u
915 #define NSF_CM_IGNORE_PERMISSIONS 0x000000004u
916 #define NSF_CM_NO_OBJECT_METHOD 0x000000008u
917 #define NSF_CM_SYSTEM_METHOD 0x000000010u
918 #define NSF_CM_LOCAL_METHOD 0x000000020u
919 #define NSF_CM_INTRINSIC_METHOD 0x000000040u
920 #define NSF_CM_KEEP_CALLER_SELF 0x000000080u
921 #define NSF_CM_ENSEMBLE_UNKNOWN 0x008000000u
922
923
924 #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)
925
926 #define NSF_VAR_TRIGGER_TRACE 1
927 #define NSF_VAR_REQUIRE_DEFINED 2
928 #define NSF_VAR_ISARRAY 4
929
930 /*
931 * Tcl uses 01 and 02, TclOO uses 04 and 08, so leave some space free
932 * for further extensions of Tcl and tcloo...
933 */
934 #define FRAME_IS_NSF_OBJECT 0x10000u
935 #define FRAME_IS_NSF_METHOD 0x20000u
936 #define FRAME_IS_NSF_CMETHOD 0x40000u
937 #define FRAME_VAR_LOADED 0x80000u
938
939 #if defined(NRE)
940 # define NRE_SANE_PATCH 1
941 # define NsfImmediateFromCallerFlags(flags) \
942 (((flags) & (NSF_CSC_CALL_IS_NRE|NSF_CSC_IMMEDIATE)) == NSF_CSC_CALL_IS_NRE ? 0 : NSF_CSC_IMMEDIATE)
943 # if defined(NRE_SANE_PATCH)
944 # define NsfNRRunCallbacks(interp, result, rootPtr) TclNRRunCallbacks(interp, result, rootPtr)
945 # if !defined(TclStackFree)
946 # define TclStackFree(interp, ptr) ckfree(ptr)
947 # define TclStackAlloc(interp, size) ckalloc(size)
948 # endif
949 # else
950 # define NsfNRRunCallbacks(interp, result, rootPtr) TclNRRunCallbacks(interp, result, rootPtr, 0)
951 # define TEOV_callback NRE_callback
952 # endif
953 #endif
954
955 #if defined(NSF_PROFILE)
956 typedef struct NsfProfile {
957 long int overallTime;
958 long int startSec;
959 long int startUSec;
960 Tcl_HashTable objectData;
961 Tcl_HashTable methodData;
962 Tcl_HashTable procData;
963 Tcl_DString traceDs;
964 int depth;
965 int verbose;
966 Tcl_Obj *shadowedObjs;
967 NsfShadowTclCommandInfo *shadowedTi;
968 int inmemory;
969 } NsfProfile;
970
971 # define NSF_PROFILE_TIME_DATA struct Tcl_Time profile_trt
972 # define NSF_PROFILE_CALL(interp, object, methodName) \
973 Tcl_GetTime(&profile_trt); \
974 NsfProfileTraceCall(interp, object, NULL, methodName)
975 # define NSF_PROFILE_EXIT(interp, object, methodName) \
976 NsfProfileTraceExit(interp, object, NULL, methodName, &profile_trt)
977 #else
978 # define NSF_PROFILE_TIME_DATA
979 # define NSF_PROFILE_CALL(interp, object, methodName)
980 # define NSF_PROFILE_EXIT(interp, object, methodName)
981 #endif
982
983 typedef struct NsfList {
984 void *data;
985 Tcl_Obj *obj;
986 struct NsfList *nextPtr;
987 } NsfList;
988
989 typedef struct NsfDList {
990 void **data;
991 size_t size;
992 size_t avail;
993 void *static_data[30];
994 } NsfDList;
995
996
997 typedef struct NsfRuntimeState {
998 /*
999 * The defined object systems
1000 */
1001 struct NsfObjectSystem *objectSystems;
1002 /*
1003 * namespaces and cmds
1004 */
1005 Tcl_Namespace *NsfNS; /* the ::nsf namespace */
1006 Tcl_Namespace *NsfClassesNS; /* the ::nsf::classes namespace, where classes are created physically */
1007 Tcl_ObjCmdProc *objInterpProc; /* cached result of TclGetObjInterpProc() */
1008 Tcl_Command colonCmd; /* cmdPtr of cmd ":" to dispatch via cmdResolver */
1009 Proc fakeProc; /* dummy proc structure, used for C-implemented methods with local scope */
1010 Tcl_Command currentMixinCmdPtr; /* cmdPtr of currently active mixin, used for "info activemixin" */
1011 unsigned int objectMethodEpoch;
1012 unsigned int instanceMethodEpoch;
1013 #if defined(PER_OBJECT_PARAMETER_CACHING)
1014 unsigned int classParamPtrEpoch;
1015 #endif
1016 unsigned int overloadedMethods; /* bit-array for tracking overloaded methods */
1017 Tcl_Obj **methodObjNames; /* global objects of nsf */
1018 struct NsfShadowTclCommandInfo *tclCommands; /* shadowed Tcl commands */
1019
1020 #if defined(CHECK_ACTIVATION_COUNTS)
1021 NsfClasses *cscList;
1022 #endif
1023 int errorCount; /* keep track of number of errors to avoid potential error loops */
1024 int unknown; /* keep track whether an unknown method is currently called */
1025 /*
1026 * Configure options. The following do*-flags could be moved into a
1027 * bit-array, but we have only one state per interp, so the win on
1028 * memory is very little.
1029 */
1030 int logSeverity;
1031 int debugCallingDepth;
1032 unsigned int doCheckArguments;
1033 unsigned int doCheckResults;
1034 int doFilters;
1035 int doKeepcmds;
1036 int doProfile;
1037 int doTrace;
1038 unsigned int preventRecursionFlags;
1039 int doClassConverterOmitUnknown;
1040 int doSoftrecreate;
1041 int exitHandlerDestroyRound; /* shutdown handling */
1042
1043 Tcl_HashTable activeFilterTablePtr; /* keep track of defined filters */
1044 NsfList *freeListPtr; /* list of elements to free when interp shuts down */
1045 NsfDList freeDList;
1046 #if defined(NSF_PROFILE)
1047 NsfProfile profile;
1048 #endif
1049 #if defined(NSF_STACKCHECK)
1050 void *bottomOfStack;
1051 void *maxStack;
1052 #endif
1053 ClientData clientData;
1054 NsfStringIncrStruct iss; /* used for new to create new symbols */
1055 short guardCount; /* keep track of guard invocations */
1056 } NsfRuntimeState;
1057
1058 #define NSF_EXITHANDLER_OFF 0
1059 #define NSF_EXITHANDLER_ON_SOFT_DESTROY 1
1060 #define NSF_EXITHANDLER_ON_PHYSICAL_DESTROY 2
1061
1062
1063 #ifdef NSF_OBJECTDATA
1064 EXTERN void
1065 NsfSetObjectData(struct NsfObject *object, struct NsfClass *class, ClientData data)
1066 nonnull(1) nonnull(2) nonnull(3);
1067 EXTERN int
1068 NsfGetObjectData(struct NsfObject *object, struct NsfClass *class, ClientData *data)
1069 nonnull(1) nonnull(2) nonnull(3);
1070 EXTERN int
1071 NsfUnsetObjectData(struct NsfObject *object, struct NsfClass *class)
1072 nonnull(1) nonnull(2);
1073 EXTERN void
1074 NsfFreeObjectData(NsfClass *class)
1075 nonnull(1);
1076 #endif
1077
1078 /*
1079 * Prototypes for method definitions
1080 */
1081 EXTERN Tcl_ObjCmdProc NsfObjDispatch;
1082
1083 /*
1084 * NsfObject Reference Accounting
1085 */
1086 EXTERN void NsfCleanupObject_(NsfObject *object) nonnull(1);
1087
1088 #if defined(NSFOBJ_TRACE)
1089 # define NsfObjectRefCountIncr(object) \
1090 ((NsfObject *)(object))->refCount++; \
1091 fprintf(stderr, "RefCountIncr %p count=%d %s\n", (object), ((NsfObject *)(object))->refCount, \
1092 ((NsfObject *)object)->cmdName?ObjStr(((NsfObject *)(object))->cmdName):"no name"); \
1093 MEM_COUNT_ALLOC("NsfObject.refCount", (object))
1094 # define NsfObjectRefCountDecr(object) \
1095 (object)->refCount--; \
1096 fprintf(stderr, "RefCountDecr %p count=%d\n", (object), (object)->refCount); \
1097 MEM_COUNT_FREE("NsfObject.refCount", (object))
1098 #else
1099 # define NsfObjectRefCountIncr(object) \
1100 (object)->refCount++; \
1101 MEM_COUNT_ALLOC("NsfObject.refCount", (object))
1102 # define NsfObjectRefCountDecr(object) \
1103 (object)->refCount--; \
1104 MEM_COUNT_FREE("NsfObject.refCount", (object))
1105 #endif
1106
1107 /*
1108 *
1109 * Internally used API functions
1110 *
1111 */
1112 #if defined(NRE)
1113 # include "stubs8.6/nsfIntDecls.h"
1114 #else
1115 # include "stubs8.5/nsfIntDecls.h"
1116 #endif
1117
1118 /*
1119 * Profiling functions
1120 */
1121
1122 EXTERN void NsfDeprecatedCmd(Tcl_Interp *interp, const char *what, const char *oldCmd, const char *newCmd)
1123 nonnull(1) nonnull(2) nonnull(3) nonnull(4);
1124 EXTERN void NsfProfileDeprecatedCall(Tcl_Interp *interp, NsfObject *object, NsfClass *class,
1125 const char *methodName, const char *altMethod)
1126 nonnull(1) nonnull(2) nonnull(4) nonnull(5);
1127 EXTERN void NsfProfileDebugCall(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName,
1128 int objc, Tcl_Obj **objv)
1129 nonnull(1) nonnull(4);
1130 EXTERN void NsfProfileDebugExit(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName,
1131 long startSec, long startUsec)
1132 nonnull(1) nonnull(4);
1133
1134 #if defined(NSF_PROFILE)
1135 EXTERN void NsfProfileRecordMethodData(Tcl_Interp* interp, NsfCallStackContent *cscPtr)
1136 nonnull(1) nonnull(2);
1137 EXTERN void NsfProfileRecordProcData(Tcl_Interp *interp, const char *methodName, long startSec, long startUsec)
1138 nonnull(1) nonnull(2);
1139 EXTERN void NsfProfileInit(Tcl_Interp *interp) nonnull(1);
1140 EXTERN void NsfProfileFree(Tcl_Interp *interp) nonnull(1);
1141 EXTERN void NsfProfileClearData(Tcl_Interp *interp) nonnull(1);
1142 EXTERN void NsfProfileGetData(Tcl_Interp *interp) nonnull(1);
1143 EXTERN int NsfProfileTrace(Tcl_Interp *interp, int withEnable, int withVerbose, int withDontsave, Tcl_Obj *builtinObjs);
1144
1145 EXTERN void NsfProfileTraceCall(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName)
1146 nonnull(1) nonnull(2) nonnull(4);
1147 EXTERN void NsfProfileTraceExit(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName,
1148 struct Tcl_Time *callTime)
1149 nonnull(1) nonnull(2) nonnull(4) nonnull(5);
1150 EXTERN void NsfProfileTraceCallAppend(Tcl_Interp *interp, const char *label)
1151 nonnull(1) nonnull(2);
1152 EXTERN void NsfProfileTraceExitAppend(Tcl_Interp *interp, const char *label, double duration)
1153 nonnull(1) nonnull(2);
1154
1155 EXTERN NsfCallStackContent *NsfCallStackGetTopFrame(const Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr)
1156 nonnull(1);
1157 #endif
1158
1159 /*
1160 * MEM Counting
1161 */
1162 #ifdef NSF_MEM_COUNT
1163 void NsfMemCountAlloc(const char *id, const void *p) nonnull(1);
1164 void NsfMemCountFree(const char *id, const void *p) nonnull(1);
1165 void NsfMemCountInit(void);
1166 void NsfMemCountRelease(void);
1167 #endif /* NSF_MEM_COUNT */
1168
1169 /*
1170 * TCL_STACK_ALLOC_TRACE
1171 */
1172 #if defined(TCL_STACK_ALLOC_TRACE)
1173 # define NsfTclStackFree(interp,ptr,msg) \
1174 fprintf(stderr, "---- TclStackFree %p %s\n", ptr, msg);\
1175 TclStackFree(interp,ptr)
1176
1177 static char *
NsfTclStackAlloc(Tcl_Interp * interp,size_t size,char * msg)1178 NsfTclStackAlloc(Tcl_Interp *interp, size_t size, char *msg) {
1179 char *ptr = TclStackAlloc(interp, size);
1180 fprintf(stderr, "---- TclStackAlloc %p %s\n", ptr, msg);
1181 return ptr;
1182 }
1183 #else
1184 # define NsfTclStackFree(interp,ptr,msg) TclStackFree(interp,ptr)
1185 # define NsfTclStackAlloc(interp,size,msg) TclStackAlloc(interp,size)
1186 #endif
1187
1188 /*
1189 * bytecode support
1190 */
1191 #ifdef NSF_BYTECODE
1192 typedef struct NsfCompEnv {
1193 int bytecode;
1194 Command *cmdPtr;
1195 CompileProc *compileProc;
1196 Tcl_ObjCmdProc *callProc;
1197 } NsfCompEnv;
1198
1199 typedef enum {INST_INITPROC, INST_NEXT, INST_SELF, INST_SELF_DISPATCH,
1200 LAST_INSTRUCTION} NsfByteCodeInstructions;
1201
1202 Tcl_ObjCmdProc NsfInitProcNSCmd, NsfSelfDispatchCmd,
1203 NsfNextObjCmd, NsfGetSelfObjCmd;
1204
1205 EXTERN NsfCompEnv *NsfGetCompEnv(void);
1206 int NsfDirectSelfDispatch(ClientData cd, Tcl_Interp *interp,
1207 int objc, Tcl_Obj *const objv[])
1208 nonnull(1) nonnull(2);
1209 #endif
1210
1211 EXTERN int NsfGetClassFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
1212 NsfClass **classPtr, bool withUnknown)
1213 nonnull(1) nonnull(2) nonnull(3);
1214
1215 EXTERN int NsfObjWrongArgs(Tcl_Interp *interp, const char *msg,
1216 Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj,
1217 const char *arglist)
1218 nonnull(1) nonnull(2);
1219
1220 EXTERN const char *NsfMethodName(Tcl_Obj *methodObj)
1221 nonnull(1) returns_nonnull;
1222
1223 EXTERN void NsfInitPkgConfig(Tcl_Interp *interp)
1224 nonnull(1);
1225
1226 EXTERN void NsfDStringArgv(Tcl_DString *dsPtr, int objc, Tcl_Obj *const objv[])
1227 nonnull(1) nonnull(3);
1228
1229 EXTERN Tcl_Obj *NsfMethodNamePath(Tcl_Interp *interp,
1230 Tcl_CallFrame *framePtr,
1231 const char *methodName)
1232 nonnull(1) nonnull(3) returns_nonnull;
1233
1234 EXTERN int NsfDStringEval(Tcl_Interp *interp, Tcl_DString *dsPtr, const char *context,
1235 unsigned int traceEvalFlags)
1236 nonnull(1) nonnull(2) nonnull(3);
1237
1238
1239 /*
1240 * Definition of methodEpoch macros
1241 */
1242 #if defined(METHOD_OBJECT_TRACE)
1243 # define NsfInstanceMethodEpochIncr(msg) \
1244 RUNTIME_STATE(interp)->instanceMethodEpoch++; \
1245 fprintf(stderr, "+++ instanceMethodEpoch %d %s\n", RUNTIME_STATE(interp)->instanceMethodEpoch, msg)
1246 # define NsfObjectMethodEpochIncr(msg) \
1247 RUNTIME_STATE(interp)->objectMethodEpoch++; \
1248 fprintf(stderr, "+++ objectMethodEpoch %d %s\n", RUNTIME_STATE(interp)->objectMethodEpoch, msg)
1249 #else
1250 # define NsfInstanceMethodEpochIncr(msg) RUNTIME_STATE(interp)->instanceMethodEpoch++
1251 # define NsfObjectMethodEpochIncr(msg) RUNTIME_STATE(interp)->objectMethodEpoch++
1252 #endif
1253
1254 #if defined(PER_OBJECT_PARAMETER_CACHING)
1255 # define NsfClassParamPtrEpochIncr(msg) RUNTIME_STATE(interp)->classParamPtrEpoch++
1256 #else
1257 # define NsfClassParamPtrEpochIncr(msg)
1258 #endif
1259
1260 /*
1261 * NsfFlag type
1262 */
1263 EXTERN Tcl_ObjType NsfFlagObjType;
1264 EXTERN int NsfFlagObjSet(Tcl_Interp *UNUSED(interp),
1265 Tcl_Obj *objPtr,
1266 Nsf_Param const *baseParamPtr,
1267 int serial,
1268 Nsf_Param const *paramPtr,
1269 Tcl_Obj *payload,
1270 unsigned int flags);
1271 typedef struct {
1272 const Nsf_Param *signature;
1273 Nsf_Param const *paramPtr;
1274 Tcl_Obj *payload;
1275 int serial;
1276 unsigned int flags;
1277 } NsfFlag;
1278
1279 #define NSF_FLAG_DASHDAH 0x01
1280 #define NSF_FLAG_CONTAINS_VALUE 0x02
1281
1282 /*
1283 * NsfMethodContext type
1284 */
1285 EXTERN Tcl_ObjType NsfInstanceMethodObjType;
1286 EXTERN Tcl_ObjType NsfObjectMethodObjType;
1287
1288 EXTERN int NsfMethodObjSet(
1289 Tcl_Interp *UNUSED(interp),
1290 Tcl_Obj *objPtr,
1291 const Tcl_ObjType *objectType,
1292 void *context,
1293 unsigned int methodEpoch,
1294 Tcl_Command cmd,
1295 NsfClass *class,
1296 unsigned int flags
1297 ) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(6);
1298
1299
1300
1301
1302 typedef struct {
1303 void *context;
1304 Tcl_Command cmd;
1305 NsfClass *cl;
1306 unsigned int methodEpoch;
1307 unsigned int flags;
1308 } NsfMethodContext;
1309
1310 /* functions from nsfUtil.c */
1311 char *Nsf_ltoa(char *buf, long i, int *lengthPtr)
1312 nonnull(1) nonnull(3);
1313
1314 char *NsfStringIncr(NsfStringIncrStruct *iss)
1315 nonnull(1);
1316
1317 void NsfStringIncrInit(NsfStringIncrStruct *iss)
1318 nonnull(1);
1319
1320 void NsfStringIncrFree(NsfStringIncrStruct *iss)
1321 nonnull(1);
1322
1323
1324 /*
1325 * Interface for NSF's custom hash tables supporting function
1326 * pointers as keys.
1327 *
1328 */
1329
1330 typedef void (Nsf_AnyFun)(void);
1331
1332 EXTERN void Nsf_InitFunPtrHashTable(Tcl_HashTable *tablePtr)
1333 nonnull(1);
1334 EXTERN Tcl_HashEntry *Nsf_CreateFunPtrHashEntry(Tcl_HashTable *tablePtr, Nsf_AnyFun *key, int *isNew)
1335 nonnull(1) nonnull(2);
1336 EXTERN Tcl_HashEntry *Nsf_FindFunPtrHashEntry(Tcl_HashTable *tablePtr, Nsf_AnyFun *key)
1337 nonnull(1) nonnull(2);
1338
1339
1340 /*
1341 * NSF enumeration-type interface
1342 */
1343 EXTERN void Nsf_EnumerationTypeInit(void);
1344 EXTERN void Nsf_EnumerationTypeRelease(void);
1345
1346 EXTERN const char *Nsf_EnumerationTypeGetDomain(Nsf_TypeConverter *converter)
1347 nonnull(1);
1348
1349 /*
1350 * NSF command definitions interface
1351 */
1352 EXTERN void Nsf_CmdDefinitionInit(void);
1353 EXTERN void Nsf_CmdDefinitionRelease(void);
1354 EXTERN Nsf_methodDefinition *Nsf_CmdDefinitionGet(Tcl_ObjCmdProc *proc)
1355 nonnull(1);
1356
1357
1358 #ifndef HAVE_STRNSTR
1359 char *strnstr(const char *buffer, const char *needle, size_t buffer_len) pure;
1360 #endif
1361
1362 /*
1363 In ANSI mode (ISO C89/90) compilers such as gcc and clang do not
1364 define the va_copy macro. However, they *do* in reasonably recent
1365 versions provide a prefixed (__*) one. The by-feature test below
1366 falls back to the prefixed version, if available, and provides a
1367 more general fallback to a simple assignment; this is primarily for
1368 MSVC; admittedly, this simplification is not generally portable to
1369 platform/compiler combos other than x86, but the best I can think of right
1370 now. One might constrain the assignment-fallback to a platform and
1371 leave va_copy undefined in uncaught platform cases (?).
1372 */
1373 #ifndef va_copy
1374 #ifdef __va_copy
1375 #define va_copy(dest,src) __va_copy((dest),(src))
1376 #else
1377 #define va_copy(dest,src) ((dest) = (src))
1378 #endif
1379 #endif
1380
1381 /* In Tcl 8.6 (tclInt.h), vsnprintf is mapped to _vsnprintf. In Tcl
1382 8.5, this is missing from tclInt.h. So ... */
1383
1384 #if defined(PRE86) && defined(_MSC_VER)
1385 #define vsnprintf _vsnprintf
1386 #endif
1387
1388 /*
1389 * There are six whitespace characters in Tcl, which serve as element
1390 * separators in string representations of Tcl lists. See tclUtil.c
1391 */
1392
1393 #define NsfHasTclSpace(str) \
1394 (strpbrk((str), " \t\n\r\v\f") != NULL)
1395
1396 #define NsfMax(a,b) ((a) > (b) ? a : b)
1397 #define NsfMin(a,b) ((a) < (b) ? a : b)
1398
1399 #define NsfCallStackFindLastInvocation(interp, offset, framePtrPtr) \
1400 NsfCallStackFindCallingContext((interp), (offset), (framePtrPtr), NULL)
1401
1402 #endif /* _nsf_int_h_ */
1403