summaryrefslogtreecommitdiffstats
path: root/generic/tclOptimize.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclOptimize.c')
-rw-r--r--generic/tclOptimize.c444
1 files changed, 0 insertions, 444 deletions
diff --git a/generic/tclOptimize.c b/generic/tclOptimize.c
deleted file mode 100644
index 827d89d..0000000
--- a/generic/tclOptimize.c
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * tclOptimize.c --
- *
- * This file contains the bytecode optimizer.
- *
- * Copyright (c) 2013 by Donal Fellows.
- *
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
- */
-
-#include "tclInt.h"
-#include "tclCompile.h"
-#include <assert.h>
-
-/*
- * Forward declarations.
- */
-
-static void AdvanceJumps(CompileEnv *envPtr);
-static void ConvertZeroEffectToNOP(CompileEnv *envPtr);
-static void LocateTargetAddresses(CompileEnv *envPtr,
- Tcl_HashTable *tablePtr);
-static void TrimUnreachable(CompileEnv *envPtr);
-
-/*
- * Helper macros.
- */
-
-#define DefineTargetAddress(tablePtr, address) \
- ((void) Tcl_CreateHashEntry((tablePtr), (void *) (address), &isNew))
-#define IsTargetAddress(tablePtr, address) \
- (Tcl_FindHashEntry((tablePtr), (void *) (address)) != NULL)
-#define AddrLength(address) \
- (tclInstructionTable[*(unsigned char *)(address)].numBytes)
-#define InstLength(instruction) \
- (tclInstructionTable[(unsigned char)(instruction)].numBytes)
-
-/*
- * ----------------------------------------------------------------------
- *
- * LocateTargetAddresses --
- *
- * Populate a hash table with places that we need to be careful around
- * because they're the targets of various kinds of jumps and other
- * non-local behavior.
- *
- * ----------------------------------------------------------------------
- */
-
-static void
-LocateTargetAddresses(
- CompileEnv *envPtr,
- Tcl_HashTable *tablePtr)
-{
- unsigned char *currentInstPtr, *targetInstPtr;
- int isNew, i;
- Tcl_HashEntry *hPtr;
- Tcl_HashSearch hSearch;
-
- Tcl_InitHashTable(tablePtr, TCL_ONE_WORD_KEYS);
-
- /*
- * The starts of commands represent target addresses.
- */
-
- for (i=0 ; i<envPtr->numCommands ; i++) {
- DefineTargetAddress(tablePtr,
- envPtr->codeStart + envPtr->cmdMapPtr[i].codeOffset);
- }
-
- /*
- * Find places where we should be careful about replacing instructions
- * because they are the targets of various types of jumps.
- */
-
- for (currentInstPtr = envPtr->codeStart ;
- currentInstPtr < envPtr->codeNext ;
- currentInstPtr += AddrLength(currentInstPtr)) {
- switch (*currentInstPtr) {
- case INST_JUMP1:
- case INST_JUMP_TRUE1:
- case INST_JUMP_FALSE1:
- targetInstPtr = currentInstPtr+TclGetInt1AtPtr(currentInstPtr+1);
- goto storeTarget;
- case INST_JUMP4:
- case INST_JUMP_TRUE4:
- case INST_JUMP_FALSE4:
- case INST_START_CMD:
- targetInstPtr = currentInstPtr+TclGetInt4AtPtr(currentInstPtr+1);
- goto storeTarget;
- case INST_BEGIN_CATCH4:
- targetInstPtr = envPtr->codeStart + envPtr->exceptArrayPtr[
- TclGetUInt4AtPtr(currentInstPtr+1)].codeOffset;
- storeTarget:
- DefineTargetAddress(tablePtr, targetInstPtr);
- break;
- case INST_JUMP_TABLE:
- hPtr = Tcl_FirstHashEntry(
- &JUMPTABLEINFO(envPtr, currentInstPtr+1)->hashTable,
- &hSearch);
- for (; hPtr ; hPtr = Tcl_NextHashEntry(&hSearch)) {
- targetInstPtr = currentInstPtr +
- PTR2INT(Tcl_GetHashValue(hPtr));
- DefineTargetAddress(tablePtr, targetInstPtr);
- }
- break;
- case INST_RETURN_CODE_BRANCH:
- for (i=TCL_ERROR ; i<TCL_CONTINUE+1 ; i++) {
- DefineTargetAddress(tablePtr, currentInstPtr + 2*i - 1);
- }
- break;
- }
- }
-
- /*
- * Add a marker *after* the last bytecode instruction. WARNING: points to
- * one past the end!
- */
-
- DefineTargetAddress(tablePtr, currentInstPtr);
-
- /*
- * Enter in the targets of exception ranges.
- */
-
- for (i=0 ; i<envPtr->exceptArrayNext ; i++) {
- ExceptionRange *rangePtr = &envPtr->exceptArrayPtr[i];
-
- if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
- targetInstPtr = envPtr->codeStart + rangePtr->catchOffset;
- DefineTargetAddress(tablePtr, targetInstPtr);
- } else {
- targetInstPtr = envPtr->codeStart + rangePtr->breakOffset;
- DefineTargetAddress(tablePtr, targetInstPtr);
- if (rangePtr->continueOffset >= 0) {
- targetInstPtr = envPtr->codeStart + rangePtr->continueOffset;
- DefineTargetAddress(tablePtr, targetInstPtr);
- }
- }
- }
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TrimUnreachable --
- *
- * Converts code that provably can't be executed into NOPs and reduces
- * the overall reported length of the bytecode where that is possible.
- *
- * ----------------------------------------------------------------------
- */
-
-static void
-TrimUnreachable(
- CompileEnv *envPtr)
-{
- unsigned char *currentInstPtr;
- Tcl_HashTable targets;
-
- LocateTargetAddresses(envPtr, &targets);
-
- for (currentInstPtr = envPtr->codeStart ;
- currentInstPtr < envPtr->codeNext-1 ;
- currentInstPtr += AddrLength(currentInstPtr)) {
- int clear = 0;
-
- if (*currentInstPtr != INST_DONE) {
- continue;
- }
-
- while (!IsTargetAddress(&targets, currentInstPtr + 1 + clear)) {
- clear += AddrLength(currentInstPtr + 1 + clear);
- }
- if (currentInstPtr + 1 + clear == envPtr->codeNext) {
- envPtr->codeNext -= clear;
- } else {
- while (clear --> 0) {
- *(currentInstPtr + 1 + clear) = INST_NOP;
- }
- }
- }
-
- Tcl_DeleteHashTable(&targets);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * ConvertZeroEffectToNOP --
- *
- * Replace PUSH/POP sequences (when non-hazardous) with NOPs. Also
- * replace PUSH empty/STR_CONCAT and TRY_CVT_NUMERIC (when followed by an
- * operation that guarantees the check for arithmeticity) and eliminate
- * LNOT when we can invert the following JUMP condition.
- *
- * ----------------------------------------------------------------------
- */
-
-static void
-ConvertZeroEffectToNOP(
- CompileEnv *envPtr)
-{
- unsigned char *currentInstPtr;
- int size;
- Tcl_HashTable targets;
-
- LocateTargetAddresses(envPtr, &targets);
- for (currentInstPtr = envPtr->codeStart ;
- currentInstPtr < envPtr->codeNext ; currentInstPtr += size) {
- int blank = 0, i, nextInst;
-
- size = AddrLength(currentInstPtr);
- while ((currentInstPtr + size < envPtr->codeNext)
- && *(currentInstPtr+size) == INST_NOP) {
- if (IsTargetAddress(&targets, currentInstPtr + size)) {
- break;
- }
- size += InstLength(INST_NOP);
- }
- if (IsTargetAddress(&targets, currentInstPtr + size)) {
- continue;
- }
- nextInst = *(currentInstPtr + size);
- switch (*currentInstPtr) {
- case INST_PUSH1:
- if (nextInst == INST_POP) {
- blank = size + InstLength(nextInst);
- } else if (nextInst == INST_STR_CONCAT1
- && TclGetUInt1AtPtr(currentInstPtr + size + 1) == 2) {
- Tcl_Obj *litPtr = TclFetchLiteral(envPtr,
- TclGetUInt1AtPtr(currentInstPtr + 1));
- int numBytes;
-
- (void) Tcl_GetStringFromObj(litPtr, &numBytes);
- if (numBytes == 0) {
- blank = size + InstLength(nextInst);
- }
- }
- break;
- case INST_PUSH4:
- if (nextInst == INST_POP) {
- blank = size + 1;
- } else if (nextInst == INST_STR_CONCAT1
- && TclGetUInt1AtPtr(currentInstPtr + size + 1) == 2) {
- Tcl_Obj *litPtr = TclFetchLiteral(envPtr,
- TclGetUInt4AtPtr(currentInstPtr + 1));
- int numBytes;
-
- (void) Tcl_GetStringFromObj(litPtr, &numBytes);
- if (numBytes == 0) {
- blank = size + InstLength(nextInst);
- }
- }
- break;
-
- case INST_LNOT:
- switch (nextInst) {
- case INST_JUMP_TRUE1:
- blank = size;
- *(currentInstPtr + size) = INST_JUMP_FALSE1;
- break;
- case INST_JUMP_FALSE1:
- blank = size;
- *(currentInstPtr + size) = INST_JUMP_TRUE1;
- break;
- case INST_JUMP_TRUE4:
- blank = size;
- *(currentInstPtr + size) = INST_JUMP_FALSE4;
- break;
- case INST_JUMP_FALSE4:
- blank = size;
- *(currentInstPtr + size) = INST_JUMP_TRUE4;
- break;
- }
- break;
-
- case INST_TRY_CVT_TO_NUMERIC:
- switch (nextInst) {
- case INST_JUMP_TRUE1:
- case INST_JUMP_TRUE4:
- case INST_JUMP_FALSE1:
- case INST_JUMP_FALSE4:
- case INST_INCR_SCALAR1:
- case INST_INCR_ARRAY1:
- case INST_INCR_ARRAY_STK:
- case INST_INCR_SCALAR_STK:
- case INST_INCR_STK:
- case INST_LOR:
- case INST_LAND:
- case INST_EQ:
- case INST_NEQ:
- case INST_LT:
- case INST_LE:
- case INST_GT:
- case INST_GE:
- case INST_MOD:
- case INST_LSHIFT:
- case INST_RSHIFT:
- case INST_BITOR:
- case INST_BITXOR:
- case INST_BITAND:
- case INST_EXPON:
- case INST_ADD:
- case INST_SUB:
- case INST_DIV:
- case INST_MULT:
- case INST_LNOT:
- case INST_BITNOT:
- case INST_UMINUS:
- case INST_UPLUS:
- case INST_TRY_CVT_TO_NUMERIC:
- blank = size;
- break;
- }
- break;
- }
-
- if (blank > 0) {
- for (i=0 ; i<blank ; i++) {
- *(currentInstPtr + i) = INST_NOP;
- }
- size = blank;
- }
- }
- Tcl_DeleteHashTable(&targets);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * AdvanceJumps --
- *
- * Advance jumps past NOPs and chained JUMPs. After this runs, the only
- * JUMPs that jump to a NOP or a JUMP will be length-1 ones that run out
- * of room in their opcode to be targeted to where they really belong.
- *
- * ----------------------------------------------------------------------
- */
-
-static void
-AdvanceJumps(
- CompileEnv *envPtr)
-{
- unsigned char *currentInstPtr;
- Tcl_HashTable jumps;
-
- for (currentInstPtr = envPtr->codeStart ;
- currentInstPtr < envPtr->codeNext-1 ;
- currentInstPtr += AddrLength(currentInstPtr)) {
- int offset, delta, isNew;
-
- switch (*currentInstPtr) {
- case INST_JUMP1:
- case INST_JUMP_TRUE1:
- case INST_JUMP_FALSE1:
- offset = TclGetInt1AtPtr(currentInstPtr + 1);
- Tcl_InitHashTable(&jumps, TCL_ONE_WORD_KEYS);
- for (delta=0 ; offset+delta != 0 ;) {
- if (offset + delta < -128 || offset + delta > 127) {
- break;
- }
- Tcl_CreateHashEntry(&jumps, INT2PTR(offset), &isNew);
- if (!isNew) {
- offset = TclGetInt1AtPtr(currentInstPtr + 1);
- break;
- }
- offset += delta;
- switch (*(currentInstPtr + offset)) {
- case INST_NOP:
- delta = InstLength(INST_NOP);
- continue;
- case INST_JUMP1:
- delta = TclGetInt1AtPtr(currentInstPtr + offset + 1);
- continue;
- case INST_JUMP4:
- delta = TclGetInt4AtPtr(currentInstPtr + offset + 1);
- continue;
- }
- break;
- }
- Tcl_DeleteHashTable(&jumps);
- TclStoreInt1AtPtr(offset, currentInstPtr + 1);
- continue;
-
- case INST_JUMP4:
- case INST_JUMP_TRUE4:
- case INST_JUMP_FALSE4:
- Tcl_InitHashTable(&jumps, TCL_ONE_WORD_KEYS);
- Tcl_CreateHashEntry(&jumps, INT2PTR(0), &isNew);
- for (offset = TclGetInt4AtPtr(currentInstPtr + 1); offset!=0 ;) {
- Tcl_CreateHashEntry(&jumps, INT2PTR(offset), &isNew);
- if (!isNew) {
- offset = TclGetInt4AtPtr(currentInstPtr + 1);
- break;
- }
- switch (*(currentInstPtr + offset)) {
- case INST_NOP:
- offset += InstLength(INST_NOP);
- continue;
- case INST_JUMP1:
- offset += TclGetInt1AtPtr(currentInstPtr + offset + 1);
- continue;
- case INST_JUMP4:
- offset += TclGetInt4AtPtr(currentInstPtr + offset + 1);
- continue;
- }
- break;
- }
- Tcl_DeleteHashTable(&jumps);
- TclStoreInt4AtPtr(offset, currentInstPtr + 1);
- continue;
- }
- }
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TclOptimizeBytecode --
- *
- * A very simple peephole optimizer for bytecode.
- *
- * ----------------------------------------------------------------------
- */
-
-void
-TclOptimizeBytecode(
- void *envPtr)
-{
- ConvertZeroEffectToNOP(envPtr);
- AdvanceJumps(envPtr);
- TrimUnreachable(envPtr);
-}
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * tab-width: 8
- * End:
- */