summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authormig <mig>2013-01-15 23:08:16 (GMT)
committermig <mig>2013-01-15 23:08:16 (GMT)
commit349f5d5c8679ca2b1ae82153e342c489922fd23a (patch)
treef56498e4bfa1ff8ccfdd1af23e4e0d0d9813bb15 /generic
parent5d968e9a205abb7d1e05e07295591f158e3abf4d (diff)
parent62f939ac8c1c9864a925460ed628c01d3c620a50 (diff)
downloadtcl-349f5d5c8679ca2b1ae82153e342c489922fd23a.zip
tcl-349f5d5c8679ca2b1ae82153e342c489922fd23a.tar.gz
tcl-349f5d5c8679ca2b1ae82153e342c489922fd23a.tar.bz2
TEBC is almost gone, down to 44 insts mostly for math. No commands are
compiled, all (including [set]) are dispatched via EvalObjv. This is just a removal, redesign and reconstruction still pending ...
Diffstat (limited to 'generic')
-rw-r--r--generic/tcl.decls6
-rw-r--r--generic/tclBasic.c196
-rw-r--r--generic/tclBinary.c12
-rw-r--r--generic/tclCmdAH.c62
-rw-r--r--generic/tclCmdIL.c44
-rw-r--r--generic/tclCmdMZ.c88
-rw-r--r--generic/tclCompCmds.c6035
-rw-r--r--generic/tclCompCmdsSZ.c3061
-rw-r--r--generic/tclCompExpr.c8
-rw-r--r--generic/tclCompile.c1854
-rw-r--r--generic/tclCompile.h1539
-rw-r--r--generic/tclDecls.h9
-rw-r--r--generic/tclDictObj.c36
-rw-r--r--generic/tclEnsemble.c852
-rw-r--r--generic/tclExecute.c4232
-rw-r--r--generic/tclIOCmd.c32
-rw-r--r--generic/tclIndexObj.c6
-rw-r--r--generic/tclInt.h335
-rw-r--r--generic/tclLiteral.c266
-rw-r--r--generic/tclNRE.h4
-rw-r--r--generic/tclNamesp.c32
-rw-r--r--generic/tclOO.c4
-rw-r--r--generic/tclOOInfo.c50
-rw-r--r--generic/tclOOMethod.c2
-rw-r--r--generic/tclObj.c14
-rw-r--r--generic/tclParse.c248
-rw-r--r--generic/tclProc.c359
-rw-r--r--generic/tclResolve.c12
-rw-r--r--generic/tclStubInit.c2
-rw-r--r--generic/tclTrace.c46
-rw-r--r--generic/tclVar.c22
31 files changed, 636 insertions, 18832 deletions
diff --git a/generic/tcl.decls b/generic/tcl.decls
index 2d41134..ac416d7 100644
--- a/generic/tcl.decls
+++ b/generic/tcl.decls
@@ -2300,9 +2300,9 @@ declare 625 {
}
# TIP #356 (NR-enabled substitution) dgp
-declare 626 {
- int Tcl_NRSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags)
-}
+#declare 626 {
+# int Tcl_NRSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags)
+#}
# TIP #357 (Export TclLoadFile and TclpFindSymbol) kbk
declare 627 {
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index aee0c99..a32247b 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -220,59 +220,59 @@ static const CmdInfo builtInCmds[] = {
* Commands in the generic core.
*/
- {"append", Tcl_AppendObjCmd, TclCompileAppendCmd, 1},
- {"apply", Tcl_ApplyObjCmd, NULL, 1},
- {"break", Tcl_BreakObjCmd, TclCompileBreakCmd, 1},
- {"catch", Tcl_CatchObjCmd, TclCompileCatchCmd, 1},
- {"concat", Tcl_ConcatObjCmd, NULL, 1},
- {"continue", Tcl_ContinueObjCmd, TclCompileContinueCmd, 1},
- {"coroutine", TclNRCoroutineObjCmd, NULL, 1},
- {"error", Tcl_ErrorObjCmd, TclCompileErrorCmd, 1},
- {"eval", Tcl_EvalObjCmd, NULL, 1},
- {"expr", Tcl_ExprObjCmd, TclCompileExprCmd, 1},
- {"for", Tcl_ForObjCmd, TclCompileForCmd, 1},
- {"foreach", Tcl_ForeachObjCmd, TclCompileForeachCmd, 1},
- {"format", Tcl_FormatObjCmd, TclCompileFormatCmd, 1},
- {"global", Tcl_GlobalObjCmd, TclCompileGlobalCmd, 1},
- {"if", Tcl_IfObjCmd, TclCompileIfCmd, 1},
- {"incr", Tcl_IncrObjCmd, TclCompileIncrCmd, 1},
- {"join", Tcl_JoinObjCmd, NULL, 1},
- {"lappend", Tcl_LappendObjCmd, TclCompileLappendCmd, 1},
- {"lassign", Tcl_LassignObjCmd, TclCompileLassignCmd, 1},
- {"lindex", Tcl_LindexObjCmd, TclCompileLindexCmd, 1},
- {"linsert", Tcl_LinsertObjCmd, NULL, 1},
- {"list", Tcl_ListObjCmd, TclCompileListCmd, 1},
- {"llength", Tcl_LlengthObjCmd, TclCompileLlengthCmd, 1},
- {"lmap", Tcl_LmapObjCmd, TclCompileLmapCmd, 1},
- {"lrange", Tcl_LrangeObjCmd, TclCompileLrangeCmd, 1},
- {"lrepeat", Tcl_LrepeatObjCmd, NULL, 1},
- {"lreplace", Tcl_LreplaceObjCmd, TclCompileLreplaceCmd, 1},
- {"lreverse", Tcl_LreverseObjCmd, NULL, 1},
- {"lsearch", Tcl_LsearchObjCmd, NULL, 1},
- {"lset", Tcl_LsetObjCmd, TclCompileLsetCmd, 1},
- {"lsort", Tcl_LsortObjCmd, NULL, 1},
- {"package", Tcl_PackageObjCmd, NULL, 1},
- {"proc", Tcl_ProcObjCmd, NULL, 1},
- {"regexp", Tcl_RegexpObjCmd, TclCompileRegexpCmd, 1},
- {"regsub", Tcl_RegsubObjCmd, TclCompileRegsubCmd, 1},
- {"rename", Tcl_RenameObjCmd, NULL, 1},
- {"return", Tcl_ReturnObjCmd, TclCompileReturnCmd, 1},
- {"scan", Tcl_ScanObjCmd, NULL, 1},
- {"set", Tcl_SetObjCmd, TclCompileSetCmd, 1},
- {"split", Tcl_SplitObjCmd, NULL, 1},
- {"subst", Tcl_SubstObjCmd, TclCompileSubstCmd, 1},
- {"switch", Tcl_SwitchObjCmd, TclCompileSwitchCmd, 1},
- {"tailcall", TclNRTailcallObjCmd, TclCompileTailcallCmd, 1},
- {"throw", Tcl_ThrowObjCmd, TclCompileThrowCmd, 1},
- {"trace", Tcl_TraceObjCmd, NULL, 1},
- {"try", Tcl_TryObjCmd, TclCompileTryCmd, 1},
- {"unset", Tcl_UnsetObjCmd, TclCompileUnsetCmd, 1},
- {"uplevel", Tcl_UplevelObjCmd, NULL, 1},
- {"upvar", Tcl_UpvarObjCmd, TclCompileUpvarCmd, 1},
- {"variable", Tcl_VariableObjCmd, TclCompileVariableCmd, 1},
- {"while", Tcl_WhileObjCmd, TclCompileWhileCmd, 1},
- {"yield", TclNRYieldObjCmd, TclCompileYieldCmd, 1},
- {"yieldto", TclNRYieldToObjCmd, NULL, 1},
+ {"append", Tcl_AppendObjCmd, NULL, 1},
+ {"apply", Tcl_ApplyObjCmd, NULL, 1},
+ {"break", Tcl_BreakObjCmd, NULL, 1},
+ {"catch", Tcl_CatchObjCmd, NULL, 1},
+ {"concat", Tcl_ConcatObjCmd, NULL, 1},
+ {"continue", Tcl_ContinueObjCmd, NULL, 1},
+ {"coroutine", TclNRCoroutineObjCmd, NULL, 1},
+ {"error", Tcl_ErrorObjCmd, NULL, 1},
+ {"eval", Tcl_EvalObjCmd, NULL, 1},
+ {"expr", Tcl_ExprObjCmd, NULL, 1},
+ {"for", Tcl_ForObjCmd, NULL, 1},
+ {"foreach", Tcl_ForeachObjCmd, NULL, 1},
+ {"format", Tcl_FormatObjCmd, NULL, 1},
+ {"global", Tcl_GlobalObjCmd, NULL, 1},
+ {"if", Tcl_IfObjCmd, NULL, 1},
+ {"incr", Tcl_IncrObjCmd, NULL, 1},
+ {"join", Tcl_JoinObjCmd, NULL, 1},
+ {"lappend", Tcl_LappendObjCmd, NULL, 1},
+ {"lassign", Tcl_LassignObjCmd, NULL, 1},
+ {"lindex", Tcl_LindexObjCmd, NULL, 1},
+ {"linsert", Tcl_LinsertObjCmd, NULL, 1},
+ {"list", Tcl_ListObjCmd, NULL, 1},
+ {"llength", Tcl_LlengthObjCmd, NULL, 1},
+ {"lmap", Tcl_LmapObjCmd, NULL, 1},
+ {"lrange", Tcl_LrangeObjCmd, NULL, 1},
+ {"lrepeat", Tcl_LrepeatObjCmd, NULL, 1},
+ {"lreplace", Tcl_LreplaceObjCmd, NULL, 1},
+ {"lreverse", Tcl_LreverseObjCmd, NULL, 1},
+ {"lsearch", Tcl_LsearchObjCmd, NULL, 1},
+ {"lset", Tcl_LsetObjCmd, NULL, 1},
+ {"lsort", Tcl_LsortObjCmd, NULL, 1},
+ {"package", Tcl_PackageObjCmd, NULL, 1},
+ {"proc", Tcl_ProcObjCmd, NULL, 1},
+ {"regexp", Tcl_RegexpObjCmd, NULL, 1},
+ {"regsub", Tcl_RegsubObjCmd, NULL, 1},
+ {"rename", Tcl_RenameObjCmd, NULL, 1},
+ {"return", Tcl_ReturnObjCmd, NULL, 1},
+ {"scan", Tcl_ScanObjCmd, NULL, 1},
+ {"set", Tcl_SetObjCmd, NULL, 1},
+ {"split", Tcl_SplitObjCmd, NULL, 1},
+ {"subst", Tcl_SubstObjCmd, NULL, 1},
+ {"switch", Tcl_SwitchObjCmd, NULL, 1},
+ {"tailcall", TclNRTailcallObjCmd, NULL, 1},
+ {"throw", Tcl_ThrowObjCmd, NULL, 1},
+ {"trace", Tcl_TraceObjCmd, NULL, 1},
+ {"try", Tcl_TryObjCmd, NULL, 1},
+ {"unset", Tcl_UnsetObjCmd, NULL, 1},
+ {"uplevel", Tcl_UplevelObjCmd, NULL, 1},
+ {"upvar", Tcl_UpvarObjCmd, NULL, 1},
+ {"variable", Tcl_VariableObjCmd, NULL, 1},
+ {"while", Tcl_WhileObjCmd, NULL, 1},
+ {"yield", TclNRYieldObjCmd, NULL, 1},
+ {"yieldto", TclNRYieldToObjCmd, NULL, 1},
/*
* Commands in the OS-interface. Note that many of these are unsafe.
@@ -480,9 +480,6 @@ Tcl_CreateInterp(void)
char c[sizeof(short)];
short s;
} order;
-#ifdef TCL_COMPILE_STATS
- ByteCodeStats *statsPtr;
-#endif /* TCL_COMPILE_STATS */
char mathFuncName[32];
CallFrame *framePtr;
int result;
@@ -553,7 +550,6 @@ Tcl_CreateInterp(void)
iPtr->cmdCount = 0;
TclInitLiteralTable(&iPtr->literalTable);
- iPtr->compileEpoch = 0;
iPtr->compiledProcPtr = NULL;
iPtr->resolverPtr = NULL;
iPtr->evalFlags = 0;
@@ -647,39 +643,6 @@ Tcl_CreateInterp(void)
Tcl_MutexUnlock(&cancelLock);
/*
- * Initialize the compilation and execution statistics kept for this
- * interpreter.
- */
-
-#ifdef TCL_COMPILE_STATS
- statsPtr = &iPtr->stats;
- statsPtr->numExecutions = 0;
- statsPtr->numCompilations = 0;
- statsPtr->numByteCodesFreed = 0;
- memset(statsPtr->instructionCount, 0,
- sizeof(statsPtr->instructionCount));
-
- statsPtr->totalSrcBytes = 0.0;
- statsPtr->totalByteCodeBytes = 0.0;
- statsPtr->currentSrcBytes = 0.0;
- statsPtr->currentByteCodeBytes = 0.0;
- memset(statsPtr->srcCount, 0, sizeof(statsPtr->srcCount));
- memset(statsPtr->byteCodeCount, 0, sizeof(statsPtr->byteCodeCount));
- memset(statsPtr->lifetimeCount, 0, sizeof(statsPtr->lifetimeCount));
-
- statsPtr->currentInstBytes = 0.0;
- statsPtr->currentLitBytes = 0.0;
- statsPtr->currentExceptBytes = 0.0;
- statsPtr->currentAuxBytes = 0.0;
- statsPtr->currentCmdMapBytes = 0.0;
-
- statsPtr->numLiteralsCreated = 0;
- statsPtr->totalLitStringBytes = 0.0;
- statsPtr->currentLitStringBytes = 0.0;
- memset(statsPtr->literalCount, 0, sizeof(statsPtr->literalCount));
-#endif /* TCL_COMPILE_STATS */
-
- /*
* Initialise the stub table pointer.
*/
@@ -770,8 +733,6 @@ Tcl_CreateInterp(void)
* Create unsupported commands for debugging bytecode and objects.
*/
- Tcl_CreateObjCommand(interp, "::tcl::unsupported::disassemble",
- Tcl_DisassembleObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "::tcl::unsupported::representation",
Tcl_RepresentationCmd, NULL, NULL);
@@ -1254,7 +1215,6 @@ Tcl_DeleteInterp(
*/
iPtr->flags |= DELETED;
- iPtr->compileEpoch++;
/*
* Ensure that the interpreter is eventually deleted.
@@ -1652,18 +1612,6 @@ Tcl_HideCommand(
cmdPtr->hPtr = hPtr;
Tcl_SetHashValue(hPtr, cmdPtr);
- /*
- * If the command being hidden has a compile function, increment the
- * interpreter's compileEpoch to invalidate its compiled code. This makes
- * sure that we don't later try to execute old code compiled with
- * command-specific (i.e., inline) bytecodes for the now-hidden command.
- * This field is checked in Tcl_EvalObj and ObjInterpProc, and code whose
- * compilation epoch doesn't match is recompiled.
- */
-
- if (cmdPtr->compileProc != NULL) {
- iPtr->compileEpoch++;
- }
return TCL_OK;
}
@@ -1823,18 +1771,6 @@ Tcl_ExposeCommand(
* TclResetShadowedCmdRefs(interp, cmdPtr);
*/
- /*
- * If the command being exposed has a compile function, increment
- * interpreter's compileEpoch to invalidate its compiled code. This makes
- * sure that we don't later try to execute old code compiled assuming the
- * command is hidden. This field is checked in Tcl_EvalObj and
- * ObjInterpProc, and code whose compilation epoch doesn't match is
- * recompiled.
- */
-
- if (cmdPtr->compileProc != NULL) {
- iPtr->compileEpoch++;
- }
return TCL_OK;
}
@@ -2478,17 +2414,6 @@ TclRenameCommand(
cmdPtr->cmdEpoch++;
/*
- * If the command being renamed has a compile function, increment the
- * interpreter's compileEpoch to invalidate its compiled code. This makes
- * sure that we don't later try to execute old code compiled for the
- * now-renamed command.
- */
-
- if (cmdPtr->compileProc != NULL) {
- iPtr->compileEpoch++;
- }
-
- /*
* Now free the Command structure, if the "oldName" command has been
* deleted by invocation of rename traces.
*/
@@ -2735,19 +2660,6 @@ Tcl_DeleteCommandFromToken(
TclInvalidateNsCmdLookup(cmdPtr->nsPtr);
- /*
- * If the command being deleted has a compile function, increment the
- * interpreter's compileEpoch to invalidate its compiled code. This makes
- * sure that we don't later try to execute old code compiled with
- * command-specific (i.e., inline) bytecodes for the now-deleted command.
- * This field is checked in Tcl_EvalObj and ObjInterpProc, and code whose
- * compilation epoch doesn't match is recompiled.
- */
-
- if (cmdPtr->compileProc != NULL) {
- iPtr->compileEpoch++;
- }
-
if (cmdPtr->deleteProc != NULL) {
/*
* Delete the command's client data. If this was an imported command
@@ -4967,7 +4879,7 @@ TclNREvalObjEx(
*/
int allowExceptions = (iPtr->evalFlags & TCL_ALLOW_EXCEPTIONS);
- ByteCode *codePtr;
+ struct ByteCode *codePtr;
CallFrame *savedVarFramePtr = NULL; /* Saves old copy of
* iPtr->varFramePtr in case
* TCL_EVAL_GLOBAL was set. */
diff --git a/generic/tclBinary.c b/generic/tclBinary.c
index 3f0f246..babd725 100644
--- a/generic/tclBinary.c
+++ b/generic/tclBinary.c
@@ -132,22 +132,22 @@ static const char B64Digits[65] = {
*/
static const EnsembleImplMap binaryMap[] = {
- { "format", BinaryFormatCmd, TclCompileBasicMin1ArgCmd, NULL, 0 },
- { "scan", BinaryScanCmd, TclCompileBasicMin2ArgCmd, NULL, 0 },
+ { "format", BinaryFormatCmd, NULL, NULL, 0 },
+ { "scan", BinaryScanCmd, NULL, NULL, 0 },
{ "encode", NULL, NULL, NULL, 0 },
{ "decode", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const EnsembleImplMap encodeMap[] = {
- { "hex", BinaryEncodeHex, TclCompileBasic1ArgCmd, (ClientData)HexDigits, 0 },
+ { "hex", BinaryEncodeHex, NULL, (ClientData)HexDigits, 0 },
{ "uuencode", BinaryEncode64, NULL, (ClientData)UueDigits, 0 },
{ "base64", BinaryEncode64, NULL, (ClientData)B64Digits, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const EnsembleImplMap decodeMap[] = {
- { "hex", BinaryDecodeHex, TclCompileBasic1Or2ArgCmd, NULL, 0 },
- { "uuencode", BinaryDecodeUu, TclCompileBasic1Or2ArgCmd, NULL, 0 },
- { "base64", BinaryDecode64, TclCompileBasic1Or2ArgCmd, NULL, 0 },
+ { "hex", BinaryDecodeHex, NULL, NULL, 0 },
+ { "uuencode", BinaryDecodeUu, NULL, NULL, 0 },
+ { "base64", BinaryDecode64, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c
index da4afd4..775e421 100644
--- a/generic/tclCmdAH.c
+++ b/generic/tclCmdAH.c
@@ -765,40 +765,40 @@ TclInitFileCmd(
*/
static const EnsembleImplMap initMap[] = {
- {"atime", FileAttrAccessTimeCmd, TclCompileBasic1Or2ArgCmd, NULL, 0},
+ {"atime", FileAttrAccessTimeCmd, NULL, NULL, 0},
{"attributes", TclFileAttrsCmd, NULL, NULL, 0},
- {"channels", TclChannelNamesCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
+ {"channels", TclChannelNamesCmd, NULL, NULL, 0},
{"copy", TclFileCopyCmd, NULL, NULL, 0},
- {"delete", TclFileDeleteCmd, TclCompileBasicMin0ArgCmd, NULL, 0},
- {"dirname", PathDirNameCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"executable", FileAttrIsExecutableCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"exists", FileAttrIsExistingCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"extension", PathExtensionCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"isdirectory", FileAttrIsDirectoryCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"isfile", FileAttrIsFileCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"join", PathJoinCmd, TclCompileBasicMin1ArgCmd, NULL, 0},
- {"link", TclFileLinkCmd, TclCompileBasic1To3ArgCmd, NULL, 0},
- {"lstat", FileAttrLinkStatCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"mtime", FileAttrModifyTimeCmd, TclCompileBasic1Or2ArgCmd, NULL, 0},
- {"mkdir", TclFileMakeDirsCmd, TclCompileBasicMin0ArgCmd, NULL, 0},
- {"nativename", PathNativeNameCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"normalize", PathNormalizeCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"owned", FileAttrIsOwnedCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"pathtype", PathTypeCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"readable", FileAttrIsReadableCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"readlink", TclFileReadLinkCmd, TclCompileBasic1ArgCmd, NULL, 0},
+ {"delete", TclFileDeleteCmd, NULL, NULL, 0},
+ {"dirname", PathDirNameCmd, NULL, NULL, 0},
+ {"executable", FileAttrIsExecutableCmd, NULL, NULL, 0},
+ {"exists", FileAttrIsExistingCmd, NULL, NULL, 0},
+ {"extension", PathExtensionCmd, NULL, NULL, 0},
+ {"isdirectory", FileAttrIsDirectoryCmd, NULL, NULL, 0},
+ {"isfile", FileAttrIsFileCmd, NULL, NULL, 0},
+ {"join", PathJoinCmd, NULL, NULL, 0},
+ {"link", TclFileLinkCmd, NULL, NULL, 0},
+ {"lstat", FileAttrLinkStatCmd, NULL, NULL, 0},
+ {"mtime", FileAttrModifyTimeCmd, NULL, NULL, 0},
+ {"mkdir", TclFileMakeDirsCmd, NULL, NULL, 0},
+ {"nativename", PathNativeNameCmd, NULL, NULL, 0},
+ {"normalize", PathNormalizeCmd, NULL, NULL, 0},
+ {"owned", FileAttrIsOwnedCmd, NULL, NULL, 0},
+ {"pathtype", PathTypeCmd, NULL, NULL, 0},
+ {"readable", FileAttrIsReadableCmd, NULL, NULL, 0},
+ {"readlink", TclFileReadLinkCmd, NULL, NULL, 0},
{"rename", TclFileRenameCmd, NULL, NULL, 0},
- {"rootname", PathRootNameCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"separator", FilesystemSeparatorCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"size", FileAttrSizeCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"split", PathSplitCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"stat", FileAttrStatCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"system", PathFilesystemCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"tail", PathTailCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"tempfile", TclFileTemporaryCmd, TclCompileBasic0To2ArgCmd, NULL, 0},
- {"type", FileAttrTypeCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"volumes", FilesystemVolumesCmd, TclCompileBasic0ArgCmd, NULL, 0},
- {"writable", FileAttrIsWritableCmd, TclCompileBasic1ArgCmd, NULL, 0},
+ {"rootname", PathRootNameCmd, NULL, NULL, 0},
+ {"separator", FilesystemSeparatorCmd, NULL, NULL, 0},
+ {"size", FileAttrSizeCmd, NULL, NULL, 0},
+ {"split", PathSplitCmd, NULL, NULL, 0},
+ {"stat", FileAttrStatCmd, NULL, NULL, 0},
+ {"system", PathFilesystemCmd, NULL, NULL, 0},
+ {"tail", PathTailCmd, NULL, NULL, 0},
+ {"tempfile", TclFileTemporaryCmd, NULL, NULL, 0},
+ {"type", FileAttrTypeCmd, NULL, NULL, 0},
+ {"volumes", FilesystemVolumesCmd, NULL, NULL, 0},
+ {"writable", FileAttrIsWritableCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, 0}
};
return TclMakeEnsemble(interp, "file", initMap);
diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c
index 2c41ada..ddab1fa 100644
--- a/generic/tclCmdIL.c
+++ b/generic/tclCmdIL.c
@@ -155,28 +155,28 @@ static Tcl_Obj * SelectObjFromSublist(Tcl_Obj *firstPtr,
*/
static const EnsembleImplMap defaultInfoMap[] = {
- {"args", InfoArgsCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"body", InfoBodyCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"cmdcount", InfoCmdCountCmd, TclCompileBasic0ArgCmd, NULL, 0},
- {"commands", InfoCommandsCmd, TclCompileInfoCommandsCmd, NULL, 0},
- {"complete", InfoCompleteCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"coroutine", TclInfoCoroutineCmd, TclCompileInfoCoroutineCmd, NULL, 0},
- {"default", InfoDefaultCmd, TclCompileBasic3ArgCmd, NULL, 0},
- {"exists", TclInfoExistsCmd, TclCompileInfoExistsCmd, NULL, 0},
- {"functions", InfoFunctionsCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"globals", TclInfoGlobalsCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"hostname", InfoHostnameCmd, TclCompileBasic0ArgCmd, NULL, 0},
- {"level", InfoLevelCmd, TclCompileInfoLevelCmd, NULL, 0},
- {"library", InfoLibraryCmd, TclCompileBasic0ArgCmd, NULL, 0},
- {"loaded", InfoLoadedCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"locals", TclInfoLocalsCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"nameofexecutable", InfoNameOfExecutableCmd, TclCompileBasic0ArgCmd, NULL, 0},
- {"patchlevel", InfoPatchLevelCmd, TclCompileBasic0ArgCmd, NULL, 0},
- {"procs", InfoProcsCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"script", InfoScriptCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"sharedlibextension", InfoSharedlibCmd, TclCompileBasic0ArgCmd, NULL, 0},
- {"tclversion", InfoTclVersionCmd, TclCompileBasic0ArgCmd, NULL, 0},
- {"vars", TclInfoVarsCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
+ {"args", InfoArgsCmd, NULL, NULL, 0},
+ {"body", InfoBodyCmd, NULL, NULL, 0},
+ {"cmdcount", InfoCmdCountCmd, NULL, NULL, 0},
+ {"commands", InfoCommandsCmd, NULL, NULL, 0},
+ {"complete", InfoCompleteCmd, NULL, NULL, 0},
+ {"coroutine", TclInfoCoroutineCmd, NULL, NULL, 0},
+ {"default", InfoDefaultCmd, NULL, NULL, 0},
+ {"exists", TclInfoExistsCmd, NULL, NULL, 0},
+ {"functions", InfoFunctionsCmd, NULL, NULL, 0},
+ {"globals", TclInfoGlobalsCmd, NULL, NULL, 0},
+ {"hostname", InfoHostnameCmd, NULL, NULL, 0},
+ {"level", InfoLevelCmd, NULL, NULL, 0},
+ {"library", InfoLibraryCmd, NULL, NULL, 0},
+ {"loaded", InfoLoadedCmd, NULL, NULL, 0},
+ {"locals", TclInfoLocalsCmd, NULL, NULL, 0},
+ {"nameofexecutable", InfoNameOfExecutableCmd, NULL, NULL, 0},
+ {"patchlevel", InfoPatchLevelCmd, NULL, NULL, 0},
+ {"procs", InfoProcsCmd, NULL, NULL, 0},
+ {"script", InfoScriptCmd, NULL, NULL, 0},
+ {"sharedlibextension", InfoSharedlibCmd, NULL, NULL, 0},
+ {"tclversion", InfoTclVersionCmd, NULL, NULL, 0},
+ {"vars", TclInfoVarsCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, 0}
};
diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c
index 5078d43..afe8378 100644
--- a/generic/tclCmdMZ.c
+++ b/generic/tclCmdMZ.c
@@ -3314,28 +3314,28 @@ TclInitStringCmd(
Tcl_Interp *interp) /* Current interpreter. */
{
static const EnsembleImplMap stringImplMap[] = {
- {"bytelength", StringBytesCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"compare", StringCmpCmd, TclCompileStringCmpCmd, NULL, 0},
- {"equal", StringEqualCmd, TclCompileStringEqualCmd, NULL, 0},
- {"first", StringFirstCmd, TclCompileStringFirstCmd, NULL, 0},
- {"index", StringIndexCmd, TclCompileStringIndexCmd, NULL, 0},
+ {"bytelength", StringBytesCmd, NULL, NULL, 0},
+ {"compare", StringCmpCmd, NULL, NULL, 0},
+ {"equal", StringEqualCmd, NULL, NULL, 0},
+ {"first", StringFirstCmd, NULL, NULL, 0},
+ {"index", StringIndexCmd, NULL, NULL, 0},
{"is", StringIsCmd, NULL, NULL, 0},
- {"last", StringLastCmd, TclCompileStringLastCmd, NULL, 0},
- {"length", StringLenCmd, TclCompileStringLenCmd, NULL, 0},
- {"map", StringMapCmd, TclCompileStringMapCmd, NULL, 0},
- {"match", StringMatchCmd, TclCompileStringMatchCmd, NULL, 0},
- {"range", StringRangeCmd, TclCompileStringRangeCmd, NULL, 0},
- {"repeat", StringReptCmd, TclCompileBasic2ArgCmd, NULL, 0},
+ {"last", StringLastCmd, NULL, NULL, 0},
+ {"length", StringLenCmd, NULL, NULL, 0},
+ {"map", StringMapCmd, NULL, NULL, 0},
+ {"match", StringMatchCmd, NULL, NULL, 0},
+ {"range", StringRangeCmd, NULL, NULL, 0},
+ {"repeat", StringReptCmd, NULL, NULL, 0},
{"replace", StringRplcCmd, NULL, NULL, 0},
- {"reverse", StringRevCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"tolower", StringLowerCmd, TclCompileBasic1To3ArgCmd, NULL, 0},
- {"toupper", StringUpperCmd, TclCompileBasic1To3ArgCmd, NULL, 0},
- {"totitle", StringTitleCmd, TclCompileBasic1To3ArgCmd, NULL, 0},
- {"trim", StringTrimCmd, TclCompileBasic1Or2ArgCmd, NULL, 0},
- {"trimleft", StringTrimLCmd, TclCompileBasic1Or2ArgCmd, NULL, 0},
- {"trimright", StringTrimRCmd, TclCompileBasic1Or2ArgCmd, NULL, 0},
- {"wordend", StringEndCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"wordstart", StringStartCmd, TclCompileBasic2ArgCmd, NULL, 0},
+ {"reverse", StringRevCmd, NULL, NULL, 0},
+ {"tolower", StringLowerCmd, NULL, NULL, 0},
+ {"toupper", StringUpperCmd, NULL, NULL, 0},
+ {"totitle", StringTitleCmd, NULL, NULL, 0},
+ {"trim", StringTrimCmd, NULL, NULL, 0},
+ {"trimleft", StringTrimLCmd, NULL, NULL, 0},
+ {"trimright", StringTrimRCmd, NULL, NULL, 0},
+ {"wordend", StringEndCmd, NULL, NULL, 0},
+ {"wordstart", StringStartCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, 0}
};
@@ -3407,18 +3407,58 @@ Tcl_SubstObjCmd(
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
- int flags;
+ static const char *substOptions[] = {
+ "-nobackslashes", "-nocommands", "-novariables", NULL
+ };
+ enum substOptions {
+ SUBST_NOBACKSLASHES, SUBST_NOCOMMANDS, SUBST_NOVARS
+ };
+ Tcl_Obj *resultPtr;
+ int flags, i;
- if (objc < 2) {
+ /*
+ * Parse command-line options.
+ */
+
+ flags = TCL_SUBST_ALL;
+ for (i = 1; i < (objc-1); i++) {
+ int optionIndex;
+
+ if (Tcl_GetIndexFromObj(interp, objv[i], substOptions, "switch", 0,
+ &optionIndex) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ switch (optionIndex) {
+ case SUBST_NOBACKSLASHES:
+ flags &= ~TCL_SUBST_BACKSLASHES;
+ break;
+ case SUBST_NOCOMMANDS:
+ flags &= ~TCL_SUBST_COMMANDS;
+ break;
+ case SUBST_NOVARS:
+ flags &= ~TCL_SUBST_VARIABLES;
+ break;
+ default:
+ Tcl_Panic("Tcl_SubstObjCmd: bad option index to SubstOptions");
+ }
+ }
+ if (i != objc-1) {
Tcl_WrongNumArgs(interp, 1, objv,
"?-nobackslashes? ?-nocommands? ?-novariables? string");
return TCL_ERROR;
}
- if (TclSubstOptions(interp, objc-2, objv+1, &flags) != TCL_OK) {
+ /*
+ * Perform the substitution.
+ */
+
+ resultPtr = Tcl_SubstObj(interp, objv[i], flags);
+
+ if (resultPtr == NULL) {
return TCL_ERROR;
}
- return Tcl_NRSubstObj(interp, objv[objc-1], flags);
+ Tcl_SetObjResult(interp, resultPtr);
+ return TCL_OK;
}
/*
diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c
index 377a3c3..ddde94f 100644
--- a/generic/tclCompCmds.c
+++ b/generic/tclCompCmds.c
@@ -14,40 +14,13 @@
*/
#include "tclInt.h"
-#include "tclCompile.h"
+#include "tclCompileInt.h"
#include <assert.h>
/*
* Prototypes for procedures defined later in this file:
*/
-static ClientData DupDictUpdateInfo(ClientData clientData);
-static void FreeDictUpdateInfo(ClientData clientData);
-static void PrintDictUpdateInfo(ClientData clientData,
- Tcl_Obj *appendObj, ByteCode *codePtr,
- unsigned int pcOffset);
-static ClientData DupForeachInfo(ClientData clientData);
-static void FreeForeachInfo(ClientData clientData);
-static void PrintForeachInfo(ClientData clientData,
- Tcl_Obj *appendObj, ByteCode *codePtr,
- unsigned int pcOffset);
-static void CompileReturnInternal(CompileEnv *envPtr,
- unsigned char op, int code, int level,
- Tcl_Obj *returnOpts);
-static int IndexTailVarIfKnown(Tcl_Interp *interp,
- Tcl_Token *varTokenPtr, CompileEnv *envPtr);
-static int PushVarName(Tcl_Interp *interp,
- Tcl_Token *varTokenPtr, CompileEnv *envPtr,
- int flags, int *localIndexPtr,
- int *simpleVarNamePtr, int *isScalarPtr);
-static int CompileEachloopCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- CompileEnv *envPtr, int collect);
-static int CompileDictEachCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr, int collect);
-
-
/*
* Macro that encapsulates an efficiency trick that avoids a function call for
* the simplest of compiles. The ANSI C "prototype" for this macro is:
@@ -71,11 +44,7 @@ static int CompileDictEachCmd(Tcl_Interp *interp,
*/
#define Emit14Inst(nm,idx,envPtr) \
- if (idx <= 255) { \
- TclEmitInstInt1(nm##1,idx,envPtr); \
- } else { \
- TclEmitInstInt4(nm##4,idx,envPtr); \
- }
+ TclEmitInstInt4(nm##4,idx,envPtr)
/*
* Flags bits used by PushVarName.
@@ -83,5431 +52,7 @@ static int CompileDictEachCmd(Tcl_Interp *interp,
#define TCL_NO_LARGE_INDEX 1 /* Do not return localIndex value > 255 */
-/*
- * The structures below define the AuxData types defined in this file.
- */
-
-const AuxDataType tclForeachInfoType = {
- "ForeachInfo", /* name */
- DupForeachInfo, /* dupProc */
- FreeForeachInfo, /* freeProc */
- PrintForeachInfo /* printProc */
-};
-
-const AuxDataType tclDictUpdateInfoType = {
- "DictUpdateInfo", /* name */
- DupDictUpdateInfo, /* dupProc */
- FreeDictUpdateInfo, /* freeProc */
- PrintDictUpdateInfo /* printProc */
-};
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileAppendCmd --
- *
- * Procedure called to compile the "append" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "append" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileAppendCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *varTokenPtr, *valueTokenPtr;
- int simpleVarName, isScalar, localIndex, numWords;
-
- numWords = parsePtr->numWords;
- if (numWords == 1) {
- return TCL_ERROR;
- } else if (numWords == 2) {
- /*
- * append varName == set varName
- */
-
- return TclCompileSetCmd(interp, parsePtr, cmdPtr, envPtr);
- } else if (numWords > 3) {
- /*
- * APPEND instructions currently only handle one value.
- */
-
- return TCL_ERROR;
- }
-
- /*
- * Decide if we can use a frame slot for the var/array name or if we need
- * to emit code to compute and push the name at runtime. We use a frame
- * slot (entry in the array of local vars) if we are compiling a procedure
- * body and if the name is simple text that does not include namespace
- * qualifiers.
- */
-
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- PushVarName(interp, varTokenPtr, envPtr, 0,
- &localIndex, &simpleVarName, &isScalar);
-
- /*
- * We are doing an assignment, otherwise TclCompileSetCmd was called, so
- * push the new value. This will need to be extended to push a value for
- * each argument.
- */
-
- if (numWords > 2) {
- valueTokenPtr = TokenAfter(varTokenPtr);
- CompileWord(envPtr, valueTokenPtr, interp);
- }
-
- /*
- * Emit instructions to set/get the variable.
- */
-
- if (simpleVarName) {
- if (isScalar) {
- if (localIndex < 0) {
- TclEmitOpcode(INST_APPEND_STK, envPtr);
- } else {
- Emit14Inst(INST_APPEND_SCALAR, localIndex, envPtr);
- }
- } else {
- if (localIndex < 0) {
- TclEmitOpcode(INST_APPEND_ARRAY_STK, envPtr);
- } else {
- Emit14Inst(INST_APPEND_ARRAY, localIndex, envPtr);
- }
- }
- } else {
- TclEmitOpcode(INST_APPEND_STK, envPtr);
- }
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileArray*Cmd --
- *
- * Functions called to compile "array" sucommands.
- *
- * Results:
- * All return TCL_OK for a successful compile, and TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "array" subcommand at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileArrayExistsCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int simpleVarName, isScalar, localIndex;
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- PushVarName(interp, tokenPtr, envPtr, 0,
- &localIndex, &simpleVarName, &isScalar);
- if (!isScalar) {
- return TCL_ERROR;
- }
-
- if (localIndex >= 0) {
- TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
- } else {
- TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr);
- }
- return TCL_OK;
-}
-
-int
-TclCompileArraySetCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int simpleVarName, isScalar, localIndex;
- int dataVar, iterVar, keyVar, valVar, infoIndex;
- int back, fwd, offsetBack, offsetFwd, savedStackDepth;
- ForeachInfo *infoPtr;
-
- if (parsePtr->numWords != 3) {
- return TCL_ERROR;
- }
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- PushVarName(interp, tokenPtr, envPtr, 0,
- &localIndex, &simpleVarName, &isScalar);
- if (!isScalar) {
- return TCL_ERROR;
- }
- tokenPtr = TokenAfter(tokenPtr);
-
- /*
- * Special case: literal empty value argument is just an "ensure array"
- * operation.
- */
-
- if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD && tokenPtr[1].size == 0) {
- if (localIndex >= 0) {
- TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
- TclEmitInstInt1(INST_JUMP_TRUE1, 7, envPtr);
- TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex, envPtr);
- } else {
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr);
- TclEmitInstInt1(INST_JUMP_TRUE1, 5, envPtr);
- savedStackDepth = envPtr->currStackDepth;
- TclEmitOpcode( INST_ARRAY_MAKE_STK, envPtr);
- TclEmitInstInt1(INST_JUMP1, 3, envPtr);
- envPtr->currStackDepth = savedStackDepth;
- TclEmitOpcode( INST_POP, envPtr);
- }
- PushLiteral(envPtr, "", 0);
- return TCL_OK;
- }
-
- /*
- * Prepare for the internal foreach.
- */
-
- if (envPtr->procPtr == NULL) {
- return TCL_ERROR;
- }
- dataVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- iterVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- keyVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- valVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
-
- infoPtr = ckalloc(sizeof(ForeachInfo) + sizeof(ForeachVarList *));
- infoPtr->numLists = 1;
- infoPtr->firstValueTemp = dataVar;
- infoPtr->loopCtTemp = iterVar;
- infoPtr->varLists[0] = ckalloc(sizeof(ForeachVarList) * 2*sizeof(int));
- infoPtr->varLists[0]->numVars = 2;
- infoPtr->varLists[0]->varIndexes[0] = keyVar;
- infoPtr->varLists[0]->varIndexes[1] = valVar;
- infoIndex = TclCreateAuxData(infoPtr, &tclForeachInfoType, envPtr);
-
- /*
- * Start issuing instructions to write to the array.
- */
-
- CompileWord(envPtr, tokenPtr, interp);
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitOpcode( INST_LIST_LENGTH, envPtr);
- PushLiteral(envPtr, "1", 1);
- TclEmitOpcode( INST_BITAND, envPtr);
- offsetFwd = CurrentOffset(envPtr);
- TclEmitInstInt1( INST_JUMP_FALSE1, 0, envPtr);
- savedStackDepth = envPtr->currStackDepth;
- PushLiteral(envPtr, "list must have an even number of elements",
- strlen("list must have an even number of elements"));
- PushLiteral(envPtr, "-errorCode {TCL ARGUMENT FORMAT}",
- strlen("-errorCode {TCL ARGUMENT FORMAT}"));
- TclEmitInstInt4( INST_RETURN_IMM, 1, envPtr);
- TclEmitInt4( 0, envPtr);
- envPtr->currStackDepth = savedStackDepth;
- fwd = CurrentOffset(envPtr) - offsetFwd;
- TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1);
- Emit14Inst( INST_STORE_SCALAR, dataVar, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
-
- if (localIndex >= 0) {
- TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
- TclEmitInstInt1(INST_JUMP_TRUE1, 7, envPtr);
- TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex, envPtr);
- TclEmitInstInt4(INST_FOREACH_START4, infoIndex, envPtr);
- offsetBack = CurrentOffset(envPtr);
- TclEmitInstInt4(INST_FOREACH_STEP4, infoIndex, envPtr);
- offsetFwd = CurrentOffset(envPtr);
- TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);
- savedStackDepth = envPtr->currStackDepth;
- Emit14Inst( INST_LOAD_SCALAR, keyVar, envPtr);
- Emit14Inst( INST_LOAD_SCALAR, valVar, envPtr);
- Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- back = offsetBack - CurrentOffset(envPtr);
- TclEmitInstInt1(INST_JUMP1, back, envPtr);
- fwd = CurrentOffset(envPtr) - offsetFwd;
- TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1);
- envPtr->currStackDepth = savedStackDepth;
- } else {
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr);
- TclEmitInstInt1(INST_JUMP_TRUE1, 4, envPtr);
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitOpcode( INST_ARRAY_MAKE_STK, envPtr);
- TclEmitInstInt4(INST_FOREACH_START4, infoIndex, envPtr);
- offsetBack = CurrentOffset(envPtr);
- TclEmitInstInt4(INST_FOREACH_STEP4, infoIndex, envPtr);
- offsetFwd = CurrentOffset(envPtr);
- TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);
- savedStackDepth = envPtr->currStackDepth;
- TclEmitOpcode( INST_DUP, envPtr);
- Emit14Inst( INST_LOAD_SCALAR, keyVar, envPtr);
- Emit14Inst( INST_LOAD_SCALAR, valVar, envPtr);
- TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- back = offsetBack - CurrentOffset(envPtr);
- TclEmitInstInt1(INST_JUMP1, back, envPtr);
- fwd = CurrentOffset(envPtr) - offsetFwd;
- TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1);
- envPtr->currStackDepth = savedStackDepth;
- TclEmitOpcode( INST_POP, envPtr);
- }
- TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( dataVar, envPtr);
- PushLiteral(envPtr, "", 0);
- return TCL_OK;
-}
-
-int
-TclCompileArrayUnsetCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
- int simpleVarName, isScalar, localIndex, savedStackDepth;
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
-
- PushVarName(interp, tokenPtr, envPtr, 0,
- &localIndex, &simpleVarName, &isScalar);
- if (!isScalar) {
- return TCL_ERROR;
- }
-
- if (localIndex >= 0) {
- TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
- TclEmitInstInt1(INST_JUMP_FALSE1, 8, envPtr);
- TclEmitInstInt1(INST_UNSET_SCALAR, 1, envPtr);
- TclEmitInt4( localIndex, envPtr);
- } else {
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr);
- TclEmitInstInt1(INST_JUMP_FALSE1, 6, envPtr);
- savedStackDepth = envPtr->currStackDepth;
- TclEmitInstInt1(INST_UNSET_STK, 1, envPtr);
- TclEmitInstInt1(INST_JUMP1, 3, envPtr);
- envPtr->currStackDepth = savedStackDepth;
- TclEmitOpcode( INST_POP, envPtr);
- }
- PushLiteral(envPtr, "", 0);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileBreakCmd --
- *
- * Procedure called to compile the "break" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "break" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileBreakCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- if (parsePtr->numWords != 1) {
- return TCL_ERROR;
- }
-
- /*
- * Emit a break instruction.
- */
-
- TclEmitOpcode(INST_BREAK, envPtr);
- PushLiteral(envPtr, "", 0); /* Evil hack! */
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileCatchCmd --
- *
- * Procedure called to compile the "catch" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "catch" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileCatchCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- JumpFixup jumpFixup;
- Tcl_Token *cmdTokenPtr, *resultNameTokenPtr, *optsNameTokenPtr;
- const char *name;
- int resultIndex, optsIndex, nameChars, range;
- int initStackDepth = envPtr->currStackDepth;
- int savedStackDepth;
-
- /*
- * If syntax does not match what we expect for [catch], do not compile.
- * Let runtime checks determine if syntax has changed.
- */
-
- if ((parsePtr->numWords < 2) || (parsePtr->numWords > 4)) {
- return TCL_ERROR;
- }
-
- /*
- * If variables were specified and the catch command is at global level
- * (not in a procedure), don't compile it inline: the payoff is too small.
- */
-
- if ((parsePtr->numWords >= 3) && !EnvHasLVT(envPtr)) {
- return TCL_ERROR;
- }
-
- /*
- * Make sure the variable names, if any, have no substitutions and just
- * refer to local scalars.
- */
-
- resultIndex = optsIndex = -1;
- cmdTokenPtr = TokenAfter(parsePtr->tokenPtr);
- if (parsePtr->numWords >= 3) {
- resultNameTokenPtr = TokenAfter(cmdTokenPtr);
- /* DGP */
- if (resultNameTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
-
- name = resultNameTokenPtr[1].start;
- nameChars = resultNameTokenPtr[1].size;
- if (!TclIsLocalScalar(name, nameChars)) {
- return TCL_ERROR;
- }
- resultIndex = TclFindCompiledLocal(resultNameTokenPtr[1].start,
- resultNameTokenPtr[1].size, /*create*/ 1, envPtr);
- if (resultIndex < 0) {
- return TCL_ERROR;
- }
-
- /* DKF */
- if (parsePtr->numWords == 4) {
- optsNameTokenPtr = TokenAfter(resultNameTokenPtr);
- if (optsNameTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- name = optsNameTokenPtr[1].start;
- nameChars = optsNameTokenPtr[1].size;
- if (!TclIsLocalScalar(name, nameChars)) {
- return TCL_ERROR;
- }
- optsIndex = TclFindCompiledLocal(optsNameTokenPtr[1].start,
- optsNameTokenPtr[1].size, /*create*/ 1, envPtr);
- if (optsIndex < 0) {
- return TCL_ERROR;
- }
- }
- }
-
- /*
- * We will compile the catch command. Declare the exception range that it
- * uses.
- */
-
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
-
- /*
- * If the body is a simple word, compile a BEGIN_CATCH instruction,
- * followed by the instructions to eval the body.
- * Otherwise, compile instructions to substitute the body text before
- * starting the catch, then BEGIN_CATCH, and then EVAL_STK to evaluate the
- * substituted body.
- * Care has to be taken to make sure that substitution happens outside the
- * catch range so that errors in the substitution are not caught.
- * [Bug 219184]
- * The reason for duplicating the script is that EVAL_STK would otherwise
- * begin by undeflowing the stack below the mark set by BEGIN_CATCH4.
- */
-
- if (cmdTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
- savedStackDepth = envPtr->currStackDepth;
- TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
- ExceptionRangeStarts(envPtr, range);
- CompileBody(envPtr, cmdTokenPtr, interp);
- } else {
- CompileTokens(envPtr, cmdTokenPtr, interp);
- savedStackDepth = envPtr->currStackDepth;
- TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
- ExceptionRangeStarts(envPtr, range);
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitOpcode( INST_EVAL_STK, envPtr);
- }
- /* Stack at this point:
- * nonsimple: script <mark> result
- * simple: <mark> result
- */
-
- if (resultIndex == -1) {
- /*
- * Special case when neither result nor options are being saved. In
- * that case, we can skip quite a bit of the command epilogue; all we
- * have to do is drop the result and push the return code (and, of
- * course, finish the catch context).
- */
-
- TclEmitOpcode( INST_POP, envPtr);
- PushLiteral(envPtr, "0", 1);
- TclEmitInstInt1( INST_JUMP1, 3, envPtr);
- envPtr->currStackDepth = savedStackDepth;
- ExceptionRangeTarget(envPtr, range, catchOffset);
- TclEmitOpcode( INST_PUSH_RETURN_CODE, envPtr);
- ExceptionRangeEnds(envPtr, range);
- TclEmitOpcode( INST_END_CATCH, envPtr);
-
- /*
- * Stack at this point:
- * nonsimple: script <mark> returnCode
- * simple: <mark> returnCode
- */
-
- goto dropScriptAtEnd;
- }
-
- /*
- * Emit the "no errors" epilogue: push "0" (TCL_OK) as the catch result,
- * and jump around the "error case" code.
- */
-
- PushLiteral(envPtr, "0", 1);
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
- /* Stack at this point: ?script? <mark> result TCL_OK */
-
- /*
- * Emit the "error case" epilogue. Push the interpreter result and the
- * return code.
- */
-
- envPtr->currStackDepth = savedStackDepth;
- ExceptionRangeTarget(envPtr, range, catchOffset);
- /* Stack at this point: ?script? */
- TclEmitOpcode( INST_PUSH_RESULT, envPtr);
- TclEmitOpcode( INST_PUSH_RETURN_CODE, envPtr);
-
- /*
- * Update the target of the jump after the "no errors" code.
- */
-
- /* Stack at this point: ?script? result returnCode */
- if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
- Tcl_Panic("TclCompileCatchCmd: bad jump distance %d",
- (int)(CurrentOffset(envPtr) - jumpFixup.codeOffset));
- }
-
- /*
- * Push the return options if the caller wants them.
- */
-
- if (optsIndex != -1) {
- TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
- }
-
- /*
- * End the catch
- */
-
- ExceptionRangeEnds(envPtr, range);
- TclEmitOpcode( INST_END_CATCH, envPtr);
-
- /*
- * At this point, the top of the stack is inconveniently ordered:
- * ?script? result returnCode ?returnOptions?
- * Reverse the stack to bring the result to the top.
- */
-
- if (optsIndex != -1) {
- TclEmitInstInt4( INST_REVERSE, 3, envPtr);
- } else {
- TclEmitInstInt4( INST_REVERSE, 2, envPtr);
- }
-
- /*
- * Store the result and remove it from the stack.
- */
-
- Emit14Inst( INST_STORE_SCALAR, resultIndex, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
-
- /*
- * Stack is now ?script? ?returnOptions? returnCode.
- * If the options dict has been requested, it is buried on the stack under
- * the return code. Reverse the stack to bring it to the top, store it and
- * remove it from the stack.
- */
-
- if (optsIndex != -1) {
- TclEmitInstInt4( INST_REVERSE, 2, envPtr);
- Emit14Inst( INST_STORE_SCALAR, optsIndex, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- }
-
- dropScriptAtEnd:
-
- /*
- * Stack is now ?script? result. Get rid of the subst'ed script if it's
- * hanging arond.
- */
-
- if (cmdTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- TclEmitInstInt4( INST_REVERSE, 2, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- }
-
- /*
- * Result of all this, on either branch, should have been to leave one
- * operand -- the return code -- on the stack.
- */
-
- if (envPtr->currStackDepth != initStackDepth + 1) {
- Tcl_Panic("in TclCompileCatchCmd, currStackDepth = %d should be %d",
- envPtr->currStackDepth, initStackDepth+1);
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileContinueCmd --
- *
- * Procedure called to compile the "continue" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "continue" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileContinueCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * There should be no argument after the "continue".
- */
-
- if (parsePtr->numWords != 1) {
- return TCL_ERROR;
- }
-
- /*
- * Emit a continue instruction.
- */
-
- TclEmitOpcode(INST_CONTINUE, envPtr);
- PushLiteral(envPtr, "", 0); /* Evil hack! */
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileDict*Cmd --
- *
- * Functions called to compile "dict" sucommands.
- *
- * Results:
- * All return TCL_OK for a successful compile, and TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "dict" subcommand at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileDictSetCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int numWords, i;
- Tcl_Token *varTokenPtr;
- int dictVarIndex, nameChars;
- const char *name;
-
- /*
- * There must be at least one argument after the command.
- */
-
- if (parsePtr->numWords < 4) {
- return TCL_ERROR;
- }
-
- /*
- * The dictionary variable must be a local scalar that is knowable at
- * compile time; anything else exceeds the complexity of the opcode. So
- * discover what the index is.
- */
-
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
- if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- name = varTokenPtr[1].start;
- nameChars = varTokenPtr[1].size;
- if (!TclIsLocalScalar(name, nameChars)) {
- return TCL_ERROR;
- }
- dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr);
- if (dictVarIndex < 0) {
- return TCL_ERROR;
- }
-
- /*
- * Remaining words (key path and value to set) can be handled normally.
- */
-
- tokenPtr = TokenAfter(varTokenPtr);
- numWords = parsePtr->numWords-1;
- for (i=1 ; i<numWords ; i++) {
- CompileWord(envPtr, tokenPtr, interp);
- tokenPtr = TokenAfter(tokenPtr);
- }
-
- /*
- * Now emit the instruction to do the dict manipulation.
- */
-
- TclEmitInstInt4( INST_DICT_SET, numWords-2, envPtr);
- TclEmitInt4( dictVarIndex, envPtr);
- TclAdjustStackDepth(-1, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileDictIncrCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *varTokenPtr, *keyTokenPtr;
- int dictVarIndex, nameChars, incrAmount;
- const char *name;
-
- /*
- * There must be at least two arguments after the command.
- */
-
- if (parsePtr->numWords < 3 || parsePtr->numWords > 4) {
- return TCL_ERROR;
- }
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
- keyTokenPtr = TokenAfter(varTokenPtr);
-
- /*
- * Parse the increment amount, if present.
- */
-
- if (parsePtr->numWords == 4) {
- const char *word;
- int numBytes, code;
- Tcl_Token *incrTokenPtr;
- Tcl_Obj *intObj;
-
- incrTokenPtr = TokenAfter(keyTokenPtr);
- if (incrTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- word = incrTokenPtr[1].start;
- numBytes = incrTokenPtr[1].size;
-
- intObj = Tcl_NewStringObj(word, numBytes);
- Tcl_IncrRefCount(intObj);
- code = TclGetIntFromObj(NULL, intObj, &incrAmount);
- TclDecrRefCount(intObj);
- if (code != TCL_OK) {
- return TCL_ERROR;
- }
- } else {
- incrAmount = 1;
- }
-
- /*
- * The dictionary variable must be a local scalar that is knowable at
- * compile time; anything else exceeds the complexity of the opcode. So
- * discover what the index is.
- */
-
- if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- name = varTokenPtr[1].start;
- nameChars = varTokenPtr[1].size;
- if (!TclIsLocalScalar(name, nameChars)) {
- return TCL_ERROR;
- }
- dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr);
- if (dictVarIndex < 0) {
- return TCL_ERROR;
- }
-
- /*
- * Emit the key and the code to actually do the increment.
- */
-
- CompileWord(envPtr, keyTokenPtr, interp);
- TclEmitInstInt4( INST_DICT_INCR_IMM, incrAmount, envPtr);
- TclEmitInt4( dictVarIndex, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileDictGetCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int numWords, i;
-
- /*
- * There must be at least two arguments after the command (the single-arg
- * case is legal, but too special and magic for us to deal with here).
- */
-
- if (parsePtr->numWords < 3) {
- return TCL_ERROR;
- }
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- numWords = parsePtr->numWords-1;
-
- /*
- * Only compile this because we need INST_DICT_GET anyway.
- */
-
- for (i=0 ; i<numWords ; i++) {
- CompileWord(envPtr, tokenPtr, interp);
- tokenPtr = TokenAfter(tokenPtr);
- }
- TclEmitInstInt4(INST_DICT_GET, numWords-1, envPtr);
- TclAdjustStackDepth(-1, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileDictExistsCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int numWords, i;
-
- /*
- * There must be at least two arguments after the command (the single-arg
- * case is legal, but too special and magic for us to deal with here).
- */
-
- if (parsePtr->numWords < 3) {
- return TCL_ERROR;
- }
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- numWords = parsePtr->numWords-1;
-
- /*
- * Now we do the code generation.
- */
-
- for (i=0 ; i<numWords ; i++) {
- CompileWord(envPtr, tokenPtr, interp);
- tokenPtr = TokenAfter(tokenPtr);
- }
- TclEmitInstInt4(INST_DICT_EXISTS, numWords-1, envPtr);
- TclAdjustStackDepth(-1, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileDictUnsetCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int i, dictVarIndex, nameChars;
- const char *name;
-
- /*
- * There must be at least one argument after the variable name for us to
- * compile to bytecode.
- */
-
- if (parsePtr->numWords < 3) {
- return TCL_ERROR;
- }
-
- /*
- * The dictionary variable must be a local scalar that is knowable at
- * compile time; anything else exceeds the complexity of the opcode. So
- * discover what the index is.
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- name = tokenPtr[1].start;
- nameChars = tokenPtr[1].size;
- if (!TclIsLocalScalar(name, nameChars)) {
- return TCL_ERROR;
- }
- dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr);
- if (dictVarIndex < 0) {
- return TCL_ERROR;
- }
-
- /*
- * Remaining words (the key path) can be handled normally.
- */
-
- for (i=2 ; i<parsePtr->numWords ; i++) {
- tokenPtr = TokenAfter(tokenPtr);
- CompileWord(envPtr, tokenPtr, interp);
- }
-
- /*
- * Now emit the instruction to do the dict manipulation.
- */
-
- TclEmitInstInt4( INST_DICT_UNSET, parsePtr->numWords-2, envPtr);
- TclEmitInt4( dictVarIndex, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileDictCreateCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- int worker; /* Temp var for building the value in. */
- Tcl_Token *tokenPtr;
- Tcl_Obj *keyObj, *valueObj, *dictObj;
- const char *bytes;
- int i, len;
-
- if ((parsePtr->numWords & 1) == 0) {
- return TCL_ERROR;
- }
-
- /*
- * See if we can build the value at compile time...
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- dictObj = Tcl_NewObj();
- Tcl_IncrRefCount(dictObj);
- for (i=1 ; i<parsePtr->numWords ; i+=2) {
- keyObj = Tcl_NewObj();
- Tcl_IncrRefCount(keyObj);
- if (!TclWordKnownAtCompileTime(tokenPtr, keyObj)) {
- Tcl_DecrRefCount(keyObj);
- Tcl_DecrRefCount(dictObj);
- goto nonConstant;
- }
- tokenPtr = TokenAfter(tokenPtr);
- valueObj = Tcl_NewObj();
- Tcl_IncrRefCount(valueObj);
- if (!TclWordKnownAtCompileTime(tokenPtr, valueObj)) {
- Tcl_DecrRefCount(keyObj);
- Tcl_DecrRefCount(valueObj);
- Tcl_DecrRefCount(dictObj);
- goto nonConstant;
- }
- tokenPtr = TokenAfter(tokenPtr);
- Tcl_DictObjPut(NULL, dictObj, keyObj, valueObj);
- Tcl_DecrRefCount(keyObj);
- Tcl_DecrRefCount(valueObj);
- }
-
- /*
- * We did! Excellent. The "verifyDict" is to do type forcing.
- */
-
- bytes = Tcl_GetStringFromObj(dictObj, &len);
- PushLiteral(envPtr, bytes, len);
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitOpcode( INST_DICT_VERIFY, envPtr);
- Tcl_DecrRefCount(dictObj);
- return TCL_OK;
-
- /*
- * Otherwise, we've got to issue runtime code to do the building, which we
- * do by [dict set]ting into an unnamed local variable. This requires that
- * we are in a context with an LVT.
- */
-
- nonConstant:
- worker = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- if (worker < 0) {
- return TCL_ERROR;
- }
-
- PushLiteral(envPtr, "", 0);
- Emit14Inst( INST_STORE_SCALAR, worker, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- for (i=1 ; i<parsePtr->numWords ; i+=2) {
- CompileWord(envPtr, tokenPtr, interp);
- tokenPtr = TokenAfter(tokenPtr);
- CompileWord(envPtr, tokenPtr, interp);
- tokenPtr = TokenAfter(tokenPtr);
- TclEmitInstInt4( INST_DICT_SET, 1, envPtr);
- TclEmitInt4( worker, envPtr);
- TclAdjustStackDepth(-1, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- }
- Emit14Inst( INST_LOAD_SCALAR, worker, envPtr);
- TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( worker, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileDictMergeCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int i, workerIndex, infoIndex, outLoop;
-
- /*
- * Deal with some special edge cases. Note that in the case with one
- * argument, the only thing to do is to verify the dict-ness.
- */
-
- if (parsePtr->numWords < 2) {
- PushLiteral(envPtr, "", 0);
- return TCL_OK;
- } else if (parsePtr->numWords == 2) {
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- CompileWord(envPtr, tokenPtr, interp);
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitOpcode( INST_DICT_VERIFY, envPtr);
- return TCL_OK;
- }
-
- /*
- * There's real merging work to do.
- *
- * Allocate some working space. This means we'll only ever compile this
- * command when there's an LVT present.
- */
-
- workerIndex = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- if (workerIndex < 0) {
- return TCL_ERROR;
- }
- infoIndex = TclFindCompiledLocal(NULL, 0, 1, envPtr);
-
- /*
- * Get the first dictionary and verify that it is so.
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- CompileWord(envPtr, tokenPtr, interp);
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitOpcode( INST_DICT_VERIFY, envPtr);
- Emit14Inst( INST_STORE_SCALAR, workerIndex, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
-
- /*
- * For each of the remaining dictionaries...
- */
-
- outLoop = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
- TclEmitInstInt4( INST_BEGIN_CATCH4, outLoop, envPtr);
- ExceptionRangeStarts(envPtr, outLoop);
- for (i=2 ; i<parsePtr->numWords ; i++) {
- /*
- * Get the dictionary, and merge its pairs into the first dict (using
- * a small loop).
- */
-
- tokenPtr = TokenAfter(tokenPtr);
- CompileWord(envPtr, tokenPtr, interp);
- TclEmitInstInt4( INST_DICT_FIRST, infoIndex, envPtr);
- TclEmitInstInt1( INST_JUMP_TRUE1, 24, envPtr);
- TclEmitInstInt4( INST_REVERSE, 2, envPtr);
- TclEmitInstInt4( INST_DICT_SET, 1, envPtr);
- TclEmitInt4( workerIndex, envPtr);
- TclAdjustStackDepth(-1, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- TclEmitInstInt4( INST_DICT_NEXT, infoIndex, envPtr);
- TclEmitInstInt1( INST_JUMP_FALSE1, -20, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( infoIndex, envPtr);
- }
- ExceptionRangeEnds(envPtr, outLoop);
- TclEmitOpcode( INST_END_CATCH, envPtr);
-
- /*
- * Clean up any state left over.
- */
-
- Emit14Inst( INST_LOAD_SCALAR, workerIndex, envPtr);
- TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( workerIndex, envPtr);
- TclEmitInstInt1( INST_JUMP1, 18, envPtr);
-
- /*
- * If an exception happens when starting to iterate over the second (and
- * subsequent) dicts. This is strictly not necessary, but it is nice.
- */
-
- ExceptionRangeTarget(envPtr, outLoop, catchOffset);
- TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
- TclEmitOpcode( INST_PUSH_RESULT, envPtr);
- TclEmitOpcode( INST_END_CATCH, envPtr);
- TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( workerIndex, envPtr);
- TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( infoIndex, envPtr);
- TclEmitOpcode( INST_RETURN_STK, envPtr);
-
- return TCL_OK;
-}
-
-int
-TclCompileDictForCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- return CompileDictEachCmd(interp, parsePtr, cmdPtr, envPtr,
- TCL_EACH_KEEP_NONE);
-}
-
-int
-TclCompileDictMapCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- return CompileDictEachCmd(interp, parsePtr, cmdPtr, envPtr,
- TCL_EACH_COLLECT);
-}
-
-int
-CompileDictEachCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr, /* Holds resulting instructions. */
- int collect) /* Flag == TCL_EACH_COLLECT to collect and
- * construct a new dictionary with the loop
- * body result. */
-{
- Tcl_Token *varsTokenPtr, *dictTokenPtr, *bodyTokenPtr;
- int keyVarIndex, valueVarIndex, nameChars, loopRange, catchRange;
- int infoIndex, jumpDisplacement, bodyTargetOffset, emptyTargetOffset;
- int numVars, endTargetOffset;
- int collectVar = -1; /* Index of temp var holding the result
- * dict. */
- int savedStackDepth = envPtr->currStackDepth;
- /* Needed because jumps confuse the stack
- * space calculator. */
- const char **argv;
- Tcl_DString buffer;
-
- /*
- * There must be at least three argument after the command.
- */
-
- if (parsePtr->numWords != 4) {
- return TCL_ERROR;
- }
-
- varsTokenPtr = TokenAfter(parsePtr->tokenPtr);
- dictTokenPtr = TokenAfter(varsTokenPtr);
- bodyTokenPtr = TokenAfter(dictTokenPtr);
- if (varsTokenPtr->type != TCL_TOKEN_SIMPLE_WORD ||
- bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
-
- /*
- * Create temporary variable to capture return values from loop body when
- * we're collecting results.
- */
-
- if (collect == TCL_EACH_COLLECT) {
- collectVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0, /*create*/ 1,
- envPtr);
- if (collectVar < 0) {
- return TCL_ERROR;
- }
- }
-
- /*
- * Check we've got a pair of variables and that they are local variables.
- * Then extract their indices in the LVT.
- */
-
- Tcl_DStringInit(&buffer);
- TclDStringAppendToken(&buffer, &varsTokenPtr[1]);
- if (Tcl_SplitList(NULL, Tcl_DStringValue(&buffer), &numVars,
- &argv) != TCL_OK) {
- Tcl_DStringFree(&buffer);
- return TCL_ERROR;
- }
- Tcl_DStringFree(&buffer);
- if (numVars != 2) {
- ckfree(argv);
- return TCL_ERROR;
- }
-
- nameChars = strlen(argv[0]);
- if (!TclIsLocalScalar(argv[0], nameChars)) {
- ckfree(argv);
- return TCL_ERROR;
- }
- keyVarIndex = TclFindCompiledLocal(argv[0], nameChars, 1, envPtr);
-
- nameChars = strlen(argv[1]);
- if (!TclIsLocalScalar(argv[1], nameChars)) {
- ckfree(argv);
- return TCL_ERROR;
- }
- valueVarIndex = TclFindCompiledLocal(argv[1], nameChars, 1, envPtr);
- ckfree(argv);
-
- if ((keyVarIndex < 0) || (valueVarIndex < 0)) {
- return TCL_ERROR;
- }
-
- /*
- * Allocate a temporary variable to store the iterator reference. The
- * variable will contain a Tcl_DictSearch reference which will be
- * allocated by INST_DICT_FIRST and disposed when the variable is unset
- * (at which point it should also have been finished with).
- */
-
- infoIndex = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- if (infoIndex < 0) {
- return TCL_ERROR;
- }
-
- /*
- * Preparation complete; issue instructions. Note that this code issues
- * fixed-sized jumps. That simplifies things a lot!
- *
- * First up, initialize the accumulator dictionary if needed.
- */
-
- if (collect == TCL_EACH_COLLECT) {
- PushLiteral(envPtr, "", 0);
- Emit14Inst( INST_STORE_SCALAR, collectVar, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- }
-
- /*
- * Get the dictionary and start the iteration. No catching of errors at
- * this point.
- */
-
- CompileWord(envPtr, dictTokenPtr, interp);
- TclEmitInstInt4( INST_DICT_FIRST, infoIndex, envPtr);
- emptyTargetOffset = CurrentOffset(envPtr);
- TclEmitInstInt4( INST_JUMP_TRUE4, 0, envPtr);
-
- /*
- * Now we catch errors from here on so that we can finalize the search
- * started by Tcl_DictObjFirst above.
- */
-
- catchRange = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
- TclEmitInstInt4( INST_BEGIN_CATCH4, catchRange, envPtr);
- ExceptionRangeStarts(envPtr, catchRange);
-
- /*
- * Inside the iteration, write the loop variables.
- */
-
- bodyTargetOffset = CurrentOffset(envPtr);
- Emit14Inst( INST_STORE_SCALAR, keyVarIndex, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- Emit14Inst( INST_STORE_SCALAR, valueVarIndex, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
-
- /*
- * Set up the loop exception targets.
- */
-
- loopRange = DeclareExceptionRange(envPtr, LOOP_EXCEPTION_RANGE);
- ExceptionRangeStarts(envPtr, loopRange);
-
- /*
- * Compile the loop body itself. It should be stack-neutral.
- */
-
- CompileBody(envPtr, bodyTokenPtr, interp);
- if (collect == TCL_EACH_COLLECT) {
- Emit14Inst( INST_LOAD_SCALAR, keyVarIndex, envPtr);
- TclEmitInstInt4(INST_OVER, 1, envPtr);
- TclEmitInstInt4(INST_DICT_SET, 1, envPtr);
- TclEmitInt4( collectVar, envPtr);
- TclAdjustStackDepth(-1, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- }
- TclEmitOpcode( INST_POP, envPtr);
-
- /*
- * Both exception target ranges (error and loop) end here.
- */
-
- ExceptionRangeEnds(envPtr, loopRange);
- ExceptionRangeEnds(envPtr, catchRange);
-
- /*
- * Continue (or just normally process) by getting the next pair of items
- * from the dictionary and jumping back to the code to write them into
- * variables if there is another pair.
- */
-
- ExceptionRangeTarget(envPtr, loopRange, continueOffset);
- TclEmitInstInt4( INST_DICT_NEXT, infoIndex, envPtr);
- jumpDisplacement = bodyTargetOffset - CurrentOffset(envPtr);
- TclEmitInstInt4( INST_JUMP_FALSE4, jumpDisplacement, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
-
- /*
- * Now do the final cleanup for the no-error case (this is where we break
- * out of the loop to) by force-terminating the iteration (if not already
- * terminated), ditching the exception info and jumping to the last
- * instruction for this command. In theory, this could be done using the
- * "finally" clause (next generated) but this is faster.
- */
-
- ExceptionRangeTarget(envPtr, loopRange, breakOffset);
- TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( infoIndex, envPtr);
- TclEmitOpcode( INST_END_CATCH, envPtr);
- endTargetOffset = CurrentOffset(envPtr);
- TclEmitInstInt4( INST_JUMP4, 0, envPtr);
-
- /*
- * Error handler "finally" clause, which force-terminates the iteration
- * and rethrows the error.
- */
-
- ExceptionRangeTarget(envPtr, catchRange, catchOffset);
- TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
- TclEmitOpcode( INST_PUSH_RESULT, envPtr);
- TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( infoIndex, envPtr);
- TclEmitOpcode( INST_END_CATCH, envPtr);
- if (collect == TCL_EACH_COLLECT) {
- TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( collectVar, envPtr);
- }
- TclEmitOpcode( INST_RETURN_STK, envPtr);
-
- /*
- * Otherwise we're done (the jump after the DICT_FIRST points here) and we
- * need to pop the bogus key/value pair (pushed to keep stack calculations
- * easy!) Note that we skip the END_CATCH. [Bug 1382528]
- */
-
- envPtr->currStackDepth = savedStackDepth + 2;
- jumpDisplacement = CurrentOffset(envPtr) - emptyTargetOffset;
- TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDisplacement,
- envPtr->codeStart + emptyTargetOffset);
- TclEmitOpcode( INST_POP, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( infoIndex, envPtr);
-
- /*
- * Final stage of the command (normal case) is that we push an empty
- * object (or push the accumulator as the result object). This is done
- * last to promote peephole optimization when it's dropped immediately.
- */
-
- jumpDisplacement = CurrentOffset(envPtr) - endTargetOffset;
- TclUpdateInstInt4AtPc(INST_JUMP4, jumpDisplacement,
- envPtr->codeStart + endTargetOffset);
- if (collect == TCL_EACH_COLLECT) {
- Emit14Inst( INST_LOAD_SCALAR, collectVar, envPtr);
- TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( collectVar, envPtr);
- } else {
- PushLiteral(envPtr, "", 0);
- }
- return TCL_OK;
-}
-
-int
-TclCompileDictUpdateCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- const char *name;
- int i, nameChars, dictIndex, numVars, range, infoIndex;
- Tcl_Token **keyTokenPtrs, *dictVarTokenPtr, *bodyTokenPtr, *tokenPtr;
- int savedStackDepth = envPtr->currStackDepth;
- DictUpdateInfo *duiPtr;
- JumpFixup jumpFixup;
-
- /*
- * There must be at least one argument after the command.
- */
-
- if (parsePtr->numWords < 5) {
- return TCL_ERROR;
- }
-
- /*
- * Parse the command. Expect the following:
- * dict update <lit(eral)> <any> <lit> ?<any> <lit> ...? <lit>
- */
-
- if ((parsePtr->numWords - 1) & 1) {
- return TCL_ERROR;
- }
- numVars = (parsePtr->numWords - 3) / 2;
-
- /*
- * The dictionary variable must be a local scalar that is knowable at
- * compile time; anything else exceeds the complexity of the opcode. So
- * discover what the index is.
- */
-
- dictVarTokenPtr = TokenAfter(parsePtr->tokenPtr);
- if (dictVarTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- name = dictVarTokenPtr[1].start;
- nameChars = dictVarTokenPtr[1].size;
- if (!TclIsLocalScalar(name, nameChars)) {
- return TCL_ERROR;
- }
- dictIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr);
- if (dictIndex < 0) {
- return TCL_ERROR;
- }
-
- /*
- * Assemble the instruction metadata. This is complex enough that it is
- * represented as auxData; it holds an ordered list of variable indices
- * that are to be used.
- */
-
- duiPtr = ckalloc(sizeof(DictUpdateInfo) + sizeof(int) * (numVars - 1));
- duiPtr->length = numVars;
- keyTokenPtrs = ckalloc(sizeof(Tcl_Token *) * numVars);
- tokenPtr = TokenAfter(dictVarTokenPtr);
-
- for (i=0 ; i<numVars ; i++) {
- /*
- * Put keys to one side for later compilation to bytecode.
- */
-
- keyTokenPtrs[i] = tokenPtr;
-
- /*
- * Variables first need to be checked for sanity.
- */
-
- tokenPtr = TokenAfter(tokenPtr);
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- goto failedUpdateInfoAssembly;
- }
- name = tokenPtr[1].start;
- nameChars = tokenPtr[1].size;
- if (!TclIsLocalScalar(name, nameChars)) {
- goto failedUpdateInfoAssembly;
- }
-
- /*
- * Stash the index in the auxiliary data.
- */
-
- duiPtr->varIndices[i] =
- TclFindCompiledLocal(name, nameChars, 1, envPtr);
- if (duiPtr->varIndices[i] < 0) {
- goto failedUpdateInfoAssembly;
- }
- tokenPtr = TokenAfter(tokenPtr);
- }
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- failedUpdateInfoAssembly:
- ckfree(duiPtr);
- ckfree(keyTokenPtrs);
- return TCL_ERROR;
- }
- bodyTokenPtr = tokenPtr;
-
- /*
- * The list of variables to bind is stored in auxiliary data so that it
- * can't be snagged by literal sharing and forced to shimmer dangerously.
- */
-
- infoIndex = TclCreateAuxData(duiPtr, &tclDictUpdateInfoType, envPtr);
-
- for (i=0 ; i<numVars ; i++) {
- CompileWord(envPtr, keyTokenPtrs[i], interp);
- }
- TclEmitInstInt4( INST_LIST, numVars, envPtr);
- TclEmitInstInt4( INST_DICT_UPDATE_START, dictIndex, envPtr);
- TclEmitInt4( infoIndex, envPtr);
-
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
- TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
-
- ExceptionRangeStarts(envPtr, range);
- envPtr->currStackDepth++;
- CompileBody(envPtr, bodyTokenPtr, interp);
- envPtr->currStackDepth = savedStackDepth;
- ExceptionRangeEnds(envPtr, range);
-
- /*
- * Normal termination code: the stack has the key list below the result of
- * the body evaluation: swap them and finish the update code.
- */
-
- TclEmitOpcode( INST_END_CATCH, envPtr);
- TclEmitInstInt4( INST_REVERSE, 2, envPtr);
- TclEmitInstInt4( INST_DICT_UPDATE_END, dictIndex, envPtr);
- TclEmitInt4( infoIndex, envPtr);
-
- /*
- * Jump around the exceptional termination code.
- */
-
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
-
- /*
- * Termination code for non-ok returns: stash the result and return
- * options in the stack, bring up the key list, finish the update code,
- * and finally return with the catched return data
- */
-
- ExceptionRangeTarget(envPtr, range, catchOffset);
- TclEmitOpcode( INST_PUSH_RESULT, envPtr);
- TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
- TclEmitOpcode( INST_END_CATCH, envPtr);
- TclEmitInstInt4( INST_REVERSE, 3, envPtr);
-
- TclEmitInstInt4( INST_DICT_UPDATE_END, dictIndex, envPtr);
- TclEmitInt4( infoIndex, envPtr);
- TclEmitOpcode( INST_RETURN_STK, envPtr);
-
- if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
- Tcl_Panic("TclCompileDictCmd(update): bad jump distance %d",
- (int) (CurrentOffset(envPtr) - jumpFixup.codeOffset));
- }
- ckfree(keyTokenPtrs);
- envPtr->currStackDepth = savedStackDepth + 1;
- return TCL_OK;
-}
-
-int
-TclCompileDictAppendCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int i, dictVarIndex;
-
- /*
- * There must be at least two argument after the command. And we impose an
- * (arbirary) safe limit; anyone exceeding it should stop worrying about
- * speed quite so much. ;-)
- */
-
- if (parsePtr->numWords<4 || parsePtr->numWords>100) {
- return TCL_ERROR;
- }
-
- /*
- * Get the index of the local variable that we will be working with.
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- } else {
- register const char *name = tokenPtr[1].start;
- register int nameChars = tokenPtr[1].size;
-
- if (!TclIsLocalScalar(name, nameChars)) {
- return TCL_ERROR;
- }
- dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr);
- if (dictVarIndex < 0) {
- return TCL_ERROR;
- }
- }
-
- /*
- * Produce the string to concatenate onto the dictionary entry.
- */
-
- tokenPtr = TokenAfter(tokenPtr);
- for (i=2 ; i<parsePtr->numWords ; i++) {
- CompileWord(envPtr, tokenPtr, interp);
- tokenPtr = TokenAfter(tokenPtr);
- }
- if (parsePtr->numWords > 4) {
- TclEmitInstInt1(INST_CONCAT1, parsePtr->numWords-3, envPtr);
- }
-
- /*
- * Do the concatenation.
- */
-
- TclEmitInstInt4(INST_DICT_APPEND, dictVarIndex, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileDictLappendCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *varTokenPtr, *keyTokenPtr, *valueTokenPtr;
- int dictVarIndex, nameChars;
- const char *name;
-
- /*
- * There must be three arguments after the command.
- */
-
- if (parsePtr->numWords != 4) {
- return TCL_ERROR;
- }
-
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
- keyTokenPtr = TokenAfter(varTokenPtr);
- valueTokenPtr = TokenAfter(keyTokenPtr);
- if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- name = varTokenPtr[1].start;
- nameChars = varTokenPtr[1].size;
- if (!TclIsLocalScalar(name, nameChars)) {
- return TCL_ERROR;
- }
- dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr);
- if (dictVarIndex < 0) {
- return TCL_ERROR;
- }
- CompileWord(envPtr, keyTokenPtr, interp);
- CompileWord(envPtr, valueTokenPtr, interp);
- TclEmitInstInt4( INST_DICT_LAPPEND, dictVarIndex, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileDictWithCmd(
- Tcl_Interp *interp, /* Used for looking up stuff. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- int i, range, varNameTmp, pathTmp, keysTmp, gotPath, dictVar = -1;
- int bodyIsEmpty = 1;
- Tcl_Token *varTokenPtr, *tokenPtr;
- int savedStackDepth = envPtr->currStackDepth;
- JumpFixup jumpFixup;
- const char *ptr, *end;
-
- /*
- * There must be at least one argument after the command.
- */
-
- if (parsePtr->numWords < 3) {
- return TCL_ERROR;
- }
-
- /*
- * Parse the command (trivially). Expect the following:
- * dict with <any (varName)> ?<any> ...? <literal>
- */
-
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
- tokenPtr = TokenAfter(varTokenPtr);
- for (i=3 ; i<parsePtr->numWords ; i++) {
- tokenPtr = TokenAfter(tokenPtr);
- }
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
-
- /*
- * Test if the last word is an empty script; if so, we can compile it in
- * all cases, but if it is non-empty we need local variable table entries
- * to hold the temporary variables (used to keep stack usage simple).
- */
-
- for (ptr=tokenPtr[1].start,end=ptr+tokenPtr[1].size ; ptr!=end ; ptr++) {
- if (*ptr!=' ' && *ptr!='\t' && *ptr!='\n' && *ptr!='\r') {
- if (envPtr->procPtr == NULL) {
- return TCL_ERROR;
- }
- bodyIsEmpty = 0;
- break;
- }
- }
-
- /*
- * Determine if we're manipulating a dict in a simple local variable.
- */
-
- gotPath = (parsePtr->numWords > 3);
- if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD &&
- TclIsLocalScalar(varTokenPtr[1].start, varTokenPtr[1].size)) {
- dictVar = TclFindCompiledLocal(varTokenPtr[1].start,
- varTokenPtr[1].size, 1, envPtr);
- }
-
- /*
- * Special case: an empty body means we definitely have no need to issue
- * try-finally style code or to allocate local variable table entries for
- * storing temporaries. Still need to do both INST_DICT_EXPAND and
- * INST_DICT_RECOMBINE_* though, because we can't determine if we're free
- * of traces.
- */
-
- if (bodyIsEmpty) {
- if (dictVar >= 0) {
- if (gotPath) {
- /*
- * Case: Path into dict in LVT with empty body.
- */
-
- tokenPtr = TokenAfter(varTokenPtr);
- for (i=2 ; i<parsePtr->numWords-1 ; i++) {
- CompileWord(envPtr, tokenPtr, interp);
- tokenPtr = TokenAfter(tokenPtr);
- }
- TclEmitInstInt4(INST_LIST, parsePtr->numWords-3,envPtr);
- Emit14Inst( INST_LOAD_SCALAR, dictVar, envPtr);
- TclEmitInstInt4(INST_OVER, 1, envPtr);
- TclEmitOpcode( INST_DICT_EXPAND, envPtr);
- TclEmitInstInt4(INST_DICT_RECOMBINE_IMM, dictVar, envPtr);
- PushLiteral(envPtr, "", 0);
- } else {
- /*
- * Case: Direct dict in LVT with empty body.
- */
-
- PushLiteral(envPtr, "", 0);
- Emit14Inst( INST_LOAD_SCALAR, dictVar, envPtr);
- PushLiteral(envPtr, "", 0);
- TclEmitOpcode( INST_DICT_EXPAND, envPtr);
- TclEmitInstInt4(INST_DICT_RECOMBINE_IMM, dictVar, envPtr);
- PushLiteral(envPtr, "", 0);
- }
- } else {
- if (gotPath) {
- /*
- * Case: Path into dict in non-simple var with empty body.
- */
-
- tokenPtr = varTokenPtr;
- for (i=1 ; i<parsePtr->numWords-1 ; i++) {
- CompileWord(envPtr, tokenPtr, interp);
- tokenPtr = TokenAfter(tokenPtr);
- }
- TclEmitInstInt4(INST_LIST, parsePtr->numWords-3,envPtr);
- TclEmitInstInt4(INST_OVER, 1, envPtr);
- TclEmitOpcode( INST_LOAD_STK, envPtr);
- TclEmitInstInt4(INST_OVER, 1, envPtr);
- TclEmitOpcode( INST_DICT_EXPAND, envPtr);
- TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr);
- PushLiteral(envPtr, "", 0);
- } else {
- /*
- * Case: Direct dict in non-simple var with empty body.
- */
-
- CompileWord(envPtr, varTokenPtr, interp);
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitOpcode( INST_LOAD_STK, envPtr);
- PushLiteral(envPtr, "", 0);
- TclEmitOpcode( INST_DICT_EXPAND, envPtr);
- PushLiteral(envPtr, "", 0);
- TclEmitInstInt4(INST_REVERSE, 2, envPtr);
- TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr);
- PushLiteral(envPtr, "", 0);
- }
- }
- envPtr->currStackDepth = savedStackDepth + 1;
- return TCL_OK;
- }
-
- /*
- * OK, we have a non-trivial body. This means that the focus is on
- * generating a try-finally structure where the INST_DICT_RECOMBINE_* goes
- * in the 'finally' clause.
- *
- * Start by allocating local (unnamed, untraced) working variables.
- */
-
- if (dictVar == -1) {
- varNameTmp = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- } else {
- varNameTmp = -1;
- }
- if (gotPath) {
- pathTmp = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- } else {
- pathTmp = -1;
- }
- keysTmp = TclFindCompiledLocal(NULL, 0, 1, envPtr);
-
- /*
- * Issue instructions. First, the part to expand the dictionary.
- */
-
- if (varNameTmp > -1) {
- CompileWord(envPtr, varTokenPtr, interp);
- Emit14Inst( INST_STORE_SCALAR, varNameTmp, envPtr);
- }
- tokenPtr = TokenAfter(varTokenPtr);
- if (gotPath) {
- for (i=2 ; i<parsePtr->numWords-1 ; i++) {
- CompileWord(envPtr, tokenPtr, interp);
- tokenPtr = TokenAfter(tokenPtr);
- }
- TclEmitInstInt4( INST_LIST, parsePtr->numWords-3,envPtr);
- Emit14Inst( INST_STORE_SCALAR, pathTmp, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- }
- if (dictVar == -1) {
- TclEmitOpcode( INST_LOAD_STK, envPtr);
- } else {
- Emit14Inst( INST_LOAD_SCALAR, dictVar, envPtr);
- }
- if (gotPath) {
- Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr);
- } else {
- PushLiteral(envPtr, "", 0);
- }
- TclEmitOpcode( INST_DICT_EXPAND, envPtr);
- Emit14Inst( INST_STORE_SCALAR, keysTmp, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
-
- /*
- * Now the body of the [dict with].
- */
-
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
- TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
-
- ExceptionRangeStarts(envPtr, range);
- envPtr->currStackDepth++;
- CompileBody(envPtr, tokenPtr, interp);
- envPtr->currStackDepth = savedStackDepth;
- ExceptionRangeEnds(envPtr, range);
-
- /*
- * Now fold the results back into the dictionary in the OK case.
- */
-
- TclEmitOpcode( INST_END_CATCH, envPtr);
- if (varNameTmp > -1) {
- Emit14Inst( INST_LOAD_SCALAR, varNameTmp, envPtr);
- }
- if (gotPath) {
- Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr);
- } else {
- PushLiteral(envPtr, "", 0);
- }
- Emit14Inst( INST_LOAD_SCALAR, keysTmp, envPtr);
- if (dictVar == -1) {
- TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr);
- } else {
- TclEmitInstInt4( INST_DICT_RECOMBINE_IMM, dictVar, envPtr);
- }
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
-
- /*
- * Now fold the results back into the dictionary in the exception case.
- */
-
- ExceptionRangeTarget(envPtr, range, catchOffset);
- TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
- TclEmitOpcode( INST_PUSH_RESULT, envPtr);
- TclEmitOpcode( INST_END_CATCH, envPtr);
- if (varNameTmp > -1) {
- Emit14Inst( INST_LOAD_SCALAR, varNameTmp, envPtr);
- }
- if (parsePtr->numWords > 3) {
- Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr);
- } else {
- PushLiteral(envPtr, "", 0);
- }
- Emit14Inst( INST_LOAD_SCALAR, keysTmp, envPtr);
- if (dictVar == -1) {
- TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr);
- } else {
- TclEmitInstInt4( INST_DICT_RECOMBINE_IMM, dictVar, envPtr);
- }
- TclEmitOpcode( INST_RETURN_STK, envPtr);
-
- /*
- * Prepare for the start of the next command.
- */
-
- envPtr->currStackDepth = savedStackDepth + 1;
- if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
- Tcl_Panic("TclCompileDictCmd(update): bad jump distance %d",
- (int) (CurrentOffset(envPtr) - jumpFixup.codeOffset));
- }
- return TCL_OK;
-}
-/*
- *----------------------------------------------------------------------
- *
- * DupDictUpdateInfo, FreeDictUpdateInfo --
- *
- * Functions to duplicate, release and print the aux data created for use
- * with the INST_DICT_UPDATE_START and INST_DICT_UPDATE_END instructions.
- *
- * Results:
- * DupDictUpdateInfo: a copy of the auxiliary data
- * FreeDictUpdateInfo: none
- * PrintDictUpdateInfo: none
- *
- * Side effects:
- * DupDictUpdateInfo: allocates memory
- * FreeDictUpdateInfo: releases memory
- * PrintDictUpdateInfo: none
- *
- *----------------------------------------------------------------------
- */
-
-static ClientData
-DupDictUpdateInfo(
- ClientData clientData)
-{
- DictUpdateInfo *dui1Ptr, *dui2Ptr;
- unsigned len;
-
- dui1Ptr = clientData;
- len = sizeof(DictUpdateInfo) + sizeof(int) * (dui1Ptr->length - 1);
- dui2Ptr = ckalloc(len);
- memcpy(dui2Ptr, dui1Ptr, len);
- return dui2Ptr;
-}
-
-static void
-FreeDictUpdateInfo(
- ClientData clientData)
-{
- ckfree(clientData);
-}
-
-static void
-PrintDictUpdateInfo(
- ClientData clientData,
- Tcl_Obj *appendObj,
- ByteCode *codePtr,
- unsigned int pcOffset)
-{
- DictUpdateInfo *duiPtr = clientData;
- int i;
-
- for (i=0 ; i<duiPtr->length ; i++) {
- if (i) {
- Tcl_AppendToObj(appendObj, ", ", -1);
- }
- Tcl_AppendPrintfToObj(appendObj, "%%v%u", duiPtr->varIndices[i]);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileErrorCmd --
- *
- * Procedure called to compile the "error" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "error" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileErrorCmd(
- Tcl_Interp *interp, /* Used for context. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * General syntax: [error message ?errorInfo? ?errorCode?]
- * However, we only deal with the case where there is just a message.
- */
- Tcl_Token *messageTokenPtr;
- int savedStackDepth = envPtr->currStackDepth;
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
- messageTokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- PushLiteral(envPtr, "-code error -level 0", 20);
- CompileWord(envPtr, messageTokenPtr, interp);
- TclEmitOpcode(INST_RETURN_STK, envPtr);
- envPtr->currStackDepth = savedStackDepth + 1;
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileExprCmd --
- *
- * Procedure called to compile the "expr" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "expr" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileExprCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *firstWordPtr;
-
- if (parsePtr->numWords == 1) {
- return TCL_ERROR;
- }
-
- firstWordPtr = TokenAfter(parsePtr->tokenPtr);
- TclCompileExprWords(interp, firstWordPtr, parsePtr->numWords-1, envPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileForCmd --
- *
- * Procedure called to compile the "for" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "for" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileForCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *startTokenPtr, *testTokenPtr, *nextTokenPtr, *bodyTokenPtr;
- JumpFixup jumpEvalCondFixup;
- int testCodeOffset, bodyCodeOffset, nextCodeOffset, jumpDist;
- int bodyRange, nextRange;
- int savedStackDepth = envPtr->currStackDepth;
-
- if (parsePtr->numWords != 5) {
- return TCL_ERROR;
- }
-
- /*
- * If the test expression requires substitutions, don't compile the for
- * command inline. E.g., the expression might cause the loop to never
- * execute or execute forever, as in "for {} "$x > 5" {incr x} {}".
- */
-
- startTokenPtr = TokenAfter(parsePtr->tokenPtr);
- testTokenPtr = TokenAfter(startTokenPtr);
- if (testTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
-
- /*
- * Bail out also if the body or the next expression require substitutions
- * in order to insure correct behaviour [Bug 219166]
- */
-
- nextTokenPtr = TokenAfter(testTokenPtr);
- bodyTokenPtr = TokenAfter(nextTokenPtr);
- if ((nextTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)
- || (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)) {
- return TCL_ERROR;
- }
-
- /*
- * Create ExceptionRange records for the body and the "next" command. The
- * "next" command's ExceptionRange supports break but not continue (and
- * has a -1 continueOffset).
- */
-
- bodyRange = DeclareExceptionRange(envPtr, LOOP_EXCEPTION_RANGE);
- nextRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
-
- /*
- * Inline compile the initial command.
- */
-
- CompileBody(envPtr, startTokenPtr, interp);
- TclEmitOpcode(INST_POP, envPtr);
-
- /*
- * Jump to the evaluation of the condition. This code uses the "loop
- * rotation" optimisation (which eliminates one branch from the loop).
- * "for start cond next body" produces then:
- * start
- * goto A
- * B: body : bodyCodeOffset
- * next : nextCodeOffset, continueOffset
- * A: cond -> result : testCodeOffset
- * if (result) goto B
- */
-
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpEvalCondFixup);
-
- /*
- * Compile the loop body.
- */
-
- bodyCodeOffset = ExceptionRangeStarts(envPtr, bodyRange);
- CompileBody(envPtr, bodyTokenPtr, interp);
- ExceptionRangeEnds(envPtr, bodyRange);
- envPtr->currStackDepth = savedStackDepth + 1;
- TclEmitOpcode(INST_POP, envPtr);
-
- /*
- * Compile the "next" subcommand.
- */
-
- envPtr->currStackDepth = savedStackDepth;
- nextCodeOffset = ExceptionRangeStarts(envPtr, nextRange);
- CompileBody(envPtr, nextTokenPtr, interp);
- ExceptionRangeEnds(envPtr, nextRange);
- envPtr->currStackDepth = savedStackDepth + 1;
- TclEmitOpcode(INST_POP, envPtr);
- envPtr->currStackDepth = savedStackDepth;
-
- /*
- * Compile the test expression then emit the conditional jump that
- * terminates the for.
- */
-
- testCodeOffset = CurrentOffset(envPtr);
-
- jumpDist = testCodeOffset - jumpEvalCondFixup.codeOffset;
- if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) {
- bodyCodeOffset += 3;
- nextCodeOffset += 3;
- testCodeOffset += 3;
- }
-
- envPtr->currStackDepth = savedStackDepth;
- TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
- envPtr->currStackDepth = savedStackDepth + 1;
-
- jumpDist = CurrentOffset(envPtr) - bodyCodeOffset;
- if (jumpDist > 127) {
- TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
- } else {
- TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
- }
-
- /*
- * Fix the starting points of the exception ranges (may have moved due to
- * jump type modification) and set where the exceptions target.
- */
-
- envPtr->exceptArrayPtr[bodyRange].codeOffset = bodyCodeOffset;
- envPtr->exceptArrayPtr[bodyRange].continueOffset = nextCodeOffset;
-
- envPtr->exceptArrayPtr[nextRange].codeOffset = nextCodeOffset;
-
- ExceptionRangeTarget(envPtr, bodyRange, breakOffset);
- ExceptionRangeTarget(envPtr, nextRange, breakOffset);
-
- /*
- * The for command's result is an empty string.
- */
-
- envPtr->currStackDepth = savedStackDepth;
- PushLiteral(envPtr, "", 0);
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileForeachCmd --
- *
- * Procedure called to compile the "foreach" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "foreach" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileForeachCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- return CompileEachloopCmd(interp, parsePtr, cmdPtr, envPtr,
- TCL_EACH_KEEP_NONE);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CompileEachloopCmd --
- *
- * Procedure called to compile the "foreach" and "lmap" commands.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "foreach" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-CompileEachloopCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr, /* Holds resulting instructions. */
- int collect) /* Select collecting or accumulating mode
- * (TCL_EACH_*) */
-{
- Proc *procPtr = envPtr->procPtr;
- ForeachInfo *infoPtr; /* Points to the structure describing this
- * foreach command. Stored in a AuxData
- * record in the ByteCode. */
- int firstValueTemp; /* Index of the first temp var in the frame
- * used to point to a value list. */
- int loopCtTemp; /* Index of temp var holding the loop's
- * iteration count. */
- int collectVar = -1; /* Index of temp var holding the result var
- * index. */
-
- Tcl_Token *tokenPtr, *bodyTokenPtr;
- unsigned char *jumpPc;
- JumpFixup jumpFalseFixup;
- int jumpBackDist, jumpBackOffset, infoIndex, range;
- int numWords, numLists, numVars, loopIndex, tempVar, i, j, code;
- int savedStackDepth = envPtr->currStackDepth;
-
- /*
- * We parse the variable list argument words and create two arrays:
- * varcList[i] is number of variables in i-th var list.
- * varvList[i] points to array of var names in i-th var list.
- */
-
- int *varcList;
- const char ***varvList;
-
- /*
- * If the foreach command isn't in a procedure, don't compile it inline:
- * the payoff is too small.
- */
-
- if (procPtr == NULL) {
- return TCL_ERROR;
- }
-
- numWords = parsePtr->numWords;
- if ((numWords < 4) || (numWords%2 != 0)) {
- return TCL_ERROR;
- }
-
- /*
- * Bail out if the body requires substitutions in order to insure correct
- * behaviour. [Bug 219166]
- */
-
- for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; i++) {
- tokenPtr = TokenAfter(tokenPtr);
- }
- bodyTokenPtr = tokenPtr;
- if (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
-
- /*
- * Allocate storage for the varcList and varvList arrays if necessary.
- */
-
- numLists = (numWords - 2)/2;
- varcList = ckalloc(numLists * sizeof(int));
- memset(varcList, 0, numLists * sizeof(int));
- varvList = (const char ***) ckalloc(numLists * sizeof(const char **));
- memset((char*) varvList, 0, numLists * sizeof(const char **));
-
- /*
- * Break up each var list and set the varcList and varvList arrays. Don't
- * compile the foreach inline if any var name needs substitutions or isn't
- * a scalar, or if any var list needs substitutions.
- */
-
- loopIndex = 0;
- for (i = 0, tokenPtr = parsePtr->tokenPtr;
- i < numWords-1;
- i++, tokenPtr = TokenAfter(tokenPtr)) {
- Tcl_DString varList;
-
- if (i%2 != 1) {
- continue;
- }
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- code = TCL_ERROR;
- goto done;
- }
-
- /*
- * Lots of copying going on here. Need a ListObj wizard to show a
- * better way.
- */
-
- Tcl_DStringInit(&varList);
- TclDStringAppendToken(&varList, &tokenPtr[1]);
- code = Tcl_SplitList(interp, Tcl_DStringValue(&varList),
- &varcList[loopIndex], &varvList[loopIndex]);
- Tcl_DStringFree(&varList);
- if (code != TCL_OK) {
- code = TCL_ERROR;
- goto done;
- }
- numVars = varcList[loopIndex];
-
- /*
- * If the variable list is empty, we can enter an infinite loop when
- * the interpreted version would not. Take care to ensure this does
- * not happen. [Bug 1671138]
- */
-
- if (numVars == 0) {
- code = TCL_ERROR;
- goto done;
- }
-
- for (j = 0; j < numVars; j++) {
- const char *varName = varvList[loopIndex][j];
-
- if (!TclIsLocalScalar(varName, (int) strlen(varName))) {
- code = TCL_ERROR;
- goto done;
- }
- }
- loopIndex++;
- }
-
- if (collect == TCL_EACH_COLLECT) {
- collectVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0, /*create*/ 1,
- envPtr);
- if (collectVar < 0) {
- return TCL_ERROR;
- }
- }
-
- /*
- * We will compile the foreach command. Reserve (numLists + 1) temporary
- * variables:
- * - numLists temps to hold each value list
- * - 1 temp for the loop counter (index of next element in each list)
- *
- * At this time we don't try to reuse temporaries; if there are two
- * nonoverlapping foreach loops, they don't share any temps.
- */
-
- code = TCL_OK;
- firstValueTemp = -1;
- for (loopIndex = 0; loopIndex < numLists; loopIndex++) {
- tempVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
- /*create*/ 1, envPtr);
- if (loopIndex == 0) {
- firstValueTemp = tempVar;
- }
- }
- loopCtTemp = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
- /*create*/ 1, envPtr);
-
- /*
- * Create and initialize the ForeachInfo and ForeachVarList data
- * structures describing this command. Then create a AuxData record
- * pointing to the ForeachInfo structure.
- */
-
- infoPtr = ckalloc(sizeof(ForeachInfo)
- + numLists * sizeof(ForeachVarList *));
- infoPtr->numLists = numLists;
- infoPtr->firstValueTemp = firstValueTemp;
- infoPtr->loopCtTemp = loopCtTemp;
- for (loopIndex = 0; loopIndex < numLists; loopIndex++) {
- ForeachVarList *varListPtr;
-
- numVars = varcList[loopIndex];
- varListPtr = ckalloc(sizeof(ForeachVarList)
- + numVars * sizeof(int));
- varListPtr->numVars = numVars;
- for (j = 0; j < numVars; j++) {
- const char *varName = varvList[loopIndex][j];
- int nameChars = strlen(varName);
-
- varListPtr->varIndexes[j] = TclFindCompiledLocal(varName,
- nameChars, /*create*/ 1, envPtr);
- }
- infoPtr->varLists[loopIndex] = varListPtr;
- }
- infoIndex = TclCreateAuxData(infoPtr, &tclForeachInfoType, envPtr);
-
- /*
- * Create an exception record to handle [break] and [continue].
- */
-
- range = DeclareExceptionRange(envPtr, LOOP_EXCEPTION_RANGE);
-
- /*
- * Evaluate then store each value list in the associated temporary.
- */
-
- loopIndex = 0;
- for (i = 0, tokenPtr = parsePtr->tokenPtr;
- i < numWords-1;
- i++, tokenPtr = TokenAfter(tokenPtr)) {
- if ((i%2 == 0) && (i > 0)) {
- CompileTokens(envPtr, tokenPtr, interp);
- tempVar = (firstValueTemp + loopIndex);
- Emit14Inst( INST_STORE_SCALAR, tempVar, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- loopIndex++;
- }
- }
-
- /*
- * Create temporary variable to capture return values from loop body.
- */
-
- if (collect == TCL_EACH_COLLECT) {
- PushLiteral(envPtr, "", 0);
- Emit14Inst( INST_STORE_SCALAR, collectVar, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- }
-
- /*
- * Initialize the temporary var that holds the count of loop iterations.
- */
-
- TclEmitInstInt4( INST_FOREACH_START4, infoIndex, envPtr);
-
- /*
- * Top of loop code: assign each loop variable and check whether
- * to terminate the loop.
- */
-
- ExceptionRangeTarget(envPtr, range, continueOffset);
- TclEmitInstInt4( INST_FOREACH_STEP4, infoIndex, envPtr);
- TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFalseFixup);
-
- /*
- * Inline compile the loop body.
- */
-
- ExceptionRangeStarts(envPtr, range);
- CompileBody(envPtr, bodyTokenPtr, interp);
- ExceptionRangeEnds(envPtr, range);
- envPtr->currStackDepth = savedStackDepth + 1;
-
- if (collect == TCL_EACH_COLLECT) {
- Emit14Inst( INST_LAPPEND_SCALAR, collectVar,envPtr);
- }
- TclEmitOpcode( INST_POP, envPtr);
-
- /*
- * Jump back to the test at the top of the loop. Generate a 4 byte jump if
- * the distance to the test is > 120 bytes. This is conservative and
- * ensures that we won't have to replace this jump if we later need to
- * replace the ifFalse jump with a 4 byte jump.
- */
-
- jumpBackOffset = CurrentOffset(envPtr);
- jumpBackDist = jumpBackOffset-envPtr->exceptArrayPtr[range].continueOffset;
- if (jumpBackDist > 120) {
- TclEmitInstInt4(INST_JUMP4, -jumpBackDist, envPtr);
- } else {
- TclEmitInstInt1(INST_JUMP1, -jumpBackDist, envPtr);
- }
-
- /*
- * Fix the target of the jump after the foreach_step test.
- */
-
- if (TclFixupForwardJumpToHere(envPtr, &jumpFalseFixup, 127)) {
- /*
- * Update the loop body's starting PC offset since it moved down.
- */
-
- envPtr->exceptArrayPtr[range].codeOffset += 3;
-
- /*
- * Update the jump back to the test at the top of the loop since it
- * also moved down 3 bytes.
- */
-
- jumpBackOffset += 3;
- jumpPc = (envPtr->codeStart + jumpBackOffset);
- jumpBackDist += 3;
- if (jumpBackDist > 120) {
- TclUpdateInstInt4AtPc(INST_JUMP4, -jumpBackDist, jumpPc);
- } else {
- TclUpdateInstInt1AtPc(INST_JUMP1, -jumpBackDist, jumpPc);
- }
- }
-
- /*
- * Set the loop's break target.
- */
-
- ExceptionRangeTarget(envPtr, range, breakOffset);
-
- /*
- * The command's result is an empty string if not collecting, or the
- * list of results from evaluating the loop body.
- */
-
- envPtr->currStackDepth = savedStackDepth;
- if (collect == TCL_EACH_COLLECT) {
- Emit14Inst( INST_LOAD_SCALAR, collectVar, envPtr);
- TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( collectVar, envPtr);
- } else {
- PushLiteral(envPtr, "", 0);
- }
- envPtr->currStackDepth = savedStackDepth + 1;
-
- done:
- for (loopIndex = 0; loopIndex < numLists; loopIndex++) {
- if (varvList[loopIndex] != NULL) {
- ckfree(varvList[loopIndex]);
- }
- }
- ckfree((void *)varvList);
- ckfree(varcList);
- return code;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * DupForeachInfo --
- *
- * This procedure duplicates a ForeachInfo structure created as auxiliary
- * data during the compilation of a foreach command.
- *
- * Results:
- * A pointer to a newly allocated copy of the existing ForeachInfo
- * structure is returned.
- *
- * Side effects:
- * Storage for the copied ForeachInfo record is allocated. If the
- * original ForeachInfo structure pointed to any ForeachVarList records,
- * these structures are also copied and pointers to them are stored in
- * the new ForeachInfo record.
- *
- *----------------------------------------------------------------------
- */
-
-static ClientData
-DupForeachInfo(
- ClientData clientData) /* The foreach command's compilation auxiliary
- * data to duplicate. */
-{
- register ForeachInfo *srcPtr = clientData;
- ForeachInfo *dupPtr;
- register ForeachVarList *srcListPtr, *dupListPtr;
- int numVars, i, j, numLists = srcPtr->numLists;
-
- dupPtr = ckalloc(sizeof(ForeachInfo)
- + numLists * sizeof(ForeachVarList *));
- dupPtr->numLists = numLists;
- dupPtr->firstValueTemp = srcPtr->firstValueTemp;
- dupPtr->loopCtTemp = srcPtr->loopCtTemp;
-
- for (i = 0; i < numLists; i++) {
- srcListPtr = srcPtr->varLists[i];
- numVars = srcListPtr->numVars;
- dupListPtr = ckalloc(sizeof(ForeachVarList)
- + numVars * sizeof(int));
- dupListPtr->numVars = numVars;
- for (j = 0; j < numVars; j++) {
- dupListPtr->varIndexes[j] = srcListPtr->varIndexes[j];
- }
- dupPtr->varLists[i] = dupListPtr;
- }
- return dupPtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * FreeForeachInfo --
- *
- * Procedure to free a ForeachInfo structure created as auxiliary data
- * during the compilation of a foreach command.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Storage for the ForeachInfo structure pointed to by the ClientData
- * argument is freed as is any ForeachVarList record pointed to by the
- * ForeachInfo structure.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-FreeForeachInfo(
- ClientData clientData) /* The foreach command's compilation auxiliary
- * data to free. */
-{
- register ForeachInfo *infoPtr = clientData;
- register ForeachVarList *listPtr;
- int numLists = infoPtr->numLists;
- register int i;
-
- for (i = 0; i < numLists; i++) {
- listPtr = infoPtr->varLists[i];
- ckfree(listPtr);
- }
- ckfree(infoPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * PrintForeachInfo --
- *
- * Function to write a human-readable representation of a ForeachInfo
- * structure to stdout for debugging.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-PrintForeachInfo(
- ClientData clientData,
- Tcl_Obj *appendObj,
- ByteCode *codePtr,
- unsigned int pcOffset)
-{
- register ForeachInfo *infoPtr = clientData;
- register ForeachVarList *varsPtr;
- int i, j;
-
- Tcl_AppendToObj(appendObj, "data=[", -1);
-
- for (i=0 ; i<infoPtr->numLists ; i++) {
- if (i) {
- Tcl_AppendToObj(appendObj, ", ", -1);
- }
- Tcl_AppendPrintfToObj(appendObj, "%%v%u",
- (unsigned) (infoPtr->firstValueTemp + i));
- }
- Tcl_AppendPrintfToObj(appendObj, "], loop=%%v%u",
- (unsigned) infoPtr->loopCtTemp);
- for (i=0 ; i<infoPtr->numLists ; i++) {
- if (i) {
- Tcl_AppendToObj(appendObj, ",", -1);
- }
- Tcl_AppendPrintfToObj(appendObj, "\n\t\t it%%v%u\t[",
- (unsigned) (infoPtr->firstValueTemp + i));
- varsPtr = infoPtr->varLists[i];
- for (j=0 ; j<varsPtr->numVars ; j++) {
- if (j) {
- Tcl_AppendToObj(appendObj, ", ", -1);
- }
- Tcl_AppendPrintfToObj(appendObj, "%%v%u",
- (unsigned) varsPtr->varIndexes[j]);
- }
- Tcl_AppendToObj(appendObj, "]", -1);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileFormatCmd --
- *
- * Procedure called to compile the "format" command. Handles cases that
- * can be done as constants or simple string concatenation only.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "format" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileFormatCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr = parsePtr->tokenPtr;
- Tcl_Obj **objv, *formatObj, *tmpObj;
- char *bytes, *start;
- int i, j, len;
-
- /*
- * Don't handle any guaranteed-error cases.
- */
-
- if (parsePtr->numWords < 2) {
- return TCL_ERROR;
- }
-
- /*
- * Check if the argument words are all compile-time-known literals; that's
- * a case we can handle by compiling to a constant.
- */
-
- formatObj = Tcl_NewObj();
- Tcl_IncrRefCount(formatObj);
- tokenPtr = TokenAfter(tokenPtr);
- if (!TclWordKnownAtCompileTime(tokenPtr, formatObj)) {
- Tcl_DecrRefCount(formatObj);
- return TCL_ERROR;
- }
-
- objv = ckalloc((parsePtr->numWords-2) * sizeof(Tcl_Obj *));
- for (i=0 ; i+2 < parsePtr->numWords ; i++) {
- tokenPtr = TokenAfter(tokenPtr);
- objv[i] = Tcl_NewObj();
- Tcl_IncrRefCount(objv[i]);
- if (!TclWordKnownAtCompileTime(tokenPtr, objv[i])) {
- goto checkForStringConcatCase;
- }
- }
-
- /*
- * Everything is a literal, so the result is constant too (or an error if
- * the format is broken). Do the format now.
- */
-
- tmpObj = Tcl_Format(interp, Tcl_GetString(formatObj),
- parsePtr->numWords-2, objv);
- for (; --i>=0 ;) {
- Tcl_DecrRefCount(objv[i]);
- }
- ckfree(objv);
- Tcl_DecrRefCount(formatObj);
- if (tmpObj == NULL) {
- return TCL_ERROR;
- }
-
- /*
- * Not an error, always a constant result, so just push the result as a
- * literal. Job done.
- */
-
- bytes = Tcl_GetStringFromObj(tmpObj, &len);
- PushLiteral(envPtr, bytes, len);
- Tcl_DecrRefCount(tmpObj);
- return TCL_OK;
-
- checkForStringConcatCase:
- /*
- * See if we can generate a sequence of things to concatenate. This
- * requires that all the % sequences be %s or %%, as everything else is
- * sufficiently complex that we don't bother.
- *
- * First, get the state of the system relatively sensible (cleaning up
- * after our attempt to spot a literal).
- */
-
- for (; i>=0 ; i--) {
- Tcl_DecrRefCount(objv[i]);
- }
- ckfree(objv);
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- tokenPtr = TokenAfter(tokenPtr);
- i = 0;
-
- /*
- * Now scan through and check for non-%s and non-%% substitutions.
- */
-
- for (bytes = Tcl_GetString(formatObj) ; *bytes ; bytes++) {
- if (*bytes == '%') {
- bytes++;
- if (*bytes == 's') {
- i++;
- continue;
- } else if (*bytes == '%') {
- continue;
- }
- Tcl_DecrRefCount(formatObj);
- return TCL_ERROR;
- }
- }
-
- /*
- * Check if the number of things to concatenate will fit in a byte.
- */
-
- if (i+2 != parsePtr->numWords || i > 125) {
- Tcl_DecrRefCount(formatObj);
- return TCL_ERROR;
- }
-
- /*
- * Generate the pushes of the things to concatenate, a sequence of
- * literals and compiled tokens (of which at least one is non-literal or
- * we'd have the case in the first half of this function) which we will
- * concatenate.
- */
-
- i = 0; /* The count of things to concat. */
- j = 2; /* The index into the argument tokens, for
- * TIP#280 handling. */
- start = Tcl_GetString(formatObj);
- /* The start of the currently-scanned literal
- * in the format string. */
- tmpObj = Tcl_NewObj(); /* The buffer used to accumulate the literal
- * being built. */
- for (bytes = start ; *bytes ; bytes++) {
- if (*bytes == '%') {
- Tcl_AppendToObj(tmpObj, start, bytes - start);
- if (*++bytes == '%') {
- Tcl_AppendToObj(tmpObj, "%", 1);
- } else {
- char *b = Tcl_GetStringFromObj(tmpObj, &len);
-
- /*
- * If there is a non-empty literal from the format string,
- * push it and reset.
- */
-
- if (len > 0) {
- PushLiteral(envPtr, b, len);
- Tcl_DecrRefCount(tmpObj);
- tmpObj = Tcl_NewObj();
- i++;
- }
-
- /*
- * Push the code to produce the string that would be
- * substituted with %s, except we'll be concatenating
- * directly.
- */
-
- CompileWord(envPtr, tokenPtr, interp);
- tokenPtr = TokenAfter(tokenPtr);
- j++;
- i++;
- }
- start = bytes + 1;
- }
- }
-
- /*
- * Handle the case of a trailing literal.
- */
-
- Tcl_AppendToObj(tmpObj, start, bytes - start);
- bytes = Tcl_GetStringFromObj(tmpObj, &len);
- if (len > 0) {
- PushLiteral(envPtr, bytes, len);
- i++;
- }
- Tcl_DecrRefCount(tmpObj);
- Tcl_DecrRefCount(formatObj);
-
- if (i > 1) {
- /*
- * Do the concatenation, which produces the result.
- */
-
- TclEmitInstInt1(INST_CONCAT1, i, envPtr);
- } else {
- /*
- * EVIL HACK! Force there to be a string representation in the case
- * where there's just a "%s" in the format; case covered by the test
- * format-20.1 (and it is horrible...)
- */
-
- TclEmitOpcode(INST_DUP, envPtr);
- PushLiteral(envPtr, "", 0);
- TclEmitOpcode(INST_STR_EQ, envPtr);
- TclEmitOpcode(INST_POP, envPtr);
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileGlobalCmd --
- *
- * Procedure called to compile the "global" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "global" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileGlobalCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *varTokenPtr;
- int localIndex, numWords, i;
-
- numWords = parsePtr->numWords;
- if (numWords < 2) {
- return TCL_ERROR;
- }
-
- /*
- * 'global' has no effect outside of proc bodies; handle that at runtime
- */
-
- if (envPtr->procPtr == NULL) {
- return TCL_ERROR;
- }
-
- /*
- * Push the namespace
- */
-
- PushLiteral(envPtr, "::", 2);
-
- /*
- * Loop over the variables.
- */
-
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
- for (i=2; i<=numWords; varTokenPtr = TokenAfter(varTokenPtr),i++) {
- localIndex = IndexTailVarIfKnown(interp, varTokenPtr, envPtr);
-
- if (localIndex < 0) {
- return TCL_ERROR;
- }
-
- CompileWord(envPtr, varTokenPtr, interp);
- TclEmitInstInt4( INST_NSUPVAR, localIndex, envPtr);
- }
-
- /*
- * Pop the namespace, and set the result to empty
- */
-
- TclEmitOpcode( INST_POP, envPtr);
- PushLiteral(envPtr, "", 0);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileIfCmd --
- *
- * Procedure called to compile the "if" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "if" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileIfCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- JumpFixupArray jumpFalseFixupArray;
- /* Used to fix the ifFalse jump after each
- * test when its target PC is determined. */
- JumpFixupArray jumpEndFixupArray;
- /* Used to fix the jump after each "then" body
- * to the end of the "if" when that PC is
- * determined. */
- Tcl_Token *tokenPtr, *testTokenPtr;
- int jumpIndex = 0; /* Avoid compiler warning. */
- int jumpFalseDist, numWords, wordIdx, numBytes, j, code;
- const char *word;
- int savedStackDepth = envPtr->currStackDepth;
- /* Saved stack depth at the start of the first
- * test; the envPtr current depth is restored
- * to this value at the start of each test. */
- int realCond = 1; /* Set to 0 for static conditions:
- * "if 0 {..}" */
- int boolVal; /* Value of static condition. */
- int compileScripts = 1;
-
- /*
- * Only compile the "if" command if all arguments are simple words, in
- * order to insure correct substitution [Bug 219166]
- */
-
- tokenPtr = parsePtr->tokenPtr;
- wordIdx = 0;
- numWords = parsePtr->numWords;
-
- for (wordIdx = 0; wordIdx < numWords; wordIdx++) {
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- tokenPtr = TokenAfter(tokenPtr);
- }
-
- TclInitJumpFixupArray(&jumpFalseFixupArray);
- TclInitJumpFixupArray(&jumpEndFixupArray);
- code = TCL_OK;
-
- /*
- * Each iteration of this loop compiles one "if expr ?then? body" or
- * "elseif expr ?then? body" clause.
- */
-
- tokenPtr = parsePtr->tokenPtr;
- wordIdx = 0;
- while (wordIdx < numWords) {
- /*
- * Stop looping if the token isn't "if" or "elseif".
- */
-
- word = tokenPtr[1].start;
- numBytes = tokenPtr[1].size;
- if ((tokenPtr == parsePtr->tokenPtr)
- || ((numBytes == 6) && (strncmp(word, "elseif", 6) == 0))) {
- tokenPtr = TokenAfter(tokenPtr);
- wordIdx++;
- } else {
- break;
- }
- if (wordIdx >= numWords) {
- code = TCL_ERROR;
- goto done;
- }
-
- /*
- * Compile the test expression then emit the conditional jump around
- * the "then" part.
- */
-
- envPtr->currStackDepth = savedStackDepth;
- testTokenPtr = tokenPtr;
-
- if (realCond) {
- /*
- * Find out if the condition is a constant.
- */
-
- Tcl_Obj *boolObj = Tcl_NewStringObj(testTokenPtr[1].start,
- testTokenPtr[1].size);
-
- Tcl_IncrRefCount(boolObj);
- code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal);
- TclDecrRefCount(boolObj);
- if (code == TCL_OK) {
- /*
- * A static condition.
- */
-
- realCond = 0;
- if (!boolVal) {
- compileScripts = 0;
- }
- } else {
- Tcl_ResetResult(interp);
- TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
- if (jumpFalseFixupArray.next >= jumpFalseFixupArray.end) {
- TclExpandJumpFixupArray(&jumpFalseFixupArray);
- }
- jumpIndex = jumpFalseFixupArray.next;
- jumpFalseFixupArray.next++;
- TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
- jumpFalseFixupArray.fixup+jumpIndex);
- }
- code = TCL_OK;
- }
-
- /*
- * Skip over the optional "then" before the then clause.
- */
-
- tokenPtr = TokenAfter(testTokenPtr);
- wordIdx++;
- if (wordIdx >= numWords) {
- code = TCL_ERROR;
- goto done;
- }
- if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
- word = tokenPtr[1].start;
- numBytes = tokenPtr[1].size;
- if ((numBytes == 4) && (strncmp(word, "then", 4) == 0)) {
- tokenPtr = TokenAfter(tokenPtr);
- wordIdx++;
- if (wordIdx >= numWords) {
- code = TCL_ERROR;
- goto done;
- }
- }
- }
-
- /*
- * Compile the "then" command body.
- */
-
- if (compileScripts) {
- envPtr->currStackDepth = savedStackDepth;
- CompileBody(envPtr, tokenPtr, interp);
- }
-
- if (realCond) {
- /*
- * Jump to the end of the "if" command. Both jumpFalseFixupArray
- * and jumpEndFixupArray are indexed by "jumpIndex".
- */
-
- if (jumpEndFixupArray.next >= jumpEndFixupArray.end) {
- TclExpandJumpFixupArray(&jumpEndFixupArray);
- }
- jumpEndFixupArray.next++;
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
- jumpEndFixupArray.fixup+jumpIndex);
-
- /*
- * Fix the target of the jumpFalse after the test. Generate a 4
- * byte jump if the distance is > 120 bytes. This is conservative,
- * and ensures that we won't have to replace this jump if we later
- * also need to replace the proceeding jump to the end of the "if"
- * with a 4 byte jump.
- */
-
- if (TclFixupForwardJumpToHere(envPtr,
- jumpFalseFixupArray.fixup+jumpIndex, 120)) {
- /*
- * Adjust the code offset for the proceeding jump to the end
- * of the "if" command.
- */
-
- jumpEndFixupArray.fixup[jumpIndex].codeOffset += 3;
- }
- } else if (boolVal) {
- /*
- * We were processing an "if 1 {...}"; stop compiling scripts.
- */
-
- compileScripts = 0;
- } else {
- /*
- * We were processing an "if 0 {...}"; reset so that the rest
- * (elseif, else) is compiled correctly.
- */
-
- realCond = 1;
- compileScripts = 1;
- }
-
- tokenPtr = TokenAfter(tokenPtr);
- wordIdx++;
- }
-
- /*
- * Restore the current stack depth in the environment; the "else" clause
- * (or its default) will add 1 to this.
- */
-
- envPtr->currStackDepth = savedStackDepth;
-
- /*
- * Check for the optional else clause. Do not compile anything if this was
- * an "if 1 {...}" case.
- */
-
- if ((wordIdx < numWords) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
- /*
- * There is an else clause. Skip over the optional "else" word.
- */
-
- word = tokenPtr[1].start;
- numBytes = tokenPtr[1].size;
- if ((numBytes == 4) && (strncmp(word, "else", 4) == 0)) {
- tokenPtr = TokenAfter(tokenPtr);
- wordIdx++;
- if (wordIdx >= numWords) {
- code = TCL_ERROR;
- goto done;
- }
- }
-
- if (compileScripts) {
- /*
- * Compile the else command body.
- */
-
- CompileBody(envPtr, tokenPtr, interp);
- }
-
- /*
- * Make sure there are no words after the else clause.
- */
-
- wordIdx++;
- if (wordIdx < numWords) {
- code = TCL_ERROR;
- goto done;
- }
- } else {
- /*
- * No else clause: the "if" command's result is an empty string.
- */
-
- if (compileScripts) {
- PushLiteral(envPtr, "", 0);
- }
- }
-
- /*
- * Fix the unconditional jumps to the end of the "if" command.
- */
-
- for (j = jumpEndFixupArray.next; j > 0; j--) {
- jumpIndex = (j - 1); /* i.e. process the closest jump first. */
- if (TclFixupForwardJumpToHere(envPtr,
- jumpEndFixupArray.fixup+jumpIndex, 127)) {
- /*
- * Adjust the immediately preceeding "ifFalse" jump. We moved it's
- * target (just after this jump) down three bytes.
- */
-
- unsigned char *ifFalsePc = envPtr->codeStart
- + jumpFalseFixupArray.fixup[jumpIndex].codeOffset;
- unsigned char opCode = *ifFalsePc;
-
- if (opCode == INST_JUMP_FALSE1) {
- jumpFalseDist = TclGetInt1AtPtr(ifFalsePc + 1);
- jumpFalseDist += 3;
- TclStoreInt1AtPtr(jumpFalseDist, (ifFalsePc + 1));
- } else if (opCode == INST_JUMP_FALSE4) {
- jumpFalseDist = TclGetInt4AtPtr(ifFalsePc + 1);
- jumpFalseDist += 3;
- TclStoreInt4AtPtr(jumpFalseDist, (ifFalsePc + 1));
- } else {
- Tcl_Panic("TclCompileIfCmd: unexpected opcode \"%d\" updating ifFalse jump", (int) opCode);
- }
- }
- }
-
- /*
- * Free the jumpFixupArray array if malloc'ed storage was used.
- */
-
- done:
- envPtr->currStackDepth = savedStackDepth + 1;
- TclFreeJumpFixupArray(&jumpFalseFixupArray);
- TclFreeJumpFixupArray(&jumpEndFixupArray);
- return code;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileIncrCmd --
- *
- * Procedure called to compile the "incr" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "incr" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileIncrCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *varTokenPtr, *incrTokenPtr;
- int simpleVarName, isScalar, localIndex, haveImmValue, immValue;
-
- if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) {
- return TCL_ERROR;
- }
-
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- PushVarName(interp, varTokenPtr, envPtr, TCL_NO_LARGE_INDEX,
- &localIndex, &simpleVarName, &isScalar);
-
- /*
- * If an increment is given, push it, but see first if it's a small
- * integer.
- */
-
- haveImmValue = 0;
- immValue = 1;
- if (parsePtr->numWords == 3) {
- incrTokenPtr = TokenAfter(varTokenPtr);
- if (incrTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
- const char *word = incrTokenPtr[1].start;
- int numBytes = incrTokenPtr[1].size;
- int code;
- Tcl_Obj *intObj = Tcl_NewStringObj(word, numBytes);
-
- Tcl_IncrRefCount(intObj);
- code = TclGetIntFromObj(NULL, intObj, &immValue);
- TclDecrRefCount(intObj);
- if ((code == TCL_OK) && (-127 <= immValue) && (immValue <= 127)) {
- haveImmValue = 1;
- }
- if (!haveImmValue) {
- PushLiteral(envPtr, word, numBytes);
- }
- } else {
- CompileTokens(envPtr, incrTokenPtr, interp);
- }
- } else { /* No incr amount given so use 1. */
- haveImmValue = 1;
- }
-
- /*
- * Emit the instruction to increment the variable.
- */
-
- if (!simpleVarName) {
- if (haveImmValue) {
- TclEmitInstInt1( INST_INCR_STK_IMM, immValue, envPtr);
- } else {
- TclEmitOpcode( INST_INCR_STK, envPtr);
- }
- } else if (isScalar) { /* Simple scalar variable. */
- if (localIndex >= 0) {
- if (haveImmValue) {
- TclEmitInstInt1(INST_INCR_SCALAR1_IMM, localIndex, envPtr);
- TclEmitInt1(immValue, envPtr);
- } else {
- TclEmitInstInt1(INST_INCR_SCALAR1, localIndex, envPtr);
- }
- } else {
- if (haveImmValue) {
- TclEmitInstInt1(INST_INCR_SCALAR_STK_IMM, immValue, envPtr);
- } else {
- TclEmitOpcode( INST_INCR_SCALAR_STK, envPtr);
- }
- }
- } else { /* Simple array variable. */
- if (localIndex >= 0) {
- if (haveImmValue) {
- TclEmitInstInt1(INST_INCR_ARRAY1_IMM, localIndex, envPtr);
- TclEmitInt1(immValue, envPtr);
- } else {
- TclEmitInstInt1(INST_INCR_ARRAY1, localIndex, envPtr);
- }
- } else {
- if (haveImmValue) {
- TclEmitInstInt1(INST_INCR_ARRAY_STK_IMM, immValue, envPtr);
- } else {
- TclEmitOpcode( INST_INCR_ARRAY_STK, envPtr);
- }
- }
- }
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileInfo*Cmd --
- *
- * Procedures called to compile "info" subcommands.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "info" subcommand at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileInfoCommandsCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr)
-{
- Tcl_Token *tokenPtr;
- Tcl_Obj *objPtr;
- char *bytes;
-
- /*
- * We require one compile-time known argument for the case we can compile.
- */
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- objPtr = Tcl_NewObj();
- Tcl_IncrRefCount(objPtr);
- if (!TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
- goto notCompilable;
- }
- bytes = Tcl_GetString(objPtr);
-
- /*
- * We require that the argument start with "::" and not have any of "*\[?"
- * in it. (Theoretically, we should look in only the final component, but
- * the difference is so slight given current naming practices.)
- */
-
- if (bytes[0] != ':' || bytes[1] != ':' || !TclMatchIsTrivial(bytes)) {
- goto notCompilable;
- }
- Tcl_DecrRefCount(objPtr);
-
- /*
- * Confirmed as a literal that will not frighten the horses. Compile. Note
- * that the result needs to be list-ified.
- */
-
- CompileWord(envPtr, tokenPtr, interp);
- TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr);
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitOpcode( INST_STR_LEN, envPtr);
- TclEmitInstInt1( INST_JUMP_FALSE1, 7, envPtr);
- TclEmitInstInt4( INST_LIST, 1, envPtr);
- return TCL_OK;
-
- notCompilable:
- Tcl_DecrRefCount(objPtr);
- return TCL_ERROR;
-}
-
-int
-TclCompileInfoCoroutineCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Only compile [info coroutine] without arguments.
- */
-
- if (parsePtr->numWords != 1) {
- return TCL_ERROR;
- }
-
- /*
- * Not much to do; we compile to a single instruction...
- */
-
- TclEmitOpcode( INST_COROUTINE_NAME, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileInfoExistsCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int isScalar, simpleVarName, localIndex;
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
-
- /*
- * Decide if we can use a frame slot for the var/array name or if we need
- * to emit code to compute and push the name at runtime. We use a frame
- * slot (entry in the array of local vars) if we are compiling a procedure
- * body and if the name is simple text that does not include namespace
- * qualifiers.
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- PushVarName(interp, tokenPtr, envPtr, 0, &localIndex,
- &simpleVarName, &isScalar);
-
- /*
- * Emit instruction to check the variable for existence.
- */
-
- if (!simpleVarName) {
- TclEmitOpcode( INST_EXIST_STK, envPtr);
- } else if (isScalar) {
- if (localIndex < 0) {
- TclEmitOpcode( INST_EXIST_STK, envPtr);
- } else {
- TclEmitInstInt4( INST_EXIST_SCALAR, localIndex, envPtr);
- }
- } else {
- if (localIndex < 0) {
- TclEmitOpcode( INST_EXIST_ARRAY_STK, envPtr);
- } else {
- TclEmitInstInt4( INST_EXIST_ARRAY, localIndex, envPtr);
- }
- }
-
- return TCL_OK;
-}
-
-int
-TclCompileInfoLevelCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Only compile [info level] without arguments or with a single argument.
- */
-
- if (parsePtr->numWords == 1) {
- /*
- * Not much to do; we compile to a single instruction...
- */
-
- TclEmitOpcode( INST_INFO_LEVEL_NUM, envPtr);
- } else if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- } else {
-
- /*
- * Compile the argument, then add the instruction to convert it into a
- * list of arguments.
- */
-
- CompileTokens(envPtr, TokenAfter(parsePtr->tokenPtr), interp);
- TclEmitOpcode( INST_INFO_LEVEL_ARGS, envPtr);
- }
- return TCL_OK;
-}
-
-int
-TclCompileInfoObjectClassCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr)
-{
- Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
- CompileWord(envPtr, tokenPtr, interp);
- TclEmitOpcode( INST_TCLOO_CLASS, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileInfoObjectIsACmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr)
-{
- Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- /*
- * We only handle [info object isa object <somevalue>]. The first three
- * words are compressed to a single token by the ensemble compilation
- * engine.
- */
-
- if (parsePtr->numWords != 3) {
- return TCL_ERROR;
- }
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size < 1
- || strncmp(tokenPtr[1].start, "object", tokenPtr[1].size)) {
- return TCL_ERROR;
- }
- tokenPtr = TokenAfter(tokenPtr);
-
- /*
- * Issue the code.
- */
-
- CompileWord(envPtr, tokenPtr, interp);
- TclEmitOpcode( INST_TCLOO_IS_OBJECT, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileInfoObjectNamespaceCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr)
-{
- Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
- CompileWord(envPtr, tokenPtr, interp);
- TclEmitOpcode( INST_TCLOO_NS, envPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileLappendCmd --
- *
- * Procedure called to compile the "lappend" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "lappend" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileLappendCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *varTokenPtr;
- int simpleVarName, isScalar, localIndex, numWords;
-
- /*
- * If we're not in a procedure, don't compile.
- */
-
- if (envPtr->procPtr == NULL) {
- return TCL_ERROR;
- }
-
- numWords = parsePtr->numWords;
- if (numWords == 1) {
- return TCL_ERROR;
- }
- if (numWords != 3) {
- /*
- * LAPPEND instructions currently only handle one value appends.
- */
-
- return TCL_ERROR;
- }
-
- /*
- * Decide if we can use a frame slot for the var/array name or if we
- * need to emit code to compute and push the name at runtime. We use a
- * frame slot (entry in the array of local vars) if we are compiling a
- * procedure body and if the name is simple text that does not include
- * namespace qualifiers.
- */
-
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- PushVarName(interp, varTokenPtr, envPtr, 0,
- &localIndex, &simpleVarName, &isScalar);
-
- /*
- * If we are doing an assignment, push the new value. In the no values
- * case, create an empty object.
- */
-
- if (numWords > 2) {
- Tcl_Token *valueTokenPtr = TokenAfter(varTokenPtr);
-
- CompileWord(envPtr, valueTokenPtr, interp);
- }
-
- /*
- * Emit instructions to set/get the variable.
- */
-
- /*
- * The *_STK opcodes should be refactored to make better use of existing
- * LOAD/STORE instructions.
- */
-
- if (!simpleVarName) {
- TclEmitOpcode( INST_LAPPEND_STK, envPtr);
- } else if (isScalar) {
- if (localIndex < 0) {
- TclEmitOpcode( INST_LAPPEND_STK, envPtr);
- } else {
- Emit14Inst( INST_LAPPEND_SCALAR, localIndex, envPtr);
- }
- } else {
- if (localIndex < 0) {
- TclEmitOpcode( INST_LAPPEND_ARRAY_STK, envPtr);
- } else {
- Emit14Inst( INST_LAPPEND_ARRAY, localIndex, envPtr);
- }
- }
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileLassignCmd --
- *
- * Procedure called to compile the "lassign" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "lassign" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileLassignCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int simpleVarName, isScalar, localIndex, numWords, idx;
-
- numWords = parsePtr->numWords;
-
- /*
- * Check for command syntax error, but we'll punt that to runtime.
- */
-
- if (numWords < 3) {
- return TCL_ERROR;
- }
-
- /*
- * Generate code to push list being taken apart by [lassign].
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- CompileWord(envPtr, tokenPtr, interp);
-
- /*
- * Generate code to assign values from the list to variables.
- */
-
- for (idx=0 ; idx<numWords-2 ; idx++) {
- tokenPtr = TokenAfter(tokenPtr);
-
- /*
- * Generate the next variable name.
- */
-
- PushVarName(interp, tokenPtr, envPtr, 0, &localIndex,
- &simpleVarName, &isScalar);
-
- /*
- * Emit instructions to get the idx'th item out of the list value on
- * the stack and assign it to the variable.
- */
-
- if (!simpleVarName) {
- TclEmitInstInt4( INST_OVER, 1, envPtr);
- TclEmitInstInt4( INST_LIST_INDEX_IMM, idx, envPtr);
- TclEmitOpcode( INST_STORE_STK, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- } else if (isScalar) {
- if (localIndex >= 0) {
- TclEmitOpcode( INST_DUP, envPtr);
- TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
- Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- } else {
- TclEmitInstInt4(INST_OVER, 1, envPtr);
- TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
- TclEmitOpcode( INST_STORE_SCALAR_STK, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- }
- } else {
- if (localIndex >= 0) {
- TclEmitInstInt4(INST_OVER, 1, envPtr);
- TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
- Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- } else {
- TclEmitInstInt4(INST_OVER, 2, envPtr);
- TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
- TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- }
- }
- }
-
- /*
- * Generate code to leave the rest of the list on the stack.
- */
-
- TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
- TclEmitInt4( -2 /* == "end" */, envPtr);
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileLindexCmd --
- *
- * Procedure called to compile the "lindex" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "lindex" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileLindexCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *idxTokenPtr, *valTokenPtr;
- int i, numWords = parsePtr->numWords;
-
- /*
- * Quit if too few args.
- */
-
- if (numWords <= 1) {
- return TCL_ERROR;
- }
-
- valTokenPtr = TokenAfter(parsePtr->tokenPtr);
- if (numWords != 3) {
- goto emitComplexLindex;
- }
-
- idxTokenPtr = TokenAfter(valTokenPtr);
- if (idxTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
- Tcl_Obj *tmpObj;
- int idx, result;
-
- tmpObj = Tcl_NewStringObj(idxTokenPtr[1].start, idxTokenPtr[1].size);
- result = TclGetIntFromObj(NULL, tmpObj, &idx);
- if (result == TCL_OK) {
- if (idx < 0) {
- result = TCL_ERROR;
- }
- } else {
- result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx);
- if (result == TCL_OK && idx > -2) {
- result = TCL_ERROR;
- }
- }
- TclDecrRefCount(tmpObj);
-
- if (result == TCL_OK) {
- /*
- * All checks have been completed, and we have exactly one of
- * these constructs:
- * lindex <arbitraryValue> <posInt>
- * lindex <arbitraryValue> end-<posInt>
- * This is best compiled as a push of the arbitrary value followed
- * by an "immediate lindex" which is the most efficient variety.
- */
-
- CompileWord(envPtr, valTokenPtr, interp);
- TclEmitInstInt4( INST_LIST_INDEX_IMM, idx, envPtr);
- return TCL_OK;
- }
-
- /*
- * If the conversion failed or the value was negative, we just keep on
- * going with the more complex compilation.
- */
- }
-
- /*
- * Push the operands onto the stack.
- */
-
- emitComplexLindex:
- for (i=1 ; i<numWords ; i++) {
- CompileWord(envPtr, valTokenPtr, interp);
- valTokenPtr = TokenAfter(valTokenPtr);
- }
-
- /*
- * Emit INST_LIST_INDEX if objc==3, or INST_LIST_INDEX_MULTI if there are
- * multiple index args.
- */
-
- if (numWords == 3) {
- TclEmitOpcode( INST_LIST_INDEX, envPtr);
- } else {
- TclEmitInstInt4( INST_LIST_INDEX_MULTI, numWords-1, envPtr);
- }
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileListCmd --
- *
- * Procedure called to compile the "list" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "list" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileListCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *valueTokenPtr;
- int i, numWords;
-
- /*
- * If we're not in a procedure, don't compile.
- */
-
- if (envPtr->procPtr == NULL) {
- return TCL_ERROR;
- }
-
- if (parsePtr->numWords == 1) {
- /*
- * [list] without arguments just pushes an empty object.
- */
-
- PushLiteral(envPtr, "", 0);
- } else {
- /*
- * Push the all values onto the stack.
- */
-
- numWords = parsePtr->numWords;
- valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
- for (i = 1; i < numWords; i++) {
- CompileWord(envPtr, valueTokenPtr, interp);
- valueTokenPtr = TokenAfter(valueTokenPtr);
- }
- TclEmitInstInt4( INST_LIST, numWords - 1, envPtr);
- }
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileLlengthCmd --
- *
- * Procedure called to compile the "llength" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "llength" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileLlengthCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *varTokenPtr;
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- CompileWord(envPtr, varTokenPtr, interp);
- TclEmitOpcode( INST_LIST_LENGTH, envPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileLrangeCmd --
- *
- * How to compile the "lrange" command. We only bother because we needed
- * the opcode anyway for "lassign".
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileLrangeCmd(
- Tcl_Interp *interp, /* Tcl interpreter for context. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the
- * command. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds the resulting instructions. */
-{
- Tcl_Token *tokenPtr, *listTokenPtr;
- Tcl_Obj *tmpObj;
- int idx1, idx2, result;
-
- if (parsePtr->numWords != 4) {
- return TCL_ERROR;
- }
- listTokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- /*
- * Parse the first index. Will only compile if it is constant and not an
- * _integer_ less than zero (since we reserve negative indices here for
- * end-relative indexing).
- */
-
- tokenPtr = TokenAfter(listTokenPtr);
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size);
- result = TclGetIntFromObj(NULL, tmpObj, &idx1);
- if (result == TCL_OK) {
- if (idx1 < 0) {
- result = TCL_ERROR;
- }
- } else {
- result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx1);
- if (result == TCL_OK && idx1 > -2) {
- result = TCL_ERROR;
- }
- }
- TclDecrRefCount(tmpObj);
- if (result != TCL_OK) {
- return TCL_ERROR;
- }
-
- /*
- * Parse the second index. Will only compile if it is constant and not an
- * _integer_ less than zero (since we reserve negative indices here for
- * end-relative indexing).
- */
-
- tokenPtr = TokenAfter(tokenPtr);
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size);
- result = TclGetIntFromObj(NULL, tmpObj, &idx2);
- if (result == TCL_OK) {
- if (idx2 < 0) {
- result = TCL_ERROR;
- }
- } else {
- result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx2);
- if (result == TCL_OK && idx2 > -2) {
- result = TCL_ERROR;
- }
- }
- TclDecrRefCount(tmpObj);
- if (result != TCL_OK) {
- return TCL_ERROR;
- }
-
- /*
- * Issue instructions. It's not safe to skip doing the LIST_RANGE, as
- * we've not proved that the 'list' argument is really a list. Not that it
- * is worth trying to do that given current knowledge.
- */
-
- CompileWord(envPtr, listTokenPtr, interp);
- TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
- TclEmitInt4( idx2, envPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileLreplaceCmd --
- *
- * How to compile the "lreplace" command. We only bother with the case
- * where there are no elements to insert and where both the 'first' and
- * 'last' arguments are constant and one can be deterined to be at the
- * end of the list. (This is the case that could also be written with
- * "lrange".)
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileLreplaceCmd(
- Tcl_Interp *interp, /* Tcl interpreter for context. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the
- * command. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds the resulting instructions. */
-{
- Tcl_Token *tokenPtr, *listTokenPtr;
- Tcl_Obj *tmpObj;
- int idx1, idx2, result, guaranteedDropAll = 0;
-
- if (parsePtr->numWords != 4) {
- return TCL_ERROR;
- }
- listTokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- /*
- * Parse the first index. Will only compile if it is constant and not an
- * _integer_ less than zero (since we reserve negative indices here for
- * end-relative indexing).
- */
-
- tokenPtr = TokenAfter(listTokenPtr);
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size);
- result = TclGetIntFromObj(NULL, tmpObj, &idx1);
- if (result == TCL_OK) {
- if (idx1 < 0) {
- result = TCL_ERROR;
- }
- } else {
- result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx1);
- if (result == TCL_OK && idx1 > -2) {
- result = TCL_ERROR;
- }
- }
- TclDecrRefCount(tmpObj);
- if (result != TCL_OK) {
- return TCL_ERROR;
- }
-
- /*
- * Parse the second index. Will only compile if it is constant and not an
- * _integer_ less than zero (since we reserve negative indices here for
- * end-relative indexing).
- */
-
- tokenPtr = TokenAfter(tokenPtr);
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size);
- result = TclGetIntFromObj(NULL, tmpObj, &idx2);
- if (result == TCL_OK) {
- if (idx2 < 0) {
- result = TCL_ERROR;
- }
- } else {
- result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx2);
- if (result == TCL_OK && idx2 > -2) {
- result = TCL_ERROR;
- }
- }
- TclDecrRefCount(tmpObj);
- if (result != TCL_OK) {
- return TCL_ERROR;
- }
-
- /*
- * Sanity check: can only issue when we're removing a range at one or
- * other end of the list. If we're at one end or the other, convert the
- * indices into the equivalent for an [lrange].
- */
-
- if (idx1 == 0) {
- if (idx2 == -2) {
- guaranteedDropAll = 1;
- }
- idx1 = idx2 + 1;
- idx2 = -2;
- } else if (idx2 == -2) {
- idx2 = idx1 - 1;
- idx1 = 0;
- } else {
- return TCL_ERROR;
- }
-
- /*
- * Issue instructions. It's not safe to skip doing the LIST_RANGE, as
- * we've not proved that the 'list' argument is really a list. Not that it
- * is worth trying to do that given current knowledge.
- */
-
- CompileWord(envPtr, listTokenPtr, interp);
- if (guaranteedDropAll) {
- TclEmitOpcode( INST_LIST_LENGTH, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- PushLiteral(envPtr, "", 0);
- } else {
- TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
- TclEmitInt4( idx2, envPtr);
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileLsetCmd --
- *
- * Procedure called to compile the "lset" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "lset" command at
- * runtime.
- *
- * The general template for execution of the "lset" command is:
- * (1) Instructions to push the variable name, unless the variable is
- * local to the stack frame.
- * (2) If the variable is an array element, instructions to push the
- * array element name.
- * (3) Instructions to push each of zero or more "index" arguments to the
- * stack, followed with the "newValue" element.
- * (4) Instructions to duplicate the variable name and/or array element
- * name onto the top of the stack, if either was pushed at steps (1)
- * and (2).
- * (5) The appropriate INST_LOAD_* instruction to place the original
- * value of the list variable at top of stack.
- * (6) At this point, the stack contains:
- * varName? arrayElementName? index1 index2 ... newValue oldList
- * The compiler emits one of INST_LSET_FLAT or INST_LSET_LIST
- * according as whether there is exactly one index element (LIST) or
- * either zero or else two or more (FLAT). This instruction removes
- * everything from the stack except for the two names and pushes the
- * new value of the variable.
- * (7) Finally, INST_STORE_* stores the new value in the variable and
- * cleans up the stack.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileLsetCmd(
- Tcl_Interp *interp, /* Tcl interpreter for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the
- * command. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds the resulting instructions. */
-{
- int tempDepth; /* Depth used for emitting one part of the
- * code burst. */
- Tcl_Token *varTokenPtr; /* Pointer to the Tcl_Token representing the
- * parse of the variable name. */
- int localIndex; /* Index of var in local var table. */
- int simpleVarName; /* Flag == 1 if var name is simple. */
- int isScalar; /* Flag == 1 if scalar, 0 if array. */
- int i;
-
- /*
- * Check argument count.
- */
-
- if (parsePtr->numWords < 3) {
- /*
- * Fail at run time, not in compilation.
- */
-
- return TCL_ERROR;
- }
-
- /*
- * Decide if we can use a frame slot for the var/array name or if we need
- * to emit code to compute and push the name at runtime. We use a frame
- * slot (entry in the array of local vars) if we are compiling a procedure
- * body and if the name is simple text that does not include namespace
- * qualifiers.
- */
-
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
- PushVarName(interp, varTokenPtr, envPtr, 0,
- &localIndex, &simpleVarName, &isScalar);
-
- /*
- * Push the "index" args and the new element value.
- */
-
- for (i=2 ; i<parsePtr->numWords ; ++i) {
- varTokenPtr = TokenAfter(varTokenPtr);
- CompileWord(envPtr, varTokenPtr, interp);
- }
-
- /*
- * Duplicate the variable name if it's been pushed.
- */
-
- if (!simpleVarName || localIndex < 0) {
- if (!simpleVarName || isScalar) {
- tempDepth = parsePtr->numWords - 2;
- } else {
- tempDepth = parsePtr->numWords - 1;
- }
- TclEmitInstInt4( INST_OVER, tempDepth, envPtr);
- }
-
- /*
- * Duplicate an array index if one's been pushed.
- */
-
- if (simpleVarName && !isScalar) {
- if (localIndex < 0) {
- tempDepth = parsePtr->numWords - 1;
- } else {
- tempDepth = parsePtr->numWords - 2;
- }
- TclEmitInstInt4( INST_OVER, tempDepth, envPtr);
- }
-
- /*
- * Emit code to load the variable's value.
- */
-
- if (!simpleVarName) {
- TclEmitOpcode( INST_LOAD_STK, envPtr);
- } else if (isScalar) {
- if (localIndex < 0) {
- TclEmitOpcode( INST_LOAD_SCALAR_STK, envPtr);
- } else {
- Emit14Inst( INST_LOAD_SCALAR, localIndex, envPtr);
- }
- } else {
- if (localIndex < 0) {
- TclEmitOpcode( INST_LOAD_ARRAY_STK, envPtr);
- } else {
- Emit14Inst( INST_LOAD_ARRAY, localIndex, envPtr);
- }
- }
-
- /*
- * Emit the correct variety of 'lset' instruction.
- */
-
- if (parsePtr->numWords == 4) {
- TclEmitOpcode( INST_LSET_LIST, envPtr);
- } else {
- TclEmitInstInt4( INST_LSET_FLAT, parsePtr->numWords-1, envPtr);
- }
-
- /*
- * Emit code to put the value back in the variable.
- */
-
- if (!simpleVarName) {
- TclEmitOpcode( INST_STORE_STK, envPtr);
- } else if (isScalar) {
- if (localIndex < 0) {
- TclEmitOpcode( INST_STORE_SCALAR_STK, envPtr);
- } else {
- Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
- }
- } else {
- if (localIndex < 0) {
- TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr);
- } else {
- Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr);
- }
- }
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileLmapCmd --
- *
- * Procedure called to compile the "lmap" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "lmap" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileLmapCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- return CompileEachloopCmd(interp, parsePtr, cmdPtr, envPtr,
- TCL_EACH_COLLECT);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileNamespace*Cmd --
- *
- * Procedures called to compile the "namespace" command; currently, only
- * the subcommands "namespace current" and "namespace upvar" are compiled
- * to bytecodes, and the latter only inside a procedure(-like) context.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "namespace upvar"
- * command at runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileNamespaceCurrentCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Only compile [namespace current] without arguments.
- */
-
- if (parsePtr->numWords != 1) {
- return TCL_ERROR;
- }
-
- /*
- * Not much to do; we compile to a single instruction...
- */
-
- TclEmitOpcode( INST_NS_CURRENT, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileNamespaceCodeCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- /*
- * The specification of [namespace code] is rather shocking, in that it is
- * supposed to check if the argument is itself the result of [namespace
- * code] and not apply itself in that case. Which is excessively cautious,
- * but what the test suite checks for.
- */
-
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || (tokenPtr[1].size > 20
- && strncmp(tokenPtr[1].start, "::namespace inscope ", 20) == 0)) {
- /*
- * Technically, we could just pass a literal '::namespace inscope '
- * term through, but that's something which really shouldn't be
- * occurring as something that the user writes so we'll just punt it.
- */
-
- return TCL_ERROR;
- }
-
- /*
- * Now we can compile using the same strategy as [namespace code]'s normal
- * implementation does internally. Note that we can't bind the namespace
- * name directly here, because TclOO plays complex games with namespaces;
- * the value needs to be determined at runtime for safety.
- */
-
- PushLiteral(envPtr, "::namespace", 11);
- PushLiteral(envPtr, "inscope", 7);
- TclEmitOpcode( INST_NS_CURRENT, envPtr);
- CompileWord(envPtr, tokenPtr, interp);
- TclEmitInstInt4( INST_LIST, 4, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileNamespaceQualifiersCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
- int off;
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
-
- CompileWord(envPtr, tokenPtr, interp);
- PushLiteral(envPtr, "0", 1);
- PushLiteral(envPtr, "::", 2);
- TclEmitInstInt4( INST_OVER, 2, envPtr);
- TclEmitOpcode( INST_STR_FIND_LAST, envPtr);
- off = CurrentOffset(envPtr);
- PushLiteral(envPtr, "1", 1);
- TclEmitOpcode( INST_SUB, envPtr);
- TclEmitInstInt4( INST_OVER, 2, envPtr);
- TclEmitInstInt4( INST_OVER, 1, envPtr);
- TclEmitOpcode( INST_STR_INDEX, envPtr);
- PushLiteral(envPtr, ":", 1);
- TclEmitOpcode( INST_STR_EQ, envPtr);
- off = off - CurrentOffset(envPtr);
- TclEmitInstInt1( INST_JUMP_TRUE1, off, envPtr);
- TclEmitOpcode( INST_STR_RANGE, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileNamespaceTailCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
- JumpFixup jumpFixup;
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
-
- /*
- * Take care; only add 2 to found index if the string was actually found.
- */
-
- CompileWord(envPtr, tokenPtr, interp);
- PushLiteral(envPtr, "::", 2);
- TclEmitInstInt4( INST_OVER, 1, envPtr);
- TclEmitOpcode( INST_STR_FIND_LAST, envPtr);
- TclEmitOpcode( INST_DUP, envPtr);
- PushLiteral(envPtr, "0", 1);
- TclEmitOpcode( INST_GE, envPtr);
- TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFixup);
- PushLiteral(envPtr, "2", 1);
- TclEmitOpcode( INST_ADD, envPtr);
- TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127);
- PushLiteral(envPtr, "end", 3);
- TclEmitOpcode( INST_STR_RANGE, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileNamespaceUpvarCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr;
- int simpleVarName, isScalar, localIndex, numWords, i;
-
- if (envPtr->procPtr == NULL) {
- return TCL_ERROR;
- }
-
- /*
- * Only compile [namespace upvar ...]: needs an even number of args, >=4
- */
-
- numWords = parsePtr->numWords;
- if ((numWords % 2) || (numWords < 4)) {
- return TCL_ERROR;
- }
-
- /*
- * Push the namespace
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- CompileWord(envPtr, tokenPtr, interp);
-
- /*
- * Loop over the (otherVar, thisVar) pairs. If any of the thisVar is not a
- * local variable, return an error so that the non-compiled command will
- * be called at runtime.
- */
-
- localTokenPtr = tokenPtr;
- for (i=3; i<=numWords; i+=2) {
- otherTokenPtr = TokenAfter(localTokenPtr);
- localTokenPtr = TokenAfter(otherTokenPtr);
-
- CompileWord(envPtr, otherTokenPtr, interp);
- PushVarName(interp, localTokenPtr, envPtr, 0,
- &localIndex, &simpleVarName, &isScalar);
-
- if ((localIndex < 0) || !isScalar) {
- return TCL_ERROR;
- }
- TclEmitInstInt4( INST_NSUPVAR, localIndex, envPtr);
- }
-
- /*
- * Pop the namespace, and set the result to empty
- */
-
- TclEmitOpcode( INST_POP, envPtr);
- PushLiteral(envPtr, "", 0);
- return TCL_OK;
-}
-
-int
-TclCompileNamespaceWhichCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr, *opt;
- int idx;
-
- if (parsePtr->numWords < 2 || parsePtr->numWords > 3) {
- return TCL_ERROR;
- }
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- idx = 1;
-
- /*
- * If there's an option, check that it's "-command". We don't handle
- * "-variable" (currently) and anything else is an error.
- */
-
- if (parsePtr->numWords == 3) {
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- opt = tokenPtr + 1;
- if (opt->size < 2 || opt->size > 8
- || strncmp(opt->start, "-command", opt->size) != 0) {
- return TCL_ERROR;
- }
- tokenPtr = TokenAfter(tokenPtr);
- idx++;
- }
-
- /*
- * Issue the bytecode.
- */
-
- CompileWord(envPtr, tokenPtr, interp);
- TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileRegexpCmd --
- *
- * Procedure called to compile the "regexp" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "regexp" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileRegexpCmd(
- Tcl_Interp *interp, /* Tcl interpreter for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the
- * command. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds the resulting instructions. */
-{
- Tcl_Token *varTokenPtr; /* Pointer to the Tcl_Token representing the
- * parse of the RE or string. */
- int i, len, nocase, exact, sawLast, simple;
- const char *str;
-
- /*
- * We are only interested in compiling simple regexp cases. Currently
- * supported compile cases are:
- * regexp ?-nocase? ?--? staticString $var
- * regexp ?-nocase? ?--? {^staticString$} $var
- */
-
- if (parsePtr->numWords < 3) {
- return TCL_ERROR;
- }
-
- simple = 0;
- nocase = 0;
- sawLast = 0;
- varTokenPtr = parsePtr->tokenPtr;
-
- /*
- * We only look for -nocase and -- as options. Everything else gets pushed
- * to runtime execution. This is different than regexp's runtime option
- * handling, but satisfies our stricter needs.
- */
-
- for (i = 1; i < parsePtr->numWords - 2; i++) {
- varTokenPtr = TokenAfter(varTokenPtr);
- if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- /*
- * Not a simple string, so punt to runtime.
- */
-
- return TCL_ERROR;
- }
- str = varTokenPtr[1].start;
- len = varTokenPtr[1].size;
- if ((len == 2) && (str[0] == '-') && (str[1] == '-')) {
- sawLast++;
- i++;
- break;
- } else if ((len > 1) && (strncmp(str,"-nocase",(unsigned)len) == 0)) {
- nocase = 1;
- } else {
- /*
- * Not an option we recognize.
- */
-
- return TCL_ERROR;
- }
- }
-
- if ((parsePtr->numWords - i) != 2) {
- /*
- * We don't support capturing to variables.
- */
-
- return TCL_ERROR;
- }
-
- /*
- * Get the regexp string. If it is not a simple string or can't be
- * converted to a glob pattern, push the word for the INST_REGEXP.
- * Keep changes here in sync with TclCompileSwitchCmd Switch_Regexp.
- */
-
- varTokenPtr = TokenAfter(varTokenPtr);
-
- if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
- Tcl_DString ds;
-
- str = varTokenPtr[1].start;
- len = varTokenPtr[1].size;
-
- /*
- * If it has a '-', it could be an incorrectly formed regexp command.
- */
-
- if ((*str == '-') && !sawLast) {
- return TCL_ERROR;
- }
-
- if (len == 0) {
- /*
- * The semantics of regexp are always match on re == "".
- */
-
- PushLiteral(envPtr, "1", 1);
- return TCL_OK;
- }
-
- /*
- * Attempt to convert pattern to glob. If successful, push the
- * converted pattern as a literal.
- */
-
- if (TclReToGlob(NULL, varTokenPtr[1].start, len, &ds, &exact)
- == TCL_OK) {
- simple = 1;
- PushLiteral(envPtr, Tcl_DStringValue(&ds),Tcl_DStringLength(&ds));
- Tcl_DStringFree(&ds);
- }
- }
-
- if (!simple) {
- CompileWord(envPtr, varTokenPtr, interp);
- }
-
- /*
- * Push the string arg.
- */
-
- varTokenPtr = TokenAfter(varTokenPtr);
- CompileWord(envPtr, varTokenPtr, interp);
-
- if (simple) {
- if (exact && !nocase) {
- TclEmitOpcode( INST_STR_EQ, envPtr);
- } else {
- TclEmitInstInt1( INST_STR_MATCH, nocase, envPtr);
- }
- } else {
- /*
- * Pass correct RE compile flags. We use only Int1 (8-bit), but
- * that handles all the flags we want to pass.
- * Don't use TCL_REG_NOSUB as we may have backrefs.
- */
-
- int cflags = TCL_REG_ADVANCED | (nocase ? TCL_REG_NOCASE : 0);
-
- TclEmitInstInt1( INST_REGEXP, cflags, envPtr);
- }
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileRegsubCmd --
- *
- * Procedure called to compile the "regsub" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "regsub" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileRegsubCmd(
- Tcl_Interp *interp, /* Tcl interpreter for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the
- * command. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds the resulting instructions. */
-{
- /*
- * We only compile the case with [regsub -all] where the pattern is both
- * known at compile time and simple (i.e., no RE metacharacters). That is,
- * the pattern must be translatable into a glob like "*foo*" with no other
- * glob metacharacters inside it; there must be some "foo" in there too.
- * The substitution string must also be known at compile time and free of
- * metacharacters ("\digit" and "&"). Finally, there must not be a
- * variable mentioned in the [regsub] to write the result back to (because
- * we can't get the count of substitutions that would be the result in
- * that case). The key is that these are the conditions under which a
- * [string map] could be used instead, in particular a [string map] of the
- * form we can compile to bytecode.
- *
- * In short, we look for:
- *
- * regsub -all [--] simpleRE string simpleReplacement
- *
- * The only optional part is the "--", and no other options are handled.
- */
-
- Tcl_Token *tokenPtr, *stringTokenPtr;
- Tcl_Obj *patternObj = NULL, *replacementObj = NULL;
- Tcl_DString pattern;
- const char *bytes;
- int len, exact, result = TCL_ERROR;
-
- if (parsePtr->numWords < 5 || parsePtr->numWords > 6) {
- return TCL_ERROR;
- }
-
- /*
- * Parse the "-all", which must be the first argument (other options not
- * supported, non-"-all" substitution we can't compile).
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size != 4
- || strncmp(tokenPtr[1].start, "-all", 4)) {
- return TCL_ERROR;
- }
-
- /*
- * Get the pattern into patternObj, checking for "--" in the process.
- */
-
- Tcl_DStringInit(&pattern);
- tokenPtr = TokenAfter(tokenPtr);
- patternObj = Tcl_NewObj();
- if (!TclWordKnownAtCompileTime(tokenPtr, patternObj)) {
- goto done;
- }
- if (Tcl_GetString(patternObj)[0] == '-') {
- if (strcmp(Tcl_GetString(patternObj), "--") != 0
- || parsePtr->numWords == 5) {
- goto done;
- }
- tokenPtr = TokenAfter(tokenPtr);
- Tcl_DecrRefCount(patternObj);
- patternObj = Tcl_NewObj();
- if (!TclWordKnownAtCompileTime(tokenPtr, patternObj)) {
- goto done;
- }
- } else if (parsePtr->numWords == 6) {
- goto done;
- }
-
- /*
- * Identify the code which produces the string to apply the substitution
- * to (stringTokenPtr), and the replacement string (into replacementObj).
- */
-
- stringTokenPtr = TokenAfter(tokenPtr);
- tokenPtr = TokenAfter(stringTokenPtr);
- replacementObj = Tcl_NewObj();
- if (!TclWordKnownAtCompileTime(tokenPtr, replacementObj)) {
- goto done;
- }
-
- /*
- * Next, higher-level checks. Is the RE a very simple glob? Is the
- * replacement "simple"?
- */
-
- bytes = Tcl_GetStringFromObj(patternObj, &len);
- if (TclReToGlob(NULL, bytes, len, &pattern, &exact) != TCL_OK || exact) {
- goto done;
- }
- bytes = Tcl_DStringValue(&pattern);
- if (*bytes++ != '*') {
- goto done;
- }
- while (1) {
- switch (*bytes) {
- case '*':
- if (bytes[1] == '\0') {
- /*
- * OK, we've proved there are no metacharacters except for the
- * '*' at each end.
- */
-
- len = Tcl_DStringLength(&pattern) - 2;
- if (len > 0) {
- goto isSimpleGlob;
- }
-
- /*
- * The pattern is "**"! I believe that should be impossible,
- * but we definitely can't handle that at all.
- */
- }
- case '\0': case '?': case '[': case '\\':
- goto done;
- }
- bytes++;
- }
- isSimpleGlob:
- for (bytes = Tcl_GetString(replacementObj); *bytes; bytes++) {
- switch (*bytes) {
- case '\\': case '&':
- goto done;
- }
- }
-
- /*
- * Proved the simplicity constraints! Time to issue the code.
- */
-
- result = TCL_OK;
- bytes = Tcl_DStringValue(&pattern) + 1;
- PushLiteral(envPtr, bytes, len);
- bytes = Tcl_GetStringFromObj(replacementObj, &len);
- PushLiteral(envPtr, bytes, len);
- CompileWord(envPtr, stringTokenPtr, interp);
- TclEmitOpcode( INST_STR_MAP, envPtr);
-
- done:
- Tcl_DStringFree(&pattern);
- if (patternObj) {
- Tcl_DecrRefCount(patternObj);
- }
- if (replacementObj) {
- Tcl_DecrRefCount(replacementObj);
- }
- return result;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileReturnCmd --
- *
- * Procedure called to compile the "return" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "return" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileReturnCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * General syntax: [return ?-option value ...? ?result?]
- * An even number of words means an explicit result argument is present.
- */
- int level, code, objc, size, status = TCL_OK;
- int numWords = parsePtr->numWords;
- int explicitResult = (0 == (numWords % 2));
- int numOptionWords = numWords - 1 - explicitResult;
- int savedStackDepth = envPtr->currStackDepth;
- Tcl_Obj *returnOpts, **objv;
- Tcl_Token *wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- /*
- * Check for special case which can always be compiled:
- * return -options <opts> <msg>
- * Unlike the normal [return] compilation, this version does everything at
- * runtime so it can handle arbitrary words and not just literals. Note
- * that if INST_RETURN_STK wasn't already needed for something else
- * ('finally' clause processing) this piece of code would not be present.
- */
-
- if ((numWords == 4) && (wordTokenPtr->type == TCL_TOKEN_SIMPLE_WORD)
- && (wordTokenPtr[1].size == 8)
- && (strncmp(wordTokenPtr[1].start, "-options", 8) == 0)) {
- Tcl_Token *optsTokenPtr = TokenAfter(wordTokenPtr);
- Tcl_Token *msgTokenPtr = TokenAfter(optsTokenPtr);
-
- CompileWord(envPtr, optsTokenPtr, interp);
- CompileWord(envPtr, msgTokenPtr, interp);
- TclEmitOpcode(INST_RETURN_STK, envPtr);
- envPtr->currStackDepth = savedStackDepth + 1;
- return TCL_OK;
- }
-
- /*
- * Allocate some working space.
- */
-
- objv = ckalloc(numOptionWords * sizeof(Tcl_Obj *));
-
- /*
- * Scan through the return options. If any are unknown at compile time,
- * there is no value in bytecompiling. Save the option values known in an
- * objv array for merging into a return options dictionary.
- */
-
- for (objc = 0; objc < numOptionWords; objc++) {
- objv[objc] = Tcl_NewObj();
- Tcl_IncrRefCount(objv[objc]);
- if (!TclWordKnownAtCompileTime(wordTokenPtr, objv[objc])) {
- objc++;
- status = TCL_ERROR;
- goto cleanup;
- }
- wordTokenPtr = TokenAfter(wordTokenPtr);
- }
- status = TclMergeReturnOptions(interp, objc, objv,
- &returnOpts, &code, &level);
- cleanup:
- while (--objc >= 0) {
- TclDecrRefCount(objv[objc]);
- }
- ckfree(objv);
- if (TCL_ERROR == status) {
- /*
- * Something was bogus in the return options. Clear the error message,
- * and report back to the compiler that this must be interpreted at
- * runtime.
- */
-
- Tcl_ResetResult(interp);
- return TCL_ERROR;
- }
-
- /*
- * All options are known at compile time, so we're going to bytecompile.
- * Emit instructions to push the result on the stack.
- */
-
- if (explicitResult) {
- CompileWord(envPtr, wordTokenPtr, interp);
- } else {
- /*
- * No explict result argument, so default result is empty string.
- */
-
- PushLiteral(envPtr, "", 0);
- }
-
- /*
- * Check for optimization: When [return] is in a proc, and there's no
- * enclosing [catch], and there are no return options, then the INST_DONE
- * instruction is equivalent, and may be more efficient.
- */
-
- if (numOptionWords == 0 && envPtr->procPtr != NULL) {
- /*
- * We have default return options and we're in a proc ...
- */
-
- int index = envPtr->exceptArrayNext - 1;
- int enclosingCatch = 0;
-
- while (index >= 0) {
- ExceptionRange range = envPtr->exceptArrayPtr[index];
-
- if ((range.type == CATCH_EXCEPTION_RANGE)
- && (range.catchOffset == -1)) {
- enclosingCatch = 1;
- break;
- }
- index--;
- }
- if (!enclosingCatch) {
- /*
- * ... and there is no enclosing catch. Issue the maximally
- * efficient exit instruction.
- */
-
- Tcl_DecrRefCount(returnOpts);
- TclEmitOpcode(INST_DONE, envPtr);
- return TCL_OK;
- }
- }
-
- /* Optimize [return -level 0 $x]. */
- Tcl_DictObjSize(NULL, returnOpts, &size);
- if (size == 0 && level == 0 && code == TCL_OK) {
- Tcl_DecrRefCount(returnOpts);
- return TCL_OK;
- }
-
- /*
- * Could not use the optimization, so we push the return options dict, and
- * emit the INST_RETURN_IMM instruction with code and level as operands.
- */
-
- CompileReturnInternal(envPtr, INST_RETURN_IMM, code, level, returnOpts);
- return TCL_OK;
-}
-
static void
CompileReturnInternal(
CompileEnv *envPtr,
@@ -5534,586 +79,10 @@ TclCompileSyntaxError(
CompileReturnInternal(envPtr, INST_SYNTAX, TCL_ERROR, 0,
Tcl_GetReturnOptions(interp, TCL_ERROR));
}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileUpvarCmd --
- *
- * Procedure called to compile the "upvar" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "upvar" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileUpvarCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr;
- int simpleVarName, isScalar, localIndex, numWords, i;
- Tcl_Obj *objPtr = Tcl_NewObj();
-
- if (envPtr->procPtr == NULL) {
- Tcl_DecrRefCount(objPtr);
- return TCL_ERROR;
- }
-
- numWords = parsePtr->numWords;
- if (numWords < 3) {
- Tcl_DecrRefCount(objPtr);
- return TCL_ERROR;
- }
-
- /*
- * Push the frame index if it is known at compile time
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- if (TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
- CallFrame *framePtr;
- const Tcl_ObjType *newTypePtr, *typePtr = objPtr->typePtr;
-
- /*
- * Attempt to convert to a level reference. Note that TclObjGetFrame
- * only changes the obj type when a conversion was successful.
- */
-
- TclObjGetFrame(interp, objPtr, &framePtr);
- newTypePtr = objPtr->typePtr;
- Tcl_DecrRefCount(objPtr);
-
- if (newTypePtr != typePtr) {
- if (numWords%2) {
- return TCL_ERROR;
- }
- CompileWord(envPtr, tokenPtr, interp);
- otherTokenPtr = TokenAfter(tokenPtr);
- i = 4;
- } else {
- if (!(numWords%2)) {
- return TCL_ERROR;
- }
- PushLiteral(envPtr, "1", 1);
- otherTokenPtr = tokenPtr;
- i = 3;
- }
- } else {
- Tcl_DecrRefCount(objPtr);
- return TCL_ERROR;
- }
-
- /*
- * Loop over the (otherVar, thisVar) pairs. If any of the thisVar is not a
- * local variable, return an error so that the non-compiled command will
- * be called at runtime.
- */
-
- for (; i<=numWords; i+=2, otherTokenPtr = TokenAfter(localTokenPtr)) {
- localTokenPtr = TokenAfter(otherTokenPtr);
-
- CompileWord(envPtr, otherTokenPtr, interp);
- PushVarName(interp, localTokenPtr, envPtr, 0,
- &localIndex, &simpleVarName, &isScalar);
-
- if ((localIndex < 0) || !isScalar) {
- return TCL_ERROR;
- }
- TclEmitInstInt4( INST_UPVAR, localIndex, envPtr);
- }
-
- /*
- * Pop the frame index, and set the result to empty
- */
-
- TclEmitOpcode( INST_POP, envPtr);
- PushLiteral(envPtr, "", 0);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileVariableCmd --
- *
- * Procedure called to compile the "variable" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "variable" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileVariableCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *varTokenPtr, *valueTokenPtr;
- int localIndex, numWords, i;
-
- numWords = parsePtr->numWords;
- if (numWords < 2) {
- return TCL_ERROR;
- }
-
- /*
- * Bail out if not compiling a proc body
- */
-
- if (envPtr->procPtr == NULL) {
- return TCL_ERROR;
- }
-
- /*
- * Loop over the (var, value) pairs.
- */
-
- valueTokenPtr = parsePtr->tokenPtr;
- for (i=1; i<numWords; i+=2) {
- varTokenPtr = TokenAfter(valueTokenPtr);
- valueTokenPtr = TokenAfter(varTokenPtr);
-
- localIndex = IndexTailVarIfKnown(interp, varTokenPtr, envPtr);
-
- if (localIndex < 0) {
- return TCL_ERROR;
- }
-
- CompileWord(envPtr, varTokenPtr, interp);
- TclEmitInstInt4( INST_VARIABLE, localIndex, envPtr);
-
- if (i+1 < numWords) {
- /*
- * A value has been given: set the variable, pop the value
- */
-
- CompileWord(envPtr, valueTokenPtr, interp);
- Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- }
- }
-
- /*
- * Set the result to empty
- */
-
- PushLiteral(envPtr, "", 0);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * IndexTailVarIfKnown --
- *
- * Procedure used in compiling [global] and [variable] commands. It
- * inspects the variable name described by varTokenPtr and, if the tail
- * is known at compile time, defines a corresponding local variable.
- *
- * Results:
- * Returns the variable's index in the table of compiled locals if the
- * tail is known at compile time, or -1 otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static int
-IndexTailVarIfKnown(
- Tcl_Interp *interp,
- Tcl_Token *varTokenPtr, /* Token representing the variable name */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Obj *tailPtr;
- const char *tailName, *p;
- int len, n = varTokenPtr->numComponents;
- Tcl_Token *lastTokenPtr;
- int full, localIndex;
-
- /*
- * Determine if the tail is (a) known at compile time, and (b) not an
- * array element. Should any of these fail, return an error so that the
- * non-compiled command will be called at runtime.
- *
- * In order for the tail to be known at compile time, the last token in
- * the word has to be constant and contain "::" if it is not the only one.
- */
-
- if (!EnvHasLVT(envPtr)) {
- return -1;
- }
- TclNewObj(tailPtr);
- if (TclWordKnownAtCompileTime(varTokenPtr, tailPtr)) {
- full = 1;
- lastTokenPtr = varTokenPtr;
- } else {
- full = 0;
- lastTokenPtr = varTokenPtr + n;
- if (!TclWordKnownAtCompileTime(lastTokenPtr, tailPtr)) {
- Tcl_DecrRefCount(tailPtr);
- return -1;
- }
- }
-
- tailName = TclGetStringFromObj(tailPtr, &len);
-
- if (len) {
- if (*(tailName+len-1) == ')') {
- /*
- * Possible array: bail out
- */
-
- Tcl_DecrRefCount(tailPtr);
- return -1;
- }
-
- /*
- * Get the tail: immediately after the last '::'
- */
-
- for (p = tailName + len -1; p > tailName; p--) {
- if ((*p == ':') && (*(p-1) == ':')) {
- p++;
- break;
- }
- }
- if (!full && (p == tailName)) {
- /*
- * No :: in the last component.
- */
-
- Tcl_DecrRefCount(tailPtr);
- return -1;
- }
- len -= p - tailName;
- tailName = p;
- }
-
- localIndex = TclFindCompiledLocal(tailName, len, 1, envPtr);
- Tcl_DecrRefCount(tailPtr);
- return localIndex;
-}
-int
-TclCompileObjectSelfCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * We only handle [self] and [self object] (which is the same operation).
- * These are the only very common operations on [self] for which
- * bytecoding is at all reasonable.
- */
-
- if (parsePtr->numWords == 1) {
- goto compileSelfObject;
- } else if (parsePtr->numWords == 2) {
- Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr), *subcmd;
-
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size==0) {
- return TCL_ERROR;
- }
-
- subcmd = tokenPtr + 1;
- if (strncmp(subcmd->start, "object", subcmd->size) == 0) {
- goto compileSelfObject;
- } else if (strncmp(subcmd->start, "namespace", subcmd->size) == 0) {
- goto compileSelfNamespace;
- }
- }
-
- /*
- * Can't compile; handle with runtime call.
- */
-
- return TCL_ERROR;
-
- compileSelfObject:
-
- /*
- * This delegates the entire problem to a single opcode.
- */
-
- TclEmitOpcode( INST_TCLOO_SELF, envPtr);
- return TCL_OK;
-
- compileSelfNamespace:
-
- /*
- * This is formally only correct with TclOO methods as they are currently
- * implemented; it assumes that the current namespace is invariably when a
- * TclOO context is present is the object's namespace, and that's
- * technically only something that's a matter of current policy. But it
- * avoids creating another opcode, so that's all good!
- */
- TclEmitOpcode( INST_TCLOO_SELF, envPtr);
- TclEmitOpcode( INST_POP, envPtr);
- TclEmitOpcode( INST_NS_CURRENT, envPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * PushVarName --
- *
- * Procedure used in the compiling where pushing a variable name is
- * necessary (append, lappend, set).
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "set" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-PushVarName(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Token *varTokenPtr, /* Points to a variable token. */
- CompileEnv *envPtr, /* Holds resulting instructions. */
- int flags, /* TCL_NO_LARGE_INDEX. */
- int *localIndexPtr, /* Must not be NULL. */
- int *simpleVarNamePtr, /* Must not be NULL. */
- int *isScalarPtr) /* Must not be NULL. */
-{
- register const char *p;
- const char *name, *elName;
- register int i, n;
- Tcl_Token *elemTokenPtr = NULL;
- int nameChars, elNameChars, simpleVarName, localIndex;
- int elemTokenCount = 0, allocedTokens = 0, removedParen = 0;
-
- /*
- * Decide if we can use a frame slot for the var/array name or if we need
- * to emit code to compute and push the name at runtime. We use a frame
- * slot (entry in the array of local vars) if we are compiling a procedure
- * body and if the name is simple text that does not include namespace
- * qualifiers.
- */
-
- simpleVarName = 0;
- name = elName = NULL;
- nameChars = elNameChars = 0;
- localIndex = -1;
-
- /*
- * Check not only that the type is TCL_TOKEN_SIMPLE_WORD, but whether
- * curly braces surround the variable name. This really matters for array
- * elements to handle things like
- * set {x($foo)} 5
- * which raises an undefined var error if we are not careful here.
- */
-
- if ((varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) &&
- (varTokenPtr->start[0] != '{')) {
- /*
- * A simple variable name. Divide it up into "name" and "elName"
- * strings. If it is not a local variable, look it up at runtime.
- */
-
- simpleVarName = 1;
-
- name = varTokenPtr[1].start;
- nameChars = varTokenPtr[1].size;
- if (name[nameChars-1] == ')') {
- /*
- * last char is ')' => potential array reference.
- */
-
- for (i=0,p=name ; i<nameChars ; i++,p++) {
- if (*p == '(') {
- elName = p + 1;
- elNameChars = nameChars - i - 2;
- nameChars = i;
- break;
- }
- }
-
- if ((elName != NULL) && elNameChars) {
- /*
- * An array element, the element name is a simple string:
- * assemble the corresponding token.
- */
-
- elemTokenPtr = ckalloc(sizeof(Tcl_Token));
- allocedTokens = 1;
- elemTokenPtr->type = TCL_TOKEN_TEXT;
- elemTokenPtr->start = elName;
- elemTokenPtr->size = elNameChars;
- elemTokenPtr->numComponents = 0;
- elemTokenCount = 1;
- }
- }
- } else if (((n = varTokenPtr->numComponents) > 1)
- && (varTokenPtr[1].type == TCL_TOKEN_TEXT)
- && (varTokenPtr[n].type == TCL_TOKEN_TEXT)
- && (varTokenPtr[n].start[varTokenPtr[n].size - 1] == ')')) {
- /*
- * Check for parentheses inside first token.
- */
-
- simpleVarName = 0;
- for (i = 0, p = varTokenPtr[1].start;
- i < varTokenPtr[1].size; i++, p++) {
- if (*p == '(') {
- simpleVarName = 1;
- break;
- }
- }
- if (simpleVarName) {
- int remainingChars;
-
- /*
- * Check the last token: if it is just ')', do not count it.
- * Otherwise, remove the ')' and flag so that it is restored at
- * the end.
- */
-
- if (varTokenPtr[n].size == 1) {
- n--;
- } else {
- varTokenPtr[n].size--;
- removedParen = n;
- }
-
- name = varTokenPtr[1].start;
- nameChars = p - varTokenPtr[1].start;
- elName = p + 1;
- remainingChars = (varTokenPtr[2].start - p) - 1;
- elNameChars = (varTokenPtr[n].start-p) + varTokenPtr[n].size - 2;
-
- if (remainingChars) {
- /*
- * Make a first token with the extra characters in the first
- * token.
- */
-
- elemTokenPtr = ckalloc(n * sizeof(Tcl_Token));
- allocedTokens = 1;
- elemTokenPtr->type = TCL_TOKEN_TEXT;
- elemTokenPtr->start = elName;
- elemTokenPtr->size = remainingChars;
- elemTokenPtr->numComponents = 0;
- elemTokenCount = n;
-
- /*
- * Copy the remaining tokens.
- */
-
- memcpy(elemTokenPtr+1, varTokenPtr+2,
- (n-1) * sizeof(Tcl_Token));
- } else {
- /*
- * Use the already available tokens.
- */
-
- elemTokenPtr = &varTokenPtr[2];
- elemTokenCount = n - 1;
- }
- }
- }
-
- if (simpleVarName) {
- /*
- * See whether name has any namespace separators (::'s).
- */
-
- int hasNsQualifiers = 0;
-
- for (i = 0, p = name; i < nameChars; i++, p++) {
- if ((*p == ':') && ((i+1) < nameChars) && (*(p+1) == ':')) {
- hasNsQualifiers = 1;
- break;
- }
- }
-
- /*
- * Look up the var name's index in the array of local vars in the proc
- * frame. If retrieving the var's value and it doesn't already exist,
- * push its name and look it up at runtime.
- */
-
- if (!hasNsQualifiers) {
- localIndex = TclFindCompiledLocal(name, nameChars,
- 1, envPtr);
- if ((flags & TCL_NO_LARGE_INDEX) && (localIndex > 255)) {
- /*
- * We'll push the name.
- */
-
- localIndex = -1;
- }
- }
- if (localIndex < 0) {
- PushLiteral(envPtr, name, nameChars);
- }
-
- /*
- * Compile the element script, if any.
- */
-
- if (elName != NULL) {
- if (elNameChars) {
- TclCompileTokens(interp, elemTokenPtr, elemTokenCount,
- envPtr);
- } else {
- PushLiteral(envPtr, "", 0);
- }
- }
- } else {
- /*
- * The var name isn't simple: compile and push it.
- */
- CompileTokens(envPtr, varTokenPtr, interp);
- }
-
- if (removedParen) {
- varTokenPtr[removedParen].size++;
- }
- if (allocedTokens) {
- ckfree(elemTokenPtr);
- }
- *localIndexPtr = localIndex;
- *simpleVarNamePtr = simpleVarName;
- *isScalarPtr = (elName == NULL);
- return TCL_OK;
-}
-
/*
* Local Variables:
* mode: c
diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c
index 3bfb75b..c27f644 100644
--- a/generic/tclCompCmdsSZ.c
+++ b/generic/tclCompCmdsSZ.c
@@ -16,21 +16,12 @@
*/
#include "tclInt.h"
-#include "tclCompile.h"
+#include "tclCompileInt.h"
/*
* Prototypes for procedures defined later in this file:
*/
-static ClientData DupJumptableInfo(ClientData clientData);
-static void FreeJumptableInfo(ClientData clientData);
-static void PrintJumptableInfo(ClientData clientData,
- Tcl_Obj *appendObj, ByteCode *codePtr,
- unsigned int pcOffset);
-static int PushVarName(Tcl_Interp *interp,
- Tcl_Token *varTokenPtr, CompileEnv *envPtr,
- int flags, int *localIndexPtr,
- int *simpleVarNamePtr, int *isScalarPtr);
static int CompileAssociativeBinaryOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, const char *identity,
int instruction, CompileEnv *envPtr);
@@ -43,25 +34,6 @@ static int CompileStrictlyBinaryOpCmd(Tcl_Interp *interp,
static int CompileUnaryOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, int instruction,
CompileEnv *envPtr);
-static void IssueSwitchChainedTests(Tcl_Interp *interp,
- CompileEnv *envPtr, int mode, int noCase,
- int valueIndex, Tcl_Token *valueTokenPtr,
- int numWords, Tcl_Token **bodyToken);
-static void IssueSwitchJumpTable(Tcl_Interp *interp,
- CompileEnv *envPtr, int valueIndex,
- Tcl_Token *valueTokenPtr, int numWords,
- Tcl_Token **bodyToken);
-static int IssueTryFinallyInstructions(Tcl_Interp *interp,
- CompileEnv *envPtr, Tcl_Token *bodyToken,
- int numHandlers, int *matchCodes,
- Tcl_Obj **matchClauses, int *resultVarIndices,
- int *optionVarIndices, Tcl_Token **handlerTokens,
- Tcl_Token *finallyToken);
-static int IssueTryInstructions(Tcl_Interp *interp,
- CompileEnv *envPtr, Tcl_Token *bodyToken,
- int numHandlers, int *matchCodes,
- Tcl_Obj **matchClauses, int *resultVarIndices,
- int *optionVarIndices, Tcl_Token **handlerTokens);
/*
* Macro that encapsulates an efficiency trick that avoids a function call for
@@ -87,17 +59,6 @@ static int IssueTryInstructions(Tcl_Interp *interp,
#define TCL_NO_LARGE_INDEX 1 /* Do not return localIndex value > 255 */
/*
- * The structures below define the AuxData types defined in this file.
- */
-
-const AuxDataType tclJumptableInfoType = {
- "JumptableInfo", /* name */
- DupJumptableInfo, /* dupProc */
- FreeJumptableInfo, /* freeProc */
- PrintJumptableInfo /* printProc */
-};
-
-/*
* Shorthand macros for instruction issuing.
*/
@@ -117,3025 +78,9 @@ const AuxDataType tclJumptableInfoType = {
#define FIXJUMP(var) \
TclStoreInt4AtPtr(CurrentOffset(envPtr)-(var),envPtr->codeStart+(var)+1)
#define LOAD(idx) \
- if ((idx)<256) {OP1(LOAD_SCALAR1,(idx));} else {OP4(LOAD_SCALAR4,(idx));}
+ OP4(LOAD_SCALAR4,(idx))
#define STORE(idx) \
- if ((idx)<256) {OP1(STORE_SCALAR1,(idx));} else {OP4(STORE_SCALAR4,(idx));}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileSetCmd --
- *
- * Procedure called to compile the "set" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "set" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileSetCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *varTokenPtr, *valueTokenPtr;
- int isAssignment, isScalar, simpleVarName, localIndex, numWords;
-
- numWords = parsePtr->numWords;
- if ((numWords != 2) && (numWords != 3)) {
- return TCL_ERROR;
- }
- isAssignment = (numWords == 3);
-
- /*
- * Decide if we can use a frame slot for the var/array name or if we need
- * to emit code to compute and push the name at runtime. We use a frame
- * slot (entry in the array of local vars) if we are compiling a procedure
- * body and if the name is simple text that does not include namespace
- * qualifiers.
- */
-
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
- PushVarName(interp, varTokenPtr, envPtr, 0,
- &localIndex, &simpleVarName, &isScalar);
-
- /*
- * If we are doing an assignment, push the new value.
- */
-
- if (isAssignment) {
- valueTokenPtr = TokenAfter(varTokenPtr);
- CompileWord(envPtr, valueTokenPtr, interp, 2);
- }
-
- /*
- * Emit instructions to set/get the variable.
- */
-
- if (simpleVarName) {
- if (isScalar) {
- if (localIndex < 0) {
- TclEmitOpcode((isAssignment?
- INST_STORE_SCALAR_STK : INST_LOAD_SCALAR_STK),
- envPtr);
- } else if (localIndex <= 255) {
- TclEmitInstInt1((isAssignment?
- INST_STORE_SCALAR1 : INST_LOAD_SCALAR1),
- localIndex, envPtr);
- } else {
- TclEmitInstInt4((isAssignment?
- INST_STORE_SCALAR4 : INST_LOAD_SCALAR4),
- localIndex, envPtr);
- }
- } else {
- if (localIndex < 0) {
- TclEmitOpcode((isAssignment?
- INST_STORE_ARRAY_STK : INST_LOAD_ARRAY_STK), envPtr);
- } else if (localIndex <= 255) {
- TclEmitInstInt1((isAssignment?
- INST_STORE_ARRAY1 : INST_LOAD_ARRAY1),
- localIndex, envPtr);
- } else {
- TclEmitInstInt4((isAssignment?
- INST_STORE_ARRAY4 : INST_LOAD_ARRAY4),
- localIndex, envPtr);
- }
- }
- } else {
- TclEmitOpcode((isAssignment? INST_STORE_STK : INST_LOAD_STK), envPtr);
- }
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileString*Cmd --
- *
- * Procedures called to compile various subcommands of the "string"
- * command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "string" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileStringCmpCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
-
- /*
- * We don't support any flags; the bytecode isn't that sophisticated.
- */
-
- if (parsePtr->numWords != 3) {
- return TCL_ERROR;
- }
-
- /*
- * Push the two operands onto the stack and then the test.
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 1);
- tokenPtr = TokenAfter(tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 2);
- TclEmitOpcode(INST_STR_CMP, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileStringEqualCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
-
- /*
- * We don't support any flags; the bytecode isn't that sophisticated.
- */
-
- if (parsePtr->numWords != 3) {
- return TCL_ERROR;
- }
-
- /*
- * Push the two operands onto the stack and then the test.
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 1);
- tokenPtr = TokenAfter(tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 2);
- TclEmitOpcode(INST_STR_EQ, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileStringFirstCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
-
- /*
- * We don't support any flags; the bytecode isn't that sophisticated.
- */
-
- if (parsePtr->numWords != 3) {
- return TCL_ERROR;
- }
-
- /*
- * Push the two operands onto the stack and then the test.
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 1);
- tokenPtr = TokenAfter(tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 2);
- OP(STR_FIND);
- return TCL_OK;
-}
-
-int
-TclCompileStringLastCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
-
- /*
- * We don't support any flags; the bytecode isn't that sophisticated.
- */
-
- if (parsePtr->numWords != 3) {
- return TCL_ERROR;
- }
-
- /*
- * Push the two operands onto the stack and then the test.
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 1);
- tokenPtr = TokenAfter(tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 2);
- OP(STR_FIND_LAST);
- return TCL_OK;
-}
-
-int
-TclCompileStringIndexCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
-
- if (parsePtr->numWords != 3) {
- return TCL_ERROR;
- }
-
- /*
- * Push the two operands onto the stack and then the index operation.
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 1);
- tokenPtr = TokenAfter(tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 2);
- TclEmitOpcode(INST_STR_INDEX, envPtr);
- return TCL_OK;
-}
-
-int
-TclCompileStringMatchCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int i, length, exactMatch = 0, nocase = 0;
- const char *str;
-
- if (parsePtr->numWords < 3 || parsePtr->numWords > 4) {
- return TCL_ERROR;
- }
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- /*
- * Check if we have a -nocase flag.
- */
-
- if (parsePtr->numWords == 4) {
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- str = tokenPtr[1].start;
- length = tokenPtr[1].size;
- if ((length <= 1) || strncmp(str, "-nocase", (size_t) length)) {
- /*
- * Fail at run time, not in compilation.
- */
-
- return TCL_ERROR;
- }
- nocase = 1;
- tokenPtr = TokenAfter(tokenPtr);
- }
-
- /*
- * Push the strings to match against each other.
- */
-
- for (i = 0; i < 2; i++) {
- if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
- str = tokenPtr[1].start;
- length = tokenPtr[1].size;
- if (!nocase && (i == 0)) {
- /*
- * Trivial matches can be done by 'string equal'. If -nocase
- * was specified, we can't do this because INST_STR_EQ has no
- * support for nocase.
- */
-
- Tcl_Obj *copy = Tcl_NewStringObj(str, length);
-
- Tcl_IncrRefCount(copy);
- exactMatch = TclMatchIsTrivial(TclGetString(copy));
- TclDecrRefCount(copy);
- }
- PushLiteral(envPtr, str, length);
- } else {
- CompileTokens(envPtr, tokenPtr, interp);
- }
- tokenPtr = TokenAfter(tokenPtr);
- }
-
- /*
- * Push the matcher.
- */
-
- if (exactMatch) {
- TclEmitOpcode(INST_STR_EQ, envPtr);
- } else {
- TclEmitInstInt1(INST_STR_MATCH, nocase, envPtr);
- }
- return TCL_OK;
-}
-
-int
-TclCompileStringLenCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- Tcl_Obj *objPtr;
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- TclNewObj(objPtr);
- if (TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
- /*
- * Here someone is asking for the length of a static string (or
- * something with backslashes). Just push the actual character (not
- * byte) length.
- */
-
- char buf[TCL_INTEGER_SPACE];
- int len = Tcl_GetCharLength(objPtr);
-
- len = sprintf(buf, "%d", len);
- PushLiteral(envPtr, buf, len);
- } else {
- CompileTokens(envPtr, tokenPtr, interp);
- TclEmitOpcode(INST_STR_LEN, envPtr);
- }
- TclDecrRefCount(objPtr);
- return TCL_OK;
-}
-
-int
-TclCompileStringMapCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *mapTokenPtr, *stringTokenPtr;
- Tcl_Obj *mapObj, **objv;
- char *bytes;
- int len;
-
- /*
- * We only handle the case:
- *
- * string map {foo bar} $thing
- *
- * That is, a literal two-element list (doesn't need to be brace-quoted,
- * but does need to be compile-time knowable) and any old argument (the
- * thing to map).
- */
-
- if (parsePtr->numWords != 3) {
- return TCL_ERROR;
- }
- mapTokenPtr = TokenAfter(parsePtr->tokenPtr);
- stringTokenPtr = TokenAfter(mapTokenPtr);
- mapObj = Tcl_NewObj();
- Tcl_IncrRefCount(mapObj);
- if (!TclWordKnownAtCompileTime(mapTokenPtr, mapObj)) {
- Tcl_DecrRefCount(mapObj);
- return TCL_ERROR;
- } else if (Tcl_ListObjGetElements(NULL, mapObj, &len, &objv) != TCL_OK) {
- Tcl_DecrRefCount(mapObj);
- return TCL_ERROR;
- } else if (len != 2) {
- Tcl_DecrRefCount(mapObj);
- return TCL_ERROR;
- }
-
- /*
- * Now issue the opcodes. Note that in the case that we know that the
- * first word is an empty word, we don't issue the map at all. That is the
- * correct semantics for mapping.
- */
-
- bytes = Tcl_GetStringFromObj(objv[0], &len);
- if (len == 0) {
- CompileWord(envPtr, stringTokenPtr, interp, 2);
- } else {
- PushLiteral(envPtr, bytes, len);
- bytes = Tcl_GetStringFromObj(objv[1], &len);
- PushLiteral(envPtr, bytes, len);
- CompileWord(envPtr, stringTokenPtr, interp, 2);
- OP(STR_MAP);
- }
- Tcl_DecrRefCount(mapObj);
- return TCL_OK;
-}
-
-int
-TclCompileStringRangeCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *stringTokenPtr, *fromTokenPtr, *toTokenPtr;
- Tcl_Obj *tmpObj;
- int idx1, idx2, result;
-
- if (parsePtr->numWords != 4) {
- return TCL_ERROR;
- }
- stringTokenPtr = TokenAfter(parsePtr->tokenPtr);
- fromTokenPtr = TokenAfter(stringTokenPtr);
- toTokenPtr = TokenAfter(fromTokenPtr);
-
- /*
- * Parse the first index. Will only compile if it is constant and not an
- * _integer_ less than zero (since we reserve negative indices here for
- * end-relative indexing).
- */
-
- tmpObj = Tcl_NewObj();
- result = TCL_ERROR;
- if (TclWordKnownAtCompileTime(fromTokenPtr, tmpObj)) {
- if (TclGetIntFromObj(NULL, tmpObj, &idx1) == TCL_OK) {
- if (idx1 >= 0) {
- result = TCL_OK;
- }
- } else if (TclGetIntForIndexM(NULL, tmpObj, -2, &idx1) == TCL_OK) {
- if (idx1 <= -2) {
- result = TCL_OK;
- }
- }
- }
- TclDecrRefCount(tmpObj);
- if (result != TCL_OK) {
- goto nonConstantIndices;
- }
-
- /*
- * Parse the second index. Will only compile if it is constant and not an
- * _integer_ less than zero (since we reserve negative indices here for
- * end-relative indexing).
- */
-
- tmpObj = Tcl_NewObj();
- result = TCL_ERROR;
- if (TclWordKnownAtCompileTime(toTokenPtr, tmpObj)) {
- if (TclGetIntFromObj(NULL, tmpObj, &idx2) == TCL_OK) {
- if (idx2 >= 0) {
- result = TCL_OK;
- }
- } else if (TclGetIntForIndexM(NULL, tmpObj, -2, &idx2) == TCL_OK) {
- if (idx2 <= -2) {
- result = TCL_OK;
- }
- }
- }
- TclDecrRefCount(tmpObj);
- if (result != TCL_OK) {
- goto nonConstantIndices;
- }
-
- /*
- * Push the operand onto the stack and then the substring operation.
- */
-
- CompileWord(envPtr, stringTokenPtr, interp, 1);
- OP44( STR_RANGE_IMM, idx1, idx2);
- return TCL_OK;
-
- /*
- * Push the operands onto the stack and then the substring operation.
- */
-
- nonConstantIndices:
- CompileWord(envPtr, stringTokenPtr, interp, 1);
- CompileWord(envPtr, fromTokenPtr, interp, 2);
- CompileWord(envPtr, toTokenPtr, interp, 3);
- OP( STR_RANGE);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileSubstCmd --
- *
- * Procedure called to compile the "subst" command.
- *
- * Results:
- * Returns TCL_OK for successful compile, or TCL_ERROR to defer
- * evaluation to runtime (either when it is too complex to get the
- * semantics right, or when we know for sure that it is an error but need
- * the error to happen at the right time).
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "subst" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileSubstCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- int numArgs = parsePtr->numWords - 1;
- int numOpts = numArgs - 1;
- int objc, flags = TCL_SUBST_ALL;
- Tcl_Obj **objv/*, *toSubst = NULL*/;
- Tcl_Token *wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
- int code = TCL_ERROR;
-
- if (numArgs == 0) {
- return TCL_ERROR;
- }
-
- objv = ckalloc(/*numArgs*/ numOpts * sizeof(Tcl_Obj *));
-
- for (objc = 0; objc < /*numArgs*/ numOpts; objc++) {
- objv[objc] = Tcl_NewObj();
- Tcl_IncrRefCount(objv[objc]);
- if (!TclWordKnownAtCompileTime(wordTokenPtr, objv[objc])) {
- objc++;
- goto cleanup;
- }
- wordTokenPtr = TokenAfter(wordTokenPtr);
- }
-
-/*
- if (TclSubstOptions(NULL, numOpts, objv, &flags) == TCL_OK) {
- toSubst = objv[numOpts];
- Tcl_IncrRefCount(toSubst);
- }
-*/
-
- /* TODO: Figure out expansion to cover WordKnownAtCompileTime
- * The difficulty is that WKACT makes a copy, and if TclSubstParse
- * below parses the copy of the original source string, some deep
- * parts of the compile machinery get upset. They want all pointers
- * stored in Tcl_Tokens to point back to the same original string.
- */
- if (wordTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
- code = TclSubstOptions(NULL, numOpts, objv, &flags);
- }
-
- cleanup:
- while (--objc >= 0) {
- TclDecrRefCount(objv[objc]);
- }
- ckfree(objv);
- if (/*toSubst == NULL*/ code != TCL_OK) {
- return TCL_ERROR;
- }
-
- TclSubstCompile(interp, wordTokenPtr[1].start, wordTokenPtr[1].size,
- flags, envPtr);
-
-/* TclDecrRefCount(toSubst);*/
- return TCL_OK;
-}
-
-void
-TclSubstCompile(
- Tcl_Interp *interp,
- const char *bytes,
- int numBytes,
- int flags,
- CompileEnv *envPtr)
-{
- Tcl_Token *endTokenPtr, *tokenPtr;
- int breakOffset = 0, count = 0;
- Tcl_Parse parse;
- Tcl_InterpState state = NULL;
-
- TclSubstParse(interp, bytes, numBytes, flags, &parse, &state);
-
- /*
- * Tricky point! If the first token does not result in a *guaranteed* push
- * of a Tcl_Obj on the stack, we must push an empty object. Otherwise it
- * is possible to get to an INST_CONCAT1 or INST_DONE without enough
- * values on the stack, resulting in a crash. Thanks to Joe Mistachkin for
- * identifying a script that could trigger this case.
- */
-
- tokenPtr = parse.tokenPtr;
- if (tokenPtr->type != TCL_TOKEN_TEXT && tokenPtr->type != TCL_TOKEN_BS) {
- PushLiteral(envPtr, "", 0);
- count++;
- }
-
- for (endTokenPtr = tokenPtr + parse.numTokens;
- tokenPtr < endTokenPtr; tokenPtr = TokenAfter(tokenPtr)) {
- int length, literal, catchRange, breakJump;
- char buf[TCL_UTF_MAX];
- JumpFixup startFixup, okFixup, returnFixup, breakFixup;
- JumpFixup continueFixup, otherFixup, endFixup;
-
- switch (tokenPtr->type) {
- case TCL_TOKEN_TEXT:
- literal = TclRegisterNewLiteral(envPtr,
- tokenPtr->start, tokenPtr->size);
- TclEmitPush(literal, envPtr);
- count++;
- continue;
- case TCL_TOKEN_BS:
- length = TclParseBackslash(tokenPtr->start, tokenPtr->size,
- NULL, buf);
- literal = TclRegisterNewLiteral(envPtr, buf, length);
- TclEmitPush(literal, envPtr);
- count++;
- continue;
- case TCL_TOKEN_VARIABLE:
- /*
- * Check for simple variable access; see if we can only generate
- * TCL_OK or TCL_ERROR from the substituted variable read; if so,
- * there is no need to generate elaborate exception-management
- * code. Note that the first component of TCL_TOKEN_VARIABLE is
- * always TCL_TOKEN_TEXT...
- */
-
- if (tokenPtr->numComponents > 1) {
- int i, foundCommand = 0;
-
- for (i=2 ; i<=tokenPtr->numComponents ; i++) {
- if (tokenPtr[i].type == TCL_TOKEN_COMMAND) {
- foundCommand = 1;
- break;
- }
- }
- if (foundCommand) {
- break;
- }
- }
-
- TclCompileVarSubst(interp, tokenPtr, envPtr);
- count++;
- continue;
- }
-
- while (count > 255) {
- OP1( CONCAT1, 255);
- count -= 254;
- }
- if (count > 1) {
- OP1( CONCAT1, count);
- count = 1;
- }
-
- if (breakOffset == 0) {
- /* Jump to the start (jump over the jump to end) */
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &startFixup);
-
- /* Jump to the end (all BREAKs land here) */
- breakOffset = CurrentOffset(envPtr);
- TclEmitInstInt4(INST_JUMP4, 0, envPtr);
-
- /* Start */
- if (TclFixupForwardJumpToHere(envPtr, &startFixup, 127)) {
- Tcl_Panic("TclCompileSubstCmd: bad start jump distance %d",
- (int) (CurrentOffset(envPtr) - startFixup.codeOffset));
- }
- }
-
- catchRange = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
- OP4( BEGIN_CATCH4, catchRange);
- ExceptionRangeStarts(envPtr, catchRange);
-
- switch (tokenPtr->type) {
- case TCL_TOKEN_COMMAND:
- TclCompileScript(interp, tokenPtr->start+1, tokenPtr->size-2,
- envPtr);
- count++;
- break;
- case TCL_TOKEN_VARIABLE:
- TclCompileVarSubst(interp, tokenPtr, envPtr);
- count++;
- break;
- default:
- Tcl_Panic("unexpected token type in TclCompileSubstCmd: %d",
- tokenPtr->type);
- }
-
- ExceptionRangeEnds(envPtr, catchRange);
-
- /* Substitution produced TCL_OK */
- OP( END_CATCH);
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &okFixup);
-
- /* Exceptional return codes processed here */
- ExceptionRangeTarget(envPtr, catchRange, catchOffset);
- OP( PUSH_RETURN_OPTIONS);
- OP( PUSH_RESULT);
- OP( PUSH_RETURN_CODE);
- OP( END_CATCH);
- OP( RETURN_CODE_BRANCH);
-
- /* ERROR -> reraise it */
- OP( RETURN_STK);
- OP( NOP);
-
- /* RETURN */
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &returnFixup);
-
- /* BREAK */
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &breakFixup);
-
- /* CONTINUE */
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &continueFixup);
-
- /* OTHER */
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &otherFixup);
-
- /* BREAK destination */
- if (TclFixupForwardJumpToHere(envPtr, &breakFixup, 127)) {
- Tcl_Panic("TclCompileSubstCmd: bad break jump distance %d",
- (int) (CurrentOffset(envPtr) - breakFixup.codeOffset));
- }
- OP( POP);
- OP( POP);
-
- breakJump = CurrentOffset(envPtr) - breakOffset;
- if (breakJump > 127) {
- OP4(JUMP4, -breakJump);
- } else {
- OP1(JUMP1, -breakJump);
- }
-
- /* CONTINUE destination */
- if (TclFixupForwardJumpToHere(envPtr, &continueFixup, 127)) {
- Tcl_Panic("TclCompileSubstCmd: bad continue jump distance %d",
- (int) (CurrentOffset(envPtr) - continueFixup.codeOffset));
- }
- OP( POP);
- OP( POP);
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &endFixup);
-
- /* RETURN + other destination */
- if (TclFixupForwardJumpToHere(envPtr, &returnFixup, 127)) {
- Tcl_Panic("TclCompileSubstCmd: bad return jump distance %d",
- (int) (CurrentOffset(envPtr) - returnFixup.codeOffset));
- }
- if (TclFixupForwardJumpToHere(envPtr, &otherFixup, 127)) {
- Tcl_Panic("TclCompileSubstCmd: bad other jump distance %d",
- (int) (CurrentOffset(envPtr) - otherFixup.codeOffset));
- }
-
- /*
- * Pull the result to top of stack, discard options dict.
- */
-
- OP4( REVERSE, 2);
- OP( POP);
-
- /*
- * We've emitted several POP instructions, and the automatic
- * computations for stack depth requirements have been decrementing
- * for every one. However, we know that every branch actually taken
- * only encounters some of those instructions. No branch passes
- * through them all. So, we now have a stack requirements estimate
- * that is too low. Here we manually fix that up.
- */
-
- TclAdjustStackDepth(5, envPtr);
-
- /* OK destination */
- if (TclFixupForwardJumpToHere(envPtr, &okFixup, 127)) {
- Tcl_Panic("TclCompileSubstCmd: bad ok jump distance %d",
- (int) (CurrentOffset(envPtr) - okFixup.codeOffset));
- }
- if (count > 1) {
- OP1(CONCAT1, count);
- count = 1;
- }
-
- /* CONTINUE jump to here */
- if (TclFixupForwardJumpToHere(envPtr, &endFixup, 127)) {
- Tcl_Panic("TclCompileSubstCmd: bad end jump distance %d",
- (int) (CurrentOffset(envPtr) - endFixup.codeOffset));
- }
- }
-
- while (count > 255) {
- OP1( CONCAT1, 255);
- count -= 254;
- }
- if (count > 1) {
- OP1( CONCAT1, count);
- }
-
- Tcl_FreeParse(&parse);
-
- if (state != NULL) {
- Tcl_RestoreInterpState(interp, state);
- TclCompileSyntaxError(interp, envPtr);
- TclAdjustStackDepth(-1, envPtr);
- }
-
- /* Final target of the multi-jump from all BREAKs */
- if (breakOffset > 0) {
- TclUpdateInstInt4AtPc(INST_JUMP4, CurrentOffset(envPtr) - breakOffset,
- envPtr->codeStart + breakOffset);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileSwitchCmd --
- *
- * Procedure called to compile the "switch" command.
- *
- * Results:
- * Returns TCL_OK for successful compile, or TCL_ERROR to defer
- * evaluation to runtime (either when it is too complex to get the
- * semantics right, or when we know for sure that it is an error but need
- * the error to happen at the right time).
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "switch" command at
- * runtime.
- *
- * FIXME:
- * Stack depths are probably not calculated correctly.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileSwitchCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr; /* Pointer to tokens in command. */
- int numWords; /* Number of words in command. */
-
- Tcl_Token *valueTokenPtr; /* Token for the value to switch on. */
- enum {Switch_Exact, Switch_Glob, Switch_Regexp} mode;
- /* What kind of switch are we doing? */
-
- Tcl_Token *bodyTokenArray; /* Array of real pattern list items. */
- Tcl_Token **bodyToken; /* Array of pointers to pattern list items. */
- int noCase; /* Has the -nocase flag been given? */
- int foundMode = 0; /* Have we seen a mode flag yet? */
- int i, valueIndex;
- int result = TCL_ERROR;
-
- /*
- * Only handle the following versions:
- * switch ?--? word {pattern body ...}
- * switch -exact ?--? word {pattern body ...}
- * switch -glob ?--? word {pattern body ...}
- * switch -regexp ?--? word {pattern body ...}
- * switch -- word simpleWordPattern simpleWordBody ...
- * switch -exact -- word simpleWordPattern simpleWordBody ...
- * switch -glob -- word simpleWordPattern simpleWordBody ...
- * switch -regexp -- word simpleWordPattern simpleWordBody ...
- * When the mode is -glob, can also handle a -nocase flag.
- *
- * First off, we don't care how the command's word was generated; we're
- * compiling it anyway! So skip it...
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- valueIndex = 1;
- numWords = parsePtr->numWords-1;
-
- /*
- * Check for options.
- */
-
- noCase = 0;
- mode = Switch_Exact;
- if (numWords == 2) {
- /*
- * There's just the switch value and the bodies list. In that case, we
- * can skip all option parsing and move on to consider switch values
- * and the body list.
- */
-
- goto finishedOptionParse;
- }
-
- /*
- * There must be at least one option, --, because without that there is no
- * way to statically avoid the problems you get from strings-to-be-matched
- * that start with a - (the interpreted code falls apart if it encounters
- * them, so we punt if we *might* encounter them as that is the easiest
- * way of emulating the behaviour).
- */
-
- for (; numWords>=3 ; tokenPtr=TokenAfter(tokenPtr),numWords--) {
- register unsigned size = tokenPtr[1].size;
- register const char *chrs = tokenPtr[1].start;
-
- /*
- * We only process literal options, and we assume that -e, -g and -n
- * are unique prefixes of -exact, -glob and -nocase respectively (true
- * at time of writing). Note that -exact and -glob may only be given
- * at most once or we bail out (error case).
- */
-
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || size < 2) {
- return TCL_ERROR;
- }
-
- if ((size <= 6) && !memcmp(chrs, "-exact", size)) {
- if (foundMode) {
- return TCL_ERROR;
- }
- mode = Switch_Exact;
- foundMode = 1;
- valueIndex++;
- continue;
- } else if ((size <= 5) && !memcmp(chrs, "-glob", size)) {
- if (foundMode) {
- return TCL_ERROR;
- }
- mode = Switch_Glob;
- foundMode = 1;
- valueIndex++;
- continue;
- } else if ((size <= 7) && !memcmp(chrs, "-regexp", size)) {
- if (foundMode) {
- return TCL_ERROR;
- }
- mode = Switch_Regexp;
- foundMode = 1;
- valueIndex++;
- continue;
- } else if ((size <= 7) && !memcmp(chrs, "-nocase", size)) {
- noCase = 1;
- valueIndex++;
- continue;
- } else if ((size == 2) && !memcmp(chrs, "--", 2)) {
- valueIndex++;
- break;
- }
-
- /*
- * The switch command has many flags we cannot compile at all (e.g.
- * all the RE-related ones) which we must have encountered. Either
- * that or we have run off the end. The action here is the same: punt
- * to interpreted version.
- */
-
- return TCL_ERROR;
- }
- if (numWords < 3) {
- return TCL_ERROR;
- }
- tokenPtr = TokenAfter(tokenPtr);
- numWords--;
- if (noCase && (mode == Switch_Exact)) {
- /*
- * Can't compile this case; no opcode for case-insensitive equality!
- */
-
- return TCL_ERROR;
- }
-
- /*
- * The value to test against is going to always get pushed on the stack.
- * But not yet; we need to verify that the rest of the command is
- * compilable too.
- */
-
- finishedOptionParse:
- valueTokenPtr = tokenPtr;
- /* For valueIndex, see previous loop. */
- tokenPtr = TokenAfter(tokenPtr);
- numWords--;
-
- /*
- * Build an array of tokens for the matcher terms and script bodies. Note
- * that in the case of the quoted bodies, this is tricky as we cannot use
- * copies of the string from the input token for the generated tokens (it
- * causes a crash during exception handling). When multiple tokens are
- * available at this point, this is pretty easy.
- */
-
- if (numWords == 1) {
- const char *bytes;
- int maxLen, numBytes;
-
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- return TCL_ERROR;
- }
- bytes = tokenPtr[1].start;
- numBytes = tokenPtr[1].size;
-
- /* Allocate enough space to work in. */
- maxLen = TclMaxListLength(bytes, numBytes, NULL);
- if (maxLen < 2) {
- return TCL_ERROR;
- }
- bodyTokenArray = ckalloc(sizeof(Tcl_Token) * maxLen);
- bodyToken = ckalloc(sizeof(Tcl_Token *) * maxLen);
-
- numWords = 0;
-
- while (numBytes > 0) {
- const char *prevBytes = bytes;
- int literal;
-
- if (TCL_OK != TclFindElement(NULL, bytes, numBytes,
- &(bodyTokenArray[numWords].start), &bytes,
- &(bodyTokenArray[numWords].size), &literal) || !literal) {
- goto abort;
- }
-
- bodyTokenArray[numWords].type = TCL_TOKEN_TEXT;
- bodyTokenArray[numWords].numComponents = 0;
- bodyToken[numWords] = bodyTokenArray + numWords;
-
- numBytes -= (bytes - prevBytes);
- numWords++;
- }
- if (numWords % 2) {
- abort:
- ckfree((char *) bodyToken);
- ckfree((char *) bodyTokenArray);
- return TCL_ERROR;
- }
- } else if (numWords % 2 || numWords == 0) {
- /*
- * Odd number of words (>1) available, or no words at all available.
- * Both are error cases, so punt and let the interpreted-version
- * generate the error message. Note that the second case probably
- * should get caught earlier, but it's easy to check here again anyway
- * because it'd cause a nasty crash otherwise.
- */
-
- return TCL_ERROR;
- } else {
- /*
- * Multi-word definition of patterns & actions.
- */
-
- bodyToken = ckalloc(sizeof(Tcl_Token *) * numWords);
- bodyTokenArray = NULL;
- for (i=0 ; i<numWords ; i++) {
- /*
- * We only handle the very simplest case. Anything more complex is
- * a good reason to go to the interpreted case anyway due to
- * traces, etc.
- */
-
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- goto freeTemporaries;
- }
- bodyToken[i] = tokenPtr+1;
-
- tokenPtr = TokenAfter(tokenPtr);
- }
- }
-
- /*
- * Fall back to interpreted if the last body is a continuation (it's
- * illegal, but this makes the error happen at the right time).
- */
-
- if (bodyToken[numWords-1]->size == 1 &&
- bodyToken[numWords-1]->start[0] == '-') {
- goto freeTemporaries;
- }
-
- /*
- * Now we commit to generating code; the parsing stage per se is done.
- * Check if we can generate a jump table, since if so that's faster than
- * doing an explicit compare with each body. Note that we're definitely
- * over-conservative with determining whether we can do the jump table,
- * but it handles the most common case well enough.
- */
-
- if (mode == Switch_Exact) {
- IssueSwitchJumpTable(interp, envPtr, valueIndex,
- valueTokenPtr, numWords, bodyToken);
- } else {
- IssueSwitchChainedTests(interp, envPtr, mode,noCase,
- valueIndex, valueTokenPtr, numWords, bodyToken);
- }
- result = TCL_OK;
-
- /*
- * Clean up all our temporary space and return.
- */
-
- freeTemporaries:
- ckfree(bodyToken);
- if (bodyTokenArray != NULL) {
- ckfree(bodyTokenArray);
- }
- return result;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * IssueSwitchChainedTests --
- *
- * Generate instructions for a [switch] command that is to be compiled
- * into a sequence of tests. This is the generic handle-everything mode
- * that inherently has performance that is (on average) linear in the
- * number of tests. It is the only mode that can handle -glob and -regexp
- * matches, or anything that is case-insensitive. It does not handle the
- * wild-and-wooly end of regexp matching (i.e., capture of match results)
- * so that's when we spill to the interpreted version.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-IssueSwitchChainedTests(
- Tcl_Interp *interp, /* Context for compiling script bodies. */
- CompileEnv *envPtr, /* Holds resulting instructions. */
- int mode, /* Exact, Glob or Regexp */
- int noCase, /* Case-insensitivity flag. */
- int valueIndex, /* The value to match against. */
- Tcl_Token *valueTokenPtr,
- int numBodyTokens, /* Number of tokens describing things the
- * switch can match against and bodies to
- * execute when the match succeeds. */
- Tcl_Token **bodyToken) /* Array of pointers to pattern list items. */
-{
- enum {Switch_Exact, Switch_Glob, Switch_Regexp};
- int savedStackDepth = envPtr->currStackDepth;
- int foundDefault; /* Flag to indicate whether a "default" clause
- * is present. */
- JumpFixup *fixupArray; /* Array of forward-jump fixup records. */
- int *fixupTargetArray; /* Array of places for fixups to point at. */
- int fixupCount; /* Number of places to fix up. */
- int contFixIndex; /* Where the first of the jumps due to a group
- * of continuation bodies starts, or -1 if
- * there aren't any. */
- int contFixCount; /* Number of continuation bodies pointing to
- * the current (or next) real body. */
- int nextArmFixupIndex;
- int simple, exact; /* For extracting the type of regexp. */
- int i;
-
- /*
- * First, we push the value we're matching against on the stack.
- */
-
- CompileTokens(envPtr, valueTokenPtr, interp);
-
- /*
- * Generate a test for each arm.
- */
-
- contFixIndex = -1;
- contFixCount = 0;
- fixupArray = ckalloc(sizeof(JumpFixup) * numBodyTokens);
- fixupTargetArray = ckalloc(sizeof(int) * numBodyTokens);
- memset(fixupTargetArray, 0, numBodyTokens * sizeof(int));
- fixupCount = 0;
- foundDefault = 0;
- for (i=0 ; i<numBodyTokens ; i+=2) {
- nextArmFixupIndex = -1;
- envPtr->currStackDepth = savedStackDepth + 1;
- if (i!=numBodyTokens-2 || bodyToken[numBodyTokens-2]->size != 7 ||
- memcmp(bodyToken[numBodyTokens-2]->start, "default", 7)) {
- /*
- * Generate the test for the arm.
- */
-
- switch (mode) {
- case Switch_Exact:
- OP( DUP);
- TclCompileTokens(interp, bodyToken[i], 1, envPtr);
- OP( STR_EQ);
- break;
- case Switch_Glob:
- TclCompileTokens(interp, bodyToken[i], 1, envPtr);
- OP4( OVER, 1);
- OP1( STR_MATCH, noCase);
- break;
- case Switch_Regexp:
- simple = exact = 0;
-
- /*
- * Keep in sync with TclCompileRegexpCmd.
- */
-
- if (bodyToken[i]->type == TCL_TOKEN_TEXT) {
- Tcl_DString ds;
-
- if (bodyToken[i]->size == 0) {
- /*
- * The semantics of regexps are that they always match
- * when the RE == "".
- */
-
- PushLiteral(envPtr, "1", 1);
- break;
- }
-
- /*
- * Attempt to convert pattern to glob. If successful, push
- * the converted pattern.
- */
-
- if (TclReToGlob(NULL, bodyToken[i]->start,
- bodyToken[i]->size, &ds, &exact) == TCL_OK) {
- simple = 1;
- PushLiteral(envPtr, Tcl_DStringValue(&ds),
- Tcl_DStringLength(&ds));
- Tcl_DStringFree(&ds);
- }
- }
- if (!simple) {
- TclCompileTokens(interp, bodyToken[i], 1, envPtr);
- }
-
- OP4( OVER, 1);
- if (!simple) {
- /*
- * Pass correct RE compile flags. We use only Int1
- * (8-bit), but that handles all the flags we want to
- * pass. Don't use TCL_REG_NOSUB as we may have backrefs
- * or capture vars.
- */
-
- int cflags = TCL_REG_ADVANCED
- | (noCase ? TCL_REG_NOCASE : 0);
-
- OP1(REGEXP, cflags);
- } else if (exact && !noCase) {
- OP( STR_EQ);
- } else {
- OP1(STR_MATCH, noCase);
- }
- break;
- default:
- Tcl_Panic("unknown switch mode: %d", mode);
- }
-
- /*
- * In a fall-through case, we will jump on _true_ to the place
- * where the body starts (generated later, with guarantee of this
- * ensured earlier; the final body is never a fall-through).
- */
-
- if (bodyToken[i+1]->size==1 && bodyToken[i+1]->start[0]=='-') {
- if (contFixIndex == -1) {
- contFixIndex = fixupCount;
- contFixCount = 0;
- }
- TclEmitForwardJump(envPtr, TCL_TRUE_JUMP,
- &fixupArray[contFixIndex+contFixCount]);
- fixupCount++;
- contFixCount++;
- continue;
- }
-
- TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
- &fixupArray[fixupCount]);
- nextArmFixupIndex = fixupCount;
- fixupCount++;
- } else {
- /*
- * Got a default clause; set a flag to inhibit the generation of
- * the jump after the body and the cleanup of the intermediate
- * value that we are switching against.
- *
- * Note that default clauses (which are always terminal clauses)
- * cannot be fall-through clauses as well, since the last clause
- * is never a fall-through clause (which we have already
- * verified).
- */
-
- foundDefault = 1;
- }
-
- /*
- * Generate the body for the arm. This is guaranteed not to be a
- * fall-through case, but it might have preceding fall-through cases,
- * so we must process those first.
- */
-
- if (contFixIndex != -1) {
- int j;
-
- for (j=0 ; j<contFixCount ; j++) {
- fixupTargetArray[contFixIndex+j] = CurrentOffset(envPtr);
- }
- contFixIndex = -1;
- }
-
- /*
- * Now do the actual compilation. Note that we do not use CompileBody
- * because we may have synthesized the tokens in a non-standard
- * pattern.
- */
-
- OP( POP);
- envPtr->currStackDepth = savedStackDepth + 1;
- TclCompileCmdWord(interp, bodyToken[i+1], 1, envPtr);
-
- if (!foundDefault) {
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
- &fixupArray[fixupCount]);
- fixupCount++;
- fixupTargetArray[nextArmFixupIndex] = CurrentOffset(envPtr);
- }
- }
-
- /*
- * Discard the value we are matching against unless we've had a default
- * clause (in which case it will already be gone due to the code at the
- * start of processing an arm, guaranteed) and make the result of the
- * command an empty string.
- */
-
- if (!foundDefault) {
- OP( POP);
- PushLiteral(envPtr, "", 0);
- }
-
- /*
- * Do jump fixups for arms that were executed. First, fill in the jumps of
- * all jumps that don't point elsewhere to point to here.
- */
-
- for (i=0 ; i<fixupCount ; i++) {
- if (fixupTargetArray[i] == 0) {
- fixupTargetArray[i] = envPtr->codeNext-envPtr->codeStart;
- }
- }
-
- /*
- * Now scan backwards over all the jumps (all of which are forward jumps)
- * doing each one. When we do one and there is a size changes, we must
- * scan back over all the previous ones and see if they need adjusting
- * before proceeding with further jump fixups (the interleaved nature of
- * all the jumps makes this impossible to do without nested loops).
- */
-
- for (i=fixupCount-1 ; i>=0 ; i--) {
- if (TclFixupForwardJump(envPtr, &fixupArray[i],
- fixupTargetArray[i] - fixupArray[i].codeOffset, 127)) {
- int j;
-
- for (j=i-1 ; j>=0 ; j--) {
- if (fixupTargetArray[j] > fixupArray[i].codeOffset) {
- fixupTargetArray[j] += 3;
- }
- }
- }
- }
- ckfree(fixupTargetArray);
- ckfree(fixupArray);
-
- envPtr->currStackDepth = savedStackDepth + 1;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * IssueSwitchJumpTable --
- *
- * Generate instructions for a [switch] command that is to be compiled
- * into a jump table. This only handles the case where case-sensitive,
- * exact matching is used, but this is actually the most common case in
- * real code.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-IssueSwitchJumpTable(
- Tcl_Interp *interp, /* Context for compiling script bodies. */
- CompileEnv *envPtr, /* Holds resulting instructions. */
- int valueIndex, /* The value to match against. */
- Tcl_Token *valueTokenPtr,
- int numBodyTokens, /* Number of tokens describing things the
- * switch can match against and bodies to
- * execute when the match succeeds. */
- Tcl_Token **bodyToken) /* Array of pointers to pattern list items. */
-{
- JumptableInfo *jtPtr;
- int savedStackDepth = envPtr->currStackDepth;
- int infoIndex, isNew, *finalFixups, numRealBodies = 0, jumpLocation;
- int mustGenerate, foundDefault, jumpToDefault, i;
- Tcl_DString buffer;
- Tcl_HashEntry *hPtr;
-
- /*
- * First, we push the value we're matching against on the stack.
- */
-
- CompileTokens(envPtr, valueTokenPtr, interp);
-
- /*
- * Compile the switch by using a jump table, which is basically a
- * hashtable that maps from literal values to match against to the offset
- * (relative to the INST_JUMP_TABLE instruction) to jump to. The jump
- * table itself is independent of any invokation of the bytecode, and as
- * such is stored in an auxData block.
- *
- * Start by allocating the jump table itself, plus some workspace.
- */
-
- jtPtr = ckalloc(sizeof(JumptableInfo));
- Tcl_InitHashTable(&jtPtr->hashTable, TCL_STRING_KEYS);
- infoIndex = TclCreateAuxData(jtPtr, &tclJumptableInfoType, envPtr);
- finalFixups = ckalloc(sizeof(int) * (numBodyTokens/2));
- foundDefault = 0;
- mustGenerate = 1;
-
- /*
- * Next, issue the instruction to do the jump, together with what we want
- * to do if things do not work out (jump to either the default clause or
- * the "default" default, which just sets the result to empty). Note that
- * we will come back and rewrite the jump's offset parameter when we know
- * what it should be, and that all jumps we issue are of the wide kind
- * because that makes the code much easier to debug!
- */
-
- jumpLocation = CurrentOffset(envPtr);
- OP4( JUMP_TABLE, infoIndex);
- jumpToDefault = CurrentOffset(envPtr);
- OP4( JUMP4, 0);
-
- for (i=0 ; i<numBodyTokens ; i+=2) {
- /*
- * For each arm, we must first work out what to do with the match
- * term.
- */
-
- if (i!=numBodyTokens-2 || bodyToken[numBodyTokens-2]->size != 7 ||
- memcmp(bodyToken[numBodyTokens-2]->start, "default", 7)) {
- /*
- * This is not a default clause, so insert the current location as
- * a target in the jump table (assuming it isn't already there,
- * which would indicate that this clause is probably masked by an
- * earlier one). Note that we use a Tcl_DString here simply
- * because the hash API does not let us specify the string length.
- */
-
- Tcl_DStringInit(&buffer);
- TclDStringAppendToken(&buffer, bodyToken[i]);
- hPtr = Tcl_CreateHashEntry(&jtPtr->hashTable,
- Tcl_DStringValue(&buffer), &isNew);
- if (isNew) {
- /*
- * First time we've encountered this match clause, so it must
- * point to here.
- */
-
- Tcl_SetHashValue(hPtr, CurrentOffset(envPtr) - jumpLocation);
- }
- Tcl_DStringFree(&buffer);
- } else {
- /*
- * This is a default clause, so patch up the fallthrough from the
- * INST_JUMP_TABLE instruction to here.
- */
-
- foundDefault = 1;
- isNew = 1;
- TclStoreInt4AtPtr(CurrentOffset(envPtr)-jumpToDefault,
- envPtr->codeStart+jumpToDefault+1);
- }
-
- /*
- * Now, for each arm we must deal with the body of the clause.
- *
- * If this is a continuation body (never true of a final clause,
- * whether default or not) we're done because the next jump target
- * will also point here, so we advance to the next clause.
- */
-
- if (bodyToken[i+1]->size == 1 && bodyToken[i+1]->start[0] == '-') {
- mustGenerate = 1;
- continue;
- }
-
- /*
- * Also skip this arm if its only match clause is masked. (We could
- * probably be more aggressive about this, but that would be much more
- * difficult to get right.)
- */
-
- if (!isNew && !mustGenerate) {
- continue;
- }
- mustGenerate = 0;
-
- /*
- * Compile the body of the arm.
- */
-
- envPtr->currStackDepth = savedStackDepth;
- TclCompileCmdWord(interp, bodyToken[i+1], 1, envPtr);
-
- /*
- * Compile a jump in to the end of the command if this body is
- * anything other than a user-supplied default arm (to either skip
- * over the remaining bodies or the code that generates an empty
- * result).
- */
-
- if (i+2 < numBodyTokens || !foundDefault) {
- finalFixups[numRealBodies++] = CurrentOffset(envPtr);
-
- /*
- * Easier by far to issue this jump as a fixed-width jump, since
- * otherwise we'd need to do a lot more (and more awkward)
- * rewriting when we fixed this all up.
- */
-
- OP4( JUMP4, 0);
- }
- }
-
- /*
- * We're at the end. If we've not already done so through the processing
- * of a user-supplied default clause, add in a "default" default clause
- * now.
- */
-
- if (!foundDefault) {
- envPtr->currStackDepth = savedStackDepth;
- TclStoreInt4AtPtr(CurrentOffset(envPtr)-jumpToDefault,
- envPtr->codeStart+jumpToDefault+1);
- PushLiteral(envPtr, "", 0);
- }
-
- /*
- * No more instructions to be issued; everything that needs to jump to the
- * end of the command is fixed up at this point.
- */
-
- for (i=0 ; i<numRealBodies ; i++) {
- TclStoreInt4AtPtr(CurrentOffset(envPtr)-finalFixups[i],
- envPtr->codeStart+finalFixups[i]+1);
- }
-
- /*
- * Clean up all our temporary space and return.
- */
-
- ckfree(finalFixups);
- envPtr->currStackDepth = savedStackDepth + 1;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * DupJumptableInfo, FreeJumptableInfo --
- *
- * Functions to duplicate, release and print a jump-table created for use
- * with the INST_JUMP_TABLE instruction.
- *
- * Results:
- * DupJumptableInfo: a copy of the jump-table
- * FreeJumptableInfo: none
- * PrintJumptableInfo: none
- *
- * Side effects:
- * DupJumptableInfo: allocates memory
- * FreeJumptableInfo: releases memory
- * PrintJumptableInfo: none
- *
- *----------------------------------------------------------------------
- */
-
-static ClientData
-DupJumptableInfo(
- ClientData clientData)
-{
- JumptableInfo *jtPtr = clientData;
- JumptableInfo *newJtPtr = ckalloc(sizeof(JumptableInfo));
- Tcl_HashEntry *hPtr, *newHPtr;
- Tcl_HashSearch search;
- int isNew;
-
- Tcl_InitHashTable(&newJtPtr->hashTable, TCL_STRING_KEYS);
- hPtr = Tcl_FirstHashEntry(&jtPtr->hashTable, &search);
- while (hPtr != NULL) {
- newHPtr = Tcl_CreateHashEntry(&newJtPtr->hashTable,
- Tcl_GetHashKey(&jtPtr->hashTable, hPtr), &isNew);
- Tcl_SetHashValue(newHPtr, Tcl_GetHashValue(hPtr));
- }
- return newJtPtr;
-}
-
-static void
-FreeJumptableInfo(
- ClientData clientData)
-{
- JumptableInfo *jtPtr = clientData;
-
- Tcl_DeleteHashTable(&jtPtr->hashTable);
- ckfree(jtPtr);
-}
-
-static void
-PrintJumptableInfo(
- ClientData clientData,
- Tcl_Obj *appendObj,
- ByteCode *codePtr,
- unsigned int pcOffset)
-{
- register JumptableInfo *jtPtr = clientData;
- Tcl_HashEntry *hPtr;
- Tcl_HashSearch search;
- const char *keyPtr;
- int offset, i = 0;
-
- hPtr = Tcl_FirstHashEntry(&jtPtr->hashTable, &search);
- for (; hPtr ; hPtr = Tcl_NextHashEntry(&search)) {
- keyPtr = Tcl_GetHashKey(&jtPtr->hashTable, hPtr);
- offset = PTR2INT(Tcl_GetHashValue(hPtr));
-
- if (i++) {
- Tcl_AppendToObj(appendObj, ", ", -1);
- if (i%4==0) {
- Tcl_AppendToObj(appendObj, "\n\t\t", -1);
- }
- }
- Tcl_AppendPrintfToObj(appendObj, "\"%s\"->pc %d",
- keyPtr, pcOffset + offset);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileTailcallCmd --
- *
- * Procedure called to compile the "tailcall" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "tailcall" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileTailcallCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr = parsePtr->tokenPtr;
- int i;
-
- if (parsePtr->numWords < 2 || parsePtr->numWords > 256
- || envPtr->procPtr == NULL) {
- return TCL_ERROR;
- }
-
- /* make room for the nsObjPtr */
- CompileWord(envPtr, tokenPtr, interp, 0);
- for (i=1 ; i<parsePtr->numWords ; i++) {
- tokenPtr = TokenAfter(tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, i);
- }
- TclEmitInstInt1( INST_TAILCALL, parsePtr->numWords, envPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileThrowCmd --
- *
- * Procedure called to compile the "throw" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "throw" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileThrowCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- int numWords = parsePtr->numWords;
- int savedStackDepth = envPtr->currStackDepth;
- Tcl_Token *codeToken, *msgToken;
- Tcl_Obj *objPtr;
-
- if (numWords != 3) {
- return TCL_ERROR;
- }
- codeToken = TokenAfter(parsePtr->tokenPtr);
- msgToken = TokenAfter(codeToken);
-
- TclNewObj(objPtr);
- Tcl_IncrRefCount(objPtr);
- if (TclWordKnownAtCompileTime(codeToken, objPtr)) {
- Tcl_Obj *errPtr, *dictPtr;
- const char *string;
- int len;
-
- /*
- * The code is known at compilation time. This allows us to issue a
- * very efficient sequence of instructions.
- */
-
- if (Tcl_ListObjLength(interp, objPtr, &len) != TCL_OK) {
- /*
- * Must still do this; might generate an error when getting this
- * "ignored" value prepared as an argument.
- */
-
- CompileWord(envPtr, msgToken, interp, 2);
- TclCompileSyntaxError(interp, envPtr);
- Tcl_DecrRefCount(objPtr);
- envPtr->currStackDepth = savedStackDepth + 1;
- return TCL_OK;
- }
- if (len == 0) {
- /*
- * Must still do this; might generate an error when getting this
- * "ignored" value prepared as an argument.
- */
-
- CompileWord(envPtr, msgToken, interp, 2);
- goto issueErrorForEmptyCode;
- }
- TclNewLiteralStringObj(errPtr, "-errorcode");
- TclNewObj(dictPtr);
- Tcl_DictObjPut(NULL, dictPtr, errPtr, objPtr);
- Tcl_IncrRefCount(dictPtr);
- string = Tcl_GetStringFromObj(dictPtr, &len);
- CompileWord(envPtr, msgToken, interp, 2);
- PushLiteral(envPtr, string, len);
- TclDecrRefCount(dictPtr);
- OP44( RETURN_IMM, 1, 0);
- envPtr->currStackDepth = savedStackDepth + 1;
- } else {
- /*
- * When the code token is not known at compilation time, we need to do
- * a little bit more work. The main tricky bit here is that the error
- * code has to be a list (a [throw] restriction) so we must emit extra
- * instructions to enforce that condition.
- */
-
- CompileWord(envPtr, codeToken, interp, 1);
- PUSH( "-errorcode");
- CompileWord(envPtr, msgToken, interp, 2);
- OP4( REVERSE, 3);
- OP( DUP);
- OP( LIST_LENGTH);
- OP1( JUMP_FALSE1, 16);
- OP4( LIST, 2);
- OP44( RETURN_IMM, 1, 0);
-
- /*
- * Generate an error for being an empty list. Can't leverage anything
- * else to do this for us.
- */
-
- issueErrorForEmptyCode:
- PUSH( "type must be non-empty list");
- PUSH( "");
- OP44( RETURN_IMM, 1, 0);
- }
- envPtr->currStackDepth = savedStackDepth + 1;
- TclDecrRefCount(objPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileTryCmd --
- *
- * Procedure called to compile the "try" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "try" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileTryCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- int numWords = parsePtr->numWords, numHandlers, result = TCL_ERROR;
- Tcl_Token *bodyToken, *finallyToken, *tokenPtr;
- Tcl_Token **handlerTokens = NULL;
- Tcl_Obj **matchClauses = NULL;
- int *matchCodes=NULL, *resultVarIndices=NULL, *optionVarIndices=NULL;
- int i;
-
- if (numWords < 2) {
- return TCL_ERROR;
- }
-
- bodyToken = TokenAfter(parsePtr->tokenPtr);
-
- if (numWords == 2) {
- /*
- * No handlers or finally; do nothing beyond evaluating the body.
- */
-
- CompileBody(envPtr, bodyToken, interp);
- return TCL_OK;
- }
-
- numWords -= 2;
- tokenPtr = TokenAfter(bodyToken);
-
- /*
- * Extract information about what handlers there are.
- */
-
- numHandlers = numWords >> 2;
- numWords -= numHandlers * 4;
- if (numHandlers > 0) {
- handlerTokens = ckalloc(sizeof(Tcl_Token*)*numHandlers);
- matchClauses = ckalloc(sizeof(Tcl_Obj *) * numHandlers);
- memset(matchClauses, 0, sizeof(Tcl_Obj *) * numHandlers);
- matchCodes = ckalloc(sizeof(int) * numHandlers);
- resultVarIndices = ckalloc(sizeof(int) * numHandlers);
- optionVarIndices = ckalloc(sizeof(int) * numHandlers);
-
- for (i=0 ; i<numHandlers ; i++) {
- Tcl_Obj *tmpObj, **objv;
- int objc;
-
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- goto failedToCompile;
- }
- if (tokenPtr[1].size == 4
- && !strncmp(tokenPtr[1].start, "trap", 4)) {
- /*
- * Parse the list of errorCode words to match against.
- */
-
- matchCodes[i] = TCL_ERROR;
- tokenPtr = TokenAfter(tokenPtr);
- TclNewObj(tmpObj);
- Tcl_IncrRefCount(tmpObj);
- if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)
- || Tcl_ListObjLength(NULL, tmpObj, &objc) != TCL_OK
- || (objc == 0)) {
- TclDecrRefCount(tmpObj);
- goto failedToCompile;
- }
- Tcl_ListObjReplace(NULL, tmpObj, 0, 0, 0, NULL);
- matchClauses[i] = tmpObj;
- } else if (tokenPtr[1].size == 2
- && !strncmp(tokenPtr[1].start, "on", 2)) {
- int code;
-
- /*
- * Parse the result code to look for.
- */
-
- tokenPtr = TokenAfter(tokenPtr);
- TclNewObj(tmpObj);
- Tcl_IncrRefCount(tmpObj);
- if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
- TclDecrRefCount(tmpObj);
- goto failedToCompile;
- }
- if (TCL_ERROR == TclGetCompletionCodeFromObj(NULL, tmpObj, &code)) {
- TclDecrRefCount(tmpObj);
- goto failedToCompile;
- }
- matchCodes[i] = code;
- TclDecrRefCount(tmpObj);
- } else {
- goto failedToCompile;
- }
-
- /*
- * Parse the variable binding.
- */
-
- tokenPtr = TokenAfter(tokenPtr);
- TclNewObj(tmpObj);
- Tcl_IncrRefCount(tmpObj);
- if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
- TclDecrRefCount(tmpObj);
- goto failedToCompile;
- }
- if (Tcl_ListObjGetElements(NULL, tmpObj, &objc, &objv) != TCL_OK
- || (objc > 2)) {
- TclDecrRefCount(tmpObj);
- goto failedToCompile;
- }
- if (objc > 0) {
- int len;
- const char *varname = Tcl_GetStringFromObj(objv[0], &len);
-
- if (!TclIsLocalScalar(varname, len)) {
- TclDecrRefCount(tmpObj);
- goto failedToCompile;
- }
- resultVarIndices[i] =
- TclFindCompiledLocal(varname, len, 1, envPtr);
- } else {
- resultVarIndices[i] = -1;
- }
- if (objc == 2) {
- int len;
- const char *varname = Tcl_GetStringFromObj(objv[1], &len);
-
- if (!TclIsLocalScalar(varname, len)) {
- TclDecrRefCount(tmpObj);
- goto failedToCompile;
- }
- optionVarIndices[i] =
- TclFindCompiledLocal(varname, len, 1, envPtr);
- } else {
- optionVarIndices[i] = -1;
- }
- TclDecrRefCount(tmpObj);
-
- /*
- * Extract the body for this handler.
- */
-
- tokenPtr = TokenAfter(tokenPtr);
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- goto failedToCompile;
- }
- if (tokenPtr[1].size == 1 && tokenPtr[1].start[0] == '-') {
- handlerTokens[i] = NULL;
- } else {
- handlerTokens[i] = tokenPtr;
- }
-
- tokenPtr = TokenAfter(tokenPtr);
- }
-
- if (handlerTokens[numHandlers-1] == NULL) {
- goto failedToCompile;
- }
- }
-
- /*
- * Parse the finally clause
- */
-
- if (numWords == 0) {
- finallyToken = NULL;
- } else if (numWords == 2) {
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size != 7
- || strncmp(tokenPtr[1].start, "finally", 7)) {
- goto failedToCompile;
- }
- finallyToken = TokenAfter(tokenPtr);
- } else {
- goto failedToCompile;
- }
-
- /*
- * Issue the bytecode.
- */
-
- if (finallyToken) {
- result = IssueTryFinallyInstructions(interp, envPtr, bodyToken,
- numHandlers, matchCodes, matchClauses, resultVarIndices,
- optionVarIndices, handlerTokens, finallyToken);
- } else {
- result = IssueTryInstructions(interp, envPtr, bodyToken, numHandlers,
- matchCodes, matchClauses, resultVarIndices, optionVarIndices,
- handlerTokens);
- }
-
- /*
- * Delete any temporary state and finish off.
- */
-
- failedToCompile:
- if (numHandlers > 0) {
- for (i=0 ; i<numHandlers ; i++) {
- if (matchClauses[i]) {
- TclDecrRefCount(matchClauses[i]);
- }
- }
- ckfree(optionVarIndices);
- ckfree(resultVarIndices);
- ckfree(matchCodes);
- ckfree(matchClauses);
- ckfree(handlerTokens);
- }
- return result;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * IssueTryInstructions, IssueTryFinallyInstructions --
- *
- * The code generators for [try]. Split from the parsing engine for
- * reasons of developer sanity, and also split between no-finally and
- * with-finally cases because so many of the details of generation vary
- * between the two.
- *
- * The macros below make the instruction issuing easier to follow.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-IssueTryInstructions(
- Tcl_Interp *interp,
- CompileEnv *envPtr,
- Tcl_Token *bodyToken,
- int numHandlers,
- int *matchCodes,
- Tcl_Obj **matchClauses,
- int *resultVars,
- int *optionVars,
- Tcl_Token **handlerTokens)
-{
- int range, resultVar, optionsVar;
- int savedStackDepth = envPtr->currStackDepth;
- int i, j, len, forwardsNeedFixing = 0;
- int *addrsToFix, *forwardsToFix, notCodeJumpSource, notECJumpSource;
- char buf[TCL_INTEGER_SPACE];
-
- resultVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- optionsVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- if (resultVar < 0 || optionsVar < 0) {
- return TCL_ERROR;
- }
-
- /*
- * Compile the body, trapping any error in it so that we can trap on it
- * and/or run a finally clause. Note that there must be at least one
- * on/trap clause; when none is present, this whole function is not called
- * (and it's never called when there's a finally clause).
- */
-
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
- OP4( BEGIN_CATCH4, range);
- ExceptionRangeStarts(envPtr, range);
- BODY( bodyToken, 1);
- ExceptionRangeEnds(envPtr, range);
- PUSH( "0");
- OP4( REVERSE, 2);
- OP1( JUMP1, 4);
- ExceptionRangeTarget(envPtr, range, catchOffset);
- OP( PUSH_RETURN_CODE);
- OP( PUSH_RESULT);
- OP( PUSH_RETURN_OPTIONS);
- OP( END_CATCH);
- STORE( optionsVar);
- OP( POP);
- STORE( resultVar);
- OP( POP);
-
- /*
- * Now we handle all the registered 'on' and 'trap' handlers in order.
- * For us to be here, there must be at least one handler.
- *
- * Slight overallocation, but reduces size of this function.
- */
-
- addrsToFix = ckalloc(sizeof(int)*numHandlers);
- forwardsToFix = ckalloc(sizeof(int)*numHandlers);
-
- for (i=0 ; i<numHandlers ; i++) {
- sprintf(buf, "%d", matchCodes[i]);
- OP( DUP);
- PUSH( buf);
- OP( EQ);
- JUMP(notCodeJumpSource, JUMP_FALSE4);
- if (matchClauses[i]) {
- Tcl_ListObjLength(NULL, matchClauses[i], &len);
-
- /*
- * Match the errorcode according to try/trap rules.
- */
-
- LOAD( optionsVar);
- PUSH( "-errorcode");
- OP4( DICT_GET, 1);
- TclAdjustStackDepth(-1, envPtr);
- OP44( LIST_RANGE_IMM, 0, len-1);
- PUSH( TclGetString(matchClauses[i]));
- OP( STR_EQ);
- JUMP(notECJumpSource, JUMP_FALSE4);
- } else {
- notECJumpSource = -1; /* LINT */
- }
- OP( POP);
-
- /*
- * There is no finally clause, so we can avoid wrapping a catch
- * context around the handler. That simplifies what instructions need
- * to be issued a lot since we can let errors just fall through.
- */
-
- if (resultVars[i] >= 0) {
- LOAD( resultVar);
- STORE( resultVars[i]);
- OP( POP);
- if (optionVars[i] >= 0) {
- LOAD( optionsVar);
- STORE( optionVars[i]);
- OP( POP);
- }
- }
- if (!handlerTokens[i]) {
- forwardsNeedFixing = 1;
- JUMP(forwardsToFix[i], JUMP4);
- } else {
- forwardsToFix[i] = -1;
- if (forwardsNeedFixing) {
- forwardsNeedFixing = 0;
- for (j=0 ; j<i ; j++) {
- if (forwardsToFix[j] == -1) {
- continue;
- }
- FIXJUMP(forwardsToFix[j]);
- forwardsToFix[j] = -1;
- }
- }
- envPtr->currStackDepth = savedStackDepth;
- BODY( handlerTokens[i], 5+i*4);
- }
-
- JUMP(addrsToFix[i], JUMP4);
- if (matchClauses[i]) {
- FIXJUMP(notECJumpSource);
- }
- FIXJUMP(notCodeJumpSource);
- }
-
- /*
- * Drop the result code since it didn't match any clause, and reissue the
- * exception. Note also that INST_RETURN_STK can proceed to the next
- * instruction.
- */
-
- OP( POP);
- LOAD( optionsVar);
- LOAD( resultVar);
- OP( RETURN_STK);
-
- /*
- * Fix all the jumps from taken clauses to here (which is the end of the
- * [try]).
- */
-
- for (i=0 ; i<numHandlers ; i++) {
- FIXJUMP(addrsToFix[i]);
- }
- ckfree(forwardsToFix);
- ckfree(addrsToFix);
- envPtr->currStackDepth = savedStackDepth + 1;
- return TCL_OK;
-}
-
-static int
-IssueTryFinallyInstructions(
- Tcl_Interp *interp,
- CompileEnv *envPtr,
- Tcl_Token *bodyToken,
- int numHandlers,
- int *matchCodes,
- Tcl_Obj **matchClauses,
- int *resultVars,
- int *optionVars,
- Tcl_Token **handlerTokens,
- Tcl_Token *finallyToken) /* Not NULL */
-{
- int savedStackDepth = envPtr->currStackDepth;
- int range, resultVar, optionsVar, i, j, len, forwardsNeedFixing = 0;
- int *addrsToFix, *forwardsToFix, notCodeJumpSource, notECJumpSource;
- char buf[TCL_INTEGER_SPACE];
-
- resultVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- optionsVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
- if (resultVar < 0 || optionsVar < 0) {
- return TCL_ERROR;
- }
-
- /*
- * Compile the body, trapping any error in it so that we can trap on it
- * (if any trap matches) and run a finally clause.
- */
-
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
- OP4( BEGIN_CATCH4, range);
- ExceptionRangeStarts(envPtr, range);
- envPtr->currStackDepth = savedStackDepth;
- BODY( bodyToken, 1);
- ExceptionRangeEnds(envPtr, range);
- PUSH( "0");
- OP4( REVERSE, 2);
- OP1( JUMP1, 4);
- ExceptionRangeTarget(envPtr, range, catchOffset);
- OP( PUSH_RETURN_CODE);
- OP( PUSH_RESULT);
- OP( PUSH_RETURN_OPTIONS);
- OP( END_CATCH);
- STORE( optionsVar);
- OP( POP);
- STORE( resultVar);
- OP( POP);
- envPtr->currStackDepth = savedStackDepth + 1;
-
- /*
- * Now we handle all the registered 'on' and 'trap' handlers in order.
- */
-
- if (numHandlers) {
- /*
- * Slight overallocation, but reduces size of this function.
- */
-
- addrsToFix = ckalloc(sizeof(int)*numHandlers);
- forwardsToFix = ckalloc(sizeof(int)*numHandlers);
-
- for (i=0 ; i<numHandlers ; i++) {
- sprintf(buf, "%d", matchCodes[i]);
- OP( DUP);
- PUSH( buf);
- OP( EQ);
- JUMP(notCodeJumpSource, JUMP_FALSE4);
- if (matchClauses[i]) {
- Tcl_ListObjLength(NULL, matchClauses[i], &len);
-
- /*
- * Match the errorcode according to try/trap rules.
- */
-
- LOAD( optionsVar);
- PUSH( "-errorcode");
- OP4( DICT_GET, 1);
- TclAdjustStackDepth(-1, envPtr);
- OP44( LIST_RANGE_IMM, 0, len-1);
- PUSH( TclGetString(matchClauses[i]));
- OP( STR_EQ);
- JUMP(notECJumpSource, JUMP_FALSE4);
- } else {
- notECJumpSource = -1; /* LINT */
- }
-
- /*
- * There is a finally clause, so we need a fairly complex sequence
- * of instructions to deal with an on/trap handler because we must
- * call the finally handler *and* we need to substitute the result
- * from a failed trap for the result from the main script.
- */
-
- if (resultVars[i] >= 0 || handlerTokens[i]) {
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
- OP4( BEGIN_CATCH4, range);
- ExceptionRangeStarts(envPtr, range);
- }
- if (resultVars[i] >= 0) {
- LOAD( resultVar);
- STORE( resultVars[i]);
- OP( POP);
- if (optionVars[i] >= 0) {
- LOAD( optionsVar);
- STORE( optionVars[i]);
- OP( POP);
- }
-
- if (!handlerTokens[i]) {
- /*
- * No handler. Will not be the last handler (that is a
- * condition that is checked by the caller). Chain to the
- * next one.
- */
-
- ExceptionRangeEnds(envPtr, range);
- OP( END_CATCH);
- forwardsNeedFixing = 1;
- JUMP(forwardsToFix[i], JUMP4);
- goto finishTrapCatchHandling;
- }
- } else if (!handlerTokens[i]) {
- /*
- * No handler. Will not be the last handler (that condition is
- * checked by the caller). Chain to the next one.
- */
-
- forwardsNeedFixing = 1;
- JUMP(forwardsToFix[i], JUMP4);
- goto endOfThisArm;
- }
-
- /*
- * Got a handler. Make sure that any pending patch-up actions from
- * previous unprocessed handlers are dealt with now that we know
- * where they are to jump to.
- */
-
- if (forwardsNeedFixing) {
- forwardsNeedFixing = 0;
- OP1( JUMP1, 7);
- for (j=0 ; j<i ; j++) {
- if (forwardsToFix[j] == -1) {
- continue;
- }
- FIXJUMP(forwardsToFix[j]);
- forwardsToFix[j] = -1;
- }
- OP4( BEGIN_CATCH4, range);
- }
- envPtr->currStackDepth = savedStackDepth;
- BODY( handlerTokens[i], 5+i*4);
- ExceptionRangeEnds(envPtr, range);
- OP( PUSH_RETURN_OPTIONS);
- OP4( REVERSE, 2);
- OP1( JUMP1, 4);
- forwardsToFix[i] = -1;
-
- /*
- * Error in handler or setting of variables; replace the stored
- * exception with the new one. Note that we only push this if we
- * have either a body or some variable setting here. Otherwise
- * this code is unreachable.
- */
-
- finishTrapCatchHandling:
- ExceptionRangeTarget(envPtr, range, catchOffset);
- OP( PUSH_RETURN_OPTIONS);
- OP( PUSH_RESULT);
- OP( END_CATCH);
- STORE( resultVar);
- OP( POP);
- STORE( optionsVar);
- OP( POP);
-
- endOfThisArm:
- if (i+1 < numHandlers) {
- JUMP(addrsToFix[i], JUMP4);
- }
- if (matchClauses[i]) {
- FIXJUMP(notECJumpSource);
- }
- FIXJUMP(notCodeJumpSource);
- }
-
- /*
- * Fix all the jumps from taken clauses to here (the start of the
- * finally clause).
- */
-
- for (i=0 ; i<numHandlers-1 ; i++) {
- FIXJUMP(addrsToFix[i]);
- }
- ckfree(forwardsToFix);
- ckfree(addrsToFix);
- }
-
- /*
- * Drop the result code.
- */
-
- OP( POP);
-
- /*
- * Process the finally clause (at last!) Note that we do not wrap this in
- * error handlers because we would just rethrow immediately anyway. Then
- * (on normal success) we reissue the exception. Note also that
- * INST_RETURN_STK can proceed to the next instruction; that'll be the
- * next command (or some inter-command manipulation).
- */
-
- envPtr->currStackDepth = savedStackDepth;
- BODY( finallyToken, 3 + 4*numHandlers);
- OP( POP);
- LOAD( optionsVar);
- LOAD( resultVar);
- OP( RETURN_STK);
- envPtr->currStackDepth = savedStackDepth + 1;
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileUnsetCmd --
- *
- * Procedure called to compile the "unset" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "unset" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileUnsetCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *varTokenPtr;
- int isScalar, simpleVarName, localIndex, numWords, flags, i;
- Tcl_Obj *leadingWord;
-
- numWords = parsePtr->numWords-1;
- flags = 1;
- varTokenPtr = TokenAfter(parsePtr->tokenPtr);
- leadingWord = Tcl_NewObj();
- if (numWords > 0 && TclWordKnownAtCompileTime(varTokenPtr, leadingWord)) {
- int len;
- const char *bytes = Tcl_GetStringFromObj(leadingWord, &len);
-
- if (len == 11 && !strncmp("-nocomplain", bytes, 11)) {
- flags = 0;
- varTokenPtr = TokenAfter(varTokenPtr);
- numWords--;
- } else if (len == 2 && !strncmp("--", bytes, 2)) {
- varTokenPtr = TokenAfter(varTokenPtr);
- numWords--;
- }
- } else {
- /*
- * Cannot guarantee that the first word is not '-nocomplain' at
- * evaluation with reasonable effort, so spill to interpreted version.
- */
-
- TclDecrRefCount(leadingWord);
- return TCL_ERROR;
- }
- TclDecrRefCount(leadingWord);
-
- for (i=0 ; i<numWords ; i++) {
- /*
- * Decide if we can use a frame slot for the var/array name or if we
- * need to emit code to compute and push the name at runtime. We use a
- * frame slot (entry in the array of local vars) if we are compiling a
- * procedure body and if the name is simple text that does not include
- * namespace qualifiers.
- */
-
- PushVarName(interp, varTokenPtr, envPtr, 0,
- &localIndex, &simpleVarName, &isScalar);
-
- /*
- * Emit instructions to unset the variable.
- */
-
- if (!simpleVarName) {
- OP1( UNSET_STK, flags);
- } else if (isScalar) {
- if (localIndex < 0) {
- OP1( UNSET_STK, flags);
- } else {
- OP14( UNSET_SCALAR, flags, localIndex);
- }
- } else {
- if (localIndex < 0) {
- OP1( UNSET_ARRAY_STK, flags);
- } else {
- OP14( UNSET_ARRAY, flags, localIndex);
- }
- }
-
- varTokenPtr = TokenAfter(varTokenPtr);
- }
- PushLiteral(envPtr, "", 0);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileWhileCmd --
- *
- * Procedure called to compile the "while" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "while" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileWhileCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *testTokenPtr, *bodyTokenPtr;
- JumpFixup jumpEvalCondFixup;
- int testCodeOffset, bodyCodeOffset, jumpDist, range, code, boolVal;
- int savedStackDepth = envPtr->currStackDepth;
- int loopMayEnd = 1; /* This is set to 0 if it is recognized as an
- * infinite loop. */
- Tcl_Obj *boolObj;
-
- if (parsePtr->numWords != 3) {
- return TCL_ERROR;
- }
-
- /*
- * If the test expression requires substitutions, don't compile the while
- * command inline. E.g., the expression might cause the loop to never
- * execute or execute forever, as in "while "$x < 5" {}".
- *
- * Bail out also if the body expression requires substitutions in order to
- * insure correct behaviour [Bug 219166]
- */
-
- testTokenPtr = TokenAfter(parsePtr->tokenPtr);
- bodyTokenPtr = TokenAfter(testTokenPtr);
-
- if ((testTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)
- || (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)) {
- return TCL_ERROR;
- }
-
- /*
- * Find out if the condition is a constant.
- */
-
- boolObj = Tcl_NewStringObj(testTokenPtr[1].start, testTokenPtr[1].size);
- Tcl_IncrRefCount(boolObj);
- code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal);
- TclDecrRefCount(boolObj);
- if (code == TCL_OK) {
- if (boolVal) {
- /*
- * It is an infinite loop; flag it so that we generate a more
- * efficient body.
- */
-
- loopMayEnd = 0;
- } else {
- /*
- * This is an empty loop: "while 0 {...}" or such. Compile no
- * bytecodes.
- */
-
- goto pushResult;
- }
- }
-
- /*
- * Create a ExceptionRange record for the loop body. This is used to
- * implement break and continue.
- */
-
- range = DeclareExceptionRange(envPtr, LOOP_EXCEPTION_RANGE);
-
- /*
- * Jump to the evaluation of the condition. This code uses the "loop
- * rotation" optimisation (which eliminates one branch from the loop).
- * "while cond body" produces then:
- * goto A
- * B: body : bodyCodeOffset
- * A: cond -> result : testCodeOffset, continueOffset
- * if (result) goto B
- *
- * The infinite loop "while 1 body" produces:
- * B: body : all three offsets here
- * goto B
- */
-
- if (loopMayEnd) {
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
- &jumpEvalCondFixup);
- testCodeOffset = 0; /* Avoid compiler warning. */
- } else {
- /*
- * Make sure that the first command in the body is preceded by an
- * INST_START_CMD, and hence counted properly. [Bug 1752146]
- */
-
- envPtr->atCmdStart = 0;
- testCodeOffset = CurrentOffset(envPtr);
- }
-
- /*
- * Compile the loop body.
- */
-
- bodyCodeOffset = ExceptionRangeStarts(envPtr, range);
- CompileBody(envPtr, bodyTokenPtr, interp);
- ExceptionRangeEnds(envPtr, range);
- envPtr->currStackDepth = savedStackDepth + 1;
- OP( POP);
-
- /*
- * Compile the test expression then emit the conditional jump that
- * terminates the while. We already know it's a simple word.
- */
-
- if (loopMayEnd) {
- testCodeOffset = CurrentOffset(envPtr);
- jumpDist = testCodeOffset - jumpEvalCondFixup.codeOffset;
- if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) {
- bodyCodeOffset += 3;
- testCodeOffset += 3;
- }
- envPtr->currStackDepth = savedStackDepth;
- TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
- envPtr->currStackDepth = savedStackDepth + 1;
-
- jumpDist = CurrentOffset(envPtr) - bodyCodeOffset;
- if (jumpDist > 127) {
- TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
- } else {
- TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
- }
- } else {
- jumpDist = CurrentOffset(envPtr) - bodyCodeOffset;
- if (jumpDist > 127) {
- TclEmitInstInt4(INST_JUMP4, -jumpDist, envPtr);
- } else {
- TclEmitInstInt1(INST_JUMP1, -jumpDist, envPtr);
- }
- }
-
- /*
- * Set the loop's body, continue and break offsets.
- */
-
- envPtr->exceptArrayPtr[range].continueOffset = testCodeOffset;
- envPtr->exceptArrayPtr[range].codeOffset = bodyCodeOffset;
- ExceptionRangeTarget(envPtr, range, breakOffset);
-
- /*
- * The while command's result is an empty string.
- */
-
- pushResult:
- envPtr->currStackDepth = savedStackDepth;
- PushLiteral(envPtr, "", 0);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileYieldCmd --
- *
- * Procedure called to compile the "yield" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "yield" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileYieldCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- if (parsePtr->numWords < 1 || parsePtr->numWords > 2) {
- return TCL_ERROR;
- }
-
- if (parsePtr->numWords == 1) {
- PushLiteral(envPtr, "", 0);
- } else {
- Tcl_Token *valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
-
- CompileWord(envPtr, valueTokenPtr, interp, 1);
- }
- OP( YIELD);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * PushVarName --
- *
- * Procedure used in the compiling where pushing a variable name is
- * necessary (append, lappend, set).
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "set" command at
- * runtime.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-PushVarName(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Token *varTokenPtr, /* Points to a variable token. */
- CompileEnv *envPtr, /* Holds resulting instructions. */
- int flags, /* TCL_NO_LARGE_INDEX. */
- int *localIndexPtr, /* Must not be NULL. */
- int *simpleVarNamePtr, /* Must not be NULL. */
- int *isScalarPtr) /* Must not be NULL. */
-{
- register const char *p;
- const char *name, *elName;
- register int i, n;
- Tcl_Token *elemTokenPtr = NULL;
- int nameChars, elNameChars, simpleVarName, localIndex;
- int elemTokenCount = 0, allocedTokens = 0, removedParen = 0;
-
- /*
- * Decide if we can use a frame slot for the var/array name or if we need
- * to emit code to compute and push the name at runtime. We use a frame
- * slot (entry in the array of local vars) if we are compiling a procedure
- * body and if the name is simple text that does not include namespace
- * qualifiers.
- */
-
- simpleVarName = 0;
- name = elName = NULL;
- nameChars = elNameChars = 0;
- localIndex = -1;
-
- /*
- * Check not only that the type is TCL_TOKEN_SIMPLE_WORD, but whether
- * curly braces surround the variable name. This really matters for array
- * elements to handle things like
- * set {x($foo)} 5
- * which raises an undefined var error if we are not careful here.
- */
-
- if ((varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) &&
- (varTokenPtr->start[0] != '{')) {
- /*
- * A simple variable name. Divide it up into "name" and "elName"
- * strings. If it is not a local variable, look it up at runtime.
- */
-
- simpleVarName = 1;
-
- name = varTokenPtr[1].start;
- nameChars = varTokenPtr[1].size;
- if (name[nameChars-1] == ')') {
- /*
- * last char is ')' => potential array reference.
- */
-
- for (i=0,p=name ; i<nameChars ; i++,p++) {
- if (*p == '(') {
- elName = p + 1;
- elNameChars = nameChars - i - 2;
- nameChars = i;
- break;
- }
- }
-
- if ((elName != NULL) && elNameChars) {
- /*
- * An array element, the element name is a simple string:
- * assemble the corresponding token.
- */
-
- elemTokenPtr = ckalloc(sizeof(Tcl_Token));
- allocedTokens = 1;
- elemTokenPtr->type = TCL_TOKEN_TEXT;
- elemTokenPtr->start = elName;
- elemTokenPtr->size = elNameChars;
- elemTokenPtr->numComponents = 0;
- elemTokenCount = 1;
- }
- }
- } else if (((n = varTokenPtr->numComponents) > 1)
- && (varTokenPtr[1].type == TCL_TOKEN_TEXT)
- && (varTokenPtr[n].type == TCL_TOKEN_TEXT)
- && (varTokenPtr[n].start[varTokenPtr[n].size - 1] == ')')) {
- /*
- * Check for parentheses inside first token.
- */
-
- simpleVarName = 0;
- for (i = 0, p = varTokenPtr[1].start;
- i < varTokenPtr[1].size; i++, p++) {
- if (*p == '(') {
- simpleVarName = 1;
- break;
- }
- }
- if (simpleVarName) {
- int remainingChars;
-
- /*
- * Check the last token: if it is just ')', do not count it.
- * Otherwise, remove the ')' and flag so that it is restored at
- * the end.
- */
-
- if (varTokenPtr[n].size == 1) {
- n--;
- } else {
- varTokenPtr[n].size--;
- removedParen = n;
- }
-
- name = varTokenPtr[1].start;
- nameChars = p - varTokenPtr[1].start;
- elName = p + 1;
- remainingChars = (varTokenPtr[2].start - p) - 1;
- elNameChars = (varTokenPtr[n].start-p) + varTokenPtr[n].size - 2;
-
- if (remainingChars) {
- /*
- * Make a first token with the extra characters in the first
- * token.
- */
-
- elemTokenPtr = ckalloc(n * sizeof(Tcl_Token));
- allocedTokens = 1;
- elemTokenPtr->type = TCL_TOKEN_TEXT;
- elemTokenPtr->start = elName;
- elemTokenPtr->size = remainingChars;
- elemTokenPtr->numComponents = 0;
- elemTokenCount = n;
-
- /*
- * Copy the remaining tokens.
- */
-
- memcpy(elemTokenPtr+1, varTokenPtr+2,
- (n-1) * sizeof(Tcl_Token));
- } else {
- /*
- * Use the already available tokens.
- */
-
- elemTokenPtr = &varTokenPtr[2];
- elemTokenCount = n - 1;
- }
- }
- }
-
- if (simpleVarName) {
- /*
- * See whether name has any namespace separators (::'s).
- */
-
- int hasNsQualifiers = 0;
-
- for (i = 0, p = name; i < nameChars; i++, p++) {
- if ((*p == ':') && ((i+1) < nameChars) && (*(p+1) == ':')) {
- hasNsQualifiers = 1;
- break;
- }
- }
-
- /*
- * Look up the var name's index in the array of local vars in the proc
- * frame. If retrieving the var's value and it doesn't already exist,
- * push its name and look it up at runtime.
- */
-
- if (!hasNsQualifiers) {
- localIndex = TclFindCompiledLocal(name, nameChars,
- 1, envPtr);
- if ((flags & TCL_NO_LARGE_INDEX) && (localIndex > 255)) {
- /*
- * We'll push the name.
- */
-
- localIndex = -1;
- }
- }
- if (localIndex < 0) {
- PushLiteral(envPtr, name, nameChars);
- }
-
- /*
- * Compile the element script, if any.
- */
-
- if (elName != NULL) {
- if (elNameChars) {
- TclCompileTokens(interp, elemTokenPtr, elemTokenCount,
- envPtr);
- } else {
- PushLiteral(envPtr, "", 0);
- }
- }
- } else {
- /*
- * The var name isn't simple: compile and push it.
- */
-
- CompileTokens(envPtr, varTokenPtr, interp);
- }
-
- if (removedParen) {
- varTokenPtr[removedParen].size++;
- }
- if (allocedTokens) {
- ckfree(elemTokenPtr);
- }
- *localIndexPtr = localIndex;
- *simpleVarNamePtr = simpleVarName;
- *isScalarPtr = (elName == NULL);
- return TCL_OK;
-}
+ OP4(STORE_SCALAR4,(idx))
/*
*----------------------------------------------------------------------
diff --git a/generic/tclCompExpr.c b/generic/tclCompExpr.c
index d93cd77..3fc070c 100644
--- a/generic/tclCompExpr.c
+++ b/generic/tclCompExpr.c
@@ -12,7 +12,7 @@
*/
#include "tclInt.h"
-#include "tclCompile.h" /* CompileEnv */
+#include "tclCompileInt.h" /* CompileEnv */
/*
* Expression parsing takes place in the routine ParseExpr(). It takes a
@@ -2349,11 +2349,7 @@ CompileExprTree(
* command with the correct number of arguments.
*/
- if (numWords < 255) {
- TclEmitInstInt1(INST_INVOKE_STK1, numWords, envPtr);
- } else {
- TclEmitInstInt4(INST_INVOKE_STK4, numWords, envPtr);
- }
+ TclEmitInstInt4(INST_INVOKE_STK4, numWords, envPtr);
/*
* Restore any saved numWords value.
diff --git a/generic/tclCompile.c b/generic/tclCompile.c
index 9681a97..424a6f4 100644
--- a/generic/tclCompile.c
+++ b/generic/tclCompile.c
@@ -13,7 +13,7 @@
*/
#include "tclInt.h"
-#include "tclCompile.h"
+#include "tclCompileInt.h"
/*
* Table of all AuxData types.
@@ -33,10 +33,6 @@ TCL_DECLARE_MUTEX(tableMutex)
* This variable is linked to the Tcl variable "tcl_traceCompile".
*/
-#ifdef TCL_COMPILE_DEBUG
-int tclTraceCompile = 0;
-static int traceInitialized = 0;
-#endif
/*
* A table describing the Tcl bytecode instructions. Entries in this table
@@ -52,488 +48,53 @@ static int traceInitialized = 0;
InstructionDesc const tclInstructionTable[] = {
/* Name Bytes stackEffect #Opnds Operand types */
- {"done", 1, -1, 0, {OPERAND_NONE}},
- /* Finish ByteCode execution and return stktop (top stack item) */
- {"push1", 2, +1, 1, {OPERAND_UINT1}},
- /* Push object at ByteCode objArray[op1] */
- {"push4", 5, +1, 1, {OPERAND_UINT4}},
- /* Push object at ByteCode objArray[op4] */
- {"pop", 1, -1, 0, {OPERAND_NONE}},
- /* Pop the topmost stack object */
- {"dup", 1, +1, 0, {OPERAND_NONE}},
- /* Duplicate the topmost stack object and push the result */
- {"concat1", 2, INT_MIN, 1, {OPERAND_UINT1}},
- /* Concatenate the top op1 items and push result */
- {"invokeStk1", 2, INT_MIN, 1, {OPERAND_UINT1}},
- /* Invoke command named objv[0]; <objc,objv> = <op1,top op1> */
- {"invokeStk4", 5, INT_MIN, 1, {OPERAND_UINT4}},
- /* Invoke command named objv[0]; <objc,objv> = <op4,top op4> */
- {"evalStk", 1, 0, 0, {OPERAND_NONE}},
- /* Evaluate command in stktop using Tcl_EvalObj. */
- {"exprStk", 1, 0, 0, {OPERAND_NONE}},
- /* Execute expression in stktop using Tcl_ExprStringObj. */
-
- {"loadScalar1", 2, 1, 1, {OPERAND_LVT1}},
- /* Load scalar variable at index op1 <= 255 in call frame */
- {"loadScalar4", 5, 1, 1, {OPERAND_LVT4}},
- /* Load scalar variable at index op1 >= 256 in call frame */
- {"loadScalarStk", 1, 0, 0, {OPERAND_NONE}},
- /* Load scalar variable; scalar's name is stktop */
- {"loadArray1", 2, 0, 1, {OPERAND_LVT1}},
- /* Load array element; array at slot op1<=255, element is stktop */
- {"loadArray4", 5, 0, 1, {OPERAND_LVT4}},
- /* Load array element; array at slot op1 > 255, element is stktop */
- {"loadArrayStk", 1, -1, 0, {OPERAND_NONE}},
- /* Load array element; element is stktop, array name is stknext */
- {"loadStk", 1, 0, 0, {OPERAND_NONE}},
- /* Load general variable; unparsed variable name is stktop */
- {"storeScalar1", 2, 0, 1, {OPERAND_LVT1}},
- /* Store scalar variable at op1<=255 in frame; value is stktop */
- {"storeScalar4", 5, 0, 1, {OPERAND_LVT4}},
- /* Store scalar variable at op1 > 255 in frame; value is stktop */
- {"storeScalarStk", 1, -1, 0, {OPERAND_NONE}},
- /* Store scalar; value is stktop, scalar name is stknext */
- {"storeArray1", 2, -1, 1, {OPERAND_LVT1}},
- /* Store array element; array at op1<=255, value is top then elem */
- {"storeArray4", 5, -1, 1, {OPERAND_LVT4}},
- /* Store array element; array at op1>=256, value is top then elem */
- {"storeArrayStk", 1, -2, 0, {OPERAND_NONE}},
- /* Store array element; value is stktop, then elem, array names */
- {"storeStk", 1, -1, 0, {OPERAND_NONE}},
- /* Store general variable; value is stktop, then unparsed name */
-
- {"incrScalar1", 2, 0, 1, {OPERAND_LVT1}},
- /* Incr scalar at index op1<=255 in frame; incr amount is stktop */
- {"incrScalarStk", 1, -1, 0, {OPERAND_NONE}},
- /* Incr scalar; incr amount is stktop, scalar's name is stknext */
- {"incrArray1", 2, -1, 1, {OPERAND_LVT1}},
- /* Incr array elem; arr at slot op1<=255, amount is top then elem */
- {"incrArrayStk", 1, -2, 0, {OPERAND_NONE}},
- /* Incr array element; amount is top then elem then array names */
- {"incrStk", 1, -1, 0, {OPERAND_NONE}},
- /* Incr general variable; amount is stktop then unparsed var name */
- {"incrScalar1Imm", 3, +1, 2, {OPERAND_LVT1, OPERAND_INT1}},
- /* Incr scalar at slot op1 <= 255; amount is 2nd operand byte */
- {"incrScalarStkImm", 2, 0, 1, {OPERAND_INT1}},
- /* Incr scalar; scalar name is stktop; incr amount is op1 */
- {"incrArray1Imm", 3, 0, 2, {OPERAND_LVT1, OPERAND_INT1}},
- /* Incr array elem; array at slot op1 <= 255, elem is stktop,
- * amount is 2nd operand byte */
- {"incrArrayStkImm", 2, -1, 1, {OPERAND_INT1}},
- /* Incr array element; elem is top then array name, amount is op1 */
- {"incrStkImm", 2, 0, 1, {OPERAND_INT1}},
- /* Incr general variable; unparsed name is top, amount is op1 */
-
- {"jump1", 2, 0, 1, {OPERAND_INT1}},
- /* Jump relative to (pc + op1) */
- {"jump4", 5, 0, 1, {OPERAND_INT4}},
- /* Jump relative to (pc + op4) */
- {"jumpTrue1", 2, -1, 1, {OPERAND_INT1}},
- /* Jump relative to (pc + op1) if stktop expr object is true */
- {"jumpTrue4", 5, -1, 1, {OPERAND_INT4}},
- /* Jump relative to (pc + op4) if stktop expr object is true */
- {"jumpFalse1", 2, -1, 1, {OPERAND_INT1}},
- /* Jump relative to (pc + op1) if stktop expr object is false */
- {"jumpFalse4", 5, -1, 1, {OPERAND_INT4}},
- /* Jump relative to (pc + op4) if stktop expr object is false */
-
- {"lor", 1, -1, 0, {OPERAND_NONE}},
- /* Logical or: push (stknext || stktop) */
- {"land", 1, -1, 0, {OPERAND_NONE}},
- /* Logical and: push (stknext && stktop) */
- {"bitor", 1, -1, 0, {OPERAND_NONE}},
- /* Bitwise or: push (stknext | stktop) */
- {"bitxor", 1, -1, 0, {OPERAND_NONE}},
- /* Bitwise xor push (stknext ^ stktop) */
- {"bitand", 1, -1, 0, {OPERAND_NONE}},
- /* Bitwise and: push (stknext & stktop) */
- {"eq", 1, -1, 0, {OPERAND_NONE}},
- /* Equal: push (stknext == stktop) */
- {"neq", 1, -1, 0, {OPERAND_NONE}},
- /* Not equal: push (stknext != stktop) */
- {"lt", 1, -1, 0, {OPERAND_NONE}},
- /* Less: push (stknext < stktop) */
- {"gt", 1, -1, 0, {OPERAND_NONE}},
- /* Greater: push (stknext > stktop) */
- {"le", 1, -1, 0, {OPERAND_NONE}},
- /* Less or equal: push (stknext <= stktop) */
- {"ge", 1, -1, 0, {OPERAND_NONE}},
- /* Greater or equal: push (stknext >= stktop) */
- {"lshift", 1, -1, 0, {OPERAND_NONE}},
- /* Left shift: push (stknext << stktop) */
- {"rshift", 1, -1, 0, {OPERAND_NONE}},
- /* Right shift: push (stknext >> stktop) */
- {"add", 1, -1, 0, {OPERAND_NONE}},
- /* Add: push (stknext + stktop) */
- {"sub", 1, -1, 0, {OPERAND_NONE}},
- /* Sub: push (stkext - stktop) */
- {"mult", 1, -1, 0, {OPERAND_NONE}},
- /* Multiply: push (stknext * stktop) */
- {"div", 1, -1, 0, {OPERAND_NONE}},
- /* Divide: push (stknext / stktop) */
- {"mod", 1, -1, 0, {OPERAND_NONE}},
- /* Mod: push (stknext % stktop) */
- {"uplus", 1, 0, 0, {OPERAND_NONE}},
- /* Unary plus: push +stktop */
- {"uminus", 1, 0, 0, {OPERAND_NONE}},
- /* Unary minus: push -stktop */
- {"bitnot", 1, 0, 0, {OPERAND_NONE}},
- /* Bitwise not: push ~stktop */
- {"not", 1, 0, 0, {OPERAND_NONE}},
- /* Logical not: push !stktop */
- {"callBuiltinFunc1", 2, 1, 1, {OPERAND_UINT1}},
- /* Call builtin math function with index op1; any args are on stk */
- {"callFunc1", 2, INT_MIN, 1, {OPERAND_UINT1}},
- /* Call non-builtin func objv[0]; <objc,objv>=<op1,top op1> */
- {"tryCvtToNumeric", 1, 0, 0, {OPERAND_NONE}},
- /* Try converting stktop to first int then double if possible. */
-
- {"break", 1, 0, 0, {OPERAND_NONE}},
- /* Abort closest enclosing loop; if none, return TCL_BREAK code. */
- {"continue", 1, 0, 0, {OPERAND_NONE}},
- /* Skip to next iteration of closest enclosing loop; if none, return
- * TCL_CONTINUE code. */
-
- {"foreach_start4", 5, 0, 1, {OPERAND_AUX4}},
- /* Initialize execution of a foreach loop. Operand is aux data index
- * of the ForeachInfo structure for the foreach command. */
- {"foreach_step4", 5, +1, 1, {OPERAND_AUX4}},
- /* "Step" or begin next iteration of foreach loop. Push 0 if to
- * terminate loop, else push 1. */
-
- {"beginCatch4", 5, 0, 1, {OPERAND_UINT4}},
- /* Record start of catch with the operand's exception index. Push the
- * current stack depth onto a special catch stack. */
- {"endCatch", 1, 0, 0, {OPERAND_NONE}},
- /* End of last catch. Pop the bytecode interpreter's catch stack. */
- {"pushResult", 1, +1, 0, {OPERAND_NONE}},
- /* Push the interpreter's object result onto the stack. */
- {"pushReturnCode", 1, +1, 0, {OPERAND_NONE}},
- /* Push interpreter's return code (e.g. TCL_OK or TCL_ERROR) as a new
- * object onto the stack. */
-
- {"streq", 1, -1, 0, {OPERAND_NONE}},
- /* Str Equal: push (stknext eq stktop) */
- {"strneq", 1, -1, 0, {OPERAND_NONE}},
- /* Str !Equal: push (stknext neq stktop) */
- {"strcmp", 1, -1, 0, {OPERAND_NONE}},
- /* Str Compare: push (stknext cmp stktop) */
- {"strlen", 1, 0, 0, {OPERAND_NONE}},
- /* Str Length: push (strlen stktop) */
- {"strindex", 1, -1, 0, {OPERAND_NONE}},
- /* Str Index: push (strindex stknext stktop) */
- {"strmatch", 2, -1, 1, {OPERAND_INT1}},
- /* Str Match: push (strmatch stknext stktop) opnd == nocase */
-
- {"list", 5, INT_MIN, 1, {OPERAND_UINT4}},
- /* List: push (stk1 stk2 ... stktop) */
- {"listIndex", 1, -1, 0, {OPERAND_NONE}},
- /* List Index: push (listindex stknext stktop) */
- {"listLength", 1, 0, 0, {OPERAND_NONE}},
- /* List Len: push (listlength stktop) */
-
- {"appendScalar1", 2, 0, 1, {OPERAND_LVT1}},
- /* Append scalar variable at op1<=255 in frame; value is stktop */
- {"appendScalar4", 5, 0, 1, {OPERAND_LVT4}},
- /* Append scalar variable at op1 > 255 in frame; value is stktop */
- {"appendArray1", 2, -1, 1, {OPERAND_LVT1}},
- /* Append array element; array at op1<=255, value is top then elem */
- {"appendArray4", 5, -1, 1, {OPERAND_LVT4}},
- /* Append array element; array at op1>=256, value is top then elem */
- {"appendArrayStk", 1, -2, 0, {OPERAND_NONE}},
- /* Append array element; value is stktop, then elem, array names */
- {"appendStk", 1, -1, 0, {OPERAND_NONE}},
- /* Append general variable; value is stktop, then unparsed name */
- {"lappendScalar1", 2, 0, 1, {OPERAND_LVT1}},
- /* Lappend scalar variable at op1<=255 in frame; value is stktop */
- {"lappendScalar4", 5, 0, 1, {OPERAND_LVT4}},
- /* Lappend scalar variable at op1 > 255 in frame; value is stktop */
- {"lappendArray1", 2, -1, 1, {OPERAND_LVT1}},
- /* Lappend array element; array at op1<=255, value is top then elem */
- {"lappendArray4", 5, -1, 1, {OPERAND_LVT4}},
- /* Lappend array element; array at op1>=256, value is top then elem */
- {"lappendArrayStk", 1, -2, 0, {OPERAND_NONE}},
- /* Lappend array element; value is stktop, then elem, array names */
- {"lappendStk", 1, -1, 0, {OPERAND_NONE}},
- /* Lappend general variable; value is stktop, then unparsed name */
-
- {"lindexMulti", 5, INT_MIN, 1, {OPERAND_UINT4}},
- /* Lindex with generalized args, operand is number of stacked objs
- * used: (operand-1) entries from stktop are the indices; then list to
- * process. */
- {"over", 5, +1, 1, {OPERAND_UINT4}},
- /* Duplicate the arg-th element from top of stack (TOS=0) */
- {"lsetList", 1, -2, 0, {OPERAND_NONE}},
- /* Four-arg version of 'lset'. stktop is old value; next is new
- * element value, next is the index list; pushes new value */
- {"lsetFlat", 5, INT_MIN, 1, {OPERAND_UINT4}},
- /* Three- or >=5-arg version of 'lset', operand is number of stacked
- * objs: stktop is old value, next is new element value, next come
- * (operand-2) indices; pushes the new value.
- */
-
- {"returnImm", 9, -1, 2, {OPERAND_INT4, OPERAND_UINT4}},
- /* Compiled [return], code, level are operands; options and result
- * are on the stack. */
- {"expon", 1, -1, 0, {OPERAND_NONE}},
- /* Binary exponentiation operator: push (stknext ** stktop) */
-
- /*
- * NOTE: the stack effects of expandStkTop and invokeExpanded are wrong -
- * but it cannot be done right at compile time, the stack effect is only
- * known at run time. The value for invokeExpanded is estimated better at
- * compile time.
- * See the comments further down in this file, where INST_INVOKE_EXPANDED
- * is emitted.
- */
- {"expandStart", 1, 0, 0, {OPERAND_NONE}},
- /* Start of command with {*} (expanded) arguments */
- {"expandStkTop", 5, 0, 1, {OPERAND_UINT4}},
- /* Expand the list at stacktop: push its elements on the stack */
- {"invokeExpanded", 1, 0, 0, {OPERAND_NONE}},
- /* Invoke the command marked by the last 'expandStart' */
-
- {"listIndexImm", 5, 0, 1, {OPERAND_IDX4}},
- /* List Index: push (lindex stktop op4) */
- {"listRangeImm", 9, 0, 2, {OPERAND_IDX4, OPERAND_IDX4}},
- /* List Range: push (lrange stktop op4 op4) */
- {"startCommand", 9, 0, 2, {OPERAND_INT4,OPERAND_UINT4}},
- /* Start of bytecoded command: op is the length of the cmd's code, op2
- * is number of commands here */
-
- {"listIn", 1, -1, 0, {OPERAND_NONE}},
- /* List containment: push [lsearch stktop stknext]>=0) */
- {"listNotIn", 1, -1, 0, {OPERAND_NONE}},
- /* List negated containment: push [lsearch stktop stknext]<0) */
-
- {"pushReturnOpts", 1, +1, 0, {OPERAND_NONE}},
- /* Push the interpreter's return option dictionary as an object on the
- * stack. */
- {"returnStk", 1, -2, 0, {OPERAND_NONE}},
- /* Compiled [return]; options and result are on the stack, code and
- * level are in the options. */
-
- {"dictGet", 5, INT_MIN, 1, {OPERAND_UINT4}},
- /* The top op4 words (min 1) are a key path into the dictionary just
- * below the keys on the stack, and all those values are replaced by
- * the value read out of that key-path (like [dict get]).
- * Stack: ... dict key1 ... keyN => ... value */
- {"dictSet", 9, INT_MIN, 2, {OPERAND_UINT4, OPERAND_LVT4}},
- /* Update a dictionary value such that the keys are a path pointing to
- * the value. op4#1 = numKeys, op4#2 = LVTindex
- * Stack: ... key1 ... keyN value => ... newDict */
- {"dictUnset", 9, INT_MIN, 2, {OPERAND_UINT4, OPERAND_LVT4}},
- /* Update a dictionary value such that the keys are not a path pointing
- * to any value. op4#1 = numKeys, op4#2 = LVTindex
- * Stack: ... key1 ... keyN => ... newDict */
- {"dictIncrImm", 9, 0, 2, {OPERAND_INT4, OPERAND_LVT4}},
- /* Update a dictionary value such that the value pointed to by key is
- * incremented by some value (or set to it if the key isn't in the
- * dictionary at all). op4#1 = incrAmount, op4#2 = LVTindex
- * Stack: ... key => ... newDict */
- {"dictAppend", 5, -1, 1, {OPERAND_LVT4}},
- /* Update a dictionary value such that the value pointed to by key has
- * some value string-concatenated onto it. op4 = LVTindex
- * Stack: ... key valueToAppend => ... newDict */
- {"dictLappend", 5, -1, 1, {OPERAND_LVT4}},
- /* Update a dictionary value such that the value pointed to by key has
- * some value list-appended onto it. op4 = LVTindex
- * Stack: ... key valueToAppend => ... newDict */
- {"dictFirst", 5, +2, 1, {OPERAND_LVT4}},
- /* Begin iterating over the dictionary, using the local scalar
- * indicated by op4 to hold the iterator state. The local scalar
- * should not refer to a named variable as the value is not wholly
- * managed correctly.
- * Stack: ... dict => ... value key doneBool */
- {"dictNext", 5, +3, 1, {OPERAND_LVT4}},
- /* Get the next iteration from the iterator in op4's local scalar.
- * Stack: ... => ... value key doneBool */
- {"dictDone", 5, 0, 1, {OPERAND_LVT4}},
- /* Terminate the iterator in op4's local scalar. Use unsetScalar
- * instead (with 0 for flags). */
- {"dictUpdateStart", 9, 0, 2, {OPERAND_LVT4, OPERAND_AUX4}},
- /* Create the variables (described in the aux data referred to by the
- * second immediate argument) to mirror the state of the dictionary in
- * the variable referred to by the first immediate argument. The list
- * of keys (top of the stack, not poppsed) must be the same length as
- * the list of variables.
- * Stack: ... keyList => ... keyList */
- {"dictUpdateEnd", 9, -1, 2, {OPERAND_LVT4, OPERAND_AUX4}},
- /* Reflect the state of local variables (described in the aux data
- * referred to by the second immediate argument) back to the state of
- * the dictionary in the variable referred to by the first immediate
- * argument. The list of keys (popped from the stack) must be the same
- * length as the list of variables.
- * Stack: ... keyList => ... */
- {"jumpTable", 5, -1, 1, {OPERAND_AUX4}},
- /* Jump according to the jump-table (in AuxData as indicated by the
- * operand) and the argument popped from the list. Always executes the
- * next instruction if no match against the table's entries was found.
- * Stack: ... value => ...
- * Note that the jump table contains offsets relative to the PC when
- * it points to this instruction; the code is relocatable. */
- {"upvar", 5, -1, 1, {OPERAND_LVT4}},
- /* finds level and otherName in stack, links to local variable at
- * index op1. Leaves the level on stack. */
- {"nsupvar", 5, -1, 1, {OPERAND_LVT4}},
- /* finds namespace and otherName in stack, links to local variable at
- * index op1. Leaves the namespace on stack. */
- {"variable", 5, -1, 1, {OPERAND_LVT4}},
- /* finds namespace and otherName in stack, links to local variable at
- * index op1. Leaves the namespace on stack. */
- {"syntax", 9, -1, 2, {OPERAND_INT4, OPERAND_UINT4}},
- /* Compiled bytecodes to signal syntax error. */
- {"reverse", 5, 0, 1, {OPERAND_UINT4}},
- /* Reverse the order of the arg elements at the top of stack */
-
- {"regexp", 2, -1, 1, {OPERAND_INT1}},
- /* Regexp: push (regexp stknext stktop) opnd == nocase */
-
- {"existScalar", 5, 1, 1, {OPERAND_LVT4}},
- /* Test if scalar variable at index op1 in call frame exists */
- {"existArray", 5, 0, 1, {OPERAND_LVT4}},
- /* Test if array element exists; array at slot op1, element is
- * stktop */
- {"existArrayStk", 1, -1, 0, {OPERAND_NONE}},
- /* Test if array element exists; element is stktop, array name is
- * stknext */
- {"existStk", 1, 0, 0, {OPERAND_NONE}},
- /* Test if general variable exists; unparsed variable name is stktop*/
-
- {"nop", 1, 0, 0, {OPERAND_NONE}},
- /* Do nothing */
- {"returnCodeBranch", 1, -1, 0, {OPERAND_NONE}},
- /* Jump to next instruction based on the return code on top of stack
- * ERROR: +1; RETURN: +3; BREAK: +5; CONTINUE: +7;
- * Other non-OK: +9
- */
-
- {"unsetScalar", 6, 0, 2, {OPERAND_UINT1, OPERAND_LVT4}},
- /* Make scalar variable at index op2 in call frame cease to exist;
- * op1 is 1 for errors on problems, 0 otherwise */
- {"unsetArray", 6, -1, 2, {OPERAND_UINT1, OPERAND_LVT4}},
- /* Make array element cease to exist; array at slot op2, element is
- * stktop; op1 is 1 for errors on problems, 0 otherwise */
- {"unsetArrayStk", 2, -2, 1, {OPERAND_UINT1}},
- /* Make array element cease to exist; element is stktop, array name is
- * stknext; op1 is 1 for errors on problems, 0 otherwise */
- {"unsetStk", 2, -1, 1, {OPERAND_UINT1}},
- /* Make general variable cease to exist; unparsed variable name is
- * stktop; op1 is 1 for errors on problems, 0 otherwise */
-
- {"dictExpand", 1, -1, 0, {OPERAND_NONE}},
- /* Probe into a dict and extract it (or a subdict of it) into
- * variables with matched names. Produces list of keys bound as
- * result. Part of [dict with].
- * Stack: ... dict path => ... keyList */
- {"dictRecombineStk", 1, -3, 0, {OPERAND_NONE}},
- /* Map variable contents back into a dictionary in a variable. Part of
- * [dict with].
- * Stack: ... dictVarName path keyList => ... */
- {"dictRecombineImm", 1, -2, 1, {OPERAND_LVT4}},
- /* Map variable contents back into a dictionary in the local variable
- * indicated by the LVT index. Part of [dict with].
- * Stack: ... path keyList => ... */
- {"dictExists", 5, INT_MIN, 1, {OPERAND_UINT4}},
- /* The top op4 words (min 1) are a key path into the dictionary just
- * below the keys on the stack, and all those values are replaced by a
- * boolean indicating whether it is possible to read out a value from
- * that key-path (like [dict exists]).
- * Stack: ... dict key1 ... keyN => ... boolean */
- {"verifyDict", 1, -1, 0, {OPERAND_NONE}},
- /* Verifies that the word on the top of the stack is a dictionary,
- * popping it if it is and throwing an error if it is not.
- * Stack: ... value => ... */
-
- {"strmap", 1, -2, 0, {OPERAND_NONE}},
- /* Simplified version of [string map] that only applies one change
- * string, and only case-sensitively.
- * Stack: ... from to string => ... changedString */
- {"strfind", 1, -1, 0, {OPERAND_NONE}},
- /* Find the first index of a needle string in a haystack string,
- * producing the index (integer) or -1 if nothing found.
- * Stack: ... needle haystack => ... index */
- {"strrfind", 1, -1, 0, {OPERAND_NONE}},
- /* Find the last index of a needle string in a haystack string,
- * producing the index (integer) or -1 if nothing found.
- * Stack: ... needle haystack => ... index */
- {"strrangeImm", 9, 0, 2, {OPERAND_IDX4, OPERAND_IDX4}},
- /* String Range: push (string range stktop op4 op4) */
- {"strrange", 1, -2, 0, {OPERAND_NONE}},
- /* String Range with non-constant arguments.
- * Stack: ... string idxA idxB => ... substring */
-
- {"yield", 1, 0, 0, {OPERAND_NONE}},
- /* Makes the current coroutine yield the value at the top of the
- * stack, and places the response back on top of the stack when it
- * resumes.
- * Stack: ... valueToYield => ... resumeValue */
- {"coroName", 1, +1, 0, {OPERAND_NONE}},
- /* Push the name of the interpreter's current coroutine as an object
- * on the stack. */
- {"tailcall", 2, INT_MIN, 1, {OPERAND_UINT1}},
- /* Do a tailcall with the opnd items on the stack as the thing to
- * tailcall to; opnd must be greater than 0 for the semantics to work
- * right. */
-
- {"currentNamespace", 1, +1, 0, {OPERAND_NONE}},
- /* Push the name of the interpreter's current namespace as an object
- * on the stack. */
- {"infoLevelNumber", 1, +1, 0, {OPERAND_NONE}},
- /* Push the stack depth (i.e., [info level]) of the interpreter as an
- * object on the stack. */
- {"infoLevelArgs", 1, 0, 0, {OPERAND_NONE}},
- /* Push the argument words to a stack depth (i.e., [info level <n>])
- * of the interpreter as an object on the stack.
- * Stack: ... depth => ... argList */
- {"resolveCmd", 1, 0, 0, {OPERAND_NONE}},
- /* Resolves the command named on the top of the stack to its fully
- * qualified version, or produces the empty string if no such command
- * exists. Never generates errors.
- * Stack: ... cmdName => ... fullCmdName */
- {"tclooSelf", 1, +1, 0, {OPERAND_NONE}},
- /* Push the identity of the current TclOO object (i.e., the name of
- * its current public access command) on the stack. */
- {"tclooClass", 1, 0, 0, {OPERAND_NONE}},
- /* Push the class of the TclOO object named at the top of the stack
- * onto the stack.
- * Stack: ... object => ... class */
- {"tclooNamespace", 1, 0, 0, {OPERAND_NONE}},
- /* Push the namespace of the TclOO object named at the top of the
- * stack onto the stack.
- * Stack: ... object => ... namespace */
- {"tclooIsObject", 1, 0, 0, {OPERAND_NONE}},
- /* Push whether the value named at the top of the stack is a TclOO
- * object (i.e., a boolean). Can corrupt the interpreter result
- * despite not throwing, so not safe for use in a post-exception
- * context.
- * Stack: ... value => ... boolean */
-
- {"arrayExistsStk", 1, 0, 0, {OPERAND_NONE}},
- /* Looks up the element on the top of the stack and tests whether it
- * is an array. Pushes a boolean describing whether this is the
- * case. Also runs the whole-array trace on the named variable, so can
- * throw anything.
- * Stack: ... varName => ... boolean */
- {"arrayExistsImm", 5, +1, 1, {OPERAND_UINT4}},
- /* Looks up the variable indexed by opnd and tests whether it is an
- * array. Pushes a boolean describing whether this is the case. Also
- * runs the whole-array trace on the named variable, so can throw
- * anything.
- * Stack: ... => ... boolean */
- {"arrayMakeStk", 1, -1, 0, {OPERAND_NONE}},
- /* Forces the element on the top of the stack to be the name of an
- * array.
- * Stack: ... varName => ... */
- {"arrayMakeImm", 5, 0, 1, {OPERAND_UINT4}},
- /* Forces the variable indexed by opnd to be an array. Does not touch
- * the stack. */
-
- {"invokeReplace", 6, INT_MIN, 2, {OPERAND_UINT4,OPERAND_UINT1}},
- /* Invoke command named objv[0], replacing the first two words with
- * the word at the top of the stack;
- * <objc,objv> = <op4,top op4 after popping 1> */
-
+ {"done", 1, -1, 0, {OPERAND_NONE}},//0
+ {"push4", 5, +1, 1, {OPERAND_UINT4}},//1
+ {"pop", 1, -1, 0, {OPERAND_NONE}},//2
+ {"concat1", 2, INT_MIN, 1, {OPERAND_UINT1}},//3
+ {"invokeStk4", 5, INT_MIN, 1, {OPERAND_UINT4}},//4
+ {"loadScalar4", 5, 1, 1, {OPERAND_LVT4}},//5
+ {"loadScalarStk", 1, 0, 0, {OPERAND_NONE}},//6
+ {"loadArray4", 5, 0, 1, {OPERAND_LVT4}},//7
+ {"loadArrayStk", 1, -1, 0, {OPERAND_NONE}},//8
+ {"storeScalar4", 5, 0, 1, {OPERAND_LVT4}},//9
+ {"jump4", 5, 0, 1, {OPERAND_INT4}},//10
+ {"jumpTrue4", 5, -1, 1, {OPERAND_INT4}},//11
+ {"jumpFalse4", 5, -1, 1, {OPERAND_INT4}},//12
+ {"bitor", 1, -1, 0, {OPERAND_NONE}},//13
+ {"bitxor", 1, -1, 0, {OPERAND_NONE}},//14
+ {"bitand", 1, -1, 0, {OPERAND_NONE}},//15
+ {"eq", 1, -1, 0, {OPERAND_NONE}},//16
+ {"neq", 1, -1, 0, {OPERAND_NONE}},//17
+ {"lt", 1, -1, 0, {OPERAND_NONE}},//18
+ {"gt", 1, -1, 0, {OPERAND_NONE}},//19
+ {"le", 1, -1, 0, {OPERAND_NONE}},//20
+ {"ge", 1, -1, 0, {OPERAND_NONE}},//21
+ {"lshift", 1, -1, 0, {OPERAND_NONE}},//22
+ {"rshift", 1, -1, 0, {OPERAND_NONE}},//23
+ {"add", 1, -1, 0, {OPERAND_NONE}},//24
+ {"sub", 1, -1, 0, {OPERAND_NONE}},//25
+ {"mult", 1, -1, 0, {OPERAND_NONE}},//26
+ {"div", 1, -1, 0, {OPERAND_NONE}},//27
+ {"mod", 1, -1, 0, {OPERAND_NONE}},//28
+ {"uplus", 1, 0, 0, {OPERAND_NONE}},//29
+ {"uminus", 1, 0, 0, {OPERAND_NONE}},//30
+ {"bitnot", 1, 0, 0, {OPERAND_NONE}},//31
+ {"not", 1, 0, 0, {OPERAND_NONE}},//32
+ {"tryCvtToNumeric", 1, 0, 0, {OPERAND_NONE}},//33
+ {"streq", 1, -1, 0, {OPERAND_NONE}},//34
+ {"strneq", 1, -1, 0, {OPERAND_NONE}},//35
+ {"expon", 1, -1, 0, {OPERAND_NONE}},//36
+ {"expandStart", 1, 0, 0, {OPERAND_NONE}},//37
+ {"expandStkTop", 5, 0, 1, {OPERAND_UINT4}},//38
+ {"invokeExpanded", 1, 0, 0, {OPERAND_NONE}},//39
+ {"listIn", 1, -1, 0, {OPERAND_NONE}},//40
+ {"listNotIn", 1, -1, 0, {OPERAND_NONE}},//41
+ {"syntax", 9, -1, 2, {OPERAND_INT4, OPERAND_UINT4}},//42
+ {"reverse", 5, 0, 1, {OPERAND_UINT4}},//43
+ {"unsetScalar", 6, 0, 2, {OPERAND_UINT1, OPERAND_LVT4}},//44
+ {"currentNamespace", 1, +1, 0, {OPERAND_NONE}},//45
+ {"tclooSelf", 1, +1, 0, {OPERAND_NONE}},//46
{NULL, 0, 0, 0, {OPERAND_NONE}}
};
@@ -541,8 +102,6 @@ InstructionDesc const tclInstructionTable[] = {
* Prototypes for procedures defined later in this file:
*/
-static ByteCode * CompileSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
- int flags);
static void DupByteCodeInternalRep(Tcl_Obj *srcPtr,
Tcl_Obj *copyPtr);
static unsigned char * EncodeCmdLocMap(CompileEnv *envPtr,
@@ -552,17 +111,9 @@ static void EnterCmdExtentData(CompileEnv *envPtr,
static void EnterCmdStartData(CompileEnv *envPtr,
int cmdNumber, int srcOffset, int codeOffset);
static void FreeByteCodeInternalRep(Tcl_Obj *objPtr);
-static void FreeSubstCodeInternalRep(Tcl_Obj *objPtr);
static int GetCmdLocEncodingSize(CompileEnv *envPtr);
-#ifdef TCL_COMPILE_STATS
-static void RecordByteCodeStats(ByteCode *codePtr);
-#endif /* TCL_COMPILE_STATS */
static int SetByteCodeFromAny(Tcl_Interp *interp,
Tcl_Obj *objPtr);
-static int FormatInstruction(ByteCode *codePtr,
- const unsigned char *pc, Tcl_Obj *bufferObj);
-static void PrintSourceToObj(Tcl_Obj *appendObj,
- const char *stringPtr, int maxChars);
/*
* The structure below defines the bytecode Tcl object type by means of
@@ -577,19 +128,6 @@ const Tcl_ObjType tclByteCodeType = {
SetByteCodeFromAny /* setFromAnyProc */
};
-/*
- * The structure below defines a bytecode Tcl object type to hold the
- * compiled bytecode for the [subst]itution of Tcl values.
- */
-
-static const Tcl_ObjType substCodeType = {
- "substcode", /* name */
- FreeSubstCodeInternalRep, /* freeIntRepProc */
- DupByteCodeInternalRep, /* dupIntRepProc - shared with bytecode */
- NULL, /* updateStringProc */
- NULL, /* setFromAnyProc */
-};
-
/*
*----------------------------------------------------------------------
@@ -633,16 +171,6 @@ TclSetByteCodeFromAny(
int length, result = TCL_OK;
const char *stringPtr;
-#ifdef TCL_COMPILE_DEBUG
- if (!traceInitialized) {
- if (Tcl_LinkVar(interp, "tcl_traceCompile",
- (char *) &tclTraceCompile, TCL_LINK_INT) != TCL_OK) {
- Tcl_Panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable");
- }
- traceInitialized = 1;
- }
-#endif
-
stringPtr = TclGetStringFromObj(objPtr, &length);
TclInitCompileEnv(interp, &compEnv, stringPtr, length);
@@ -680,18 +208,7 @@ TclSetByteCodeFromAny(
* objects and aux data items is given to the ByteCode object.
*/
-#ifdef TCL_COMPILE_DEBUG
- TclVerifyLocalLiteralTable(&compEnv);
-#endif /*TCL_COMPILE_DEBUG*/
-
TclInitByteCodeObj(objPtr, &compEnv);
-#ifdef TCL_COMPILE_DEBUG
- if (tclTraceCompile >= 2) {
- TclPrintByteCodeObj(interp, objPtr);
- fflush(stdout);
- }
-#endif /* TCL_COMPILE_DEBUG */
-
if (result != TCL_OK) {
/*
* Handle any error from the hookProc
@@ -702,9 +219,6 @@ TclSetByteCodeFromAny(
TclReleaseLiteral(interp, entryPtr->objPtr);
entryPtr++;
}
-#ifdef TCL_COMPILE_DEBUG
- TclVerifyGlobalLiteralTable((Interp *)interp);
-#endif /*TCL_COMPILE_DEBUG*/
auxDataPtr = compEnv.auxDataArrayPtr;
for (i = 0; i < compEnv.auxDataArrayNext; i++) {
@@ -846,44 +360,6 @@ TclCleanupByteCode(
register Tcl_Obj **objArrayPtr, *objPtr;
register const AuxData *auxDataPtr;
int i;
-#ifdef TCL_COMPILE_STATS
-
- if (interp != NULL) {
- ByteCodeStats *statsPtr;
- Tcl_Time destroyTime;
- int lifetimeSec, lifetimeMicroSec, log2;
-
- statsPtr = &((Interp *)interp)->stats;
-
- statsPtr->numByteCodesFreed++;
- statsPtr->currentSrcBytes -= (double) codePtr->numSrcBytes;
- statsPtr->currentByteCodeBytes -= (double) codePtr->structureSize;
-
- statsPtr->currentInstBytes -= (double) codePtr->numCodeBytes;
- statsPtr->currentLitBytes -= (double)
- codePtr->numLitObjects * sizeof(Tcl_Obj *);
- statsPtr->currentExceptBytes -= (double)
- codePtr->numExceptRanges * sizeof(ExceptionRange);
- statsPtr->currentAuxBytes -= (double)
- codePtr->numAuxDataItems * sizeof(AuxData);
- statsPtr->currentCmdMapBytes -= (double) codePtr->numCmdLocBytes;
-
- Tcl_GetTime(&destroyTime);
- lifetimeSec = destroyTime.sec - codePtr->createTime.sec;
- if (lifetimeSec > 2000) { /* avoid overflow */
- lifetimeSec = 2000;
- }
- lifetimeMicroSec = 1000000 * lifetimeSec +
- (destroyTime.usec - codePtr->createTime.usec);
-
- log2 = TclLog2(lifetimeMicroSec);
- if (log2 > 31) {
- log2 = 31;
- }
- statsPtr->lifetimeCount[log2]++;
- }
-#endif /* TCL_COMPILE_STATS */
-
/*
* A single heap object holds the ByteCode structure and its code, object,
* command location, and auxiliary data arrays. This means we only need to
@@ -951,174 +427,6 @@ TclCleanupByteCode(
/*
*----------------------------------------------------------------------
*
- * Tcl_SubstObj --
- *
- * This function performs the substitutions specified on the given string
- * as described in the user documentation for the "subst" Tcl command.
- *
- * Results:
- * A Tcl_Obj* containing the substituted string, or NULL to indicate that
- * an error occurred.
- *
- * Side effects:
- * See the user documentation.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Obj *
-Tcl_SubstObj(
- Tcl_Interp *interp, /* Interpreter in which substitution occurs */
- Tcl_Obj *objPtr, /* The value to be substituted. */
- int flags) /* What substitutions to do. */
-{
- TclNRSetRoot(interp);
- if (TclNRRunCallbacks(interp, Tcl_NRSubstObj(interp, objPtr, flags))
- != TCL_OK) {
- return NULL;
- }
- return Tcl_GetObjResult(interp);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_NRSubstObj --
- *
- * Request substitution of a Tcl value by the NR stack.
- *
- * Results:
- * Returns TCL_OK.
- *
- * Side effects:
- * Compiles objPtr into bytecode that performs the substitutions as
- * governed by flags and places callbacks on the NR stack to execute
- * the bytecode and store the result in the interp.
- *
- *----------------------------------------------------------------------
- */
-
-int
-Tcl_NRSubstObj(
- Tcl_Interp *interp,
- Tcl_Obj *objPtr,
- int flags)
-{
- ByteCode *codePtr = CompileSubstObj(interp, objPtr, flags);
-
- /* TODO: Confirm we do not need this. */
- /* Tcl_ResetResult(interp); */
- return TclNRExecuteByteCode(interp, codePtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CompileSubstObj --
- *
- * Compile a Tcl value into ByteCode implementing its substitution, as
- * governed by flags.
- *
- * Results:
- * A (ByteCode *) is returned pointing to the resulting ByteCode.
- * The caller must manage its refCount and arrange for a call to
- * TclCleanupByteCode() when the last reference disappears.
- *
- * Side effects:
- * The Tcl_ObjType of objPtr is changed to the "substcode" type, and the
- * ByteCode and governing flags value are kept in the internal rep for
- * faster operations the next time CompileSubstObj is called on the same
- * value.
- *
- *----------------------------------------------------------------------
- */
-
-static ByteCode *
-CompileSubstObj(
- Tcl_Interp *interp,
- Tcl_Obj *objPtr,
- int flags)
-{
- Interp *iPtr = (Interp *) interp;
- ByteCode *codePtr = NULL;
-
- if (objPtr->typePtr == &substCodeType) {
- Namespace *nsPtr = iPtr->varFramePtr->nsPtr;
-
- codePtr = objPtr->internalRep.ptrAndLongRep.ptr;
- if ((unsigned long)flags != objPtr->internalRep.ptrAndLongRep.value
- || ((Interp *) *codePtr->interpHandle != iPtr)
- || (codePtr->compileEpoch != iPtr->compileEpoch)
- || (codePtr->nsPtr != nsPtr)
- || (codePtr->nsEpoch != nsPtr->resolverEpoch)
- || (codePtr->localCachePtr !=
- iPtr->varFramePtr->localCachePtr)) {
- FreeSubstCodeInternalRep(objPtr);
- }
- }
- if (objPtr->typePtr != &substCodeType) {
- CompileEnv compEnv;
- int numBytes;
- const char *bytes = Tcl_GetStringFromObj(objPtr, &numBytes);
-
- TclInitCompileEnv(interp, &compEnv, bytes, numBytes);
-
- TclSubstCompile(interp, bytes, numBytes, flags, &compEnv);
-
- TclEmitOpcode(INST_DONE, &compEnv);
- TclInitByteCodeObj(objPtr, &compEnv);
- objPtr->typePtr = &substCodeType;
- TclFreeCompileEnv(&compEnv);
-
- codePtr = objPtr->internalRep.otherValuePtr;
- objPtr->internalRep.ptrAndLongRep.ptr = codePtr;
- objPtr->internalRep.ptrAndLongRep.value = flags;
- if (iPtr->varFramePtr->localCachePtr) {
- codePtr->localCachePtr = iPtr->varFramePtr->localCachePtr;
- codePtr->localCachePtr->refCount++;
- }
- /* TODO: Debug printing? */
- }
- return codePtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * FreeSubstCodeInternalRep --
- *
- * Part of the substcode Tcl object type implementation. Frees the
- * storage associated with a substcode object's internal representation
- * unless its code is actively being executed.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The substcode object's internal rep is marked invalid and its code
- * gets freed unless the code is actively being executed. In that case
- * the cleanup is delayed until the last execution of the code completes.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-FreeSubstCodeInternalRep(
- register Tcl_Obj *objPtr) /* Object whose internal rep to free. */
-{
- register ByteCode *codePtr = objPtr->internalRep.ptrAndLongRep.ptr;
-
- objPtr->typePtr = NULL;
- objPtr->internalRep.otherValuePtr = NULL;
- codePtr->refCount--;
- if (codePtr->refCount <= 0) {
- TclCleanupByteCode(codePtr);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
* TclInitCompileEnv --
*
* Initializes a CompileEnv compilation environment structure for the
@@ -1339,7 +647,6 @@ TclCompileScript(
* first null character. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
- Interp *iPtr = (Interp *) interp;
int lastTopLevelCmdIndex = -1;
/* Index of most recent toplevel command in
* the command location table. Initialized to
@@ -1424,19 +731,6 @@ TclCompileScript(
commandLength -= 1;
}
-#ifdef TCL_COMPILE_DEBUG
- /*
- * If tracing, print a line for each top level command compiled.
- */
-
- if ((tclTraceCompile >= 1) && (envPtr->procPtr == NULL)) {
- fprintf(stdout, " Compiling: ");
- TclPrintSource(stdout, parsePtr->commandStart,
- TclMin(commandLength, 55));
- fprintf(stdout, "\n");
- }
-#endif
-
/*
* Check whether expansion has been requested for any of the
* words.
@@ -1512,120 +806,6 @@ TclCompileScript(
Tcl_DStringValue(&ds),
(Tcl_Namespace *) cmdNsPtr, /*flags*/ 0);
- if ((cmdPtr != NULL)
- && (cmdPtr->compileProc != NULL)
- && !(cmdPtr->nsPtr->flags&NS_SUPPRESS_COMPILATION)
- && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES)
- && !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) {
- int code, savedNumCmds = envPtr->numCommands;
- unsigned savedCodeNext =
- envPtr->codeNext - envPtr->codeStart;
- int update = 0;
-#ifdef TCL_COMPILE_DEBUG
- int startStackDepth = envPtr->currStackDepth;
-#endif
-
- /*
- * Mark the start of the command; the proper bytecode
- * length will be updated later. There is no need to
- * do this for the first bytecode in the compile env,
- * as the check is done before calling
- * TclNRExecuteByteCode(). Do emit an INST_START_CMD in
- * special cases where the first bytecode is in a
- * loop, to insure that the corresponding command is
- * counted properly. Compilers for commands able to
- * produce such a beast (currently 'while 1' only) set
- * envPtr->atCmdStart to 0 in order to signal this
- * case. [Bug 1752146]
- *
- * Note that the environment is initialised with
- * atCmdStart=1 to avoid emitting ISC for the first
- * command.
- */
-
- if (envPtr->atCmdStart) {
- if (savedCodeNext != 0) {
- /*
- * Increase the number of commands being
- * started at the current point. Note that
- * this depends on the exact layout of the
- * INST_START_CMD's operands, so be careful!
- */
-
- unsigned char *fixPtr = envPtr->codeNext - 4;
-
- TclStoreInt4AtPtr(TclGetUInt4AtPtr(fixPtr)+1,
- fixPtr);
- }
- } else {
- TclEmitInstInt4(INST_START_CMD, 0, envPtr);
- TclEmitInt4(1, envPtr);
- update = 1;
- }
-
- code = cmdPtr->compileProc(interp, parsePtr, cmdPtr,
- envPtr);
-
- if (code == TCL_OK) {
- /*
- * Confirm that the command compiler generated a
- * single value on the stack as its result. This
- * is only done in debugging mode, as it *should*
- * be correct and normal users have no reasonable
- * way to fix it anyway.
- */
-
-#ifdef TCL_COMPILE_DEBUG
- int diff = envPtr->currStackDepth-startStackDepth;
-
- if (diff != 1 && (diff != 0 ||
- *(envPtr->codeNext-1) != INST_DONE)) {
- Tcl_Panic("bad stack adjustment when compiling"
- " %.*s (was %d instead of 1)",
- parsePtr->tokenPtr->size,
- parsePtr->tokenPtr->start, diff);
- }
-#endif
- if (update) {
- /*
- * Fix the bytecode length.
- */
-
- unsigned char *fixPtr = envPtr->codeStart
- + savedCodeNext + 1;
- unsigned fixLen = envPtr->codeNext
- - envPtr->codeStart - savedCodeNext;
-
- TclStoreInt4AtPtr(fixLen, fixPtr);
- }
- goto finishCommand;
- }
-
- if (envPtr->atCmdStart && savedCodeNext != 0) {
- /*
- * Decrease the number of commands being started
- * at the current point. Note that this depends on
- * the exact layout of the INST_START_CMD's
- * operands, so be careful!
- */
-
- unsigned char *fixPtr = envPtr->codeNext - 4;
-
- TclStoreInt4AtPtr(TclGetUInt4AtPtr(fixPtr)-1,
- fixPtr);
- }
-
- /*
- * Restore numCommands and codeNext to their correct
- * values, removing any commands compiled before the
- * failure to produce bytecode got reported. [Bugs
- * 705406 and 735055]
- */
-
- envPtr->numCommands = savedNumCmds;
- envPtr->codeNext = envPtr->codeStart + savedCodeNext;
- }
-
/*
* No compile procedure so push the word. If the command
* was found, push a CmdName object to reduce runtime
@@ -1681,11 +861,7 @@ TclCompileScript(
TclEmitOpcode(INST_INVOKE_EXPANDED, envPtr);
TclAdjustStackDepth((1-wordIdx), envPtr);
} else if (wordIdx > 0) {
- if (wordIdx <= 255) {
- TclEmitInstInt1(INST_INVOKE_STK1, wordIdx, envPtr);
- } else {
- TclEmitInstInt4(INST_INVOKE_STK4, wordIdx, envPtr);
- }
+ TclEmitInstInt4(INST_INVOKE_STK4, wordIdx, envPtr);
}
/*
@@ -1693,7 +869,6 @@ TclCompileScript(
* offsets of the source and code for the command.
*/
- finishCommand:
EnterCmdExtentData(envPtr, currCmdIndex, commandLength,
(envPtr->codeNext-envPtr->codeStart) - startCodeOffset);
isFirstCmd = 0;
@@ -1795,8 +970,6 @@ TclCompileVarSubst(
if (tokenPtr->numComponents == 1) {
if (localVar < 0) {
TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr);
- } else if (localVar <= 255) {
- TclEmitInstInt1(INST_LOAD_SCALAR1, localVar, envPtr);
} else {
TclEmitInstInt4(INST_LOAD_SCALAR4, localVar, envPtr);
}
@@ -1804,8 +977,6 @@ TclCompileVarSubst(
TclCompileTokens(interp, tokenPtr+2, tokenPtr->numComponents-1, envPtr);
if (localVar < 0) {
TclEmitOpcode(INST_LOAD_ARRAY_STK, envPtr);
- } else if (localVar <= 255) {
- TclEmitInstInt1(INST_LOAD_ARRAY1, localVar, envPtr);
} else {
TclEmitInstInt4(INST_LOAD_ARRAY4, localVar, envPtr);
}
@@ -1925,171 +1096,6 @@ TclCompileTokens(
/*
*----------------------------------------------------------------------
*
- * TclCompileCmdWord --
- *
- * Given an array of parse tokens for a word containing one or more Tcl
- * commands, emit inline instructions to execute them. This procedure
- * differs from TclCompileTokens in that a simple word such as a loop
- * body enclosed in braces is not just pushed as a string, but is itself
- * parsed into tokens and compiled.
- *
- * Results:
- * The return value is a standard Tcl result. If an error occurs, an
- * error message is left in the interpreter's result.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the tokens at runtime.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclCompileCmdWord(
- Tcl_Interp *interp, /* Used for error and status reporting. */
- Tcl_Token *tokenPtr, /* Pointer to first in an array of tokens for
- * a command word to compile inline. */
- int count, /* Number of tokens to consider at tokenPtr.
- * Must be at least 1. */
- CompileEnv *envPtr) /* Holds the resulting instructions. */
-{
- if ((count == 1) && (tokenPtr->type == TCL_TOKEN_TEXT)) {
- /*
- * Handle the common case: if there is a single text token, compile it
- * into an inline sequence of instructions.
- */
-
- TclCompileScript(interp, tokenPtr->start, tokenPtr->size, envPtr);
- } else {
- /*
- * Multiple tokens or the single token involves substitutions. Emit
- * instructions to invoke the eval command procedure at runtime on the
- * result of evaluating the tokens.
- */
-
- TclCompileTokens(interp, tokenPtr, count, envPtr);
- TclEmitOpcode(INST_EVAL_STK, envPtr);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileExprWords --
- *
- * Given an array of parse tokens representing one or more words that
- * contain a Tcl expression, emit inline instructions to execute the
- * expression. This procedure differs from TclCompileExpr in that it
- * supports Tcl's two-level substitution semantics for expressions that
- * appear as command words.
- *
- * Results:
- * The return value is a standard Tcl result. If an error occurs, an
- * error message is left in the interpreter's result.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the expression.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclCompileExprWords(
- Tcl_Interp *interp, /* Used for error and status reporting. */
- Tcl_Token *tokenPtr, /* Points to first in an array of word tokens
- * tokens for the expression to compile
- * inline. */
- int numWords, /* Number of word tokens starting at tokenPtr.
- * Must be at least 1. Each word token
- * contains one or more subtokens. */
- CompileEnv *envPtr) /* Holds the resulting instructions. */
-{
- Tcl_Token *wordPtr;
- int i, concatItems;
-
- /*
- * If the expression is a single word that doesn't require substitutions,
- * just compile its string into inline instructions.
- */
-
- if ((numWords == 1) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
- TclCompileExpr(interp, tokenPtr[1].start,tokenPtr[1].size, envPtr, 1);
- return;
- }
-
- /*
- * Emit code to call the expr command proc at runtime. Concatenate the
- * (already substituted once) expr tokens with a space between each.
- */
-
- wordPtr = tokenPtr;
- for (i = 0; i < numWords; i++) {
- TclCompileTokens(interp, wordPtr+1, wordPtr->numComponents, envPtr);
- if (i < (numWords - 1)) {
- TclEmitPush(TclRegisterNewLiteral(envPtr, " ", 1), envPtr);
- }
- wordPtr += wordPtr->numComponents + 1;
- }
- concatItems = 2*numWords - 1;
- while (concatItems > 255) {
- TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
- concatItems -= 254;
- }
- if (concatItems > 1) {
- TclEmitInstInt1(INST_CONCAT1, concatItems, envPtr);
- }
- TclEmitOpcode(INST_EXPR_STK, envPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileNoOp --
- *
- * Function called to compile no-op's
- *
- * Results:
- * The return value is TCL_OK, indicating successful compilation.
- *
- * Side effects:
- * Instructions are added to envPtr to execute a no-op at runtime. No
- * result is pushed onto the stack: the compiler has to take care of this
- * itself if the last compiled command is a NoOp.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileNoOp(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- int i;
- int savedStackDepth = envPtr->currStackDepth;
-
- tokenPtr = parsePtr->tokenPtr;
- for (i = 1; i < parsePtr->numWords; i++) {
- tokenPtr = tokenPtr + tokenPtr->numComponents + 1;
- envPtr->currStackDepth = savedStackDepth;
-
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents,
- envPtr);
- TclEmitOpcode(INST_POP, envPtr);
- }
- }
- envPtr->currStackDepth = savedStackDepth;
- TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
* TclInitByteCodeObj --
*
* Create a ByteCode structure and initialize it from a CompileEnv
@@ -2124,9 +1130,6 @@ TclInitByteCodeObj(
size_t codeBytes, objArrayBytes, exceptArrayBytes, cmdLocBytes;
size_t auxDataArrayBytes, structureSize;
register unsigned char *p;
-#ifdef TCL_COMPILE_DEBUG
- unsigned char *nextPtr;
-#endif
int numLitObjects = envPtr->literalArrayNext;
Namespace *namespacePtr;
int i;
@@ -2160,7 +1163,6 @@ TclInitByteCodeObj(
p = ckalloc(structureSize);
codePtr = (ByteCode *) p;
codePtr->interpHandle = TclHandlePreserve(iPtr->handle);
- codePtr->compileEpoch = iPtr->compileEpoch;
codePtr->nsPtr = namespacePtr;
codePtr->nsEpoch = namespacePtr->resolverEpoch;
codePtr->refCount = 1;
@@ -2229,28 +1231,13 @@ TclInitByteCodeObj(
}
p += auxDataArrayBytes;
-#ifndef TCL_COMPILE_DEBUG
EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
-#else
- nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
- if (((size_t)(nextPtr - p)) != cmdLocBytes) {
- Tcl_Panic("TclInitByteCodeObj: encoded cmd location bytes %lu != expected size %lu", (unsigned long)(nextPtr - p), (unsigned long)cmdLocBytes);
- }
-#endif
/*
* Record various compilation-related statistics about the new ByteCode
* structure. Don't include overhead for statistics-related fields.
*/
-#ifdef TCL_COMPILE_STATS
- codePtr->structureSize = structureSize
- - (sizeof(size_t) + sizeof(Tcl_Time));
- Tcl_GetTime(&codePtr->createTime);
-
- RecordByteCodeStats(codePtr);
-#endif /* TCL_COMPILE_STATS */
-
/*
* Free the old internal rep then convert the object to a bytecode object
* by making its internal rep point to the just compiled ByteCode.
@@ -2867,13 +1854,13 @@ TclEmitForwardJump(
switch (jumpType) {
case TCL_UNCONDITIONAL_JUMP:
- TclEmitInstInt1(INST_JUMP1, 0, envPtr);
+ TclEmitInstInt4(INST_JUMP4, 0, envPtr);
break;
case TCL_TRUE_JUMP:
- TclEmitInstInt1(INST_JUMP_TRUE1, 0, envPtr);
+ TclEmitInstInt4(INST_JUMP_TRUE4, 0, envPtr);
break;
default:
- TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);
+ TclEmitInstInt4(INST_JUMP_FALSE4, 0, envPtr);
break;
}
}
@@ -2914,90 +1901,21 @@ TclFixupForwardJump(
int distThreshold) /* Maximum distance before the two byte jump
* is grown to five bytes. */
{
- unsigned char *jumpPc, *p;
- int firstCmd, lastCmd, firstRange, lastRange, k;
- unsigned numBytes;
+ unsigned char *jumpPc;
- if (jumpDist <= distThreshold) {
- jumpPc = envPtr->codeStart + jumpFixupPtr->codeOffset;
- switch (jumpFixupPtr->jumpType) {
+ jumpPc = envPtr->codeStart + jumpFixupPtr->codeOffset;
+ switch (jumpFixupPtr->jumpType) {
case TCL_UNCONDITIONAL_JUMP:
- TclUpdateInstInt1AtPc(INST_JUMP1, jumpDist, jumpPc);
+ TclUpdateInstInt4AtPc(INST_JUMP4, jumpDist, jumpPc);
break;
case TCL_TRUE_JUMP:
- TclUpdateInstInt1AtPc(INST_JUMP_TRUE1, jumpDist, jumpPc);
+ TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDist, jumpPc);
break;
default:
- TclUpdateInstInt1AtPc(INST_JUMP_FALSE1, jumpDist, jumpPc);
- break;
- }
- return 0;
- }
-
- /*
- * We must grow the jump then move subsequent instructions down. Note that
- * if we expand the space for generated instructions, code addresses might
- * change; be careful about updating any of these addresses held in
- * variables.
- */
-
- if ((envPtr->codeNext + 3) > envPtr->codeEnd) {
- TclExpandCodeArray(envPtr);
- }
- jumpPc = envPtr->codeStart + jumpFixupPtr->codeOffset;
- numBytes = envPtr->codeNext-jumpPc-2;
- p = jumpPc+2;
- memmove(p+3, p, numBytes);
-
- envPtr->codeNext += 3;
- jumpDist += 3;
- switch (jumpFixupPtr->jumpType) {
- case TCL_UNCONDITIONAL_JUMP:
- TclUpdateInstInt4AtPc(INST_JUMP4, jumpDist, jumpPc);
- break;
- case TCL_TRUE_JUMP:
- TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDist, jumpPc);
- break;
- default:
- TclUpdateInstInt4AtPc(INST_JUMP_FALSE4, jumpDist, jumpPc);
- break;
- }
-
- /*
- * Adjust the code offsets for any commands and any ExceptionRange records
- * between the jump and the current code address.
- */
-
- firstCmd = jumpFixupPtr->cmdIndex;
- lastCmd = envPtr->numCommands - 1;
- if (firstCmd < lastCmd) {
- for (k = firstCmd; k <= lastCmd; k++) {
- envPtr->cmdMapPtr[k].codeOffset += 3;
- }
- }
-
- firstRange = jumpFixupPtr->exceptIndex;
- lastRange = envPtr->exceptArrayNext - 1;
- for (k = firstRange; k <= lastRange; k++) {
- ExceptionRange *rangePtr = &envPtr->exceptArrayPtr[k];
-
- rangePtr->codeOffset += 3;
- switch (rangePtr->type) {
- case LOOP_EXCEPTION_RANGE:
- rangePtr->breakOffset += 3;
- if (rangePtr->continueOffset != -1) {
- rangePtr->continueOffset += 3;
- }
- break;
- case CATCH_EXCEPTION_RANGE:
- rangePtr->catchOffset += 3;
+ TclUpdateInstInt4AtPc(INST_JUMP_FALSE4, jumpDist, jumpPc);
break;
- default:
- Tcl_Panic("TclFixupForwardJump: bad ExceptionRange type %d",
- rangePtr->type);
- }
}
- return 1; /* the jump was grown */
+ return 0;
}
/*
@@ -3149,9 +2067,6 @@ TclInitAuxDataTypeTable(void)
* There are only two AuxData type at this time, so register them here.
*/
- TclRegisterAuxDataType(&tclForeachInfoType);
- TclRegisterAuxDataType(&tclJumptableInfoType);
- TclRegisterAuxDataType(&tclDictUpdateInfoType);
}
/*
@@ -3382,657 +2297,6 @@ EncodeCmdLocMap(
return p;
}
-#ifdef TCL_COMPILE_DEBUG
-/*
- *----------------------------------------------------------------------
- *
- * TclPrintByteCodeObj --
- *
- * This procedure prints ("disassembles") the instructions of a bytecode
- * object to stdout.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclPrintByteCodeObj(
- Tcl_Interp *interp, /* Used only for Tcl_GetStringFromObj. */
- Tcl_Obj *objPtr) /* The bytecode object to disassemble. */
-{
- Tcl_Obj *bufPtr = TclDisassembleByteCodeObj(objPtr);
-
- fprintf(stdout, "\n%s", TclGetString(bufPtr));
- Tcl_DecrRefCount(bufPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclPrintInstruction --
- *
- * This procedure prints ("disassembles") one instruction from a bytecode
- * object to stdout.
- *
- * Results:
- * Returns the length in bytes of the current instruiction.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclPrintInstruction(
- ByteCode *codePtr, /* Bytecode containing the instruction. */
- const unsigned char *pc) /* Points to first byte of instruction. */
-{
- Tcl_Obj *bufferObj;
- int numBytes;
-
- TclNewObj(bufferObj);
- numBytes = FormatInstruction(codePtr, pc, bufferObj);
- fprintf(stdout, "%s", TclGetString(bufferObj));
- Tcl_DecrRefCount(bufferObj);
- return numBytes;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclPrintObject --
- *
- * This procedure prints up to a specified number of characters from the
- * argument Tcl object's string representation to a specified file.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Outputs characters to the specified file.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclPrintObject(
- FILE *outFile, /* The file to print the source to. */
- Tcl_Obj *objPtr, /* Points to the Tcl object whose string
- * representation should be printed. */
- int maxChars) /* Maximum number of chars to print. */
-{
- char *bytes;
- int length;
-
- bytes = Tcl_GetStringFromObj(objPtr, &length);
- TclPrintSource(outFile, bytes, TclMin(length, maxChars));
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclPrintSource --
- *
- * This procedure prints up to a specified number of characters from the
- * argument string to a specified file. It tries to produce legible
- * output by adding backslashes as necessary.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Outputs characters to the specified file.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclPrintSource(
- FILE *outFile, /* The file to print the source to. */
- const char *stringPtr, /* The string to print. */
- int maxChars) /* Maximum number of chars to print. */
-{
- Tcl_Obj *bufferObj;
-
- TclNewObj(bufferObj);
- PrintSourceToObj(bufferObj, stringPtr, maxChars);
- fprintf(outFile, "%s", TclGetString(bufferObj));
- Tcl_DecrRefCount(bufferObj);
-}
-#endif /* TCL_COMPILE_DEBUG */
-
-/*
- *----------------------------------------------------------------------
- *
- * TclDisassembleByteCodeObj --
- *
- * Given an object which is of bytecode type, return a disassembled
- * version of the bytecode (in a new refcount 0 object). No guarantees
- * are made about the details of the contents of the result.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Obj *
-TclDisassembleByteCodeObj(
- Tcl_Obj *objPtr) /* The bytecode object to disassemble. */
-{
- ByteCode *codePtr = objPtr->internalRep.otherValuePtr;
- unsigned char *codeStart, *codeLimit, *pc;
- unsigned char *codeDeltaNext, *codeLengthNext;
- unsigned char *srcDeltaNext, *srcLengthNext;
- int codeOffset, codeLen, srcOffset, srcLen, numCmds, delta, i;
- Interp *iPtr = (Interp *) *codePtr->interpHandle;
- Tcl_Obj *bufferObj;
- char ptrBuf1[20], ptrBuf2[20];
-
- TclNewObj(bufferObj);
- if (codePtr->refCount <= 0) {
- return bufferObj; /* Already freed. */
- }
-
- codeStart = codePtr->codeStart;
- codeLimit = codeStart + codePtr->numCodeBytes;
- numCmds = codePtr->numCommands;
-
- /*
- * Print header lines describing the ByteCode.
- */
-
- sprintf(ptrBuf1, "%p", codePtr);
- sprintf(ptrBuf2, "%p", iPtr);
- Tcl_AppendPrintfToObj(bufferObj,
- "ByteCode 0x%s, refCt %u, epoch %u, interp 0x%s (epoch %u)\n",
- ptrBuf1, codePtr->refCount, codePtr->compileEpoch, ptrBuf2,
- iPtr->compileEpoch);
- Tcl_AppendToObj(bufferObj, " Source ", -1);
- PrintSourceToObj(bufferObj, codePtr->source,
- TclMin(codePtr->numSrcBytes, 55));
- Tcl_AppendPrintfToObj(bufferObj,
- "\n Cmds %d, src %d, inst %d, litObjs %u, aux %d, stkDepth %u, code/src %.2f\n",
- numCmds, codePtr->numSrcBytes, codePtr->numCodeBytes,
- codePtr->numLitObjects, codePtr->numAuxDataItems,
- codePtr->maxStackDepth,
-#ifdef TCL_COMPILE_STATS
- codePtr->numSrcBytes?
- codePtr->structureSize/(float)codePtr->numSrcBytes :
-#endif
- 0.0);
-
-#ifdef TCL_COMPILE_STATS
- Tcl_AppendPrintfToObj(bufferObj,
- " Code %lu = header %lu+inst %d+litObj %lu+exc %lu+aux %lu+cmdMap %d\n",
- (unsigned long) codePtr->structureSize,
- (unsigned long) (sizeof(ByteCode) - sizeof(size_t) - sizeof(Tcl_Time)),
- codePtr->numCodeBytes,
- (unsigned long) (codePtr->numLitObjects * sizeof(Tcl_Obj *)),
- (unsigned long) (codePtr->numExceptRanges*sizeof(ExceptionRange)),
- (unsigned long) (codePtr->numAuxDataItems * sizeof(AuxData)),
- codePtr->numCmdLocBytes);
-#endif /* TCL_COMPILE_STATS */
-
- /*
- * If the ByteCode is the compiled body of a Tcl procedure, print
- * information about that procedure. Note that we don't know the
- * procedure's name since ByteCode's can be shared among procedures.
- */
-
- if (codePtr->procPtr != NULL) {
- Proc *procPtr = codePtr->procPtr;
- int numCompiledLocals = procPtr->numCompiledLocals;
-
- sprintf(ptrBuf1, "%p", procPtr);
- Tcl_AppendPrintfToObj(bufferObj,
- " Proc 0x%s, refCt %d, args %d, compiled locals %d\n",
- ptrBuf1, procPtr->refCount, procPtr->numArgs,
- numCompiledLocals);
- if (numCompiledLocals > 0) {
- CompiledLocal *localPtr = procPtr->firstLocalPtr;
-
- for (i = 0; i < numCompiledLocals; i++) {
- Tcl_AppendPrintfToObj(bufferObj,
- " slot %d%s%s%s%s%s%s", i,
- (localPtr->flags & (VAR_ARRAY|VAR_LINK)) ? "" : ", scalar",
- (localPtr->flags & VAR_ARRAY) ? ", array" : "",
- (localPtr->flags & VAR_LINK) ? ", link" : "",
- (localPtr->flags & VAR_ARGUMENT) ? ", arg" : "",
- (localPtr->flags & VAR_TEMPORARY) ? ", temp" : "",
- (localPtr->flags & VAR_RESOLVED) ? ", resolved" : "");
- if (TclIsVarTemporary(localPtr)) {
- Tcl_AppendToObj(bufferObj, "\n", -1);
- } else {
- Tcl_AppendPrintfToObj(bufferObj, ", \"%s\"\n",
- localPtr->name);
- }
- localPtr = localPtr->nextPtr;
- }
- }
- }
-
- /*
- * Print the ExceptionRange array.
- */
-
- if (codePtr->numExceptRanges > 0) {
- Tcl_AppendPrintfToObj(bufferObj, " Exception ranges %d, depth %d:\n",
- codePtr->numExceptRanges, codePtr->maxExceptDepth);
- for (i = 0; i < codePtr->numExceptRanges; i++) {
- ExceptionRange *rangePtr = &codePtr->exceptArrayPtr[i];
-
- Tcl_AppendPrintfToObj(bufferObj,
- " %d: level %d, %s, pc %d-%d, ",
- i, rangePtr->nestingLevel,
- (rangePtr->type==LOOP_EXCEPTION_RANGE ? "loop" : "catch"),
- rangePtr->codeOffset,
- (rangePtr->codeOffset + rangePtr->numCodeBytes - 1));
- switch (rangePtr->type) {
- case LOOP_EXCEPTION_RANGE:
- Tcl_AppendPrintfToObj(bufferObj, "continue %d, break %d\n",
- rangePtr->continueOffset, rangePtr->breakOffset);
- break;
- case CATCH_EXCEPTION_RANGE:
- Tcl_AppendPrintfToObj(bufferObj, "catch %d\n",
- rangePtr->catchOffset);
- break;
- default:
- Tcl_Panic("TclDisassembleByteCodeObj: bad ExceptionRange type %d",
- rangePtr->type);
- }
- }
- }
-
- /*
- * If there were no commands (e.g., an expression or an empty string was
- * compiled), just print all instructions and return.
- */
-
- if (numCmds == 0) {
- pc = codeStart;
- while (pc < codeLimit) {
- Tcl_AppendToObj(bufferObj, " ", -1);
- pc += FormatInstruction(codePtr, pc, bufferObj);
- }
- return bufferObj;
- }
-
- /*
- * Print table showing the code offset, source offset, and source length
- * for each command. These are encoded as a sequence of bytes.
- */
-
- Tcl_AppendPrintfToObj(bufferObj, " Commands %d:", numCmds);
- codeDeltaNext = codePtr->codeDeltaStart;
- codeLengthNext = codePtr->codeLengthStart;
- srcDeltaNext = codePtr->srcDeltaStart;
- srcLengthNext = codePtr->srcLengthStart;
- codeOffset = srcOffset = 0;
- for (i = 0; i < numCmds; i++) {
- if ((unsigned) *codeDeltaNext == (unsigned) 0xFF) {
- codeDeltaNext++;
- delta = TclGetInt4AtPtr(codeDeltaNext);
- codeDeltaNext += 4;
- } else {
- delta = TclGetInt1AtPtr(codeDeltaNext);
- codeDeltaNext++;
- }
- codeOffset += delta;
-
- if ((unsigned) *codeLengthNext == (unsigned) 0xFF) {
- codeLengthNext++;
- codeLen = TclGetInt4AtPtr(codeLengthNext);
- codeLengthNext += 4;
- } else {
- codeLen = TclGetInt1AtPtr(codeLengthNext);
- codeLengthNext++;
- }
-
- if ((unsigned) *srcDeltaNext == (unsigned) 0xFF) {
- srcDeltaNext++;
- delta = TclGetInt4AtPtr(srcDeltaNext);
- srcDeltaNext += 4;
- } else {
- delta = TclGetInt1AtPtr(srcDeltaNext);
- srcDeltaNext++;
- }
- srcOffset += delta;
-
- if ((unsigned) *srcLengthNext == (unsigned) 0xFF) {
- srcLengthNext++;
- srcLen = TclGetInt4AtPtr(srcLengthNext);
- srcLengthNext += 4;
- } else {
- srcLen = TclGetInt1AtPtr(srcLengthNext);
- srcLengthNext++;
- }
-
- Tcl_AppendPrintfToObj(bufferObj, "%s%4d: pc %d-%d, src %d-%d",
- ((i % 2)? " " : "\n "),
- (i+1), codeOffset, (codeOffset + codeLen - 1),
- srcOffset, (srcOffset + srcLen - 1));
- }
- if (numCmds > 0) {
- Tcl_AppendToObj(bufferObj, "\n", -1);
- }
-
- /*
- * Print each instruction. If the instruction corresponds to the start of
- * a command, print the command's source. Note that we don't need the code
- * length here.
- */
-
- codeDeltaNext = codePtr->codeDeltaStart;
- srcDeltaNext = codePtr->srcDeltaStart;
- srcLengthNext = codePtr->srcLengthStart;
- codeOffset = srcOffset = 0;
- pc = codeStart;
- for (i = 0; i < numCmds; i++) {
- if ((unsigned) *codeDeltaNext == (unsigned) 0xFF) {
- codeDeltaNext++;
- delta = TclGetInt4AtPtr(codeDeltaNext);
- codeDeltaNext += 4;
- } else {
- delta = TclGetInt1AtPtr(codeDeltaNext);
- codeDeltaNext++;
- }
- codeOffset += delta;
-
- if ((unsigned) *srcDeltaNext == (unsigned) 0xFF) {
- srcDeltaNext++;
- delta = TclGetInt4AtPtr(srcDeltaNext);
- srcDeltaNext += 4;
- } else {
- delta = TclGetInt1AtPtr(srcDeltaNext);
- srcDeltaNext++;
- }
- srcOffset += delta;
-
- if ((unsigned) *srcLengthNext == (unsigned) 0xFF) {
- srcLengthNext++;
- srcLen = TclGetInt4AtPtr(srcLengthNext);
- srcLengthNext += 4;
- } else {
- srcLen = TclGetInt1AtPtr(srcLengthNext);
- srcLengthNext++;
- }
-
- /*
- * Print instructions before command i.
- */
-
- while ((pc-codeStart) < codeOffset) {
- Tcl_AppendToObj(bufferObj, " ", -1);
- pc += FormatInstruction(codePtr, pc, bufferObj);
- }
-
- Tcl_AppendPrintfToObj(bufferObj, " Command %d: ", i+1);
- PrintSourceToObj(bufferObj, (codePtr->source + srcOffset),
- TclMin(srcLen, 55));
- Tcl_AppendToObj(bufferObj, "\n", -1);
- }
- if (pc < codeLimit) {
- /*
- * Print instructions after the last command.
- */
-
- while (pc < codeLimit) {
- Tcl_AppendToObj(bufferObj, " ", -1);
- pc += FormatInstruction(codePtr, pc, bufferObj);
- }
- }
- return bufferObj;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * FormatInstruction --
- *
- * Appends a representation of a bytecode instruction to a Tcl_Obj.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-FormatInstruction(
- ByteCode *codePtr, /* Bytecode containing the instruction. */
- const unsigned char *pc, /* Points to first byte of instruction. */
- Tcl_Obj *bufferObj) /* Object to append instruction info to. */
-{
- Proc *procPtr = codePtr->procPtr;
- unsigned char opCode = *pc;
- register const InstructionDesc *instDesc = &tclInstructionTable[opCode];
- unsigned char *codeStart = codePtr->codeStart;
- unsigned pcOffset = pc - codeStart;
- int opnd = 0, i, j, numBytes = 1;
- int localCt = procPtr ? procPtr->numCompiledLocals : 0;
- CompiledLocal *localPtr = procPtr ? procPtr->firstLocalPtr : NULL;
- char suffixBuffer[128]; /* Additional info to print after main opcode
- * and immediates. */
- char *suffixSrc = NULL;
- Tcl_Obj *suffixObj = NULL;
- AuxData *auxPtr = NULL;
-
- suffixBuffer[0] = '\0';
- Tcl_AppendPrintfToObj(bufferObj, "(%u) %s ", pcOffset, instDesc->name);
- for (i = 0; i < instDesc->numOperands; i++) {
- switch (instDesc->opTypes[i]) {
- case OPERAND_INT1:
- opnd = TclGetInt1AtPtr(pc+numBytes); numBytes++;
- if (opCode == INST_JUMP1 || opCode == INST_JUMP_TRUE1
- || opCode == INST_JUMP_FALSE1) {
- sprintf(suffixBuffer, "pc %u", pcOffset+opnd);
- }
- Tcl_AppendPrintfToObj(bufferObj, "%+d ", opnd);
- break;
- case OPERAND_INT4:
- opnd = TclGetInt4AtPtr(pc+numBytes); numBytes += 4;
- if (opCode == INST_JUMP4 || opCode == INST_JUMP_TRUE4
- || opCode == INST_JUMP_FALSE4) {
- sprintf(suffixBuffer, "pc %u", pcOffset+opnd);
- } else if (opCode == INST_START_CMD) {
- sprintf(suffixBuffer, "next cmd at pc %u", pcOffset+opnd);
- }
- Tcl_AppendPrintfToObj(bufferObj, "%+d ", opnd);
- break;
- case OPERAND_UINT1:
- opnd = TclGetUInt1AtPtr(pc+numBytes); numBytes++;
- if (opCode == INST_PUSH1) {
- suffixObj = codePtr->objArrayPtr[opnd];
- }
- Tcl_AppendPrintfToObj(bufferObj, "%u ", (unsigned) opnd);
- break;
- case OPERAND_AUX4:
- case OPERAND_UINT4:
- opnd = TclGetUInt4AtPtr(pc+numBytes); numBytes += 4;
- if (opCode == INST_PUSH4) {
- suffixObj = codePtr->objArrayPtr[opnd];
- } else if (opCode == INST_START_CMD && opnd != 1) {
- sprintf(suffixBuffer+strlen(suffixBuffer),
- ", %u cmds start here", opnd);
- }
- Tcl_AppendPrintfToObj(bufferObj, "%u ", (unsigned) opnd);
- if (instDesc->opTypes[i] == OPERAND_AUX4) {
- auxPtr = &codePtr->auxDataArrayPtr[opnd];
- }
- break;
- case OPERAND_IDX4:
- opnd = TclGetInt4AtPtr(pc+numBytes); numBytes += 4;
- if (opnd >= -1) {
- Tcl_AppendPrintfToObj(bufferObj, "%d ", opnd);
- } else if (opnd == -2) {
- Tcl_AppendPrintfToObj(bufferObj, "end ");
- } else {
- Tcl_AppendPrintfToObj(bufferObj, "end-%d ", -2-opnd);
- }
- break;
- case OPERAND_LVT1:
- opnd = TclGetUInt1AtPtr(pc+numBytes);
- numBytes++;
- goto printLVTindex;
- case OPERAND_LVT4:
- opnd = TclGetUInt4AtPtr(pc+numBytes);
- numBytes += 4;
- printLVTindex:
- if (localPtr != NULL) {
- if (opnd >= localCt) {
- Tcl_Panic("FormatInstruction: bad local var index %u (%u locals)",
- (unsigned) opnd, localCt);
- }
- for (j = 0; j < opnd; j++) {
- localPtr = localPtr->nextPtr;
- }
- if (TclIsVarTemporary(localPtr)) {
- sprintf(suffixBuffer, "temp var %u", (unsigned) opnd);
- } else {
- sprintf(suffixBuffer, "var ");
- suffixSrc = localPtr->name;
- }
- }
- Tcl_AppendPrintfToObj(bufferObj, "%%v%u ", (unsigned) opnd);
- break;
- case OPERAND_NONE:
- default:
- break;
- }
- }
- if (suffixObj) {
- const char *bytes;
- int length;
-
- Tcl_AppendToObj(bufferObj, "\t# ", -1);
- bytes = Tcl_GetStringFromObj(codePtr->objArrayPtr[opnd], &length);
- PrintSourceToObj(bufferObj, bytes, TclMin(length, 40));
- } else if (suffixBuffer[0]) {
- Tcl_AppendPrintfToObj(bufferObj, "\t# %s", suffixBuffer);
- if (suffixSrc) {
- PrintSourceToObj(bufferObj, suffixSrc, 40);
- }
- }
- Tcl_AppendToObj(bufferObj, "\n", -1);
- if (auxPtr && auxPtr->type->printProc) {
- Tcl_AppendToObj(bufferObj, "\t\t[", -1);
- auxPtr->type->printProc(auxPtr->clientData, bufferObj, codePtr,
- pcOffset);
- Tcl_AppendToObj(bufferObj, "]\n", -1);
- }
- return numBytes;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * PrintSourceToObj --
- *
- * Appends a quoted representation of a string to a Tcl_Obj.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-PrintSourceToObj(
- Tcl_Obj *appendObj, /* The object to print the source to. */
- const char *stringPtr, /* The string to print. */
- int maxChars) /* Maximum number of chars to print. */
-{
- register const char *p;
- register int i = 0;
-
- if (stringPtr == NULL) {
- Tcl_AppendToObj(appendObj, "\"\"", -1);
- return;
- }
-
- Tcl_AppendToObj(appendObj, "\"", -1);
- p = stringPtr;
- for (; (*p != '\0') && (i < maxChars); p++, i++) {
- switch (*p) {
- case '"':
- Tcl_AppendToObj(appendObj, "\\\"", -1);
- continue;
- case '\f':
- Tcl_AppendToObj(appendObj, "\\f", -1);
- continue;
- case '\n':
- Tcl_AppendToObj(appendObj, "\\n", -1);
- continue;
- case '\r':
- Tcl_AppendToObj(appendObj, "\\r", -1);
- continue;
- case '\t':
- Tcl_AppendToObj(appendObj, "\\t", -1);
- continue;
- case '\v':
- Tcl_AppendToObj(appendObj, "\\v", -1);
- continue;
- default:
- Tcl_AppendPrintfToObj(appendObj, "%c", *p);
- continue;
- }
- }
- Tcl_AppendToObj(appendObj, "\"", -1);
-}
-
-#ifdef TCL_COMPILE_STATS
-/*
- *----------------------------------------------------------------------
- *
- * RecordByteCodeStats --
- *
- * Accumulates various compilation-related statistics for each newly
- * compiled ByteCode. Called by the TclInitByteCodeObj when Tcl is
- * compiled with the -DTCL_COMPILE_STATS flag
- *
- * Results:
- * None.
- *
- * Side effects:
- * Accumulates aggregate code-related statistics in the interpreter's
- * ByteCodeStats structure. Records statistics specific to a ByteCode in
- * its ByteCode structure.
- *
- *----------------------------------------------------------------------
- */
-
-void
-RecordByteCodeStats(
- ByteCode *codePtr) /* Points to ByteCode structure with info
- * to add to accumulated statistics. */
-{
- Interp *iPtr = (Interp *) *codePtr->interpHandle;
- register ByteCodeStats *statsPtr;
-
- if (iPtr == NULL) {
- /* Avoid segfaulting in case we're called in a deleted interp */
- return;
- }
- statsPtr = &(iPtr->stats);
-
- statsPtr->numCompilations++;
- statsPtr->totalSrcBytes += (double) codePtr->numSrcBytes;
- statsPtr->totalByteCodeBytes += (double) codePtr->structureSize;
- statsPtr->currentSrcBytes += (double) codePtr->numSrcBytes;
- statsPtr->currentByteCodeBytes += (double) codePtr->structureSize;
-
- statsPtr->srcCount[TclLog2(codePtr->numSrcBytes)]++;
- statsPtr->byteCodeCount[TclLog2((int) codePtr->structureSize)]++;
-
- statsPtr->currentInstBytes += (double) codePtr->numCodeBytes;
- statsPtr->currentLitBytes += (double)
- codePtr->numLitObjects * sizeof(Tcl_Obj *);
- statsPtr->currentExceptBytes += (double)
- codePtr->numExceptRanges * sizeof(ExceptionRange);
- statsPtr->currentAuxBytes += (double)
- codePtr->numAuxDataItems * sizeof(AuxData);
- statsPtr->currentCmdMapBytes += (double) codePtr->numCmdLocBytes;
-}
-#endif /* TCL_COMPILE_STATS */
-
/*
* Local Variables:
* mode: c
diff --git a/generic/tclCompile.h b/generic/tclCompile.h
index cedd638..b6288d0 100644
--- a/generic/tclCompile.h
+++ b/generic/tclCompile.h
@@ -10,825 +10,8 @@
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#ifndef _TCLCOMPILATION
-#define _TCLCOMPILATION 1
-
-#include "tclInt.h"
-
struct ByteCode; /* Forward declaration. */
-/*
- *------------------------------------------------------------------------
- * Variables related to compilation. These are used in tclCompile.c,
- * tclExecute.c, tclBasic.c, and their clients.
- *------------------------------------------------------------------------
- */
-
-#ifdef TCL_COMPILE_DEBUG
-/*
- * Variable that controls whether compilation tracing is enabled and, if so,
- * what level of tracing is desired:
- * 0: no compilation tracing
- * 1: summarize compilation of top level cmds and proc bodies
- * 2: display all instructions of each ByteCode compiled
- * This variable is linked to the Tcl variable "tcl_traceCompile".
- */
-
-MODULE_SCOPE int tclTraceCompile;
-
-/*
- * Variable that controls whether execution tracing is enabled and, if so,
- * what level of tracing is desired:
- * 0: no execution tracing
- * 1: trace invocations of Tcl procs only
- * 2: trace invocations of all (not compiled away) commands
- * 3: display each instruction executed
- * This variable is linked to the Tcl variable "tcl_traceExec".
- */
-
-MODULE_SCOPE int tclTraceExec;
-#endif
-
-/*
- *------------------------------------------------------------------------
- * Data structures related to compilation.
- *------------------------------------------------------------------------
- */
-
-/*
- * The structure used to implement Tcl "exceptions" (exceptional returns): for
- * example, those generated in loops by the break and continue commands, and
- * those generated by scripts and caught by the catch command. This
- * ExceptionRange structure describes a range of code (e.g., a loop body), the
- * kind of exceptions (e.g., a break or continue) that might occur, and the PC
- * offsets to jump to if a matching exception does occur. Exception ranges can
- * nest so this structure includes a nesting level that is used at runtime to
- * find the closest exception range surrounding a PC. For example, when a
- * break command is executed, the ExceptionRange structure for the most deeply
- * nested loop, if any, is found and used. These structures are also generated
- * for the "next" subcommands of for loops since a break there terminates the
- * for command. This means a for command actually generates two LoopInfo
- * structures.
- */
-
-typedef enum {
- LOOP_EXCEPTION_RANGE, /* Exception's range is part of a loop. Break
- * and continue "exceptions" cause jumps to
- * appropriate PC offsets. */
- CATCH_EXCEPTION_RANGE /* Exception's range is controlled by a catch
- * command. Errors in the range cause a jump
- * to a catch PC offset. */
-} ExceptionRangeType;
-
-typedef struct ExceptionRange {
- ExceptionRangeType type; /* The kind of ExceptionRange. */
- int nestingLevel; /* Static depth of the exception range. Used
- * to find the most deeply-nested range
- * surrounding a PC at runtime. */
- int codeOffset; /* Offset of the first instruction byte of the
- * code range. */
- int numCodeBytes; /* Number of bytes in the code range. */
- int breakOffset; /* If LOOP_EXCEPTION_RANGE, the target PC
- * offset for a break command in the range. */
- int continueOffset; /* If LOOP_EXCEPTION_RANGE and not -1, the
- * target PC offset for a continue command in
- * the code range. Otherwise, ignore this
- * range when processing a continue
- * command. */
- int catchOffset; /* If a CATCH_EXCEPTION_RANGE, the target PC
- * offset for any "exception" in range. */
-} ExceptionRange;
-
-/*
- * Structure used to map between instruction pc and source locations. It
- * defines for each compiled Tcl command its code's starting offset and its
- * source's starting offset and length. Note that the code offset increases
- * monotonically: that is, the table is sorted in code offset order. The
- * source offset is not monotonic.
- */
-
-typedef struct CmdLocation {
- int codeOffset; /* Offset of first byte of command code. */
- int numCodeBytes; /* Number of bytes for command's code. */
- int srcOffset; /* Offset of first char of the command. */
- int numSrcBytes; /* Number of command source chars. */
-} CmdLocation;
-
-/*
- * CompileProcs need the ability to record information during compilation that
- * can be used by bytecode instructions during execution. The AuxData
- * structure provides this "auxiliary data" mechanism. An arbitrary number of
- * these structures can be stored in the ByteCode record (during compilation
- * they are stored in a CompileEnv structure). Each AuxData record holds one
- * word of client-specified data (often a pointer) and is given an index that
- * instructions can later use to look up the structure and its data.
- *
- * The following definitions declare the types of procedures that are called
- * to duplicate or free this auxiliary data when the containing ByteCode
- * objects are duplicated and freed. Pointers to these procedures are kept in
- * the AuxData structure.
- */
-
-typedef ClientData (AuxDataDupProc) (ClientData clientData);
-typedef void (AuxDataFreeProc) (ClientData clientData);
-typedef void (AuxDataPrintProc)(ClientData clientData,
- Tcl_Obj *appendObj, struct ByteCode *codePtr,
- unsigned int pcOffset);
-
-/*
- * We define a separate AuxDataType struct to hold type-related information
- * for the AuxData structure. This separation makes it possible for clients
- * outside of the TCL core to manipulate (in a limited fashion!) AuxData; for
- * example, it makes it possible to pickle and unpickle AuxData structs.
- */
-
-typedef struct AuxDataType {
- const char *name; /* The name of the type. Types can be
- * registered and found by name */
- AuxDataDupProc *dupProc; /* Callback procedure to invoke when the aux
- * data is duplicated (e.g., when the ByteCode
- * structure containing the aux data is
- * duplicated). NULL means just copy the
- * source clientData bits; no proc need be
- * called. */
- AuxDataFreeProc *freeProc; /* Callback procedure to invoke when the aux
- * data is freed. NULL means no proc need be
- * called. */
- AuxDataPrintProc *printProc;/* Callback function to invoke when printing
- * the aux data as part of debugging. NULL
- * means that the data can't be printed. */
-} AuxDataType;
-
-/*
- * The definition of the AuxData structure that holds information created
- * during compilation by CompileProcs and used by instructions during
- * execution.
- */
-
-typedef struct AuxData {
- const AuxDataType *type; /* Pointer to the AuxData type associated with
- * this ClientData. */
- ClientData clientData; /* The compilation data itself. */
-} AuxData;
-
-/*
- * Structure defining the compilation environment. After compilation, fields
- * describing bytecode instructions are copied out into the more compact
- * ByteCode structure defined below.
- */
-
-#define COMPILEENV_INIT_CODE_BYTES 250
-#define COMPILEENV_INIT_NUM_OBJECTS 60
-#define COMPILEENV_INIT_EXCEPT_RANGES 5
-#define COMPILEENV_INIT_CMD_MAP_SIZE 40
-#define COMPILEENV_INIT_AUX_DATA_SIZE 5
-
-typedef struct CompileEnv {
- Interp *iPtr; /* Interpreter containing the code being
- * compiled. Commands and their compile procs
- * are specific to an interpreter so the code
- * emitted will depend on the interpreter. */
- const char *source; /* The source string being compiled by
- * SetByteCodeFromAny. This pointer is not
- * owned by the CompileEnv and must not be
- * freed or changed by it. */
- int numSrcBytes; /* Number of bytes in source. */
- Proc *procPtr; /* If a procedure is being compiled, a pointer
- * to its Proc structure; otherwise NULL. Used
- * to compile local variables. Set from
- * information provided by ObjInterpProc in
- * tclProc.c. */
- int numCommands; /* Number of commands compiled. */
- int exceptDepth; /* Current exception range nesting level; -1
- * if not in any range currently. */
- int maxExceptDepth; /* Max nesting level of exception ranges; -1
- * if no ranges have been compiled. */
- int maxStackDepth; /* Maximum number of stack elements needed to
- * execute the code. Set by compilation
- * procedures before returning. */
- int currStackDepth; /* Current stack depth. */
- LiteralTable localLitTable; /* Contains LiteralEntry's describing all Tcl
- * objects referenced by this compiled code.
- * Indexed by the string representations of
- * the literals. Used to avoid creating
- * duplicate objects. */
- unsigned char *codeStart; /* Points to the first byte of the code. */
- unsigned char *codeNext; /* Points to next code array byte to use. */
- unsigned char *codeEnd; /* Points just after the last allocated code
- * array byte. */
- int mallocedCodeArray; /* Set 1 if code array was expanded and
- * codeStart points into the heap.*/
- LiteralEntry *literalArrayPtr;
- /* Points to start of LiteralEntry array. */
- int literalArrayNext; /* Index of next free object array entry. */
- int literalArrayEnd; /* Index just after last obj array entry. */
- int mallocedLiteralArray; /* 1 if object array was expanded and objArray
- * points into the heap, else 0. */
- ExceptionRange *exceptArrayPtr;
- /* Points to start of the ExceptionRange
- * array. */
- int exceptArrayNext; /* Next free ExceptionRange array index.
- * exceptArrayNext is the number of ranges and
- * (exceptArrayNext-1) is the index of the
- * current range's array entry. */
- int exceptArrayEnd; /* Index after the last ExceptionRange array
- * entry. */
- int mallocedExceptArray; /* 1 if ExceptionRange array was expanded and
- * exceptArrayPtr points in heap, else 0. */
- CmdLocation *cmdMapPtr; /* Points to start of CmdLocation array.
- * numCommands is the index of the next entry
- * to use; (numCommands-1) is the entry index
- * for the last command. */
- int cmdMapEnd; /* Index after last CmdLocation entry. */
- int mallocedCmdMap; /* 1 if command map array was expanded and
- * cmdMapPtr points in the heap, else 0. */
- AuxData *auxDataArrayPtr; /* Points to auxiliary data array start. */
- int auxDataArrayNext; /* Next free compile aux data array index.
- * auxDataArrayNext is the number of aux data
- * items and (auxDataArrayNext-1) is index of
- * current aux data array entry. */
- int auxDataArrayEnd; /* Index after last aux data array entry. */
- int mallocedAuxDataArray; /* 1 if aux data array was expanded and
- * auxDataArrayPtr points in heap else 0. */
- unsigned char staticCodeSpace[COMPILEENV_INIT_CODE_BYTES];
- /* Initial storage for code. */
- LiteralEntry staticLiteralSpace[COMPILEENV_INIT_NUM_OBJECTS];
- /* Initial storage of LiteralEntry array. */
- ExceptionRange staticExceptArraySpace[COMPILEENV_INIT_EXCEPT_RANGES];
- /* Initial ExceptionRange array storage. */
- CmdLocation staticCmdMapSpace[COMPILEENV_INIT_CMD_MAP_SIZE];
- /* Initial storage for cmd location map. */
- AuxData staticAuxDataArraySpace[COMPILEENV_INIT_AUX_DATA_SIZE];
- /* Initial storage for aux data array. */
- int atCmdStart; /* Flag to say whether an INST_START_CMD
- * should be issued; they should never be
- * issued repeatedly, as that is significantly
- * inefficient. */
-} CompileEnv;
-
-/*
- * The structure defining the bytecode instructions resulting from compiling a
- * Tcl script. Note that this structure is variable length: a single heap
- * object is allocated to hold the ByteCode structure immediately followed by
- * the code bytes, the literal object array, the ExceptionRange array, the
- * CmdLocation map, and the compilation AuxData array.
- */
-
-/*
- * A PRECOMPILED bytecode struct is one that was generated from a compiled
- * image rather than implicitly compiled from source
- */
-
-#define TCL_BYTECODE_PRECOMPILED 0x0001
-
-/*
- * When a bytecode is compiled, interp or namespace resolvers have not been
- * applied yet: this is indicated by the TCL_BYTECODE_RESOLVE_VARS flag.
- */
-
-#define TCL_BYTECODE_RESOLVE_VARS 0x0002
-
-#define TCL_BYTECODE_RECOMPILE 0x0004
-
-typedef struct ByteCode {
- TclHandle interpHandle; /* Handle for interpreter containing the
- * compiled code. Commands and their compile
- * procs are specific to an interpreter so the
- * code emitted will depend on the
- * interpreter. */
- int compileEpoch; /* Value of iPtr->compileEpoch when this
- * ByteCode was compiled. Used to invalidate
- * code when, e.g., commands with compile
- * procs are redefined. */
- Namespace *nsPtr; /* Namespace context in which this code was
- * compiled. If the code is executed if a
- * different namespace, it must be
- * recompiled. */
- int nsEpoch; /* Value of nsPtr->resolverEpoch when this
- * ByteCode was compiled. Used to invalidate
- * code when new namespace resolution rules
- * are put into effect. */
- int refCount; /* Reference count: set 1 when created plus 1
- * for each execution of the code currently
- * active. This structure can be freed when
- * refCount becomes zero. */
- unsigned int flags; /* flags describing state for the codebyte.
- * this variable holds ORed values from the
- * TCL_BYTECODE_ masks defined above */
- const char *source; /* The source string from which this ByteCode
- * was compiled. Note that this pointer is not
- * owned by the ByteCode and must not be freed
- * or modified by it. */
- Proc *procPtr; /* If the ByteCode was compiled from a
- * procedure body, this is a pointer to its
- * Proc structure; otherwise NULL. This
- * pointer is also not owned by the ByteCode
- * and must not be freed by it. */
- size_t structureSize; /* Number of bytes in the ByteCode structure
- * itself. Does not include heap space for
- * literal Tcl objects or storage referenced
- * by AuxData entries. */
- int numCommands; /* Number of commands compiled. */
- int numSrcBytes; /* Number of source bytes compiled. */
- int numCodeBytes; /* Number of code bytes. */
- int numLitObjects; /* Number of objects in literal array. */
- int numExceptRanges; /* Number of ExceptionRange array elems. */
- int numAuxDataItems; /* Number of AuxData items. */
- int numCmdLocBytes; /* Number of bytes needed for encoded command
- * location information. */
- int maxExceptDepth; /* Maximum nesting level of ExceptionRanges;
- * -1 if no ranges were compiled. */
- int maxStackDepth; /* Maximum number of stack elements needed to
- * execute the code. */
- unsigned char *codeStart; /* Points to the first byte of the code. This
- * is just after the final ByteCode member
- * cmdMapPtr. */
- Tcl_Obj **objArrayPtr; /* Points to the start of the literal object
- * array. This is just after the last code
- * byte. */
- ExceptionRange *exceptArrayPtr;
- /* Points to the start of the ExceptionRange
- * array. This is just after the last object
- * in the object array. */
- AuxData *auxDataArrayPtr; /* Points to the start of the auxiliary data
- * array. This is just after the last entry in
- * the ExceptionRange array. */
- unsigned char *codeDeltaStart;
- /* Points to the first of a sequence of bytes
- * that encode the change in the starting
- * offset of each command's code. If -127 <=
- * delta <= 127, it is encoded as 1 byte,
- * otherwise 0xFF (128) appears and the delta
- * is encoded by the next 4 bytes. Code deltas
- * are always positive. This sequence is just
- * after the last entry in the AuxData
- * array. */
- unsigned char *codeLengthStart;
- /* Points to the first of a sequence of bytes
- * that encode the length of each command's
- * code. The encoding is the same as for code
- * deltas. Code lengths are always positive.
- * This sequence is just after the last entry
- * in the code delta sequence. */
- unsigned char *srcDeltaStart;
- /* Points to the first of a sequence of bytes
- * that encode the change in the starting
- * offset of each command's source. The
- * encoding is the same as for code deltas.
- * Source deltas can be negative. This
- * sequence is just after the last byte in the
- * code length sequence. */
- unsigned char *srcLengthStart;
- /* Points to the first of a sequence of bytes
- * that encode the length of each command's
- * source. The encoding is the same as for
- * code deltas. Source lengths are always
- * positive. This sequence is just after the
- * last byte in the source delta sequence. */
- LocalCache *localCachePtr; /* Pointer to the start of the cached variable
- * names and initialisation data for local
- * variables. */
-#ifdef TCL_COMPILE_STATS
- Tcl_Time createTime; /* Absolute time when the ByteCode was
- * created. */
-#endif /* TCL_COMPILE_STATS */
-} ByteCode;
-
-/*
- * Opcodes for the Tcl bytecode instructions. These must correspond to the
- * entries in the table of instruction descriptions, tclInstructionTable, in
- * tclCompile.c. Also, the order and number of the expression opcodes (e.g.,
- * INST_LOR) must match the entries in the array operatorStrings in
- * tclExecute.c.
- */
-
-/* Opcodes 0 to 9 */
-#define INST_DONE 0
-#define INST_PUSH1 1
-#define INST_PUSH4 2
-#define INST_POP 3
-#define INST_DUP 4
-#define INST_CONCAT1 5
-#define INST_INVOKE_STK1 6
-#define INST_INVOKE_STK4 7
-#define INST_EVAL_STK 8
-#define INST_EXPR_STK 9
-
-/* Opcodes 10 to 23 */
-#define INST_LOAD_SCALAR1 10
-#define INST_LOAD_SCALAR4 11
-#define INST_LOAD_SCALAR_STK 12
-#define INST_LOAD_ARRAY1 13
-#define INST_LOAD_ARRAY4 14
-#define INST_LOAD_ARRAY_STK 15
-#define INST_LOAD_STK 16
-#define INST_STORE_SCALAR1 17
-#define INST_STORE_SCALAR4 18
-#define INST_STORE_SCALAR_STK 19
-#define INST_STORE_ARRAY1 20
-#define INST_STORE_ARRAY4 21
-#define INST_STORE_ARRAY_STK 22
-#define INST_STORE_STK 23
-
-/* Opcodes 24 to 33 */
-#define INST_INCR_SCALAR1 24
-#define INST_INCR_SCALAR_STK 25
-#define INST_INCR_ARRAY1 26
-#define INST_INCR_ARRAY_STK 27
-#define INST_INCR_STK 28
-#define INST_INCR_SCALAR1_IMM 29
-#define INST_INCR_SCALAR_STK_IMM 30
-#define INST_INCR_ARRAY1_IMM 31
-#define INST_INCR_ARRAY_STK_IMM 32
-#define INST_INCR_STK_IMM 33
-
-/* Opcodes 34 to 39 */
-#define INST_JUMP1 34
-#define INST_JUMP4 35
-#define INST_JUMP_TRUE1 36
-#define INST_JUMP_TRUE4 37
-#define INST_JUMP_FALSE1 38
-#define INST_JUMP_FALSE4 39
-
-/* Opcodes 40 to 64 */
-#define INST_LOR 40
-#define INST_LAND 41
-#define INST_BITOR 42
-#define INST_BITXOR 43
-#define INST_BITAND 44
-#define INST_EQ 45
-#define INST_NEQ 46
-#define INST_LT 47
-#define INST_GT 48
-#define INST_LE 49
-#define INST_GE 50
-#define INST_LSHIFT 51
-#define INST_RSHIFT 52
-#define INST_ADD 53
-#define INST_SUB 54
-#define INST_MULT 55
-#define INST_DIV 56
-#define INST_MOD 57
-#define INST_UPLUS 58
-#define INST_UMINUS 59
-#define INST_BITNOT 60
-#define INST_LNOT 61
-#define INST_CALL_BUILTIN_FUNC1 62
-#define INST_CALL_FUNC1 63
-#define INST_TRY_CVT_TO_NUMERIC 64
-
-/* Opcodes 65 to 66 */
-#define INST_BREAK 65
-#define INST_CONTINUE 66
-
-/* Opcodes 67 to 68 */
-#define INST_FOREACH_START4 67
-#define INST_FOREACH_STEP4 68
-
-/* Opcodes 69 to 72 */
-#define INST_BEGIN_CATCH4 69
-#define INST_END_CATCH 70
-#define INST_PUSH_RESULT 71
-#define INST_PUSH_RETURN_CODE 72
-
-/* Opcodes 73 to 78 */
-#define INST_STR_EQ 73
-#define INST_STR_NEQ 74
-#define INST_STR_CMP 75
-#define INST_STR_LEN 76
-#define INST_STR_INDEX 77
-#define INST_STR_MATCH 78
-
-/* Opcodes 78 to 81 */
-#define INST_LIST 79
-#define INST_LIST_INDEX 80
-#define INST_LIST_LENGTH 81
-
-/* Opcodes 82 to 87 */
-#define INST_APPEND_SCALAR1 82
-#define INST_APPEND_SCALAR4 83
-#define INST_APPEND_ARRAY1 84
-#define INST_APPEND_ARRAY4 85
-#define INST_APPEND_ARRAY_STK 86
-#define INST_APPEND_STK 87
-
-/* Opcodes 88 to 93 */
-#define INST_LAPPEND_SCALAR1 88
-#define INST_LAPPEND_SCALAR4 89
-#define INST_LAPPEND_ARRAY1 90
-#define INST_LAPPEND_ARRAY4 91
-#define INST_LAPPEND_ARRAY_STK 92
-#define INST_LAPPEND_STK 93
-
-/* TIP #22 - LINDEX operator with flat arg list */
-
-#define INST_LIST_INDEX_MULTI 94
-
-/*
- * TIP #33 - 'lset' command. Code gen also required a Forth-like
- * OVER operation.
- */
-
-#define INST_OVER 95
-#define INST_LSET_LIST 96
-#define INST_LSET_FLAT 97
-
-/* TIP#90 - 'return' command. */
-
-#define INST_RETURN_IMM 98
-
-/* TIP#123 - exponentiation operator. */
-
-#define INST_EXPON 99
-
-/* TIP #157 - {*}... (word expansion) language syntax support. */
-
-#define INST_EXPAND_START 100
-#define INST_EXPAND_STKTOP 101
-#define INST_INVOKE_EXPANDED 102
-
-/*
- * TIP #57 - 'lassign' command. Code generation requires immediate
- * LINDEX and LRANGE operators.
- */
-
-#define INST_LIST_INDEX_IMM 103
-#define INST_LIST_RANGE_IMM 104
-
-#define INST_START_CMD 105
-
-#define INST_LIST_IN 106
-#define INST_LIST_NOT_IN 107
-
-#define INST_PUSH_RETURN_OPTIONS 108
-#define INST_RETURN_STK 109
-
-/*
- * Dictionary (TIP#111) related commands.
- */
-
-#define INST_DICT_GET 110
-#define INST_DICT_SET 111
-#define INST_DICT_UNSET 112
-#define INST_DICT_INCR_IMM 113
-#define INST_DICT_APPEND 114
-#define INST_DICT_LAPPEND 115
-#define INST_DICT_FIRST 116
-#define INST_DICT_NEXT 117
-#define INST_DICT_DONE 118
-#define INST_DICT_UPDATE_START 119
-#define INST_DICT_UPDATE_END 120
-
-/*
- * Instruction to support jumps defined by tables (instead of the classic
- * [switch] technique of chained comparisons).
- */
-
-#define INST_JUMP_TABLE 121
-
-/*
- * Instructions to support compilation of global, variable, upvar and
- * [namespace upvar].
- */
-
-#define INST_UPVAR 122
-#define INST_NSUPVAR 123
-#define INST_VARIABLE 124
-
-/* Instruction to support compiling syntax error to bytecode */
-
-#define INST_SYNTAX 125
-
-/* Instruction to reverse N items on top of stack */
-
-#define INST_REVERSE 126
-
-/* regexp instruction */
-
-#define INST_REGEXP 127
-
-/* For [info exists] compilation */
-#define INST_EXIST_SCALAR 128
-#define INST_EXIST_ARRAY 129
-#define INST_EXIST_ARRAY_STK 130
-#define INST_EXIST_STK 131
-
-/* For [subst] compilation */
-#define INST_NOP 132
-#define INST_RETURN_CODE_BRANCH 133
-
-/* For [unset] compilation */
-#define INST_UNSET_SCALAR 134
-#define INST_UNSET_ARRAY 135
-#define INST_UNSET_ARRAY_STK 136
-#define INST_UNSET_STK 137
-
-/* For [dict with], [dict exists], [dict create] and [dict merge] */
-#define INST_DICT_EXPAND 138
-#define INST_DICT_RECOMBINE_STK 139
-#define INST_DICT_RECOMBINE_IMM 140
-#define INST_DICT_EXISTS 141
-#define INST_DICT_VERIFY 142
-
-/* For [string map] and [regsub] compilation */
-#define INST_STR_MAP 143
-#define INST_STR_FIND 144
-#define INST_STR_FIND_LAST 145
-#define INST_STR_RANGE_IMM 146
-#define INST_STR_RANGE 147
-
-/* For operations to do with coroutines and other NRE-manipulators */
-#define INST_YIELD 148
-#define INST_COROUTINE_NAME 149
-#define INST_TAILCALL 150
-
-/* For compilation of basic information operations */
-#define INST_NS_CURRENT 151
-#define INST_INFO_LEVEL_NUM 152
-#define INST_INFO_LEVEL_ARGS 153
-#define INST_RESOLVE_COMMAND 154
-#define INST_TCLOO_SELF 155
-#define INST_TCLOO_CLASS 156
-#define INST_TCLOO_NS 157
-#define INST_TCLOO_IS_OBJECT 158
-
-/* For compilation of [array] subcommands */
-#define INST_ARRAY_EXISTS_STK 159
-#define INST_ARRAY_EXISTS_IMM 160
-#define INST_ARRAY_MAKE_STK 161
-#define INST_ARRAY_MAKE_IMM 162
-
-#define INST_INVOKE_REPLACE 163
-
-/* The last opcode */
-#define LAST_INST_OPCODE 163
-
-/*
- * Table describing the Tcl bytecode instructions: their name (for displaying
- * code), total number of code bytes required (including operand bytes), and a
- * description of the type of each operand. These operand types include signed
- * and unsigned integers of length one and four bytes. The unsigned integers
- * are used for indexes or for, e.g., the count of objects to push in a "push"
- * instruction.
- */
-
-#define MAX_INSTRUCTION_OPERANDS 2
-
-typedef enum InstOperandType {
- OPERAND_NONE,
- OPERAND_INT1, /* One byte signed integer. */
- OPERAND_INT4, /* Four byte signed integer. */
- OPERAND_UINT1, /* One byte unsigned integer. */
- OPERAND_UINT4, /* Four byte unsigned integer. */
- OPERAND_IDX4, /* Four byte signed index (actually an
- * integer, but displayed differently.) */
- OPERAND_LVT1, /* One byte unsigned index into the local
- * variable table. */
- OPERAND_LVT4, /* Four byte unsigned index into the local
- * variable table. */
- OPERAND_AUX4 /* Four byte unsigned index into the aux data
- * table. */
-} InstOperandType;
-
-typedef struct InstructionDesc {
- const char *name; /* Name of instruction. */
- int numBytes; /* Total number of bytes for instruction. */
- int stackEffect; /* The worst-case balance stack effect of the
- * instruction, used for stack requirements
- * computations. The value INT_MIN signals
- * that the instruction's worst case effect is
- * (1-opnd1). */
- int numOperands; /* Number of operands. */
- InstOperandType opTypes[MAX_INSTRUCTION_OPERANDS];
- /* The type of each operand. */
-} InstructionDesc;
-
-MODULE_SCOPE InstructionDesc const tclInstructionTable[];
-
-/*
- * Compilation of some Tcl constructs such as if commands and the logical or
- * (||) and logical and (&&) operators in expressions requires the generation
- * of forward jumps. Since the PC target of these jumps isn't known when the
- * jumps are emitted, we record the offset of each jump in an array of
- * JumpFixup structures. There is one array for each sequence of jumps to one
- * target PC. When we learn the target PC, we update the jumps with the
- * correct distance. Also, if the distance is too great (> 127 bytes), we
- * replace the single-byte jump with a four byte jump instruction, move the
- * instructions after the jump down, and update the code offsets for any
- * commands between the jump and the target.
- */
-
-typedef enum {
- TCL_UNCONDITIONAL_JUMP,
- TCL_TRUE_JUMP,
- TCL_FALSE_JUMP
-} TclJumpType;
-
-typedef struct JumpFixup {
- TclJumpType jumpType; /* Indicates the kind of jump. */
- int codeOffset; /* Offset of the first byte of the one-byte
- * forward jump's code. */
- int cmdIndex; /* Index of the first command after the one
- * for which the jump was emitted. Used to
- * update the code offsets for subsequent
- * commands if the two-byte jump at jumpPc
- * must be replaced with a five-byte one. */
- int exceptIndex; /* Index of the first range entry in the
- * ExceptionRange array after the current one.
- * This field is used to adjust the code
- * offsets in subsequent ExceptionRange
- * records when a jump is grown from 2 bytes
- * to 5 bytes. */
-} JumpFixup;
-
-#define JUMPFIXUP_INIT_ENTRIES 10
-
-typedef struct JumpFixupArray {
- JumpFixup *fixup; /* Points to start of jump fixup array. */
- int next; /* Index of next free array entry. */
- int end; /* Index of last usable entry in array. */
- int mallocedArray; /* 1 if array was expanded and fixups points
- * into the heap, else 0. */
- JumpFixup staticFixupSpace[JUMPFIXUP_INIT_ENTRIES];
- /* Initial storage for jump fixup array. */
-} JumpFixupArray;
-
-/*
- * The structure describing one variable list of a foreach command. Note that
- * only foreach commands inside procedure bodies are compiled inline so a
- * ForeachVarList structure always describes local variables. Furthermore,
- * only scalar variables are supported for inline-compiled foreach loops.
- */
-
-typedef struct ForeachVarList {
- int numVars; /* The number of variables in the list. */
- int varIndexes[1]; /* An array of the indexes ("slot numbers")
- * for each variable in the procedure's array
- * of local variables. Only scalar variables
- * are supported. The actual size of this
- * field will be large enough to numVars
- * indexes. THIS MUST BE THE LAST FIELD IN THE
- * STRUCTURE! */
-} ForeachVarList;
-
-/*
- * Structure used to hold information about a foreach command that is needed
- * during program execution. These structures are stored in CompileEnv and
- * ByteCode structures as auxiliary data.
- */
-
-typedef struct ForeachInfo {
- int numLists; /* The number of both the variable and value
- * lists of the foreach command. */
- int firstValueTemp; /* Index of the first temp var in a proc frame
- * used to point to a value list. */
- int loopCtTemp; /* Index of temp var in a proc frame holding
- * the loop's iteration count. Used to
- * determine next value list element to assign
- * each loop var. */
- ForeachVarList *varLists[1];/* An array of pointers to ForeachVarList
- * structures describing each var list. The
- * actual size of this field will be large
- * enough to numVars indexes. THIS MUST BE THE
- * LAST FIELD IN THE STRUCTURE! */
-} ForeachInfo;
-
-MODULE_SCOPE const AuxDataType tclForeachInfoType;
-
-/*
- * Structure used to hold information about a switch command that is needed
- * during program execution. These structures are stored in CompileEnv and
- * ByteCode structures as auxiliary data.
- */
-
-typedef struct JumptableInfo {
- Tcl_HashTable hashTable; /* Hash that maps strings to signed ints (PC
- * offsets). */
-} JumptableInfo;
-
-MODULE_SCOPE const AuxDataType tclJumptableInfoType;
-
-/*
- * Structure used to hold information about a [dict update] command that is
- * needed during program execution. These structures are stored in CompileEnv
- * and ByteCode structures as auxiliary data.
- */
-
-typedef struct {
- int length; /* Size of array */
- int varIndices[1]; /* Array of variable indices to manage when
- * processing the start and end of a [dict
- * update]. There is really more than one
- * entry, and the structure is allocated to
- * take account of this. MUST BE LAST FIELD IN
- * STRUCTURE. */
-} DictUpdateInfo;
-
-MODULE_SCOPE const AuxDataType tclDictUpdateInfoType;
-
-/*
- * ClientData type used by the math operator commands.
- */
typedef struct {
const char *op; /* Do not call it 'operator': C++ reserved */
@@ -838,107 +21,7 @@ typedef struct {
int identity;
} i;
} TclOpCmdClientData;
-
-/*
- *----------------------------------------------------------------
- * Procedures exported by tclBasic.c to be used within the engine.
- *----------------------------------------------------------------
- */
-
-MODULE_SCOPE Tcl_ObjCmdProc TclNRInterpCoroutine;
-/*
- *----------------------------------------------------------------
- * Procedures exported by the engine to be used by tclBasic.c
- *----------------------------------------------------------------
- */
-
-MODULE_SCOPE ByteCode * TclCompileObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
-
-/*
- *----------------------------------------------------------------
- * Procedures shared among Tcl bytecode compilation and execution modules but
- * not used outside:
- *----------------------------------------------------------------
- */
-
-MODULE_SCOPE void TclCleanupByteCode(ByteCode *codePtr);
-MODULE_SCOPE void TclCompileCmdWord(Tcl_Interp *interp,
- Tcl_Token *tokenPtr, int count,
- CompileEnv *envPtr);
-MODULE_SCOPE void TclCompileExpr(Tcl_Interp *interp, const char *script,
- int numBytes, CompileEnv *envPtr, int optimize);
-MODULE_SCOPE void TclCompileExprWords(Tcl_Interp *interp,
- Tcl_Token *tokenPtr, int numWords,
- CompileEnv *envPtr);
-MODULE_SCOPE void TclCompileScript(Tcl_Interp *interp,
- const char *script, int numBytes,
- CompileEnv *envPtr);
-MODULE_SCOPE void TclCompileSyntaxError(Tcl_Interp *interp,
- CompileEnv *envPtr);
-MODULE_SCOPE void TclCompileTokens(Tcl_Interp *interp,
- Tcl_Token *tokenPtr, int count,
- CompileEnv *envPtr);
-MODULE_SCOPE void TclCompileVarSubst(Tcl_Interp *interp,
- Tcl_Token *tokenPtr, CompileEnv *envPtr);
-MODULE_SCOPE int TclCreateAuxData(ClientData clientData,
- const AuxDataType *typePtr, CompileEnv *envPtr);
-MODULE_SCOPE int TclCreateExceptRange(ExceptionRangeType type,
- CompileEnv *envPtr);
-MODULE_SCOPE ExecEnv * TclCreateExecEnv(Tcl_Interp *interp, int size);
-MODULE_SCOPE Tcl_Obj * TclCreateLiteral(Interp *iPtr, char *bytes,
- int length, unsigned int hash, int *newPtr,
- Namespace *nsPtr, int flags,
- LiteralEntry **globalPtrPtr);
-MODULE_SCOPE void TclDeleteExecEnv(ExecEnv *eePtr);
-MODULE_SCOPE void TclDeleteLiteralTable(Tcl_Interp *interp,
- LiteralTable *tablePtr);
-MODULE_SCOPE void TclEmitForwardJump(CompileEnv *envPtr,
- TclJumpType jumpType, JumpFixup *jumpFixupPtr);
-MODULE_SCOPE ExceptionRange * TclGetExceptionRangeForPc(unsigned char *pc,
- int catchOnly, ByteCode *codePtr);
-MODULE_SCOPE void TclExpandJumpFixupArray(JumpFixupArray *fixupArrayPtr);
-MODULE_SCOPE int TclNRExecuteByteCode(Tcl_Interp *interp,
- ByteCode *codePtr);
-MODULE_SCOPE void TclFinalizeAuxDataTypeTable(void);
-MODULE_SCOPE int TclFindCompiledLocal(const char *name, int nameChars,
- int create, CompileEnv *envPtr);
-MODULE_SCOPE LiteralEntry * TclLookupLiteralEntry(Tcl_Interp *interp,
- Tcl_Obj *objPtr);
-MODULE_SCOPE int TclFixupForwardJump(CompileEnv *envPtr,
- JumpFixup *jumpFixupPtr, int jumpDist,
- int distThreshold);
-MODULE_SCOPE void TclFreeCompileEnv(CompileEnv *envPtr);
-MODULE_SCOPE void TclFreeJumpFixupArray(JumpFixupArray *fixupArrayPtr);
-MODULE_SCOPE void TclInitAuxDataTypeTable(void);
-MODULE_SCOPE void TclInitByteCodeObj(Tcl_Obj *objPtr,
- CompileEnv *envPtr);
-MODULE_SCOPE void TclInitCompilation(void);
-MODULE_SCOPE void TclInitCompileEnv(Tcl_Interp *interp,
- CompileEnv *envPtr, const char *string,
- int numBytes);
-MODULE_SCOPE void TclInitJumpFixupArray(JumpFixupArray *fixupArrayPtr);
-MODULE_SCOPE void TclInitLiteralTable(LiteralTable *tablePtr);
-#ifdef TCL_COMPILE_STATS
-MODULE_SCOPE char * TclLiteralStats(LiteralTable *tablePtr);
-MODULE_SCOPE int TclLog2(int value);
-#endif
-#ifdef TCL_COMPILE_DEBUG
-MODULE_SCOPE void TclPrintByteCodeObj(Tcl_Interp *interp,
- Tcl_Obj *objPtr);
-#endif
-MODULE_SCOPE int TclPrintInstruction(ByteCode *codePtr,
- const unsigned char *pc);
-MODULE_SCOPE void TclPrintObject(FILE *outFile,
- Tcl_Obj *objPtr, int maxChars);
-MODULE_SCOPE void TclPrintSource(FILE *outFile,
- const char *string, int maxChars);
-MODULE_SCOPE void TclRegisterAuxDataType(const AuxDataType *typePtr);
-MODULE_SCOPE int TclRegisterLiteral(CompileEnv *envPtr,
- char *bytes, int length, int flags);
-MODULE_SCOPE void TclReleaseLiteral(Tcl_Interp *interp, Tcl_Obj *objPtr);
-MODULE_SCOPE void TclInvalidateCmdLiteral(Tcl_Interp *interp,
- const char *name, Namespace *nsPtr);
MODULE_SCOPE int TclSingleOpCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
@@ -951,621 +34,21 @@ MODULE_SCOPE int TclVariadicOpCmd(ClientData clientData,
MODULE_SCOPE int TclNoIdentOpCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
-#ifdef TCL_COMPILE_DEBUG
-MODULE_SCOPE void TclVerifyGlobalLiteralTable(Interp *iPtr);
-MODULE_SCOPE void TclVerifyLocalLiteralTable(CompileEnv *envPtr);
-#endif
-MODULE_SCOPE int TclWordKnownAtCompileTime(Tcl_Token *tokenPtr,
- Tcl_Obj *valuePtr);
-
-/*
- *----------------------------------------------------------------
- * Macros and flag values used by Tcl bytecode compilation and execution
- * modules inside the Tcl core but not used outside.
- *----------------------------------------------------------------
- */
-
-#define LITERAL_ON_HEAP 0x01
-#define LITERAL_CMD_NAME 0x02
-
-/*
- * Form of TclRegisterLiteral with flags == 0. In that case, it is safe to
- * cast away constness, and it is cleanest to do that here, all in one place.
- *
- * int TclRegisterNewLiteral(CompileEnv *envPtr, const char *bytes,
- * int length);
- */
-
-#define TclRegisterNewLiteral(envPtr, bytes, length) \
- TclRegisterLiteral(envPtr, (char *)(bytes), length, /*flags*/ 0)
-
-/*
- * Form of TclRegisterLiteral with flags == LITERAL_CMD_NAME. In that case, it
- * is safe to cast away constness, and it is cleanest to do that here, all in
- * one place.
- *
- * int TclRegisterNewNSLiteral(CompileEnv *envPtr, const char *bytes,
- * int length);
- */
-
-#define TclRegisterNewCmdLiteral(envPtr, bytes, length) \
- TclRegisterLiteral(envPtr, (char *)(bytes), length, LITERAL_CMD_NAME)
-
-/*
- * Macro used to manually adjust the stack requirements; used in cases where
- * the stack effect cannot be computed from the opcode and its operands, but
- * is still known at compile time.
- *
- * void TclAdjustStackDepth(int delta, CompileEnv *envPtr);
- */
-
-#define TclAdjustStackDepth(delta, envPtr) \
- do { \
- if ((delta) < 0) { \
- if ((envPtr)->maxStackDepth < (envPtr)->currStackDepth) { \
- (envPtr)->maxStackDepth = (envPtr)->currStackDepth; \
- } \
- } \
- (envPtr)->currStackDepth += (delta); \
- } while (0)
-
-/*
- * Macro used to update the stack requirements. It is called by the macros
- * TclEmitOpCode, TclEmitInst1 and TclEmitInst4.
- * Remark that the very last instruction of a bytecode always reduces the
- * stack level: INST_DONE or INST_POP, so that the maxStackdepth is always
- * updated.
- *
- * void TclUpdateStackReqs(unsigned char op, int i, CompileEnv *envPtr);
- */
-
-#define TclUpdateStackReqs(op, i, envPtr) \
- do { \
- int delta = tclInstructionTable[(op)].stackEffect; \
- if (delta) { \
- if (delta == INT_MIN) { \
- delta = 1 - (i); \
- } \
- TclAdjustStackDepth(delta, envPtr); \
- } \
- } while (0)
-
-/*
- * Macro to emit an opcode byte into a CompileEnv's code array. The ANSI C
- * "prototype" for this macro is:
- *
- * void TclEmitOpcode(unsigned char op, CompileEnv *envPtr);
- */
-
-#define TclEmitOpcode(op, envPtr) \
- do { \
- if ((envPtr)->codeNext == (envPtr)->codeEnd) { \
- TclExpandCodeArray(envPtr); \
- } \
- *(envPtr)->codeNext++ = (unsigned char) (op); \
- (envPtr)->atCmdStart = ((op) == INST_START_CMD); \
- TclUpdateStackReqs(op, 0, envPtr); \
- } while (0)
-
-/*
- * Macros to emit an integer operand. The ANSI C "prototype" for these macros
- * are:
- *
- * void TclEmitInt1(int i, CompileEnv *envPtr);
- * void TclEmitInt4(int i, CompileEnv *envPtr);
- */
-
-#define TclEmitInt1(i, envPtr) \
- do { \
- if ((envPtr)->codeNext == (envPtr)->codeEnd) { \
- TclExpandCodeArray(envPtr); \
- } \
- *(envPtr)->codeNext++ = (unsigned char) ((unsigned int) (i)); \
- } while (0)
-
-#define TclEmitInt4(i, envPtr) \
- do { \
- if (((envPtr)->codeNext + 4) > (envPtr)->codeEnd) { \
- TclExpandCodeArray(envPtr); \
- } \
- *(envPtr)->codeNext++ = \
- (unsigned char) ((unsigned int) (i) >> 24); \
- *(envPtr)->codeNext++ = \
- (unsigned char) ((unsigned int) (i) >> 16); \
- *(envPtr)->codeNext++ = \
- (unsigned char) ((unsigned int) (i) >> 8); \
- *(envPtr)->codeNext++ = \
- (unsigned char) ((unsigned int) (i) ); \
- } while (0)
-
-/*
- * Macros to emit an instruction with signed or unsigned integer operands.
- * Four byte integers are stored in "big-endian" order with the high order
- * byte stored at the lowest address. The ANSI C "prototypes" for these macros
- * are:
- *
- * void TclEmitInstInt1(unsigned char op, int i, CompileEnv *envPtr);
- * void TclEmitInstInt4(unsigned char op, int i, CompileEnv *envPtr);
- */
-
-#define TclEmitInstInt1(op, i, envPtr) \
- do { \
- if (((envPtr)->codeNext + 2) > (envPtr)->codeEnd) { \
- TclExpandCodeArray(envPtr); \
- } \
- *(envPtr)->codeNext++ = (unsigned char) (op); \
- *(envPtr)->codeNext++ = (unsigned char) ((unsigned int) (i)); \
- (envPtr)->atCmdStart = ((op) == INST_START_CMD); \
- TclUpdateStackReqs(op, i, envPtr); \
- } while (0)
-
-#define TclEmitInstInt4(op, i, envPtr) \
- do { \
- if (((envPtr)->codeNext + 5) > (envPtr)->codeEnd) { \
- TclExpandCodeArray(envPtr); \
- } \
- *(envPtr)->codeNext++ = (unsigned char) (op); \
- *(envPtr)->codeNext++ = \
- (unsigned char) ((unsigned int) (i) >> 24); \
- *(envPtr)->codeNext++ = \
- (unsigned char) ((unsigned int) (i) >> 16); \
- *(envPtr)->codeNext++ = \
- (unsigned char) ((unsigned int) (i) >> 8); \
- *(envPtr)->codeNext++ = \
- (unsigned char) ((unsigned int) (i) ); \
- (envPtr)->atCmdStart = ((op) == INST_START_CMD); \
- TclUpdateStackReqs(op, i, envPtr); \
- } while (0)
-
-/*
- * Macro to push a Tcl object onto the Tcl evaluation stack. It emits the
- * object's one or four byte array index into the CompileEnv's code array.
- * These support, respectively, a maximum of 256 (2**8) and 2**32 objects in a
- * CompileEnv. The ANSI C "prototype" for this macro is:
- *
- * void TclEmitPush(int objIndex, CompileEnv *envPtr);
- */
-
-#define TclEmitPush(objIndex, envPtr) \
- do { \
- register int objIndexCopy = (objIndex); \
- if (objIndexCopy <= 255) { \
- TclEmitInstInt1(INST_PUSH1, objIndexCopy, (envPtr)); \
- } else { \
- TclEmitInstInt4(INST_PUSH4, objIndexCopy, (envPtr)); \
- } \
- } while (0)
-
-/*
- * Macros to update a (signed or unsigned) integer starting at a pointer. The
- * two variants depend on the number of bytes. The ANSI C "prototypes" for
- * these macros are:
- *
- * void TclStoreInt1AtPtr(int i, unsigned char *p);
- * void TclStoreInt4AtPtr(int i, unsigned char *p);
- */
-
-#define TclStoreInt1AtPtr(i, p) \
- *(p) = (unsigned char) ((unsigned int) (i))
-
-#define TclStoreInt4AtPtr(i, p) \
- do { \
- *(p) = (unsigned char) ((unsigned int) (i) >> 24); \
- *(p+1) = (unsigned char) ((unsigned int) (i) >> 16); \
- *(p+2) = (unsigned char) ((unsigned int) (i) >> 8); \
- *(p+3) = (unsigned char) ((unsigned int) (i) ); \
- } while (0)
-
-/*
- * Macros to update instructions at a particular pc with a new op code and a
- * (signed or unsigned) int operand. The ANSI C "prototypes" for these macros
- * are:
- *
- * void TclUpdateInstInt1AtPc(unsigned char op, int i, unsigned char *pc);
- * void TclUpdateInstInt4AtPc(unsigned char op, int i, unsigned char *pc);
- */
-
-#define TclUpdateInstInt1AtPc(op, i, pc) \
- do { \
- *(pc) = (unsigned char) (op); \
- TclStoreInt1AtPtr((i), ((pc)+1)); \
- } while (0)
-
-#define TclUpdateInstInt4AtPc(op, i, pc) \
- do { \
- *(pc) = (unsigned char) (op); \
- TclStoreInt4AtPtr((i), ((pc)+1)); \
- } while (0)
-
-/*
- * Macro to fix up a forward jump to point to the current code-generation
- * position in the bytecode being created (the most common case). The ANSI C
- * "prototypes" for this macro is:
- *
- * int TclFixupForwardJumpToHere(CompileEnv *envPtr, JumpFixup *fixupPtr,
- * int threshold);
- */
-
-#define TclFixupForwardJumpToHere(envPtr, fixupPtr, threshold) \
- TclFixupForwardJump((envPtr), (fixupPtr), \
- (envPtr)->codeNext-(envPtr)->codeStart-(fixupPtr)->codeOffset, \
- (threshold))
-
-/*
- * Macros to get a signed integer (GET_INT{1,2}) or an unsigned int
- * (GET_UINT{1,2}) from a pointer. There are two variants for each return type
- * that depend on the number of bytes fetched. The ANSI C "prototypes" for
- * these macros are:
- *
- * int TclGetInt1AtPtr(unsigned char *p);
- * int TclGetInt4AtPtr(unsigned char *p);
- * unsigned int TclGetUInt1AtPtr(unsigned char *p);
- * unsigned int TclGetUInt4AtPtr(unsigned char *p);
- */
-
-/*
- * The TclGetInt1AtPtr macro is tricky because we want to do sign extension on
- * the 1-byte value. Unfortunately the "char" type isn't signed on all
- * platforms so sign-extension doesn't always happen automatically. Sometimes
- * we can explicitly declare the pointer to be signed, but other times we have
- * to explicitly sign-extend the value in software.
- */
-
-#ifndef __CHAR_UNSIGNED__
-# define TclGetInt1AtPtr(p) ((int) *((char *) p))
-#elif defined(HAVE_SIGNED_CHAR)
-# define TclGetInt1AtPtr(p) ((int) *((signed char *) p))
-#else
-# define TclGetInt1AtPtr(p) \
- (((int) *((char *) p)) | ((*(p) & 0200) ? (-256) : 0))
-#endif
-
-#define TclGetInt4AtPtr(p) \
- (((int) TclGetInt1AtPtr(p) << 24) | \
- (*((p)+1) << 16) | \
- (*((p)+2) << 8) | \
- (*((p)+3)))
-
-#define TclGetUInt1AtPtr(p) \
- ((unsigned int) *(p))
-#define TclGetUInt4AtPtr(p) \
- ((unsigned int) (*(p) << 24) | \
- (*((p)+1) << 16) | \
- (*((p)+2) << 8) | \
- (*((p)+3)))
-
-/*
- * Macros used to compute the minimum and maximum of two integers. The ANSI C
- * "prototypes" for these macros are:
- *
- * int TclMin(int i, int j);
- * int TclMax(int i, int j);
- */
-
-#define TclMin(i, j) ((((int) i) < ((int) j))? (i) : (j))
-#define TclMax(i, j) ((((int) i) > ((int) j))? (i) : (j))
-/*
- * Convenience macro for use when compiling bodies of commands. The ANSI C
- * "prototype" for this macro is:
- *
- * static void CompileBody(CompileEnv *envPtr, Tcl_Token *tokenPtr,
- * Tcl_Interp *interp);
- */
-
-#define CompileBody(envPtr, tokenPtr, interp) \
- TclCompileCmdWord((interp), (tokenPtr)+1, (tokenPtr)->numComponents, \
- (envPtr))
-
-/*
- * Convenience macro for use when compiling tokens to be pushed. The ANSI C
- * "prototype" for this macro is:
- *
- * static void CompileTokens(CompileEnv *envPtr, Tcl_Token *tokenPtr,
- * Tcl_Interp *interp);
- */
-
-#define CompileTokens(envPtr, tokenPtr, interp) \
- TclCompileTokens((interp), (tokenPtr)+1, (tokenPtr)->numComponents, \
- (envPtr));
-/*
- * Convenience macro for use when pushing literals. The ANSI C "prototype" for
- * this macro is:
- *
- * static void PushLiteral(CompileEnv *envPtr,
- * const char *string, int length);
- */
-
-#define PushLiteral(envPtr, string, length) \
- TclEmitPush(TclRegisterNewLiteral((envPtr), (string), (length)), (envPtr))
-
-/*
- * Macro to advance to the next token; it is more mnemonic than the address
- * arithmetic that it replaces. The ANSI C "prototype" for this macro is:
- *
- * static Tcl_Token * TokenAfter(Tcl_Token *tokenPtr);
- */
-
-#define TokenAfter(tokenPtr) \
- ((tokenPtr) + ((tokenPtr)->numComponents + 1))
-
-/*
- * Macro to get the offset to the next instruction to be issued. The ANSI C
- * "prototype" for this macro is:
- *
- * static int CurrentOffset(CompileEnv *envPtr);
- */
-
-#define CurrentOffset(envPtr) \
- ((envPtr)->codeNext - (envPtr)->codeStart)
-
-/*
- * Note: the exceptDepth is a bit of a misnomer: TEBC only needs the
- * maximal depth of nested CATCH ranges in order to alloc runtime
- * memory. These macros should compute precisely that? OTOH, the nesting depth
- * of LOOP ranges is an interesting datum for debugging purposes, and that is
- * what we compute now.
- *
- * static int DeclareExceptionRange(CompileEnv *envPtr, int type);
- * static int ExceptionRangeStarts(CompileEnv *envPtr, int index);
- * static void ExceptionRangeEnds(CompileEnv *envPtr, int index);
- * static void ExceptionRangeTarget(CompileEnv *envPtr, int index, LABEL);
- */
-
-#define DeclareExceptionRange(envPtr, type) \
- (TclCreateExceptRange((type), (envPtr)))
-#define ExceptionRangeStarts(envPtr, index) \
- (((envPtr)->exceptDepth++), \
- ((envPtr)->maxExceptDepth = \
- TclMax((envPtr)->exceptDepth, (envPtr)->maxExceptDepth)), \
- ((envPtr)->exceptArrayPtr[(index)].codeOffset = CurrentOffset(envPtr)))
-#define ExceptionRangeEnds(envPtr, index) \
- (((envPtr)->exceptDepth--), \
- ((envPtr)->exceptArrayPtr[(index)].numCodeBytes = \
- CurrentOffset(envPtr) - (envPtr)->exceptArrayPtr[(index)].codeOffset))
-#define ExceptionRangeTarget(envPtr, index, targetType) \
- ((envPtr)->exceptArrayPtr[(index)].targetType = CurrentOffset(envPtr))
-
-/*
- * Check if there is an LVT for compiled locals
- */
-
-#define EnvHasLVT(envPtr) \
- (envPtr->procPtr || envPtr->iPtr->varFramePtr->localCachePtr)
-
-/*
- * Macros for making it easier to deal with tokens and DStrings.
- */
-
-#define TclDStringAppendToken(dsPtr, tokenPtr) \
- Tcl_DStringAppend((dsPtr), (tokenPtr)->start, (tokenPtr)->size)
-#define TclRegisterDStringLiteral(envPtr, dsPtr) \
- TclRegisterLiteral(envPtr, Tcl_DStringValue(dsPtr), \
- Tcl_DStringLength(dsPtr), /*flags*/ 0)
-
-/*
- * DTrace probe macros (NOPs if DTrace support is not enabled).
- */
-
-/*
- * Define the following macros to enable debug logging of the DTrace proc,
- * cmd, and inst probes. Note that this does _not_ require a platform with
- * DTrace, it simply logs all probe output to /tmp/tclDTraceDebug-[pid].log.
- *
- * If the second macro is defined, logging to file starts immediately,
- * otherwise only after the first call to [tcl::dtrace]. Note that the debug
- * probe data is always computed, even when it is not logged to file.
- *
- * Defining the third macro enables debug logging of inst probes (disabled
- * by default due to the significant performance impact).
- */
-
-/*
-#define TCL_DTRACE_DEBUG 1
-#define TCL_DTRACE_DEBUG_LOG_ENABLED 1
-#define TCL_DTRACE_DEBUG_INST_PROBES 1
-*/
-
-#if !(defined(TCL_DTRACE_DEBUG) && defined(__GNUC__))
-
-#ifdef USE_DTRACE
-
-#if defined(__GNUC__) && __GNUC__ > 2
-/*
- * Use gcc branch prediction hint to minimize cost of DTrace ENABLED checks.
- */
-#define unlikely(x) (__builtin_expect((x), 0))
-#else
-#define unlikely(x) (x)
-#endif
-
-#define TCL_DTRACE_PROC_ENTRY_ENABLED() unlikely(TCL_PROC_ENTRY_ENABLED())
-#define TCL_DTRACE_PROC_RETURN_ENABLED() unlikely(TCL_PROC_RETURN_ENABLED())
-#define TCL_DTRACE_PROC_RESULT_ENABLED() unlikely(TCL_PROC_RESULT_ENABLED())
-#define TCL_DTRACE_PROC_ARGS_ENABLED() unlikely(TCL_PROC_ARGS_ENABLED())
-#define TCL_DTRACE_PROC_INFO_ENABLED() unlikely(TCL_PROC_INFO_ENABLED())
-#define TCL_DTRACE_PROC_ENTRY(a0, a1, a2) TCL_PROC_ENTRY(a0, a1, a2)
-#define TCL_DTRACE_PROC_RETURN(a0, a1) TCL_PROC_RETURN(a0, a1)
-#define TCL_DTRACE_PROC_RESULT(a0, a1, a2, a3) TCL_PROC_RESULT(a0, a1, a2, a3)
-#define TCL_DTRACE_PROC_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
- TCL_PROC_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
-#define TCL_DTRACE_PROC_INFO(a0, a1, a2, a3, a4, a5, a6, a7) \
- TCL_PROC_INFO(a0, a1, a2, a3, a4, a5, a6, a7)
-
-#define TCL_DTRACE_CMD_ENTRY_ENABLED() unlikely(TCL_CMD_ENTRY_ENABLED())
-#define TCL_DTRACE_CMD_RETURN_ENABLED() unlikely(TCL_CMD_RETURN_ENABLED())
-#define TCL_DTRACE_CMD_RESULT_ENABLED() unlikely(TCL_CMD_RESULT_ENABLED())
-#define TCL_DTRACE_CMD_ARGS_ENABLED() unlikely(TCL_CMD_ARGS_ENABLED())
-#define TCL_DTRACE_CMD_INFO_ENABLED() unlikely(TCL_CMD_INFO_ENABLED())
-#define TCL_DTRACE_CMD_ENTRY(a0, a1, a2) TCL_CMD_ENTRY(a0, a1, a2)
-#define TCL_DTRACE_CMD_RETURN(a0, a1) TCL_CMD_RETURN(a0, a1)
-#define TCL_DTRACE_CMD_RESULT(a0, a1, a2, a3) TCL_CMD_RESULT(a0, a1, a2, a3)
-#define TCL_DTRACE_CMD_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
- TCL_CMD_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
-#define TCL_DTRACE_CMD_INFO(a0, a1, a2, a3, a4, a5, a6, a7) \
- TCL_CMD_INFO(a0, a1, a2, a3, a4, a5, a6, a7)
-
-#define TCL_DTRACE_INST_START_ENABLED() unlikely(TCL_INST_START_ENABLED())
-#define TCL_DTRACE_INST_DONE_ENABLED() unlikely(TCL_INST_DONE_ENABLED())
-#define TCL_DTRACE_INST_START(a0, a1, a2) TCL_INST_START(a0, a1, a2)
-#define TCL_DTRACE_INST_DONE(a0, a1, a2) TCL_INST_DONE(a0, a1, a2)
-
-#define TCL_DTRACE_TCL_PROBE_ENABLED() unlikely(TCL_TCL_PROBE_ENABLED())
-#define TCL_DTRACE_TCL_PROBE(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
- TCL_TCL_PROBE(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
-
-#define TCL_DTRACE_DEBUG_LOG()
-
-MODULE_SCOPE void TclDTraceInfo(Tcl_Obj *info, const char **args,
- int *argsi);
-
-#else /* USE_DTRACE */
-
-#define TCL_DTRACE_PROC_ENTRY_ENABLED() 0
-#define TCL_DTRACE_PROC_RETURN_ENABLED() 0
-#define TCL_DTRACE_PROC_RESULT_ENABLED() 0
-#define TCL_DTRACE_PROC_ARGS_ENABLED() 0
-#define TCL_DTRACE_PROC_INFO_ENABLED() 0
-#define TCL_DTRACE_PROC_ENTRY(a0, a1, a2) {if (a0) {}}
-#define TCL_DTRACE_PROC_RETURN(a0, a1) {if (a0) {}}
-#define TCL_DTRACE_PROC_RESULT(a0, a1, a2, a3) {if (a0) {}; if (a3) {}}
-#define TCL_DTRACE_PROC_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {}
-#define TCL_DTRACE_PROC_INFO(a0, a1, a2, a3, a4, a5, a6, a7) {}
-
-#define TCL_DTRACE_CMD_ENTRY_ENABLED() 0
-#define TCL_DTRACE_CMD_RETURN_ENABLED() 0
-#define TCL_DTRACE_CMD_RESULT_ENABLED() 0
-#define TCL_DTRACE_CMD_ARGS_ENABLED() 0
-#define TCL_DTRACE_CMD_INFO_ENABLED() 0
-#define TCL_DTRACE_CMD_ENTRY(a0, a1, a2) {}
-#define TCL_DTRACE_CMD_RETURN(a0, a1) {}
-#define TCL_DTRACE_CMD_RESULT(a0, a1, a2, a3) {}
-#define TCL_DTRACE_CMD_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {}
-#define TCL_DTRACE_CMD_INFO(a0, a1, a2, a3, a4, a5, a6, a7) {}
-
-#define TCL_DTRACE_INST_START_ENABLED() 0
-#define TCL_DTRACE_INST_DONE_ENABLED() 0
-#define TCL_DTRACE_INST_START(a0, a1, a2) {}
-#define TCL_DTRACE_INST_DONE(a0, a1, a2) {}
-
-#define TCL_DTRACE_TCL_PROBE_ENABLED() 0
-#define TCL_DTRACE_TCL_PROBE(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {}
-#define TclDTraceInfo(info, args, argsi) {*args = ""; *argsi = 0;}
-
-#endif /* USE_DTRACE */
-
-#else /* TCL_DTRACE_DEBUG */
-
-#define USE_DTRACE 1
-
-#if !defined(TCL_DTRACE_DEBUG_LOG_ENABLED) || !(TCL_DTRACE_DEBUG_LOG_ENABLED)
-#undef TCL_DTRACE_DEBUG_LOG_ENABLED
-#define TCL_DTRACE_DEBUG_LOG_ENABLED 0
-#endif
-
-#if !defined(TCL_DTRACE_DEBUG_INST_PROBES) || !(TCL_DTRACE_DEBUG_INST_PROBES)
-#undef TCL_DTRACE_DEBUG_INST_PROBES
-#define TCL_DTRACE_DEBUG_INST_PROBES 0
-#endif
-
-MODULE_SCOPE int tclDTraceDebugEnabled, tclDTraceDebugIndent;
-MODULE_SCOPE FILE *tclDTraceDebugLog;
-MODULE_SCOPE void TclDTraceOpenDebugLog(void);
-MODULE_SCOPE void TclDTraceInfo(Tcl_Obj *info, const char **args, int *argsi);
-
-#define TCL_DTRACE_DEBUG_LOG() \
- int tclDTraceDebugEnabled = TCL_DTRACE_DEBUG_LOG_ENABLED; \
- int tclDTraceDebugIndent = 0; \
- FILE *tclDTraceDebugLog = NULL; \
- void TclDTraceOpenDebugLog(void) { \
- char n[35]; \
- sprintf(n, "/tmp/tclDTraceDebug-%lu.log", \
- (unsigned long) getpid()); \
- tclDTraceDebugLog = fopen(n, "a"); \
- }
-
-#define TclDTraceDbgMsg(p, m, ...) \
- do { \
- if (tclDTraceDebugEnabled) { \
- int _l, _t = 0; \
- if (!tclDTraceDebugLog) { TclDTraceOpenDebugLog(); } \
- fprintf(tclDTraceDebugLog, "%.12s:%.4d:%n", \
- strrchr(__FILE__, '/')+1, __LINE__, &_l); _t += _l; \
- fprintf(tclDTraceDebugLog, " %.*s():%n", \
- (_t < 18 ? 18 - _t : 0) + 18, __func__, &_l); _t += _l; \
- fprintf(tclDTraceDebugLog, "%*s" p "%n", \
- (_t < 40 ? 40 - _t : 0) + 2 * tclDTraceDebugIndent, \
- "", &_l); _t += _l; \
- fprintf(tclDTraceDebugLog, "%*s" m "\n", \
- (_t < 64 ? 64 - _t : 1), "", ##__VA_ARGS__); \
- fflush(tclDTraceDebugLog); \
- } \
- } while (0)
-
-#define TCL_DTRACE_PROC_ENTRY_ENABLED() 1
-#define TCL_DTRACE_PROC_RETURN_ENABLED() 1
-#define TCL_DTRACE_PROC_RESULT_ENABLED() 1
-#define TCL_DTRACE_PROC_ARGS_ENABLED() 1
-#define TCL_DTRACE_PROC_INFO_ENABLED() 1
-#define TCL_DTRACE_PROC_ENTRY(a0, a1, a2) \
- tclDTraceDebugIndent++; \
- TclDTraceDbgMsg("-> proc-entry", "%s %d %p", a0, a1, a2)
-#define TCL_DTRACE_PROC_RETURN(a0, a1) \
- TclDTraceDbgMsg("<- proc-return", "%s %d", a0, a1); \
- tclDTraceDebugIndent--
-#define TCL_DTRACE_PROC_RESULT(a0, a1, a2, a3) \
- TclDTraceDbgMsg(" | proc-result", "%s %d %s %p", a0, a1, a2, a3)
-#define TCL_DTRACE_PROC_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
- TclDTraceDbgMsg(" | proc-args", "%s %s %s %s %s %s %s %s %s %s", a0, \
- a1, a2, a3, a4, a5, a6, a7, a8, a9)
-#define TCL_DTRACE_PROC_INFO(a0, a1, a2, a3, a4, a5, a6, a7) \
- TclDTraceDbgMsg(" | proc-info", "%s %s %s %s %d %d %s %s", a0, a1, \
- a2, a3, a4, a5, a6, a7)
+MODULE_SCOPE void TclInitLiteralTable(LiteralTable *tablePtr);
+MODULE_SCOPE ExecEnv * TclCreateExecEnv(Tcl_Interp *interp, int size);
+MODULE_SCOPE void TclDeleteExecEnv(ExecEnv *eePtr);
+MODULE_SCOPE void TclDeleteLiteralTable(Tcl_Interp *interp,
+ LiteralTable *tablePtr);
+MODULE_SCOPE void TclInvalidateCmdLiteral(Tcl_Interp *interp,
+ const char *name, Namespace *nsPtr);
-#define TCL_DTRACE_CMD_ENTRY_ENABLED() 1
-#define TCL_DTRACE_CMD_RETURN_ENABLED() 1
-#define TCL_DTRACE_CMD_RESULT_ENABLED() 1
-#define TCL_DTRACE_CMD_ARGS_ENABLED() 1
-#define TCL_DTRACE_CMD_INFO_ENABLED() 1
-#define TCL_DTRACE_CMD_ENTRY(a0, a1, a2) \
- tclDTraceDebugIndent++; \
- TclDTraceDbgMsg("-> cmd-entry", "%s %d %p", a0, a1, a2)
-#define TCL_DTRACE_CMD_RETURN(a0, a1) \
- TclDTraceDbgMsg("<- cmd-return", "%s %d", a0, a1); \
- tclDTraceDebugIndent--
-#define TCL_DTRACE_CMD_RESULT(a0, a1, a2, a3) \
- TclDTraceDbgMsg(" | cmd-result", "%s %d %s %p", a0, a1, a2, a3)
-#define TCL_DTRACE_CMD_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
- TclDTraceDbgMsg(" | cmd-args", "%s %s %s %s %s %s %s %s %s %s", a0, \
- a1, a2, a3, a4, a5, a6, a7, a8, a9)
-#define TCL_DTRACE_CMD_INFO(a0, a1, a2, a3, a4, a5, a6, a7) \
- TclDTraceDbgMsg(" | cmd-info", "%s %s %s %s %d %d %s %s", a0, a1, \
- a2, a3, a4, a5, a6, a7)
+MODULE_SCOPE struct ByteCode * TclCompileObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
-#define TCL_DTRACE_INST_START_ENABLED() TCL_DTRACE_DEBUG_INST_PROBES
-#define TCL_DTRACE_INST_DONE_ENABLED() TCL_DTRACE_DEBUG_INST_PROBES
-#define TCL_DTRACE_INST_START(a0, a1, a2) \
- TclDTraceDbgMsg(" | inst-start", "%s %d %p", a0, a1, a2)
-#define TCL_DTRACE_INST_DONE(a0, a1, a2) \
- TclDTraceDbgMsg(" | inst-end", "%s %d %p", a0, a1, a2)
+MODULE_SCOPE int TclNRExecuteByteCode(Tcl_Interp *interp,
+ struct ByteCode *codePtr);
-#define TCL_DTRACE_TCL_PROBE_ENABLED() 1
-#define TCL_DTRACE_TCL_PROBE(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
- do { \
- tclDTraceDebugEnabled = 1; \
- TclDTraceDbgMsg(" | tcl-probe", "%s %s %s %s %s %s %s %s %s %s", a0, \
- a1, a2, a3, a4, a5, a6, a7, a8, a9); \
- } while (0)
+MODULE_SCOPE Tcl_ObjCmdProc TclNRInterpCoroutine;
-#endif /* TCL_DTRACE_DEBUG */
-#endif /* _TCLCOMPILATION */
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */
diff --git a/generic/tclDecls.h b/generic/tclDecls.h
index 53dae93..9ccca78 100644
--- a/generic/tclDecls.h
+++ b/generic/tclDecls.h
@@ -1777,9 +1777,7 @@ EXTERN int Tcl_CloseEx(Tcl_Interp *interp, Tcl_Channel chan,
/* 625 */
EXTERN int Tcl_NRExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
Tcl_Obj *resultPtr);
-/* 626 */
-EXTERN int Tcl_NRSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
- int flags);
+/* Slot 626 is reserved */
/* 627 */
EXTERN int Tcl_LoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr,
const char *const symv[], int flags,
@@ -2455,7 +2453,7 @@ typedef struct TclStubs {
Tcl_Obj * (*tcl_GetStartupScript) (const char **encodingPtr); /* 623 */
int (*tcl_CloseEx) (Tcl_Interp *interp, Tcl_Channel chan, int flags); /* 624 */
int (*tcl_NRExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *resultPtr); /* 625 */
- int (*tcl_NRSubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 626 */
+ void (*reserved626)(void);
int (*tcl_LoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *const symv[], int flags, void *procPtrs, Tcl_LoadHandle *handlePtr); /* 627 */
void * (*tcl_FindSymbol) (Tcl_Interp *interp, Tcl_LoadHandle handle, const char *symbol); /* 628 */
int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */
@@ -3737,8 +3735,7 @@ extern const TclStubs *tclStubsPtr;
(tclStubsPtr->tcl_CloseEx) /* 624 */
#define Tcl_NRExprObj \
(tclStubsPtr->tcl_NRExprObj) /* 625 */
-#define Tcl_NRSubstObj \
- (tclStubsPtr->tcl_NRSubstObj) /* 626 */
+/* Slot 626 is reserved */
#define Tcl_LoadFile \
(tclStubsPtr->tcl_LoadFile) /* 627 */
#define Tcl_FindSymbol \
diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c
index 9f16f88..019521c 100644
--- a/generic/tclDictObj.c
+++ b/generic/tclDictObj.c
@@ -88,26 +88,26 @@ static int DictMapLoopCallback(ClientData data[],
*/
static const EnsembleImplMap implementationMap[] = {
- {"append", DictAppendCmd, TclCompileDictAppendCmd, NULL, 0 },
- {"create", DictCreateCmd, TclCompileDictCreateCmd, NULL, 0 },
- {"exists", DictExistsCmd, TclCompileDictExistsCmd, NULL, 0 },
+ {"append", DictAppendCmd, NULL, NULL, 0 },
+ {"create", DictCreateCmd, NULL, NULL, 0 },
+ {"exists", DictExistsCmd, NULL, NULL, 0 },
{"filter", DictFilterCmd, NULL, NULL, 0 },
- {"for", DictForNRCmd, TclCompileDictForCmd, NULL, 0 },
- {"get", DictGetCmd, TclCompileDictGetCmd, NULL, 0 },
- {"incr", DictIncrCmd, TclCompileDictIncrCmd, NULL, 0 },
- {"info", DictInfoCmd, TclCompileBasic1ArgCmd, NULL, 0 },
- {"keys", DictKeysCmd, TclCompileBasic1Or2ArgCmd, NULL, 0 },
- {"lappend", DictLappendCmd, TclCompileDictLappendCmd, NULL, 0 },
- {"map", DictMapNRCmd, TclCompileDictMapCmd, NULL, 0 },
- {"merge", DictMergeCmd, TclCompileDictMergeCmd, NULL, 0 },
- {"remove", DictRemoveCmd, TclCompileBasicMin1ArgCmd, NULL, 0 },
+ {"for", DictForNRCmd, NULL, NULL, 0 },
+ {"get", DictGetCmd, NULL, NULL, 0 },
+ {"incr", DictIncrCmd, NULL, NULL, 0 },
+ {"info", DictInfoCmd, NULL, NULL, 0 },
+ {"keys", DictKeysCmd, NULL, NULL, 0 },
+ {"lappend", DictLappendCmd, NULL, NULL, 0 },
+ {"map", DictMapNRCmd, NULL, NULL, 0 },
+ {"merge", DictMergeCmd, NULL, NULL, 0 },
+ {"remove", DictRemoveCmd, NULL, NULL, 0 },
{"replace", DictReplaceCmd, NULL, NULL, 0 },
- {"set", DictSetCmd, TclCompileDictSetCmd, NULL, 0 },
- {"size", DictSizeCmd, TclCompileBasic1ArgCmd, NULL, 0 },
- {"unset", DictUnsetCmd, TclCompileDictUnsetCmd, NULL, 0 },
- {"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, 0 },
- {"values", DictValuesCmd, TclCompileBasic1Or2ArgCmd, NULL, 0 },
- {"with", DictWithCmd, TclCompileDictWithCmd, NULL, 0 },
+ {"set", DictSetCmd, NULL, NULL, 0 },
+ {"size", DictSizeCmd, NULL, NULL, 0 },
+ {"unset", DictUnsetCmd, NULL, NULL, 0 },
+ {"update", DictUpdateCmd, NULL, NULL, 0 },
+ {"values", DictValuesCmd, NULL, NULL, 0 },
+ {"with", DictWithCmd, NULL, NULL, 0 },
{NULL, NULL, NULL, NULL, 0}
};
diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c
index 766f5d7..a58851d 100644
--- a/generic/tclEnsemble.c
+++ b/generic/tclEnsemble.c
@@ -11,7 +11,6 @@
*/
#include "tclInt.h"
-#include "tclCompile.h"
/*
* Declarations for functions local to this file:
@@ -33,15 +32,6 @@ static void MakeCachedEnsembleCommand(Tcl_Obj *objPtr,
static void FreeEnsembleCmdRep(Tcl_Obj *objPtr);
static void DupEnsembleCmdRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr);
static void StringOfEnsembleCmdRep(Tcl_Obj *objPtr);
-static int CompileToCompiledCommand(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, int depth, Command *cmdPtr,
- CompileEnv *envPtr);
-static void CompileToInvokedCommand(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Tcl_Obj *replacements,
- Command *cmdPtr, CompileEnv *envPtr);
-static int CompileBasicNArgCommand(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- CompileEnv *envPtr);
/*
* The lists of subcommands and options for the [namespace ensemble] command.
@@ -690,10 +680,6 @@ Tcl_CreateEnsemble(
nsPtr->exportLookupEpoch++;
- if (flags & ENSEMBLE_COMPILE) {
- ((Command *) ensemblePtr->token)->compileProc = TclCompileEnsemble;
- }
-
if (nameObj != NULL) {
TclDecrRefCount(nameObj);
}
@@ -763,15 +749,6 @@ Tcl_SetEnsembleSubcommandList(
ensemblePtr->nsPtr->exportLookupEpoch++;
- /*
- * Special hack to make compiling of [info exists] work when the
- * dictionary is modified.
- */
-
- if (cmdPtr->compileProc != NULL) {
- ((Interp *) interp)->compileEpoch++;
- }
-
return TCL_OK;
}
@@ -840,15 +817,6 @@ Tcl_SetEnsembleParameterList(
ensemblePtr->nsPtr->exportLookupEpoch++;
- /*
- * Special hack to make compiling of [info exists] work when the
- * dictionary is modified.
- */
-
- if (cmdPtr->compileProc != NULL) {
- ((Interp *) interp)->compileEpoch++;
- }
-
return TCL_OK;
}
@@ -939,15 +907,6 @@ Tcl_SetEnsembleMappingDict(
ensemblePtr->nsPtr->exportLookupEpoch++;
- /*
- * Special hack to make compiling of [info exists] work when the
- * dictionary is modified.
- */
-
- if (cmdPtr->compileProc != NULL) {
- ((Interp *) interp)->compileEpoch++;
- }
-
return TCL_OK;
}
@@ -1042,7 +1001,6 @@ Tcl_SetEnsembleFlags(
{
Command *cmdPtr = (Command *) token;
EnsembleConfig *ensemblePtr;
- int wasCompiled;
if (!isEnsemble(cmdPtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
@@ -1052,7 +1010,6 @@ Tcl_SetEnsembleFlags(
}
ensemblePtr = cmdPtr->objClientData;
- wasCompiled = ensemblePtr->flags & ENSEMBLE_COMPILE;
/*
* This API refuses to set the ENSEMBLE_DEAD flag...
@@ -1070,24 +1027,6 @@ Tcl_SetEnsembleFlags(
ensemblePtr->nsPtr->exportLookupEpoch++;
- /*
- * If the ENSEMBLE_COMPILE flag status was changed, install or remove the
- * compiler function and bump the interpreter's compilation epoch so that
- * bytecode gets regenerated.
- */
-
- if (flags & ENSEMBLE_COMPILE) {
- if (!wasCompiled) {
- ((Command*) ensemblePtr->token)->compileProc = TclCompileEnsemble;
- ((Interp *) interp)->compileEpoch++;
- }
- } else {
- if (wasCompiled) {
- ((Command *) ensemblePtr->token)->compileProc = NULL;
- ((Interp *) interp)->compileEpoch++;
- }
- }
-
return TCL_OK;
}
@@ -1578,14 +1517,6 @@ TclMakeEnsemble(
}
}
Tcl_SetEnsembleMappingDict(interp, ensemble, mapDict);
-
- /*
- * Switch on compilation always for core ensembles now that we can do
- * nice bytecode things with them.
- */
-
- Tcl_SetEnsembleFlags(interp, ensemble,
- ensembleFlags | ENSEMBLE_COMPILE);
}
Tcl_DStringFree(&buf);
@@ -2703,789 +2634,6 @@ StringOfEnsembleCmdRep(
}
/*
- *----------------------------------------------------------------------
- *
- * TclCompileEnsemble --
- *
- * Procedure called to compile an ensemble command. Note that most
- * ensembles are not compiled, since modifying a compiled ensemble causes
- * a invalidation of all existing bytecode (expensive!) which is not
- * normally warranted.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the subcommands of the
- * ensemble at runtime if a compile-time mapping is possible.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclCompileEnsemble(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
- Tcl_Obj *mapObj, *subcmdObj, *targetCmdObj, *listObj, **elems;
- Tcl_Obj *replaced = Tcl_NewObj(), *replacement;
- Tcl_Command ensemble = (Tcl_Command) cmdPtr;
- Command *oldCmdPtr = cmdPtr, *newCmdPtr;
- int len, result, flags = 0, i, depth = 1, invokeAnyway = 0;
- int ourResult = TCL_ERROR;
- unsigned numBytes;
- const char *word;
-
- Tcl_IncrRefCount(replaced);
-
- /*
- * This is where we return to if we are parsing multiple nested compiled
- * ensembles. [info object] is such a beast.
- */
-
- checkNextWord:
- if (parsePtr->numWords < depth + 1) {
- goto failed;
- }
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
- /*
- * Too hard.
- */
-
- goto failed;
- }
-
- word = tokenPtr[1].start;
- numBytes = tokenPtr[1].size;
-
- /*
- * There's a sporting chance we'll be able to compile this. But now we
- * must check properly. To do that, check that we're compiling an ensemble
- * that has a compilable command as its appropriate subcommand.
- */
-
- if (Tcl_GetEnsembleMappingDict(NULL, ensemble, &mapObj) != TCL_OK
- || mapObj == NULL) {
- /*
- * Either not an ensemble or a mapping isn't installed. Crud. Too hard
- * to proceed.
- */
-
- goto failed;
- }
-
- /*
- * Also refuse to compile anything that uses a formal parameter list for
- * now, on the grounds that it is too complex.
- */
-
- if (Tcl_GetEnsembleParameterList(NULL, ensemble, &listObj) != TCL_OK
- || listObj != NULL) {
- /*
- * Figuring out how to compile this has become too much. Bail out.
- */
-
- goto failed;
- }
-
- /*
- * Next, get the flags. We need them on several code paths so that we can
- * know whether we're to do prefix matching.
- */
-
- (void) Tcl_GetEnsembleFlags(NULL, ensemble, &flags);
-
- /*
- * Check to see if there's also a subcommand list; must check to see if
- * the subcommand we are calling is in that list if it exists, since that
- * list filters the entries in the map.
- */
-
- (void) Tcl_GetEnsembleSubcommandList(NULL, ensemble, &listObj);
- if (listObj != NULL) {
- int sclen;
- const char *str;
- Tcl_Obj *matchObj = NULL;
-
- if (Tcl_ListObjGetElements(NULL, listObj, &len, &elems) != TCL_OK) {
- goto failed;
- }
- for (i=0 ; i<len ; i++) {
- str = Tcl_GetStringFromObj(elems[i], &sclen);
- if ((sclen == (int) numBytes) && !memcmp(word, str, numBytes)) {
- /*
- * Exact match! Excellent!
- */
-
- result = Tcl_DictObjGet(NULL, mapObj,elems[i], &targetCmdObj);
- if (result != TCL_OK || targetCmdObj == NULL) {
- goto failed;
- }
- replacement = elems[i];
- goto doneMapLookup;
- }
-
- /*
- * Check to see if we've got a prefix match. A single prefix match
- * is fine, and allows us to refine our dictionary lookup, but
- * multiple prefix matches is a Bad Thing and will prevent us from
- * making progress. Note that we cannot do the lookup immediately
- * in the prefix case; might be another entry later in the list
- * that causes things to fail.
- */
-
- if ((flags & TCL_ENSEMBLE_PREFIX)
- && strncmp(word, str, numBytes) == 0) {
- if (matchObj != NULL) {
- goto failed;
- }
- matchObj = elems[i];
- }
- }
- if (matchObj == NULL) {
- goto failed;
- }
- result = Tcl_DictObjGet(NULL, mapObj, matchObj, &targetCmdObj);
- if (result != TCL_OK || targetCmdObj == NULL) {
- goto failed;
- }
- replacement = matchObj;
- } else {
- Tcl_DictSearch s;
- int done, matched;
- Tcl_Obj *tmpObj;
-
- /*
- * No map, so check the dictionary directly.
- */
-
- TclNewStringObj(subcmdObj, word, (int) numBytes);
- result = Tcl_DictObjGet(NULL, mapObj, subcmdObj, &targetCmdObj);
- if (result == TCL_OK && targetCmdObj != NULL) {
- /*
- * Got it. Skip the fiddling around with prefixes.
- */
-
- replacement = subcmdObj;
- goto doneMapLookup;
- }
- TclDecrRefCount(subcmdObj);
-
- /*
- * We've not literally got a valid subcommand. But maybe we have a
- * prefix. Check if prefix matches are allowed.
- */
-
- if (!(flags & TCL_ENSEMBLE_PREFIX)) {
- goto failed;
- }
-
- /*
- * Iterate over the keys in the dictionary, checking to see if we're a
- * prefix.
- */
-
- Tcl_DictObjFirst(NULL, mapObj, &s, &subcmdObj, &tmpObj, &done);
- matched = 0;
- replacement = NULL; /* Silence, fool compiler! */
- while (!done) {
- if (strncmp(TclGetString(subcmdObj), word, numBytes) == 0) {
- if (matched++) {
- /*
- * Must have matched twice! Not unique, so no point
- * looking further.
- */
-
- break;
- }
- replacement = subcmdObj;
- targetCmdObj = tmpObj;
- }
- Tcl_DictObjNext(&s, &subcmdObj, &tmpObj, &done);
- }
- Tcl_DictObjDone(&s);
-
- /*
- * If we have anything other than a single match, we've failed the
- * unique prefix check.
- */
-
- if (matched != 1) {
- invokeAnyway = 1;
- goto failed;
- }
- }
-
- /*
- * OK, we definitely map to something. But what?
- *
- * The command we map to is the first word out of the map element. Note
- * that we also reject dealing with multi-element rewrites if we are in a
- * safe interpreter, as there is otherwise a (highly gnarly!) way to make
- * Tcl crash open to exploit.
- */
-
- doneMapLookup:
- Tcl_ListObjAppendElement(NULL, replaced, replacement);
- if (Tcl_ListObjGetElements(NULL, targetCmdObj, &len, &elems) != TCL_OK) {
- goto failed;
- } else if (len != 1) {
- /*
- * Note that at this point we know we can't issue any special
- * instruction sequence as the mapping isn't one that we support at
- * the compiled level.
- */
-
- goto cleanup;
- }
- targetCmdObj = elems[0];
-
- oldCmdPtr = cmdPtr;
- Tcl_IncrRefCount(targetCmdObj);
- newCmdPtr = (Command *) Tcl_GetCommandFromObj(interp, targetCmdObj);
- TclDecrRefCount(targetCmdObj);
- if (newCmdPtr == NULL || Tcl_IsSafe(interp)
- || newCmdPtr->nsPtr->flags & NS_SUPPRESS_COMPILATION
- || newCmdPtr->flags & CMD_HAS_EXEC_TRACES
- || ((Interp *)interp)->flags & DONT_COMPILE_CMDS_INLINE) {
- /*
- * Maps to an undefined command or a command without a compiler.
- * Cannot compile.
- */
-
- goto cleanup;
- }
- cmdPtr = newCmdPtr;
- depth++;
-
- /*
- * See whether we have a nested ensemble. If we do, we can go round the
- * mulberry bush again, consuming the next word.
- */
-
- if (cmdPtr->compileProc == TclCompileEnsemble) {
- tokenPtr = TokenAfter(tokenPtr);
- ensemble = (Tcl_Command) cmdPtr;
- goto checkNextWord;
- }
-
- /*
- * Now we've done the mapping process, can now actually try to compile.
- * If there is a subcommand compiler and that successfully produces code,
- * we'll use that. Otherwise, we fall back to generating opcodes to do the
- * invoke at runtime.
- */
-
- invokeAnyway = 1;
- if (CompileToCompiledCommand(interp, parsePtr, depth, cmdPtr,
- envPtr) == TCL_OK) {
- ourResult = TCL_OK;
- goto cleanup;
- }
-
- /*
- * Failed to do a full compile for some reason. Try to do a direct invoke
- * instead of going through the ensemble lookup process again.
- */
-
- failed:
- if (depth < 250) {
- if (depth > 1) {
- if (!invokeAnyway) {
- cmdPtr = oldCmdPtr;
- depth--;
- }
- (void) Tcl_ListObjReplace(NULL, replaced, depth, 2, 0, NULL);
- }
- CompileToInvokedCommand(interp, parsePtr, replaced, cmdPtr, envPtr);
- ourResult = TCL_OK;
- }
-
- /*
- * Release the memory we allocated. If we've got here, we've either done
- * something useful or we're in a case that we can't compile at all and
- * we're just giving up.
- */
-
- cleanup:
- Tcl_DecrRefCount(replaced);
- return ourResult;
-}
-
-/*
- * How to compile a subcommand using its own command compiler. To do that, we
- * have to perform some trickery to rewrite the arguments, as compilers *must*
- * have parse tokens that refer to addresses in the original script.
- */
-
-static int
-CompileToCompiledCommand(
- Tcl_Interp *interp,
- Tcl_Parse *parsePtr,
- int depth,
- Command *cmdPtr,
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Parse synthetic;
- Tcl_Token *tokenPtr;
- int result, i;
-
- if (cmdPtr->compileProc == NULL) {
- return TCL_ERROR;
- }
-
- TclParseInit(interp, NULL, 0, &synthetic);
- synthetic.numWords = parsePtr->numWords - depth + 1;
- TclGrowParseTokenArray(&synthetic, 2);
- synthetic.numTokens = 2;
-
- /*
- * Now we have the space to work in, install something rewritten. The
- * first word will "officially" be the bytes of the structured ensemble
- * name. That's technically wrong, but nobody will care; we just need
- * *something* here...
- */
-
- synthetic.tokenPtr[0].type = TCL_TOKEN_SIMPLE_WORD;
- synthetic.tokenPtr[0].start = parsePtr->tokenPtr[0].start;
- synthetic.tokenPtr[0].numComponents = 1;
- synthetic.tokenPtr[1].type = TCL_TOKEN_TEXT;
- synthetic.tokenPtr[1].start = parsePtr->tokenPtr[0].start;
- synthetic.tokenPtr[1].numComponents = 0;
- for (i=0,tokenPtr=parsePtr->tokenPtr ; i<depth ; i++) {
- int sclen = (tokenPtr->start - synthetic.tokenPtr[0].start)
- + tokenPtr->size;
-
- synthetic.tokenPtr[0].size = sclen;
- synthetic.tokenPtr[1].size = sclen;
- tokenPtr = TokenAfter(tokenPtr);
- }
-
- /*
- * Copy over the real argument tokens.
- */
-
- for (i=1; i<synthetic.numWords; i++) {
- int toCopy;
-
- toCopy = tokenPtr->numComponents + 1;
- TclGrowParseTokenArray(&synthetic, toCopy);
- memcpy(synthetic.tokenPtr + synthetic.numTokens, tokenPtr,
- sizeof(Tcl_Token) * toCopy);
- synthetic.numTokens += toCopy;
- tokenPtr = TokenAfter(tokenPtr);
- }
-
- /*
- * Hand off compilation to the subcommand compiler. At last!
- */
-
- result = cmdPtr->compileProc(interp, &synthetic, cmdPtr, envPtr);
-
- /*
- * Clean up if necessary.
- */
-
- Tcl_FreeParse(&synthetic);
- return result;
-}
-
-/*
- * How to compile a subcommand to a _replacing_ invoke of its implementation
- * command.
- */
-
-static void
-CompileToInvokedCommand(
- Tcl_Interp *interp,
- Tcl_Parse *parsePtr,
- Tcl_Obj *replacements,
- Command *cmdPtr,
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokPtr;
- Tcl_Obj *objPtr, **words;
- char *bytes;
- int length, i, numWords, cmdLit;
-
- /*
- * Push the words of the command.
- */
-
- Tcl_ListObjGetElements(NULL, replacements, &numWords, &words);
- for (i=0,tokPtr=parsePtr->tokenPtr ; i<parsePtr->numWords ; i++) {
- if (i > 0 && i < numWords+1) {
- bytes = Tcl_GetStringFromObj(words[i-1], &length);
- PushLiteral(envPtr, bytes, length);
- } else if (tokPtr->type == TCL_TOKEN_SIMPLE_WORD) {
- int literal = TclRegisterNewLiteral(envPtr,
- tokPtr[1].start, tokPtr[1].size);
-
- TclEmitPush(literal, envPtr);
- } else {
- CompileTokens(envPtr, tokPtr, interp);
- }
- tokPtr = TokenAfter(tokPtr);
- }
-
- /*
- * Push the name of the command we're actually dispatching to as part of
- * the implementation.
- */
-
- objPtr = Tcl_NewObj();
- Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr);
- bytes = Tcl_GetStringFromObj(objPtr, &length);
- cmdLit = TclRegisterNewCmdLiteral(envPtr, bytes, length);
- TclSetCmdNameObj(interp, envPtr->literalArrayPtr[cmdLit].objPtr, cmdPtr);
- TclEmitPush(cmdLit, envPtr);
- TclDecrRefCount(objPtr);
-
- /*
- * Do the replacing dispatch.
- */
-
- TclEmitInstInt4(INST_INVOKE_REPLACE, parsePtr->numWords, envPtr);
- TclEmitInt1(numWords+1, envPtr);
- TclAdjustStackDepth(-1, envPtr); /* Correction to stack depth calcs. */
-}
-
-/*
- * Helpers that do issuing of instructions for commands that "don't have
- * compilers" (well, they do; these). They all work by just generating base
- * code to invoke the command; they're intended for ensemble subcommands so
- * that the costs of INST_INVOKE_REPLACE can be avoided where we can work out
- * that they're not needed.
- *
- * Note that these are NOT suitable for commands where there's an argument
- * that is a script, as an [info level] or [info frame] in the inner context
- * can see the difference.
- */
-
-static int
-CompileBasicNArgCommand(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- Tcl_Token *tokenPtr;
- Tcl_Obj *objPtr;
- char *bytes;
- int length, i, literal;
-
- /*
- * Push the name of the command we're actually dispatching to as part of
- * the implementation.
- */
-
- objPtr = Tcl_NewObj();
- Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr);
- bytes = Tcl_GetStringFromObj(objPtr, &length);
- literal = TclRegisterNewCmdLiteral(envPtr, bytes, length);
- TclSetCmdNameObj(interp, envPtr->literalArrayPtr[literal].objPtr, cmdPtr);
- TclEmitPush(literal, envPtr);
- TclDecrRefCount(objPtr);
-
- /*
- * Push the words of the command.
- */
-
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- for (i=1 ; i<parsePtr->numWords ; i++) {
- if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
- PushLiteral(envPtr, tokenPtr[1].start, tokenPtr[1].size);
- } else {
- CompileTokens(envPtr, tokenPtr, interp);
- }
- tokenPtr = TokenAfter(tokenPtr);
- }
-
- /*
- * Do the standard dispatch.
- */
-
- if (i <= 255) {
- TclEmitInstInt1(INST_INVOKE_STK1, i, envPtr);
- } else {
- TclEmitInstInt4(INST_INVOKE_STK4, i, envPtr);
- }
- return TCL_OK;
-}
-
-int
-TclCompileBasic0ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords != 1) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-int
-TclCompileBasic1ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-int
-TclCompileBasic2ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords != 3) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-int
-TclCompileBasic3ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords != 4) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-int
-TclCompileBasic0Or1ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords != 1 && parsePtr->numWords != 2) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-int
-TclCompileBasic1Or2ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords != 2 && parsePtr->numWords != 3) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-int
-TclCompileBasic2Or3ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords != 3 && parsePtr->numWords != 4) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-int
-TclCompileBasic0To2ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords < 1 || parsePtr->numWords > 3) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-int
-TclCompileBasic1To3ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords < 2 || parsePtr->numWords > 4) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-int
-TclCompileBasicMin0ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords < 1) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-int
-TclCompileBasicMin1ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords < 2) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-int
-TclCompileBasicMin2ArgCmd(
- Tcl_Interp *interp, /* Used for error reporting. */
- Tcl_Parse *parsePtr, /* Points to a parse structure for the command
- * created by Tcl_ParseCommand. */
- Command *cmdPtr, /* Points to defintion of command being
- * compiled. */
- CompileEnv *envPtr) /* Holds resulting instructions. */
-{
- /*
- * Verify that the number of arguments is correct; that's the only case
- * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
- * which is the only code that sees the shenanigans of ensemble dispatch.
- */
-
- if (parsePtr->numWords < 3) {
- return TCL_ERROR;
- }
-
- return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
-}
-
-/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index 4ebeeb8..be85fb9 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -16,7 +16,7 @@
*/
#include "tclInt.h"
-#include "tclCompile.h"
+#include "tclCompileInt.h"
#include "tclOOInt.h"
#include "tommath.h"
#include <math.h>
@@ -52,31 +52,17 @@ TCL_DECLARE_MUTEX(execMutex)
static int cachedInExit = 0;
-#ifdef TCL_COMPILE_DEBUG
-/*
- * Variable that controls whether execution tracing is enabled and, if so,
- * what level of tracing is desired:
- * 0: no execution tracing
- * 1: trace invocations of Tcl procs only
- * 2: trace invocations of all (not compiled away) commands
- * 3: display each instruction executed
- * This variable is linked to the Tcl variable "tcl_traceExec".
- */
-
-int tclTraceExec = 0;
-#endif
-
/*
* Mapping from expression instruction opcodes to strings; used for error
* messages. Note that these entries must match the order and number of the
- * expression opcodes (e.g., INST_LOR) in tclCompile.h.
+ * expression opcodes (e.g., INST_BITOR) in tclCompile.h.
*
* Does not include the string for INST_EXPON (and beyond), as that is
* disjoint for backward-compatability reasons.
*/
static const char *const operatorStrings[] = {
- "||", "&&", "|", "^", "&", "==", "!=", "<", ">", "<=", ">=", "<<", ">>",
+ "|", "^", "&", "==", "!=", "<", ">", "<=", ">=", "<<", ">>",
"+", "-", "*", "/", "%", "+", "-", "~", "!",
"BUILTIN FUNCTION", "FUNCTION",
"", "", "", "", "", "", "", "", "eq", "ne"
@@ -87,79 +73,10 @@ static const char *const operatorStrings[] = {
* messages.
*/
-#ifdef TCL_COMPILE_DEBUG
-static const char *const resultStrings[] = {
- "TCL_OK", "TCL_ERROR", "TCL_RETURN", "TCL_BREAK", "TCL_CONTINUE"
-};
-#endif
-
/*
* These are used by evalstats to monitor object usage in Tcl.
*/
-#ifdef TCL_COMPILE_STATS
-long tclObjsAlloced = 0;
-long tclObjsFreed = 0;
-long tclObjsShared[TCL_MAX_SHARED_OBJ_STATS] = { 0, 0, 0, 0, 0 };
-#endif /* TCL_COMPILE_STATS */
-
-/*
- * Support pre-8.5 bytecodes unless specifically requested otherwise.
- */
-
-#ifndef TCL_SUPPORT_84_BYTECODE
-#define TCL_SUPPORT_84_BYTECODE 1
-#endif
-
-#if TCL_SUPPORT_84_BYTECODE
-/*
- * We need to know the tclBuiltinFuncTable to support translation of pre-8.5
- * math functions to the namespace-based ::tcl::mathfunc::op in 8.5+.
- */
-
-typedef struct {
- const char *name; /* Name of function. */
- int numArgs; /* Number of arguments for function. */
-} BuiltinFunc;
-
-/*
- * Table describing the built-in math functions. Entries in this table are
- * indexed by the values of the INST_CALL_BUILTIN_FUNC instruction's
- * operand byte.
- */
-
-static BuiltinFunc const tclBuiltinFuncTable[] = {
- {"acos", 1},
- {"asin", 1},
- {"atan", 1},
- {"atan2", 2},
- {"ceil", 1},
- {"cos", 1},
- {"cosh", 1},
- {"exp", 1},
- {"floor", 1},
- {"fmod", 2},
- {"hypot", 2},
- {"log", 1},
- {"log10", 1},
- {"pow", 2},
- {"sin", 1},
- {"sinh", 1},
- {"sqrt", 1},
- {"tan", 1},
- {"tanh", 1},
- {"abs", 1},
- {"double", 1},
- {"int", 1},
- {"rand", 0},
- {"round", 1},
- {"srand", 1},
- {"wide", 1},
- {NULL, 0},
-};
-
-#define LAST_BUILTIN_FUNC 25
-#endif
/*
* NR_TEBC
@@ -167,7 +84,7 @@ static BuiltinFunc const tclBuiltinFuncTable[] = {
* Minimal data required to fully reconstruct the execution state.
*/
-typedef struct TEBCdata {
+typedef struct {
ByteCode *codePtr; /* Constant until the BC returns */
/* -----------------------------------------*/
Tcl_Obj **tosPtr;
@@ -254,18 +171,9 @@ VarHashCreateVar(
/* Verify the stack depth, only when no expansion is in progress */
-#if TCL_COMPILE_DEBUG
-#define CHECK_STACK() \
- ValidatePcAndStackTop(codePtr, pc, CURR_DEPTH, \
- /*checkStack*/ auxObjList == NULL)
-#else
-#define CHECK_STACK()
-#endif
-
#define NEXT_INST_F(pcAdjustment, nCleanup, resultHandling) \
do { \
TCL_CT_ASSERT((nCleanup >= 0) && (nCleanup <= 2)); \
- CHECK_STACK(); \
if (nCleanup == 0) { \
if (resultHandling != 0) { \
if ((resultHandling) > 0) { \
@@ -295,7 +203,6 @@ VarHashCreateVar(
} while (0)
#define NEXT_INST_V(pcAdjustment, nCleanup, resultHandling) \
- CHECK_STACK(); \
do { \
pc += (pcAdjustment); \
cleanup = (nCleanup); \
@@ -343,68 +250,6 @@ VarHashCreateVar(
* only used in TRACE* calls to get a string from an object.
*/
-#ifdef TCL_COMPILE_DEBUG
-# define TRACE(a) \
- while (traceInstructions) { \
- fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, \
- (int) CURR_DEPTH, \
- (unsigned) (pc - codePtr->codeStart), \
- GetOpcodeName(pc)); \
- printf a; \
- break; \
- }
-# define TRACE_APPEND(a) \
- while (traceInstructions) { \
- printf a; \
- break; \
- }
-# define TRACE_WITH_OBJ(a, objPtr) \
- while (traceInstructions) { \
- fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, \
- (int) CURR_DEPTH, \
- (unsigned) (pc - codePtr->codeStart), \
- GetOpcodeName(pc)); \
- printf a; \
- TclPrintObject(stdout, objPtr, 30); \
- fprintf(stdout, "\n"); \
- break; \
- }
-# define O2S(objPtr) \
- (objPtr ? TclGetString(objPtr) : "")
-#else /* !TCL_COMPILE_DEBUG */
-# define TRACE(a)
-# define TRACE_APPEND(a)
-# define TRACE_WITH_OBJ(a, objPtr)
-# define O2S(objPtr)
-#endif /* TCL_COMPILE_DEBUG */
-
-/*
- * DTrace instruction probe macros.
- */
-
-#define TCL_DTRACE_INST_NEXT() \
- do { \
- if (TCL_DTRACE_INST_DONE_ENABLED()) { \
- if (curInstName) { \
- TCL_DTRACE_INST_DONE(curInstName, (int) CURR_DEPTH, \
- tosPtr); \
- } \
- curInstName = tclInstructionTable[*pc].name; \
- if (TCL_DTRACE_INST_START_ENABLED()) { \
- TCL_DTRACE_INST_START(curInstName, (int) CURR_DEPTH, \
- tosPtr); \
- } \
- } else if (TCL_DTRACE_INST_START_ENABLED()) { \
- TCL_DTRACE_INST_START(tclInstructionTable[*pc].name, \
- (int) CURR_DEPTH, tosPtr); \
- } \
- } while (0)
-#define TCL_DTRACE_INST_LAST() \
- do { \
- if (TCL_DTRACE_INST_DONE_ENABLED() && curInstName) { \
- TCL_DTRACE_INST_DONE(curInstName, (int) CURR_DEPTH, tosPtr);\
- } \
- } while (0)
/*
* Macro used in this file to save a function call for common uses of
@@ -669,19 +514,6 @@ static const size_t Exp64ValueSize = sizeof(Exp64Value) / sizeof(Tcl_WideInt);
* Declarations for local procedures to this file:
*/
-#ifdef TCL_COMPILE_STATS
-static int EvalStatsCmd(ClientData clientData,
- Tcl_Interp *interp, int objc,
- Tcl_Obj *const objv[]);
-#endif /* TCL_COMPILE_STATS */
-#ifdef TCL_COMPILE_DEBUG
-static const char * GetOpcodeName(const unsigned char *pc);
-static void PrintByteCodeInfo(ByteCode *codePtr);
-static const char * StringForResultCode(int result);
-static void ValidatePcAndStackTop(ByteCode *codePtr,
- const unsigned char *pc, int stackTop,
- int checkStack);
-#endif /* TCL_COMPILE_DEBUG */
static ByteCode * CompileExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
static void DupExprCodeInternalRep(Tcl_Obj *srcPtr,
Tcl_Obj *copyPtr);
@@ -701,7 +533,6 @@ static const char * GetSrcInfoForPc(const unsigned char *pc,
static void IllegalExprOperandType(Tcl_Interp *interp,
const unsigned char *pc, Tcl_Obj *opndPtr);
static void InitByteCodeExecution(Tcl_Interp *interp);
-static void ReleaseDictIterator(Tcl_Obj *objPtr);
static Tcl_NRPostProc CopyCallback;
static Tcl_NRPostProc ExprObjCallback;
@@ -720,55 +551,6 @@ static const Tcl_ObjType exprCodeType = {
NULL /* setFromAnyProc */
};
-/*
- * Custom object type only used in this file; values of its type should never
- * be seen by user scripts.
- */
-
-static const Tcl_ObjType dictIteratorType = {
- "dictIterator",
- ReleaseDictIterator,
- NULL, NULL, NULL
-};
-
-/*
- *----------------------------------------------------------------------
- *
- * ReleaseDictIterator --
- *
- * This takes apart a dictionary iterator that is stored in the given Tcl
- * object.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Deallocates memory, marks the object as being untyped.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-ReleaseDictIterator(
- Tcl_Obj *objPtr)
-{
- Tcl_DictSearch *searchPtr;
- Tcl_Obj *dictPtr;
-
- /*
- * First kill the search, and then release the reference to the dictionary
- * that we were holding.
- */
-
- searchPtr = objPtr->internalRep.twoPtrValue.ptr1;
- Tcl_DictObjDone(searchPtr);
- ckfree(searchPtr);
-
- dictPtr = objPtr->internalRep.twoPtrValue.ptr2;
- TclDecrRefCount(dictPtr);
-
- objPtr->typePtr = NULL;
-}
static void UpdateStringOfBcSource(Tcl_Obj *objPtr);
@@ -796,7 +578,19 @@ UpdateStringOfBcSource(
objPtr->length = len;
}
+static inline int
+TclCodeIsStale(
+ ByteCode *codePtr,
+ Interp *iPtr)
+{
+ Namespace *namespacePtr = iPtr->varFramePtr->nsPtr;
+ int check = (((Interp *) *codePtr->interpHandle != iPtr)
+ || (codePtr->nsPtr != namespacePtr)
+ || (codePtr->nsEpoch != namespacePtr->resolverEpoch)
+ || (codePtr->localCachePtr != iPtr->varFramePtr->localCachePtr));
+ return check;
+}
/*
@@ -826,15 +620,6 @@ InitByteCodeExecution(
* "tcl_traceExec" is linked to control
* instruction tracing. */
{
-#ifdef TCL_COMPILE_DEBUG
- if (Tcl_LinkVar(interp, "tcl_traceExec", (char *) &tclTraceExec,
- TCL_LINK_INT) != TCL_OK) {
- Tcl_Panic("InitByteCodeExecution: can't create link for tcl_traceExec variable");
- }
-#endif
-#ifdef TCL_COMPILE_STATS
- Tcl_CreateObjCommand(interp, "evalstats", EvalStatsCmd, NULL, NULL);
-#endif /* TCL_COMPILE_STATS */
}
/*
@@ -1112,14 +897,8 @@ CompileExprObj(
* is valid in the current context.
*/
if (objPtr->typePtr == &exprCodeType) {
- Namespace *namespacePtr = iPtr->varFramePtr->nsPtr;
-
codePtr = objPtr->internalRep.otherValuePtr;
- if (((Interp *) *codePtr->interpHandle != iPtr)
- || (codePtr->compileEpoch != iPtr->compileEpoch)
- || (codePtr->nsPtr != namespacePtr)
- || (codePtr->nsEpoch != namespacePtr->resolverEpoch)
- || (codePtr->localCachePtr != iPtr->varFramePtr->localCachePtr)) {
+ if (TclCodeIsStale(codePtr, iPtr)) {
FreeExprCodeInternalRep(objPtr);
}
}
@@ -1155,12 +934,6 @@ CompileExprObj(
codePtr->localCachePtr = iPtr->varFramePtr->localCachePtr;
codePtr->localCachePtr->refCount++;
}
-#ifdef TCL_COMPILE_DEBUG
- if (tclTraceCompile == 2) {
- TclPrintByteCodeObj(interp, objPtr);
- fflush(stdout);
- }
-#endif /* TCL_COMPILE_DEBUG */
}
return codePtr;
}
@@ -1255,7 +1028,6 @@ TclCompileObj(
{
register Interp *iPtr = (Interp *) interp;
register ByteCode *codePtr; /* Tcl Internal type of bytecode. */
- Namespace *namespacePtr = iPtr->varFramePtr->nsPtr;
/*
* If the object is not already of tclByteCodeType, compile it (and reset
@@ -1282,17 +1054,13 @@ TclCompileObj(
*/
codePtr = objPtr->internalRep.otherValuePtr;
- if (((Interp *) *codePtr->interpHandle != iPtr)
- || (codePtr->compileEpoch != iPtr->compileEpoch)
- || (codePtr->nsPtr != namespacePtr)
- || (codePtr->nsEpoch != namespacePtr->resolverEpoch)) {
+ if (TclCodeIsStale(codePtr, iPtr)) {
if (!(codePtr->flags & TCL_BYTECODE_PRECOMPILED)) {
goto recompileObj;
}
if ((Interp *) *codePtr->interpHandle != iPtr) {
Tcl_Panic("Tcl_EvalObj: compiled script jumped interps");
}
- codePtr->compileEpoch = iPtr->compileEpoch;
}
/*
@@ -1511,10 +1279,6 @@ TclNRExecuteByteCode(
TD->checkInterp = 0;
TD->capacity = codePtr->maxStackDepth;
-#ifdef TCL_COMPILE_STATS
- iPtr->stats.numExecutions++;
-#endif
-
/*
* Push the callback for bytecode execution
*/
@@ -1555,11 +1319,6 @@ TEBCresume(
int instructionCount = 0; /* Counter that is used to work out when to
* call Tcl_AsyncReady() */
- const char *curInstName;
-#ifdef TCL_COMPILE_DEBUG
- int traceInstructions; /* Whether we are doing instruction-level
- * tracing or not. */
-#endif
Var *compiledLocals = iPtr->varFramePtr->compiledLocals;
Tcl_Obj **constants = &iPtr->execEnvPtr->constants[0];
@@ -1607,23 +1366,9 @@ TEBCresume(
int objc = 0;
int opnd, length, pcAdjustment;
Var *varPtr, *arrayPtr;
-#ifdef TCL_COMPILE_DEBUG
- char cmdNameBuf[21];
-#endif
-#ifdef TCL_COMPILE_DEBUG
- traceInstructions = (tclTraceExec == 3);
-#endif
TEBC_DATA_DIG();
-#ifdef TCL_COMPILE_DEBUG
- if (!data[1] && (tclTraceExec >= 2)) {
- PrintByteCodeInfo(codePtr);
- fprintf(stdout, " Starting stack top=%d\n", (int) CURR_DEPTH);
- fflush(stdout);
- }
-#endif
-
if (data[1] /* resume from invocation */) {
if (iPtr->execEnvPtr->rewind) {
result = TCL_ERROR;
@@ -1635,19 +1380,15 @@ TEBCresume(
checkInterp = 1;
if (result == TCL_OK) {
-#ifndef TCL_COMPILE_DEBUG
if (*pc == INST_POP) {
NEXT_INST_V(1, cleanup, 0);
}
-#endif
+
/*
* Push the call's object result and continue execution with the
* next instruction.
*/
- TRACE_WITH_OBJ(("%u => ... after \"%.20s\": TCL_OK, result=",
- objc, cmdNameBuf), Tcl_GetObjResult(interp));
-
objResultPtr = Tcl_GetObjResult(interp);
/*
@@ -1747,23 +1488,6 @@ TEBCresume(
}
cleanup0:
-#ifdef TCL_COMPILE_DEBUG
- /*
- * Skip the stack depth check if an expansion is in progress.
- */
-
- CHECK_STACK();
- 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
-
/*
* Check for asynchronous handlers [Bug 746722]; we do the check every
* ASYNC_CHECK_COUNT_MASK instruction, of the form (2**n-1).
@@ -1794,26 +1518,8 @@ TEBCresume(
checkInterp = 1;
}
- TCL_DTRACE_INST_NEXT();
-
- /*
- * 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: {
+ case INST_SYNTAX: {
int code = TclGetInt4AtPtr(pc+1);
int level = TclGetUInt4AtPtr(pc+5);
@@ -1821,11 +1527,8 @@ TEBCresume(
* OBJ_AT_TOS is returnOpts, OBJ_UNDER_TOS is resultObjPtr.
*/
- TRACE(("%u %u => ", code, level));
result = TclProcessReturn(interp, code, level, OBJ_AT_TOS);
if (result == TCL_OK) {
- TRACE_APPEND(("continuing to next instruction (result=\"%.30s\")",
- O2S(objResultPtr)));
NEXT_INST_F(9, 1, 0);
}
Tcl_SetObjResult(interp, OBJ_UNDER_TOS);
@@ -1836,95 +1539,6 @@ TEBCresume(
goto processExceptionReturn;
}
- case INST_RETURN_STK:
- TRACE(("=> "));
- objResultPtr = POP_OBJECT();
- result = Tcl_SetReturnOptions(interp, OBJ_AT_TOS);
- Tcl_DecrRefCount(OBJ_AT_TOS);
- OBJ_AT_TOS = objResultPtr;
- if (result == TCL_OK) {
- TRACE_APPEND(("continuing to next instruction (result=\"%.30s\")",
- O2S(objResultPtr)));
- NEXT_INST_F(1, 0, 0);
- }
- Tcl_SetObjResult(interp, objResultPtr);
- cleanup = 1;
- goto processExceptionReturn;
-
- case INST_YIELD: {
- CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
-
- TRACE(("%.30s => ", O2S(OBJ_AT_TOS)));
- if (!corPtr) {
- TRACE_APPEND(("ERROR: yield outside coroutine\n"));
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "yield can only be called in a coroutine", -1));
- Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ILLEGAL_YIELD",
- NULL);
- goto gotError;
- }
-
-#ifdef TCL_COMPILE_DEBUG
- TRACE_WITH_OBJ(("yield, result="), iPtr->objResultPtr);
- if (traceInstructions) {
- fprintf(stdout, "\n");
- }
-#endif
-
- pc++;
- cleanup = 1;
- TEBC_YIELD();
-
- Tcl_SetObjResult(interp, OBJ_AT_TOS);
- Tcl_NRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr,
- INT2PTR(0), NULL, NULL);
-
- return TCL_OK;
- }
-
- case INST_TAILCALL: {
- Tcl_Obj *listPtr, *nsObjPtr;
-
- opnd = TclGetUInt1AtPtr(pc+1);
-
- if (!(iPtr->varFramePtr->isProcCallFrame & 1)) {
- TRACE(("%d => ERROR: tailcall in non-proc context\n", opnd));
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "tailcall can only be called from a proc or lambda", -1));
- Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "ILLEGAL", NULL);
- goto gotError;
- }
-
-#ifdef TCL_COMPILE_DEBUG
- {
- register int i;
-
- TRACE(("%d [", opnd));
- for (i=opnd-1 ; i>=0 ; i--) {
- TRACE_APPEND(("\"%.30s\"", O2S(OBJ_AT_DEPTH(i))));
- if (i > 0) {
- TRACE_APPEND((" "));
- }
- }
- TRACE_APPEND(("] => RETURN..."));
- }
-#endif
-
- /*
- * Push the evaluation of the called command into the NR callback
- * stack.
- */
-
- listPtr = Tcl_NewListObj(opnd, &OBJ_AT_DEPTH(opnd-1));
- nsObjPtr = Tcl_NewStringObj(iPtr->varFramePtr->nsPtr->fullName, -1);
- TclListObjSetElement(interp, listPtr, 0, nsObjPtr);
- iPtr->varFramePtr->tailcallPtr = listPtr;
-
- result = TCL_RETURN;
- cleanup = opnd;
- goto processExceptionReturn;
- }
-
case INST_DONE:
if (tosPtr > initTosPtr) {
/*
@@ -1935,116 +1549,13 @@ TEBCresume(
*/
Tcl_SetObjResult(interp, OBJ_AT_TOS);
-#ifdef TCL_COMPILE_DEBUG
- TRACE_WITH_OBJ(("=> return code=%d, result=", result),
- iPtr->objResultPtr);
- if (traceInstructions) {
- fprintf(stdout, "\n");
- }
-#endif
goto checkForCatch;
}
(void) POP_OBJECT();
goto abnormalReturn;
- case INST_PUSH1:
- instPush1Peephole:
- PUSH_OBJECT(codePtr->objArrayPtr[TclGetUInt1AtPtr(pc+1)]);
- TRACE_WITH_OBJ(("%u => ", TclGetInt1AtPtr(pc+1)), OBJ_AT_TOS);
- pc += 2;
-#if !TCL_COMPILE_DEBUG
- /*
- * Runtime peephole optimisation: check if we are pushing again.
- */
-
- if (*pc == INST_PUSH1) {
- TCL_DTRACE_INST_NEXT();
- goto instPush1Peephole;
- }
-#endif
- NEXT_INST_F(0, 0, 0);
-
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:
- TRACE_WITH_OBJ(("=> discarding "), OBJ_AT_TOS);
- objPtr = POP_OBJECT();
- TclDecrRefCount(objPtr);
-
- /*
- * Runtime peephole optimisation: an INST_POP is scheduled at the end
- * of most commands. If the next instruction is an INST_START_CMD,
- * fall through to it.
- */
-
- pc++;
-#if !TCL_COMPILE_DEBUG
- if (*pc == INST_START_CMD) {
- TCL_DTRACE_INST_NEXT();
- goto instStartCmdPeephole;
- }
-#endif
- NEXT_INST_F(0, 0, 0);
-
- case INST_START_CMD:
-#if !TCL_COMPILE_DEBUG
- instStartCmdPeephole:
-#endif
- /*
- * Remark that if the interpreter is marked for deletion its
- * compileEpoch is modified, so that the epoch check also verifies
- * that the interp is not deleted. If no outside call has been made
- * since the last check, it is safe to omit the check.
- */
-
- iPtr->cmdCount += TclGetUInt4AtPtr(pc+5);
- if (!checkInterp) {
- goto instStartCmdOK;
- } else if (((codePtr->compileEpoch == iPtr->compileEpoch)
- && (codePtr->nsEpoch == iPtr->varFramePtr->nsPtr->resolverEpoch))
- || (codePtr->flags & TCL_BYTECODE_PRECOMPILED)) {
- checkInterp = 0;
- instStartCmdOK:
- NEXT_INST_F(9, 0, 0);
- } else {
- const char *bytes;
-
- length = 0;
-
- /*
- * We used to switch to direct eval; for NRE-awareness we now
- * compile and eval the command so that this evaluation does not
- * add a new TEBC instance. [Bug 2910748]
- */
-
- if (TclInterpReady(interp) == TCL_ERROR) {
- goto gotError;
- }
-
- codePtr->flags |= TCL_BYTECODE_RECOMPILE;
- bytes = GetSrcInfoForPc(pc, codePtr, &length, NULL);
- opnd = TclGetUInt4AtPtr(pc+1);
- pc += (opnd-1);
- PUSH_OBJECT(Tcl_NewStringObj(bytes, length));
- goto instEvalStk;
- }
-
- case INST_NOP:
- pc += 1;
- goto cleanup0;
-
- case INST_DUP:
- objResultPtr = OBJ_AT_TOS;
- TRACE_WITH_OBJ(("=> "), objResultPtr);
- NEXT_INST_F(1, 0, 1);
-
- case INST_OVER:
- opnd = TclGetUInt4AtPtr(pc+1);
- objResultPtr = OBJ_AT_DEPTH(opnd);
- TRACE_WITH_OBJ(("=> "), objResultPtr);
NEXT_INST_F(5, 0, 1);
case INST_REVERSE: {
@@ -2121,7 +1632,6 @@ TEBCresume(
*/
if (appendLen == 0) {
- TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
NEXT_INST_V(2, (opnd-1), 0);
}
@@ -2142,15 +1652,6 @@ TEBCresume(
Tcl_Panic("max size for a Tcl value (%d bytes) exceeded",
INT_MAX);
}
-#if !TCL_COMPILE_DEBUG
- if (bytes != tclEmptyStringRep && !Tcl_IsShared(objResultPtr)) {
- TclFreeIntRep(objResultPtr);
- objResultPtr->bytes = ckrealloc(bytes, length+appendLen+1);
- objResultPtr->length = length + appendLen;
- p = TclGetString(objResultPtr) + length;
- currPtr = &OBJ_AT_DEPTH(opnd - 2);
- } else
-#endif
{
p = ckalloc(length + appendLen + 1);
TclNewObj(objResultPtr);
@@ -2178,14 +1679,6 @@ TEBCresume(
Tcl_Panic("max size for a Tcl value (%d bytes) exceeded",
INT_MAX);
}
-#if !TCL_COMPILE_DEBUG
- if (!Tcl_IsShared(objResultPtr)) {
- bytes = (char *) Tcl_SetByteArrayLength(objResultPtr,
- length + appendLen);
- p = bytes + length;
- currPtr = &OBJ_AT_DEPTH(opnd - 2);
- } else
-#endif
{
TclNewObj(objResultPtr);
bytes = (char *) Tcl_SetByteArrayLength(objResultPtr,
@@ -2207,7 +1700,6 @@ TEBCresume(
}
}
- TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
NEXT_INST_V(2, opnd, 1);
}
@@ -2242,8 +1734,6 @@ TEBCresume(
objPtr = OBJ_AT_TOS;
if (TclListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
- TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(objPtr)),
- Tcl_GetObjResult(interp));
goto gotError;
}
@@ -2286,28 +1776,6 @@ TEBCresume(
NEXT_INST_F(5, 0, 0);
}
- case INST_EXPR_STK: {
- ByteCode *newCodePtr;
-
- newCodePtr = CompileExprObj(interp, OBJ_AT_TOS);
- checkInterp = 1;
- cleanup = 1;
- pc++;
- TEBC_YIELD();
- return TclNRExecuteByteCode(interp, newCodePtr);
- }
-
- /*
- * INVOCATION BLOCK
- */
-
- instEvalStk:
- case INST_EVAL_STK:
- cleanup = 1;
- pc += 1;
- TEBC_YIELD();
- return TclNREvalObjEx(interp, OBJ_AT_TOS, 0);
-
case INST_INVOKE_EXPANDED:
CLANG_ASSERT(auxObjList);
objc = CURR_DEPTH - auxObjList->internalRep.ptrAndLongRep.value;
@@ -2327,35 +1795,12 @@ TEBCresume(
case INST_INVOKE_STK4:
objc = TclGetUInt4AtPtr(pc+1);
pcAdjustment = 5;
- goto doInvocation;
-
- case INST_INVOKE_STK1:
- objc = TclGetUInt1AtPtr(pc+1);
- pcAdjustment = 2;
doInvocation:
+
objv = &OBJ_AT_DEPTH(objc-1);
cleanup = objc;
-#ifdef TCL_COMPILE_DEBUG
- if (tclTraceExec >= 2) {
- int i;
-
- if (traceInstructions) {
- strncpy(cmdNameBuf, TclGetString(objv[0]), 20);
- TRACE(("%u => call ", objc));
- } else {
- fprintf(stdout, "%d: (%u) invoking ", iPtr->numLevels,
- (unsigned)(pc - codePtr->codeStart));
- }
- for (i = 0; i < objc; i++) {
- TclPrintObject(stdout, objv[i], 15);
- fprintf(stdout, " ");
- }
- fprintf(stdout, "\n");
- fflush(stdout);
- }
-#endif /*TCL_COMPILE_DEBUG*/
/*
* Finally, let TclEvalObjv handle the command.
@@ -2373,147 +1818,11 @@ TEBCresume(
return TclNREvalObjv(interp, objc, objv,
TCL_EVAL_NOERR, NULL);
-#if TCL_SUPPORT_84_BYTECODE
- 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
- * ::tcl::mathfunc::$objv[0]. We need to insert the named math
- * function into the stack.
- */
-
- opnd = TclGetUInt1AtPtr(pc+1);
- if ((opnd < 0) || (opnd > LAST_BUILTIN_FUNC)) {
- TRACE(("UNRECOGNIZED BUILTIN FUNC CODE %d\n", opnd));
- Tcl_Panic("TclNRExecuteByteCode: unrecognized builtin function code %d", opnd);
- }
-
- TclNewLiteralStringObj(objPtr, "::tcl::mathfunc::");
- Tcl_AppendToObj(objPtr, tclBuiltinFuncTable[opnd].name, -1);
-
- /*
- * Only 0, 1 or 2 args.
- */
-
- {
- int numArgs = tclBuiltinFuncTable[opnd].numArgs;
- Tcl_Obj *tmpPtr1, *tmpPtr2;
-
- if (numArgs == 0) {
- PUSH_OBJECT(objPtr);
- } else if (numArgs == 1) {
- tmpPtr1 = POP_OBJECT();
- PUSH_OBJECT(objPtr);
- PUSH_OBJECT(tmpPtr1);
- Tcl_DecrRefCount(tmpPtr1);
- } else {
- tmpPtr2 = POP_OBJECT();
- tmpPtr1 = POP_OBJECT();
- PUSH_OBJECT(objPtr);
- PUSH_OBJECT(tmpPtr1);
- PUSH_OBJECT(tmpPtr2);
- Tcl_DecrRefCount(tmpPtr1);
- Tcl_DecrRefCount(tmpPtr2);
- }
- objc = numArgs + 1;
- }
- pcAdjustment = 2;
- goto doInvocation;
-
- 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
- * INST_INVOKE_STK1 converting the first arg to
- * ::tcl::mathfunc::$objv[0].
- */
-
- objc = TclGetUInt1AtPtr(pc+1); /* Number of arguments. The function
- * name is the 0-th argument. */
-
- objPtr = OBJ_AT_DEPTH(objc-1);
- TclNewLiteralStringObj(tmpPtr, "::tcl::mathfunc::");
- Tcl_AppendObjToObj(tmpPtr, objPtr);
- Tcl_DecrRefCount(objPtr);
-
- /*
- * Variation of PUSH_OBJECT.
- */
-
- OBJ_AT_DEPTH(objc-1) = tmpPtr;
- Tcl_IncrRefCount(tmpPtr);
-
- pcAdjustment = 2;
- goto doInvocation;
-#else
/*
* INST_CALL_BUILTIN_FUNC1 and INST_CALL_FUNC1 were made obsolete by the
- * changes to add a ::tcl::mathfunc namespace in 8.5. Optional support
- * remains for existing bytecode precompiled files.
+ * changes to add a ::tcl::mathfunc namespace in 8.5.
*/
- case INST_CALL_BUILTIN_FUNC1:
- Tcl_Panic("TclNRExecuteByteCode: obsolete INST_CALL_BUILTIN_FUNC1 found");
- case INST_CALL_FUNC1:
- Tcl_Panic("TclNRExecuteByteCode: obsolete INST_CALL_FUNC1 found");
-#endif
-
- case INST_INVOKE_REPLACE:
- objc = TclGetUInt4AtPtr(pc+1);
- opnd = TclGetUInt1AtPtr(pc+5);
- objPtr = POP_OBJECT();
- objv = &OBJ_AT_DEPTH(objc-1);
- cleanup = objc;
-#ifdef TCL_COMPILE_DEBUG
- if (tclTraceExec >= 2) {
- int i;
-
- if (traceInstructions) {
- strncpy(cmdNameBuf, TclGetString(objv[0]), 20);
- TRACE(("%u => call (implementation %s) ", objc, O2S(objPtr)));
- } else {
- fprintf(stdout,
- "%d: (%u) invoking (using implementation %s) ",
- iPtr->numLevels, (unsigned)(pc - codePtr->codeStart),
- O2S(objPtr));
- }
- for (i = 0; i < objc; i++) {
- if (i < opnd) {
- fprintf(stdout, "<");
- TclPrintObject(stdout, objv[i], 15);
- fprintf(stdout, ">");
- } else {
- TclPrintObject(stdout, objv[i], 15);
- }
- fprintf(stdout, " ");
- }
- fprintf(stdout, "\n");
- fflush(stdout);
- }
-#endif /*TCL_COMPILE_DEBUG*/
- {
- Tcl_Obj *copyPtr = Tcl_NewListObj(objc - opnd + 1, NULL);
- register List *listRepPtr = copyPtr->internalRep.twoPtrValue.ptr1;
- Tcl_Obj **copyObjv = &listRepPtr->elements;
- int i;
-
- listRepPtr->elemCount = objc - opnd + 1;
- copyObjv[0] = objPtr;
- memcpy(copyObjv+1, objv+opnd, sizeof(Tcl_Obj *) * (objc - opnd));
- for (i=1 ; i<objc-opnd+1 ; i++) {
- Tcl_IncrRefCount(copyObjv[i]);
- }
- objPtr = copyPtr;
- }
- iPtr->ensembleRewrite.sourceObjs = objv;
- iPtr->ensembleRewrite.numRemovedObjs = opnd;
- iPtr->ensembleRewrite.numInsertedObjs = 1;
- pc += 6;
- TEBC_YIELD();
- Tcl_NRAddCallback(interp, TclClearRootEnsemble, NULL,NULL,NULL,NULL);
- TclMarkTailcall(interp);
- return TclNREvalObjEx(interp, objPtr, TCL_EVAL_INVOKE);
-
/*
* -----------------------------------------------------------------
* Start of INST_LOAD instructions.
@@ -2523,43 +1832,18 @@ TEBCresume(
* common execution code.
*/
- case INST_LOAD_SCALAR1:
- instLoadScalar1:
- opnd = TclGetUInt1AtPtr(pc+1);
- varPtr = LOCAL(opnd);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- TRACE(("%u => ", opnd));
- if (TclIsVarDirectReadable(varPtr)) {
- /*
- * No errors, no traces: just get the value.
- */
-
- objResultPtr = varPtr->value.objPtr;
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_F(2, 0, 1);
- }
- pcAdjustment = 2;
- cleanup = 0;
- arrayPtr = NULL;
- part1Ptr = part2Ptr = NULL;
- goto doCallPtrGetVar;
-
case INST_LOAD_SCALAR4:
opnd = TclGetUInt4AtPtr(pc+1);
varPtr = LOCAL(opnd);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
- TRACE(("%u => ", opnd));
if (TclIsVarDirectReadable(varPtr)) {
/*
* No errors, no traces: just get the value.
*/
objResultPtr = varPtr->value.objPtr;
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_F(5, 0, 1);
}
pcAdjustment = 5;
@@ -2573,10 +1857,6 @@ TEBCresume(
pcAdjustment = 5;
goto doLoadArray;
- case INST_LOAD_ARRAY1:
- opnd = TclGetUInt1AtPtr(pc+1);
- pcAdjustment = 2;
-
doLoadArray:
part1Ptr = NULL;
part2Ptr = OBJ_AT_TOS;
@@ -2584,7 +1864,6 @@ TEBCresume(
while (TclIsVarLink(arrayPtr)) {
arrayPtr = arrayPtr->value.linkPtr;
}
- TRACE(("%u \"%.30s\" => ", opnd, O2S(part2Ptr)));
if (TclIsVarArray(arrayPtr) && !ReadTraced(arrayPtr)) {
varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
if (varPtr && TclIsVarDirectReadable(varPtr)) {
@@ -2593,14 +1872,12 @@ TEBCresume(
*/
objResultPtr = varPtr->value.objPtr;
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_F(pcAdjustment, 1, 1);
}
}
varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
TCL_LEAVE_ERR_MSG, "read", 0, 1, arrayPtr, opnd);
if (varPtr == NULL) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
goto gotError;
}
cleanup = 1;
@@ -2610,15 +1887,12 @@ TEBCresume(
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:
cleanup = 1;
part2Ptr = NULL;
objPtr = OBJ_AT_TOS; /* variable name */
- TRACE(("\"%.30s\" => ", O2S(objPtr)));
doLoadStk:
part1Ptr = objPtr;
@@ -2626,7 +1900,6 @@ TEBCresume(
TCL_LEAVE_ERR_MSG, "read", /*createPart1*/0, /*createPart2*/1,
&arrayPtr);
if (!varPtr) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
goto gotError;
}
@@ -2636,7 +1909,6 @@ TEBCresume(
*/
objResultPtr = varPtr->value.objPtr;
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(1, cleanup, 1);
}
pcAdjustment = 1;
@@ -2652,10 +1924,8 @@ TEBCresume(
part1Ptr, part2Ptr, TCL_LEAVE_ERR_MSG, opnd);
checkInterp = 1;
if (!objResultPtr) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
goto gotError;
}
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(pcAdjustment, cleanup, 1);
/*
@@ -2668,976 +1938,27 @@ TEBCresume(
* common execution code.
*/
- {
- int storeFlags;
-
- case INST_STORE_ARRAY4:
- opnd = TclGetUInt4AtPtr(pc+1);
- pcAdjustment = 5;
- goto doStoreArrayDirect;
-
- case INST_STORE_ARRAY1:
- opnd = TclGetUInt1AtPtr(pc+1);
- pcAdjustment = 2;
-
- doStoreArrayDirect:
- valuePtr = OBJ_AT_TOS;
- part2Ptr = OBJ_UNDER_TOS;
- arrayPtr = LOCAL(opnd);
- TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, O2S(part2Ptr),
- O2S(valuePtr)));
- while (TclIsVarLink(arrayPtr)) {
- arrayPtr = arrayPtr->value.linkPtr;
- }
- if (TclIsVarArray(arrayPtr) && !WriteTraced(arrayPtr)) {
- varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
- if (varPtr && TclIsVarDirectWritable(varPtr)) {
- tosPtr--;
- Tcl_DecrRefCount(OBJ_AT_TOS);
- OBJ_AT_TOS = valuePtr;
- goto doStoreVarDirect;
- }
- }
- cleanup = 2;
- storeFlags = TCL_LEAVE_ERR_MSG;
- part1Ptr = NULL;
- goto doStoreArrayDirectFailed;
-
case INST_STORE_SCALAR4:
opnd = TclGetUInt4AtPtr(pc+1);
pcAdjustment = 5;
- goto doStoreScalarDirect;
- case INST_STORE_SCALAR1:
- opnd = TclGetUInt1AtPtr(pc+1);
- pcAdjustment = 2;
-
- doStoreScalarDirect:
valuePtr = OBJ_AT_TOS;
varPtr = LOCAL(opnd);
- TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- if (!TclIsVarDirectWritable(varPtr)) {
- storeFlags = TCL_LEAVE_ERR_MSG;
- part1Ptr = NULL;
- goto doStoreScalar;
- }
-
- /*
- * No traces, no errors, plain 'set': we can safely inline. The value
- * *will* be set to what's requested, so that the stack top remains
- * pointing to the same Tcl_Obj.
- */
-
- doStoreVarDirect:
- valuePtr = varPtr->value.objPtr;
if (valuePtr != NULL) {
TclDecrRefCount(valuePtr);
}
+
objResultPtr = OBJ_AT_TOS;
varPtr->value.objPtr = objResultPtr;
-#ifndef TCL_COMPILE_DEBUG
- if (*(pc+pcAdjustment) == INST_POP) {
- tosPtr--;
- NEXT_INST_F((pcAdjustment+1), 0, 0);
- }
-#else
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
-#endif
Tcl_IncrRefCount(objResultPtr);
- NEXT_INST_F(pcAdjustment, 0, 0);
-
- case INST_LAPPEND_STK:
- valuePtr = OBJ_AT_TOS; /* value to append */
- part2Ptr = NULL;
- storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
- | TCL_LIST_ELEMENT);
- goto doStoreStk;
-
- 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);
- goto doStoreStk;
-
- 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:
- 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:
- valuePtr = OBJ_AT_TOS;
- part2Ptr = OBJ_UNDER_TOS;
- storeFlags = TCL_LEAVE_ERR_MSG;
- goto doStoreStk;
-
- case INST_STORE_STK:
- case INST_STORE_SCALAR_STK:
- valuePtr = OBJ_AT_TOS;
- part2Ptr = NULL;
- storeFlags = TCL_LEAVE_ERR_MSG;
-
- doStoreStk:
- objPtr = OBJ_AT_DEPTH(1 + (part2Ptr != NULL)); /* variable name */
- part1Ptr = objPtr;
-#ifdef TCL_COMPILE_DEBUG
- if (part2Ptr == NULL) {
- TRACE(("\"%.30s\" <- \"%.30s\" =>", O2S(part1Ptr),O2S(valuePtr)));
- } else {
- TRACE(("\"%.30s(%.30s)\" <- \"%.30s\" => ",
- O2S(part1Ptr), O2S(part2Ptr), O2S(valuePtr)));
- }
-#endif
- varPtr = TclObjLookupVarEx(interp, objPtr,part2Ptr, TCL_LEAVE_ERR_MSG,
- "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
- if (!varPtr) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- cleanup = ((part2Ptr == NULL)? 2 : 3);
- pcAdjustment = 1;
- opnd = -1;
- goto doCallPtrSetVar;
-
- case INST_LAPPEND_ARRAY4:
- opnd = TclGetUInt4AtPtr(pc+1);
- pcAdjustment = 5;
- storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
- | TCL_LIST_ELEMENT);
- goto doStoreArray;
-
- case INST_LAPPEND_ARRAY1:
- opnd = TclGetUInt1AtPtr(pc+1);
- pcAdjustment = 2;
- storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
- | TCL_LIST_ELEMENT);
- goto doStoreArray;
-
- case INST_APPEND_ARRAY4:
- opnd = TclGetUInt4AtPtr(pc+1);
- pcAdjustment = 5;
- storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
- goto doStoreArray;
-
- case INST_APPEND_ARRAY1:
- opnd = TclGetUInt1AtPtr(pc+1);
- pcAdjustment = 2;
- storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
- goto doStoreArray;
-
- doStoreArray:
- valuePtr = OBJ_AT_TOS;
- part2Ptr = OBJ_UNDER_TOS;
- arrayPtr = LOCAL(opnd);
- TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, O2S(part2Ptr),
- O2S(valuePtr)));
- while (TclIsVarLink(arrayPtr)) {
- arrayPtr = arrayPtr->value.linkPtr;
- }
- cleanup = 2;
- part1Ptr = NULL;
-
- doStoreArrayDirectFailed:
- varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
- TCL_LEAVE_ERR_MSG, "set", 1, 1, arrayPtr, opnd);
- if (!varPtr) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- goto doCallPtrSetVar;
-
- case INST_LAPPEND_SCALAR4:
- opnd = TclGetUInt4AtPtr(pc+1);
- pcAdjustment = 5;
- storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
- | TCL_LIST_ELEMENT);
- goto doStoreScalar;
-
- case INST_LAPPEND_SCALAR1:
- opnd = TclGetUInt1AtPtr(pc+1);
- pcAdjustment = 2;
- storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
- | TCL_LIST_ELEMENT);
- goto doStoreScalar;
-
- case INST_APPEND_SCALAR4:
- opnd = TclGetUInt4AtPtr(pc+1);
- pcAdjustment = 5;
- storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
- goto doStoreScalar;
-
- case INST_APPEND_SCALAR1:
- opnd = TclGetUInt1AtPtr(pc+1);
- pcAdjustment = 2;
- storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
- goto doStoreScalar;
-
- doStoreScalar:
- valuePtr = OBJ_AT_TOS;
- varPtr = LOCAL(opnd);
- TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- cleanup = 1;
- arrayPtr = NULL;
- part1Ptr = part2Ptr = NULL;
-
- doCallPtrSetVar:
- objResultPtr = TclPtrSetVar(interp, varPtr, arrayPtr,
- part1Ptr, part2Ptr, valuePtr, storeFlags, opnd);
- checkInterp = 1;
- if (!objResultPtr) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
-#ifndef TCL_COMPILE_DEBUG
- if (*(pc+pcAdjustment) == INST_POP) {
- NEXT_INST_V((pcAdjustment+1), cleanup, 0);
- }
-#endif
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_V(pcAdjustment, cleanup, 1);
- }
-
- /*
- * End of INST_STORE and related instructions.
- * -----------------------------------------------------------------
- * Start of INST_INCR instructions.
- *
- * WARNING: more 'goto' here than your doctor recommended! The different
- * instructions set the value of some variables and then jump to somme
- * common execution code.
- */
-
-/*TODO: Consider more untangling here; merge with LOAD and STORE ? */
-
- {
- Tcl_Obj *incrPtr;
-#ifndef NO_WIDE_TYPE
- Tcl_WideInt w;
-#endif
- long increment;
-
- 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) {
- case INST_INCR_SCALAR1:
- pcAdjustment = 2;
- goto doIncrScalar;
- case INST_INCR_ARRAY1:
- pcAdjustment = 2;
- goto doIncrArray;
- default:
- pcAdjustment = 1;
- goto doIncrStk;
- }
-
- case INST_INCR_ARRAY_STK_IMM:
- case INST_INCR_SCALAR_STK_IMM:
- case INST_INCR_STK_IMM:
- increment = TclGetInt1AtPtr(pc+1);
- incrPtr = Tcl_NewIntObj(increment);
- Tcl_IncrRefCount(incrPtr);
- pcAdjustment = 2;
-
- doIncrStk:
- if ((*pc == INST_INCR_ARRAY_STK_IMM)
- || (*pc == INST_INCR_ARRAY_STK)) {
- part2Ptr = OBJ_AT_TOS;
- objPtr = OBJ_UNDER_TOS;
- TRACE(("\"%.30s(%.30s)\" (by %ld) => ",
- O2S(objPtr), O2S(part2Ptr), increment));
- } else {
- part2Ptr = NULL;
- objPtr = OBJ_AT_TOS;
- TRACE(("\"%.30s\" (by %ld) => ", O2S(objPtr), increment));
- }
- part1Ptr = objPtr;
- opnd = -1;
- varPtr = TclObjLookupVarEx(interp, objPtr, part2Ptr,
- TCL_LEAVE_ERR_MSG, "read", 1, 1, &arrayPtr);
- if (!varPtr) {
- Tcl_AddObjErrorInfo(interp,
- "\n (reading value of variable to increment)", -1);
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- Tcl_DecrRefCount(incrPtr);
- goto gotError;
- }
- cleanup = ((part2Ptr == NULL)? 1 : 2);
- goto doIncrVar;
-
- case INST_INCR_ARRAY1_IMM:
- opnd = TclGetUInt1AtPtr(pc+1);
- increment = TclGetInt1AtPtr(pc+2);
- incrPtr = Tcl_NewIntObj(increment);
- Tcl_IncrRefCount(incrPtr);
- pcAdjustment = 3;
-
- doIncrArray:
- part1Ptr = NULL;
- part2Ptr = OBJ_AT_TOS;
- arrayPtr = LOCAL(opnd);
- cleanup = 1;
- while (TclIsVarLink(arrayPtr)) {
- arrayPtr = arrayPtr->value.linkPtr;
- }
- TRACE(("%u \"%.30s\" (by %ld) => ", opnd, O2S(part2Ptr), increment));
- varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
- TCL_LEAVE_ERR_MSG, "read", 1, 1, arrayPtr, opnd);
- if (!varPtr) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- Tcl_DecrRefCount(incrPtr);
- goto gotError;
- }
- goto doIncrVar;
-
- case INST_INCR_SCALAR1_IMM:
- opnd = TclGetUInt1AtPtr(pc+1);
- increment = TclGetInt1AtPtr(pc+2);
- pcAdjustment = 3;
- cleanup = 0;
- varPtr = LOCAL(opnd);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
-
- if (TclIsVarDirectModifyable(varPtr)) {
- ClientData ptr;
- int type;
-
- objPtr = varPtr->value.objPtr;
- if (GetNumberFromObj(NULL, objPtr, &ptr, &type) == TCL_OK) {
- if (type == TCL_NUMBER_LONG) {
- long augend = *((const long *)ptr);
- long sum = augend + increment;
-
- /*
- * Overflow when (augend and sum have different sign) and
- * (augend and increment have the same sign). This is
- * encapsulated in the Overflowing macro.
- */
-
- if (!Overflowing(augend, increment, sum)) {
- TRACE(("%u %ld => ", opnd, increment));
- if (Tcl_IsShared(objPtr)) {
- objPtr->refCount--; /* We know it's shared. */
- TclNewLongObj(objResultPtr, sum);
- Tcl_IncrRefCount(objResultPtr);
- varPtr->value.objPtr = objResultPtr;
- } else {
- objResultPtr = objPtr;
- TclSetLongObj(objPtr, sum);
- }
- goto doneIncr;
- }
-#ifndef NO_WIDE_TYPE
- w = (Tcl_WideInt)augend;
-
- TRACE(("%u %ld => ", opnd, increment));
- if (Tcl_IsShared(objPtr)) {
- objPtr->refCount--; /* We know it's shared. */
- objResultPtr = Tcl_NewWideIntObj(w+increment);
- Tcl_IncrRefCount(objResultPtr);
- varPtr->value.objPtr = objResultPtr;
- } else {
- objResultPtr = objPtr;
-
- /*
- * We know the sum value is outside the long range;
- * use macro form that doesn't range test again.
- */
-
- TclSetWideIntObj(objPtr, w+increment);
- }
- goto doneIncr;
-#endif
- } /* end if (type == TCL_NUMBER_LONG) */
-#ifndef NO_WIDE_TYPE
- if (type == TCL_NUMBER_WIDE) {
- Tcl_WideInt sum;
-
- w = *((const Tcl_WideInt *) ptr);
- sum = w + increment;
-
- /*
- * Check for overflow.
- */
-
- if (!Overflowing(w, increment, sum)) {
- TRACE(("%u %ld => ", opnd, increment));
- if (Tcl_IsShared(objPtr)) {
- objPtr->refCount--; /* We know it's shared. */
- objResultPtr = Tcl_NewWideIntObj(sum);
- Tcl_IncrRefCount(objResultPtr);
- varPtr->value.objPtr = objResultPtr;
- } else {
- objResultPtr = objPtr;
-
- /*
- * We *do not* know the sum value is outside the
- * long range (wide + long can yield long); use
- * the function call that checks range.
- */
-
- Tcl_SetWideIntObj(objPtr, sum);
- }
- goto doneIncr;
- }
- }
-#endif
- }
- if (Tcl_IsShared(objPtr)) {
- objPtr->refCount--; /* We know it's shared */
- objResultPtr = Tcl_DuplicateObj(objPtr);
- Tcl_IncrRefCount(objResultPtr);
- varPtr->value.objPtr = objResultPtr;
- } else {
- objResultPtr = objPtr;
- }
- TclNewLongObj(incrPtr, increment);
- if (TclIncrObj(interp, objResultPtr, incrPtr) != TCL_OK) {
- Tcl_DecrRefCount(incrPtr);
- TRACE_APPEND(("ERROR: %.30s\n",
- O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- Tcl_DecrRefCount(incrPtr);
- goto doneIncr;
- }
-
- /*
- * All other cases, flow through to generic handling.
- */
-
- TclNewLongObj(incrPtr, increment);
- Tcl_IncrRefCount(incrPtr);
-
- doIncrScalar:
- varPtr = LOCAL(opnd);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- arrayPtr = NULL;
- part1Ptr = part2Ptr = NULL;
- cleanup = 0;
- TRACE(("%u %ld => ", opnd, increment));
-
- doIncrVar:
- if (TclIsVarDirectModifyable2(varPtr, arrayPtr)) {
- objPtr = varPtr->value.objPtr;
- if (Tcl_IsShared(objPtr)) {
- objPtr->refCount--; /* We know it's shared */
- objResultPtr = Tcl_DuplicateObj(objPtr);
- Tcl_IncrRefCount(objResultPtr);
- varPtr->value.objPtr = objResultPtr;
- } else {
- objResultPtr = objPtr;
- }
- if (TclIncrObj(interp, objResultPtr, incrPtr) != TCL_OK) {
- Tcl_DecrRefCount(incrPtr);
- TRACE_APPEND(("ERROR: %.30s\n",
- O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- Tcl_DecrRefCount(incrPtr);
- } else {
- objResultPtr = TclPtrIncrObjVar(interp, varPtr, arrayPtr,
- part1Ptr, part2Ptr, incrPtr, TCL_LEAVE_ERR_MSG, opnd);
- checkInterp = 1;
- Tcl_DecrRefCount(incrPtr);
- if (objResultPtr == NULL) {
- TRACE_APPEND(("ERROR: %.30s\n",
- O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- }
- doneIncr:
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
-#ifndef TCL_COMPILE_DEBUG
- if (*(pc+pcAdjustment) == INST_POP) {
- NEXT_INST_V((pcAdjustment+1), cleanup, 0);
- }
-#endif
- NEXT_INST_V(pcAdjustment, cleanup, 1);
- }
-
- /*
- * End of INST_INCR instructions.
- * -----------------------------------------------------------------
- * Start of INST_EXIST instructions.
- */
-
- case INST_EXIST_SCALAR:
- opnd = TclGetUInt4AtPtr(pc+1);
- varPtr = LOCAL(opnd);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- TRACE(("%u => ", opnd));
- if (ReadTraced(varPtr)) {
- TclObjCallVarTraces(iPtr, NULL, varPtr, NULL, NULL,
- TCL_TRACE_READS, 0, opnd);
- checkInterp = 1;
- if (TclIsVarUndefined(varPtr)) {
- TclCleanupVar(varPtr, NULL);
- varPtr = NULL;
- }
- }
-
- /*
- * Tricky! Arrays always exist.
- */
-
- objResultPtr = TCONST(!varPtr || TclIsVarUndefined(varPtr) ? 0 : 1);
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_F(5, 0, 1);
-
- case INST_EXIST_ARRAY:
- opnd = TclGetUInt4AtPtr(pc+1);
- part2Ptr = OBJ_AT_TOS;
- arrayPtr = LOCAL(opnd);
- while (TclIsVarLink(arrayPtr)) {
- arrayPtr = arrayPtr->value.linkPtr;
- }
- TRACE(("%u \"%.30s\" => ", opnd, O2S(part2Ptr)));
- if (TclIsVarArray(arrayPtr) && !ReadTraced(arrayPtr)) {
- varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
- if (!varPtr || !ReadTraced(varPtr)) {
- goto doneExistArray;
- }
- }
- varPtr = TclLookupArrayElement(interp, NULL, part2Ptr, 0, "access",
- 0, 1, arrayPtr, opnd);
- if (varPtr) {
- if (ReadTraced(varPtr) || (arrayPtr && ReadTraced(arrayPtr))) {
- TclObjCallVarTraces(iPtr, arrayPtr, varPtr, NULL, part2Ptr,
- TCL_TRACE_READS, 0, opnd);
- checkInterp = 1;
- }
- if (TclIsVarUndefined(varPtr)) {
- TclCleanupVar(varPtr, arrayPtr);
- varPtr = NULL;
- }
- }
- doneExistArray:
- objResultPtr = TCONST(!varPtr || TclIsVarUndefined(varPtr) ? 0 : 1);
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_F(5, 1, 1);
-
- case INST_EXIST_ARRAY_STK:
- cleanup = 2;
- part2Ptr = OBJ_AT_TOS; /* element name */
- part1Ptr = OBJ_UNDER_TOS; /* array name */
- TRACE(("\"%.30s(%.30s)\" => ", O2S(part1Ptr), O2S(part2Ptr)));
- goto doExistStk;
-
- case INST_EXIST_STK:
- cleanup = 1;
- part2Ptr = NULL;
- part1Ptr = OBJ_AT_TOS; /* variable name */
- TRACE(("\"%.30s\" => ", O2S(part1Ptr)));
-
- doExistStk:
- varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, 0, "access",
- /*createPart1*/0, /*createPart2*/1, &arrayPtr);
- if (varPtr) {
- if (ReadTraced(varPtr) || (arrayPtr && ReadTraced(arrayPtr))) {
- TclObjCallVarTraces(iPtr, arrayPtr, varPtr, part1Ptr,part2Ptr,
- TCL_TRACE_READS, 0, -1);
- checkInterp = 1;
- }
- if (TclIsVarUndefined(varPtr)) {
- TclCleanupVar(varPtr, arrayPtr);
- varPtr = NULL;
- }
- }
- objResultPtr = TCONST(!varPtr || TclIsVarUndefined(varPtr) ? 0 : 1);
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_V(1, cleanup, 1);
-
- /*
- * End of INST_EXIST instructions.
- * -----------------------------------------------------------------
- * Start of INST_UNSET instructions.
- */
-
- {
- int flags;
-
- case INST_UNSET_SCALAR:
- flags = TclGetUInt1AtPtr(pc+1) ? TCL_LEAVE_ERR_MSG : 0;
- opnd = TclGetUInt4AtPtr(pc+2);
- varPtr = LOCAL(opnd);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- TRACE(("%s %u\n", (flags?"normal":"noerr"), opnd));
- if (TclIsVarDirectUnsettable(varPtr) && !TclIsVarInHash(varPtr)) {
- /*
- * No errors, no traces, no searches: just make the variable cease
- * to exist.
- */
-
- if (!TclIsVarUndefined(varPtr)) {
- TclDecrRefCount(varPtr->value.objPtr);
- } else if (flags & TCL_LEAVE_ERR_MSG) {
- goto slowUnsetScalar;
- }
- varPtr->value.objPtr = NULL;
- NEXT_INST_F(6, 0, 0);
- }
-
- slowUnsetScalar:
- if (TclPtrUnsetVar(interp, varPtr, NULL, NULL, NULL, flags,
- opnd) != TCL_OK && flags) {
- goto errorInUnset;
- }
- checkInterp = 1;
- NEXT_INST_F(6, 0, 0);
-
- case INST_UNSET_ARRAY:
- flags = TclGetUInt1AtPtr(pc+1) ? TCL_LEAVE_ERR_MSG : 0;
- opnd = TclGetUInt4AtPtr(pc+2);
- part2Ptr = OBJ_AT_TOS;
- arrayPtr = LOCAL(opnd);
- while (TclIsVarLink(arrayPtr)) {
- arrayPtr = arrayPtr->value.linkPtr;
- }
- TRACE(("%s %u \"%.30s\"\n",
- (flags ? "normal" : "noerr"), opnd, O2S(part2Ptr)));
- if (TclIsVarArray(arrayPtr) && !UnsetTraced(arrayPtr)) {
- varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
- if (varPtr && TclIsVarDirectUnsettable(varPtr)) {
- /*
- * No nasty traces and element exists, so we can proceed to
- * unset it. Might still not exist though...
- */
-
- if (!TclIsVarUndefined(varPtr)) {
- TclDecrRefCount(varPtr->value.objPtr);
- } else if (flags & TCL_LEAVE_ERR_MSG) {
- goto slowUnsetArray;
- }
- varPtr->value.objPtr = NULL;
- NEXT_INST_F(6, 1, 0);
- } else if (!varPtr && !(flags & TCL_LEAVE_ERR_MSG)) {
- /*
- * Don't need to do anything here.
- */
-
- NEXT_INST_F(6, 1, 0);
- }
- }
- slowUnsetArray:
- varPtr = TclLookupArrayElement(interp, NULL, part2Ptr, flags, "unset",
- 0, 0, arrayPtr, opnd);
- if (!varPtr) {
- if (flags & TCL_LEAVE_ERR_MSG) {
- goto errorInUnset;
- }
- } else if (TclPtrUnsetVar(interp, varPtr, arrayPtr, NULL, part2Ptr,
- flags, opnd) != TCL_OK && (flags & TCL_LEAVE_ERR_MSG)) {
- goto errorInUnset;
- }
- checkInterp = 1;
- NEXT_INST_F(6, 1, 0);
-
- case INST_UNSET_ARRAY_STK:
- flags = TclGetUInt1AtPtr(pc+1) ? TCL_LEAVE_ERR_MSG : 0;
- cleanup = 2;
- part2Ptr = OBJ_AT_TOS; /* element name */
- part1Ptr = OBJ_UNDER_TOS; /* array name */
- TRACE(("%s \"%.30s(%.30s)\"\n", (flags?"normal":"noerr"),
- O2S(part1Ptr), O2S(part2Ptr)));
- goto doUnsetStk;
-
- case INST_UNSET_STK:
- flags = TclGetUInt1AtPtr(pc+1) ? TCL_LEAVE_ERR_MSG : 0;
- cleanup = 1;
- part2Ptr = NULL;
- part1Ptr = OBJ_AT_TOS; /* variable name */
- TRACE(("%s \"%.30s\"\n", (flags?"normal":"noerr"), O2S(part1Ptr)));
-
- doUnsetStk:
- if (TclObjUnsetVar2(interp, part1Ptr, part2Ptr, flags) != TCL_OK
- && (flags & TCL_LEAVE_ERR_MSG)) {
- goto errorInUnset;
- }
- checkInterp = 1;
- NEXT_INST_V(2, cleanup, 0);
-
- errorInUnset:
- checkInterp = 1;
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- goto gotError;
-
- /*
- * This is really an unset operation these days. Do not issue.
- */
-
- case INST_DICT_DONE:
- opnd = TclGetUInt4AtPtr(pc+1);
- TRACE(("%u\n", opnd));
- varPtr = LOCAL(opnd);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- if (TclIsVarDirectUnsettable(varPtr) && !TclIsVarInHash(varPtr)) {
- if (!TclIsVarUndefined(varPtr)) {
- TclDecrRefCount(varPtr->value.objPtr);
- }
- varPtr->value.objPtr = NULL;
- } else {
- TclPtrUnsetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
- checkInterp = 1;
- }
NEXT_INST_F(5, 0, 0);
- }
-
- /*
- * End of INST_UNSET instructions.
- * -----------------------------------------------------------------
- * Start of INST_ARRAY instructions.
- */
-
- case INST_ARRAY_EXISTS_IMM:
- opnd = TclGetUInt4AtPtr(pc+1);
- pcAdjustment = 5;
- cleanup = 0;
- part1Ptr = NULL;
- arrayPtr = NULL;
- TRACE(("%u => ", opnd));
- varPtr = LOCAL(opnd);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- goto doArrayExists;
- case INST_ARRAY_EXISTS_STK:
- opnd = -1;
- pcAdjustment = 1;
- cleanup = 1;
- part1Ptr = OBJ_AT_TOS;
- TRACE(("\"%.30s\" => ", O2S(part1Ptr)));
- varPtr = TclObjLookupVarEx(interp, part1Ptr, NULL, 0, NULL,
- /*createPart1*/0, /*createPart2*/0, &arrayPtr);
- doArrayExists:
- if (varPtr && (varPtr->flags & VAR_TRACED_ARRAY)
- && (TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr))) {
- result = TclObjCallVarTraces(iPtr, arrayPtr, varPtr, part1Ptr,
- NULL, (TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY|
- TCL_GLOBAL_ONLY|TCL_TRACE_ARRAY), 1, opnd);
- if (result == TCL_ERROR) {
- TRACE_APPEND(("ERROR: %.30s\n",
- O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- }
- if (varPtr && TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) {
- objResultPtr = TCONST(1);
- } else {
- objResultPtr = TCONST(0);
- }
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_V(pcAdjustment, cleanup, 1);
-
- case INST_ARRAY_MAKE_IMM:
- opnd = TclGetUInt4AtPtr(pc+1);
- pcAdjustment = 5;
- cleanup = 0;
- part1Ptr = NULL;
- arrayPtr = NULL;
- TRACE(("%u => ", opnd));
- varPtr = LOCAL(opnd);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- goto doArrayMake;
- case INST_ARRAY_MAKE_STK:
- opnd = -1;
- pcAdjustment = 1;
- cleanup = 1;
- part1Ptr = OBJ_AT_TOS;
- TRACE(("\"%.30s\" => ", O2S(part1Ptr)));
- varPtr = TclObjLookupVarEx(interp, part1Ptr, NULL, TCL_LEAVE_ERR_MSG,
- "set", /*createPart1*/1, /*createPart2*/0, &arrayPtr);
- if (varPtr == NULL) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- doArrayMake:
- if (varPtr && !TclIsVarArray(varPtr)) {
- if (TclIsVarArrayElement(varPtr) || !TclIsVarUndefined(varPtr)) {
- /*
- * Either an array element, or a scalar: lose!
- */
-
- TclObjVarErrMsg(interp, part1Ptr, NULL, "array set",
- "variable isn't array", opnd);
- Tcl_SetErrorCode(interp, "TCL", "WRITE", "ARRAY", NULL);
- TRACE_APPEND(("ERROR: bad array ref: %.30s\n",
- O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- TclSetVarArray(varPtr);
- varPtr->value.tablePtr = ckalloc(sizeof(TclVarHashTable));
- TclInitVarHashTable(varPtr->value.tablePtr,
- TclGetVarNsPtr(varPtr));
-#ifdef TCL_COMPILE_DEBUG
- TRACE_APPEND(("done\n"));
- } else {
- TRACE_APPEND(("nothing to do\n"));
-#endif
- }
- NEXT_INST_V(pcAdjustment, cleanup, 0);
/*
- * End of INST_ARRAY instructions.
- * -----------------------------------------------------------------
- * Start of variable linking instructions.
- */
-
- {
- Var *otherPtr;
- CallFrame *framePtr, *savedFramePtr;
- Tcl_Namespace *nsPtr;
- Namespace *savedNsPtr;
-
- case INST_UPVAR:
- TRACE_WITH_OBJ(("upvar "), OBJ_UNDER_TOS);
-
- if (TclObjGetFrame(interp, OBJ_UNDER_TOS, &framePtr) == -1) {
- goto gotError;
- }
-
- /*
- * Locate the other variable.
- */
-
- savedFramePtr = iPtr->varFramePtr;
- iPtr->varFramePtr = framePtr;
- otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
- TCL_LEAVE_ERR_MSG, "access", /*createPart1*/ 1,
- /*createPart2*/ 1, &varPtr);
- iPtr->varFramePtr = savedFramePtr;
- if (!otherPtr) {
- goto gotError;
- }
- goto doLinkVars;
-
- case INST_NSUPVAR:
- TRACE_WITH_OBJ(("nsupvar "), OBJ_UNDER_TOS);
- if (TclGetNamespaceFromObj(interp, OBJ_UNDER_TOS, &nsPtr) != TCL_OK) {
- goto gotError;
- }
-
- /*
- * Locate the other variable.
- */
-
- savedNsPtr = iPtr->varFramePtr->nsPtr;
- iPtr->varFramePtr->nsPtr = (Namespace *) nsPtr;
- otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
- (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access",
- /*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
- iPtr->varFramePtr->nsPtr = savedNsPtr;
- if (!otherPtr) {
- goto gotError;
- }
- goto doLinkVars;
-
- case INST_VARIABLE:
- TRACE(("variable "));
- otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
- (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access",
- /*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
- if (!otherPtr) {
- goto gotError;
- }
-
- /*
- * Do the [variable] magic.
- */
-
- TclSetVarNamespaceVar(otherPtr);
-
- doLinkVars:
-
- /*
- * If we are here, the local variable has already been created: do the
- * little work of TclPtrMakeUpvar that remains to be done right here
- * if there are no errors; otherwise, let it handle the case.
- */
-
- opnd = TclGetInt4AtPtr(pc+1);;
- varPtr = LOCAL(opnd);
- if ((varPtr != otherPtr) && !TclIsVarTraced(varPtr)
- && (TclIsVarUndefined(varPtr) || TclIsVarLink(varPtr))) {
- if (!TclIsVarUndefined(varPtr)) {
- /*
- * Then it is a defined link.
- */
-
- Var *linkPtr = varPtr->value.linkPtr;
-
- if (linkPtr == otherPtr) {
- NEXT_INST_F(5, 1, 0);
- }
- if (TclIsVarInHash(linkPtr)) {
- VarHashRefCount(linkPtr)--;
- if (TclIsVarUndefined(linkPtr)) {
- TclCleanupVar(linkPtr, NULL);
- }
- }
- }
- TclSetVarLink(varPtr);
- varPtr->value.linkPtr = otherPtr;
- if (TclIsVarInHash(otherPtr)) {
- VarHashRefCount(otherPtr)++;
- }
- } else if (TclPtrObjMakeUpvar(interp, otherPtr, NULL, 0,
- opnd) != TCL_OK) {
- goto gotError;
- }
-
- /*
- * Do not pop the namespace or frame index, it may be needed for other
- * variables - and [variable] did not push it at all.
- */
-
- NEXT_INST_F(5, 1, 0);
- }
-
- /*
- * End of variable linking instructions.
- * -----------------------------------------------------------------
+ * End of INST_STORE and related instructions.
*/
- case INST_JUMP1:
- opnd = TclGetInt1AtPtr(pc+1);
- TRACE(("%d => new pc %u\n", opnd,
- (unsigned)(pc + opnd - codePtr->codeStart)));
- NEXT_INST_F(opnd, 0, 0);
-
case INST_JUMP4:
opnd = TclGetInt4AtPtr(pc+1);
- TRACE(("%d => new pc %u\n", opnd,
- (unsigned)(pc + opnd - codePtr->codeStart)));
NEXT_INST_F(opnd, 0, 0);
{
@@ -3655,549 +1976,32 @@ TEBCresume(
jmpOffset[1] = TclGetInt4AtPtr(pc+1);
goto doCondJump;
- case INST_JUMP_FALSE1:
- jmpOffset[0] = TclGetInt1AtPtr(pc+1);
- jmpOffset[1] = 2;
- goto doCondJump;
-
- case INST_JUMP_TRUE1:
- jmpOffset[0] = 2;
- jmpOffset[1] = TclGetInt1AtPtr(pc+1);
-
doCondJump:
valuePtr = OBJ_AT_TOS;
/* TODO - check claim that taking address of b harms performance */
/* TODO - consider optimization search for constants */
if (TclGetBooleanFromObj(interp, valuePtr, &b) != TCL_OK) {
- TRACE_WITH_OBJ(("%d => ERROR: ", jmpOffset[
- ((*pc == INST_JUMP_FALSE1) || (*pc == INST_JUMP_FALSE4))
- ? 0 : 1]), Tcl_GetObjResult(interp));
goto gotError;
}
-#ifdef TCL_COMPILE_DEBUG
- if (b) {
- if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
- TRACE(("%d => %.20s true, new pc %u\n", jmpOffset[1],
- O2S(valuePtr),
- (unsigned)(pc + jmpOffset[1] - codePtr->codeStart)));
- } else {
- TRACE(("%d => %.20s true\n", jmpOffset[0], O2S(valuePtr)));
- }
- } else {
- if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
- TRACE(("%d => %.20s false\n", jmpOffset[0], O2S(valuePtr)));
- } else {
- TRACE(("%d => %.20s false, new pc %u\n", jmpOffset[0],
- O2S(valuePtr),
- (unsigned)(pc + jmpOffset[1] - codePtr->codeStart)));
- }
- }
-#endif
NEXT_INST_F(jmpOffset[b], 1, 0);
}
- case INST_JUMP_TABLE: {
- Tcl_HashEntry *hPtr;
- JumptableInfo *jtPtr;
-
- /*
- * Jump to location looked up in a hashtable; fall through to next
- * instr if lookup fails.
- */
-
- opnd = TclGetInt4AtPtr(pc+1);
- jtPtr = (JumptableInfo *) codePtr->auxDataArrayPtr[opnd].clientData;
- TRACE(("%d => %.20s ", opnd, O2S(OBJ_AT_TOS)));
- hPtr = Tcl_FindHashEntry(&jtPtr->hashTable, TclGetString(OBJ_AT_TOS));
- if (hPtr != NULL) {
- int jumpOffset = PTR2INT(Tcl_GetHashValue(hPtr));
-
- TRACE_APPEND(("found in table, new pc %u\n",
- (unsigned)(pc - codePtr->codeStart + jumpOffset)));
- NEXT_INST_F(jumpOffset, 1, 0);
- } else {
- TRACE_APPEND(("not found in table\n"));
- NEXT_INST_F(5, 1, 0);
- }
- }
-
- /*
- * These two instructions are now redundant: the complete logic of the LOR
- * and LAND is now handled by the expression compiler.
- */
-
- case INST_LOR:
- case INST_LAND: {
- /*
- * Operands must be boolean or numeric. No int->double conversions are
- * performed.
- */
-
- int i1, i2, iResult;
-
- value2Ptr = OBJ_AT_TOS;
- valuePtr = OBJ_UNDER_TOS;
- if (TclGetBooleanFromObj(NULL, valuePtr, &i1) != TCL_OK) {
- TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
- (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
- IllegalExprOperandType(interp, pc, valuePtr);
- checkInterp = 1;
- goto gotError;
- }
-
- if (TclGetBooleanFromObj(NULL, value2Ptr, &i2) != TCL_OK) {
- TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(value2Ptr),
- (value2Ptr->typePtr? value2Ptr->typePtr->name : "null")));
- IllegalExprOperandType(interp, pc, value2Ptr);
- checkInterp = 1;
- goto gotError;
- }
-
- if (*pc == INST_LOR) {
- iResult = (i1 || i2);
- } else {
- iResult = (i1 && i2);
- }
- objResultPtr = TCONST(iResult);
- TRACE(("%.20s %.20s => %d\n", O2S(valuePtr),O2S(value2Ptr),iResult));
- NEXT_INST_F(1, 2, 1);
- }
-
/*
* -----------------------------------------------------------------
* Start of general introspector instructions.
*/
- case INST_NS_CURRENT: {
- Namespace *currNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
-
- if (currNsPtr == (Namespace *) TclGetGlobalNamespace(interp)) {
- TclNewLiteralStringObj(objResultPtr, "::");
- } else {
- TclNewStringObj(objResultPtr, currNsPtr->fullName,
- strlen(currNsPtr->fullName));
- }
- TRACE_WITH_OBJ(("=> "), objResultPtr);
- NEXT_INST_F(1, 0, 1);
- }
- case INST_COROUTINE_NAME: {
- CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
-
- TclNewObj(objResultPtr);
- if (corPtr && !(corPtr->cmdPtr->flags & CMD_IS_DELETED)) {
- Tcl_GetCommandFullName(interp, (Tcl_Command) corPtr->cmdPtr,
- objResultPtr);
- }
- TRACE_WITH_OBJ(("=> "), objResultPtr);
- NEXT_INST_F(1, 0, 1);
- }
- case INST_INFO_LEVEL_NUM:
- TclNewIntObj(objResultPtr, iPtr->varFramePtr->level);
- TRACE_WITH_OBJ(("=> "), objResultPtr);
- NEXT_INST_F(1, 0, 1);
- case INST_INFO_LEVEL_ARGS: {
- int level;
- register CallFrame *framePtr = iPtr->varFramePtr;
- register CallFrame *rootFramePtr = iPtr->rootFramePtr;
-
- valuePtr = OBJ_AT_TOS;
- if (TclGetIntFromObj(interp, valuePtr, &level) != TCL_OK) {
- TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)),
- Tcl_GetObjResult(interp));
- goto gotError;
- }
- TRACE(("%d => ", level));
- if (level <= 0) {
- level += framePtr->level;
- }
- for (; (framePtr->level!=level) && (framePtr!=rootFramePtr) ;
- framePtr = framePtr->callerVarPtr) {
- /* Empty loop body */
- }
- if (framePtr == rootFramePtr) {
- Tcl_AppendResult(interp, "bad level \"", TclGetString(valuePtr),
- "\"", NULL);
- TRACE_APPEND(("ERROR: bad level\n"));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "STACK_LEVEL",
- TclGetString(valuePtr), NULL);
- goto gotError;
- }
- objResultPtr = Tcl_NewListObj(framePtr->objc, framePtr->objv);
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_F(1, 1, 1);
- }
- case INST_RESOLVE_COMMAND: {
- Tcl_Command cmd = Tcl_GetCommandFromObj(interp, OBJ_AT_TOS);
-
- TclNewObj(objResultPtr);
- if (cmd != NULL) {
- Tcl_GetCommandFullName(interp, cmd, objResultPtr);
- }
- TRACE_WITH_OBJ(("\"%.20s\" => ", O2S(OBJ_AT_TOS)), objResultPtr);
- NEXT_INST_F(1, 1, 1);
- }
- case INST_TCLOO_SELF: {
- CallFrame *framePtr = iPtr->varFramePtr;
- CallContext *contextPtr;
-
- if (framePtr == NULL ||
- !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
- TRACE(("=> ERROR: no TclOO call context\n"));
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "self may only be called from inside a method",
- -1));
- Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL);
- goto gotError;
- }
- contextPtr = framePtr->clientData;
-
- /*
- * Call out to get the name; it's expensive to compute but cached.
- */
-
- objResultPtr = TclOOObjectName(interp, contextPtr->oPtr);
- TRACE_WITH_OBJ(("=> "), objResultPtr);
- NEXT_INST_F(1, 0, 1);
- }
- {
- Object *oPtr;
-
- case INST_TCLOO_IS_OBJECT:
- oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
- objResultPtr = TCONST(oPtr != NULL ? 1 : 0);
- TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr);
- NEXT_INST_F(1, 1, 1);
- case INST_TCLOO_CLASS:
- oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
- if (oPtr == NULL) {
- TRACE(("%.30s => ERROR: not object\n", O2S(OBJ_AT_TOS)));
- goto gotError;
- }
- objResultPtr = TclOOObjectName(interp, oPtr->selfCls->thisPtr);
- TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr);
- NEXT_INST_F(1, 1, 1);
- case INST_TCLOO_NS:
- oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
- if (oPtr == NULL) {
- TRACE(("%.30s => ERROR: not object\n", O2S(OBJ_AT_TOS)));
- goto gotError;
- }
-
- /*
- * TclOO objects *never* have the global namespace as their NS.
- */
-
- TclNewStringObj(objResultPtr, oPtr->namespacePtr->fullName,
- strlen(oPtr->namespacePtr->fullName));
- TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr);
- NEXT_INST_F(1, 1, 1);
- }
-
/*
* -----------------------------------------------------------------
* Start of INST_LIST and related instructions.
*/
{
- int index, numIndices, fromIdx, toIdx;
- int nocase, match, length2, cflags, s1len, s2len;
+ int match, s1len, s2len;
const char *s1, *s2;
- case INST_LIST:
- /*
- * Pop the opnd (objc) top stack elements into a new list obj and then
- * decrement their ref counts.
- */
-
- opnd = TclGetUInt4AtPtr(pc+1);
- objResultPtr = Tcl_NewListObj(opnd, &OBJ_AT_DEPTH(opnd-1));
- TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
- NEXT_INST_V(5, opnd, 1);
-
- case INST_LIST_LENGTH:
- valuePtr = OBJ_AT_TOS;
- if (TclListObjLength(interp, valuePtr, &length) != TCL_OK) {
- TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)),
- Tcl_GetObjResult(interp));
- goto gotError;
- }
- TclNewIntObj(objResultPtr, length);
- TRACE(("%.20s => %d\n", O2S(valuePtr), length));
- NEXT_INST_F(1, 1, 1);
-
- case INST_LIST_INDEX: /* lindex with objc == 3 */
- value2Ptr = OBJ_AT_TOS;
- valuePtr = OBJ_UNDER_TOS;
-
- /*
- * Extract the desired list element.
- */
-
- if ((TclListObjGetElements(interp, valuePtr, &objc, &objv) == TCL_OK)
- && (value2Ptr->typePtr != &tclListType)
- && (TclGetIntForIndexM(NULL , value2Ptr, objc-1,
- &index) == TCL_OK)) {
- TclDecrRefCount(value2Ptr);
- tosPtr--;
- pcAdjustment = 1;
- goto lindexFastPath;
- }
-
- objResultPtr = TclLindexList(interp, valuePtr, value2Ptr);
- if (!objResultPtr) {
- TRACE_WITH_OBJ(("%.30s %.30s => ERROR: ", O2S(valuePtr),
- O2S(value2Ptr)), Tcl_GetObjResult(interp));
- goto gotError;
- }
-
- /*
- * Stash the list element on the stack.
- */
-
- TRACE(("%.20s %.20s => %s\n",
- O2S(valuePtr), O2S(value2Ptr), O2S(objResultPtr)));
- NEXT_INST_F(1, 2, -1); /* Already has the correct refCount */
-
- case INST_LIST_INDEX_IMM: /* lindex with objc==3 and index in bytecode
- * stream */
-
- /*
- * Pop the list and get the index.
- */
-
- valuePtr = OBJ_AT_TOS;
- opnd = TclGetInt4AtPtr(pc+1);
-
- /*
- * Get the contents of the list, making sure that it really is a list
- * in the process.
- */
-
- if (TclListObjGetElements(interp, valuePtr, &objc, &objv) != TCL_OK) {
- TRACE_WITH_OBJ(("\"%.30s\" %d => ERROR: ", O2S(valuePtr), opnd),
- Tcl_GetObjResult(interp));
- goto gotError;
- }
-
- /*
- * Select the list item based on the index. Negative operand means
- * end-based indexing.
- */
-
- if (opnd < -1) {
- index = opnd+1 + objc;
- } else {
- index = opnd;
- }
- pcAdjustment = 5;
-
- lindexFastPath:
- if (index >= 0 && index < objc) {
- objResultPtr = objv[index];
- } else {
- TclNewObj(objResultPtr);
- }
-
- TRACE_WITH_OBJ(("\"%.30s\" %d => ", O2S(valuePtr), opnd),
- objResultPtr);
- NEXT_INST_F(pcAdjustment, 1, 1);
-
- case INST_LIST_INDEX_MULTI: /* 'lindex' with multiple index args */
- /*
- * Determine the count of index args.
- */
-
- opnd = TclGetUInt4AtPtr(pc+1);
- numIndices = opnd-1;
-
- /*
- * Do the 'lindex' operation.
- */
-
- objResultPtr = TclLindexFlat(interp, OBJ_AT_DEPTH(numIndices),
- numIndices, &OBJ_AT_DEPTH(numIndices - 1));
- if (!objResultPtr) {
- TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp));
- goto gotError;
- }
-
- /*
- * Set result.
- */
-
- TRACE(("%d => %s\n", opnd, O2S(objResultPtr)));
- NEXT_INST_V(5, opnd, -1);
-
- case INST_LSET_FLAT:
- /*
- * Lset with 3, 5, or more args. Get the number of index args.
- */
-
- opnd = TclGetUInt4AtPtr(pc + 1);
- numIndices = opnd - 2;
-
- /*
- * Get the old value of variable, and remove the stack ref. This is
- * safe because the variable still references the object; the ref
- * count will never go zero here - we can use the smaller macro
- * Tcl_DecrRefCount.
- */
-
- valuePtr = POP_OBJECT();
- Tcl_DecrRefCount(valuePtr); /* This one should be done here */
-
- /*
- * Compute the new variable value.
- */
-
- objResultPtr = TclLsetFlat(interp, valuePtr, numIndices,
- &OBJ_AT_DEPTH(numIndices), OBJ_AT_TOS);
- if (!objResultPtr) {
- TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp));
- goto gotError;
- }
-
- /*
- * Set result.
- */
-
- TRACE(("%d => %s\n", opnd, O2S(objResultPtr)));
- NEXT_INST_V(5, numIndices+1, -1);
-
- case INST_LSET_LIST: /* 'lset' with 4 args */
- /*
- * Get the old value of variable, and remove the stack ref. This is
- * safe because the variable still references the object; the ref
- * count will never go zero here - we can use the smaller macro
- * Tcl_DecrRefCount.
- */
-
- objPtr = POP_OBJECT();
- Tcl_DecrRefCount(objPtr); /* This one should be done here. */
-
- /*
- * Get the new element value, and the index list.
- */
-
- valuePtr = OBJ_AT_TOS;
- value2Ptr = OBJ_UNDER_TOS;
-
- /*
- * Compute the new variable value.
- */
-
- objResultPtr = TclLsetList(interp, objPtr, value2Ptr, valuePtr);
- if (!objResultPtr) {
- TRACE_WITH_OBJ(("\"%.30s\" => ERROR: ", O2S(value2Ptr)),
- Tcl_GetObjResult(interp));
- goto gotError;
- }
-
- /*
- * Set result.
- */
-
- TRACE(("=> %s\n", O2S(objResultPtr)));
- NEXT_INST_F(1, 2, -1);
-
- case INST_LIST_RANGE_IMM: /* lrange with objc==4 and both indices in
- * bytecode stream */
-
- /*
- * Pop the list and get the indices.
- */
-
- valuePtr = OBJ_AT_TOS;
- fromIdx = TclGetInt4AtPtr(pc+1);
- toIdx = TclGetInt4AtPtr(pc+5);
-
- /*
- * Get the contents of the list, making sure that it really is a list
- * in the process.
- */
-
- if (TclListObjGetElements(interp, valuePtr, &objc, &objv) != TCL_OK) {
- TRACE_WITH_OBJ(("\"%.30s\" %d %d => ERROR: ", O2S(valuePtr),
- fromIdx, toIdx), Tcl_GetObjResult(interp));
- goto gotError;
- }
-
- /*
- * Skip a lot of work if we're about to throw the result away (common
- * with uses of [lassign]).
- */
-
-#ifndef TCL_COMPILE_DEBUG
- if (*(pc+9) == INST_POP) {
- NEXT_INST_F(10, 1, 0);
- }
-#endif
-
- /*
- * Adjust the indices for end-based handling.
- */
-
- if (fromIdx < -1) {
- fromIdx += 1+objc;
- if (fromIdx < -1) {
- fromIdx = -1;
- }
- } else if (fromIdx > objc) {
- fromIdx = objc;
- }
- if (toIdx < -1) {
- toIdx += 1 + objc;
- if (toIdx < -1) {
- toIdx = -1;
- }
- } else if (toIdx > objc) {
- toIdx = objc;
- }
-
- /*
- * Check if we are referring to a valid, non-empty list range, and if
- * so, build the list of elements in that range.
- */
-
- if (fromIdx<=toIdx && fromIdx<objc && toIdx>=0) {
- if (fromIdx < 0) {
- fromIdx = 0;
- }
- if (toIdx >= objc) {
- toIdx = objc-1;
- }
- if (fromIdx == 0 && toIdx != objc-1 && !Tcl_IsShared(valuePtr)) {
- /*
- * BEWARE! This is looking inside the implementation of the
- * list type.
- */
-
- List *listPtr = valuePtr->internalRep.twoPtrValue.ptr1;
-
- if (listPtr->refCount == 1) {
- TRACE(("\"%.30s\" %d %d => ", O2S(valuePtr),
- TclGetInt4AtPtr(pc+1), TclGetInt4AtPtr(pc+5)));
- for (index=toIdx+1 ; index<objc-1 ; index++) {
- TclDecrRefCount(objv[index]);
- }
- listPtr->elemCount = toIdx+1;
- listPtr->canonicalFlag = 1;
- TclInvalidateStringRep(valuePtr);
- TRACE_APPEND(("%.30s\n", O2S(valuePtr)));
- NEXT_INST_F(9, 0, 0);
- }
- }
- objResultPtr = Tcl_NewListObj(toIdx-fromIdx+1, objv+fromIdx);
- } else {
- TclNewObj(objResultPtr);
- }
-
- TRACE_WITH_OBJ(("\"%.30s\" %d %d => ", O2S(valuePtr),
- TclGetInt4AtPtr(pc+1), TclGetInt4AtPtr(pc+5)), objResultPtr);
- NEXT_INST_F(9, 1, 1);
-
case INST_LIST_IN:
case INST_LIST_NOT_IN: /* Basic list containment operators. */
value2Ptr = OBJ_AT_TOS;
@@ -4205,8 +2009,6 @@ TEBCresume(
s1 = TclGetStringFromObj(valuePtr, &s1len);
if (TclListObjLength(interp, value2Ptr, &length) != TCL_OK) {
- TRACE_WITH_OBJ(("\"%.30s\" \"%.30s\" => ERROR: ", O2S(valuePtr),
- O2S(value2Ptr)), Tcl_GetObjResult(interp));
goto gotError;
}
match = 0;
@@ -4237,8 +2039,6 @@ TEBCresume(
match = !match;
}
- TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), match));
-
/*
* Peep-hole optimisation: if you're about to jump, do jump from here.
* We're saving the effort of pushing a boolean value only to pop it
@@ -4246,30 +2046,11 @@ TEBCresume(
*/
pc++;
-#ifndef TCL_COMPILE_DEBUG
- switch (*pc) {
- case INST_JUMP_FALSE1:
- NEXT_INST_F((match ? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
- case INST_JUMP_TRUE1:
- NEXT_INST_F((match ? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
- case INST_JUMP_FALSE4:
- NEXT_INST_F((match ? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
- case INST_JUMP_TRUE4:
- NEXT_INST_F((match ? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
- }
-#endif
objResultPtr = TCONST(match);
NEXT_INST_F(0, 2, 1);
- /*
- * End of INST_LIST and related instructions.
- * -----------------------------------------------------------------
- * Start of string-related instructions.
- */
-
- case INST_STR_EQ:
+ case INST_STR_EQ:
case INST_STR_NEQ: /* String (in)equality check */
- case INST_STR_CMP: /* String compare. */
stringCompare:
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
@@ -4361,7 +2142,7 @@ TEBCresume(
* TODO: consider peephole opt.
*/
- if (*pc != INST_STR_CMP) {
+ if (1) {
/*
* Take care of the opcodes that goto'ed into here.
*/
@@ -4394,334 +2175,8 @@ TEBCresume(
} else {
objResultPtr = TCONST(match > 0);
}
- TRACE(("%.20s %.20s => %s\n", O2S(valuePtr), O2S(value2Ptr),
- O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
- case INST_STR_LEN:
- valuePtr = OBJ_AT_TOS;
- length = Tcl_GetCharLength(valuePtr);
- TclNewIntObj(objResultPtr, length);
- TRACE(("%.20s => %d\n", O2S(valuePtr), length));
- NEXT_INST_F(1, 1, 1);
-
- case INST_STR_INDEX:
- value2Ptr = OBJ_AT_TOS;
- valuePtr = OBJ_UNDER_TOS;
-
- /*
- * Get char length to calulate what 'end' means.
- */
-
- length = Tcl_GetCharLength(valuePtr);
- if (TclGetIntForIndexM(interp, value2Ptr, length-1, &index)!=TCL_OK) {
- goto gotError;
- }
-
- if ((index < 0) || (index >= length)) {
- TclNewObj(objResultPtr);
- } else if (TclIsPureByteArray(valuePtr)) {
- objResultPtr = Tcl_NewByteArrayObj(
- Tcl_GetByteArrayFromObj(valuePtr, &length)+index, 1);
- } else if (valuePtr->bytes && length == valuePtr->length) {
- objResultPtr = Tcl_NewStringObj((const char *)
- valuePtr->bytes+index, 1);
- } else {
- char buf[TCL_UTF_MAX];
- Tcl_UniChar ch = Tcl_GetUniChar(valuePtr, index);
-
- /*
- * This could be: Tcl_NewUnicodeObj((const Tcl_UniChar *)&ch, 1)
- * but creating the object as a string seems to be faster in
- * practical use.
- */
-
- length = Tcl_UniCharToUtf(ch, buf);
- objResultPtr = Tcl_NewStringObj(buf, length);
- }
-
- TRACE(("%.20s %.20s => %s\n", O2S(valuePtr), O2S(value2Ptr),
- O2S(objResultPtr)));
- NEXT_INST_F(1, 2, 1);
-
- case INST_STR_RANGE:
- TRACE(("\"%.20s\" %s %s =>",
- O2S(OBJ_AT_DEPTH(2)), O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS)));
- length = Tcl_GetCharLength(OBJ_AT_DEPTH(2)) - 1;
- if (TclGetIntForIndexM(interp, OBJ_UNDER_TOS, length,
- &fromIdx) != TCL_OK
- || TclGetIntForIndexM(interp, OBJ_AT_TOS, length,
- &toIdx) != TCL_OK) {
- goto gotError;
- }
-
- if (fromIdx < 0) {
- fromIdx = 0;
- }
- if (toIdx >= length) {
- toIdx = length;
- }
- if (toIdx >= fromIdx) {
- objResultPtr = Tcl_GetRange(OBJ_AT_DEPTH(2), fromIdx, toIdx);
- } else {
- TclNewObj(objResultPtr);
- }
- TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
- NEXT_INST_V(1, 3, 1);
-
- case INST_STR_RANGE_IMM:
- valuePtr = OBJ_AT_TOS;
- fromIdx = TclGetInt4AtPtr(pc+1);
- toIdx = TclGetInt4AtPtr(pc+5);
- length = Tcl_GetCharLength(valuePtr);
- TRACE(("\"%.20s\" %d %d => ", O2S(valuePtr), fromIdx, toIdx));
-
- /*
- * Adjust indices for end-based indexing.
- */
-
- if (fromIdx < -1) {
- fromIdx += 1 + length;
- if (fromIdx < 0) {
- fromIdx = 0;
- }
- } else if (fromIdx >= length) {
- fromIdx = length;
- }
- if (toIdx < -1) {
- toIdx += 1 + length;
- } else if (toIdx >= length) {
- toIdx = length - 1;
- }
-
- /*
- * Check if we can do a sane substring.
- */
-
- if (fromIdx <= toIdx) {
- objResultPtr = Tcl_GetRange(valuePtr, fromIdx, toIdx);
- } else {
- TclNewObj(objResultPtr);
- }
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_F(9, 1, 1);
-
- {
- Tcl_UniChar *ustring1, *ustring2, *ustring3, *end, *p;
- int length3;
- Tcl_Obj *value3Ptr;
-
- case INST_STR_MAP:
- valuePtr = OBJ_AT_TOS; /* "Main" string. */
- value3Ptr = OBJ_UNDER_TOS; /* "Target" string. */
- value2Ptr = OBJ_AT_DEPTH(2); /* "Source" string. */
- if (value3Ptr == value2Ptr) {
- objResultPtr = valuePtr;
- NEXT_INST_V(1, 3, 1);
- } else if (valuePtr == value2Ptr) {
- objResultPtr = value3Ptr;
- NEXT_INST_V(1, 3, 1);
- }
- ustring1 = Tcl_GetUnicodeFromObj(valuePtr, &length);
- if (length == 0) {
- objResultPtr = valuePtr;
- NEXT_INST_V(1, 3, 1);
- }
- ustring2 = Tcl_GetUnicodeFromObj(value2Ptr, &length2);
- if (length2 > length || length2 == 0) {
- objResultPtr = valuePtr;
- NEXT_INST_V(1, 3, 1);
- } else if (length2 == length) {
- if (memcmp(ustring1, ustring2, sizeof(Tcl_UniChar) * length)) {
- objResultPtr = valuePtr;
- } else {
- objResultPtr = value3Ptr;
- }
- NEXT_INST_V(1, 3, 1);
- }
- ustring3 = Tcl_GetUnicodeFromObj(value3Ptr, &length3);
-
- objResultPtr = Tcl_NewUnicodeObj(ustring1, 0);
- p = ustring1;
- end = ustring1 + length;
- for (; ustring1 < end; ustring1++) {
- if ((*ustring1 == *ustring2) && (length2==1 ||
- memcmp(ustring1, ustring2, sizeof(Tcl_UniChar) * length2)
- == 0)) {
- if (p != ustring1) {
- Tcl_AppendUnicodeToObj(objResultPtr, p, ustring1-p);
- p = ustring1 + length2;
- } else {
- p += length2;
- }
- ustring1 = p - 1;
-
- Tcl_AppendUnicodeToObj(objResultPtr, ustring3, length3);
- }
- }
- if (p != ustring1) {
- /*
- * Put the rest of the unmapped chars onto result.
- */
-
- Tcl_AppendUnicodeToObj(objResultPtr, p, ustring1 - p);
- }
- TRACE_WITH_OBJ(("%.20s %.20s %.20s => ",
- O2S(value2Ptr), O2S(value3Ptr), O2S(valuePtr)), objResultPtr);
- NEXT_INST_V(1, 3, 1);
-
- case INST_STR_FIND:
- ustring1 = Tcl_GetUnicodeFromObj(OBJ_AT_TOS, &length); /* Haystack */
- ustring2 = Tcl_GetUnicodeFromObj(OBJ_UNDER_TOS, &length2);/* Needle */
-
- match = -1;
- if (length2 > 0 && length2 <= length) {
- end = ustring1 + length - length2 + 1;
- for (p=ustring1 ; p<end ; p++) {
- if ((*p == *ustring2) &&
- memcmp(ustring2,p,sizeof(Tcl_UniChar)*length2) == 0) {
- match = p - ustring1;
- break;
- }
- }
- }
-
- TRACE(("%.20s %.20s => %d\n",
- O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), match));
-
- TclNewIntObj(objResultPtr, match);
- NEXT_INST_F(1, 2, 1);
-
- case INST_STR_FIND_LAST:
- ustring1 = Tcl_GetUnicodeFromObj(OBJ_AT_TOS, &length); /* Haystack */
- ustring2 = Tcl_GetUnicodeFromObj(OBJ_UNDER_TOS, &length2);/* Needle */
-
- match = -1;
- if (length2 > 0 && length2 <= length) {
- for (p=ustring1+length-length2 ; p>=ustring1 ; p--) {
- if ((*p == *ustring2) &&
- memcmp(ustring2,p,sizeof(Tcl_UniChar)*length2) == 0) {
- match = p - ustring1;
- break;
- }
- }
- }
-
- TRACE(("%.20s %.20s => %d\n",
- O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), match));
-
- TclNewIntObj(objResultPtr, match);
- NEXT_INST_F(1, 2, 1);
- }
-
- case INST_STR_MATCH:
- nocase = TclGetInt1AtPtr(pc+1);
- valuePtr = OBJ_AT_TOS; /* String */
- value2Ptr = OBJ_UNDER_TOS; /* Pattern */
-
- /*
- * Check that at least one of the objects is Unicode before promoting
- * both.
- */
-
- if ((valuePtr->typePtr == &tclStringType)
- || (value2Ptr->typePtr == &tclStringType)) {
- Tcl_UniChar *ustring1, *ustring2;
-
- ustring1 = Tcl_GetUnicodeFromObj(valuePtr, &length);
- ustring2 = Tcl_GetUnicodeFromObj(value2Ptr, &length2);
- match = TclUniCharMatch(ustring1, length, ustring2, length2,
- nocase);
- } else if (TclIsPureByteArray(valuePtr) && !nocase) {
- unsigned char *bytes1, *bytes2;
-
- bytes1 = Tcl_GetByteArrayFromObj(valuePtr, &length);
- bytes2 = Tcl_GetByteArrayFromObj(value2Ptr, &length2);
- match = TclByteArrayMatch(bytes1, length, bytes2, length2, 0);
- } else {
- match = Tcl_StringCaseMatch(TclGetString(valuePtr),
- TclGetString(value2Ptr), nocase);
- }
-
- /*
- * Reuse value2Ptr object already on stack if possible. Adjustment is
- * 2 due to the nocase byte
- */
-
- TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), match));
-
- /*
- * Peep-hole optimisation: if you're about to jump, do jump from here.
- */
-
- pc += 2;
-#ifndef TCL_COMPILE_DEBUG
- switch (*pc) {
- case INST_JUMP_FALSE1:
- NEXT_INST_F((match? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
- case INST_JUMP_TRUE1:
- NEXT_INST_F((match? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
- case INST_JUMP_FALSE4:
- NEXT_INST_F((match? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
- case INST_JUMP_TRUE4:
- NEXT_INST_F((match? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
- }
-#endif
- objResultPtr = TCONST(match);
- NEXT_INST_F(0, 2, 1);
-
- case INST_REGEXP:
- cflags = TclGetInt1AtPtr(pc+1); /* RE compile flages like NOCASE */
- valuePtr = OBJ_AT_TOS; /* String */
- value2Ptr = OBJ_UNDER_TOS; /* Pattern */
-
- /*
- * Compile and match the regular expression.
- */
-
- {
- Tcl_RegExp regExpr =
- Tcl_GetRegExpFromObj(interp, value2Ptr, cflags);
-
- if (regExpr == NULL) {
- goto regexpFailure;
- }
-
- match = Tcl_RegExpExecObj(interp, regExpr, valuePtr, 0, 0, 0);
-
- if (match < 0) {
- regexpFailure:
-#ifdef TCL_COMPILE_DEBUG
- objResultPtr = Tcl_GetObjResult(interp);
- TRACE_WITH_OBJ(("%.20s %.20s => ERROR: ",
- O2S(valuePtr), O2S(value2Ptr)), objResultPtr);
-#endif
- goto gotError;
- }
- }
-
- TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), match));
-
- /*
- * Peep-hole optimisation: if you're about to jump, do jump from here.
- * Adjustment is 2 due to the nocase byte.
- */
-
- pc += 2;
-#ifndef TCL_COMPILE_DEBUG
- switch (*pc) {
- case INST_JUMP_FALSE1:
- NEXT_INST_F((match? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
- case INST_JUMP_TRUE1:
- NEXT_INST_F((match? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
- case INST_JUMP_FALSE4:
- NEXT_INST_F((match? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
- case INST_JUMP_TRUE4:
- NEXT_INST_F((match? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
- }
-#endif
- objResultPtr = TCONST(match);
- NEXT_INST_F(0, 2, 1);
}
/*
@@ -4820,18 +2275,6 @@ TEBCresume(
foundResult:
pc++;
-#ifndef TCL_COMPILE_DEBUG
- switch (*pc) {
- case INST_JUMP_FALSE1:
- NEXT_INST_F((iResult? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
- case INST_JUMP_TRUE1:
- NEXT_INST_F((iResult? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
- case INST_JUMP_FALSE4:
- NEXT_INST_F((iResult? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
- case INST_JUMP_TRUE4:
- NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
- }
-#endif
objResultPtr = TCONST(iResult);
NEXT_INST_F(0, 2, 1);
}
@@ -4847,9 +2290,6 @@ TEBCresume(
if ((GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK)
|| (type1==TCL_NUMBER_DOUBLE) || (type1==TCL_NUMBER_NAN)) {
- TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(valuePtr),
- O2S(value2Ptr), (valuePtr->typePtr?
- valuePtr->typePtr->name : "null")));
IllegalExprOperandType(interp, pc, valuePtr);
checkInterp = 1;
goto gotError;
@@ -4857,9 +2297,6 @@ TEBCresume(
if ((GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2) != TCL_OK)
|| (type2==TCL_NUMBER_DOUBLE) || (type2==TCL_NUMBER_NAN)) {
- TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(valuePtr),
- O2S(value2Ptr), (value2Ptr->typePtr?
- value2Ptr->typePtr->name : "null")));
IllegalExprOperandType(interp, pc, value2Ptr);
checkInterp = 1;
goto gotError;
@@ -4876,26 +2313,20 @@ TEBCresume(
switch (*pc) {
case INST_MOD:
if (l2 == 0) {
- TRACE(("%s %s => DIVIDE BY ZERO\n", O2S(valuePtr),
- O2S(value2Ptr)));
goto divideByZero;
} else if ((l2 == 1) || (l2 == -1)) {
/*
* Div. by |1| always yields remainder of 0.
*/
- TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = TCONST(0);
- TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
} else if (l1 == 0) {
/*
* 0 % (non-zero) always yields remainder of 0.
*/
- TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = TCONST(0);
- TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
} else {
lResult = l1 / l2;
@@ -4926,9 +2357,7 @@ TEBCresume(
#endif
goto gotError;
} else if (l1 == 0) {
- TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = TCONST(0);
- TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
} else {
/*
@@ -4943,13 +2372,11 @@ TEBCresume(
* 4e9 and the latter 32 or 64...
*/
- TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
if (l1 > 0L) {
objResultPtr = TCONST(0);
} else {
TclNewIntObj(objResultPtr, -1);
}
- TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
}
@@ -4973,9 +2400,7 @@ TEBCresume(
#endif
goto gotError;
} else if (l1 == 0) {
- TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = TCONST(0);
- TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
} else if (l2 > (long) INT_MAX) {
/*
@@ -5012,7 +2437,6 @@ TEBCresume(
* Too large; need to use the broken-out function.
*/
- TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
break;
case INST_BITAND:
@@ -5024,14 +2448,11 @@ TEBCresume(
case INST_BITXOR:
lResult = l1 ^ l2;
longResultOfArithmetic:
- TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
if (Tcl_IsShared(valuePtr)) {
TclNewLongObj(objResultPtr, lResult);
- TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
}
TclSetLongObj(valuePtr, lResult);
- TRACE(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 1, 0);
}
}
@@ -5042,21 +2463,15 @@ TEBCresume(
* is highly undesirable due to the overall impact on size.
*/
- TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = ExecuteExtendedBinaryMathOp(interp, *pc, &TCONST(0),
valuePtr, value2Ptr);
if (objResultPtr == DIVIDED_BY_ZERO) {
- TRACE_APPEND(("DIVIDE BY ZERO\n"));
goto divideByZero;
} else if (objResultPtr == GENERAL_ARITHMETIC_ERROR) {
- TRACE_APPEND(("ERROR: %s\n",
- TclGetString(Tcl_GetObjResult(interp))));
goto gotError;
} else if (objResultPtr == NULL) {
- TRACE_APPEND(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 1, 0);
} else {
- TRACE_APPEND(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
}
@@ -5070,9 +2485,6 @@ TEBCresume(
if ((GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK)
|| IsErroringNaNType(type1)) {
- TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n",
- O2S(value2Ptr), O2S(valuePtr),
- (valuePtr->typePtr? valuePtr->typePtr->name: "null")));
IllegalExprOperandType(interp, pc, valuePtr);
checkInterp = 1;
goto gotError;
@@ -5090,9 +2502,6 @@ TEBCresume(
if ((GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2) != TCL_OK)
|| IsErroringNaNType(type2)) {
- TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n",
- O2S(value2Ptr), O2S(valuePtr),
- (value2Ptr->typePtr? value2Ptr->typePtr->name: "null")));
IllegalExprOperandType(interp, pc, value2Ptr);
checkInterp = 1;
goto gotError;
@@ -5156,20 +2565,15 @@ TEBCresume(
}
#endif
wideResultOfArithmetic:
- TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
if (Tcl_IsShared(valuePtr)) {
objResultPtr = Tcl_NewWideIntObj(wResult);
- TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
}
Tcl_SetWideIntObj(valuePtr, wResult);
- TRACE(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 1, 0);
case INST_DIV:
if (l2 == 0) {
- TRACE(("%s %s => DIVIDE BY ZERO\n",
- O2S(valuePtr), O2S(value2Ptr)));
goto divideByZero;
} else if ((l1 == LONG_MIN) && (l2 == -1)) {
/*
@@ -5210,24 +2614,17 @@ TEBCresume(
}
overflow:
- TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = ExecuteExtendedBinaryMathOp(interp, *pc, &TCONST(0),
valuePtr, value2Ptr);
if (objResultPtr == DIVIDED_BY_ZERO) {
- TRACE_APPEND(("DIVIDE BY ZERO\n"));
goto divideByZero;
} else if (objResultPtr == EXPONENT_OF_ZERO) {
- TRACE_APPEND(("EXPONENT OF ZERO\n"));
goto exponOfZero;
} else if (objResultPtr == GENERAL_ARITHMETIC_ERROR) {
- TRACE_APPEND(("ERROR: %s\n",
- TclGetString(Tcl_GetObjResult(interp))));
goto gotError;
} else if (objResultPtr == NULL) {
- TRACE_APPEND(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 1, 0);
} else {
- TRACE_APPEND(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
}
@@ -5239,8 +2636,6 @@ TEBCresume(
/* TODO - check claim that taking address of b harms performance */
/* TODO - consider optimization search for constants */
if (TclGetBooleanFromObj(NULL, valuePtr, &b) != TCL_OK) {
- TRACE(("\"%.20s\" => ILLEGAL TYPE %s\n", O2S(valuePtr),
- (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
IllegalExprOperandType(interp, pc, valuePtr);
checkInterp = 1;
goto gotError;
@@ -5258,8 +2653,6 @@ TEBCresume(
* ... ~$NonInteger => raise an error.
*/
- TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
- (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
IllegalExprOperandType(interp, pc, valuePtr);
checkInterp = 1;
goto gotError;
@@ -5284,8 +2677,6 @@ TEBCresume(
valuePtr = OBJ_AT_TOS;
if ((GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK)
|| IsErroringNaNType(type1)) {
- TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
- (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
IllegalExprOperandType(interp, pc, valuePtr);
checkInterp = 1;
goto gotError;
@@ -5329,15 +2720,12 @@ TEBCresume(
* ... +$NonNumeric => raise an error.
*/
- TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
- (valuePtr->typePtr? valuePtr->typePtr->name:"null")));
IllegalExprOperandType(interp, pc, valuePtr);
checkInterp = 1;
goto gotError;
}
/* ... TryConvertToNumeric($NonNumeric) is acceptable */
- TRACE(("\"%.20s\" => not numeric\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
if (IsErroringNaNType(type1)) {
@@ -5346,8 +2734,6 @@ TEBCresume(
* ... +$NonNumeric => raise an error.
*/
- TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
- (valuePtr->typePtr? valuePtr->typePtr->name:"null")));
IllegalExprOperandType(interp, pc, valuePtr);
checkInterp = 1;
} else {
@@ -5355,8 +2741,6 @@ TEBCresume(
* Numeric conversion of NaN -> error.
*/
- TRACE(("\"%.20s\" => IEEE FLOATING PT ERROR\n",
- O2S(objResultPtr)));
TclExprFloatError(interp, *((const double *) ptr1));
checkInterp = 1;
}
@@ -5373,7 +2757,6 @@ TEBCresume(
*/
if (valuePtr->bytes == NULL) {
- TRACE(("\"%.20s\" => numeric, same Tcl_Obj\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
if (Tcl_IsShared(valuePtr)) {
@@ -5388,11 +2771,9 @@ TEBCresume(
valuePtr->bytes = NULL;
objResultPtr = Tcl_DuplicateObj(valuePtr);
valuePtr->bytes = savedString;
- TRACE(("\"%.20s\" => numeric, new Tcl_Obj\n", O2S(valuePtr)));
NEXT_INST_F(1, 1, 1);
}
TclInvalidateStringRep(valuePtr);
- TRACE(("\"%.20s\" => numeric, same Tcl_Obj\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
@@ -5401,829 +2782,6 @@ TEBCresume(
* -----------------------------------------------------------------
*/
- case INST_BREAK:
- /*
- Tcl_ResetResult(interp);
- checkInterp = 1;
- */
- result = TCL_BREAK;
- cleanup = 0;
- goto processExceptionReturn;
-
- case INST_CONTINUE:
- /*
- Tcl_ResetResult(interp);
- checkInterp = 1;
- */
- result = TCL_CONTINUE;
- cleanup = 0;
- goto processExceptionReturn;
-
- {
- ForeachInfo *infoPtr;
- Var *iterVarPtr, *listVarPtr;
- Tcl_Obj *oldValuePtr, *listPtr, **elements;
- ForeachVarList *varListPtr;
- int numLists, iterNum, listTmpIndex, listLen, numVars;
- int varIndex, valIndex, continueLoop, j, iterTmpIndex;
- long i;
-
- case INST_FOREACH_START4:
- /*
- * Initialize the temporary local var that holds the count of the
- * number of iterations of the loop body to -1.
- */
-
- opnd = TclGetUInt4AtPtr(pc+1);
- infoPtr = codePtr->auxDataArrayPtr[opnd].clientData;
- iterTmpIndex = infoPtr->loopCtTemp;
- iterVarPtr = LOCAL(iterTmpIndex);
- oldValuePtr = iterVarPtr->value.objPtr;
-
- if (oldValuePtr == NULL) {
- TclNewLongObj(iterVarPtr->value.objPtr, -1);
- Tcl_IncrRefCount(iterVarPtr->value.objPtr);
- } else {
- TclSetLongObj(oldValuePtr, -1);
- }
- TRACE(("%u => loop iter count temp %d\n", opnd, iterTmpIndex));
-
-#ifndef TCL_COMPILE_DEBUG
- /*
- * Remark that the compiler ALWAYS sets INST_FOREACH_STEP4 immediately
- * after INST_FOREACH_START4 - let us just fall through instead of
- * jumping back to the top.
- */
-
- pc += 5;
- TCL_DTRACE_INST_NEXT();
-#else
- NEXT_INST_F(5, 0, 0);
-#endif
-
- 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.
- */
-
- opnd = TclGetUInt4AtPtr(pc+1);
- infoPtr = codePtr->auxDataArrayPtr[opnd].clientData;
- numLists = infoPtr->numLists;
-
- /*
- * Increment the temp holding the loop iteration number.
- */
-
- iterVarPtr = LOCAL(infoPtr->loopCtTemp);
- valuePtr = iterVarPtr->value.objPtr;
- iterNum = valuePtr->internalRep.longValue + 1;
- TclSetLongObj(valuePtr, iterNum);
-
- /*
- * Check whether all value lists are exhausted and we should stop the
- * loop.
- */
-
- continueLoop = 0;
- listTmpIndex = infoPtr->firstValueTemp;
- for (i = 0; i < numLists; i++) {
- varListPtr = infoPtr->varLists[i];
- numVars = varListPtr->numVars;
-
- listVarPtr = LOCAL(listTmpIndex);
- listPtr = listVarPtr->value.objPtr;
- if (TclListObjLength(interp, listPtr, &listLen) != TCL_OK) {
- TRACE_WITH_OBJ(("%u => ERROR converting list %ld, \"%s\": ",
- opnd, i, O2S(listPtr)), Tcl_GetObjResult(interp));
- goto gotError;
- }
- if (listLen > iterNum * numVars) {
- continueLoop = 1;
- }
- listTmpIndex++;
- }
-
- /*
- * If some var in some var list still has a remaining list element
- * iterate one more time. Assign to var the next element from its
- * value list. We already checked above that each list temp holds a
- * valid list object (by calling Tcl_ListObjLength), but cannot rely
- * on that check remaining valid: one list could have been shimmered
- * as a side effect of setting a traced variable.
- */
-
- if (continueLoop) {
- listTmpIndex = infoPtr->firstValueTemp;
- for (i = 0; i < numLists; i++) {
- varListPtr = infoPtr->varLists[i];
- numVars = varListPtr->numVars;
-
- listVarPtr = LOCAL(listTmpIndex);
- listPtr = TclListObjCopy(NULL, listVarPtr->value.objPtr);
- TclListObjGetElements(interp, listPtr, &listLen, &elements);
-
- valIndex = (iterNum * numVars);
- for (j = 0; j < numVars; j++) {
- if (valIndex >= listLen) {
- TclNewObj(valuePtr);
- } else {
- valuePtr = elements[valIndex];
- }
-
- varIndex = varListPtr->varIndexes[j];
- varPtr = LOCAL(varIndex);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- if (TclIsVarDirectWritable(varPtr)) {
- value2Ptr = varPtr->value.objPtr;
- if (valuePtr != value2Ptr) {
- if (value2Ptr != NULL) {
- TclDecrRefCount(value2Ptr);
- }
- varPtr->value.objPtr = valuePtr;
- Tcl_IncrRefCount(valuePtr);
- }
- } else {
- if (TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
- valuePtr, TCL_LEAVE_ERR_MSG, varIndex)==NULL){
- checkInterp = 1;
- TRACE_WITH_OBJ((
- "%u => ERROR init. index temp %d: ",
- opnd,varIndex), Tcl_GetObjResult(interp));
- TclDecrRefCount(listPtr);
- goto gotError;
- }
- checkInterp = 1;
- }
- valIndex++;
- }
- TclDecrRefCount(listPtr);
- listTmpIndex++;
- }
- }
- TRACE(("%u => %d lists, iter %d, %s loop\n", opnd, numLists,
- iterNum, (continueLoop? "continue" : "exit")));
-
- /*
- * Run-time peep-hole optimisation: the compiler ALWAYS follows
- * INST_FOREACH_STEP4 with an INST_JUMP_FALSE. We just skip that
- * instruction and jump direct from here.
- */
-
- pc += 5;
- if (*pc == INST_JUMP_FALSE1) {
- NEXT_INST_F((continueLoop? 2 : TclGetInt1AtPtr(pc+1)), 0, 0);
- } else {
- NEXT_INST_F((continueLoop? 5 : TclGetInt4AtPtr(pc+1)), 0, 0);
- }
- }
-
- 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
- * stack.
- */
-
- catchStack[++catchDepth] = INT2PTR(CURR_DEPTH);
- TRACE(("%u => catchDepth=%d, stackTop=%d\n",
- TclGetUInt4AtPtr(pc+1), (int) (catchDepth),
- (int) CURR_DEPTH));
- NEXT_INST_F(5, 0, 0);
-
- case INST_END_CATCH:
- catchDepth--;
- Tcl_ResetResult(interp);
- checkInterp = 1;
- result = TCL_OK;
- TRACE(("=> catchDepth=%d\n", (int) (catchDepth)));
- NEXT_INST_F(1, 0, 0);
-
- case INST_PUSH_RESULT:
- objResultPtr = Tcl_GetObjResult(interp);
- TRACE_WITH_OBJ(("=> "), objResultPtr);
-
- /*
- * See the comments at INST_INVOKE_STK
- */
-
- TclNewObj(objPtr);
- Tcl_IncrRefCount(objPtr);
- iPtr->objResultPtr = objPtr;
- NEXT_INST_F(1, 0, -1);
-
- case INST_PUSH_RETURN_CODE:
- TclNewIntObj(objResultPtr, result);
- TRACE(("=> %u\n", result));
- NEXT_INST_F(1, 0, 1);
-
- case INST_PUSH_RETURN_OPTIONS:
- objResultPtr = Tcl_GetReturnOptions(interp, result);
- checkInterp = 1;
- TRACE_WITH_OBJ(("=> "), objResultPtr);
- NEXT_INST_F(1, 0, 1);
-
- case INST_RETURN_CODE_BRANCH: {
- int code;
-
- if (TclGetIntFromObj(NULL, OBJ_AT_TOS, &code) != TCL_OK) {
- Tcl_Panic("INST_RETURN_CODE_BRANCH: TOS not a return code!");
- }
- if (code == TCL_OK) {
- Tcl_Panic("INST_RETURN_CODE_BRANCH: TOS is TCL_OK!");
- }
- if (code < TCL_ERROR || code > TCL_CONTINUE) {
- code = TCL_CONTINUE + 1;
- }
- NEXT_INST_F(2*code -1, 1, 0);
- }
-
- /*
- * -----------------------------------------------------------------
- * Start of dictionary-related instructions.
- */
-
- {
- int opnd2, allocateDict, done, i, allocdict;
- Tcl_Obj *dictPtr, *statePtr, *keyPtr, *listPtr, *varNamePtr, *keysPtr;
- Tcl_Obj *emptyPtr, **keyPtrPtr;
- Tcl_DictSearch *searchPtr;
- DictUpdateInfo *duiPtr;
-
- case INST_DICT_VERIFY:
- dictPtr = OBJ_AT_TOS;
- TRACE(("=> "));
- if (Tcl_DictObjSize(interp, dictPtr, &done) != TCL_OK) {
- TRACE_APPEND(("ERROR verifying dictionary nature of \"%s\": %s\n",
- O2S(OBJ_AT_DEPTH(opnd)), O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- TRACE_APPEND(("OK\n"));
- NEXT_INST_F(1, 1, 0);
-
- case INST_DICT_GET:
- case INST_DICT_EXISTS: {
- register Tcl_Interp *interp2 = interp;
-
- opnd = TclGetUInt4AtPtr(pc+1);
- TRACE(("%u => ", opnd));
- dictPtr = OBJ_AT_DEPTH(opnd);
- if (*pc == INST_DICT_EXISTS) {
- interp2 = NULL;
- }
- if (opnd > 1) {
- dictPtr = TclTraceDictPath(interp2, dictPtr, opnd-1,
- &OBJ_AT_DEPTH(opnd-1), DICT_PATH_READ);
- if (dictPtr == NULL) {
- if (*pc == INST_DICT_EXISTS) {
- goto dictNotExists;
- }
- TRACE_WITH_OBJ((
- "ERROR tracing dictionary path into \"%s\": ",
- O2S(OBJ_AT_DEPTH(opnd))),
- Tcl_GetObjResult(interp));
- goto gotError;
- }
- }
- if (Tcl_DictObjGet(interp2, dictPtr, OBJ_AT_TOS,
- &objResultPtr) == TCL_OK) {
- if (*pc == INST_DICT_EXISTS) {
- objResultPtr = TCONST(objResultPtr ? 1 : 0);
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_V(5, opnd+1, 1);
- }
- if (objResultPtr) {
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_V(5, opnd+1, 1);
- }
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "key \"%s\" not known in dictionary",
- TclGetString(OBJ_AT_TOS)));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT",
- TclGetString(OBJ_AT_TOS), NULL);
- checkInterp = 1;
- TRACE_WITH_OBJ(("%u => ERROR ", opnd), Tcl_GetObjResult(interp));
- } else {
- if (*pc == INST_DICT_EXISTS) {
- dictNotExists:
- objResultPtr = TCONST(0);
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_V(5, opnd+1, 1);
- }
- TRACE_WITH_OBJ((
- "%u => ERROR reading leaf dictionary key \"%s\": ",
- opnd, O2S(dictPtr)), Tcl_GetObjResult(interp));
- }
- goto gotError;
- }
-
- case INST_DICT_SET:
- case INST_DICT_UNSET:
- case INST_DICT_INCR_IMM:
- opnd = TclGetUInt4AtPtr(pc+1);
- opnd2 = TclGetUInt4AtPtr(pc+5);
-
- varPtr = LOCAL(opnd2);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- TRACE(("%u %u => ", opnd, opnd2));
- if (TclIsVarDirectReadable(varPtr)) {
- dictPtr = varPtr->value.objPtr;
- } else {
- dictPtr = TclPtrGetVar(interp, varPtr, NULL,NULL,NULL, 0, opnd2);
- checkInterp = 1;
- }
- if (dictPtr == NULL) {
- TclNewObj(dictPtr);
- allocateDict = 1;
- } else {
- allocateDict = Tcl_IsShared(dictPtr);
- if (allocateDict) {
- dictPtr = Tcl_DuplicateObj(dictPtr);
- }
- }
-
- switch (*pc) {
- case INST_DICT_SET:
- cleanup = opnd + 1;
- result = Tcl_DictObjPutKeyList(interp, dictPtr, opnd,
- &OBJ_AT_DEPTH(opnd), OBJ_AT_TOS);
- break;
- case INST_DICT_INCR_IMM:
- cleanup = 1;
- opnd = TclGetInt4AtPtr(pc+1);
- result = Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS, &valuePtr);
- if (result != TCL_OK) {
- break;
- }
- if (valuePtr == NULL) {
- Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS,Tcl_NewIntObj(opnd));
- } else {
- value2Ptr = Tcl_NewIntObj(opnd);
- Tcl_IncrRefCount(value2Ptr);
- if (Tcl_IsShared(valuePtr)) {
- valuePtr = Tcl_DuplicateObj(valuePtr);
- Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS, valuePtr);
- }
- result = TclIncrObj(interp, valuePtr, value2Ptr);
- if (result == TCL_OK) {
- TclInvalidateStringRep(dictPtr);
- }
- TclDecrRefCount(value2Ptr);
- }
- break;
- case INST_DICT_UNSET:
- cleanup = opnd;
- result = Tcl_DictObjRemoveKeyList(interp, dictPtr, opnd,
- &OBJ_AT_DEPTH(opnd-1));
- break;
- default:
- cleanup = 0; /* stop compiler warning */
- Tcl_Panic("Should not happen!");
- }
-
- if (result != TCL_OK) {
- if (allocateDict) {
- TclDecrRefCount(dictPtr);
- }
- TRACE_WITH_OBJ(("%u %u => ERROR updating dictionary: ",
- opnd, opnd2), Tcl_GetObjResult(interp));
- goto checkForCatch;
- }
-
- if (TclIsVarDirectWritable(varPtr)) {
- if (allocateDict) {
- value2Ptr = varPtr->value.objPtr;
- Tcl_IncrRefCount(dictPtr);
- if (value2Ptr != NULL) {
- TclDecrRefCount(value2Ptr);
- }
- varPtr->value.objPtr = dictPtr;
- }
- objResultPtr = dictPtr;
- } else {
- Tcl_IncrRefCount(dictPtr);
- objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
- dictPtr, TCL_LEAVE_ERR_MSG, opnd2);
- checkInterp = 1;
- TclDecrRefCount(dictPtr);
- if (objResultPtr == NULL) {
- TRACE_APPEND(("ERROR: %.30s\n",
- O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- }
-#ifndef TCL_COMPILE_DEBUG
- if (*(pc+9) == INST_POP) {
- NEXT_INST_V(10, cleanup, 0);
- }
-#endif
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_V(9, cleanup, 1);
-
- case INST_DICT_APPEND:
- case INST_DICT_LAPPEND:
- opnd = TclGetUInt4AtPtr(pc+1);
- varPtr = LOCAL(opnd);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- TRACE(("%u => ", opnd));
- if (TclIsVarDirectReadable(varPtr)) {
- dictPtr = varPtr->value.objPtr;
- } else {
- dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
- checkInterp = 1;
- }
- if (dictPtr == NULL) {
- TclNewObj(dictPtr);
- allocateDict = 1;
- } else {
- allocateDict = Tcl_IsShared(dictPtr);
- if (allocateDict) {
- dictPtr = Tcl_DuplicateObj(dictPtr);
- }
- }
-
- if (Tcl_DictObjGet(interp, dictPtr, OBJ_UNDER_TOS,
- &valuePtr) != TCL_OK) {
- if (allocateDict) {
- TclDecrRefCount(dictPtr);
- }
- goto gotError;
- }
-
- /*
- * Note that a non-existent key results in a NULL valuePtr, which is a
- * case handled separately below. What we *can* say at this point is
- * that the write-back will always succeed.
- */
-
- switch (*pc) {
- case INST_DICT_APPEND:
- if (valuePtr == NULL) {
- Tcl_DictObjPut(NULL, dictPtr, OBJ_UNDER_TOS, OBJ_AT_TOS);
- } else if (Tcl_IsShared(valuePtr)) {
- valuePtr = Tcl_DuplicateObj(valuePtr);
- Tcl_AppendObjToObj(valuePtr, OBJ_AT_TOS);
- Tcl_DictObjPut(NULL, dictPtr, OBJ_UNDER_TOS, valuePtr);
- } else {
- Tcl_AppendObjToObj(valuePtr, OBJ_AT_TOS);
-
- /*
- * Must invalidate the string representation of dictionary
- * here because we have directly updated the internal
- * representation; if we don't, callers could see the wrong
- * string rep despite the internal version of the dictionary
- * having the correct value. [Bug 3079830]
- */
-
- TclInvalidateStringRep(dictPtr);
- }
- break;
- case INST_DICT_LAPPEND:
- /*
- * More complex because list-append can fail.
- */
-
- if (valuePtr == NULL) {
- Tcl_DictObjPut(NULL, dictPtr, OBJ_UNDER_TOS,
- Tcl_NewListObj(1, &OBJ_AT_TOS));
- break;
- } else if (Tcl_IsShared(valuePtr)) {
- valuePtr = Tcl_DuplicateObj(valuePtr);
- if (Tcl_ListObjAppendElement(interp, valuePtr,
- OBJ_AT_TOS) != TCL_OK) {
- TclDecrRefCount(valuePtr);
- if (allocateDict) {
- TclDecrRefCount(dictPtr);
- }
- goto gotError;
- }
- Tcl_DictObjPut(NULL, dictPtr, OBJ_UNDER_TOS, valuePtr);
- } else {
- if (Tcl_ListObjAppendElement(interp, valuePtr,
- OBJ_AT_TOS) != TCL_OK) {
- if (allocateDict) {
- TclDecrRefCount(dictPtr);
- }
- goto gotError;
- }
-
- /*
- * Must invalidate the string representation of dictionary
- * here because we have directly updated the internal
- * representation; if we don't, callers could see the wrong
- * string rep despite the internal version of the dictionary
- * having the correct value. [Bug 3079830]
- */
-
- TclInvalidateStringRep(dictPtr);
- }
- break;
- default:
- Tcl_Panic("Should not happen!");
- }
-
- if (TclIsVarDirectWritable(varPtr)) {
- if (allocateDict) {
- value2Ptr = varPtr->value.objPtr;
- Tcl_IncrRefCount(dictPtr);
- if (value2Ptr != NULL) {
- TclDecrRefCount(value2Ptr);
- }
- varPtr->value.objPtr = dictPtr;
- }
- objResultPtr = dictPtr;
- } else {
- Tcl_IncrRefCount(dictPtr);
- objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
- dictPtr, TCL_LEAVE_ERR_MSG, opnd);
- checkInterp = 1;
- TclDecrRefCount(dictPtr);
- if (objResultPtr == NULL) {
- TRACE_APPEND(("ERROR: %.30s\n",
- O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- }
-#ifndef TCL_COMPILE_DEBUG
- if (*(pc+5) == INST_POP) {
- NEXT_INST_F(6, 2, 0);
- }
-#endif
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_F(5, 2, 1);
-
- case INST_DICT_FIRST:
- opnd = TclGetUInt4AtPtr(pc+1);
- TRACE(("%u => ", opnd));
- dictPtr = POP_OBJECT();
- searchPtr = ckalloc(sizeof(Tcl_DictSearch));
- if (Tcl_DictObjFirst(interp, dictPtr, searchPtr, &keyPtr,
- &valuePtr, &done) != TCL_OK) {
- ckfree(searchPtr);
- goto gotError;
- }
- TclNewObj(statePtr);
- statePtr->typePtr = &dictIteratorType;
- statePtr->internalRep.twoPtrValue.ptr1 = searchPtr;
- statePtr->internalRep.twoPtrValue.ptr2 = dictPtr;
- varPtr = LOCAL(opnd);
- if (varPtr->value.objPtr) {
- if (varPtr->value.objPtr->typePtr == &dictIteratorType) {
- Tcl_Panic("mis-issued dictFirst!");
- }
- TclDecrRefCount(varPtr->value.objPtr);
- }
- varPtr->value.objPtr = statePtr;
- Tcl_IncrRefCount(statePtr);
- goto pushDictIteratorResult;
-
- case INST_DICT_NEXT:
- opnd = TclGetUInt4AtPtr(pc+1);
- TRACE(("%u => ", opnd));
- statePtr = (*LOCAL(opnd)).value.objPtr;
- if (statePtr == NULL || statePtr->typePtr != &dictIteratorType) {
- Tcl_Panic("mis-issued dictNext!");
- }
- searchPtr = statePtr->internalRep.twoPtrValue.ptr1;
- Tcl_DictObjNext(searchPtr, &keyPtr, &valuePtr, &done);
- pushDictIteratorResult:
- if (done) {
- TclNewObj(emptyPtr);
- PUSH_OBJECT(emptyPtr);
- PUSH_OBJECT(emptyPtr);
- } else {
- PUSH_OBJECT(valuePtr);
- PUSH_OBJECT(keyPtr);
- }
-
-#ifndef TCL_COMPILE_DEBUG
- /*
- * The INST_DICT_FIRST and INST_DICT_NEXT instructsions are always
- * followed by a conditional jump, so we can take advantage of this to
- * do some peephole optimization (note that we're careful to not close
- * out someone doing something else).
- */
-
- pc += 5;
- switch (*pc) {
- case INST_JUMP_FALSE1:
- NEXT_INST_F((done ? 2 : TclGetInt1AtPtr(pc+1)), 0, 0);
- case INST_JUMP_FALSE4:
- NEXT_INST_F((done ? 5 : TclGetInt4AtPtr(pc+1)), 0, 0);
- case INST_JUMP_TRUE1:
- NEXT_INST_F((done ? TclGetInt1AtPtr(pc+1) : 2), 0, 0);
- case INST_JUMP_TRUE4:
- NEXT_INST_F((done ? TclGetInt4AtPtr(pc+1) : 5), 0, 0);
- default:
- pc -= 5;
- /* fall through to non-debug handling */
- }
-#endif
-
- TRACE_APPEND(("\"%.30s\" \"%.30s\" %d",
- O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), done));
- objResultPtr = TCONST(done);
- /* TODO: consider opt like INST_FOREACH_STEP4 */
- NEXT_INST_F(5, 0, 1);
-
- case INST_DICT_UPDATE_START:
- opnd = TclGetUInt4AtPtr(pc+1);
- opnd2 = TclGetUInt4AtPtr(pc+5);
- varPtr = LOCAL(opnd);
- duiPtr = codePtr->auxDataArrayPtr[opnd2].clientData;
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- TRACE(("%u => ", opnd));
- if (TclIsVarDirectReadable(varPtr)) {
- dictPtr = varPtr->value.objPtr;
- } else {
- dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL,
- TCL_LEAVE_ERR_MSG, opnd);
- checkInterp = 1;
- if (dictPtr == NULL) {
- goto gotError;
- }
- }
- if (TclListObjGetElements(interp, OBJ_AT_TOS, &length,
- &keyPtrPtr) != TCL_OK) {
- goto gotError;
- }
- if (length != duiPtr->length) {
- Tcl_Panic("dictUpdateStart argument length mismatch");
- }
- for (i=0 ; i<length ; i++) {
- if (Tcl_DictObjGet(interp, dictPtr, keyPtrPtr[i],
- &valuePtr) != TCL_OK) {
- goto gotError;
- }
- varPtr = LOCAL(duiPtr->varIndices[i]);
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- if (valuePtr == NULL) {
- TclObjUnsetVar2(interp,
- localName(iPtr->varFramePtr, duiPtr->varIndices[i]),
- NULL, 0);
- } else if (TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
- valuePtr, TCL_LEAVE_ERR_MSG,
- duiPtr->varIndices[i]) == NULL) {
- checkInterp = 1;
- goto gotError;
- }
- checkInterp = 1;
- }
- NEXT_INST_F(9, 0, 0);
-
- case INST_DICT_UPDATE_END:
- opnd = TclGetUInt4AtPtr(pc+1);
- opnd2 = TclGetUInt4AtPtr(pc+5);
- varPtr = LOCAL(opnd);
- duiPtr = codePtr->auxDataArrayPtr[opnd2].clientData;
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- TRACE(("%u => ", opnd));
- if (TclIsVarDirectReadable(varPtr)) {
- dictPtr = varPtr->value.objPtr;
- } else {
- dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
- checkInterp = 1;
- }
- if (dictPtr == NULL) {
- NEXT_INST_F(9, 1, 0);
- }
- if (Tcl_DictObjSize(interp, dictPtr, &length) != TCL_OK
- || TclListObjGetElements(interp, OBJ_AT_TOS, &length,
- &keyPtrPtr) != TCL_OK) {
- goto gotError;
- }
- allocdict = Tcl_IsShared(dictPtr);
- if (allocdict) {
- dictPtr = Tcl_DuplicateObj(dictPtr);
- }
- if (length > 0) {
- TclInvalidateStringRep(dictPtr);
- }
- for (i=0 ; i<length ; i++) {
- Var *var2Ptr = LOCAL(duiPtr->varIndices[i]);
-
- while (TclIsVarLink(var2Ptr)) {
- var2Ptr = var2Ptr->value.linkPtr;
- }
- if (TclIsVarDirectReadable(var2Ptr)) {
- valuePtr = var2Ptr->value.objPtr;
- } else {
- valuePtr = TclPtrGetVar(interp, var2Ptr, NULL, NULL, NULL, 0,
- duiPtr->varIndices[i]);
- checkInterp = 1;
- }
- if (valuePtr == NULL) {
- Tcl_DictObjRemove(interp, dictPtr, keyPtrPtr[i]);
- } else if (dictPtr == valuePtr) {
- Tcl_DictObjPut(interp, dictPtr, keyPtrPtr[i],
- Tcl_DuplicateObj(valuePtr));
- } else {
- Tcl_DictObjPut(interp, dictPtr, keyPtrPtr[i], valuePtr);
- }
- }
- if (TclIsVarDirectWritable(varPtr)) {
- Tcl_IncrRefCount(dictPtr);
- TclDecrRefCount(varPtr->value.objPtr);
- varPtr->value.objPtr = dictPtr;
- } else {
- objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
- dictPtr, TCL_LEAVE_ERR_MSG, opnd);
- checkInterp = 1;
- if (objResultPtr == NULL) {
- if (allocdict) {
- TclDecrRefCount(dictPtr);
- }
- goto gotError;
- }
- }
- NEXT_INST_F(9, 1, 0);
-
- case INST_DICT_EXPAND:
- dictPtr = OBJ_UNDER_TOS;
- listPtr = OBJ_AT_TOS;
- if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) {
- TRACE_WITH_OBJ(("%.30s %.30s => ERROR: ",
- O2S(dictPtr), O2S(listPtr)), Tcl_GetObjResult(interp));
- goto gotError;
- }
- objResultPtr = TclDictWithInit(interp, dictPtr, objc, objv);
- if (objResultPtr == NULL) {
- TRACE_WITH_OBJ(("%.30s %.30s => ERROR: ",
- O2S(dictPtr), O2S(listPtr)), Tcl_GetObjResult(interp));
- goto gotError;
- }
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_F(1, 2, 1);
-
- case INST_DICT_RECOMBINE_STK:
- keysPtr = POP_OBJECT();
- varNamePtr = OBJ_UNDER_TOS;
- listPtr = OBJ_AT_TOS;
- TRACE(("\"%.30s\" \"%.30s\" \"%.30s\" => ",
- O2S(varNamePtr), O2S(valuePtr), O2S(keysPtr)));
- if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- TclDecrRefCount(keysPtr);
- goto gotError;
- }
- varPtr = TclObjLookupVarEx(interp, varNamePtr, NULL,
- TCL_LEAVE_ERR_MSG, "set", 1, 1, &arrayPtr);
- if (varPtr == NULL) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- TclDecrRefCount(keysPtr);
- goto gotError;
- }
- result = TclDictWithFinish(interp, varPtr,arrayPtr,varNamePtr,NULL,-1,
- objc, objv, keysPtr);
- TclDecrRefCount(keysPtr);
- if (result != TCL_OK) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- TRACE_APPEND(("OK\n"));
- NEXT_INST_F(1, 2, 0);
-
- case INST_DICT_RECOMBINE_IMM:
- opnd = TclGetUInt4AtPtr(pc+1);
- listPtr = OBJ_UNDER_TOS;
- keysPtr = OBJ_AT_TOS;
- varPtr = LOCAL(opnd);
- TRACE(("%u <- \"%.30s\" \"%.30s\" => ", opnd, O2S(valuePtr),
- O2S(keysPtr)));
- if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- while (TclIsVarLink(varPtr)) {
- varPtr = varPtr->value.linkPtr;
- }
- result = TclDictWithFinish(interp, varPtr, NULL, NULL, NULL, opnd,
- objc, objv, keysPtr);
- if (result != TCL_OK) {
- TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
- goto gotError;
- }
- TRACE_APPEND(("OK\n"));
- NEXT_INST_F(5, 2, 0);
- }
-
- /*
- * End of dictionary-related instructions.
- * -----------------------------------------------------------------
- */
-
default:
Tcl_Panic("TclNRExecuteByteCode: unrecognized opCode %u", *pc);
} /* end of switch on opCode */
@@ -6247,37 +2805,12 @@ TEBCresume(
*/
processExceptionReturn:
-#if TCL_COMPILE_DEBUG
- switch (*pc) {
- case INST_INVOKE_STK1:
- opnd = TclGetUInt1AtPtr(pc+1);
- TRACE(("%u => ... after \"%.20s\": ", opnd, cmdNameBuf));
- break;
- case INST_INVOKE_STK4:
- opnd = TclGetUInt4AtPtr(pc+1);
- TRACE(("%u => ... after \"%.20s\": ", opnd, cmdNameBuf));
- break;
- case INST_EVAL_STK:
- /*
- * Note that the object at stacktop has to be used before doing
- * the cleanup.
- */
-
- TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
- break;
- default:
- TRACE(("=> "));
- }
-#endif
if ((result == TCL_CONTINUE) || (result == TCL_BREAK)) {
rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 0, codePtr);
if (rangePtr == NULL) {
- TRACE_APPEND(("no encl. loop or catch, returning %s\n",
- StringForResultCode(result)));
goto abnormalReturn;
}
if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
- TRACE_APPEND(("%s ...\n", StringForResultCode(result)));
goto processCatch;
}
while (cleanup--) {
@@ -6287,35 +2820,15 @@ TEBCresume(
if (result == TCL_BREAK) {
result = TCL_OK;
pc = (codePtr->codeStart + rangePtr->breakOffset);
- TRACE_APPEND(("%s, range at %d, new pc %d\n",
- StringForResultCode(result),
- rangePtr->codeOffset, rangePtr->breakOffset));
NEXT_INST_F(0, 0, 0);
}
if (rangePtr->continueOffset == -1) {
- TRACE_APPEND(("%s, loop w/o continue, checking for catch\n",
- StringForResultCode(result)));
goto checkForCatch;
}
result = TCL_OK;
pc = (codePtr->codeStart + rangePtr->continueOffset);
- TRACE_APPEND(("%s, range at %d, new pc %d\n",
- StringForResultCode(result),
- rangePtr->codeOffset, rangePtr->continueOffset));
NEXT_INST_F(0, 0, 0);
}
-#if TCL_COMPILE_DEBUG
- if (traceInstructions) {
- objPtr = Tcl_GetObjResult(interp);
- if ((result != TCL_ERROR) && (result != TCL_RETURN)) {
- TRACE_APPEND(("OTHER RETURN CODE %d, result= \"%s\"\n ",
- result, O2S(objPtr)));
- } else {
- TRACE_APPEND(("%s, result= \"%s\"\n",
- StringForResultCode(result), O2S(objPtr)));
- }
- }
-#endif
goto checkForCatch;
/*
@@ -6394,12 +2907,6 @@ TEBCresume(
*/
if (TclCanceled(iPtr) && (Tcl_Canceled(interp, 0) == TCL_ERROR)) {
-#ifdef TCL_COMPILE_DEBUG
- if (traceInstructions) {
- fprintf(stdout, " ... cancel with unwind, returning %s\n",
- StringForResultCode(result));
- }
-#endif
goto abnormalReturn;
}
@@ -6410,21 +2917,9 @@ TEBCresume(
*/
if (TclLimitExceeded(iPtr->limit)) {
-#ifdef TCL_COMPILE_DEBUG
- if (traceInstructions) {
- fprintf(stdout, " ... limit exceeded, returning %s\n",
- StringForResultCode(result));
- }
-#endif
goto abnormalReturn;
}
if (catchDepth == -1) {
-#ifdef TCL_COMPILE_DEBUG
- if (traceInstructions) {
- fprintf(stdout, " ... no enclosing catch, returning %s\n",
- StringForResultCode(result));
- }
-#endif
goto abnormalReturn;
}
rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 1, codePtr);
@@ -6435,12 +2930,6 @@ TEBCresume(
* breaking compat with previous .tbc compiled scripts.
*/
-#ifdef TCL_COMPILE_DEBUG
- if (traceInstructions) {
- fprintf(stdout, " ... no enclosing catch, returning %s\n",
- StringForResultCode(result));
- }
-#endif
goto abnormalReturn;
}
@@ -6457,14 +2946,6 @@ TEBCresume(
valuePtr = POP_OBJECT();
TclDecrRefCount(valuePtr);
}
-#ifdef TCL_COMPILE_DEBUG
- if (traceInstructions) {
- fprintf(stdout, " ... found catch at %d, catchDepth=%d, "
- "unwound to %ld, new pc %u\n",
- rangePtr->codeOffset, (int) catchDepth,
- PTR2INT(catchStack[catchDepth]), (unsigned) rangePtr->catchOffset);
- }
-#endif
pc = (codePtr->codeStart + rangePtr->catchOffset);
NEXT_INST_F(0, 0, 0); /* Restart the execution loop at pc. */
@@ -6479,8 +2960,6 @@ TEBCresume(
*/
abnormalReturn:
- TCL_DTRACE_INST_LAST();
-
/*
* Clear all expansions and same-level NR calls.
*
@@ -7881,141 +4360,6 @@ TclCompareTwoNumbers(
}
}
-#ifdef TCL_COMPILE_DEBUG
-/*
- *----------------------------------------------------------------------
- *
- * PrintByteCodeInfo --
- *
- * This procedure prints a summary about a bytecode object to stdout. It
- * is called by TclNRExecuteByteCode when starting to execute the bytecode
- * object if tclTraceExec has the value 2 or more.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-PrintByteCodeInfo(
- register ByteCode *codePtr) /* The bytecode whose summary is printed to
- * stdout. */
-{
- Proc *procPtr = codePtr->procPtr;
- Interp *iPtr = (Interp *) *codePtr->interpHandle;
-
- fprintf(stdout, "\nExecuting ByteCode 0x%p, refCt %u, epoch %u, interp 0x%p (epoch %u)\n",
- codePtr, codePtr->refCount, codePtr->compileEpoch, iPtr,
- iPtr->compileEpoch);
-
- fprintf(stdout, " Source: ");
- TclPrintSource(stdout, codePtr->source, 60);
-
- fprintf(stdout, "\n Cmds %d, src %d, inst %u, litObjs %u, aux %d, stkDepth %u, code/src %.2f\n",
- codePtr->numCommands, codePtr->numSrcBytes,
- codePtr->numCodeBytes, codePtr->numLitObjects,
- codePtr->numAuxDataItems, codePtr->maxStackDepth,
-#ifdef TCL_COMPILE_STATS
- codePtr->numSrcBytes?
- ((float)codePtr->structureSize)/codePtr->numSrcBytes :
-#endif
- 0.0);
-
-#ifdef TCL_COMPILE_STATS
- fprintf(stdout, " Code %lu = header %lu+inst %d+litObj %lu+exc %lu+aux %lu+cmdMap %d\n",
- (unsigned long) codePtr->structureSize,
- (unsigned long) (sizeof(ByteCode)-sizeof(size_t)-sizeof(Tcl_Time)),
- codePtr->numCodeBytes,
- (unsigned long) (codePtr->numLitObjects * sizeof(Tcl_Obj *)),
- (unsigned long) (codePtr->numExceptRanges*sizeof(ExceptionRange)),
- (unsigned long) (codePtr->numAuxDataItems * sizeof(AuxData)),
- codePtr->numCmdLocBytes);
-#endif /* TCL_COMPILE_STATS */
- if (procPtr != NULL) {
- fprintf(stdout,
- " Proc 0x%p, refCt %d, args %d, compiled locals %d\n",
- procPtr, procPtr->refCount, procPtr->numArgs,
- procPtr->numCompiledLocals);
- }
-}
-#endif /* TCL_COMPILE_DEBUG */
-
-/*
- *----------------------------------------------------------------------
- *
- * ValidatePcAndStackTop --
- *
- * This procedure is called by TclNRExecuteByteCode when debugging to
- * verify that the program counter and stack top are valid during
- * execution.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Prints a message to stderr and panics if either the pc or stack top
- * are invalid.
- *
- *----------------------------------------------------------------------
- */
-
-#ifdef TCL_COMPILE_DEBUG
-static void
-ValidatePcAndStackTop(
- register ByteCode *codePtr, /* The bytecode whose summary is printed to
- * stdout. */
- const unsigned char *pc, /* Points to first byte of a bytecode
- * instruction. The program counter. */
- int stackTop, /* Current stack top. Must be between
- * stackLowerBound and stackUpperBound
- * (inclusive). */
- int checkStack) /* 0 if the stack depth check should be
- * skipped. */
-{
- int stackUpperBound = codePtr->maxStackDepth;
- /* Greatest legal value for stackTop. */
- unsigned relativePc = (unsigned) (pc - codePtr->codeStart);
- unsigned long codeStart = (unsigned long) codePtr->codeStart;
- unsigned long codeEnd = (unsigned long)
- (codePtr->codeStart + codePtr->numCodeBytes);
- unsigned char opCode = *pc;
-
- if (((unsigned long) pc < codeStart) || ((unsigned long) pc > codeEnd)) {
- fprintf(stderr, "\nBad instruction pc 0x%p in TclNRExecuteByteCode\n",
- pc);
- Tcl_Panic("TclNRExecuteByteCode execution failure: bad pc");
- }
- if ((unsigned) opCode > LAST_INST_OPCODE) {
- fprintf(stderr, "\nBad opcode %d at pc %u in TclNRExecuteByteCode\n",
- (unsigned) opCode, relativePc);
- Tcl_Panic("TclNRExecuteByteCode execution failure: bad opcode");
- }
- if (checkStack &&
- ((stackTop < 0) || (stackTop > stackUpperBound))) {
- int numChars;
- const char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars, NULL);
-
- fprintf(stderr, "\nBad stack top %d at pc %u in TclNRExecuteByteCode (min 0, max %i)",
- stackTop, relativePc, stackUpperBound);
- if (cmd != NULL) {
- Tcl_Obj *message;
-
- TclNewLiteralStringObj(message, "\n executing ");
- Tcl_IncrRefCount(message);
- Tcl_AppendLimitedToObj(message, cmd, numChars, 100, NULL);
- fprintf(stderr,"%s\n", Tcl_GetString(message));
- Tcl_DecrRefCount(message);
- } else {
- fprintf(stderr, "\n");
- }
- Tcl_Panic("TclNRExecuteByteCode execution failure: bad stack top");
- }
-}
-#endif /* TCL_COMPILE_DEBUG */
/*
*----------------------------------------------------------------------
@@ -8047,7 +4391,7 @@ IllegalExprOperandType(
ClientData ptr;
int type;
const unsigned char opcode = *pc;
- const char *description, *operator = operatorStrings[opcode - INST_LOR];
+ const char *description, *operator = operatorStrings[opcode - INST_BITOR];
if (opcode == INST_EXPON) {
operator = "**";
@@ -8295,36 +4639,6 @@ GetExceptRangeForPc(
/*
*----------------------------------------------------------------------
*
- * GetOpcodeName --
- *
- * This procedure is called by the TRACE and TRACE_WITH_OBJ macros used
- * in TclNRExecuteByteCode when debugging. It returns the name of the
- * bytecode instruction at a specified instruction pc.
- *
- * Results:
- * A character string for the instruction.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-#ifdef TCL_COMPILE_DEBUG
-static const char *
-GetOpcodeName(
- const unsigned char *pc) /* Points to the instruction whose name should
- * be returned. */
-{
- unsigned char opCode = *pc;
-
- return tclInstructionTable[opCode].name;
-}
-#endif /* TCL_COMPILE_DEBUG */
-
-/*
- *----------------------------------------------------------------------
- *
* TclExprFloatError --
*
* This procedure is called when an error occurs during a floating-point
@@ -8371,497 +4685,7 @@ TclExprFloatError(
}
}
-#ifdef TCL_COMPILE_STATS
-/*
- *----------------------------------------------------------------------
- *
- * TclLog2 --
- *
- * Procedure used while collecting compilation statistics to determine
- * the log base 2 of an integer.
- *
- * Results:
- * Returns the log base 2 of the operand. If the argument is less than or
- * equal to zero, a zero is returned.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclLog2(
- register int value) /* The integer for which to compute the log
- * base 2. */
-{
- register int n = value;
- register int result = 0;
-
- while (n > 1) {
- n = n >> 1;
- result++;
- }
- return result;
-}
-/*
- *----------------------------------------------------------------------
- *
- * EvalStatsCmd --
- *
- * Implements the "evalstats" command that prints instruction execution
- * counts to stdout.
- *
- * Results:
- * Standard Tcl results.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-EvalStatsCmd(
- ClientData unused, /* Unused. */
- Tcl_Interp *interp, /* The current interpreter. */
- int objc, /* The number of arguments. */
- Tcl_Obj *const objv[]) /* The argument strings. */
-{
- Interp *iPtr = (Interp *) interp;
- LiteralTable *globalTablePtr = &iPtr->literalTable;
- ByteCodeStats *statsPtr = &iPtr->stats;
- double totalCodeBytes, currentCodeBytes;
- double totalLiteralBytes, currentLiteralBytes;
- double objBytesIfUnshared, strBytesIfUnshared, sharingBytesSaved;
- double strBytesSharedMultX, strBytesSharedOnce;
- double numInstructions, currentHeaderBytes;
- long numCurrentByteCodes, numByteCodeLits;
- long refCountSum, literalMgmtBytes, sum;
- int numSharedMultX, numSharedOnce;
- int decadeHigh, minSizeDecade, maxSizeDecade, length, i;
- char *litTableStats;
- LiteralEntry *entryPtr;
- Tcl_Obj *objPtr;
-
-#define Percent(a,b) ((a) * 100.0 / (b))
-
- objPtr = Tcl_NewObj();
- Tcl_IncrRefCount(objPtr);
-
- numInstructions = 0.0;
- for (i = 0; i < 256; i++) {
- if (statsPtr->instructionCount[i] != 0) {
- numInstructions += statsPtr->instructionCount[i];
- }
- }
-
- totalLiteralBytes = sizeof(LiteralTable)
- + iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)
- + (statsPtr->numLiteralsCreated * sizeof(LiteralEntry))
- + (statsPtr->numLiteralsCreated * sizeof(Tcl_Obj))
- + statsPtr->totalLitStringBytes;
- totalCodeBytes = statsPtr->totalByteCodeBytes + totalLiteralBytes;
-
- numCurrentByteCodes =
- statsPtr->numCompilations - statsPtr->numByteCodesFreed;
- currentHeaderBytes = numCurrentByteCodes
- * (sizeof(ByteCode) - sizeof(size_t) - sizeof(Tcl_Time));
- literalMgmtBytes = sizeof(LiteralTable)
- + (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *))
- + (iPtr->literalTable.numEntries * sizeof(LiteralEntry));
- currentLiteralBytes = literalMgmtBytes
- + iPtr->literalTable.numEntries * sizeof(Tcl_Obj)
- + statsPtr->currentLitStringBytes;
- currentCodeBytes = statsPtr->currentByteCodeBytes + currentLiteralBytes;
-
- /*
- * Summary statistics, total and current source and ByteCode sizes.
- */
-
- Tcl_AppendPrintfToObj(objPtr, "\n----------------------------------------------------------------\n");
- Tcl_AppendPrintfToObj(objPtr,
- "Compilation and execution statistics for interpreter %#lx\n",
- (long int)iPtr);
-
- Tcl_AppendPrintfToObj(objPtr, "\nNumber ByteCodes executed\t%ld\n",
- statsPtr->numExecutions);
- Tcl_AppendPrintfToObj(objPtr, "Number ByteCodes compiled\t%ld\n",
- statsPtr->numCompilations);
- Tcl_AppendPrintfToObj(objPtr, " Mean executions/compile\t%.1f\n",
- statsPtr->numExecutions / (float)statsPtr->numCompilations);
-
- Tcl_AppendPrintfToObj(objPtr, "\nInstructions executed\t\t%.0f\n",
- numInstructions);
- Tcl_AppendPrintfToObj(objPtr, " Mean inst/compile\t\t%.0f\n",
- numInstructions / statsPtr->numCompilations);
- Tcl_AppendPrintfToObj(objPtr, " Mean inst/execution\t\t%.0f\n",
- numInstructions / statsPtr->numExecutions);
-
- Tcl_AppendPrintfToObj(objPtr, "\nTotal ByteCodes\t\t\t%ld\n",
- statsPtr->numCompilations);
- Tcl_AppendPrintfToObj(objPtr, " Source bytes\t\t\t%.6g\n",
- statsPtr->totalSrcBytes);
- Tcl_AppendPrintfToObj(objPtr, " Code bytes\t\t\t%.6g\n",
- totalCodeBytes);
- Tcl_AppendPrintfToObj(objPtr, " ByteCode bytes\t\t%.6g\n",
- statsPtr->totalByteCodeBytes);
- Tcl_AppendPrintfToObj(objPtr, " Literal bytes\t\t%.6g\n",
- totalLiteralBytes);
- Tcl_AppendPrintfToObj(objPtr, " table %lu + bkts %lu + entries %lu + objects %lu + strings %.6g\n",
- (unsigned long) sizeof(LiteralTable),
- (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
- (unsigned long) (statsPtr->numLiteralsCreated * sizeof(LiteralEntry)),
- (unsigned long) (statsPtr->numLiteralsCreated * sizeof(Tcl_Obj)),
- statsPtr->totalLitStringBytes);
- Tcl_AppendPrintfToObj(objPtr, " Mean code/compile\t\t%.1f\n",
- totalCodeBytes / statsPtr->numCompilations);
- Tcl_AppendPrintfToObj(objPtr, " Mean code/source\t\t%.1f\n",
- totalCodeBytes / statsPtr->totalSrcBytes);
-
- Tcl_AppendPrintfToObj(objPtr, "\nCurrent (active) ByteCodes\t%ld\n",
- numCurrentByteCodes);
- Tcl_AppendPrintfToObj(objPtr, " Source bytes\t\t\t%.6g\n",
- statsPtr->currentSrcBytes);
- Tcl_AppendPrintfToObj(objPtr, " Code bytes\t\t\t%.6g\n",
- currentCodeBytes);
- Tcl_AppendPrintfToObj(objPtr, " ByteCode bytes\t\t%.6g\n",
- statsPtr->currentByteCodeBytes);
- Tcl_AppendPrintfToObj(objPtr, " Literal bytes\t\t%.6g\n",
- currentLiteralBytes);
- Tcl_AppendPrintfToObj(objPtr, " table %lu + bkts %lu + entries %lu + objects %lu + strings %.6g\n",
- (unsigned long) sizeof(LiteralTable),
- (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
- (unsigned long) (iPtr->literalTable.numEntries * sizeof(LiteralEntry)),
- (unsigned long) (iPtr->literalTable.numEntries * sizeof(Tcl_Obj)),
- statsPtr->currentLitStringBytes);
- Tcl_AppendPrintfToObj(objPtr, " Mean code/source\t\t%.1f\n",
- currentCodeBytes / statsPtr->currentSrcBytes);
- Tcl_AppendPrintfToObj(objPtr, " Code + source bytes\t\t%.6g (%0.1f mean code/src)\n",
- (currentCodeBytes + statsPtr->currentSrcBytes),
- (currentCodeBytes / statsPtr->currentSrcBytes) + 1.0);
-
- /*
- * Tcl_IsShared statistics check
- *
- * This gives the refcount of each obj as Tcl_IsShared was called for it.
- * Shared objects must be duplicated before they can be modified.
- */
-
- numSharedMultX = 0;
- Tcl_AppendPrintfToObj(objPtr, "\nTcl_IsShared object check (all objects):\n");
- Tcl_AppendPrintfToObj(objPtr, " Object had refcount <=1 (not shared)\t%ld\n",
- tclObjsShared[1]);
- for (i = 2; i < TCL_MAX_SHARED_OBJ_STATS; i++) {
- Tcl_AppendPrintfToObj(objPtr, " refcount ==%d\t\t%ld\n",
- i, tclObjsShared[i]);
- numSharedMultX += tclObjsShared[i];
- }
- Tcl_AppendPrintfToObj(objPtr, " refcount >=%d\t\t%ld\n",
- i, tclObjsShared[0]);
- numSharedMultX += tclObjsShared[0];
- Tcl_AppendPrintfToObj(objPtr, " Total shared objects\t\t\t%d\n",
- numSharedMultX);
-
- /*
- * Literal table statistics.
- */
-
- numByteCodeLits = 0;
- refCountSum = 0;
- numSharedMultX = 0;
- numSharedOnce = 0;
- objBytesIfUnshared = 0.0;
- strBytesIfUnshared = 0.0;
- strBytesSharedMultX = 0.0;
- strBytesSharedOnce = 0.0;
- for (i = 0; i < globalTablePtr->numBuckets; i++) {
- for (entryPtr = globalTablePtr->buckets[i]; entryPtr != NULL;
- entryPtr = entryPtr->nextPtr) {
- if (entryPtr->objPtr->typePtr == &tclByteCodeType) {
- numByteCodeLits++;
- }
- (void) Tcl_GetStringFromObj(entryPtr->objPtr, &length);
- refCountSum += entryPtr->refCount;
- objBytesIfUnshared += (entryPtr->refCount * sizeof(Tcl_Obj));
- strBytesIfUnshared += (entryPtr->refCount * (length+1));
- if (entryPtr->refCount > 1) {
- numSharedMultX++;
- strBytesSharedMultX += (length+1);
- } else {
- numSharedOnce++;
- strBytesSharedOnce += (length+1);
- }
- }
- }
- sharingBytesSaved = (objBytesIfUnshared + strBytesIfUnshared)
- - currentLiteralBytes;
-
- Tcl_AppendPrintfToObj(objPtr, "\nTotal objects (all interps)\t%ld\n",
- tclObjsAlloced);
- Tcl_AppendPrintfToObj(objPtr, "Current objects\t\t\t%ld\n",
- (tclObjsAlloced - tclObjsFreed));
- Tcl_AppendPrintfToObj(objPtr, "Total literal objects\t\t%ld\n",
- statsPtr->numLiteralsCreated);
-
- Tcl_AppendPrintfToObj(objPtr, "\nCurrent literal objects\t\t%d (%0.1f%% of current objects)\n",
- globalTablePtr->numEntries,
- Percent(globalTablePtr->numEntries, tclObjsAlloced-tclObjsFreed));
- Tcl_AppendPrintfToObj(objPtr, " ByteCode literals\t\t%ld (%0.1f%% of current literals)\n",
- numByteCodeLits,
- Percent(numByteCodeLits, globalTablePtr->numEntries));
- Tcl_AppendPrintfToObj(objPtr, " Literals reused > 1x\t\t%d\n",
- numSharedMultX);
- Tcl_AppendPrintfToObj(objPtr, " Mean reference count\t\t%.2f\n",
- ((double) refCountSum) / globalTablePtr->numEntries);
- Tcl_AppendPrintfToObj(objPtr, " Mean len, str reused >1x \t%.2f\n",
- (numSharedMultX ? strBytesSharedMultX/numSharedMultX : 0.0));
- Tcl_AppendPrintfToObj(objPtr, " Mean len, str used 1x\t\t%.2f\n",
- (numSharedOnce ? strBytesSharedOnce/numSharedOnce : 0.0));
- Tcl_AppendPrintfToObj(objPtr, " Total sharing savings\t\t%.6g (%0.1f%% of bytes if no sharing)\n",
- sharingBytesSaved,
- Percent(sharingBytesSaved, objBytesIfUnshared+strBytesIfUnshared));
- Tcl_AppendPrintfToObj(objPtr, " Bytes with sharing\t\t%.6g\n",
- currentLiteralBytes);
- Tcl_AppendPrintfToObj(objPtr, " table %lu + bkts %lu + entries %lu + objects %lu + strings %.6g\n",
- (unsigned long) sizeof(LiteralTable),
- (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
- (unsigned long) (iPtr->literalTable.numEntries * sizeof(LiteralEntry)),
- (unsigned long) (iPtr->literalTable.numEntries * sizeof(Tcl_Obj)),
- statsPtr->currentLitStringBytes);
- Tcl_AppendPrintfToObj(objPtr, " Bytes if no sharing\t\t%.6g = objects %.6g + strings %.6g\n",
- (objBytesIfUnshared + strBytesIfUnshared),
- objBytesIfUnshared, strBytesIfUnshared);
- Tcl_AppendPrintfToObj(objPtr, " String sharing savings \t%.6g = unshared %.6g - shared %.6g\n",
- (strBytesIfUnshared - statsPtr->currentLitStringBytes),
- strBytesIfUnshared, statsPtr->currentLitStringBytes);
- Tcl_AppendPrintfToObj(objPtr, " Literal mgmt overhead\t\t%ld (%0.1f%% of bytes with sharing)\n",
- literalMgmtBytes,
- Percent(literalMgmtBytes, currentLiteralBytes));
- Tcl_AppendPrintfToObj(objPtr, " table %lu + buckets %lu + entries %lu\n",
- (unsigned long) sizeof(LiteralTable),
- (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
- (unsigned long) (iPtr->literalTable.numEntries * sizeof(LiteralEntry)));
-
- /*
- * Breakdown of current ByteCode space requirements.
- */
-
- Tcl_AppendPrintfToObj(objPtr, "\nBreakdown of current ByteCode requirements:\n");
- Tcl_AppendPrintfToObj(objPtr, " Bytes Pct of Avg per\n");
- Tcl_AppendPrintfToObj(objPtr, " total ByteCode\n");
- Tcl_AppendPrintfToObj(objPtr, "Total %12.6g 100.00%% %8.1f\n",
- statsPtr->currentByteCodeBytes,
- statsPtr->currentByteCodeBytes / numCurrentByteCodes);
- Tcl_AppendPrintfToObj(objPtr, "Header %12.6g %8.1f%% %8.1f\n",
- currentHeaderBytes,
- Percent(currentHeaderBytes, statsPtr->currentByteCodeBytes),
- currentHeaderBytes / numCurrentByteCodes);
- Tcl_AppendPrintfToObj(objPtr, "Instructions %12.6g %8.1f%% %8.1f\n",
- statsPtr->currentInstBytes,
- Percent(statsPtr->currentInstBytes,statsPtr->currentByteCodeBytes),
- statsPtr->currentInstBytes / numCurrentByteCodes);
- Tcl_AppendPrintfToObj(objPtr, "Literal ptr array %12.6g %8.1f%% %8.1f\n",
- statsPtr->currentLitBytes,
- Percent(statsPtr->currentLitBytes,statsPtr->currentByteCodeBytes),
- statsPtr->currentLitBytes / numCurrentByteCodes);
- Tcl_AppendPrintfToObj(objPtr, "Exception table %12.6g %8.1f%% %8.1f\n",
- statsPtr->currentExceptBytes,
- Percent(statsPtr->currentExceptBytes,statsPtr->currentByteCodeBytes),
- statsPtr->currentExceptBytes / numCurrentByteCodes);
- Tcl_AppendPrintfToObj(objPtr, "Auxiliary data %12.6g %8.1f%% %8.1f\n",
- statsPtr->currentAuxBytes,
- Percent(statsPtr->currentAuxBytes,statsPtr->currentByteCodeBytes),
- statsPtr->currentAuxBytes / numCurrentByteCodes);
- Tcl_AppendPrintfToObj(objPtr, "Command map %12.6g %8.1f%% %8.1f\n",
- statsPtr->currentCmdMapBytes,
- Percent(statsPtr->currentCmdMapBytes,statsPtr->currentByteCodeBytes),
- statsPtr->currentCmdMapBytes / numCurrentByteCodes);
-
- /*
- * Detailed literal statistics.
- */
-
- Tcl_AppendPrintfToObj(objPtr, "\nLiteral string sizes:\n");
- Tcl_AppendPrintfToObj(objPtr, "\t Up to length\t\tPercentage\n");
- maxSizeDecade = 0;
- for (i = 31; i >= 0; i--) {
- if (statsPtr->literalCount[i] > 0) {
- maxSizeDecade = i;
- break;
- }
- }
- sum = 0;
- for (i = 0; i <= maxSizeDecade; i++) {
- decadeHigh = (1 << (i+1)) - 1;
- sum += statsPtr->literalCount[i];
- Tcl_AppendPrintfToObj(objPtr, "\t%10d\t\t%8.0f%%\n",
- decadeHigh, Percent(sum, statsPtr->numLiteralsCreated));
- }
-
- litTableStats = TclLiteralStats(globalTablePtr);
- Tcl_AppendPrintfToObj(objPtr, "\nCurrent literal table statistics:\n%s\n",
- litTableStats);
- ckfree(litTableStats);
-
- /*
- * Source and ByteCode size distributions.
- */
-
- Tcl_AppendPrintfToObj(objPtr, "\nSource sizes:\n");
- Tcl_AppendPrintfToObj(objPtr, "\t Up to size\t\tPercentage\n");
- minSizeDecade = maxSizeDecade = 0;
- for (i = 0; i < 31; i++) {
- if (statsPtr->srcCount[i] > 0) {
- minSizeDecade = i;
- break;
- }
- }
- for (i = 31; i >= 0; i--) {
- if (statsPtr->srcCount[i] > 0) {
- maxSizeDecade = i;
- break;
- }
- }
- sum = 0;
- for (i = minSizeDecade; i <= maxSizeDecade; i++) {
- decadeHigh = (1 << (i+1)) - 1;
- sum += statsPtr->srcCount[i];
- Tcl_AppendPrintfToObj(objPtr, "\t%10d\t\t%8.0f%%\n",
- decadeHigh, Percent(sum, statsPtr->numCompilations));
- }
-
- Tcl_AppendPrintfToObj(objPtr, "\nByteCode sizes:\n");
- Tcl_AppendPrintfToObj(objPtr, "\t Up to size\t\tPercentage\n");
- minSizeDecade = maxSizeDecade = 0;
- for (i = 0; i < 31; i++) {
- if (statsPtr->byteCodeCount[i] > 0) {
- minSizeDecade = i;
- break;
- }
- }
- for (i = 31; i >= 0; i--) {
- if (statsPtr->byteCodeCount[i] > 0) {
- maxSizeDecade = i;
- break;
- }
- }
- sum = 0;
- for (i = minSizeDecade; i <= maxSizeDecade; i++) {
- decadeHigh = (1 << (i+1)) - 1;
- sum += statsPtr->byteCodeCount[i];
- Tcl_AppendPrintfToObj(objPtr, "\t%10d\t\t%8.0f%%\n",
- decadeHigh, Percent(sum, statsPtr->numCompilations));
- }
-
- Tcl_AppendPrintfToObj(objPtr, "\nByteCode longevity (excludes Current ByteCodes):\n");
- Tcl_AppendPrintfToObj(objPtr, "\t Up to ms\t\tPercentage\n");
- minSizeDecade = maxSizeDecade = 0;
- for (i = 0; i < 31; i++) {
- if (statsPtr->lifetimeCount[i] > 0) {
- minSizeDecade = i;
- break;
- }
- }
- for (i = 31; i >= 0; i--) {
- if (statsPtr->lifetimeCount[i] > 0) {
- maxSizeDecade = i;
- break;
- }
- }
- sum = 0;
- for (i = minSizeDecade; i <= maxSizeDecade; i++) {
- decadeHigh = (1 << (i+1)) - 1;
- sum += statsPtr->lifetimeCount[i];
- Tcl_AppendPrintfToObj(objPtr, "\t%12.3f\t\t%8.0f%%\n",
- decadeHigh/1000.0, Percent(sum, statsPtr->numByteCodesFreed));
- }
-
- /*
- * Instruction counts.
- */
-
- Tcl_AppendPrintfToObj(objPtr, "\nInstruction counts:\n");
- for (i = 0; i <= LAST_INST_OPCODE; i++) {
- Tcl_AppendPrintfToObj(objPtr, "%20s %8ld ",
- tclInstructionTable[i].name, statsPtr->instructionCount[i]);
- if (statsPtr->instructionCount[i]) {
- Tcl_AppendPrintfToObj(objPtr, "%6.1f%%\n",
- Percent(statsPtr->instructionCount[i], numInstructions));
- } else {
- Tcl_AppendPrintfToObj(objPtr, "0\n");
- }
- }
-
-#ifdef TCL_MEM_DEBUG
- Tcl_AppendPrintfToObj(objPtr, "\nHeap Statistics:\n");
- TclDumpMemoryInfo((ClientData) objPtr, 1);
-#endif
- Tcl_AppendPrintfToObj(objPtr, "\n----------------------------------------------------------------\n");
-
- if (objc == 1) {
- Tcl_SetObjResult(interp, objPtr);
- } else {
- Tcl_Channel outChan;
- char *str = Tcl_GetStringFromObj(objv[1], &length);
-
- if (length) {
- if (strcmp(str, "stdout") == 0) {
- outChan = Tcl_GetStdChannel(TCL_STDOUT);
- } else if (strcmp(str, "stderr") == 0) {
- outChan = Tcl_GetStdChannel(TCL_STDERR);
- } else {
- outChan = Tcl_OpenFileChannel(NULL, str, "w", 0664);
- }
- } else {
- outChan = Tcl_GetStdChannel(TCL_STDOUT);
- }
- if (outChan != NULL) {
- Tcl_WriteObj(outChan, objPtr);
- }
- }
- Tcl_DecrRefCount(objPtr);
- return TCL_OK;
-}
-#endif /* TCL_COMPILE_STATS */
-
-#ifdef TCL_COMPILE_DEBUG
-/*
- *----------------------------------------------------------------------
- *
- * StringForResultCode --
- *
- * Procedure that returns a human-readable string representing a Tcl
- * result code such as TCL_ERROR.
- *
- * Results:
- * If the result code is one of the standard Tcl return codes, the result
- * is a string representing that code such as "TCL_ERROR". Otherwise, the
- * result string is that code formatted as a sequence of decimal digit
- * characters. Note that the resulting string must not be modified by the
- * caller.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static const char *
-StringForResultCode(
- int result) /* The Tcl result code for which to generate a
- * string. */
-{
- static char buf[TCL_INTEGER_SPACE];
-
- if ((result >= TCL_OK) && (result <= TCL_CONTINUE)) {
- return resultStrings[result];
- }
- TclFormatInt(buf, result);
- return buf;
-}
-#endif /* TCL_COMPILE_DEBUG */
/*
* Local Variables:
diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c
index eb195ab..4d157cc 100644
--- a/generic/tclIOCmd.c
+++ b/generic/tclIOCmd.c
@@ -1952,25 +1952,25 @@ TclInitChanCmd(
* function at the moment.
*/
static const EnsembleImplMap initMap[] = {
- {"blocked", Tcl_FblockedObjCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"close", Tcl_CloseObjCmd, TclCompileBasic1Or2ArgCmd, NULL, 0},
+ {"blocked", Tcl_FblockedObjCmd, NULL, NULL, 0},
+ {"close", Tcl_CloseObjCmd, NULL, NULL, 0},
{"copy", Tcl_FcopyObjCmd, NULL, NULL, 0},
- {"create", TclChanCreateObjCmd, TclCompileBasic2ArgCmd, NULL, 0}, /* TIP #219 */
- {"eof", Tcl_EofObjCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"event", Tcl_FileEventObjCmd, TclCompileBasic2Or3ArgCmd, NULL, 0},
- {"flush", Tcl_FlushObjCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"gets", Tcl_GetsObjCmd, TclCompileBasic1Or2ArgCmd, NULL, 0},
- {"names", TclChannelNamesCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"pending", ChanPendingObjCmd, TclCompileBasic2ArgCmd, NULL, 0}, /* TIP #287 */
- {"pipe", ChanPipeObjCmd, TclCompileBasic0ArgCmd, NULL, 0}, /* TIP #304 */
- {"pop", TclChanPopObjCmd, TclCompileBasic1ArgCmd, NULL, 0}, /* TIP #230 */
- {"postevent", TclChanPostEventObjCmd, TclCompileBasic2ArgCmd, NULL, 0}, /* TIP #219 */
- {"push", TclChanPushObjCmd, TclCompileBasic2ArgCmd, NULL, 0}, /* TIP #230 */
+ {"create", TclChanCreateObjCmd, NULL, NULL, 0}, /* TIP #219 */
+ {"eof", Tcl_EofObjCmd, NULL, NULL, 0},
+ {"event", Tcl_FileEventObjCmd, NULL, NULL, 0},
+ {"flush", Tcl_FlushObjCmd, NULL, NULL, 0},
+ {"gets", Tcl_GetsObjCmd, NULL, NULL, 0},
+ {"names", TclChannelNamesCmd, NULL, NULL, 0},
+ {"pending", ChanPendingObjCmd, NULL, NULL, 0}, /* TIP #287 */
+ {"pipe", ChanPipeObjCmd, NULL, NULL, 0}, /* TIP #304 */
+ {"pop", TclChanPopObjCmd, NULL, NULL, 0}, /* TIP #230 */
+ {"postevent", TclChanPostEventObjCmd, NULL, NULL, 0}, /* TIP #219 */
+ {"push", TclChanPushObjCmd, NULL, NULL, 0}, /* TIP #230 */
{"puts", Tcl_PutsObjCmd, NULL, NULL, 0},
{"read", Tcl_ReadObjCmd, NULL, NULL, 0},
- {"seek", Tcl_SeekObjCmd, TclCompileBasic2Or3ArgCmd, NULL, 0},
- {"tell", Tcl_TellObjCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"truncate", ChanTruncateObjCmd, TclCompileBasic1Or2ArgCmd, NULL, 0}, /* TIP #208 */
+ {"seek", Tcl_SeekObjCmd, NULL, NULL, 0},
+ {"tell", Tcl_TellObjCmd, NULL, NULL, 0},
+ {"truncate", ChanTruncateObjCmd, NULL, NULL, 0}, /* TIP #208 */
{NULL, NULL, NULL, NULL, 0}
};
static const char *const extras[] = {
diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c
index 2351719..a439db9 100644
--- a/generic/tclIndexObj.c
+++ b/generic/tclIndexObj.c
@@ -533,9 +533,9 @@ TclInitPrefixCmd(
Tcl_Interp *interp) /* Current interpreter. */
{
static const EnsembleImplMap prefixImplMap[] = {
- {"all", PrefixAllObjCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"longest", PrefixLongestObjCmd,TclCompileBasic2ArgCmd, NULL, 0},
- {"match", PrefixMatchObjCmd, TclCompileBasicMin2ArgCmd, NULL, 0},
+ {"all", PrefixAllObjCmd, NULL, NULL, 0},
+ {"longest", PrefixLongestObjCmd,NULL, NULL, 0},
+ {"match", PrefixMatchObjCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, 0}
};
Tcl_Command prefixCmd;
diff --git a/generic/tclInt.h b/generic/tclInt.h
index f45746e..b91a718 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -1347,38 +1347,6 @@ typedef struct LiteralTable {
* interpreter's operation in that interpreter.
*/
-#ifdef TCL_COMPILE_STATS
-typedef struct ByteCodeStats {
- long numExecutions; /* Number of ByteCodes executed. */
- long numCompilations; /* Number of ByteCodes created. */
- long numByteCodesFreed; /* Number of ByteCodes destroyed. */
- long instructionCount[256]; /* Number of times each instruction was
- * executed. */
-
- double totalSrcBytes; /* Total source bytes ever compiled. */
- double totalByteCodeBytes; /* Total bytes for all ByteCodes. */
- double currentSrcBytes; /* Src bytes for all current ByteCodes. */
- double currentByteCodeBytes;/* Code bytes in all current ByteCodes. */
-
- long srcCount[32]; /* Source size distribution: # of srcs of
- * size [2**(n-1)..2**n), n in [0..32). */
- long byteCodeCount[32]; /* ByteCode size distribution. */
- long lifetimeCount[32]; /* ByteCode lifetime distribution (ms). */
-
- double currentInstBytes; /* Instruction bytes-current ByteCodes. */
- double currentLitBytes; /* Current literal bytes. */
- double currentExceptBytes; /* Current exception table bytes. */
- double currentAuxBytes; /* Current auxiliary information bytes. */
- double currentCmdMapBytes; /* Current src<->code map bytes. */
-
- long numLiteralsCreated; /* Total literal objects ever compiled. */
- double totalLitStringBytes; /* Total string bytes in all literals. */
- double currentLitStringBytes;
- /* String bytes in current literals. */
- long literalCount[32]; /* Distribution of literal string sizes. */
-} ByteCodeStats;
-#endif /* TCL_COMPILE_STATS */
-
/*
* Structure used in implementation of those core ensembles which are
* partially compiled. Used as an array of these, with a terminating field
@@ -1686,11 +1654,6 @@ typedef struct Interp {
* compiled by the interpreter. Indexed by the
* string representations of literals. Used to
* avoid creating duplicate objects. */
- int compileEpoch; /* Holds the current "compilation epoch" for
- * this interpreter. This is incremented to
- * invalidate existing ByteCodes when, e.g., a
- * command with a compile procedure is
- * redefined. */
Proc *compiledProcPtr; /* If a procedure is being compiled, a pointer
* to its Proc structure; otherwise, this is
* NULL. Set by ObjInterpProc in tclProc.c and
@@ -1869,15 +1832,6 @@ typedef struct Interp {
* over the default error messages returned by
* a script cancellation operation. */
-#ifdef TCL_COMPILE_STATS
- /*
- * Statistical information about the bytecode compiler and interpreter's
- * operation. This should be the last field of Interp.
- */
-
- ByteCodeStats stats; /* Holds compilation and execution statistics
- * for this interpreter. */
-#endif /* TCL_COMPILE_STATS */
Tcl_Obj *cmdSourcePtr; /* Command source obj, used for command traces */
} Interp;
@@ -2442,13 +2396,6 @@ MODULE_SCOPE const Tcl_HashKeyType tclOneWordHashKeyType;
MODULE_SCOPE const Tcl_HashKeyType tclStringHashKeyType;
MODULE_SCOPE const Tcl_HashKeyType tclObjHashKeyType;
-#ifdef TCL_COMPILE_STATS
-MODULE_SCOPE long tclObjsAlloced;
-MODULE_SCOPE long tclObjsFreed;
-#define TCL_MAX_SHARED_OBJ_STATS 5
-MODULE_SCOPE long tclObjsShared[TCL_MAX_SHARED_OBJ_STATS];
-#endif /* TCL_COMPILE_STATS */
-
/*
* Pointer to a heap-allocated string of length zero that the Tcl core uses as
* the value of an empty string representation for an object. This value is
@@ -2782,8 +2729,6 @@ MODULE_SCOPE int TclStringMatch(const char *str, int strLen,
MODULE_SCOPE int TclStringMatchObj(Tcl_Obj *stringObj,
Tcl_Obj *patternObj, int flags);
MODULE_SCOPE Tcl_Obj * TclStringObjReverse(Tcl_Obj *objPtr);
-MODULE_SCOPE void TclSubstCompile(Tcl_Interp *interp, const char *bytes,
- int numBytes, int flags, struct CompileEnv *envPtr);
MODULE_SCOPE int TclSubstOptions(Tcl_Interp *interp, int numOpts,
Tcl_Obj *const opts[], int *flagPtr);
MODULE_SCOPE void TclSubstParse(Tcl_Interp *interp, const char *bytes,
@@ -2814,7 +2759,6 @@ MODULE_SCOPE void TclFinalizeThreadStorage(void);
MODULE_SCOPE Tcl_WideInt TclpGetWideClicks(void);
MODULE_SCOPE double TclpWideClicksToNanoseconds(Tcl_WideInt clicks);
#endif
-MODULE_SCOPE Tcl_Obj * TclDisassembleByteCodeObj(Tcl_Obj *objPtr);
MODULE_SCOPE int TclZlibInit(Tcl_Interp *interp);
MODULE_SCOPE void * TclpThreadCreateKey(void);
MODULE_SCOPE void TclpThreadDeleteKey(void *keyPtr);
@@ -2884,9 +2828,6 @@ MODULE_SCOPE int TclDictWithFinish(Tcl_Interp *interp, Var *varPtr,
Tcl_Obj *const pathv[], Tcl_Obj *keysPtr);
MODULE_SCOPE Tcl_Obj * TclDictWithInit(Tcl_Interp *interp, Tcl_Obj *dictPtr,
int pathc, Tcl_Obj *const pathv[]);
-MODULE_SCOPE int Tcl_DisassembleObjCmd(ClientData clientData,
- Tcl_Interp *interp, int objc,
- Tcl_Obj *const objv[]);
MODULE_SCOPE int Tcl_EncodingObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
@@ -3109,271 +3050,6 @@ MODULE_SCOPE int Tcl_WhileObjCmd(ClientData clientData,
*----------------------------------------------------------------
*/
-MODULE_SCOPE int TclCompileAppendCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileArrayExistsCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileArraySetCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileArrayUnsetCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBreakCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileCatchCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileContinueCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictAppendCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictCreateCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictExistsCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictForCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictGetCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictIncrCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictLappendCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictMapCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictMergeCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictSetCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictUnsetCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictUpdateCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictWithCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileEnsemble(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileErrorCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileExprCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileForCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileForeachCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileFormatCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileGlobalCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileIfCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileInfoCommandsCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileInfoCoroutineCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileInfoExistsCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileInfoLevelCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileInfoObjectClassCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileInfoObjectIsACmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileInfoObjectNamespaceCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileIncrCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileLappendCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileLassignCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileLindexCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileListCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileLlengthCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileLmapCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileLrangeCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileLreplaceCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileLsetCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileNamespaceCodeCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileNamespaceCurrentCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileNamespaceQualifiersCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileNamespaceTailCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileNamespaceUpvarCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileNamespaceWhichCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileNoOp(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileObjectSelfCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileRegexpCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileRegsubCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileReturnCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileSetCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileStringCmpCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileStringEqualCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileStringFirstCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileStringIndexCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileStringLastCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileStringLenCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileStringMapCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileStringMatchCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileStringRangeCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileSubstCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileSwitchCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileTailcallCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileThrowCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileTryCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileUnsetCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileUpvarCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileVariableCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileWhileCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileYieldCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasic0ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasic1ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasic2ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasic3ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasic0Or1ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasic1Or2ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasic2Or3ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasic0To2ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasic1To3ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasicMin0ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasicMin1ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileBasicMin2ArgCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-
MODULE_SCOPE int TclInvertOpCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
@@ -3513,10 +3189,6 @@ MODULE_SCOPE int TclCompileStreqOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileAssembleCmd(Tcl_Interp *interp,
- Tcl_Parse *parsePtr, Command *cmdPtr,
- struct CompileEnv *envPtr);
-
/*
* Functions defined in generic/tclVar.c and currenttly exported only for use
* by the bytecode compiler and engine. Some of these could later be placed in
@@ -3606,15 +3278,8 @@ typedef const char *TclDTraceStr;
#define TCL_DTRACE_OBJ_FREE(objPtr) {}
#endif /* USE_DTRACE */
-#ifdef TCL_COMPILE_STATS
-# define TclIncrObjsAllocated() \
- tclObjsAlloced++
-# define TclIncrObjsFreed() \
- tclObjsFreed++
-#else
# define TclIncrObjsAllocated()
# define TclIncrObjsFreed()
-#endif /* TCL_COMPILE_STATS */
# define TclAllocObjStorage(objPtr) \
(objPtr) = TclSmallAlloc()
diff --git a/generic/tclLiteral.c b/generic/tclLiteral.c
index 441ea91..628a5d8 100644
--- a/generic/tclLiteral.c
+++ b/generic/tclLiteral.c
@@ -15,7 +15,7 @@
*/
#include "tclInt.h"
-#include "tclCompile.h"
+#include "tclCompileInt.h"
/*
* When there are this many entries per bucket, on average, rebuild a
@@ -108,10 +108,6 @@ TclDeleteLiteralTable(
* search from the bucket chain we last found an entry.
*/
-#ifdef TCL_COMPILE_DEBUG
- TclVerifyGlobalLiteralTable((Interp *) interp);
-#endif /*TCL_COMPILE_DEBUG*/
-
/*
* We used to call TclReleaseLiteral for each literal in the table, which
* is rather inefficient as it causes one lookup-by-hash for each
@@ -238,13 +234,6 @@ TclCreateLiteral(
TclInitStringRep(objPtr, bytes, length);
}
-#ifdef TCL_COMPILE_DEBUG
- if (TclLookupLiteralEntry((Tcl_Interp *) iPtr, objPtr) != NULL) {
- Tcl_Panic("%s: literal \"%.*s\" found globally but shouldn't be",
- "TclRegisterLiteral", (length>60? 60 : length), bytes);
- }
-#endif
-
globalPtr = ckalloc(sizeof(LiteralEntry));
globalPtr->objPtr = objPtr;
globalPtr->refCount = 1;
@@ -262,35 +251,6 @@ TclCreateLiteral(
RebuildLiteralTable(globalTablePtr);
}
-#ifdef TCL_COMPILE_DEBUG
- TclVerifyGlobalLiteralTable(iPtr);
- {
- LiteralEntry *entryPtr;
- int found, i;
-
- found = 0;
- for (i=0 ; i<globalTablePtr->numBuckets ; i++) {
- for (entryPtr=globalTablePtr->buckets[i]; entryPtr!=NULL ;
- entryPtr=entryPtr->nextPtr) {
- if ((entryPtr == globalPtr) && (entryPtr->objPtr == objPtr)) {
- found = 1;
- }
- }
- }
- if (!found) {
- Tcl_Panic("%s: literal \"%.*s\" wasn't global",
- "TclRegisterLiteral", (length>60? 60 : length), bytes);
- }
- }
-#endif /*TCL_COMPILE_DEBUG*/
-
-#ifdef TCL_COMPILE_STATS
- iPtr->stats.numLiteralsCreated++;
- iPtr->stats.totalLitStringBytes += (double) (length + 1);
- iPtr->stats.currentLitStringBytes += (double) (length + 1);
- iPtr->stats.literalCount[TclLog2(length)]++;
-#endif /*TCL_COMPILE_STATS*/
-
if (globalPtrPtr) {
*globalPtrPtr = globalPtr;
}
@@ -370,9 +330,6 @@ TclRegisterLiteral(
ckfree(bytes);
}
objIndex = (localPtr - envPtr->literalArrayPtr);
-#ifdef TCL_COMPILE_DEBUG
- TclVerifyLocalLiteralTable(envPtr);
-#endif /*TCL_COMPILE_DEBUG*/
return objIndex;
}
@@ -403,14 +360,6 @@ TclRegisterLiteral(
&globalPtr);
objIndex = AddLocalLiteralEntry(envPtr, objPtr, localHash);
-#ifdef TCL_COMPILE_DEBUG
- if (globalPtr->refCount < 1) {
- Tcl_Panic("%s: global literal \"%.*s\" had bad refCount %d",
- "TclRegisterLiteral", (length>60? 60 : length), bytes,
- globalPtr->refCount);
- }
- TclVerifyLocalLiteralTable(envPtr);
-#endif /*TCL_COMPILE_DEBUG*/
return objIndex;
}
@@ -620,30 +569,6 @@ AddLocalLiteralEntry(
RebuildLiteralTable(localTablePtr);
}
-#ifdef TCL_COMPILE_DEBUG
- TclVerifyLocalLiteralTable(envPtr);
- {
- char *bytes;
- int length, found, i;
-
- found = 0;
- for (i=0 ; i<localTablePtr->numBuckets ; i++) {
- for (localPtr=localTablePtr->buckets[i] ; localPtr!=NULL ;
- localPtr=localPtr->nextPtr) {
- if (localPtr->objPtr == objPtr) {
- found = 1;
- }
- }
- }
-
- if (!found) {
- bytes = Tcl_GetStringFromObj(objPtr, &length);
- Tcl_Panic("%s: literal \"%.*s\" wasn't found locally",
- "AddLocalLiteralEntry", (length>60? 60 : length), bytes);
- }
- }
-#endif /*TCL_COMPILE_DEBUG*/
-
return objIndex;
}
@@ -786,9 +711,6 @@ TclReleaseLiteral(
TclDecrRefCount(objPtr);
-#ifdef TCL_COMPILE_STATS
- iPtr->stats.currentLitStringBytes -= (double) (length + 1);
-#endif /*TCL_COMPILE_STATS*/
}
break;
}
@@ -976,192 +898,6 @@ TclInvalidateCmdLiteral(
}
}
-#ifdef TCL_COMPILE_STATS
-/*
- *----------------------------------------------------------------------
- *
- * TclLiteralStats --
- *
- * Return statistics describing the layout of the hash table in its hash
- * buckets.
- *
- * Results:
- * The return value is a malloc-ed string containing information about
- * tablePtr. It is the caller's responsibility to free this string.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-char *
-TclLiteralStats(
- LiteralTable *tablePtr) /* Table for which to produce stats. */
-{
-#define NUM_COUNTERS 10
- int count[NUM_COUNTERS], overflow, i, j;
- double average, tmp;
- register LiteralEntry *entryPtr;
- char *result, *p;
-
- /*
- * Compute a histogram of bucket usage. For each bucket chain i, j is the
- * number of entries in the chain.
- */
-
- for (i=0 ; i<NUM_COUNTERS ; i++) {
- count[i] = 0;
- }
- overflow = 0;
- average = 0.0;
- for (i=0 ; i<tablePtr->numBuckets ; i++) {
- j = 0;
- for (entryPtr=tablePtr->buckets[i] ; entryPtr!=NULL;
- entryPtr=entryPtr->nextPtr) {
- j++;
- }
- if (j < NUM_COUNTERS) {
- count[j]++;
- } else {
- overflow++;
- }
- tmp = j;
- average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;
- }
-
- /*
- * Print out the histogram and a few other pieces of information.
- */
-
- result = ckalloc(NUM_COUNTERS*60 + 300);
- sprintf(result, "%d entries in table, %d buckets\n",
- tablePtr->numEntries, tablePtr->numBuckets);
- p = result + strlen(result);
- for (i=0 ; i<NUM_COUNTERS ; i++) {
- sprintf(p, "number of buckets with %d entries: %d\n",
- i, count[i]);
- p += strlen(p);
- }
- sprintf(p, "number of buckets with %d or more entries: %d\n",
- NUM_COUNTERS, overflow);
- p += strlen(p);
- sprintf(p, "average search distance for entry: %.1f", average);
- return result;
-}
-#endif /*TCL_COMPILE_STATS*/
-
-#ifdef TCL_COMPILE_DEBUG
-/*
- *----------------------------------------------------------------------
- *
- * TclVerifyLocalLiteralTable --
- *
- * Check a CompileEnv's local literal table for consistency.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Tcl_Panic if problems are found.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclVerifyLocalLiteralTable(
- CompileEnv *envPtr) /* Points to CompileEnv whose literal table is
- * to be validated. */
-{
- register LiteralTable *localTablePtr = &envPtr->localLitTable;
- register LiteralEntry *localPtr;
- char *bytes;
- register int i;
- int length, count;
-
- count = 0;
- for (i=0 ; i<localTablePtr->numBuckets ; i++) {
- for (localPtr=localTablePtr->buckets[i] ; localPtr!=NULL;
- localPtr=localPtr->nextPtr) {
- count++;
- if (localPtr->refCount != -1) {
- bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length);
- Tcl_Panic("%s: local literal \"%.*s\" had bad refCount %d",
- "TclVerifyLocalLiteralTable",
- (length>60? 60 : length), bytes, localPtr->refCount);
- }
- if (TclLookupLiteralEntry((Tcl_Interp *) envPtr->iPtr,
- localPtr->objPtr) == NULL) {
- bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length);
- Tcl_Panic("%s: local literal \"%.*s\" is not global",
- "TclVerifyLocalLiteralTable",
- (length>60? 60 : length), bytes);
- }
- if (localPtr->objPtr->bytes == NULL) {
- Tcl_Panic("%s: literal has NULL string rep",
- "TclVerifyLocalLiteralTable");
- }
- }
- }
- if (count != localTablePtr->numEntries) {
- Tcl_Panic("%s: local literal table had %d entries, should be %d",
- "TclVerifyLocalLiteralTable", count,
- localTablePtr->numEntries);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclVerifyGlobalLiteralTable --
- *
- * Check an interpreter's global literal table literal for consistency.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Tcl_Panic if problems are found.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclVerifyGlobalLiteralTable(
- Interp *iPtr) /* Points to interpreter whose global literal
- * table is to be validated. */
-{
- register LiteralTable *globalTablePtr = &iPtr->literalTable;
- register LiteralEntry *globalPtr;
- char *bytes;
- register int i;
- int length, count;
-
- count = 0;
- for (i=0 ; i<globalTablePtr->numBuckets ; i++) {
- for (globalPtr=globalTablePtr->buckets[i] ; globalPtr!=NULL;
- globalPtr=globalPtr->nextPtr) {
- count++;
- if (globalPtr->refCount < 1) {
- bytes = Tcl_GetStringFromObj(globalPtr->objPtr, &length);
- Tcl_Panic("%s: global literal \"%.*s\" had bad refCount %d",
- "TclVerifyGlobalLiteralTable",
- (length>60? 60 : length), bytes, globalPtr->refCount);
- }
- if (globalPtr->objPtr->bytes == NULL) {
- Tcl_Panic("%s: literal has NULL string rep",
- "TclVerifyGlobalLiteralTable");
- }
- }
- }
- if (count != globalTablePtr->numEntries) {
- Tcl_Panic("%s: global literal table had %d entries, should be %d",
- "TclVerifyGlobalLiteralTable", count,
- globalTablePtr->numEntries);
- }
-}
-#endif /*TCL_COMPILE_DEBUG*/
-
/*
* Local Variables:
* mode: c
diff --git a/generic/tclNRE.h b/generic/tclNRE.h
index d740105..9c99f19 100644
--- a/generic/tclNRE.h
+++ b/generic/tclNRE.h
@@ -3,7 +3,11 @@
* **********************************************
*/
+#ifdef TCL_NRE_DEBUG
+#define NRE_STACK_DEBUG 1
+#else
#define NRE_STACK_DEBUG 0
+#endif
#define NRE_STACK_SIZE 100
diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c
index 0ccf02e..14408c9 100644
--- a/generic/tclNamesp.c
+++ b/generic/tclNamesp.c
@@ -154,25 +154,25 @@ static const Tcl_ObjType nsNameType = {
*/
static const EnsembleImplMap defaultNamespaceMap[] = {
- {"children", NamespaceChildrenCmd, TclCompileBasic0To2ArgCmd, NULL, 0},
- {"code", NamespaceCodeCmd, TclCompileNamespaceCodeCmd, NULL, 0},
- {"current", NamespaceCurrentCmd, TclCompileNamespaceCurrentCmd, NULL, 0},
- {"delete", NamespaceDeleteCmd, TclCompileBasicMin0ArgCmd, NULL, 0},
+ {"children", NamespaceChildrenCmd, NULL, NULL, 0},
+ {"code", NamespaceCodeCmd, NULL, NULL, 0},
+ {"current", NamespaceCurrentCmd, NULL, NULL, 0},
+ {"delete", NamespaceDeleteCmd, NULL, NULL, 0},
{"ensemble", TclNamespaceEnsembleCmd, NULL, NULL, 0},
{"eval", NamespaceEvalCmd, NULL, NULL, 0},
- {"exists", NamespaceExistsCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"export", NamespaceExportCmd, TclCompileBasicMin0ArgCmd, NULL, 0},
- {"forget", NamespaceForgetCmd, TclCompileBasicMin0ArgCmd, NULL, 0},
- {"import", NamespaceImportCmd, TclCompileBasicMin0ArgCmd, NULL, 0},
+ {"exists", NamespaceExistsCmd, NULL, NULL, 0},
+ {"export", NamespaceExportCmd, NULL, NULL, 0},
+ {"forget", NamespaceForgetCmd, NULL, NULL, 0},
+ {"import", NamespaceImportCmd, NULL, NULL, 0},
{"inscope", NamespaceInscopeCmd, NULL, NULL, 0},
- {"origin", NamespaceOriginCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"parent", NamespaceParentCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"path", NamespacePathCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"qualifiers", NamespaceQualifiersCmd, TclCompileNamespaceQualifiersCmd, NULL, 0},
- {"tail", NamespaceTailCmd, TclCompileNamespaceTailCmd, NULL, 0},
- {"unknown", NamespaceUnknownCmd, TclCompileBasic0Or1ArgCmd, NULL, 0},
- {"upvar", NamespaceUpvarCmd, TclCompileNamespaceUpvarCmd, NULL, 0},
- {"which", NamespaceWhichCmd, TclCompileNamespaceWhichCmd, NULL, 0},
+ {"origin", NamespaceOriginCmd, NULL, NULL, 0},
+ {"parent", NamespaceParentCmd, NULL, NULL, 0},
+ {"path", NamespacePathCmd, NULL, NULL, 0},
+ {"qualifiers", NamespaceQualifiersCmd, NULL, NULL, 0},
+ {"tail", NamespaceTailCmd, NULL, NULL, 0},
+ {"unknown", NamespaceUnknownCmd, NULL, NULL, 0},
+ {"upvar", NamespaceUpvarCmd, NULL, NULL, 0},
+ {"which", NamespaceWhichCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, 0}
};
diff --git a/generic/tclOO.c b/generic/tclOO.c
index 21ef402..cbdd2dc 100644
--- a/generic/tclOO.c
+++ b/generic/tclOO.c
@@ -308,7 +308,6 @@ InitFoundation(
Foundation *fPtr = ckalloc(sizeof(Foundation));
Tcl_Obj *namePtr, *argsPtr, *bodyPtr;
Tcl_DString buffer;
- Command *cmdPtr;
int i;
/*
@@ -435,9 +434,8 @@ InitFoundation(
NULL);
Tcl_CreateObjCommand(interp, "::oo::Helpers::nextto", TclOONextToObjCmd,
NULL, NULL);
- cmdPtr = (Command *) Tcl_CreateObjCommand(interp, "::oo::Helpers::self",
+ Tcl_CreateObjCommand(interp, "::oo::Helpers::self",
TclOOSelfObjCmd, NULL, NULL);
- cmdPtr->compileProc = TclCompileObjectSelfCmd;
Tcl_CreateObjCommand(interp, "::oo::define", TclOODefineObjCmd, NULL,
NULL);
Tcl_CreateObjCommand(interp, "::oo::objdefine", TclOOObjDefObjCmd, NULL,
diff --git a/generic/tclOOInfo.c b/generic/tclOOInfo.c
index 54e3e0a..25ca79b 100644
--- a/generic/tclOOInfo.c
+++ b/generic/tclOOInfo.c
@@ -48,18 +48,18 @@ static Tcl_ObjCmdProc InfoClassVariablesCmd;
*/
static const EnsembleImplMap infoObjectCmds[] = {
- {"call", InfoObjectCallCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"class", InfoObjectClassCmd, TclCompileInfoObjectClassCmd, NULL, 0},
- {"definition", InfoObjectDefnCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"filters", InfoObjectFiltersCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"forward", InfoObjectForwardCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"isa", InfoObjectIsACmd, TclCompileInfoObjectIsACmd, NULL, 0},
- {"methods", InfoObjectMethodsCmd, TclCompileBasicMin1ArgCmd, NULL, 0},
- {"methodtype", InfoObjectMethodTypeCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"mixins", InfoObjectMixinsCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"namespace", InfoObjectNsCmd, TclCompileInfoObjectNamespaceCmd, NULL, 0},
- {"variables", InfoObjectVariablesCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"vars", InfoObjectVarsCmd, TclCompileBasic1Or2ArgCmd, NULL, 0},
+ {"call", InfoObjectCallCmd, NULL, NULL, 0},
+ {"class", InfoObjectClassCmd, NULL, NULL, 0},
+ {"definition", InfoObjectDefnCmd, NULL, NULL, 0},
+ {"filters", InfoObjectFiltersCmd, NULL, NULL, 0},
+ {"forward", InfoObjectForwardCmd, NULL, NULL, 0},
+ {"isa", InfoObjectIsACmd, NULL, NULL, 0},
+ {"methods", InfoObjectMethodsCmd, NULL, NULL, 0},
+ {"methodtype", InfoObjectMethodTypeCmd, NULL, NULL, 0},
+ {"mixins", InfoObjectMixinsCmd, NULL, NULL, 0},
+ {"namespace", InfoObjectNsCmd, NULL, NULL, 0},
+ {"variables", InfoObjectVariablesCmd, NULL, NULL, 0},
+ {"vars", InfoObjectVarsCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, 0}
};
@@ -68,19 +68,19 @@ static const EnsembleImplMap infoObjectCmds[] = {
*/
static const EnsembleImplMap infoClassCmds[] = {
- {"call", InfoClassCallCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"constructor", InfoClassConstrCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"definition", InfoClassDefnCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"destructor", InfoClassDestrCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"filters", InfoClassFiltersCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"forward", InfoClassForwardCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"instances", InfoClassInstancesCmd, TclCompileBasic1Or2ArgCmd, NULL, 0},
- {"methods", InfoClassMethodsCmd, TclCompileBasicMin1ArgCmd, NULL, 0},
- {"methodtype", InfoClassMethodTypeCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"mixins", InfoClassMixinsCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"subclasses", InfoClassSubsCmd, TclCompileBasic1Or2ArgCmd, NULL, 0},
- {"superclasses", InfoClassSupersCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"variables", InfoClassVariablesCmd, TclCompileBasic1ArgCmd, NULL, 0},
+ {"call", InfoClassCallCmd, NULL, NULL, 0},
+ {"constructor", InfoClassConstrCmd, NULL, NULL, 0},
+ {"definition", InfoClassDefnCmd, NULL, NULL, 0},
+ {"destructor", InfoClassDestrCmd, NULL, NULL, 0},
+ {"filters", InfoClassFiltersCmd, NULL, NULL, 0},
+ {"forward", InfoClassForwardCmd, NULL, NULL, 0},
+ {"instances", InfoClassInstancesCmd, NULL, NULL, 0},
+ {"methods", InfoClassMethodsCmd, NULL, NULL, 0},
+ {"methodtype", InfoClassMethodTypeCmd, NULL, NULL, 0},
+ {"mixins", InfoClassMixinsCmd, NULL, NULL, 0},
+ {"subclasses", InfoClassSubsCmd, NULL, NULL, 0},
+ {"superclasses", InfoClassSupersCmd, NULL, NULL, 0},
+ {"variables", InfoClassVariablesCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, 0}
};
diff --git a/generic/tclOOMethod.c b/generic/tclOOMethod.c
index 45a3ede..5cc78c7 100644
--- a/generic/tclOOMethod.c
+++ b/generic/tclOOMethod.c
@@ -14,7 +14,7 @@
#endif
#include "tclInt.h"
#include "tclOOInt.h"
-#include "tclCompile.h"
+#include "tclCompileInt.h"
/*
* Structure used to contain all the information needed about a call frame
diff --git a/generic/tclObj.c b/generic/tclObj.c
index d4769fa..34f1387 100644
--- a/generic/tclObj.c
+++ b/generic/tclObj.c
@@ -3356,20 +3356,6 @@ Tcl_DbIsShared(
# endif /* TCL_THREADS */
#endif /* TCL_MEM_DEBUG */
-#if 0
- // FIXME: reenable
-#ifdef TCL_COMPILE_STATS
- Tcl_MutexLock(&tclObjMutex);
- if ((objPtr)->refCount <= 1) {
- tclObjsShared[1]++;
- } else if ((objPtr)->refCount < TCL_MAX_SHARED_OBJ_STATS) {
- tclObjsShared[(objPtr)->refCount]++;
- } else {
- tclObjsShared[0]++;
- }
- Tcl_MutexUnlock(&tclObjMutex);
-#endif /* TCL_COMPILE_STATS */
-#endif
return ((objPtr)->refCount > 1);
}
diff --git a/generic/tclParse.c b/generic/tclParse.c
index f8b0946..a9bc2ad 100644
--- a/generic/tclParse.c
+++ b/generic/tclParse.c
@@ -2082,6 +2082,254 @@ TclSubstParse(
/*
*----------------------------------------------------------------------
*
+ * Tcl_SubstObj --
+ *
+ * This function performs the substitutions specified on the given string
+ * as described in the user documentation for the "subst" Tcl command.
+ *
+ * Results:
+ * A Tcl_Obj* containing the substituted string, or NULL to indicate that
+ * an error occurred.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_Obj *
+Tcl_SubstObj(
+ Tcl_Interp *interp, /* Interpreter in which substitution occurs */
+ Tcl_Obj *objPtr, /* The value to be substituted. */
+ int flags) /* What substitutions to do. */
+{
+ int length, tokensLeft, code;
+ Tcl_Token *endTokenPtr;
+ Tcl_Obj *result, *errMsg = NULL;
+ const char *p = TclGetStringFromObj(objPtr, &length);
+ Tcl_Parse *parsePtr = (Tcl_Parse *) ckalloc(sizeof(Tcl_Parse));
+
+ TclParseInit(interp, p, length, parsePtr);
+
+ /*
+ * First parse the string rep of objPtr, as if it were enclosed as a
+ * "-quoted word in a normal Tcl command. Honor flags that selectively
+ * inhibit types of substitution.
+ */
+
+ if (TCL_OK != ParseTokens(p, length, /* mask */ 0, flags, parsePtr)) {
+ /*
+ * There was a parse error. Save the error message for possible
+ * reporting later.
+ */
+
+ errMsg = Tcl_GetObjResult(interp);
+ Tcl_IncrRefCount(errMsg);
+
+ /*
+ * We need to re-parse to get the portion of the string we can [subst]
+ * before the parse error. Sadly, all the Tcl_Token's created by the
+ * first parse attempt are gone, freed according to the public spec
+ * for the Tcl_Parse* routines. The only clue we have is parse.term,
+ * which points to either the unmatched opener, or to characters that
+ * follow a close brace or close quote.
+ *
+ * Call ParseTokens again, working on the string up to parse.term.
+ * Keep repeating until we get a good parse on a prefix.
+ */
+
+ do {
+ parsePtr->numTokens = 0;
+ parsePtr->tokensAvailable = NUM_STATIC_TOKENS;
+ parsePtr->end = parsePtr->term;
+ parsePtr->incomplete = 0;
+ parsePtr->errorType = TCL_PARSE_SUCCESS;
+ } while (TCL_OK !=
+ ParseTokens(p, parsePtr->end - p, 0, flags, parsePtr));
+
+ /*
+ * The good parse will have to be followed by {, (, or [.
+ */
+
+ switch (*(parsePtr->term)) {
+ case '{':
+ /*
+ * Parse error was a missing } in a ${varname} variable
+ * substitution at the toplevel. We will subst everything up to
+ * that broken variable substitution before reporting the parse
+ * error. Substituting the leftover '$' will have no side-effects,
+ * so the current token stream is fine.
+ */
+ break;
+
+ case '(':
+ /*
+ * Parse error was during the parsing of the index part of an
+ * array variable substitution at the toplevel.
+ */
+
+ if (*(parsePtr->term - 1) == '$') {
+ /*
+ * Special case where removing the array index left us with
+ * just a dollar sign (array variable with name the empty
+ * string as its name), instead of with a scalar variable
+ * reference.
+ *
+ * As in the previous case, existing token stream is OK.
+ */
+ } else {
+ /*
+ * The current parse includes a successful parse of a scalar
+ * variable substitution where there should have been an array
+ * variable substitution. We remove that mistaken part of the
+ * parse before moving on. A scalar variable substitution is
+ * two tokens.
+ */
+
+ Tcl_Token *varTokenPtr =
+ parsePtr->tokenPtr + parsePtr->numTokens - 2;
+
+ if (varTokenPtr->type != TCL_TOKEN_VARIABLE) {
+ Tcl_Panic("Tcl_SubstObj: programming error");
+ }
+ if (varTokenPtr[1].type != TCL_TOKEN_TEXT) {
+ Tcl_Panic("Tcl_SubstObj: programming error");
+ }
+ parsePtr->numTokens -= 2;
+ }
+ break;
+ case '[':
+ /*
+ * Parse error occurred during parsing of a toplevel command
+ * substitution.
+ */
+
+ parsePtr->end = p + length;
+ p = parsePtr->term + 1;
+ length = parsePtr->end - p;
+ if (length == 0) {
+ /*
+ * No commands, just an unmatched [. As in previous cases,
+ * existing token stream is OK.
+ */
+ } else {
+ /*
+ * We want to add the parsing of as many commands as we can
+ * within that substitution until we reach the actual parse
+ * error. We'll do additional parsing to determine what length
+ * to claim for the final TCL_TOKEN_COMMAND token.
+ */
+
+ Tcl_Token *tokenPtr;
+ const char *lastTerm = parsePtr->term;
+ Tcl_Parse *nestedPtr = (Tcl_Parse *)
+ ckalloc(sizeof(Tcl_Parse));
+
+ while (TCL_OK ==
+ Tcl_ParseCommand(NULL, p, length, 0, nestedPtr)) {
+ Tcl_FreeParse(nestedPtr);
+ p = nestedPtr->term + (nestedPtr->term < nestedPtr->end);
+ length = nestedPtr->end - p;
+ if ((length == 0) && (nestedPtr->term == nestedPtr->end)) {
+ /*
+ * If we run out of string, blame the missing close
+ * bracket on the last command, and do not evaluate it
+ * during substitution.
+ */
+
+ break;
+ }
+ lastTerm = nestedPtr->term;
+ }
+ ckfree(nestedPtr);
+
+ if (lastTerm == parsePtr->term) {
+ /*
+ * Parse error in first command. No commands to subst, add
+ * no more tokens.
+ */
+ break;
+ }
+
+ /*
+ * Create a command substitution token for whatever commands
+ * got parsed.
+ */
+
+ TclGrowParseTokenArray(parsePtr, 1);
+ tokenPtr = &(parsePtr->tokenPtr[parsePtr->numTokens]);
+ tokenPtr->start = parsePtr->term;
+ tokenPtr->numComponents = 0;
+ tokenPtr->type = TCL_TOKEN_COMMAND;
+ tokenPtr->size = lastTerm - tokenPtr->start + 1;
+ parsePtr->numTokens++;
+ }
+ break;
+
+ default:
+ Tcl_Panic("bad parse in Tcl_SubstObj: %c", p[length]);
+ }
+ }
+
+ /*
+ * Next, substitute the parsed tokens just as in normal Tcl evaluation.
+ */
+
+ endTokenPtr = parsePtr->tokenPtr + parsePtr->numTokens;
+ tokensLeft = parsePtr->numTokens;
+ code = TclSubstTokens(interp, endTokenPtr - tokensLeft, tokensLeft,
+ &tokensLeft);
+ if (code == TCL_OK) {
+ Tcl_FreeParse(parsePtr);
+ ckfree(parsePtr);
+ if (errMsg != NULL) {
+ Tcl_SetObjResult(interp, errMsg);
+ Tcl_DecrRefCount(errMsg);
+ return NULL;
+ }
+ return Tcl_GetObjResult(interp);
+ }
+
+ result = Tcl_NewObj();
+ while (1) {
+ switch (code) {
+ case TCL_ERROR:
+ Tcl_FreeParse(parsePtr);
+ ckfree(parsePtr);
+ Tcl_DecrRefCount(result);
+ if (errMsg != NULL) {
+ Tcl_DecrRefCount(errMsg);
+ }
+ return NULL;
+ case TCL_BREAK:
+ tokensLeft = 0; /* Halt substitution */
+ default:
+ Tcl_AppendObjToObj(result, Tcl_GetObjResult(interp));
+ }
+
+ if (tokensLeft == 0) {
+ Tcl_FreeParse(parsePtr);
+ ckfree(parsePtr);
+ if (errMsg != NULL) {
+ if (code != TCL_BREAK) {
+ Tcl_DecrRefCount(result);
+ Tcl_SetObjResult(interp, errMsg);
+ Tcl_DecrRefCount(errMsg);
+ return NULL;
+ }
+ Tcl_DecrRefCount(errMsg);
+ }
+ return result;
+ }
+
+ code = TclSubstTokens(interp, endTokenPtr - tokensLeft, tokensLeft,
+ &tokensLeft);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclSubstTokens --
*
* Accepts an array of count Tcl_Token's, and creates a result value in
diff --git a/generic/tclProc.c b/generic/tclProc.c
index 27c5262..c949086 100644
--- a/generic/tclProc.c
+++ b/generic/tclProc.c
@@ -14,7 +14,7 @@
*/
#include "tclInt.h"
-#include "tclCompile.h"
+#include "tclCompileInt.h"
#include "tclOOInt.h"
/*
@@ -130,7 +130,7 @@ Tcl_ProcObjCmd(
register Interp *iPtr = (Interp *) interp;
Proc *procPtr;
const char *fullName;
- const char *procName, *procArgs, *procBody;
+ const char *procName;
Namespace *nsPtr, *altNsPtr, *cxtNsPtr;
Tcl_Command cmd;
Tcl_DString ds;
@@ -211,61 +211,6 @@ Tcl_ProcObjCmd(
*/
procPtr->cmdPtr = (Command *) cmd;
-
- /*
- * Optimize for no-op procs: if the body is not precompiled (like a TclPro
- * procbody), and the argument list is just "args" and the body is empty,
- * define a compileProc to compile a no-op.
- *
- * Notes:
- * - cannot be done for any argument list without having different
- * compiled/not-compiled behaviour in the "wrong argument #" case, or
- * making this code much more complicated. In any case, it doesn't
- * seem to make a lot of sense to verify the number of arguments we
- * are about to ignore ...
- * - could be enhanced to handle also non-empty bodies that contain only
- * comments; however, parsing the body will slow down the compilation
- * of all procs whose argument list is just _args_
- */
-
- if (objv[3]->typePtr == &tclProcBodyType) {
- goto done;
- }
-
- procArgs = TclGetString(objv[2]);
-
- while (*procArgs == ' ') {
- procArgs++;
- }
-
- if ((procArgs[0] == 'a') && (strncmp(procArgs, "args", 4) == 0)) {
- int numBytes;
-
- procArgs +=4;
- while (*procArgs != '\0') {
- if (*procArgs != ' ') {
- goto done;
- }
- procArgs++;
- }
-
- /*
- * The argument list is just "args"; check the body
- */
-
- procBody = Tcl_GetStringFromObj(objv[3], &numBytes);
- if (TclParseAllWhiteSpace(procBody, numBytes) < numBytes) {
- goto done;
- }
-
- /*
- * The body is just spaces: link the compileProc
- */
-
- ((Command *) cmd)->compileProc = TclCompileNoOp;
- }
-
- done:
return TCL_OK;
}
@@ -1509,7 +1454,6 @@ PushProcCallFrame(
codePtr = procPtr->bodyPtr->internalRep.otherValuePtr;
if (((Interp *) *codePtr->interpHandle != iPtr)
- || (codePtr->compileEpoch != iPtr->compileEpoch)
|| (codePtr->nsPtr != nsPtr)
|| (codePtr->nsEpoch != nsPtr->resolverEpoch)) {
goto doCompilation;
@@ -1627,56 +1571,6 @@ TclNRInterpProcCore(
return TCL_ERROR;
}
-#if defined(TCL_COMPILE_DEBUG)
- if (tclTraceExec >= 1) {
- register CallFrame *framePtr = iPtr->varFramePtr;
- register int i;
-
- if (framePtr->isProcCallFrame & FRAME_IS_LAMBDA) {
- fprintf(stdout, "Calling lambda ");
- } else {
- fprintf(stdout, "Calling proc ");
- }
- for (i = 0; i < framePtr->objc; i++) {
- TclPrintObject(stdout, framePtr->objv[i], 15);
- fprintf(stdout, " ");
- }
- fprintf(stdout, "\n");
- fflush(stdout);
- }
-#endif /*TCL_COMPILE_DEBUG*/
-
-#ifdef USE_DTRACE
- if (TCL_DTRACE_PROC_ARGS_ENABLED()) {
- int l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
- const char *a[10];
- int i;
-
- for (i = 0 ; i < 10 ; i++) {
- a[i] = (l < iPtr->varFramePtr->objc ?
- TclGetString(iPtr->varFramePtr->objv[l]) : NULL);
- l++;
- }
- TCL_DTRACE_PROC_ARGS(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
- a[8], a[9]);
- }
- if (TCL_DTRACE_PROC_ENTRY_ENABLED()) {
- int l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
-
- TCL_DTRACE_PROC_ENTRY(l < iPtr->varFramePtr->objc ?
- TclGetString(iPtr->varFramePtr->objv[l]) : NULL,
- iPtr->varFramePtr->objc - l - 1,
- (Tcl_Obj **)(iPtr->varFramePtr->objv + l + 1));
- }
- if (TCL_DTRACE_PROC_ENTRY_ENABLED()) {
- int l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
-
- TCL_DTRACE_PROC_ENTRY(l < iPtr->varFramePtr->objc ?
- TclGetString(iPtr->varFramePtr->objv[l]) : NULL,
- iPtr->varFramePtr->objc - l - 1,
- (Tcl_Obj **)(iPtr->varFramePtr->objv + l + 1));
- }
-#endif /* USE_DTRACE */
/*
* Invoke the commands in the procedure's body.
@@ -1843,7 +1737,6 @@ TclProcCompileProc(
if (bodyPtr->typePtr == &tclByteCodeType) {
if (((Interp *) *codePtr->interpHandle == iPtr)
- && (codePtr->compileEpoch == iPtr->compileEpoch)
&& (codePtr->nsPtr == nsPtr)
&& (codePtr->nsEpoch == nsPtr->resolverEpoch)) {
return TCL_OK;
@@ -1857,7 +1750,6 @@ TclProcCompileProc(
"CROSSINTERPBYTECODE", NULL);
return TCL_ERROR;
}
- codePtr->compileEpoch = iPtr->compileEpoch;
codePtr->nsPtr = nsPtr;
} else {
TclFreeIntRep(bodyPtr);
@@ -1865,24 +1757,6 @@ TclProcCompileProc(
}
if (bodyPtr->typePtr != &tclByteCodeType) {
-#ifdef TCL_COMPILE_DEBUG
- if (tclTraceCompile >= 1) {
- /*
- * Display a line summarizing the top level command we are about
- * to compile.
- */
-
- Tcl_Obj *message;
-
- TclNewLiteralStringObj(message, "Compiling ");
- Tcl_IncrRefCount(message);
- Tcl_AppendStringsToObj(message, description, " \"", NULL);
- Tcl_AppendLimitedToObj(message, procName, -1, 50, NULL);
- fprintf(stdout, "%s\"\n", TclGetString(message));
- Tcl_DecrRefCount(message);
- }
-#endif
-
/*
* Plug the current procPtr into the interpreter and coerce the code
* body to byte codes. The interpreter needs to know which proc it's
@@ -2533,235 +2407,6 @@ MakeLambdaError(
}
/*
- *----------------------------------------------------------------------
- *
- * Tcl_DisassembleObjCmd --
- *
- * Implementation of the "::tcl::unsupported::disassemble" command. This
- * command is not documented, but will disassemble procedures, lambda
- * terms and general scripts. Note that will compile terms if necessary
- * in order to disassemble them.
- *
- *----------------------------------------------------------------------
- */
-
-int
-Tcl_DisassembleObjCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- static const char *const types[] = {
- "lambda", "method", "objmethod", "proc", "script", NULL
- };
- enum Types {
- DISAS_LAMBDA, DISAS_CLASS_METHOD, DISAS_OBJECT_METHOD, DISAS_PROC,
- DISAS_SCRIPT
- };
- int idx, result;
- Tcl_Obj *codeObjPtr = NULL;
- Proc *procPtr = NULL;
- Tcl_HashEntry *hPtr;
- Object *oPtr;
-
- if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "type ...");
- return TCL_ERROR;
- }
- if (Tcl_GetIndexFromObj(interp, objv[1], types, "type", 0, &idx)!=TCL_OK){
- return TCL_ERROR;
- }
-
- switch ((enum Types) idx) {
- case DISAS_LAMBDA: {
- Command cmd;
- Tcl_Obj *nsObjPtr;
- Tcl_Namespace *nsPtr;
-
- /*
- * Compile (if uncompiled) and disassemble a lambda term.
- */
-
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "lambdaTerm");
- return TCL_ERROR;
- }
- if (objv[2]->typePtr == &lambdaType) {
- procPtr = objv[2]->internalRep.twoPtrValue.ptr1;
- }
- if (procPtr == NULL || procPtr->iPtr != (Interp *) interp) {
- result = SetLambdaFromAny(interp, objv[2]);
- if (result != TCL_OK) {
- return result;
- }
- procPtr = objv[2]->internalRep.twoPtrValue.ptr1;
- }
-
- memset(&cmd, 0, sizeof(Command));
- nsObjPtr = objv[2]->internalRep.twoPtrValue.ptr2;
- result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr);
- if (result != TCL_OK) {
- return result;
- }
- cmd.nsPtr = (Namespace *) nsPtr;
- procPtr->cmdPtr = &cmd;
- result = PushProcCallFrame(procPtr, interp, objc, objv, 1);
- if (result != TCL_OK) {
- return result;
- }
- TclPopStackFrame(interp);
- codeObjPtr = procPtr->bodyPtr;
- break;
- }
- case DISAS_PROC:
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "procName");
- return TCL_ERROR;
- }
-
- procPtr = TclFindProc((Interp *) interp, TclGetString(objv[2]));
- if (procPtr == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "\"%s\" isn't a procedure", TclGetString(objv[2])));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "PROC",
- TclGetString(objv[2]), NULL);
- return TCL_ERROR;
- }
-
- /*
- * Compile (if uncompiled) and disassemble a procedure.
- */
-
- result = PushProcCallFrame(procPtr, interp, 2, objv+1, 1);
- if (result != TCL_OK) {
- return result;
- }
- TclPopStackFrame(interp);
- codeObjPtr = procPtr->bodyPtr;
- break;
- case DISAS_SCRIPT:
- /*
- * Compile and disassemble a script.
- */
-
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "script");
- return TCL_ERROR;
- }
- if (objv[2]->typePtr != &tclByteCodeType) {
- if (TclSetByteCodeFromAny(interp, objv[2], NULL, NULL) != TCL_OK){
- return TCL_ERROR;
- }
- }
- codeObjPtr = objv[2];
- break;
-
- case DISAS_CLASS_METHOD:
- if (objc != 4) {
- Tcl_WrongNumArgs(interp, 2, objv, "className methodName");
- return TCL_ERROR;
- }
-
- /*
- * Look up the body of a class method.
- */
-
- oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[2]);
- if (oPtr == NULL) {
- return TCL_ERROR;
- }
- if (oPtr->classPtr == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "\"%s\" is not a class", TclGetString(objv[2])));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS",
- TclGetString(objv[2]), NULL);
- return TCL_ERROR;
- }
- hPtr = Tcl_FindHashEntry(&oPtr->classPtr->classMethods,
- (char *) objv[3]);
- goto methodBody;
- case DISAS_OBJECT_METHOD:
- if (objc != 4) {
- Tcl_WrongNumArgs(interp, 2, objv, "objectName methodName");
- return TCL_ERROR;
- }
-
- /*
- * Look up the body of an instance method.
- */
-
- oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[2]);
- if (oPtr == NULL) {
- return TCL_ERROR;
- }
- if (oPtr->methodsPtr == NULL) {
- goto unknownMethod;
- }
- hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, (char *) objv[3]);
-
- /*
- * Compile (if necessary) and disassemble a method body.
- */
-
- methodBody:
- if (hPtr == NULL) {
- unknownMethod:
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "unknown method \"%s\"", TclGetString(objv[3])));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
- TclGetString(objv[3]), NULL);
- return TCL_ERROR;
- }
- procPtr = TclOOGetProcFromMethod(Tcl_GetHashValue(hPtr));
- if (procPtr == NULL) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "body not available for this kind of method", -1));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE",
- "METHODTYPE", NULL);
- return TCL_ERROR;
- }
- if (procPtr->bodyPtr->typePtr != &tclByteCodeType) {
- Command cmd;
-
- /*
- * Yes, this is ugly, but we need to pass the namespace in to the
- * compiler in two places.
- */
-
- cmd.nsPtr = (Namespace *) oPtr->namespacePtr;
- procPtr->cmdPtr = &cmd;
- result = TclProcCompileProc(interp, procPtr, procPtr->bodyPtr,
- (Namespace *) oPtr->namespacePtr, "body of method",
- TclGetString(objv[3]));
- procPtr->cmdPtr = NULL;
- if (result != TCL_OK) {
- return result;
- }
- }
- codeObjPtr = procPtr->bodyPtr;
- break;
- default:
- CLANG_ASSERT(0);
- }
-
- /*
- * Do the actual disassembly.
- */
-
- if (((ByteCode *) codeObjPtr->internalRep.otherValuePtr)->flags
- & TCL_BYTECODE_PRECOMPILED) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "may not disassemble prebuilt bytecode", -1));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE",
- "BYTECODE", NULL);
- return TCL_ERROR;
- }
- Tcl_SetObjResult(interp, TclDisassembleByteCodeObj(codeObjPtr));
- return TCL_OK;
-}
-
-/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff --git a/generic/tclResolve.c b/generic/tclResolve.c
index 974737e..4520890 100644
--- a/generic/tclResolve.c
+++ b/generic/tclResolve.c
@@ -43,8 +43,6 @@ static void BumpCmdRefEpochs(Namespace *nsPtr);
* cmdProcPtr, varProcPtr and compiledVarProcPtr arguments.
*
* Side effects:
- * If a compiledVarProc is specified, this function bumps the
- * compileEpoch for the interpreter, forcing all code to be recompiled.
* If a cmdProc is specified, this function bumps the cmdRefEpoch in all
* namespaces, forcing commands to be resolved again using the new rules.
*
@@ -75,9 +73,6 @@ Tcl_AddInterpResolvers(
* cmdRefEpoch in all namespaces.
*/
- if (compiledVarProc) {
- iPtr->compileEpoch++;
- }
if (cmdProc) {
BumpCmdRefEpochs(iPtr->globalNsPtr);
}
@@ -175,9 +170,7 @@ Tcl_GetInterpResolvers(
* was deleted. Returns zero otherwise.
*
* Side effects:
- * If a scheme with a compiledVarProc was deleted, this function bumps
- * the compileEpoch for the interpreter, forcing all code to be
- * recompiled. If a scheme with a cmdProc was deleted, this function
+ * If a scheme with a cmdProc was deleted, this function
* bumps the cmdRefEpoch in all namespaces, forcing commands to be
* resolved again using the new rules.
*
@@ -217,9 +210,6 @@ Tcl_RemoveInterpResolvers(
* cmdRefEpoch in all namespaces.
*/
- if (resPtr->compiledVarResProc) {
- iPtr->compileEpoch++;
- }
if (resPtr->cmdResProc) {
BumpCmdRefEpochs(iPtr->globalNsPtr);
}
diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c
index c38f076..28382b9 100644
--- a/generic/tclStubInit.c
+++ b/generic/tclStubInit.c
@@ -1287,7 +1287,7 @@ const TclStubs tclStubs = {
Tcl_GetStartupScript, /* 623 */
Tcl_CloseEx, /* 624 */
Tcl_NRExprObj, /* 625 */
- Tcl_NRSubstObj, /* 626 */
+ 0, /* 626 */
Tcl_LoadFile, /* 627 */
Tcl_FindSymbol, /* 628 */
Tcl_FSUnloadFile, /* 629 */
diff --git a/generic/tclTrace.c b/generic/tclTrace.c
index 61bac9b..4157c43 100644
--- a/generic/tclTrace.c
+++ b/generic/tclTrace.c
@@ -1131,10 +1131,6 @@ Tcl_TraceCommand(
* Bug 3484621: up the interp's epoch if this is a BC'ed command
*/
- if ((cmdPtr->compileProc != NULL) && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES)){
- Interp *iPtr = (Interp *) interp;
- iPtr->compileEpoch++;
- }
cmdPtr->flags |= CMD_HAS_EXEC_TRACES;
}
@@ -1241,15 +1237,6 @@ Tcl_UntraceCommand(
*/
cmdPtr->flags &= ~CMD_HAS_EXEC_TRACES;
-
- /*
- * Bug 3484621: up the interp's epoch if this is a BC'ed command
- */
-
- if (cmdPtr->compileProc != NULL) {
- Interp *iPtr = (Interp *) interp;
- iPtr->compileEpoch++;
- }
}
}
@@ -2142,24 +2129,6 @@ Tcl_CreateObjTrace(
* Test if this trace allows inline compilation of commands.
*/
- if (!(flags & TCL_ALLOW_INLINE_COMPILATION)) {
- if (iPtr->tracesForbiddingInline == 0) {
- /*
- * When the first trace forbidding inline compilation is created,
- * invalidate existing compiled code for this interpreter and
- * arrange (by setting the DONT_COMPILE_CMDS_INLINE flag) that
- * when compiling new code, no commands will be compiled inline
- * (i.e., into an inline sequence of instructions). We do this
- * because commands that were compiled inline will never result in
- * a command trace being called.
- */
-
- iPtr->compileEpoch++;
- iPtr->flags |= DONT_COMPILE_CMDS_INLINE;
- }
- iPtr->tracesForbiddingInline++;
- }
-
tracePtr = ckalloc(sizeof(Trace));
tracePtr->level = level;
tracePtr->proc = proc;
@@ -2371,21 +2340,6 @@ Tcl_DeleteTrace(
}
/*
- * If the trace forbids bytecode compilation, change the interpreter's
- * state. If bytecode compilation is now permitted, flag the fact and
- * advance the compilation epoch so that procs will be recompiled to take
- * advantage of it.
- */
-
- if (!(tracePtr->flags & TCL_ALLOW_INLINE_COMPILATION)) {
- iPtr->tracesForbiddingInline--;
- if (iPtr->tracesForbiddingInline == 0) {
- iPtr->flags &= ~DONT_COMPILE_CMDS_INLINE;
- iPtr->compileEpoch++;
- }
- }
-
- /*
* Execute any delete callback.
*/
diff --git a/generic/tclVar.c b/generic/tclVar.c
index cf33561..f7a1966 100644
--- a/generic/tclVar.c
+++ b/generic/tclVar.c
@@ -4214,17 +4214,17 @@ TclInitArrayCmd(
Tcl_Interp *interp) /* Current interpreter. */
{
static const EnsembleImplMap arrayImplMap[] = {
- {"anymore", ArrayAnyMoreCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"donesearch", ArrayDoneSearchCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"exists", ArrayExistsCmd, TclCompileArrayExistsCmd, NULL, 0},
- {"get", ArrayGetCmd, TclCompileBasic1Or2ArgCmd, NULL, 0},
- {"names", ArrayNamesCmd, TclCompileBasic1To3ArgCmd, NULL, 0},
- {"nextelement", ArrayNextElementCmd, TclCompileBasic2ArgCmd, NULL, 0},
- {"set", ArraySetCmd, TclCompileArraySetCmd, NULL, 0},
- {"size", ArraySizeCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"startsearch", ArrayStartSearchCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"statistics", ArrayStatsCmd, TclCompileBasic1ArgCmd, NULL, 0},
- {"unset", ArrayUnsetCmd, TclCompileArrayUnsetCmd, NULL, 0},
+ {"anymore", ArrayAnyMoreCmd, NULL, NULL, 0},
+ {"donesearch", ArrayDoneSearchCmd, NULL, NULL, 0},
+ {"exists", ArrayExistsCmd, NULL, NULL, 0},
+ {"get", ArrayGetCmd, NULL, NULL, 0},
+ {"names", ArrayNamesCmd, NULL, NULL, 0},
+ {"nextelement", ArrayNextElementCmd, NULL, NULL, 0},
+ {"set", ArraySetCmd, NULL, NULL, 0},
+ {"size", ArraySizeCmd, NULL, NULL, 0},
+ {"startsearch", ArrayStartSearchCmd, NULL, NULL, 0},
+ {"statistics", ArrayStatsCmd, NULL, NULL, 0},
+ {"unset", ArrayUnsetCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, 0}
};