diff options
author | apnadkarni <apnmbx-wits@yahoo.com> | 2022-11-03 17:04:07 (GMT) |
---|---|---|
committer | apnadkarni <apnmbx-wits@yahoo.com> | 2022-11-03 17:04:07 (GMT) |
commit | f768eb3bf2d09ebf310ed07f664dc114e1c1412d (patch) | |
tree | 0654108b366eb7baaf8c4e36a83ae1de9327f2bd | |
parent | d9a19f95121e4fd846211083cc7c3b0d22c7a564 (diff) | |
download | tcl-f768eb3bf2d09ebf310ed07f664dc114e1c1412d.zip tcl-f768eb3bf2d09ebf310ed07f664dc114e1c1412d.tar.gz tcl-f768eb3bf2d09ebf310ed07f664dc114e1c1412d.tar.bz2 |
Rewrite lreplace4 implementation not to need extra immediate operands.
-rw-r--r-- | generic/tclBasic.c | 2 | ||||
-rw-r--r-- | generic/tclCompCmdsGR.c | 210 | ||||
-rw-r--r-- | generic/tclCompile.c | 13 | ||||
-rw-r--r-- | generic/tclCompile.h | 10 | ||||
-rw-r--r-- | generic/tclExecute.c | 129 | ||||
-rw-r--r-- | generic/tclInt.h | 3 |
6 files changed, 135 insertions, 232 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c index a1eb4cc..80dc416 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -310,7 +310,7 @@ static const CmdInfo builtInCmds[] = { {"join", Tcl_JoinObjCmd, NULL, NULL, CMD_IS_SAFE}, {"lappend", Tcl_LappendObjCmd, TclCompileLappendCmd, NULL, CMD_IS_SAFE}, {"lassign", Tcl_LassignObjCmd, TclCompileLassignCmd, NULL, CMD_IS_SAFE}, - {"ledit", Tcl_LeditObjCmd, TclCompileLeditCmd, NULL, CMD_IS_SAFE}, + {"ledit", Tcl_LeditObjCmd, NULL, NULL, CMD_IS_SAFE}, {"lindex", Tcl_LindexObjCmd, TclCompileLindexCmd, NULL, CMD_IS_SAFE}, {"linsert", Tcl_LinsertObjCmd, TclCompileLinsertCmd, NULL, CMD_IS_SAFE}, {"list", Tcl_ListObjCmd, TclCompileListCmd, NULL, CMD_IS_SAFE|CMD_COMPILES_EXPANDED}, diff --git a/generic/tclCompCmdsGR.c b/generic/tclCompCmdsGR.c index bf6288a..2681d01 100644 --- a/generic/tclCompCmdsGR.c +++ b/generic/tclCompCmdsGR.c @@ -1036,124 +1036,6 @@ TclCompileLassignCmd( /* *---------------------------------------------------------------------- * - * TclCompileLeditCmd -- - * - * How to compile the "ledit" command. We only bother with the case - * where the index is constant. - * - *---------------------------------------------------------------------- - */ - -int -TclCompileLeditCmd( - Tcl_Interp *interp, /* Tcl interpreter for context. */ - Tcl_Parse *parsePtr, /* Points to a parse structure for the - * command. */ - TCL_UNUSED(Command *), - CompileEnv *envPtr) /* Holds the resulting instructions. */ -{ - DefineLineInformation; /* TIP #280 */ - Tcl_Token *tokenPtr, *varTokenPtr; - int localIndex; /* Index of var in local var table. */ - int isScalar; /* Flag == 1 if scalar, 0 if array. */ - int tempDepth; /* Depth used for emitting one part of the - * code burst. */ - int first, last, i, end_indicator; - - if (parsePtr->numWords < 4) { - return TCL_ERROR; - } - varTokenPtr = TokenAfter(parsePtr->tokenPtr); - - tokenPtr = TokenAfter(varTokenPtr); - if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_NONE, - &first) != TCL_OK) { - return TCL_ERROR; - } - - tokenPtr = TokenAfter(tokenPtr); - if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_NONE, TCL_INDEX_END, - &last) != TCL_OK) { - return TCL_ERROR; - } - end_indicator = 1; /* "end" means last element by default */ - if (first == (int)TCL_INDEX_NONE) { - /* first == TCL_INDEX_NONE => Range after last element. */ - first = TCL_INDEX_END; /* Insert at end where ... */ - end_indicator = 0; /* ... end means AFTER last element */ - last = TCL_INDEX_NONE; /* Informs lreplace, nothing to replace */ - } - - PushVarNameWord(interp, varTokenPtr, envPtr, 0, - &localIndex, &isScalar, 1); - - /* Duplicate the variable name if it's been pushed. */ - if (localIndex < 0) { - if (isScalar) { - tempDepth = 0; - } else { - tempDepth = 1; - } - TclEmitInstInt4(INST_OVER, tempDepth, envPtr); - } - - /* Duplicate an array index if one's been pushed. */ - if (!isScalar) { - if (localIndex < 0) { - tempDepth = 1; - } else { - tempDepth = parsePtr->numWords - 2; - } - TclEmitInstInt4(INST_OVER, tempDepth, envPtr); - } - - /* Emit code to load the variable's value. */ - if (isScalar) { - if (localIndex < 0) { - TclEmitOpcode(INST_LOAD_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); - } - } - - for (i=4 ; i<parsePtr->numWords ; ++i) { - tokenPtr = TokenAfter(tokenPtr); - CompileWord(envPtr, tokenPtr, interp, i); - } - - TclEmitInstInt4(INST_LREPLACE4, parsePtr->numWords - 3, envPtr); - TclEmitInt4(end_indicator, envPtr); - TclEmitInt4(first, envPtr); - TclEmitInt4(last, envPtr); - - /* Emit code to put the value back in the variable. */ - - if (isScalar) { - if (localIndex < 0) { - TclEmitOpcode(INST_STORE_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; -} - -/* - *---------------------------------------------------------------------- - * * TclCompileLindexCmd -- * * Procedure called to compile the "lindex" command. @@ -1473,42 +1355,34 @@ TclCompileLinsertCmd( CompileEnv *envPtr) /* Holds the resulting instructions. */ { DefineLineInformation; /* TIP #280 */ - Tcl_Token *tokenPtr, *listTokenPtr; - int idx, i; + Tcl_Token *tokenPtr; + int i; if (parsePtr->numWords < 3) { return TCL_ERROR; } - listTokenPtr = TokenAfter(parsePtr->tokenPtr); - - tokenPtr = TokenAfter(listTokenPtr); - - /* - * This command treats all inserts at indices before the list - * the same as inserts at the start of the list, and all inserts - * after the list the same as inserts at the end of the list. We - * make that transformation here so we can use the optimized bytecode - * as much as possible. - */ - if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_END, &idx) - != TCL_OK) { - /* Not a constant index. */ - return TCL_ERROR; - } - - CompileWord(envPtr, listTokenPtr, interp, 1); + + /* Push list, insertion index onto the stack */ + tokenPtr = TokenAfter(parsePtr->tokenPtr); + CompileWord(envPtr, tokenPtr, interp, 1); + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp, 2); + /* Push new elements to be inserted */ for (i=3 ; i<parsePtr->numWords ; i++) { tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp, i); } - /* First operand is count of new elements */ - TclEmitInstInt4(INST_LREPLACE4, parsePtr->numWords - 2, envPtr); - TclEmitInt4(0, envPtr); /* "end" refers to position AFTER last element */ - TclEmitInt4(idx, envPtr);/* Insertion point (also start of range to delete) */ - TclEmitInt4(TCL_INDEX_NONE, envPtr); /* End of range to delete. - TCL_INDEX_NONE => no deletions */ + /* First operand is count of arguments */ + TclEmitInstInt4(INST_LREPLACE4, parsePtr->numWords - 1, envPtr); + /* + * Second operand is bitmask + * TCL_LREPLACE4_END_IS_LAST - end refers to last element + * TCL_LREPLACE4_SINGLE_INDEX - second index is not present + * indicating this is a pure insert + */ + TclEmitInt1(TCL_LREPLACE4_SINGLE_INDEX, envPtr); return TCL_OK; } @@ -1533,46 +1407,38 @@ TclCompileLreplaceCmd( CompileEnv *envPtr) /* Holds the resulting instructions. */ { DefineLineInformation; /* TIP #280 */ - Tcl_Token *tokenPtr, *listTokenPtr; - int first, last, i, end_indicator; + Tcl_Token *tokenPtr; + int i; if (parsePtr->numWords < 4) { return TCL_ERROR; } - listTokenPtr = TokenAfter(parsePtr->tokenPtr); - - tokenPtr = TokenAfter(listTokenPtr); - if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_NONE, - &first) != TCL_OK) { - return TCL_ERROR; - } + /* Push list, first, last onto the stack */ + tokenPtr = TokenAfter(parsePtr->tokenPtr); + CompileWord(envPtr, tokenPtr, interp, 1); tokenPtr = TokenAfter(tokenPtr); - if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_NONE, TCL_INDEX_END, - &last) != TCL_OK) { - return TCL_ERROR; - } - end_indicator = 1; /* "end" means last element by default */ - if (first == (int)TCL_INDEX_NONE) { - /* Special case: first == TCL_INDEX_NONE => Range after last element. */ - first = TCL_INDEX_END; /* Insert at end where ... */ - end_indicator = 0; /* ... end means AFTER last element */ - last = TCL_INDEX_NONE; /* Informs lreplace, nothing to replace */ - } - - CompileWord(envPtr, listTokenPtr, interp, 1); + CompileWord(envPtr, tokenPtr, interp, 2); + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp, 3); + /* Push new elements to be inserted */ for (i=4 ; i<parsePtr->numWords ; i++) { tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp, i); } - TclEmitInstInt4(INST_LREPLACE4, parsePtr->numWords - 3, envPtr); - TclEmitInt4(end_indicator, envPtr); - TclEmitInt4(first, envPtr); - TclEmitInt4(last, envPtr); - return TCL_OK;} - + /* First operand is count of arguments */ + TclEmitInstInt4(INST_LREPLACE4, parsePtr->numWords - 1, envPtr); + /* + * Second operand is bitmask + * TCL_LREPLACE4_END_IS_LAST - end refers to last element + */ + TclEmitInt1(TCL_LREPLACE4_END_IS_LAST, envPtr); + + return TCL_OK; +} + /* *---------------------------------------------------------------------- * diff --git a/generic/tclCompile.c b/generic/tclCompile.c index 57e2d71..2dd0718 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -675,12 +675,13 @@ InstructionDesc const tclInstructionTable[] = { /* String Less or equal: push (stknext <= stktop) */ {"strge", 1, -1, 0, {OPERAND_NONE}}, /* String Greater or equal: push (stknext >= stktop) */ - {"lreplace4", 17, INT_MIN, 4, {OPERAND_UINT4, OPERAND_UINT4, OPERAND_INT4, OPERAND_INT4}}, - /* Operands: number of arguments, end_indicator, firstIdx, lastIdx - * end_indicator: 1 if "end" is treated as index of last element, - * 0 if "end" is position after last element - * firstIdx,lastIdx: range of elements to delete - * Stack: ... listobj new1 ... newN => ... newlistobj */ + {"lreplace4", 6, INT_MIN, 2, {OPERAND_UINT4, OPERAND_UINT1}}, + /* Operands: number of arguments, flags + * flags: Combination of TCL_LREPLACE4_* flags + * Stack: ... listobj index1 ?index2? new1 ... newN => ... newlistobj + * where index2 is present only if TCL_LREPLACE_SINGLE_INDEX is not + * set in flags. + */ {NULL, 0, 0, 0, {OPERAND_NONE}} }; diff --git a/generic/tclCompile.h b/generic/tclCompile.h index 9633050..71ceede 100644 --- a/generic/tclCompile.h +++ b/generic/tclCompile.h @@ -848,7 +848,7 @@ typedef struct ByteCode { #define INST_STR_LE 193 #define INST_STR_GE 194 -#define INST_LREPLACE4 195 +#define INST_LREPLACE4 195 /* The last opcode */ #define LAST_INST_OPCODE 195 @@ -862,7 +862,7 @@ typedef struct ByteCode { * instruction. */ -#define MAX_INSTRUCTION_OPERANDS 4 +#define MAX_INSTRUCTION_OPERANDS 2 typedef enum InstOperandType { OPERAND_NONE, @@ -1685,6 +1685,12 @@ MODULE_SCOPE int TclPushProcCallFrame(void *clientData, #define TCL_NO_ELEMENT 2 /* Do not push the array element. */ /* + * Flags bits used by lreplace4 instruction + */ +#define TCL_LREPLACE4_END_IS_LAST 1 /* "end" refers to last element */ +#define TCL_LREPLACE4_SINGLE_INDEX 2 /* Second index absent (pure insert) */ + +/* * DTrace probe macros (NOPs if DTrace support is not enabled). */ diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 2713093..a8d9d57 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -5246,61 +5246,94 @@ TEBCresume( case INST_LREPLACE4: { - int firstIdx, lastIdx, numToDelete, numNewElems, end_indicator; - opnd = TclGetInt4AtPtr(pc + 1); - end_indicator = TclGetInt4AtPtr(pc + 5); - firstIdx = TclGetInt4AtPtr(pc + 9); - lastIdx = TclGetInt4AtPtr(pc + 13); - numNewElems = opnd - 1; - valuePtr = OBJ_AT_DEPTH(numNewElems); - if (Tcl_ListObjLength(interp, valuePtr, &length) != TCL_OK) { + int numToDelete, numNewElems, end_indicator; + int haveSecondIndex, flags; + Tcl_Obj *fromIdxObj, *toIdxObj; + opnd = TclGetInt4AtPtr(pc + 1); + flags = TclGetInt1AtPtr(pc + 5); + + /* Stack: ... listobj index1 ?index2? new1 ... newN */ + valuePtr = OBJ_AT_DEPTH(opnd-1); + + /* haveSecondIndex==0 => pure insert */ + haveSecondIndex = (flags & TCL_LREPLACE4_SINGLE_INDEX) == 0; + numNewElems = opnd - 2 - haveSecondIndex; + + /* end_indicator==1 => "end" is last element's index, 0=>index beyond */ + end_indicator = (flags & TCL_LREPLACE4_END_IS_LAST) != 0; + fromIdxObj = OBJ_AT_DEPTH(opnd - 2); + toIdxObj = haveSecondIndex ? OBJ_AT_DEPTH(opnd - 3) : NULL; + if (Tcl_ListObjLength(interp, valuePtr, &length) != TCL_OK) { + TRACE_ERROR(interp); + goto gotError; + } + + DECACHE_STACK_INFO(); + + if (TclGetIntForIndexM( + interp, fromIdxObj, length - end_indicator, &fromIdx) + != TCL_OK) { + CACHE_STACK_INFO(); + TRACE_ERROR(interp); + goto gotError; + } + if (fromIdx == TCL_INDEX_NONE) { + fromIdx = 0; + } + else if (fromIdx > length) { + fromIdx = length; + } + numToDelete = 0; + if (toIdxObj) { + if (TclGetIntForIndexM( + interp, toIdxObj, length - end_indicator, &toIdx) + != TCL_OK) { + CACHE_STACK_INFO(); TRACE_ERROR(interp); goto gotError; } - firstIdx = TclIndexDecode(firstIdx, length-end_indicator); - if (firstIdx == TCL_INDEX_NONE) { - firstIdx = 0; - } else if (firstIdx > length) { - firstIdx = length; - } - numToDelete = 0; - if (lastIdx != TCL_INDEX_NONE) { - lastIdx = TclIndexDecode(lastIdx, length - end_indicator); - if (lastIdx >= firstIdx) { - numToDelete = lastIdx - firstIdx + 1; - } + if (toIdx > length) { + toIdx = length; } - if (Tcl_IsShared(valuePtr)) { - objResultPtr = Tcl_DuplicateObj(valuePtr); - if (Tcl_ListObjReplace(interp, - objResultPtr, - firstIdx, - numToDelete, - numNewElems, - &OBJ_AT_DEPTH(numNewElems-1)) - != TCL_OK) { - TRACE_ERROR(interp); - Tcl_DecrRefCount(objResultPtr); - goto gotError; - } - TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr))); - NEXT_INST_V(17, opnd, 1); - } else { - if (Tcl_ListObjReplace(interp, - valuePtr, - firstIdx, - numToDelete, - numNewElems, - &OBJ_AT_DEPTH(numNewElems-1)) - != TCL_OK) { - TRACE_ERROR(interp); - goto gotError; - } - TRACE_APPEND(("\"%.30s\"\n", O2S(valuePtr))); - NEXT_INST_V(17, opnd-1, 0); + if (toIdx >= fromIdx) { + numToDelete = toIdx - fromIdx + 1; } } + CACHE_STACK_INFO(); + + if (Tcl_IsShared(valuePtr)) { + objResultPtr = Tcl_DuplicateObj(valuePtr); + if (Tcl_ListObjReplace(interp, + objResultPtr, + fromIdx, + numToDelete, + numNewElems, + &OBJ_AT_DEPTH(numNewElems - 1)) + != TCL_OK) { + TRACE_ERROR(interp); + Tcl_DecrRefCount(objResultPtr); + goto gotError; + } + TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr))); + NEXT_INST_V(6, opnd, 1); + } + else { + if (Tcl_ListObjReplace(interp, + valuePtr, + fromIdx, + numToDelete, + numNewElems, + &OBJ_AT_DEPTH(numNewElems - 1)) + != TCL_OK) { + TRACE_ERROR(interp); + goto gotError; + } + TRACE_APPEND(("\"%.30s\"\n", O2S(valuePtr))); + NEXT_INST_V(6, opnd - 1, 0); + } + } + /* * End of INST_LIST and related instructions. * ----------------------------------------------------------------- diff --git a/generic/tclInt.h b/generic/tclInt.h index 5c977e5..a67c8f9 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -3759,9 +3759,6 @@ MODULE_SCOPE int TclCompileLappendCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileLassignCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclCompileLeditCmd(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); |