summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorapnadkarni <apnmbx-wits@yahoo.com>2022-11-03 17:04:07 (GMT)
committerapnadkarni <apnmbx-wits@yahoo.com>2022-11-03 17:04:07 (GMT)
commitf768eb3bf2d09ebf310ed07f664dc114e1c1412d (patch)
tree0654108b366eb7baaf8c4e36a83ae1de9327f2bd
parentd9a19f95121e4fd846211083cc7c3b0d22c7a564 (diff)
downloadtcl-f768eb3bf2d09ebf310ed07f664dc114e1c1412d.zip
tcl-f768eb3bf2d09ebf310ed07f664dc114e1c1412d.tar.gz
tcl-f768eb3bf2d09ebf310ed07f664dc114e1c1412d.tar.bz2
Rewrite lreplace4 implementation not to need extra immediate operands.
-rw-r--r--generic/tclBasic.c2
-rw-r--r--generic/tclCompCmdsGR.c210
-rw-r--r--generic/tclCompile.c13
-rw-r--r--generic/tclCompile.h10
-rw-r--r--generic/tclExecute.c129
-rw-r--r--generic/tclInt.h3
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);