summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclBasic.c8
-rw-r--r--generic/tclCompile.c10
-rw-r--r--generic/tclExecute.c9
-rw-r--r--generic/tclProc.c33
4 files changed, 56 insertions, 4 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index 5c5bc64..0fc8e31 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -5968,6 +5968,14 @@ TclNREvalObjEx(
int result;
/*
+ * Shortcut for empty scripts; avoid computing a string rep
+ */
+
+ if (objPtr->bytes && (*objPtr->bytes == '\0')) {
+ return TCL_OK;
+ }
+
+ /*
* This function consists of three independent blocks for: direct
* evaluation of canonical lists, compilation and bytecode execution and
* finally direct evaluation. Precisely one of these blocks will be run.
diff --git a/generic/tclCompile.c b/generic/tclCompile.c
index f62ec14..af86ba6 100644
--- a/generic/tclCompile.c
+++ b/generic/tclCompile.c
@@ -1255,8 +1255,14 @@ Tcl_NRSubstObj(
{
ByteCode *codePtr = CompileSubstObj(interp, objPtr, flags);
- /* TODO: Confirm we do not need this. */
- /* Tcl_ResetResult(interp); */
+ /*
+ * Shortcut for empty scripts; avoid computing a string rep
+ */
+
+ if (objPtr->bytes && (*objPtr->bytes == '\0')) {
+ return TCL_OK;
+ }
+
return TclNRExecuteByteCode(interp, codePtr);
}
diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index b10af65..ff1da8b 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -2034,6 +2034,15 @@ TclNRExecuteByteCode(
* sizeof(void *);
int numWords = (size + sizeof(Tcl_Obj *) - 1) / sizeof(Tcl_Obj *);
+ /*
+ * Shortcut for compiled empty scripts
+ */
+
+ if (codePtr->source && (*codePtr->source == '\0')
+ && !(codePtr->flags & TCL_BYTECODE_PRECOMPILED)) {
+ return TCL_OK;
+ }
+
codePtr->refCount++;
/*
diff --git a/generic/tclProc.c b/generic/tclProc.c
index ac65bde..f6f6e3e 100644
--- a/generic/tclProc.c
+++ b/generic/tclProc.c
@@ -1441,7 +1441,7 @@ InitArgsAndLocals(
if (localCt) {
if (!codePtr->localCachePtr) {
- InitLocalCache(procPtr) ;
+ InitLocalCache(procPtr);
}
framePtr->localCachePtr = codePtr->localCachePtr;
framePtr->localCachePtr->refCount++;
@@ -1697,12 +1697,41 @@ TclNRInterpProc(
* procedure. */
Tcl_Obj *const objv[]) /* Argument value objects. */
{
- int result = TclPushProcCallFrame(clientData, interp, objc, objv,
+ Proc *procPtr = clientData;
+ Interp *iPtr = (Interp *) interp;
+ int result;
+ Tcl_Obj *bodyPtr = procPtr->bodyPtr;
+
+ /*
+ * Shortcut for empty bodies. Note that this also avoids compiling and
+ * shimmering the empty string, as well as pushing/popping a CallFrame and
+ * invoking TEBC.
+ */
+
+ if (bodyPtr->bytes && (*bodyPtr->bytes == '\0')) {
+ /* empty body ... */
+ ByteCode *codePtr = (ByteCode *) bodyPtr->internalRep.twoPtrValue.ptr1;
+ if ((bodyPtr->typePtr != &tclByteCodeType) ||
+ !(codePtr->flags & TCL_BYTECODE_PRECOMPILED)) {
+ /* ... and not precompiled ... */
+ if (objc == procPtr->numArgs + 1) {
+ /* ... and correct number of arguments; we will still be
+ * compiling empty bodies that have default values or args
+ * for simplicity sake - to avoid having to go through the
+ * linked list of compiled locals to determine the nature of
+ * the last formal argument(s). */
+ return TCL_OK;
+ }
+ }
+ }
+
+ result = TclPushProcCallFrame(procPtr, interp, objc, objv,
/*isLambda*/ 0);
if (result != TCL_OK) {
return TCL_ERROR;
}
+
return TclNRInterpProcCore(interp, objv[0], 1, &MakeProcError);
}