Tcl Source Code

Artifact [bdd58f1151]
Login

Artifact bdd58f11517dbd1139ece68524f2760885121477:

Attachment "noopProc.patch" to ticket [451441ffff] added by msofer 2001-08-18 06:23:32.
Index: generic/tclProc.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclProc.c,v
retrieving revision 1.25
diff -u -r1.25 tclProc.c
--- generic/tclProc.c	2001/04/27 22:11:51	1.25
+++ generic/tclProc.c	2001/08/17 23:13:15
@@ -27,6 +27,8 @@
 static void	ProcBodyUpdateString _ANSI_ARGS_((Tcl_Obj *objPtr));
 static  int	ProcessProcResultCode _ANSI_ARGS_((Tcl_Interp *interp,
 		    char *procName, int nameLen, int returnCode));
+static int	TclCompileNoOp _ANSI_ARGS_((Tcl_Interp *interp,
+		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
 
 /*
  * The ProcBodyObjType type
@@ -146,6 +148,51 @@
     
     procPtr->cmdPtr = (Command *) cmd;
 
+
+    /*
+     * Optimize for noop procs: if the argument list is just "args"
+     * and the body is empty, define a compileProc.
+     *
+     * Notes: 
+     *   - cannot be done for any argument list without having different
+     *     compiled/not-compiled behaviour in the "wrong argument #" case
+     *   - Should be enhanced to handle also non-empty bodies that contain 
+     *     only comments; parsing the body will make the compilation of 
+     *     other procs slower
+     */
+    
+    {
+	char *txt;
+	txt = Tcl_GetString(objv[2]);
+	
+	while(*txt == ' ') txt++;
+	
+	if ((txt[0] == 'a') && (memcmp(txt, "args", 4) == 0)) {
+	    txt +=4;
+	    while(*txt != '\0') {
+		if (*txt != ' ') goto done;;
+		txt++;
+	    }	
+    
+	    /* 
+	     * The argument list is just "args"; check the body
+	     */
+
+	    txt = Tcl_GetString(objv[3]);
+	    while(*txt != '\0') {
+		if (!isspace(*txt)) goto done;
+		txt++;
+	    }	
+    
+	    /* 
+	     * The body is just spaces: link the compileProc
+	     */
+
+	    ((Command *) cmd)->compileProc = TclCompileNoOp;
+	}
+    }
+
+ done:
     return TCL_OK;
 }
 
@@ -1582,4 +1629,49 @@
     Tcl_Obj *objPtr;		/* the object to update */
 {
     panic("called ProcBodyUpdateString");
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclCompileNoOp --
+ *
+ *	Procedure called to compile noOp's
+ *
+ * Results:
+ *	The return value is TCL_OK, indicating successful compilation.
+ *
+ *	envPtr->maxStackDepth is updated with the maximum number of stack
+ *	elements needed to execute the command.
+ *
+ * Side effects:
+ *	Instructions are added to envPtr to execute a noOp at runtime.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclCompileNoOp(interp, parsePtr, envPtr)
+    Tcl_Interp *interp;         /* Used for error reporting. */
+    Tcl_Parse *parsePtr;        /* Points to a parse structure for the
+                                 * command created by Tcl_ParseCommand. */
+    CompileEnv *envPtr;         /* Holds resulting instructions. */
+{
+    Tcl_Token *tokenPtr;
+    int i, code;
+
+    envPtr->maxStackDepth = 1;
+    tokenPtr = parsePtr->tokenPtr;
+    for(i = 1; i < parsePtr->numWords; i++) {
+	tokenPtr = tokenPtr + tokenPtr->numComponents + 1;
+	if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { 
+	    code = TclCompileTokens(interp, tokenPtr+1,
+	        tokenPtr->numComponents, envPtr);
+	    if (code != TCL_OK) return code;
+	    TclEmitOpcode(INST_POP, envPtr);
+	} 
+    }
+    TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0), envPtr);
+    return TCL_OK;
 }
Index: tests/proc.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/proc.test,v
retrieving revision 1.8
diff -u -r1.8 proc.test
--- tests/proc.test	2000/05/03 00:14:36	1.8
+++ tests/proc.test	2001/08/17 23:14:45
@@ -294,6 +294,23 @@
     set result
 } {procedure "t": formal parameter "z" has default value inconsistent with precompiled body}
 
+test proc-5.1 {Bytecompiling noop; test for correct argument substitution} {
+    proc p args {} ; # this will be bytecompiled into t
+    proc t {} {
+	set ct 0
+	set a 0
+	set b 0
+	trace add variable a read {incr ct ;#}
+	trace add variable b write {incr ct ;#}
+	p $a ccccccw {bfe} {$a} [incr b] [incr a] {[incr b]} {$a} hello
+	set ct
+    }
+    set result [t]
+    catch {rename p ""}
+    catch {rename t ""}
+    set result
+} {3}    
+
 # cleanup
 catch {rename p ""}
 catch {rename t ""}