Tcl Source Code

Artifact [281be40299]
Login

Artifact 281be40299518a8484135acc2979e37abb7dda2b:

Attachment "tclExecute-TEBCinline-compgoto.diff" to ticket [1820448fff] added by das 2007-11-10 02:18:33.
Index: generic/tclExecute.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclExecute.c,v
retrieving revision 1.342
diff -u -p -r1.342 tclExecute.c
--- generic/tclExecute.c	9 Nov 2007 18:55:14 -0000	1.342
+++ generic/tclExecute.c	9 Nov 2007 19:02:11 -0000
@@ -24,6 +24,15 @@
 #include <float.h>
 
 /*
+ * FIXME: manual configuration of TEBC inline level & computed goto use:
+ */
+
+#ifndef TEBC_INLINE_LEVEL
+#   define TEBC_INLINE_LEVEL	0	/* 0 - 4  */
+#   define USE_COMPUTED_GOTO	0	/* 0 or 1 */
+#endif
+
+/*
  * Hack to determine whether we may expect IEEE floating point. The hack is
  * formally incorrect in that non-IEEE platforms might have the same precision
  * and range, but VAX, IBM, and Cray do not; are there any other floating
@@ -187,6 +196,258 @@ VarHashCreateVar(
     VarHashCreateVar((tablePtr), (key), NULL)
 
 /*
+ * Use gcc branch prediction builtin when available.
+ */
+
+#ifdef HAVE_BUILTIN_EXPECT
+#   ifndef USE_BUILTIN_EXPECT
+#	define USE_BUILTIN_EXPECT	1
+#   endif
+#else
+#   ifndef USE_BUILTIN_EXPECT
+#	define USE_BUILTIN_EXPECT	0
+#   elif USE_BUILTIN_EXPECT
+#	warning __builtin_expect unavailable
+#	undef  USE_BUILTIN_EXPECT
+#	define USE_BUILTIN_EXPECT	0
+#   endif
+#endif
+
+#if USE_BUILTIN_EXPECT
+#   define LIKELY(t)			(__builtin_expect((t), 1))
+#   define UNLIKELY(t)			(__builtin_expect((t), 0))
+#else
+#   define LIKELY(t)	(t)
+#   define UNLIKELY(t)	(t)
+#endif
+
+/*
+ * Use computed goto instead of big switch when available.
+ */
+
+#ifdef HAVE_COMPUTED_GOTO
+#   ifndef USE_COMPUTED_GOTO
+#	define USE_COMPUTED_GOTO	1
+#   endif
+#else
+#   ifndef USE_COMPUTED_GOTO
+#	define USE_COMPUTED_GOTO	0
+#   elif USE_COMPUTED_GOTO
+#	warning computed goto unavailable
+#	undef  USE_COMPUTED_GOTO
+#	define USE_COMPUTED_GOTO	0
+#   endif
+#endif
+
+/*
+ * Macros to construct the instruction switch resp. jumptable.
+ */
+
+#if !USE_COMPUTED_GOTO
+#   define CASE(i)		case i
+#   define BAD_INST()		default
+#   define DISPATCH_INST()	switch (*pc)
+#else
+#   define CASE(i) 		l_inst_##i
+#   define BAD_INST()		l_bad_inst
+#   define DISPATCH_INST()	GOTO_NEXT_INST(); l_top:
+#   define CADR(i)		((char*) &&l_inst_##i - (char*) &&l_top)
+#   define GOTO_NEXT_INST() \
+	if (LIKELY(*pc <= LAST_INST_OPCODE)) {\
+	    goto *(void*)(instJumptable[*pc] + (char*) &&l_top);\
+	} else {\
+	    goto BAD_INST();\
+	}
+#endif
+
+/*
+ * Define the NEXT_INST() and NEXT_INST_DISPATCH() macros according to the
+ * chosen level of inlining into the NEXT_INST_F() and NEXT_INST_V() macros:
+ *	0 no inlining
+ *	1 inline cleanup code
+ *	2 also inline async handler and other check code
+ *	3 also inline peephole gotos
+ *	4 also do indirect threading (direct computed goto to next instruction)
+ */
+
+#ifndef TEBC_INLINE_LEVEL
+#   define TEBC_INLINE_LEVEL		0
+#endif
+
+#if TEBC_INLINE_LEVEL > 3 && USE_COMPUTED_GOTO
+#   define NEXT_INST() \
+	NEXT_INST_CHECKS();\
+	NEXT_INST_PEEPHOLE();\
+	GOTO_NEXT_INST();
+#   define NEXT_INST_DISPATCH() \
+	NEXT_INST_CHECKS();\
+	NEXT_INST_PEEPHOLE();\
+	DISPATCH_INST()
+#elif TEBC_INLINE_LEVEL > 2
+#   define NEXT_INST() \
+	NEXT_INST_CHECKS();\
+	NEXT_INST_PEEPHOLE();\
+	goto l_next_inst;
+#   define NEXT_INST_DISPATCH() \
+	NEXT_INST_CHECKS();\
+	NEXT_INST_PEEPHOLE();\
+	l_next_inst:\
+	DISPATCH_INST()
+#elif TEBC_INLINE_LEVEL > 1
+#   define NEXT_INST() \
+	NEXT_INST_CHECKS();\
+	goto l_next_inst;
+#   define NEXT_INST_DISPATCH() \
+	NEXT_INST_CHECKS();\
+	l_next_inst:\
+	NEXT_INST_PEEPHOLE();\
+	DISPATCH_INST()
+#elif TEBC_INLINE_LEVEL > 0
+#   define NEXT_INST() \
+	goto l_next_inst;
+#   define NEXT_INST_DISPATCH() \
+	l_next_inst:\
+	NEXT_INST_CHECKS();\
+	NEXT_INST_PEEPHOLE();\
+	DISPATCH_INST()
+#else
+#   define NEXT_INST() \
+	goto l_next_inst;
+#   define NEXT_INST_DISPATCH() \
+	goto l_next_inst;\
+	NEXT_INST_CLEANUP();\
+	l_next_inst:\
+	NEXT_INST_CHECKS();\
+	NEXT_INST_PEEPHOLE();\
+	DISPATCH_INST()
+#endif
+
+/*
+ * Macros for pre-instruction-execution checks and stats.
+ */
+
+#define NEXT_INST_CHECKS() \
+    NEXT_INST_STACK_CHECK();\
+    NEXT_INST_STATS();\
+    TCL_DTRACE_INST_NEXT();\
+    NEXT_INST_ASYNC_CHECK()
+
+#ifdef TCL_COMPILE_DEBUG
+    /*
+     * Skip the stack depth check if an expansion is in progress.
+     */
+#   define NEXT_INST_STACK_CHECK() \
+    ValidatePcAndStackTop(codePtr, pc, CURR_DEPTH, 0,\
+	    /*checkStack*/ expandNestList == NULL);\
+    if (traceInstructions) {\
+	fprintf(stdout, "%2d: %2d ", iPtr->numLevels, (int) CURR_DEPTH);\
+	TclPrintInstruction(codePtr, pc);\
+	fflush(stdout);\
+    }
+#else
+#   define NEXT_INST_STACK_CHECK()
+#endif /* TCL_COMPILE_DEBUG */
+
+#ifdef TCL_COMPILE_STATS
+#   define NEXT_INST_STATS() iPtr->stats.instructionCount[*pc]++;
+#else
+#   define NEXT_INST_STATS()
+#endif
+
+/*
+ * Check for asynchronous handlers [Bug 746722]; we do the check every
+ * ASYNC_CHECK_COUNT_MASK instruction, of the form (2**n-1).
+ */
+
+#define NEXT_INST_ASYNC_CHECK() \
+    if ((instructionCount++ & ASYNC_CHECK_COUNT_MASK) == 0) {\
+	int localResult;\
+	if (Tcl_AsyncReady()) {\
+	    DECACHE_STACK_INFO();\
+	    localResult = Tcl_AsyncInvoke(interp, result);\
+	    CACHE_STACK_INFO();\
+	    if (localResult == TCL_ERROR) {\
+		result = localResult;\
+		goto checkForCatch;\
+	    }\
+	}\
+	if (TclLimitReady(iPtr->limit)) {\
+	    DECACHE_STACK_INFO();\
+	    localResult = Tcl_LimitCheck(interp);\
+	    CACHE_STACK_INFO();\
+	    if (localResult == TCL_ERROR) {\
+		result = localResult;\
+		goto checkForCatch;\
+	    }\
+	}\
+    }
+
+/*
+ * These two instructions account for 26% of all instructions (according
+ * to measurements on tclbench by Ben Vitale
+ * [http://www.cs.toronto.edu/syslab/pubs/tcl2005-vitale-zaleski.pdf]
+ * Resolving them before the switch reduces the cost of branch
+ * mispredictions, seems to improve runtime by 5% to 15%, and (amazingly!)
+ * reduces total obj size.
+ */
+
+#define NEXT_INST_PEEPHOLE() \
+    if (*pc == INST_LOAD_SCALAR1) {\
+	goto instLoadScalar1;\
+    } else if (*pc == INST_PUSH1) {\
+	goto instPush1Peephole;\
+    }
+
+/*
+ * Macros for standard instruction endings; unrolled for speed in the most
+ * frequent cases (instructions that consume up to two stack elements).
+ */
+
+#define CLEANUP_POP() {\
+	Tcl_Obj *valuePtr = POP_OBJECT();\
+	TclDecrRefCount(valuePtr);\
+    }
+#define CLEANUP_TOS() {\
+	Tcl_Obj *valuePtr = OBJ_AT_TOS;\
+	TclDecrRefCount(valuePtr);\
+	OBJ_AT_TOS = objResultPtr;\
+    }
+#define CLEANUPV_PUSH_L(l1, l2) \
+    switch (cleanup) {\
+	case 0:		*(++tosPtr) = (objResultPtr); break;\
+	default:	cleanup -= 2; while (cleanup--) { CLEANUP_POP(); }\
+	case 2:		l2 CLEANUP_POP();\
+	case 1:		l1 CLEANUP_TOS();\
+    }
+#define CLEANUPV_L(l1, l2) \
+    switch (cleanup) {\
+	default:	cleanup -= 2; while (cleanup--) { CLEANUP_POP(); }\
+	case 2:		l2 CLEANUP_POP();\
+	case 1:		l1 CLEANUP_POP();\
+	case 0:		break;\
+    }
+#if TEBC_INLINE_LEVEL > 0
+#   define CLEANUP2_PUSH()	CLEANUP_POP()
+#   define CLEANUP1_PUSH()	CLEANUP_TOS()
+#   define CLEANUP2()		CLEANUP_POP()
+#   define CLEANUP1()		CLEANUP_POP()
+#   define CLEANUPV_PUSH()	CLEANUPV_PUSH_L(,)
+#   define CLEANUPV()		CLEANUPV_L(,)
+#else
+#   define CLEANUP2_PUSH()	goto l_cleanup2_push;
+#   define CLEANUP1_PUSH()	goto l_cleanup1_push;
+#   define CLEANUP2()		goto l_cleanup2;
+#   define CLEANUP1()		goto l_cleanup1;
+#   define CLEANUPV_PUSH()	goto l_cleanupV_push;
+#   define CLEANUPV()		goto l_cleanupV;
+#   define NEXT_INST_CLEANUP() \
+	l_cleanupV_push:  CLEANUPV_PUSH_L(l_cleanup1_push:, l_cleanup2_push:);\
+	goto l_cleanup_done;\
+	l_cleanupV:	  CLEANUPV_L(l_cleanup1:, l_cleanup2:);\
+	l_cleanup_done:
+#endif
+
+/*
  * The new macro for ending an instruction; note that a reasonable C-optimiser
  * will resolve all branches at compile time. (result) is always a constant;
  * the macro NEXT_INST_F handles constant (nCleanup), NEXT_INST_V is resolved
@@ -210,25 +471,25 @@ VarHashCreateVar(
 	    }\
 	} \
 	pc += (pcAdjustment);\
-	goto cleanup0;\
-    } else if (resultHandling != 0) {\
+    } else if (resultHandling) {\
 	if ((resultHandling) > 0) {\
 	    Tcl_IncrRefCount(objResultPtr);\
 	}\
 	pc += (pcAdjustment);\
 	switch (nCleanup) {\
-	    case 1: goto cleanup1_pushObjResultPtr;\
-	    case 2: goto cleanup2_pushObjResultPtr;\
 	    default: Tcl_Panic("bad usage of macro NEXT_INST_F");\
+	    case 2: CLEANUP2_PUSH();\
+	    case 1: CLEANUP1_PUSH();\
 	}\
     } else {\
 	pc += (pcAdjustment);\
 	switch (nCleanup) {\
-	    case 1: goto cleanup1;\
-	    case 2: goto cleanup2;\
 	    default: Tcl_Panic("bad usage of macro NEXT_INST_F");\
+	    case 2: CLEANUP2();\
+	    case 1: CLEANUP1();\
 	}\
-    }
+    }\
+    NEXT_INST();
 
 #define NEXT_INST_V(pcAdjustment, nCleanup, resultHandling) \
     pc += (pcAdjustment);\
@@ -237,10 +498,11 @@ VarHashCreateVar(
 	if ((resultHandling) > 0) {\
 	    Tcl_IncrRefCount(objResultPtr);\
 	}\
-	goto cleanupV_pushObjResultPtr;\
+	CLEANUPV_PUSH();\
     } else {\
-	goto cleanupV;\
-    }
+	CLEANUPV();\
+    }\
+    NEXT_INST();
 
 /*
  * Macros used to cache often-referenced Tcl evaluation stack information
@@ -1584,6 +1846,81 @@ TclExecuteByteCode(
 #endif
     char *curInstName = NULL;
 
+#if USE_COMPUTED_GOTO
+
+    /*
+     * Instruction jumptable for computed goto dispatch, needs to be kept
+     * in sync with instruction list in tclCompile.h.
+     */
+
+    static const ptrdiff_t instJumptable[] = {
+	CADR(INST_DONE),		CADR(INST_PUSH1),
+	CADR(INST_PUSH4),		CADR(INST_POP),
+	CADR(INST_DUP),			CADR(INST_CONCAT1),
+	CADR(INST_INVOKE_STK1),		CADR(INST_INVOKE_STK4),
+	CADR(INST_EVAL_STK),		CADR(INST_EXPR_STK),
+	CADR(INST_LOAD_SCALAR1),	CADR(INST_LOAD_SCALAR4),
+	CADR(INST_LOAD_SCALAR_STK),	CADR(INST_LOAD_ARRAY1),
+	CADR(INST_LOAD_ARRAY4),		CADR(INST_LOAD_ARRAY_STK),
+	CADR(INST_LOAD_STK),		CADR(INST_STORE_SCALAR1),
+	CADR(INST_STORE_SCALAR4),	CADR(INST_STORE_SCALAR_STK),
+	CADR(INST_STORE_ARRAY1),	CADR(INST_STORE_ARRAY4),
+	CADR(INST_STORE_ARRAY_STK),	CADR(INST_STORE_STK),
+	CADR(INST_INCR_SCALAR1),	CADR(INST_INCR_SCALAR_STK),
+	CADR(INST_INCR_ARRAY1),		CADR(INST_INCR_ARRAY_STK),
+	CADR(INST_INCR_STK),		CADR(INST_INCR_SCALAR1_IMM),
+	CADR(INST_INCR_SCALAR_STK_IMM),	CADR(INST_INCR_ARRAY1_IMM),
+	CADR(INST_INCR_ARRAY_STK_IMM),	CADR(INST_INCR_STK_IMM),
+	CADR(INST_JUMP1),		CADR(INST_JUMP4),
+	CADR(INST_JUMP_TRUE1),		CADR(INST_JUMP_TRUE4),
+	CADR(INST_JUMP_FALSE1),		CADR(INST_JUMP_FALSE4),
+	CADR(INST_LOR),			CADR(INST_LAND),
+	CADR(INST_BITOR),		CADR(INST_BITXOR),
+	CADR(INST_BITAND),		CADR(INST_EQ),
+	CADR(INST_NEQ),			CADR(INST_LT),
+	CADR(INST_GT),			CADR(INST_LE),
+	CADR(INST_GE),			CADR(INST_LSHIFT),
+	CADR(INST_RSHIFT),		CADR(INST_ADD),
+	CADR(INST_SUB),			CADR(INST_MULT),
+	CADR(INST_DIV),			CADR(INST_MOD),
+	CADR(INST_UPLUS),		CADR(INST_UMINUS),
+	CADR(INST_BITNOT),		CADR(INST_LNOT),
+	CADR(INST_CALL_BUILTIN_FUNC1),	CADR(INST_CALL_FUNC1),
+	CADR(INST_TRY_CVT_TO_NUMERIC),	CADR(INST_BREAK),
+	CADR(INST_CONTINUE),		CADR(INST_FOREACH_START4),
+	CADR(INST_FOREACH_STEP4),	CADR(INST_BEGIN_CATCH4),
+	CADR(INST_END_CATCH),		CADR(INST_PUSH_RESULT),
+	CADR(INST_PUSH_RETURN_CODE),	CADR(INST_STR_EQ),
+	CADR(INST_STR_NEQ),		CADR(INST_STR_CMP),
+	CADR(INST_STR_LEN),		CADR(INST_STR_INDEX),
+	CADR(INST_STR_MATCH),		CADR(INST_LIST),
+	CADR(INST_LIST_INDEX),		CADR(INST_LIST_LENGTH),
+	CADR(INST_APPEND_SCALAR1),	CADR(INST_APPEND_SCALAR4),
+	CADR(INST_APPEND_ARRAY1),	CADR(INST_APPEND_ARRAY4),
+	CADR(INST_APPEND_ARRAY_STK),	CADR(INST_APPEND_STK),
+	CADR(INST_LAPPEND_SCALAR1),	CADR(INST_LAPPEND_SCALAR4),
+	CADR(INST_LAPPEND_ARRAY1),	CADR(INST_LAPPEND_ARRAY4),
+	CADR(INST_LAPPEND_ARRAY_STK),	CADR(INST_LAPPEND_STK),
+	CADR(INST_LIST_INDEX_MULTI),	CADR(INST_OVER),
+	CADR(INST_LSET_LIST),		CADR(INST_LSET_FLAT),
+	CADR(INST_RETURN_IMM),		CADR(INST_EXPON),
+	CADR(INST_EXPAND_START),	CADR(INST_EXPAND_STKTOP),
+	CADR(INST_INVOKE_EXPANDED),	CADR(INST_LIST_INDEX_IMM),
+	CADR(INST_LIST_RANGE_IMM),	CADR(INST_START_CMD),
+	CADR(INST_LIST_IN),		CADR(INST_LIST_NOT_IN),
+	CADR(INST_PUSH_RETURN_OPTIONS),	CADR(INST_RETURN_STK),
+	CADR(INST_DICT_GET),		CADR(INST_DICT_SET),
+	CADR(INST_DICT_UNSET),		CADR(INST_DICT_INCR_IMM),
+	CADR(INST_DICT_APPEND),		CADR(INST_DICT_LAPPEND),
+	CADR(INST_DICT_FIRST),		CADR(INST_DICT_NEXT),
+	CADR(INST_DICT_DONE),		CADR(INST_DICT_UPDATE_START),
+	CADR(INST_DICT_UPDATE_END),	CADR(INST_JUMP_TABLE),
+	CADR(INST_UPVAR),		CADR(INST_NSUPVAR),
+	CADR(INST_VARIABLE),		CADR(INST_SYNTAX),
+	CADR(INST_REVERSE),
+    };
+#endif
+
     /*
      * The execution uses a unified stack: first the catch stack, immediately
      * above it a CmdFrame, then the execution stack.
@@ -1639,143 +1976,9 @@ TclExecuteByteCode(
      * or some error.
      */
 
