Tcl Source Code

Check-in [58ebb29700]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:new INST_LMAP_COLLECT, speeds up lmap and eliminates the need for a temp var
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 58ebb297000cbc64a593e1950fdfc5738f8446b2
User & Date: mig 2013-12-10 11:38:17
Context
2013-12-10
12:05
fix stack computations for lmap check-in: e4212fccc3 user: mig tags: trunk
11:55
fix stack computations for lmap check-in: 8aa6e6e51b user: mig tags: mistake
11:40
get INST_LMAP_COLLECT from trunk check-in: 72fd8739c8 user: mig tags: mig-optimize
11:38
new INST_LMAP_COLLECT, speeds up lmap and eliminates the need for a temp var check-in: 58ebb29700 user: mig tags: trunk
2013-12-06
15:58
change NULL to INT2PTR(0), for clarity check-in: 6cfea930ff user: mig tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclCompCmds.c.

2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
    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 collectVar = -1;	/* Index of temp var holding the result var
				 * index. */
    
    Tcl_Token *tokenPtr, *bodyTokenPtr;
    int jumpBackOffset, infoIndex, range;
    int numWords, numLists, numVars, loopIndex, i, j, code;
    DefineLineInformation;	/* TIP #280 */

    /*







<
<







2454
2455
2456
2457
2458
2459
2460


2461
2462
2463
2464
2465
2466
2467
    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. */


    
    Tcl_Token *tokenPtr, *bodyTokenPtr;
    int jumpBackOffset, infoIndex, range;
    int numWords, numLists, numVars, loopIndex, i, j, code;
    DefineLineInformation;	/* TIP #280 */

    /*
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
	loopIndex++;
    }

    /*
     * We will compile the foreach command.
     */

    if (collect == TCL_EACH_COLLECT) {
	collectVar = AnonymousLocal(envPtr);
	if (collectVar < 0) {
	    return TCL_ERROR;
	}
    }
	    
    code = TCL_OK;

    /*
     * Create and initialize the ForeachInfo and ForeachVarList data
     * structures describing this command. Then create a AuxData record
     * pointing to the ForeachInfo structure.
     */







<
<
<
<
<
<
<







2569
2570
2571
2572
2573
2574
2575







2576
2577
2578
2579
2580
2581
2582
	loopIndex++;
    }

    /*
     * We will compile the foreach command.
     */








    code = TCL_OK;

    /*
     * Create and initialize the ForeachInfo and ForeachVarList data
     * structures describing this command. Then create a AuxData record
     * pointing to the ForeachInfo structure.
     */
2607
2608
2609
2610
2611
2612
2613








2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651

2652
2653
2654
2655
2656
2657
2658
	    varListPtr->varIndexes[j] = TclFindCompiledLocal(varName,
		    nameChars, /*create*/ 1, envPtr);
	}
	infoPtr->varLists[loopIndex] = varListPtr;
    }
    infoIndex = TclCreateAuxData(infoPtr, &tclNewForeachInfoType, envPtr);









    /*
     * Evaluate each value list and leave it on stack.
     */

    for (i = 0, tokenPtr = parsePtr->tokenPtr;
	    i < numWords-1;
	    i++, tokenPtr = TokenAfter(tokenPtr)) {
	if ((i%2 == 0) && (i > 0)) {
	    CompileWord(envPtr, tokenPtr, interp, i);
	}
    }

    /*
     * Create temporary variable to capture return values from loop body.
     */
     
    if (collect == TCL_EACH_COLLECT) {
	PushStringLiteral(envPtr, "");
	Emit14Inst(		INST_STORE_SCALAR, collectVar,	envPtr);
	TclEmitOpcode(		INST_POP,			envPtr);
    }

    TclEmitInstInt4(INST_FOREACH_START, infoIndex, envPtr);
    
    /*
     * Inline compile the loop body.
     */

    range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);

    ExceptionRangeStarts(envPtr, range);
    BODY(bodyTokenPtr, numWords - 1);
    ExceptionRangeEnds(envPtr, range);
    
    if (collect == TCL_EACH_COLLECT) {
	Emit14Inst(		INST_LAPPEND_SCALAR, collectVar,envPtr);
    }
    TclEmitOpcode(		INST_POP,			envPtr);


    /*
     * Bottom of loop code: assign each loop variable and check whether
     * to terminate the loop. Set the loop's break target. 
     */

    ExceptionRangeTarget(envPtr, range, continueOffset);







>
>
>
>
>
>
>
>












<
<
<
<
<
<
<
<
<
<













|
|
|
>







2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624










