| 9562 | |
| 9563 | |
| 9564 | ResultType Line::ExecUntil(ExecUntilMode aMode, ResultToken *aResultToken, Line **apJumpToLine) |
| 9565 | // Start executing at "this" line, stop when aMode indicates. |
| 9566 | // RECURSIVE: Handles all lines that involve flow-control. |
| 9567 | // aMode can be UNTIL_RETURN, UNTIL_BLOCK_END, ONLY_ONE_LINE. |
| 9568 | // Returns OK, FAIL, EARLY_RETURN, EARLY_EXIT, or (perhaps only indirectly) LOOP_BREAK, or LOOP_CONTINUE. |
| 9569 | // apJumpToLine is a pointer to Line-ptr (handle), which is an output parameter. If NULL, |
| 9570 | // the caller is indicating it doesn't need this value, so it won't (and can't) be set by |
| 9571 | // the called recursion layer. |
| 9572 | { |
| 9573 | Line *unused_jump_to_line; |
| 9574 | Line *&caller_jump_to_line = apJumpToLine ? *apJumpToLine : unused_jump_to_line; // Simplifies code in other places. |
| 9575 | // Important to init, since most of the time it will keep this value. |
| 9576 | // Tells caller that no jump is required (default): |
| 9577 | caller_jump_to_line = NULL; |
| 9578 | |
| 9579 | // The benchmark improvement of having the following variables declared outside the loop rather than inside |
| 9580 | // is about 0.25%. Since that is probably not even statistically significant, the only reason for declaring |
| 9581 | // them here is in case compilers other than MSVC++ 7.1 benefit more -- and because it's an old silly habit. |
| 9582 | __int64 loop_iteration; |
| 9583 | LoopFilesStruct *loop_file; |
| 9584 | RegItemStruct *loop_reg_item; |
| 9585 | LoopReadFileStruct *loop_read_file; |
| 9586 | LPTSTR loop_field; |
| 9587 | |
| 9588 | Line *jump_to_line; // Don't use *apJumpToLine because it might not exist. |
| 9589 | Label *jump_to_label; // For use with Goto. |
| 9590 | ResultType if_condition, result; |
| 9591 | LONG_OPERATION_INIT |
| 9592 | global_struct &g = *::g; // Reduces code size and may improve performance. Eclipsing ::g with local g makes compiler remind/enforce the use of the right one. |
| 9593 | |
| 9594 | for (Line *line = this; line != NULL;) |
| 9595 | { |
| 9596 | // The below must be done at least when the keybd or mouse hook is active, but is currently |
| 9597 | // always done since it's a very low overhead call, and has the side-benefit of making |
| 9598 | // the app maximally responsive when the script is busy. |
| 9599 | // This low-overhead call achieves at least two purposes optimally: |
| 9600 | // 1) Keyboard and mouse lag is minimized when the hook(s) are installed, since this single |
| 9601 | // Peek() is apparently enough to route all pending input to the hooks (though it's inexplicable |
| 9602 | // why calling MsgSleep(-1) does not achieve this goal, since it too does a Peek(). |
| 9603 | // Nevertheless, that is the testing result that was obtained: the mouse cursor lagged |
| 9604 | // in tight script loops even when MsgSleep(-1) or (0) was called every 10ms or so. |
| 9605 | // 2) The app is maximally responsive while executing in a tight loop. |
| 9606 | // 3) Hotkeys are maximally responsive. For example, if a user has game hotkeys, using |
| 9607 | // a GetTickCount() method (which very slightly improves performance by cutting back on |
| 9608 | // the number of Peek() calls) would introduce up to 10ms of delay before the hotkey |
| 9609 | // finally takes effect. 10ms can be significant in games, where ping (latency) itself |
| 9610 | // can sometimes be only 10 or 20ms. UPDATE: It looks like PeekMessage() yields CPU time |
| 9611 | // automatically, similar to a Sleep(0), when our queue has no messages. Since this would |
| 9612 | // make scripts slow to a crawl, only do the Peek() every 5ms or so (though the timer |
| 9613 | // granularity is 10ms on most OSes, so that's the true interval). |
| 9614 | // 4) Timed subroutines are run as consistently as possible (to help with this, a check |
| 9615 | // similar to the below is also done for single commmands that take a long time, such |
| 9616 | // as Download, FileSetAttrib, etc. |
| 9617 | LONG_OPERATION_UPDATE |
| 9618 | |
| 9619 | // If interruptions are currently forbidden, it's our responsibility to check if the number |
| 9620 | // of lines that have been run since this quasi-thread started now indicate that |
| 9621 | // interruptibility should be reenabled. g.UninterruptedLineCount must also be tracked |
no test coverage detected