-    goto cleanup0;
-
-    /*
-     * Targets for standard instruction endings; unrolled for speed in the
-     * most frequent cases (instructions that consume up to two stack
-     * elements).
-     *
-     * This used to be a "for(;;)" loop, with each instruction doing its own
-     * cleanup.
-     */
-
-    {
-	Tcl_Obj *valuePtr;
-
-    cleanupV_pushObjResultPtr:
-	switch (cleanup) {
-	case 0:
-	    *(++tosPtr) = (objResultPtr);
-	    goto cleanup0;
-	default:
-	    cleanup -= 2;
-	    while (cleanup--) {
-		valuePtr = POP_OBJECT();
-		TclDecrRefCount(valuePtr);
-	    }
-	case 2:
-	cleanup2_pushObjResultPtr:
-	    valuePtr = POP_OBJECT();
-	    TclDecrRefCount(valuePtr);
-	case 1:
-	cleanup1_pushObjResultPtr:
-	    valuePtr = OBJ_AT_TOS;
-	    TclDecrRefCount(valuePtr);
-	}
-	OBJ_AT_TOS = objResultPtr;
-	goto cleanup0;
-
-    cleanupV:
-	switch (cleanup) {
-	default:
-	    cleanup -= 2;
-	    while (cleanup--) {
-		valuePtr = POP_OBJECT();
-		TclDecrRefCount(valuePtr);
-	    }
-	case 2:
-	cleanup2:
-	    valuePtr = POP_OBJECT();
-	    TclDecrRefCount(valuePtr);
-	case 1:
-	cleanup1:
-	    valuePtr = POP_OBJECT();
-	    TclDecrRefCount(valuePtr);
-	case 0:
-	    /*
-	     * We really want to do nothing now, but this is needed for some
-	     * compilers (SunPro CC).
-	     */
-
-	    break;
-	}
-    }
- cleanup0:
-
-#ifdef TCL_COMPILE_DEBUG
-    /*
-     * Skip the stack depth check if an expansion is in progress.
-     */
-
-    ValidatePcAndStackTop(codePtr, pc, CURR_DEPTH, 0,
-	    /*checkStack*/ expandNestList == NULL);
-    if (traceInstructions) {
-	fprintf(stdout, "%2d: %2d ", iPtr->numLevels, (int) CURR_DEPTH);
-	TclPrintInstruction(codePtr, pc);
-	fflush(stdout);
-    }
-#endif /* TCL_COMPILE_DEBUG */
-
-#ifdef TCL_COMPILE_STATS
-    iPtr->stats.instructionCount[*pc]++;
-#endif
-
-     TCL_DTRACE_INST_NEXT();
-
-    /*
-     * Check for asynchronous handlers [Bug 746722]; we do the check every
-     * ASYNC_CHECK_COUNT_MASK instruction, of the form (2**n-1).
-     */
-
-    if ((instructionCount++ & ASYNC_CHECK_COUNT_MASK) == 0) {
-	/*
-	 * Check for asynchronous handlers [Bug 746722]; we do the check every
-	 * ASYNC_CHECK_COUNT_MASK instruction, of the form (2**n-<1).
-	 */
-
-	if (Tcl_AsyncReady()) {
-	    int localResult;
-
-	    DECACHE_STACK_INFO();
-	    localResult = Tcl_AsyncInvoke(interp, result);
-	    CACHE_STACK_INFO();
-	    if (localResult == TCL_ERROR) {
-		result = localResult;
-		goto checkForCatch;
-	    }
-	}
-	if (TclLimitReady(iPtr->limit)) {
-	    int localResult;
-
-	    DECACHE_STACK_INFO();
-	    localResult = Tcl_LimitCheck(interp);
-	    CACHE_STACK_INFO();
-	    if (localResult == TCL_ERROR) {
-		result = localResult;
-		goto checkForCatch;
-	    }
-	}
-    }
-
-    /*
-     * These two instructions account for 26% of all instructions (according
-     * to measurements on tclbench by Ben Vitale
-     * [http://www.cs.toronto.edu/syslab/pubs/tcl2005-vitale-zaleski.pdf]
-     * Resolving them before the switch reduces the cost of branch
-     * mispredictions, seems to improve runtime by 5% to 15%, and (amazingly!)
-     * reduces total obj size.
-     */
-
-    if (*pc == INST_LOAD_SCALAR1) {
-	goto instLoadScalar1;
-    } else if (*pc == INST_PUSH1) {
-	goto instPush1Peephole;
-    }
-    
-    switch (*pc) {
-    case INST_SYNTAX:
-    case INST_RETURN_IMM: {
+    NEXT_INST_DISPATCH() {
+    CASE(INST_SYNTAX):
+    CASE(INST_RETURN_IMM): {
 	int code = TclGetInt4AtPtr(pc+1);
 	int level = TclGetUInt4AtPtr(pc+5);
 
@@ -1799,7 +2002,7 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_RETURN_STK:
+    CASE(INST_RETURN_STK):
 	TRACE(("=> "));
 	objResultPtr = POP_OBJECT();
 	result = Tcl_SetReturnOptions(interp, OBJ_AT_TOS);
@@ -1814,7 +2017,7 @@ TclExecuteByteCode(
 	    goto processExceptionReturn;
 	}
 
-    case INST_DONE:
+    CASE(INST_DONE):
 	if (tosPtr > initTosPtr) {
 	    /*
 	     * Set the interpreter's object result to point to the topmost
@@ -1837,7 +2040,7 @@ TclExecuteByteCode(
 	    goto abnormalReturn;
 	}
 
-    case INST_PUSH1:
+    CASE(INST_PUSH1):
     instPush1Peephole:
 	PUSH_OBJECT(codePtr->objArrayPtr[TclGetUInt1AtPtr(pc+1)]);
 	TRACE_WITH_OBJ(("%u => ", TclGetInt1AtPtr(pc+1)), OBJ_AT_TOS);
@@ -1854,12 +2057,12 @@ TclExecuteByteCode(
 #endif
 	NEXT_INST_F(0, 0, 0);
 
-    case INST_PUSH4:
+    CASE(INST_PUSH4):
 	objResultPtr = codePtr->objArrayPtr[TclGetUInt4AtPtr(pc+1)];
 	TRACE_WITH_OBJ(("%u => ", TclGetUInt4AtPtr(pc+1)), objResultPtr);
 	NEXT_INST_F(5, 0, 1);
 
-    case INST_POP: {
+    CASE(INST_POP): {
 	Tcl_Obj *valuePtr;
 
 	TRACE_WITH_OBJ(("=> discarding "), OBJ_AT_TOS);
@@ -1882,7 +2085,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(0, 0, 0);
     }
 
-    case INST_START_CMD:
+    CASE(INST_START_CMD):
 #if !TCL_COMPILE_DEBUG
     instStartCmdPeephole:
 #endif
@@ -1923,12 +2126,12 @@ TclExecuteByteCode(
 	    NEXT_INST_V(opnd, 0, -1);
 	}
 
-    case INST_DUP:
+    CASE(INST_DUP):
 	objResultPtr = OBJ_AT_TOS;
 	TRACE_WITH_OBJ(("=> "), objResultPtr);
 	NEXT_INST_F(1, 0, 1);
 
-    case INST_OVER: {
+    CASE(INST_OVER): {
 	int opnd;
 
 	opnd = TclGetUInt4AtPtr(pc+1);
@@ -1937,7 +2140,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(5, 0, 1);
     }
 
-    case INST_REVERSE: {
+    CASE(INST_REVERSE): {
 	int opnd;
 	Tcl_Obj **a, **b;
 
@@ -1953,7 +2156,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(5, 0, 0);
     }
 
-    case INST_CONCAT1: {
+    CASE(INST_CONCAT1): {
 	int opnd, length, appendLen = 0;
 	char *bytes, *p;
 	Tcl_Obj **currPtr;
@@ -2028,7 +2231,7 @@ TclExecuteByteCode(
 	NEXT_INST_V(2, opnd, 1);
     }
 
-    case INST_EXPAND_START: {
+    CASE(INST_EXPAND_START): {
 	/*
 	 * Push an element to the expandNestList. This records the current
 	 * stack depth - i.e., the point in the stack where the expanded
@@ -2051,7 +2254,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(1, 0, 0);
     }
 
-    case INST_EXPAND_STKTOP: {
+    CASE(INST_EXPAND_STKTOP): {
 	int objc, length, i;
 	Tcl_Obj **objv, *valuePtr;
 	ptrdiff_t moved;
@@ -2115,7 +2318,7 @@ TclExecuteByteCode(
 
 	int objc, pcAdjustment;
 
-    case INST_INVOKE_EXPANDED:
+    CASE(INST_INVOKE_EXPANDED):
 	{
 	    Tcl_Obj *objPtr = expandNestList;
 
@@ -2137,12 +2340,12 @@ TclExecuteByteCode(
 	    NEXT_INST_F(1, 0, 1);
 	}
 
-    case INST_INVOKE_STK4:
+    CASE(INST_INVOKE_STK4):
 	objc = TclGetUInt4AtPtr(pc+1);
 	pcAdjustment = 5;
 	goto doInvocation;
 
-    case INST_INVOKE_STK1:
+    CASE(INST_INVOKE_STK1):
 	objc = TclGetUInt1AtPtr(pc+1);
 	pcAdjustment = 2;
 
@@ -2234,7 +2437,7 @@ TclExecuteByteCode(
 	}
 
 #if TCL_SUPPORT_84_BYTECODE
-    case INST_CALL_BUILTIN_FUNC1: {
+    CASE(INST_CALL_BUILTIN_FUNC1): {
 	/*
 	 * Call one of the built-in pre-8.5 Tcl math functions. This
 	 * translates to INST_INVOKE_STK1 with the first argument of
@@ -2282,7 +2485,7 @@ TclExecuteByteCode(
 	goto doInvocation;
     }
 
-    case INST_CALL_FUNC1: {
+    CASE(INST_CALL_FUNC1): {
 	/*
 	 * Call a non-builtin Tcl math function previously registered by a
 	 * call to Tcl_CreateMathFunc pre-8.5. This is essentially
@@ -2320,14 +2523,14 @@ TclExecuteByteCode(
      * remains for existing bytecode precompiled files.
      */
 
-    case INST_CALL_BUILTIN_FUNC1:
+    CASE(INST_CALL_BUILTIN_FUNC1):
 	Tcl_Panic("TclExecuteByteCode: obsolete INST_CALL_BUILTIN_FUNC1 found");
-    case INST_CALL_FUNC1:
+    CASE(INST_CALL_FUNC1):
 	Tcl_Panic("TclExecuteByteCode: obsolete INST_CALL_FUNC1 found");
 #endif
     }
 
-    case INST_EVAL_STK: {
+    CASE(INST_EVAL_STK): {
 	/*
 	 * Note to maintainers: it is important that INST_EVAL_STK pop its
 	 * argument from the stack before jumping to checkForCatch! DO NOT
@@ -2376,7 +2579,7 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_EXPR_STK: {
+    CASE(INST_EXPR_STK): {
 	Tcl_Obj *objPtr, *valuePtr;
 
 	objPtr = OBJ_AT_TOS;
@@ -2409,7 +2612,7 @@ TclExecuteByteCode(
 	Var *varPtr, *arrayPtr;
 	Tcl_Obj *objPtr;
 
-    case INST_LOAD_SCALAR1:
+    CASE(INST_LOAD_SCALAR1):
 	instLoadScalar1:
 	opnd = TclGetUInt1AtPtr(pc+1);
 	varPtr = &(compiledLocals[opnd]);
@@ -2432,7 +2635,7 @@ TclExecuteByteCode(
 	part1Ptr = part2Ptr = NULL;
 	goto doCallPtrGetVar;
 
-    case INST_LOAD_SCALAR4:
+    CASE(INST_LOAD_SCALAR4):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	varPtr = &(compiledLocals[opnd]);
 	while (TclIsVarLink(varPtr)) {
@@ -2454,12 +2657,12 @@ TclExecuteByteCode(
 	part1Ptr = part2Ptr = NULL;
 	goto doCallPtrGetVar;
 
-    case INST_LOAD_ARRAY4:
+    CASE(INST_LOAD_ARRAY4):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	pcAdjustment = 5;
 	goto doLoadArray;
 
-    case INST_LOAD_ARRAY1:
+    CASE(INST_LOAD_ARRAY1):
 	opnd = TclGetUInt1AtPtr(pc+1);
 	pcAdjustment = 2;
 
@@ -2494,15 +2697,15 @@ TclExecuteByteCode(
 	cleanup = 1;
 	goto doCallPtrGetVar;
 
-    case INST_LOAD_ARRAY_STK:
+    CASE(INST_LOAD_ARRAY_STK):
 	cleanup = 2;
 	part2Ptr = OBJ_AT_TOS;		/* element name */
 	objPtr = OBJ_UNDER_TOS;		/* array name */
 	TRACE(("\"%.30s(%.30s)\" => ", O2S(objPtr), O2S(part2Ptr)));
 	goto doLoadStk;
 
-    case INST_LOAD_STK:
-    case INST_LOAD_SCALAR_STK:
+    CASE(INST_LOAD_STK):
+    CASE(INST_LOAD_SCALAR_STK):
 	cleanup = 1;
 	part2Ptr = NULL;
 	objPtr = OBJ_AT_TOS;		/* variable name */
@@ -2572,12 +2775,12 @@ TclExecuteByteCode(
 	Var *varPtr, *arrayPtr;
 	Tcl_Obj *objPtr, *valuePtr;
 
-    case INST_STORE_ARRAY4:
+    CASE(INST_STORE_ARRAY4):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	pcAdjustment = 5;
 	goto doStoreArrayDirect;
 
-    case INST_STORE_ARRAY1:
+    CASE(INST_STORE_ARRAY1):
 	opnd = TclGetUInt1AtPtr(pc+1);
 	pcAdjustment = 2;
 
@@ -2604,12 +2807,12 @@ TclExecuteByteCode(
 	part1Ptr = NULL;
 	goto doStoreArrayDirectFailed;
 
-    case INST_STORE_SCALAR4:
+    CASE(INST_STORE_SCALAR4):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	pcAdjustment = 5;
 	goto doStoreScalarDirect;
 
-    case INST_STORE_SCALAR1:
+    CASE(INST_STORE_SCALAR1):
 	opnd = TclGetUInt1AtPtr(pc+1);
 	pcAdjustment = 2;
 
@@ -2649,40 +2852,40 @@ TclExecuteByteCode(
 	part1Ptr = NULL;
 	goto doStoreScalar;
 
-    case INST_LAPPEND_STK:
+    CASE(INST_LAPPEND_STK):
 	valuePtr = OBJ_AT_TOS; /* value to append */
 	part2Ptr = NULL;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
 		| TCL_LIST_ELEMENT | TCL_TRACE_READS);
 	goto doStoreStk;
 
-    case INST_LAPPEND_ARRAY_STK:
+    CASE(INST_LAPPEND_ARRAY_STK):
 	valuePtr = OBJ_AT_TOS; /* value to append */
 	part2Ptr = OBJ_UNDER_TOS;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
 		| TCL_LIST_ELEMENT | TCL_TRACE_READS);
 	goto doStoreStk;
 
-    case INST_APPEND_STK:
+    CASE(INST_APPEND_STK):
 	valuePtr = OBJ_AT_TOS; /* value to append */
 	part2Ptr = NULL;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
 	goto doStoreStk;
 
-    case INST_APPEND_ARRAY_STK:
+    CASE(INST_APPEND_ARRAY_STK):
 	valuePtr = OBJ_AT_TOS; /* value to append */
 	part2Ptr = OBJ_UNDER_TOS;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
 	goto doStoreStk;
 
-    case INST_STORE_ARRAY_STK:
+    CASE(INST_STORE_ARRAY_STK):
 	valuePtr = OBJ_AT_TOS;
 	part2Ptr = OBJ_UNDER_TOS;
 	storeFlags = TCL_LEAVE_ERR_MSG;
 	goto doStoreStk;
 
-    case INST_STORE_STK:
-    case INST_STORE_SCALAR_STK:
+    CASE(INST_STORE_STK):
+    CASE(INST_STORE_SCALAR_STK):
 	valuePtr = OBJ_AT_TOS;
 	part2Ptr = NULL;
 	storeFlags = TCL_LEAVE_ERR_MSG;
@@ -2711,27 +2914,27 @@ TclExecuteByteCode(
 	    goto checkForCatch;
 	}
 
-    case INST_LAPPEND_ARRAY4:
+    CASE(INST_LAPPEND_ARRAY4):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	pcAdjustment = 5;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
 		| TCL_LIST_ELEMENT | TCL_TRACE_READS);
 	goto doStoreArray;
 
-    case INST_LAPPEND_ARRAY1:
+    CASE(INST_LAPPEND_ARRAY1):
 	opnd = TclGetUInt1AtPtr(pc+1);
 	pcAdjustment = 2;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
 		| TCL_LIST_ELEMENT | TCL_TRACE_READS);
 	goto doStoreArray;
 
-    case INST_APPEND_ARRAY4:
+    CASE(INST_APPEND_ARRAY4):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	pcAdjustment = 5;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
 	goto doStoreArray;
 
-    case INST_APPEND_ARRAY1:
+    CASE(INST_APPEND_ARRAY1):
 	opnd = TclGetUInt1AtPtr(pc+1);
 	pcAdjustment = 2;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
@@ -2760,27 +2963,27 @@ TclExecuteByteCode(
 	    goto checkForCatch;
 	}
 
-    case INST_LAPPEND_SCALAR4:
+    CASE(INST_LAPPEND_SCALAR4):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	pcAdjustment = 5;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
 		| TCL_LIST_ELEMENT | TCL_TRACE_READS);
 	goto doStoreScalar;
 
-    case INST_LAPPEND_SCALAR1:
+    CASE(INST_LAPPEND_SCALAR1):
 	opnd = TclGetUInt1AtPtr(pc+1);
 	pcAdjustment = 2;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
 		| TCL_LIST_ELEMENT | TCL_TRACE_READS);
 	goto doStoreScalar;
 
-    case INST_APPEND_SCALAR4:
+    CASE(INST_APPEND_SCALAR4):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	pcAdjustment = 5;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
 	goto doStoreScalar;
 
-    case INST_APPEND_SCALAR1:
+    CASE(INST_APPEND_SCALAR1):
 	opnd = TclGetUInt1AtPtr(pc+1);
 	pcAdjustment = 2;
 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
@@ -2843,11 +3046,11 @@ TclExecuteByteCode(
 	Tcl_Obj *part1Ptr, *part2Ptr;
 	Var *varPtr, *arrayPtr;
 
-    case INST_INCR_SCALAR1:
-    case INST_INCR_ARRAY1:
-    case INST_INCR_ARRAY_STK:
-    case INST_INCR_SCALAR_STK:
-    case INST_INCR_STK:
+    CASE(INST_INCR_SCALAR1):
+    CASE(INST_INCR_ARRAY1):
+    CASE(INST_INCR_ARRAY_STK):
+    CASE(INST_INCR_SCALAR_STK):
+    CASE(INST_INCR_STK):
 	opnd = TclGetUInt1AtPtr(pc+1);
 	incrPtr = POP_OBJECT();
 	switch (*pc) {
@@ -2862,9 +3065,9 @@ TclExecuteByteCode(
 	    goto doIncrStk;
 	}
 
-    case INST_INCR_ARRAY_STK_IMM:
-    case INST_INCR_SCALAR_STK_IMM:
-    case INST_INCR_STK_IMM:
+    CASE(INST_INCR_ARRAY_STK_IMM):
+    CASE(INST_INCR_SCALAR_STK_IMM):
+    CASE(INST_INCR_STK_IMM):
 	i = TclGetInt1AtPtr(pc+1);
 	incrPtr = Tcl_NewIntObj(i);
 	Tcl_IncrRefCount(incrPtr);
@@ -2898,7 +3101,7 @@ TclExecuteByteCode(
 	    goto checkForCatch;
 	}
 
-    case INST_INCR_ARRAY1_IMM:
+    CASE(INST_INCR_ARRAY1_IMM):
 	opnd = TclGetUInt1AtPtr(pc+1);
 	i = TclGetInt1AtPtr(pc+2);
 	incrPtr = Tcl_NewIntObj(i);
@@ -2925,7 +3128,7 @@ TclExecuteByteCode(
 	    goto checkForCatch;
 	}
 
-    case INST_INCR_SCALAR1_IMM:
+    CASE(INST_INCR_SCALAR1_IMM):
 	opnd = TclGetUInt1AtPtr(pc+1);
 	i = TclGetInt1AtPtr(pc+2);
 	pcAdjustment = 3;
@@ -3107,7 +3310,7 @@ TclExecuteByteCode(
      * ---------------------------------------------------------
      */
 
-    case INST_UPVAR: {
+    CASE(INST_UPVAR): {
 	int opnd;
 	Var *varPtr, *otherPtr;
 
@@ -3137,7 +3340,7 @@ TclExecuteByteCode(
 	    goto checkForCatch;
 	}
 
-    case INST_VARIABLE:
+    CASE(INST_VARIABLE):
 	TRACE(("variable "));
 	otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
 		(TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access",
@@ -3154,7 +3357,7 @@ TclExecuteByteCode(
 	result = TCL_ERROR;
 	goto checkForCatch;
 
-    case INST_NSUPVAR:
+    CASE(INST_NSUPVAR):
 	TRACE_WITH_OBJ(("nsupvar "), OBJ_UNDER_TOS);
 
 	{
@@ -3226,7 +3429,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(5, 1, 0);
     }
 
-    case INST_JUMP1: {
+    CASE(INST_JUMP1): {
 	int opnd;
 
 	opnd = TclGetInt1AtPtr(pc+1);
@@ -3235,7 +3438,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(opnd, 0, 0);
     }
 
-    case INST_JUMP4: {
+    CASE(INST_JUMP4): {
 	int opnd;
 
 	opnd = TclGetInt4AtPtr(pc+1);
@@ -3250,22 +3453,22 @@ TclExecuteByteCode(
 
 	/* TODO: consider rewrite so we don't compute the offset we're not
 	 * going to take. */
-    case INST_JUMP_FALSE4:
+    CASE(INST_JUMP_FALSE4):
 	jmpOffset[0] = TclGetInt4AtPtr(pc+1);	/* FALSE offset */
 	jmpOffset[1] = 5;			/* TRUE offset*/
 	goto doCondJump;
 
-    case INST_JUMP_TRUE4:
+    CASE(INST_JUMP_TRUE4):
 	jmpOffset[0] = 5;
 	jmpOffset[1] = TclGetInt4AtPtr(pc+1);
 	goto doCondJump;
 
-    case INST_JUMP_FALSE1:
+    CASE(INST_JUMP_FALSE1):
 	jmpOffset[0] = TclGetInt1AtPtr(pc+1);
 	jmpOffset[1] = 2;
 	goto doCondJump;
 
-    case INST_JUMP_TRUE1:
+    CASE(INST_JUMP_TRUE1):
 	jmpOffset[0] = 2;
 	jmpOffset[1] = TclGetInt1AtPtr(pc+1);
 
@@ -3304,7 +3507,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(jmpOffset[b], 1, 0);
     }
 
-    case INST_JUMP_TABLE: {
+    CASE(INST_JUMP_TABLE): {
 	Tcl_HashEntry *hPtr;
 	JumptableInfo *jtPtr;
 	int opnd;
@@ -3335,8 +3538,8 @@ TclExecuteByteCode(
      * and LAND is now handled by the expression compiler.
      */
 
-    case INST_LOR:
-    case INST_LAND: {
+    CASE(INST_LOR):
+    CASE(INST_LAND): {
 	/*
 	 * Operands must be boolean or numeric. No int->double conversions are
 	 * performed.
@@ -3377,7 +3580,7 @@ TclExecuteByteCode(
      *	   Start of INST_LIST and related instructions.
      */
 
-    case INST_LIST: {
+    CASE(INST_LIST): {
 	/*
 	 * Pop the opnd (objc) top stack elements into a new list obj and then
 	 * decrement their ref counts.
@@ -3391,7 +3594,7 @@ TclExecuteByteCode(
 	NEXT_INST_V(5, opnd, 1);
     }
 
-    case INST_LIST_LENGTH: {
+    CASE(INST_LIST_LENGTH): {
 	Tcl_Obj *valuePtr;
 	int length;
 
@@ -3409,7 +3612,7 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_LIST_INDEX: {
+    CASE(INST_LIST_INDEX): {
 	/*** lindex with objc == 3 ***/
 
 	Tcl_Obj *valuePtr, *value2Ptr;
@@ -3442,7 +3645,7 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_LIST_INDEX_IMM: {
+    CASE(INST_LIST_INDEX_IMM): {
 	/*** lindex with objc==3 and index in bytecode stream ***/
 
 	int listc, idx, opnd;
@@ -3489,7 +3692,7 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_LIST_INDEX_MULTI: {
+    CASE(INST_LIST_INDEX_MULTI): {
 	/*
 	 * 'lindex' with multiple index args:
 	 *
@@ -3526,7 +3729,7 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_LSET_FLAT: {
+    CASE(INST_LSET_FLAT): {
 	/*
 	 * Lset with 3, 5, or more args. Get the number of index args.
 	 */
@@ -3578,7 +3781,7 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_LSET_LIST: {
+    CASE(INST_LSET_LIST): {
 	/*
 	 * 'lset' with 4 args.
 	 */
@@ -3627,7 +3830,7 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_LIST_RANGE_IMM: {
+    CASE(INST_LIST_RANGE_IMM): {
 	/*** lrange with objc==4 and both indices in bytecode stream ***/
 
 	int listc, fromIdx, toIdx;
@@ -3708,8 +3911,8 @@ TclExecuteByteCode(
 	NEXT_INST_F(9, 1, 1);
     }
 
-    case INST_LIST_IN:
-    case INST_LIST_NOT_IN: {
+    CASE(INST_LIST_IN):
+    CASE(INST_LIST_NOT_IN): {
 	/*
 	 * Basic list containment operators.
 	 */
@@ -3785,8 +3988,8 @@ TclExecuteByteCode(
      * ---------------------------------------------------------
      */
 
-    case INST_STR_EQ:
-    case INST_STR_NEQ: {
+    CASE(INST_STR_EQ):
+    CASE(INST_STR_NEQ): {
 	/*
 	 * String (in)equality check
 	 * TODO: Consider merging into INST_STR_CMP
@@ -3851,7 +4054,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(0, 2, 1);
     }
 
-    case INST_STR_CMP: {
+    CASE(INST_STR_CMP): {
 	/*
 	 * String compare.
 	 */
@@ -3960,7 +4163,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(1, 2, 1);
     }
 
-    case INST_STR_LEN: {
+    CASE(INST_STR_LEN): {
 	int length;
 	Tcl_Obj *valuePtr;
 
@@ -3976,7 +4179,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(1, 1, 1);
     }
 
-    case INST_STR_INDEX: {
+    CASE(INST_STR_INDEX): {
 	/*
 	 * String compare.
 	 */
@@ -4041,7 +4244,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(1, 2, 1);
     }
 
-    case INST_STR_MATCH: {
+    CASE(INST_STR_MATCH): {
 	int nocase, match;
 	Tcl_Obj *valuePtr, *value2Ptr;
 
@@ -4086,12 +4289,12 @@ TclExecuteByteCode(
 	NEXT_INST_F(2, 2, 1);
     }
 
-    case INST_EQ:
-    case INST_NEQ:
-    case INST_LT:
-    case INST_GT:
-    case INST_LE:
-    case INST_GE: {
+    CASE(INST_EQ):
+    CASE(INST_NEQ):
+    CASE(INST_LT):
+    CASE(INST_GT):
+    CASE(INST_LE):
+    CASE(INST_GE): {
 	Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
 	Tcl_Obj *value2Ptr = OBJ_AT_TOS;
 	ClientData ptr1, ptr2;
@@ -4403,9 +4606,9 @@ TclExecuteByteCode(
 	NEXT_INST_F(0, 2, 1);
     }
 
-    case INST_MOD:
-    case INST_LSHIFT:
-    case INST_RSHIFT: {
+    CASE(INST_MOD):
+    CASE(INST_LSHIFT):
+    CASE(INST_RSHIFT): {
 	Tcl_Obj *value2Ptr = OBJ_AT_TOS;
 	Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
 	ClientData ptr1, ptr2;
@@ -4862,9 +5065,9 @@ TclExecuteByteCode(
 	NEXT_INST_F(1, 2, 1);
     }
 
-    case INST_BITOR:
-    case INST_BITXOR:
-    case INST_BITAND: {
+    CASE(INST_BITOR):
+    CASE(INST_BITXOR):
+    CASE(INST_BITAND): {
 	ClientData ptr1, ptr2;
 	int type1, type2;
 	Tcl_Obj *value2Ptr = OBJ_AT_TOS;
@@ -5105,11 +5308,11 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_EXPON:
-    case INST_ADD:
-    case INST_SUB:
-    case INST_DIV:
-    case INST_MULT: {
+    CASE(INST_EXPON):
+    CASE(INST_ADD):
+    CASE(INST_SUB):
+    CASE(INST_DIV):
+    CASE(INST_MULT): {
 	ClientData ptr1, ptr2;
 	int type1, type2;
 	Tcl_Obj *value2Ptr = OBJ_AT_TOS;
@@ -5838,7 +6041,7 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_LNOT: {
+    CASE(INST_LNOT): {
 	int b;
 	Tcl_Obj *valuePtr = OBJ_AT_TOS;
 
@@ -5856,7 +6059,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(1, 1, 1);
     }
 
-    case INST_BITNOT: {
+    CASE(INST_BITNOT): {
 	mp_int big;
 	ClientData ptr;
 	int type;
@@ -5908,7 +6111,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(1, 0, 0);
     }
 
-    case INST_UMINUS: {
+    CASE(INST_UMINUS): {
 	ClientData ptr;
 	int type;
 	Tcl_Obj *valuePtr = OBJ_AT_TOS;
@@ -5999,8 +6202,8 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_UPLUS:
-    case INST_TRY_CVT_TO_NUMERIC: {
+    CASE(INST_UPLUS):
+    CASE(INST_TRY_CVT_TO_NUMERIC): {
 	/*
 	 * Try to convert the topmost stack object to numeric object. This is
 	 * done in order to support [expr]'s policy of interpreting operands
@@ -6085,7 +6288,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(1, 0, 0);
     }
 
-    case INST_BREAK:
+    CASE(INST_BREAK):
 	/*
 	DECACHE_STACK_INFO();
 	Tcl_ResetResult(interp);
@@ -6095,7 +6298,7 @@ TclExecuteByteCode(
 	cleanup = 0;
 	goto processExceptionReturn;
 
-    case INST_CONTINUE:
+    CASE(INST_CONTINUE):
 	/*
 	DECACHE_STACK_INFO();
 	Tcl_ResetResult(interp);
@@ -6105,7 +6308,7 @@ TclExecuteByteCode(
 	cleanup = 0;
 	goto processExceptionReturn;
 
-    case INST_FOREACH_START4: {
+    CASE(INST_FOREACH_START4): {
 	/*
 	 * Initialize the temporary local var that holds the count of the
 	 * number of iterations of the loop body to -1.
@@ -6144,7 +6347,7 @@ TclExecuteByteCode(
 #endif
     }
 
-    case INST_FOREACH_STEP4: {
+    CASE(INST_FOREACH_STEP4): {
 	/*
 	 * "Step" a foreach loop (i.e., begin its next iteration) by assigning
 	 * the next value list element to each loop var.
@@ -6276,7 +6479,7 @@ TclExecuteByteCode(
 	}
     }
 
-    case INST_BEGIN_CATCH4:
+    CASE(INST_BEGIN_CATCH4):
 	/*
 	 * Record start of the catch command with exception range index equal
 	 * to the operand. Push the current stack depth onto the special catch
@@ -6289,14 +6492,14 @@ TclExecuteByteCode(
 		(int) CURR_DEPTH));
 	NEXT_INST_F(5, 0, 0);
 
-    case INST_END_CATCH:
+    CASE(INST_END_CATCH):
 	catchTop--;
 	Tcl_ResetResult(interp);
 	result = TCL_OK;
 	TRACE(("=> catchTop=%d\n", (catchTop - initCatchTop - 1)));
 	NEXT_INST_F(1, 0, 0);
 
-    case INST_PUSH_RESULT:
+    CASE(INST_PUSH_RESULT):
 	objResultPtr = Tcl_GetObjResult(interp);
 	TRACE_WITH_OBJ(("=> "), objResultPtr);
 
@@ -6313,12 +6516,12 @@ TclExecuteByteCode(
 
 	NEXT_INST_F(1, 0, -1);
 
-    case INST_PUSH_RETURN_CODE:
+    CASE(INST_PUSH_RETURN_CODE):
 	TclNewIntObj(objResultPtr, result);
 	TRACE(("=> %u\n", result));
 	NEXT_INST_F(1, 0, 1);
 
-    case INST_PUSH_RETURN_OPTIONS:
+    CASE(INST_PUSH_RETURN_OPTIONS):
 	objResultPtr = Tcl_GetReturnOptions(interp, result);
 	TRACE_WITH_OBJ(("=> "), objResultPtr);
 	NEXT_INST_F(1, 0, 1);
@@ -6329,7 +6532,7 @@ TclExecuteByteCode(
 	Tcl_Obj *dictPtr, *valPtr;
 	Var *varPtr;
 
-    case INST_DICT_GET:
+    CASE(INST_DICT_GET):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	TRACE(("%u => ", opnd));
 	dictPtr = OBJ_AT_DEPTH(opnd);
@@ -6363,9 +6566,9 @@ TclExecuteByteCode(
 	}
 	goto checkForCatch;
 
-    case INST_DICT_SET:
-    case INST_DICT_UNSET:
-    case INST_DICT_INCR_IMM:
+    CASE(INST_DICT_SET):
+    CASE(INST_DICT_UNSET):
+    CASE(INST_DICT_INCR_IMM):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	opnd2 = TclGetUInt4AtPtr(pc+5);
 
@@ -6473,8 +6676,8 @@ TclExecuteByteCode(
 	TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
 	NEXT_INST_V(9, cleanup, 1);
 
-    case INST_DICT_APPEND:
-    case INST_DICT_LAPPEND:
+    CASE(INST_DICT_APPEND):
+    CASE(INST_DICT_LAPPEND):
 	opnd = TclGetUInt4AtPtr(pc+1);
 
 	varPtr = &(compiledLocals[opnd]);
@@ -6597,7 +6800,7 @@ TclExecuteByteCode(
 	Var *varPtr;
 	Tcl_DictSearch *searchPtr;
 
-    case INST_DICT_FIRST:
+    CASE(INST_DICT_FIRST):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	TRACE(("%u => ", opnd));
 	dictPtr = POP_OBJECT();
@@ -6624,7 +6827,7 @@ TclExecuteByteCode(
 	Tcl_IncrRefCount(statePtr);
 	goto pushDictIteratorResult;
 
-    case INST_DICT_NEXT:
+    CASE(INST_DICT_NEXT):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	TRACE(("%u => ", opnd));
 	statePtr = compiledLocals[opnd].value.objPtr;
@@ -6648,7 +6851,7 @@ TclExecuteByteCode(
 	/* TODO: consider opt like INST_FOREACH_STEP4 */
 	NEXT_INST_F(5, 0, 1);
 
-    case INST_DICT_DONE:
+    CASE(INST_DICT_DONE):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	TRACE(("%u => ", opnd));
 	statePtr = compiledLocals[opnd].value.objPtr;
@@ -6689,7 +6892,7 @@ TclExecuteByteCode(
 	DictUpdateInfo *duiPtr;
 	Var *varPtr;
 
-    case INST_DICT_UPDATE_START:
+    CASE(INST_DICT_UPDATE_START):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	opnd2 = TclGetUInt4AtPtr(pc+5);
 	varPtr = &(compiledLocals[opnd]);
@@ -6744,7 +6947,7 @@ TclExecuteByteCode(
 	}
 	NEXT_INST_F(9, 0, 0);
 
-    case INST_DICT_UPDATE_END:
+    CASE(INST_DICT_UPDATE_END):
 	opnd = TclGetUInt4AtPtr(pc+1);
 	opnd2 = TclGetUInt4AtPtr(pc+5);
 	varPtr = &(compiledLocals[opnd]);
@@ -6818,7 +7021,7 @@ TclExecuteByteCode(
 	NEXT_INST_F(9, 1, 0);
     }
 
-    default:
+    BAD_INST():
 	Tcl_Panic("TclExecuteByteCode: unrecognized opCode %u", *pc);
     } /* end of switch on opCode */
 
Index: unix/configure
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/configure,v
retrieving revision 1.209
diff -u -p -r1.209 configure
--- unix/configure	30 Oct 2007 19:03:56 -0000	1.209
+++ unix/configure	9 Nov 2007 19:02:17 -0000
@@ -17679,6 +17679,139 @@ echo "${ECHO_T}supplied by Tcl" >&6
     INSTALL_TZDATA=install-tzdata
 fi
 
+#------------------------------------------------------------------------
+#	Check for computed goto and __builtin_expect support.
+#------------------------------------------------------------------------
+
+echo "$as_me:$LINENO: checking for computed goto" >&5
+echo $ECHO_N "checking for computed goto... $ECHO_C" >&6
+if test "${tcl_cv_cc_computed_goto+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stddef.h>
+int
+main ()
+{
+
+	int a; ptrdiff_t offset = (char*) &&l - (char*) &&t;
+	goto *(void*)(offset + (char*) &&t); t: a = 0; l: a = 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  tcl_cv_cc_computed_goto=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_cv_cc_computed_goto=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $tcl_cv_cc_computed_goto" >&5
+echo "${ECHO_T}$tcl_cv_cc_computed_goto" >&6
+if test $tcl_cv_cc_computed_goto = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_COMPUTED_GOTO 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for __builtin_expect" >&5
+echo $ECHO_N "checking for __builtin_expect... $ECHO_C" >&6
+if test "${tcl_cv_cc_builtin_expect+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+	int a = 1; if (__builtin_expect(a, 1)) {a = 0;}
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  tcl_cv_cc_builtin_expect=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_cv_cc_builtin_expect=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $tcl_cv_cc_builtin_expect" >&5
+echo "${ECHO_T}$tcl_cv_cc_builtin_expect" >&6
+if test $tcl_cv_cc_builtin_expect = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_BUILTIN_EXPECT 1
+_ACEOF
+
+fi
+
 #--------------------------------------------------------------------
 #	DTrace support
 #--------------------------------------------------------------------
Index: unix/configure.in
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/configure.in,v
retrieving revision 1.167
diff -u -p -r1.167 configure.in
--- unix/configure.in	30 Oct 2007 19:03:57 -0000	1.167
+++ unix/configure.in	9 Nov 2007 19:02:17 -0000
@@ -631,6 +631,27 @@ then
     INSTALL_TZDATA=install-tzdata
 fi
 
+#------------------------------------------------------------------------
+#	Check for computed goto and __builtin_expect support.
+#------------------------------------------------------------------------
+
+AC_CACHE_CHECK([for computed goto], tcl_cv_cc_computed_goto, [
+    AC_TRY_COMPILE([#include <stddef.h>], [
+	int a; ptrdiff_t offset = (char*) &&l - (char*) &&t;
+	goto *(void*)(offset + (char*) &&t); t: a = 0; l: a = 1;
+	], tcl_cv_cc_computed_goto=yes, tcl_cv_cc_computed_goto=no)])
+if test $tcl_cv_cc_computed_goto = yes; then
+    AC_DEFINE(HAVE_COMPUTED_GOTO, 1, [Is computed goto available?])
+fi
+
+AC_CACHE_CHECK([for __builtin_expect], tcl_cv_cc_builtin_expect, [
+    AC_TRY_COMPILE(, [
+	int a = 1; if (__builtin_expect(a, 1)) {a = 0;}
+	], tcl_cv_cc_builtin_expect=yes, tcl_cv_cc_builtin_expect=no)])
+if test $tcl_cv_cc_builtin_expect = yes; then
+    AC_DEFINE(HAVE_BUILTIN_EXPECT, 1, [Is __builtin_expect available?])
+fi
+
 #--------------------------------------------------------------------
 #	DTrace support
 #--------------------------------------------------------------------