summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--generic/tclAssembly.c576
-rw-r--r--tests/assemble.test34
3 files changed, 384 insertions, 235 deletions
diff --git a/ChangeLog b/ChangeLog
index 245ba99..92dcc28 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2010-10-24 Kevin B. Kenny <kennykb@acm.org>
+
+ [dogeen-assembler-branch]
+ * tclAssembly.c:
+ * assembly.test (assemble-17.15): Reworked branch handling so that
+ forward branches can use jump1 (jumpTrue1, jumpFalse1). Added test
+ cases that the forward branches will expand to jump4, jumpTrue4,
+ jumpFalse4 when needed.
+
2010-10-23 Kevin B. Kenny <kennykb@acm.org>
[dogeen-assembler-branch]
diff --git a/generic/tclAssembly.c b/generic/tclAssembly.c
index c773ee0..490ba4b 100644
--- a/generic/tclAssembly.c
+++ b/generic/tclAssembly.c
@@ -12,13 +12,11 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclAssembly.c,v 1.1.2.15 2010/10/23 16:14:24 kennykb Exp $
+ * RCS: @(#) $Id: tclAssembly.c,v 1.1.2.16 2010/10/24 01:46:42 kennykb Exp $
*/
/*-
*- THINGS TO DO:
- *- Rework jump handling to allow jump1, jumpTrue1, jumpFalse1 in the
- *- forward direction
*- More instructions:
*- done - alternate exit point (affects stack and exception range checking)
*- break and continue - if exception ranges can be sorted out.
@@ -30,6 +28,7 @@
*- jumpTable
*- syntax (?)
*- returnCodeBranch
+ *- enterCatch/leaveCatch
*/
#include "tclInt.h"
@@ -64,13 +63,19 @@ typedef enum BasicBlockCatchState {
typedef struct BasicBlock {
+ int originalStartOffset; /* Instruction offset before JUMP1s
+ * were substituted with JUMP4's */
int startOffset; /* Instruction offset of the start of
* the block */
int startLine; /* Line number in the input script of the
* instruction at the start of the block */
+ int jumpOffset; /* Bytecode offset of the 'jump' instruction
+ * that ends the block, or -1 if there is no
+ * jump. */
int jumpLine; /* Line number in the input script of the
* 'jump' instruction that ends the block,
* or -1 if there is no jump */
+ struct BasicBlock* prevPtr; /* Immediate predecessor of this block */
struct BasicBlock* predecessor;
/* Predecessor of this block in the
* spanning tree */
@@ -115,15 +120,17 @@ enum BasicBlockFlags {
* traversal */
BB_FALLTHRU = (1 << 1), /* Control may pass from this block to
* a successor */
- BB_BEGINCATCH = (1 << 2), /* Block ends with a 'beginCatch' instruction,
+ BB_JUMP1 = (1 << 2), /* Basic block ends with a 1-byte-offset
+ * jump and may need expansion */
+ BB_BEGINCATCH = (1 << 3), /* Block ends with a 'beginCatch' instruction,
* marking it as the start of a 'catch'
* sequence. The 'jumpTarget' is the exception
* exit from the catch block. */
- BB_DONECATCH = (1 << 3), /* Block commences with a 'doneCatch'
+ BB_DONECATCH = (1 << 4), /* Block commences with a 'doneCatch'
* directive, indicating that the program
* is finished with the body of a catch block.
*/
- BB_ENDCATCH = (1 << 4), /* Block ends with an 'endCatch' instruction,
+ BB_ENDCATCH = (1 << 5), /* Block ends with an 'endCatch' instruction,
* unwinding the catch from the exception
* stack. */
};
@@ -158,6 +165,7 @@ typedef enum TalInstType {
ASSEM_INVOKE, /* 1- or 4-byte operand count, must be strictly positive,
* consumes N, produces 1. */
ASSEM_JUMP, /* Jump instructions */
+ ASSEM_JUMP4, /* Jump instructions forcing a 4-byte offset */
ASSEM_LABEL, /* The assembly directive that defines a label */
ASSEM_LINDEX_MULTI,
/* 4-byte operand count, must be strictly positive,
@@ -199,19 +207,9 @@ typedef struct TalInstDesc {
* -1-operandsProduced */
} TalInstDesc;
-/* Description of a label in the assembly code */
-
-typedef struct JumpLabel {
- int isDefined; /* Flag == 1 if label is defined */
- int offset; /* Offset in the code where the label starts,
- * or head of a linked list of jump target
- * addresses if the label is undefined */
- BasicBlock* basicBlock; /* Basic block that begins at the label */
-} JumpLabel;
-
/* Structure that holds the state of the assembler while generating code */
-typedef struct AssembleEnv {
+typedef struct AssemblyEnv {
CompileEnv* envPtr; /* Compilation environment being used
* for code generation */
Tcl_Parse* parsePtr; /* Parse of the current line of source */
@@ -233,61 +231,62 @@ typedef struct AssembleEnv {
int maxCatchDepth; /* Maximum depth of catches encountered */
int flags; /* Compilation flags (TCL_EVAL_DIRECT) */
-} AssembleEnv;
+} AssemblyEnv;
/* Static functions defined in this file */
-static void AddBasicBlockRangeToErrorInfo(AssembleEnv*, BasicBlock*);
-static BasicBlock * AllocBB(AssembleEnv*);
-static int AssembleOneLine(AssembleEnv* envPtr);
+static void AddBasicBlockRangeToErrorInfo(AssemblyEnv*, BasicBlock*);
+static BasicBlock * AllocBB(AssemblyEnv*);
+static int AssembleOneLine(AssemblyEnv* envPtr);
static void BBAdjustStackDepth(BasicBlock* bbPtr, int consumed, int produced);
static void BBUpdateStackReqs(BasicBlock* bbPtr, int tblind, int count);
-static void BBEmitInstInt1(AssembleEnv* assemEnvPtr, int tblind,
+static void BBEmitInstInt1(AssemblyEnv* assemEnvPtr, int tblind,
unsigned char opnd, int count);
-static void BBEmitInstInt4(AssembleEnv* assemEnvPtr, int tblind, int opnd,
+static void BBEmitInstInt4(AssemblyEnv* assemEnvPtr, int tblind, int opnd,
int count);
-static void BBEmitInst1or4(AssembleEnv* assemEnvPtr, int tblind, int param,
+static void BBEmitInst1or4(AssemblyEnv* assemEnvPtr, int tblind, int param,
int count);
-static void BBEmitOpcode(AssembleEnv* assemEnvPtr, int tblind, int count);
-static int BuildExceptionRanges(AssembleEnv* assemEnvPtr);
-static int CheckForUnclosedCatches(AssembleEnv*);
+static void BBEmitOpcode(AssemblyEnv* assemEnvPtr, int tblind, int count);
+static int BuildExceptionRanges(AssemblyEnv* assemEnvPtr);
+static int CalculateJumpRelocations(AssemblyEnv*, int*);
+static int CheckForUnclosedCatches(AssemblyEnv*);
static int CheckNamespaceQualifiers(Tcl_Interp*, const char*, int);
static int CheckNonNegative(Tcl_Interp*, int);
static int CheckOneByte(Tcl_Interp*, int);
static int CheckSignedOneByte(Tcl_Interp*, int);
-static int CheckStack(AssembleEnv*);
+static int CheckStack(AssemblyEnv*);
static int CheckStrictlyPositive(Tcl_Interp*, int);
-static int CheckUndefinedLabels(AssembleEnv*);
static ByteCode * CompileAssembleObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
-static void CompileEmbeddedScript(AssembleEnv*, Tcl_Token*, TalInstDesc*);
-static int DefineLabel(AssembleEnv* envPtr, const char* label);
+static void CompileEmbeddedScript(AssemblyEnv*, Tcl_Token*, TalInstDesc*);
+static int DefineLabel(AssemblyEnv* envPtr, const char* label);
static void DupAssembleCodeInternalRep(Tcl_Obj* src, Tcl_Obj* dest);
-static JumpLabel* FindLabel(AssembleEnv* envPtr, Tcl_Obj* name);
-static int FindLocalVar(AssembleEnv* envPtr, Tcl_Token** tokenPtrPtr);
-static int FinishAssembly(AssembleEnv*);
+static void FillInJumpOffsets(AssemblyEnv*);
+static int FindLocalVar(AssemblyEnv* envPtr, Tcl_Token** tokenPtrPtr);
+static int FinishAssembly(AssemblyEnv*);
static void FreeAssembleCodeInternalRep(Tcl_Obj *objPtr);
-static void FreeAssembleEnv(AssembleEnv*);
-static int GetBooleanOperand(AssembleEnv*, Tcl_Token**, int*);
-static int GetListIndexOperand(AssembleEnv*, Tcl_Token**, int*);
-static int GetIntegerOperand(AssembleEnv*, Tcl_Token**, int*);
-static int GetNextOperand(AssembleEnv*, Tcl_Token**, Tcl_Obj**);
+static void FreeAssemblyEnv(AssemblyEnv*);
+static int GetBooleanOperand(AssemblyEnv*, Tcl_Token**, int*);
+static int GetListIndexOperand(AssemblyEnv*, Tcl_Token**, int*);
+static int GetIntegerOperand(AssemblyEnv*, Tcl_Token**, int*);
+static int GetNextOperand(AssemblyEnv*, Tcl_Token**, Tcl_Obj**);
static void LookForFreshCatches(BasicBlock*, BasicBlock**);
-static void MoveExceptionRangesToBasicBlock(AssembleEnv*, int, int);
-static AssembleEnv* NewAssembleEnv(CompileEnv*, int);
-static int ProcessCatches(AssembleEnv*);
-static int ProcessCatchesInBasicBlock(AssembleEnv*, BasicBlock*, BasicBlock*,
+static void MoveCodeForJumps(AssemblyEnv*, int);
+static void MoveExceptionRangesToBasicBlock(AssemblyEnv*, int, int);
+static AssemblyEnv* NewAssemblyEnv(CompileEnv*, int);
+static int ProcessCatches(AssemblyEnv*);
+static int ProcessCatchesInBasicBlock(AssemblyEnv*, BasicBlock*, BasicBlock*,
enum BasicBlockCatchState, int);
-static void ResetVisitedBasicBlocks(AssembleEnv*);
-static void RestoreEmbeddedExceptionRanges(AssembleEnv*);
-static int StackCheckBasicBlock(AssembleEnv*, BasicBlock *, BasicBlock *, int);
-static BasicBlock* StartBasicBlock(AssembleEnv*, int fallthrough,
+static void ResetVisitedBasicBlocks(AssemblyEnv*);
+static void RestoreEmbeddedExceptionRanges(AssemblyEnv*);
+static int StackCheckBasicBlock(AssemblyEnv*, BasicBlock *, BasicBlock *, int);
+static BasicBlock* StartBasicBlock(AssemblyEnv*, int fallthrough,
Tcl_Obj* jumpLabel);
/* static int AdvanceIp(const unsigned char *pc); */
-static int StackCheckBasicBlock(AssembleEnv*, BasicBlock *, BasicBlock *, int);
-static int StackCheckExit(AssembleEnv*);
-static void StackFreshCatches(AssembleEnv*, BasicBlock*, int, BasicBlock**,
+static int StackCheckBasicBlock(AssemblyEnv*, BasicBlock *, BasicBlock *, int);
+static int StackCheckExit(AssemblyEnv*);
+static void StackFreshCatches(AssemblyEnv*, BasicBlock*, int, BasicBlock**,
int*);
-static void SyncStackDepth(AssembleEnv*);
+static void SyncStackDepth(AssemblyEnv*);
static int TclAssembleCode(CompileEnv* envPtr, const char* code, int codeLen,
int flags);
static void UnstackExpiredCatches(CompileEnv*, BasicBlock*, int,
@@ -384,12 +383,12 @@ TalInstDesc TalInstructionTable[] = {
1, 1},
{"invokeStk", ASSEM_INVOKE, (INST_INVOKE_STK1 << 8
| INST_INVOKE_STK4), INT_MIN,1},
- {"jump", ASSEM_JUMP, (INST_JUMP1 << 8
- | INST_JUMP4), 0, 0},
- {"jumpFalse", ASSEM_JUMP, (INST_JUMP_FALSE1 << 8
- | INST_JUMP_FALSE4), 1, 0},
- {"jumpTrue", ASSEM_JUMP, (INST_JUMP_TRUE1 << 8
- | INST_JUMP_TRUE4), 1, 0},
+ {"jump", ASSEM_JUMP, INST_JUMP1, 0, 0},
+ {"jump4", ASSEM_JUMP4, INST_JUMP4, 0, 0},
+ {"jumpFalse", ASSEM_JUMP, INST_JUMP_FALSE1, 1, 0},
+ {"jumpFalse4", ASSEM_JUMP4, INST_JUMP_FALSE4, 1, 0},
+ {"jumpTrue", ASSEM_JUMP, INST_JUMP_TRUE1, 1, 0},
+ {"jumpTrue4", ASSEM_JUMP4, INST_JUMP_TRUE4, 1, 0},
{"label", ASSEM_LABEL, 0, 0, 0},
{"land", ASSEM_1BYTE , INST_LAND , 2 , 1},
{"lappend", ASSEM_LVT, (INST_LAPPEND_SCALAR1<<8
@@ -564,7 +563,7 @@ BBUpdateStackReqs(BasicBlock* bbPtr,
*/
static void
-BBEmitOpcode(AssembleEnv* assemEnvPtr,
+BBEmitOpcode(AssemblyEnv* assemEnvPtr,
/* Assembly environment */
int tblind, /* Table index in TalInstructionTable of op */
int count) /* Operand count for variadic ops */
@@ -587,7 +586,7 @@ BBEmitOpcode(AssembleEnv* assemEnvPtr,
BBUpdateStackReqs(bbPtr, tblind, count);
}
static void
-BBEmitInstInt1(AssembleEnv* assemEnvPtr,
+BBEmitInstInt1(AssemblyEnv* assemEnvPtr,
/* Assembly environment */
int tblind, /* Index in TalInstructionTable of op */
unsigned char opnd,
@@ -598,7 +597,7 @@ BBEmitInstInt1(AssembleEnv* assemEnvPtr,
TclEmitInt1(opnd, assemEnvPtr->envPtr);
}
static void
-BBEmitInstInt4(AssembleEnv* assemEnvPtr,
+BBEmitInstInt4(AssemblyEnv* assemEnvPtr,
/* Assembly environment */
int tblind, /* Index in TalInstructionTable of op */
int opnd, /* 4-byte operand */
@@ -620,7 +619,7 @@ BBEmitInstInt4(AssembleEnv* assemEnvPtr,
*/
static void
-BBEmitInst1or4(AssembleEnv* assemEnvPtr,
+BBEmitInst1or4(AssemblyEnv* assemEnvPtr,
/* Assembly environment */
int tblind, /* Index in TalInstructionTable of op */
int param, /* Variable-length parameter */
@@ -921,7 +920,7 @@ TclAssembleCode(CompileEnv *envPtr,
* to be parsed */
int status; /* Tcl status return */
- AssembleEnv* assemEnvPtr = NewAssembleEnv(envPtr, flags);
+ AssemblyEnv* assemEnvPtr = NewAssemblyEnv(envPtr, flags);
Tcl_Parse* parsePtr = assemEnvPtr->parsePtr;
do {
@@ -941,7 +940,7 @@ TclAssembleCode(CompileEnv *envPtr,
Tcl_LogCommandInfo(interp, codePtr, parsePtr->commandStart,
instLen);
}
- FreeAssembleEnv(assemEnvPtr);
+ FreeAssemblyEnv(assemEnvPtr);
return TCL_ERROR;
}
@@ -958,8 +957,9 @@ TclAssembleCode(CompileEnv *envPtr,
/* If tracing, show each line assembled as it happens */
#ifdef TCL_COMPILE_DEBUG
- if ((tclTraceCompile >= 1) && (envPtr->procPtr == NULL)) {
- printf(" Assembling: ");
+ if ((tclTraceCompile >= 2) && (envPtr->procPtr == NULL)) {
+ printf(" %4d Assembling: ",
+ envPtr->codeNext - envPtr->codeStart);
TclPrintSource(stdout, parsePtr->commandStart,
TclMin(instLen, 55));
printf("\n");
@@ -971,7 +971,7 @@ TclAssembleCode(CompileEnv *envPtr,
instLen);
}
Tcl_FreeParse(parsePtr);
- FreeAssembleEnv(assemEnvPtr);
+ FreeAssemblyEnv(assemEnvPtr);
return TCL_ERROR;
}
}
@@ -990,14 +990,14 @@ TclAssembleCode(CompileEnv *envPtr,
/* Done with parsing the code */
status = FinishAssembly(assemEnvPtr);
- FreeAssembleEnv(assemEnvPtr);
+ FreeAssemblyEnv(assemEnvPtr);
return status;
}
/*
*-----------------------------------------------------------------------------
*
- * NewAssembleEnv --
+ * NewAssemblyEnv --
*
* Creates an environment for the assembler to run in.
*
@@ -1007,15 +1007,15 @@ TclAssembleCode(CompileEnv *envPtr,
*-----------------------------------------------------------------------------
*/
-static AssembleEnv*
-NewAssembleEnv(CompileEnv* envPtr,
+static AssemblyEnv*
+NewAssemblyEnv(CompileEnv* envPtr,
/* Compilation environment being used
* for code generation*/
int flags) /* Compilation flags (TCL_EVAL_DIRECT) */
{
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
- AssembleEnv* assemEnvPtr = TclStackAlloc(interp, sizeof(AssembleEnv));
+ AssemblyEnv* assemEnvPtr = TclStackAlloc(interp, sizeof(AssemblyEnv));
/* Assembler environment under construction */
Tcl_Parse* parsePtr = TclStackAlloc(interp, sizeof(Tcl_Parse));
/* Parse of one line of assembly code */
@@ -1031,6 +1031,7 @@ NewAssembleEnv(CompileEnv* envPtr,
/* Start the first basic block */
+ assemEnvPtr->curr_bb = NULL;
assemEnvPtr->head_bb = AllocBB(assemEnvPtr);
assemEnvPtr->curr_bb = assemEnvPtr->head_bb;
assemEnvPtr->head_bb->startLine = 1;
@@ -1045,7 +1046,7 @@ NewAssembleEnv(CompileEnv* envPtr,
/*
*-----------------------------------------------------------------------------
*
- * FreeAssembleEnv --
+ * FreeAssemblyEnv --
*
* Cleans up the assembler environment when assembly is complete.
*
@@ -1053,7 +1054,7 @@ NewAssembleEnv(CompileEnv* envPtr,
*/
static void
-FreeAssembleEnv(AssembleEnv* assemEnvPtr)
+FreeAssemblyEnv(AssemblyEnv* assemEnvPtr)
/* Environment to free */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
@@ -1067,7 +1068,6 @@ FreeAssembleEnv(AssembleEnv* assemEnvPtr)
* successor */
Tcl_HashEntry* hashEntry;
Tcl_HashSearch hashSearch;
- JumpLabel* labelPtr;
/* Free all the basic block structures */
for (thisBB = assemEnvPtr->head_bb; thisBB != NULL; thisBB = nextBB) {
@@ -1081,14 +1081,11 @@ FreeAssembleEnv(AssembleEnv* assemEnvPtr)
ckfree((char*)thisBB);
}
- /* Free all the labels */
+ /* Free the label hash */
while ((hashEntry = Tcl_FirstHashEntry(&assemEnvPtr->labelHash,
&hashSearch)) != NULL) {
- labelPtr = (JumpLabel*) Tcl_GetHashValue(hashEntry);
- ckfree((char*) labelPtr);
Tcl_DeleteHashEntry(hashEntry);
}
- Tcl_DeleteHashTable(&assemEnvPtr->labelHash);
TclStackFree(interp, assemEnvPtr->parsePtr);
TclStackFree(interp, assemEnvPtr);
@@ -1110,7 +1107,7 @@ FreeAssembleEnv(AssembleEnv* assemEnvPtr)
*/
static int
-AssembleOneLine(AssembleEnv* assemEnvPtr)
+AssembleOneLine(AssemblyEnv* assemEnvPtr)
/* State of the assembly */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
@@ -1130,11 +1127,10 @@ AssembleOneLine(AssembleEnv* assemEnvPtr)
/* First operand to the instruction */
const char* operand1; /* String rep of the operand */
int operand1Len; /* String length of the operand */
- JumpLabel* l; /* Structure descibing a label in the
- * assembly code */
int opnd; /* Integer representation of an operand */
int litIndex; /* Literal pool index of a constant */
int localVar; /* LVT index of a local variable */
+ int flags; /* Flags for a basic block */
int status = TCL_ERROR; /* Return value from this function */
/* Make sure that the instruction name is known at compile time. */
@@ -1195,10 +1191,11 @@ AssembleOneLine(AssembleEnv* assemEnvPtr)
if (GetNextOperand(assemEnvPtr, &tokenPtr, &operand1Obj) != TCL_OK) {
goto cleanup;
}
- FindLabel(assemEnvPtr, operand1Obj);
+ assemEnvPtr->curr_bb->jumpLine = assemEnvPtr->cmdLine;
+ assemEnvPtr->curr_bb->jumpOffset = envPtr->codeNext - envPtr->codeStart;
BBEmitInstInt4(assemEnvPtr, tblind, 0, 0);
assemEnvPtr->curr_bb->flags |= BB_BEGINCATCH;
- StartBasicBlock(assemEnvPtr, 1, operand1Obj);
+ StartBasicBlock(assemEnvPtr, BB_FALLTHRU, operand1Obj);
break;
case ASSEM_BOOL:
@@ -1279,7 +1276,7 @@ AssembleOneLine(AssembleEnv* assemEnvPtr)
break;
case ASSEM_DONECATCH:
- StartBasicBlock(assemEnvPtr, 0, NULL);
+ StartBasicBlock(assemEnvPtr, BB_FALLTHRU, NULL);
assemEnvPtr->curr_bb->flags |= BB_DONECATCH;
break;
@@ -1290,7 +1287,7 @@ AssembleOneLine(AssembleEnv* assemEnvPtr)
}
assemEnvPtr->curr_bb->flags |= BB_ENDCATCH;
BBEmitOpcode(assemEnvPtr, tblind, 0);
- StartBasicBlock(assemEnvPtr, 1, NULL);
+ StartBasicBlock(assemEnvPtr, BB_FALLTHRU, NULL);
break;
case ASSEM_EVAL:
@@ -1334,6 +1331,7 @@ AssembleOneLine(AssembleEnv* assemEnvPtr)
break;
case ASSEM_JUMP:
+ case ASSEM_JUMP4:
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "label");
goto cleanup;
@@ -1341,23 +1339,22 @@ AssembleOneLine(AssembleEnv* assemEnvPtr)
if (GetNextOperand(assemEnvPtr, &tokenPtr, &operand1Obj) != TCL_OK) {
goto cleanup;
}
- l = FindLabel(assemEnvPtr, operand1Obj);
- if (l->isDefined) {
- BBEmitInst1or4(assemEnvPtr, tblind,
- l->offset - (envPtr->codeNext - envPtr->codeStart),
- 0);
+ assemEnvPtr->curr_bb->jumpOffset = envPtr->codeNext - envPtr->codeStart;
+ if (instType == ASSEM_JUMP) {
+ flags = BB_JUMP1;
+ BBEmitInstInt1(assemEnvPtr, tblind, 0, 0);
} else {
- int here = envPtr->codeNext - envPtr->codeStart;
- BBEmitInstInt4(assemEnvPtr, tblind, l->offset, 0);
- l->offset = here;
+ flags = 0;
+ BBEmitInstInt4(assemEnvPtr, tblind, 0, 0);
}
/* Start a new basic block at the instruction following the jump */
assemEnvPtr->curr_bb->jumpLine = assemEnvPtr->cmdLine;
- StartBasicBlock(assemEnvPtr,
- (TalInstructionTable[tblind].operandsConsumed != 0),
- operand1Obj);
+ if (TalInstructionTable[tblind].operandsConsumed != 0) {
+ flags |= BB_FALLTHRU;
+ }
+ StartBasicBlock(assemEnvPtr, flags, operand1Obj);
break;
@@ -1586,7 +1583,7 @@ AssembleOneLine(AssembleEnv* assemEnvPtr)
*/
static void
-CompileEmbeddedScript(AssembleEnv* assemEnvPtr,
+CompileEmbeddedScript(AssemblyEnv* assemEnvPtr,
/* Assembler environment */
Tcl_Token* tokenPtr,
/* Tcl_Token containing the script */
@@ -1619,7 +1616,7 @@ CompileEmbeddedScript(AssembleEnv* assemEnvPtr,
envPtr->currStackDepth = 0;
envPtr->maxStackDepth = 0;
- StartBasicBlock(assemEnvPtr, 1, NULL);
+ StartBasicBlock(assemEnvPtr, BB_FALLTHRU, NULL);
switch(instPtr->tclInstCode) {
case INST_EVAL_STK:
TclCompileScript(interp, tokenPtr->start, tokenPtr->size, envPtr);
@@ -1650,7 +1647,7 @@ CompileEmbeddedScript(AssembleEnv* assemEnvPtr,
/* Flush the current basic block */
- StartBasicBlock(assemEnvPtr, 1, NULL);
+ StartBasicBlock(assemEnvPtr, BB_FALLTHRU, NULL);
}
/*
@@ -1674,7 +1671,7 @@ CompileEmbeddedScript(AssembleEnv* assemEnvPtr,
*/
static void
-SyncStackDepth(AssembleEnv* assemEnvPtr)
+SyncStackDepth(AssemblyEnv* assemEnvPtr)
/* Assembly environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
@@ -1704,7 +1701,7 @@ SyncStackDepth(AssembleEnv* assemEnvPtr)
*/
static void
-MoveExceptionRangesToBasicBlock(AssembleEnv* assemEnvPtr,
+MoveExceptionRangesToBasicBlock(AssemblyEnv* assemEnvPtr,
/* Assembler environment */
int savedCodeIndex,
/* Start of the embedded code */
@@ -1772,7 +1769,7 @@ MoveExceptionRangesToBasicBlock(AssembleEnv* assemEnvPtr,
*/
static int
-GetNextOperand(AssembleEnv* assemEnvPtr,
+GetNextOperand(AssemblyEnv* assemEnvPtr,
/* Assembler environment */
Tcl_Token** tokenPtrPtr,
/* INPUT/OUTPUT: Pointer to the token
@@ -1820,7 +1817,7 @@ GetNextOperand(AssembleEnv* assemEnvPtr,
*/
static int
-GetBooleanOperand(AssembleEnv* assemEnvPtr,
+GetBooleanOperand(AssemblyEnv* assemEnvPtr,
/* Assembly environment */
Tcl_Token** tokenPtrPtr,
/* Current token from the parser */
@@ -1874,7 +1871,7 @@ GetBooleanOperand(AssembleEnv* assemEnvPtr,
*/
static int
-GetIntegerOperand(AssembleEnv* assemEnvPtr,
+GetIntegerOperand(AssemblyEnv* assemEnvPtr,
/* Assembly environment */
Tcl_Token** tokenPtrPtr,
/* Current token from the parser */
@@ -1929,7 +1926,7 @@ GetIntegerOperand(AssembleEnv* assemEnvPtr,
static int
GetListIndexOperand(
- AssembleEnv* assemEnvPtr,
+ AssemblyEnv* assemEnvPtr,
/* Assembly environment */
Tcl_Token** tokenPtrPtr,
/* Current token from the parser */
@@ -1986,7 +1983,7 @@ GetListIndexOperand(
*/
static int
-FindLocalVar(AssembleEnv* assemEnvPtr,
+FindLocalVar(AssemblyEnv* assemEnvPtr,
Tcl_Token** tokenPtrPtr)
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
@@ -2213,7 +2210,7 @@ CheckStrictlyPositive(Tcl_Interp* interp,
*/
static int
-DefineLabel(AssembleEnv* assemEnvPtr, /* Assembly environment */
+DefineLabel(AssemblyEnv* assemEnvPtr, /* Assembly environment */
const char* labelName) /* Label being defined */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
@@ -2223,11 +2220,11 @@ DefineLabel(AssembleEnv* assemEnvPtr, /* Assembly environment */
Tcl_HashEntry* entry; /* Label's entry in the symbol table */
int isNew; /* Flag == 1 iff the label was previously
* undefined */
- JumpLabel* l; /* 'JumpLabel' struct describing the
- * newly defined label */
Tcl_Obj* result; /* Error message */
- StartBasicBlock(assemEnvPtr, 1, NULL);
+ /* TODO - This can now be simplified! */
+
+ StartBasicBlock(assemEnvPtr, BB_FALLTHRU, NULL);
/* Look up the newly-defined label in the symbol table */
@@ -2236,84 +2233,26 @@ DefineLabel(AssembleEnv* assemEnvPtr, /* Assembly environment */
/* This is the first appearance of the label in the code */
- l = (JumpLabel*)ckalloc(sizeof(JumpLabel));
- l->isDefined = 1;
- l->offset = envPtr->codeNext - envPtr->codeStart;
- l->basicBlock = assemEnvPtr->curr_bb;
- Tcl_SetHashValue(entry, l);
+ Tcl_SetHashValue(entry, assemEnvPtr->curr_bb);
} else {
- /* The label has appeared earlier. Make sure that it's not defined. */
-
- l = (JumpLabel*) Tcl_GetHashValue(entry);
- if (l->isDefined) {
- if (assemEnvPtr-> flags & (TCL_EVAL_DIRECT)) {
- result = Tcl_NewStringObj("duplicate definition "
- "of label \"", -1);
- Tcl_AppendToObj(result, labelName, -1);
- Tcl_AppendToObj(result, "\"", -1);
- Tcl_SetObjResult(interp, result);
- Tcl_SetErrorCode(interp, "TCL", "ASSEM", "DUPLABEL",
- labelName, NULL);
- }
- return TCL_ERROR;
- } else {
+ /* This is a duplicate label */
- /*
- * Walk the linked list of previous references to the label
- * and fix them up.
- */
-
- int jump = l->offset;
- while (jump >= 0) {
- int prevJump = TclGetInt4AtPtr(envPtr->codeStart + jump + 1);
- TclStoreInt4AtPtr(envPtr->codeNext - envPtr->codeStart - jump,
- envPtr->codeStart + jump + 1);
- jump = prevJump;
- }
- l->offset = envPtr->codeNext - envPtr->codeStart;
- l->basicBlock = assemEnvPtr->curr_bb;
- l->isDefined = 1;
- }
+ if (assemEnvPtr-> flags & (TCL_EVAL_DIRECT)) {
+ result = Tcl_NewStringObj("duplicate definition "
+ "of label \"", -1);
+ Tcl_AppendToObj(result, labelName, -1);
+ Tcl_AppendToObj(result, "\"", -1);
+ Tcl_SetObjResult(interp, result);
+ Tcl_SetErrorCode(interp, "TCL", "ASSEM", "DUPLABEL",
+ labelName, NULL);
+ }
+ return TCL_ERROR;
}
return TCL_OK;
}
-/*
- *-----------------------------------------------------------------------------
- *
- * FindLabel --
- *
- * Find a named label in the bytecode.
- *
- * Results:
- * Returns a pointer to the label. If the label is not known, an
- * undefined placeholder is created for it.
- *
- *-----------------------------------------------------------------------------
- */
-
-static JumpLabel*
-FindLabel(AssembleEnv* assemEnvPtr,
- /* Assembler environment */
- Tcl_Obj* name) /* Name of the label */
-{
- int isNew; /* Flag == 1 iff the label is undefined */
- JumpLabel* l; /* Label structure for an undefined label */
- Tcl_HashEntry* entry =
- Tcl_CreateHashEntry(&assemEnvPtr->labelHash,
- Tcl_GetString(name), &isNew);
- if (isNew) {
- l = (JumpLabel*) ckalloc(sizeof(JumpLabel));
- l -> isDefined = 0;
- l -> offset = -1;
- Tcl_SetHashValue(entry, l);
- } else {
- l = Tcl_GetHashValue(entry);
- }
- return l;
-}
/*
*-----------------------------------------------------------------------------
@@ -2330,11 +2269,10 @@ FindLabel(AssembleEnv* assemEnvPtr,
*/
static BasicBlock*
-StartBasicBlock(AssembleEnv* assemEnvPtr,
+StartBasicBlock(AssemblyEnv* assemEnvPtr,
/* Assembly environment */
- int fallsThrough,
- /* 1 if execution falls through into
- * the following block, 0 otherwise */
+ int flags, /* Flags to apply to the basic block
+ * being closed, if there is one. */
Tcl_Obj* jumpLabel)
/* Label of the location that the
* block jumps to, or NULL if the block
@@ -2364,9 +2302,7 @@ StartBasicBlock(AssembleEnv* assemEnvPtr,
/* Record the fallthrough if there is one. */
- if (fallsThrough) {
- currBB->flags |= BB_FALLTHRU;
- }
+ currBB->flags |= flags;
/* Record the successor block */
@@ -2390,15 +2326,18 @@ StartBasicBlock(AssembleEnv* assemEnvPtr,
*/
static BasicBlock *
-AllocBB(AssembleEnv* assemEnvPtr)
+AllocBB(AssemblyEnv* assemEnvPtr)
/* Assembly environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
BasicBlock * bb = (BasicBlock *) ckalloc(sizeof(BasicBlock));
- bb->startOffset = envPtr->codeNext - envPtr->codeStart;
+ bb->originalStartOffset =
+ bb->startOffset = envPtr->codeNext - envPtr->codeStart;
bb->startLine = assemEnvPtr->cmdLine + 1;
+ bb->jumpOffset = -1;
bb->jumpLine = -1;
+ bb->prevPtr = assemEnvPtr->curr_bb;
bb->predecessor = NULL;
bb->successor1 = NULL;
bb->jumpTarget = NULL;
@@ -2437,16 +2376,32 @@ AllocBB(AssembleEnv* assemEnvPtr)
*/
static int
-FinishAssembly(AssembleEnv* assemEnvPtr)
+FinishAssembly(AssemblyEnv* assemEnvPtr)
/* Assembly environment */
{
- /* Make sure there are no undefined labels */
+ int mustMove; /* Amount by which the code needs to be
+ * grown because of expanding jumps */
- if (CheckUndefinedLabels(assemEnvPtr) != TCL_OK) {
+ /*
+ * Resolve the targets of all jumps and determine whether code needs
+ * to be moved around.
+ */
+
+ if (CalculateJumpRelocations(assemEnvPtr, &mustMove)) {
return TCL_ERROR;
}
+ /* Move the code if necessary */
+
+ if (mustMove) {
+ MoveCodeForJumps(assemEnvPtr, mustMove);
+ }
+
+ /* Resolve jump target labels to bytecode offsets */
+
+ FillInJumpOffsets(assemEnvPtr);
+
/* Label each basic block with its catch context. Quit on inconsistency */
if (ProcessCatches(assemEnvPtr) != TCL_OK) {
@@ -2468,21 +2423,37 @@ FinishAssembly(AssembleEnv* assemEnvPtr)
/*
*-----------------------------------------------------------------------------
*
- * CheckUndefinedLabels --
+ * CalculateJumpRelocations --
*
- * Check to make sure that the assembly code contains no undefined
- * labels.
+ * Calculate any movement that has to be done in the assembly code to
+ * expand JUMP1 instructions to JUMP4 (because they jump more than
+ * a 1-byte range).
*
* Results:
* Returns a standard Tcl result, with an appropriate error message
- * if undefined labels exist.
+ * if anything fails.
+ *
+ * Side effects:
+ * Sets the 'startOffset' pointer in every basic block to the new
+ * origin of the block, and turns off JUMP1 flags on instructions that
+ * must be expanded (and adjusts them to the corresponding JUMP4's)
+ * Does *not* store the jump offsets at this point.
+ *
+ * Sets *mustMove to 1 if and only if at least one instruction changed
+ * size so the code must be moved.
+ *
+ * As a side effect, also checks for undefined labels
+ * and reports them.
*
*-----------------------------------------------------------------------------
*/
-
+
static int
-CheckUndefinedLabels(AssembleEnv* assemEnvPtr)
- /* Assembly environment */
+CalculateJumpRelocations(AssemblyEnv* assemEnvPtr,
+ /* Assembler environment */
+ int* mustMove)
+ /* OUTPUT: Number of bytes that have been
+ * added to the code */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
@@ -2490,16 +2461,38 @@ CheckUndefinedLabels(AssembleEnv* assemEnvPtr)
/* Tcl interpreter */
BasicBlock* bbPtr; /* Pointer to a basic block being checked */
Tcl_HashEntry* entry; /* Exit label's entry in the symbol table */
- JumpLabel* l; /* Exit label of the block */
+ BasicBlock* jumpTarget; /* Basic block where the jump goes */
Tcl_Obj* result; /* Error message */
+ int motion; /* Amount by which the code has expanded */
+ int offset; /* Offset in the bytecode from a jump
+ * instruction to its target */
+ unsigned opcode; /* Opcode in the bytecode being adjusted */
- for (bbPtr = assemEnvPtr->head_bb; bbPtr != NULL; bbPtr=bbPtr->successor1)
- {
+ /* Iterate through basic blocks as long as a change results in
+ * code expansion */
+
+ *mustMove = 0;
+ do {
+ motion = 0;
+ for (bbPtr = assemEnvPtr->head_bb;
+ bbPtr != NULL;
+ bbPtr=bbPtr->successor1) {
+
+ /*
+ * Advance the basic block start offset by however many bytes
+ * we have inserted in the code up to this point
+ */
+ bbPtr->startOffset += motion;
+
+ /*
+ * If the basic block references a label (and hence performs
+ * a jump), find the location of the label. Report an error if
+ * the label is missing.
+ */
if (bbPtr->jumpTarget != NULL) {
entry = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
Tcl_GetString(bbPtr->jumpTarget));
- l = (JumpLabel*) Tcl_GetHashValue(entry);
- if (!(l->isDefined)) {
+ if (entry == NULL) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
result = Tcl_NewStringObj("undefined label \"", -1);
Tcl_AppendObjToObj(result, bbPtr->jumpTarget);
@@ -2512,14 +2505,127 @@ CheckUndefinedLabels(AssembleEnv* assemEnvPtr)
}
return TCL_ERROR;
}
+
+ /*
+ * If the instruction is a JUMP1, turn it into a JUMP4 if its
+ * target is out of range.
+ */
+ jumpTarget = (BasicBlock*) Tcl_GetHashValue(entry);
+ if (bbPtr->flags & BB_JUMP1) {
+ offset = jumpTarget->startOffset
+ - (bbPtr->jumpOffset + motion);
+ if (offset < -0x80 || offset > 0x7f) {
+ opcode = TclGetUInt1AtPtr(envPtr->codeStart
+ + bbPtr->jumpOffset);
+ ++opcode;
+ TclStoreInt1AtPtr(opcode,
+ envPtr->codeStart
+ + bbPtr->jumpOffset);
+ motion += 3;
+ bbPtr->flags &= ~BB_JUMP1;
+ }
+ }
}
}
+ *mustMove += motion;
+ } while (motion != 0);
+
return TCL_OK;
}
/*
*-----------------------------------------------------------------------------
*
+ * MoveCodeForJumps --
+ *
+ * Move bytecodes in memory to accommodate JUMP1 instructions that have
+ * expanded to become JUMP4's.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+MoveCodeForJumps(AssemblyEnv* assemEnvPtr,
+ /* Assembler environment */
+ int mustMove) /* Number of bytes of added code */
+{
+ CompileEnv* envPtr = assemEnvPtr->envPtr;
+ /* Compilation environment */
+ BasicBlock* bbPtr; /* Pointer to a basic block being checked */
+ int topOffset; /* Bytecode offset of the following
+ * basic block before code motion */
+
+ /*
+ * Make sure that there is enough space in the bytecode array to accommodate
+ * the expanded code.
+ */
+
+ while (envPtr->codeEnd < envPtr->codeNext + mustMove) {
+ TclExpandCodeArray(envPtr);
+ }
+
+ /*
+ * Iterate through the bytecodes in reverse order, and move them
+ * upward to their new homes.
+ */
+
+ topOffset = envPtr->codeNext - envPtr->codeStart;
+ for (bbPtr = assemEnvPtr->curr_bb; bbPtr != NULL; bbPtr = bbPtr->prevPtr) {
+ memmove(envPtr->codeStart + bbPtr->startOffset,
+ envPtr->codeStart + bbPtr->originalStartOffset,
+ topOffset - bbPtr->originalStartOffset);
+ topOffset = bbPtr->originalStartOffset;
+ bbPtr->jumpOffset += (bbPtr->startOffset - bbPtr->originalStartOffset);
+ }
+ envPtr->codeNext += mustMove;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * FillInJumpOffsets --
+ *
+ * Fill in the final offsets of all jump instructions once bytecode
+ * locations have been completely determined.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+FillInJumpOffsets(AssemblyEnv* assemEnvPtr)
+{
+ CompileEnv* envPtr = assemEnvPtr->envPtr;
+ /* Compilation environment */
+ BasicBlock* bbPtr; /* Pointer to a basic block being checked */
+ Tcl_HashEntry* entry; /* Hashtable entry for a jump target label */
+ BasicBlock* jumpTarget; /* Basic block where a jump goes */
+ int fromOffset; /* Bytecode location of a jump instruction */
+ int targetOffset; /* Bytecode location of a jump instruction's
+ * target */
+
+ for (bbPtr = assemEnvPtr->head_bb;
+ bbPtr != NULL;
+ bbPtr = bbPtr->successor1) {
+ if (bbPtr->jumpTarget != NULL) {
+ entry = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
+ Tcl_GetString(bbPtr->jumpTarget));
+ jumpTarget = (BasicBlock*) Tcl_GetHashValue(entry);
+ fromOffset = bbPtr->jumpOffset;
+ targetOffset = jumpTarget->startOffset;
+ if (bbPtr->flags & BB_JUMP1) {
+ TclStoreInt1AtPtr(targetOffset - fromOffset,
+ envPtr->codeStart + fromOffset + 1);
+ } else {
+ TclStoreInt4AtPtr(targetOffset - fromOffset,
+ envPtr->codeStart + fromOffset + 1);
+ }
+ }
+ }
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
* CheckStack --
*
* Audit stack usage in a block of assembly code.
@@ -2536,7 +2642,7 @@ CheckUndefinedLabels(AssembleEnv* assemEnvPtr)
*/
static int
-CheckStack(AssembleEnv* assemEnvPtr)
+CheckStack(AssemblyEnv* assemEnvPtr)
/* Assembly environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
@@ -2596,7 +2702,7 @@ CheckStack(AssembleEnv* assemEnvPtr)
*/
static int
-StackCheckBasicBlock(AssembleEnv* assemEnvPtr,
+StackCheckBasicBlock(AssemblyEnv* assemEnvPtr,
/* Assembly environment */
BasicBlock* blockPtr,
/* Pointer to the basic block being checked */
@@ -2610,9 +2716,11 @@ StackCheckBasicBlock(AssembleEnv* assemEnvPtr,
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
+ BasicBlock* jumpTarget; /* Basic block where a jump goes */
int stackDepth; /* Current stack depth */
int maxDepth; /* Maximum stack depth so far */
int result; /* Tcl status return */
+ Tcl_HashEntry* entry;
if (blockPtr->flags & BB_VISITED) {
@@ -2675,11 +2783,10 @@ StackCheckBasicBlock(AssembleEnv* assemEnvPtr,
}
if (result == TCL_OK && blockPtr->jumpTarget != NULL) {
- Tcl_HashEntry* entry =
- Tcl_FindHashEntry(&assemEnvPtr->labelHash,
- Tcl_GetString(blockPtr->jumpTarget));
- JumpLabel* targetLabel = (JumpLabel*) Tcl_GetHashValue(entry);
- result = StackCheckBasicBlock(assemEnvPtr, targetLabel->basicBlock,
+ entry = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
+ Tcl_GetString(blockPtr->jumpTarget));
+ jumpTarget = (BasicBlock*) Tcl_GetHashValue(entry);
+ result = StackCheckBasicBlock(assemEnvPtr, jumpTarget,
blockPtr, stackDepth);
}
return result;
@@ -2707,7 +2814,7 @@ StackCheckBasicBlock(AssembleEnv* assemEnvPtr,
*/
static int
-StackCheckExit(AssembleEnv* assemEnvPtr)
+StackCheckExit(AssemblyEnv* assemEnvPtr)
/* Assembler environment */
{
@@ -2785,7 +2892,7 @@ StackCheckExit(AssembleEnv* assemEnvPtr)
*/
static int
-ProcessCatches(AssembleEnv* assemEnvPtr)
+ProcessCatches(AssemblyEnv* assemEnvPtr)
/* Assembler environment */
{
BasicBlock* blockPtr; /* Pointer to a basic block */
@@ -2849,7 +2956,7 @@ ProcessCatches(AssembleEnv* assemEnvPtr)
*/
static int
-ProcessCatchesInBasicBlock(AssembleEnv* assemEnvPtr,
+ProcessCatchesInBasicBlock(AssemblyEnv* assemEnvPtr,
/* Assembler environment */
BasicBlock* bbPtr,
/* Basic block being processed */
@@ -2877,6 +2984,8 @@ ProcessCatchesInBasicBlock(AssembleEnv* assemEnvPtr,
int changed = 0; /* Flag == 1 iff successor blocks need
* to be checked because the state of this
* block has changed. */
+ BasicBlock* jumpTarget; /* Basic block where a jump goes */
+ Tcl_HashEntry* entry;
/*
* Update the state of the current block, checking for consistency.
@@ -2995,12 +3104,10 @@ ProcessCatchesInBasicBlock(AssembleEnv* assemEnvPtr,
catchDepth);
}
if (result == TCL_OK && bbPtr->jumpTarget != NULL) {
- Tcl_HashEntry* entry =
- Tcl_FindHashEntry(&assemEnvPtr->labelHash,
- Tcl_GetString(bbPtr->jumpTarget));
- JumpLabel* targetLabel = (JumpLabel*) Tcl_GetHashValue(entry);
- result = ProcessCatchesInBasicBlock(assemEnvPtr,
- targetLabel->basicBlock,
+ entry = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
+ Tcl_GetString(bbPtr->jumpTarget));
+ jumpTarget = (BasicBlock*) Tcl_GetHashValue(entry);
+ result = ProcessCatchesInBasicBlock(assemEnvPtr, jumpTarget,
jumpEnclosing, jumpState,
catchDepth);
}
@@ -3023,7 +3130,7 @@ ProcessCatchesInBasicBlock(AssembleEnv* assemEnvPtr,
*/
static int
-CheckForUnclosedCatches(AssembleEnv* assemEnvPtr)
+CheckForUnclosedCatches(AssemblyEnv* assemEnvPtr)
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
@@ -3067,15 +3174,11 @@ CheckForUnclosedCatches(AssembleEnv* assemEnvPtr)
*/
static int
-BuildExceptionRanges(AssembleEnv* assemEnvPtr)
+BuildExceptionRanges(AssemblyEnv* assemEnvPtr)
/* Assembler environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
-#if 0
- Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
- /* Tcl interpreter */
-#endif
BasicBlock* bbPtr; /* Current basic block */
BasicBlock* prevPtr = NULL; /* Previous basic block */
int catchDepth = 0; /* Current catch depth */
@@ -3276,7 +3379,7 @@ LookForFreshCatches(BasicBlock* bbPtr,
*/
static void
-StackFreshCatches(AssembleEnv* assemEnvPtr,
+StackFreshCatches(AssemblyEnv* assemEnvPtr,
/* Assembly environment */
BasicBlock* bbPtr,
/* Basic block being processed */
@@ -3293,7 +3396,8 @@ StackFreshCatches(AssembleEnv* assemEnvPtr,
/* Compilation environment */
ExceptionRange* range; /* Exception range for a specific catch */
BasicBlock* catch; /* Catch block being examined */
- JumpLabel* l; /* Error exit from the catch block */
+ BasicBlock* errorExit; /* Error exit from the catch block */
+ Tcl_HashEntry* entryPtr;
catchDepth = 0;
@@ -3318,12 +3422,16 @@ StackFreshCatches(AssembleEnv* assemEnvPtr,
envPtr->maxExceptDepth =
TclMax(range->nestingLevel + 1, envPtr->maxExceptDepth);
range->codeOffset = bbPtr->startOffset;
- l = FindLabel(assemEnvPtr, catch->jumpTarget);
- if (!l->isDefined) {
+
+ if ((entryPtr =
+ Tcl_FindHashEntry(&assemEnvPtr->labelHash,
+ Tcl_GetString(catch->jumpTarget)))
+ == NULL) {
Tcl_Panic("undefined label in tclAssembly.c:"
"BuildExceptionRanges, can't happen");
} else {
- range->catchOffset = l->offset;
+ errorExit = (BasicBlock*) Tcl_GetHashValue(entryPtr);
+ range->catchOffset = errorExit->startOffset;
}
}
}
@@ -3341,7 +3449,7 @@ StackFreshCatches(AssembleEnv* assemEnvPtr,
*/
static void
-RestoreEmbeddedExceptionRanges(AssembleEnv* assemEnvPtr)
+RestoreEmbeddedExceptionRanges(AssemblyEnv* assemEnvPtr)
/* Assembler environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
@@ -3430,7 +3538,7 @@ RestoreEmbeddedExceptionRanges(AssembleEnv* assemEnvPtr)
*/
static void
-ResetVisitedBasicBlocks(AssembleEnv* assemEnvPtr)
+ResetVisitedBasicBlocks(AssemblyEnv* assemEnvPtr)
{
BasicBlock* block;
for (block = assemEnvPtr->head_bb; block != NULL;
@@ -3454,7 +3562,7 @@ ResetVisitedBasicBlocks(AssembleEnv* assemEnvPtr)
*/
static void
-AddBasicBlockRangeToErrorInfo(AssembleEnv* assemEnvPtr,
+AddBasicBlockRangeToErrorInfo(AssemblyEnv* assemEnvPtr,
/* Assembly environment */
BasicBlock* bbPtr)
/* Basic block in which the error is
diff --git a/tests/assemble.test b/tests/assemble.test
index 08295d6..c5898c1 100644
--- a/tests/assemble.test
+++ b/tests/assemble.test
@@ -1914,7 +1914,7 @@ test assemble-17.9 {jump - resolve a label multiple times} {
-cleanup {rename x {}}
}
-test assemble-17.10 {jump4} {
+test assemble-17.10 {jump4 needed} {
-body {
assemble "push x; jump one; label two; [string repeat {dup; pop;} 128]
jump three; label one; jump two; label three"
@@ -1982,6 +1982,38 @@ test assemble-17.14 {jump to undefined label, line number correct?} {
-result {*"assemble" body, line 4*}
}
+test assemble-17.15 {multiple passes of code resizing} {
+ -setup {
+ set body {
+ push -
+ }
+ for {set i 0} {$i < 14} {incr i} {
+ append body "label a" $i \
+ "; push a; concat 2; nop; nop; jump b" \
+ $i \n
+ }
+ append body {label a14; push a; concat 2; push 1; jumpTrue b14} \n
+ append body {label a15; push a; concat 2; push 0; jumpFalse b15} \n
+ for {set i 0} {$i < 15} {incr i} {
+ append body "label b" $i \
+ "; push b; concat 2; nop; nop; jump a" \
+ [expr {$i+1}] \n
+ }
+ append body {label c; push -; concat 2; nop; nop; nop; jump d} \n
+ append body {label b15; push b; concat 2; nop; nop; jump c} \n
+ append body {label d}
+ proc x {} [list assemble $body]
+ }
+ -body {
+ x
+ }
+ -cleanup {
+ catch {unset body}
+ catch {rename x {}}
+ }
+ -result -abababababababababababababababab-
+}
+
# assemble-18 - lindexMulti
test assemble-18.1 {lindexMulti - wrong # args} {