2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
	    varListPtr->varIndexes[j] = TclFindCompiledLocal(varName,
		    nameChars, /*create*/ 1, envPtr);
	}
	infoPtr->varLists[loopIndex] = varListPtr;
    }
    infoIndex = TclCreateAuxData(infoPtr, &tclNewForeachInfoType, envPtr);

    /*
     * Create the collecting object, unshared.
     */
    
    if (collect == TCL_EACH_COLLECT) {
	TclEmitInstInt4(INST_LIST, 0, envPtr);
    }
	    
    /*
     * Evaluate each value list and leave it on stack.
     */

    for (i = 0, tokenPtr = parsePtr->tokenPtr;
	    i < numWords-1;
	    i++, tokenPtr = TokenAfter(tokenPtr)) {
	if ((i%2 == 0) && (i > 0)) {
	    CompileWord(envPtr, tokenPtr, interp, i);
	}
    }











    TclEmitInstInt4(INST_FOREACH_START, infoIndex, envPtr);
    
    /*
     * Inline compile the loop body.
     */

    range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);

    ExceptionRangeStarts(envPtr, range);
    BODY(bodyTokenPtr, numWords - 1);
    ExceptionRangeEnds(envPtr, range);
    
    if (collect == TCL_EACH_COLLECT) {
	TclEmitOpcode(INST_LMAP_COLLECT, envPtr);
    } else {
	TclEmitOpcode(		INST_POP,			envPtr);
    }

    /*
     * Bottom of loop code: assign each loop variable and check whether
     * to terminate the loop. Set the loop's break target. 
     */

    ExceptionRangeTarget(envPtr, range, continueOffset);
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
     */
    
    jumpBackOffset = envPtr->exceptArrayPtr[range].continueOffset -
	    envPtr->exceptArrayPtr[range].codeOffset;
    infoPtr->loopCtTemp = -jumpBackOffset;

    /*
     * The command's result is an empty string if not collecting, or the
     * list of results from evaluating the loop body.
     */

    if (collect == TCL_EACH_COLLECT) {
	Emit14Inst(		INST_LOAD_SCALAR, collectVar,	envPtr);
	TclEmitInstInt1(INST_UNSET_SCALAR, 0,			envPtr);
	TclEmitInt4(		collectVar,			envPtr);
    } else {
	PushStringLiteral(envPtr, "");
    }
    
    done:
    for (loopIndex = 0;  loopIndex < numLists;  loopIndex++) {
	if (varvList[loopIndex] != NULL) {
	    ckfree(varvList[loopIndex]);







|
|


|
<
<
<
<







2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669




2670
2671
2672
2673
2674
2675
2676
     */
    
    jumpBackOffset = envPtr->exceptArrayPtr[range].continueOffset -
	    envPtr->exceptArrayPtr[range].codeOffset;
    infoPtr->loopCtTemp = -jumpBackOffset;

    /*
     * The command's result is an empty string if not collecting. If
     * collecting, it is automatically left on stack after FOREACH_END.
     */

    if (collect != TCL_EACH_COLLECT) {




	PushStringLiteral(envPtr, "");
    }
    
    done:
    for (loopIndex = 0;  loopIndex < numLists;  loopIndex++) {
	if (varvList[loopIndex] != NULL) {
	    ckfree(varvList[loopIndex]);

Changes to generic/tclCompile.c.

550
551
552
553
554
555
556

557
558
559
560
561
562
563
	/* Initialize execution of a foreach loop. Operand is aux data index
	 * of the ForeachInfo structure for the foreach command. It pushes 2
	 * elements which hold runtime params for foreach_step, they are later
	 * dropped by foreach_end together with the value lists. */ 
    {"foreach_step",	  1,    0,         0,	{OPERAND_NONE}},
	/* "Step" or begin next iteration of foreach loop. */
    {"foreach_end",	  1,    0,         0,	{OPERAND_NONE}},


    {NULL, 0, 0, 0, {OPERAND_NONE}}
};

/*
 * Prototypes for procedures defined later in this file:
 */







>







550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
	/* Initialize execution of a foreach loop. Operand is aux data index
	 * of the ForeachInfo structure for the foreach command. It pushes 2
	 * elements which hold runtime params for foreach_step, they are later
	 * dropped by foreach_end together with the value lists. */ 
    {"foreach_step",	  1,    0,         0,	{OPERAND_NONE}},
	/* "Step" or begin next iteration of foreach loop. */
    {"foreach_end",	  1,    0,         0,	{OPERAND_NONE}},
    {"lmap_collect",	  1,    0,         0,	{OPERAND_NONE}},

    {NULL, 0, 0, 0, {OPERAND_NONE}}
};

/*
 * Prototypes for procedures defined later in this file:
 */

Changes to generic/tclCompile.h.

769
770
771
772
773
774
775

776
777
778
779
780
781
782
783
784
785
#define INST_EXPAND_DROP		165

/* New foreach implementation */

#define INST_FOREACH_START              166
#define INST_FOREACH_STEP               167
#define INST_FOREACH_END                168


/* The last opcode */
#define LAST_INST_OPCODE		168

/*
 * 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"







>


|







769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
#define INST_EXPAND_DROP		165

/* New foreach implementation */

#define INST_FOREACH_START              166
#define INST_FOREACH_STEP               167
#define INST_FOREACH_END                168
#define INST_LMAP_COLLECT               169

/* The last opcode */
#define LAST_INST_OPCODE		169

/*
 * 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"

Changes to generic/tclExecute.c.

6341
6342
6343
6344
6345
6346
6347



















6348
6349
6350
6351
6352
6353
6354

    case INST_FOREACH_END:
	/* THIS INSTRUCTION IS ONLY CALLED AS A BREAK TARGET */
	tmpPtr = OBJ_AT_TOS;
	infoPtr = tmpPtr->internalRep.otherValuePtr;
	numLists = infoPtr->numLists;
	NEXT_INST_V(1, numLists+2, 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.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373

    case INST_FOREACH_END:
	/* THIS INSTRUCTION IS ONLY CALLED AS A BREAK TARGET */
	tmpPtr = OBJ_AT_TOS;
	infoPtr = tmpPtr->internalRep.otherValuePtr;
	numLists = infoPtr->numLists;
	NEXT_INST_V(1, numLists+2, 0);

    case INST_LMAP_COLLECT:
	/*
	 * This instruction is only issued by lmap. The stack is:
	 *   - result
	 *   - infoPtr
	 *   - loop counters
	 *   - valLists
	 *   - collecting obj (unshared)
	 * The instruction lappends the result to the collecting obj.
	 */

	tmpPtr = OBJ_AT_DEPTH(1);
	infoPtr = tmpPtr->internalRep.otherValuePtr;
	numLists = infoPtr->numLists;
	
	objPtr = OBJ_AT_DEPTH(3 + numLists);
	Tcl_ListObjAppendElement(NULL, objPtr, OBJ_AT_TOS);
	NEXT_INST_F(1, 1, 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.