Index: asm.tcl =================================================================== diff -u -r04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb -r66f91dca78bc8c4e9963c8e8039183298f0c0f09 --- asm.tcl (.../asm.tcl) (revision 04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb) +++ asm.tcl (.../asm.tcl) (revision 66f91dca78bc8c4e9963c8e8039183298f0c0f09) @@ -18,18 +18,35 @@ {obj 0} {var obj 0} {var obj 1} - {copyScalar int 6 obj 2} - {copyScalar int 7 obj 5} - {leScalar int 4 int 7} - {jumpTrue int 7} - {incrScalar int 6 int 7} - {incrScalar int 7 int 3} - {jump int 2} - {setResult int 6} + {duplicateObj slot 6 obj 2} + {duplicateObj slot 7 obj 5} + {leIntObj slot 4 slot 7} + {jumpTrue instruction 7} + {incrObj slot 6 slot 7} + {incrObj slot 7 slot 3} + {jump instruction 2} + {setResult slot 6} } +nsf::asm::proc sum10.asm2 {} { + {obj sum} + {obj i} + {integer int 1} + {integer int 100} + {integer int 0} + {integer int 0} + {setInt slot 4 int 0} + {setInt slot 5 int 0} + {leInt slot 3 slot 5} + {jumpTrue instruction 7} + {incrInt slot 4 slot 5} + {incrInt slot 5 slot 2} + {jump instruction 2} + {setResultInt slot 4} +} ? {sum10.tcl} "4950" ? {sum10.asm1} "4950" +? {sum10.asm2} "4950" #exit @@ -47,8 +64,9 @@ {obj x} {obj 1} {var obj 0} - {setScalar int 2 arg 0} - {incrScalar int 2 int 1} + {setObj slot 2 arg 0} + {incrObj slot 2 slot 1} + {setResult slot 2} } ? {incr1.tcl 10} "11" ? {incr1.asm1 10} "11" @@ -68,8 +86,9 @@ {obj a} {obj 1} {var obj 0} - {setScalar int 2 arg 0} - {incrScalar int 2 int 1} + {setObj slot 2 arg 0} + {incrObj slot 2 slot 1} + {setResult slot 2} } ? {incr2.tcl 13} "14" ? {incr2.asm1 13} "14" @@ -88,7 +107,7 @@ {cmd ::set obj 0 obj 2} {cmd ::set obj 1 arg 0} {cmd ::incr obj 1} - {store code 4 argv 2} + {store instruction 4 argv 2} {cmd ::incr obj 0 result 3} {cmd ::set obj 0} } @@ -99,11 +118,11 @@ {var obj 0} {var obj 1} {var obj 2} - {setScalar int 3 obj 2} - {setScalar int 4 arg 0} - {incrScalar int 4 int 2} - {setScalarResult int 5} - {incrScalar int 3 int 5} + {setObj slot 3 obj 2} + {setObj slot 4 arg 0} + {incrObj slot 4 slot 2} + {setObjToResult slot 5} + {incrObj slot 3 slot 5} {cmd ::set obj 0} } ? {foo.tcl 100} "102" @@ -119,9 +138,9 @@ {obj 64} {obj 65} {cmd ::format obj 0 obj 2} - {store code 4 argv 1} + {store instruction 4 argv 1} {cmd ::format obj 0 obj 3} - {store code 4 argv 3} + {store instruction 4 argv 3} {cmd ::concat result 1 obj 1 result 3 obj 1 arg 0} } #puts [bar.asm 123] Index: generic/asmExecuteTemplateLabelThreading.c =================================================================== diff -u -r04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb -r66f91dca78bc8c4e9963c8e8039183298f0c0f09 --- generic/asmExecuteTemplateLabelThreading.c (.../asmExecuteTemplateLabelThreading.c) (revision 04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb) +++ generic/asmExecuteTemplateLabelThreading.c (.../asmExecuteTemplateLabelThreading.c) (revision 66f91dca78bc8c4e9963c8e8039183298f0c0f09) @@ -6,7 +6,7 @@ }; enum asmStatementIndex { - asmCmdIdx, + asmObjProcIdx, $STATEMENT_INDICES }; @@ -16,21 +16,53 @@ NULL }; -enum asmCmdArgIndex {asmCmdArgArgIdx, asmCmdArgIntIdx, asmCmdArgObjIdx, asmCmdArgResultIdx, asmCmdArgVarIdx}; -static CONST char *asmCmdArgTypes[] = {"arg", "int", "obj", "result", "var", NULL}; +enum asmStatmentArgTypeIndex { + asmStatementArgTypeArgIdx, + asmStatementArgTypeArgvIdx, + asmStatementArgTypeInstructionIdx, + asmStatementArgTypeIntIdx, + asmStatementArgTypeObjIdx, + asmStatementArgTypeResultIdx, + asmStatementArgTypeSlotIdx, + asmStatementArgTypeVarIdx +}; -enum asmAddrIndex {asmAddrCodeIdx, asmAddrArgvIdx}; -static CONST char *asmAddrTypes[] = {"code", "argv", NULL}; +static CONST char *asmStatementArgType[] = { + "arg", + "argv", + "instruction", + "int", + "obj", + "result", + "slot", + "var", + NULL}; +static CONST char *asmStatementCmdType[] = {"arg", "obj", "result", "var", NULL}; +static CONST char *asmStatementInstructionType[] = {"instruction", NULL}; +static CONST char *asmStatementIntType[] = {"int", NULL}; +static CONST char *asmStatementObjType[] = {"obj", NULL}; +static CONST char *asmStatementSlotObjArgType[] = {"slot", "obj", "arg", NULL}; +static CONST char *asmStatementSlotType[] = {"slot", NULL}; +static CONST char *asmStatementSlotIntType[] = {"slot", "int", NULL}; +static CONST char *asmStatementStoreType[] = {"instruction", "argv", NULL}; + static AsmStatementInfo asmStatementInfo[] = { - /* asmCmdIdx, */ + /* asmObjProcIdx, */ {ASM_INFO_PAIRS|ASM_INFO_SKIP1, NULL, 2, -1, NR_PAIRS1}, $STATEMENT_INFO }; +/* + *---------------------------------------------------------------------- + * AsmExecute -- + * + * Define the execution engine for the code + * + *---------------------------------------------------------------------- + */ int AsmExecute(ClientData cd, Tcl_Interp *interp, AsmCompiledProc *proc, int argc, Tcl_Obj *CONST argv[]) { int i, result, indexValue; - ClientData clientData; NsfObject *object; Tcl_Command cmd; AsmInstruction *ip; @@ -83,3 +115,230 @@ $GENERATED_INSTRUCTIONS } + + +/* + *---------------------------------------------------------------------- + * AsmAssemble -- + * + * The assmbler, takes an assembly script in the form of a nested + * list and emits the internal representation for the execution + * enigine. + * + *---------------------------------------------------------------------- + */ + +static int +AsmAssemble(ClientData cd, Tcl_Interp *interp, Tcl_Obj *nameObj, + int nrArgs, Tcl_Obj *asmObj, AsmCompiledProc **retAsmProc) { + AsmPatches patchArray[100], *patches = &patchArray[0], *patchPtr; // TODO: make me dynamic + Tcl_Command cmd; + AsmCompiledProc *proc; + AsmInstruction *inst; + int i, result, nrAsmInstructions, nrLocalObjs, totalArgvArgs; + int oc, currentAsmInstruction, currentSlot; + Tcl_Obj **ov; + CONST char *procName; + + assert(nameObj); + procName = ObjStr(nameObj); + + if (Tcl_ListObjGetElements(interp, asmObj, &oc, &ov) != TCL_OK) { + return NsfPrintError(interp, "Asm code is not a valid list"); + } + + /* + * First Iteration: check wellformedness, determine sizes + */ + nrAsmInstructions = 0; + nrLocalObjs = 0; + totalArgvArgs = 0; + + for (i = 0; i < oc; i++) { + int index, offset, wordOc; + Tcl_Obj *lineObj = ov[i], **wordOv; + + if (Tcl_ListObjGetElements(interp, lineObj, &wordOc, &wordOv) != TCL_OK) { + return NsfPrintError(interp, + "Asm: line is not a well-formed asm instruction: %s", + ObjStr(lineObj)); + } + + result = Tcl_GetIndexFromObj(interp, wordOv[0], asmStatementNames, "asm instruction", 0, &index); + if (result != TCL_OK) { + return NsfPrintError(interp, + "Asm: line is not a valid asm instruction: word %s, line %s", + ObjStr(wordOv[0]), ObjStr(lineObj)); + } + + offset = (asmStatementInfo[index].flags & ASM_INFO_SKIP1) ? 2 : 1; + + if ((asmStatementInfo[index].flags & ASM_INFO_PAIRS) && (wordOc-offset) % 2 == 1) { + return NsfPrintError(interp, "Asm: argument list of cmd must contain pairs: %s", + ObjStr(lineObj)); + } + + if (asmStatementInfo[index].minArgs > -1 + && wordOc < asmStatementInfo[index].minArgs) { + return NsfPrintError(interp, "Asm: statement must contain at least %d words: %s", + asmStatementInfo[index].minArgs, ObjStr(lineObj)); + } + + if (asmStatementInfo[index].maxArgs > -1 + && wordOc > asmStatementInfo[index].maxArgs) { + return NsfPrintError(interp, "Asm: statement must contain at most %d words: %s", + asmStatementInfo[index].maxArgs, ObjStr(lineObj)); + } + + if (asmStatementInfo[index].argTypes) { + result = AsmInstructionArgvCheck(interp, offset, wordOc, + asmStatementInfo[index].argTypes, + nrLocalObjs, oc, wordOv, lineObj); + if (unlikely(result != TCL_OK)) {return result;} + } + + if ((asmStatementInfo[index].flags & ASM_INFO_DECL) == 0) { + int cArgs = asmStatementInfo[index].cArgs; + /* + * Determine the actual number of arguments passed to the + * emitted instruction. This number might be determine by the + * instruction type, or by the actual instruction being + * processed (and later maybe for {*} etc.). + */ + if (cArgs == NR_PAIRS) { + cArgs = (wordOc-offset) / 2; + } else if (cArgs == NR_PAIRS1) { + cArgs = 1 + (wordOc-offset) / 2; + } + //fprintf(stderr, "instruction %s need argvargs %d\n", ObjStr(lineObj), cArgs); + totalArgvArgs += cArgs; + + nrAsmInstructions++; + } else { + /* currently obj and var from the same pool, will change... */ + nrLocalObjs ++; + } + + /* + * optional, per-statement check operations + */ + switch (index) { + case asmObjProcIdx: + /* {cmd ::set slot 0 slot 2} */ + cmd = Tcl_GetCommandFromObj(interp, wordOv[1]); + if (cmd == NULL) { + return NsfPrintError(interp, + "Asm: cmd is not a valid tcl command: %s\n", + Tcl_GetString( wordOv[1])); + } + break; + + /* begin generated code */ + $ASSEMBLE_CHECK_CODE + /* end generated code */ + + default: + break; + } + } + + nrAsmInstructions ++; + fprintf(stderr, "%s: nrAsmInstructions %d nrLocalObjs %d nrArgs %d argvArgs %d => data %d\n", + procName, nrAsmInstructions, nrLocalObjs, nrArgs, totalArgvArgs, + nrLocalObjs + nrArgs + totalArgvArgs ); + + /* + * Allocate structures + */ + + proc = (AsmCompiledProc *)ckalloc(sizeof(AsmCompiledProc)); + proc->code = (AsmInstruction *)ckalloc(sizeof(AsmInstruction) * nrAsmInstructions); + memset(proc->slotFlags, 0, sizeof(int) * NSF_ASM_NR_STATIC_SLOTS); + + proc->ip = proc->code; /* points to the first writable instructon */ + proc->firstObj = proc->staticObjs; /* point to the first free obj */ + proc->locals = proc->staticObjs; /* locals is just an alias */ + proc->nrAsmArgReferences = 0; + proc->slots = proc->locals + nrArgs; + //fprintf(stderr, "args = %ld\n", proc->slots - proc->locals); + + AsmLocalsAlloc(proc, nrArgs + nrLocalObjs); + /* when freeing, we need something like + for (i=0; i < nrArgs + nrLocalObjs; i++) { + if (proc->slotFlags[i] & ASM_SLOT_MUST_DECR) {Tcl_DecrRefCount(proc->slots[i]); } + } + */ + + /* + * Second Iteration: emit code + */ + currentSlot = 0; + currentAsmInstruction = 0; + + for (i = 0; i < oc; i++) { + int index, offset, cArgs, argc, codeIndex, argvIndex, j; + Tcl_Obj *lineObj = ov[i], **argv; + + Tcl_ListObjGetElements(interp, lineObj, &argc, &argv); + Tcl_GetIndexFromObj(interp, argv[0], asmStatementNames, "asm instruction", 0, &index); + + offset = (asmStatementInfo[index].flags & ASM_INFO_SKIP1) ? 2 : 1; + + cArgs = asmStatementInfo[index].cArgs; + if (cArgs == NR_PAIRS) { + cArgs = (argc-offset) / 2; + } else if (cArgs == NR_PAIRS1) { + cArgs = 1 + (argc-offset) / 2; + } + + switch (index) { + + case asmObjProcIdx: + /* {cmd ::set slot 0 slot 2} */ + cmd = Tcl_GetCommandFromObj(interp, argv[1]); +#if defined(LABEL_THREADING) + inst = AsmInstructionNew(proc, objProc, cArgs); + inst->cmd = ((Command *)cmd)->objProc; +#else + inst = AsmInstructionNew(proc, ((Command *)cmd)->objProc, cArgs); +#endif + inst->clientData = ((Command *)cmd)->objClientData; + /* use the assembly word as cmd name; should be ok when we keep assembly around */ + inst->argv[0] = argv[1]; + /*fprintf(stderr, "[%d] %s/%d\n", currentAsmInstruction, Tcl_GetString(argv[1]), 1+((argc-offset)/2));*/ + + AsmInstructionArgvSet(interp, offset, argc, 1, inst, proc, argv, 0); + break; + + /* begin generated code */ +$ASSEMBLE_EMIT_CODE + /* end generated code */ + } + + if ((asmStatementInfo[index].flags & ASM_INFO_DECL) == 0) { + currentAsmInstruction ++; + } + } + + /* + * add END instruction + */ + inst = AsmInstructionNew(proc, NULL, 0); + + /* + * All addresses are determined, apply the argv patches triggered + * from above. + */ + + for (patchPtr = &patchArray[0]; patchPtr < patches; patchPtr++) { + fprintf(stderr, "wanna patch code[%d]->argv = code[%d]->argv[%d]\n", + patchPtr->targetAsmInstruction, patchPtr->sourceAsmInstruction, patchPtr->argvIndex); + /* set the argument vector of code[1] to the address of code[4]->argv[1] */ + (&proc->code[patchPtr->targetAsmInstruction])->argv = + &(&proc->code[patchPtr->sourceAsmInstruction])->argv[patchPtr->argvIndex]; + } + + *retAsmProc = proc; + + return TCL_OK; +} Index: generic/genAssemble.tcl =================================================================== diff -u -r04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb -r66f91dca78bc8c4e9963c8e8039183298f0c0f09 --- generic/genAssemble.tcl (.../genAssemble.tcl) (revision 04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb) +++ generic/genAssemble.tcl (.../genAssemble.tcl) (revision 66f91dca78bc8c4e9963c8e8039183298f0c0f09) @@ -1,5 +1,4 @@ package require nx - ###################################################################### # The code engine ###################################################################### @@ -8,8 +7,6 @@ Instruction mixin add ${threadingType}::Instruction set suffix [string trimleft ${threadingType} :] set dirName [file dirname [info script]] - set fn $dirName/asmExecuteTemplate$suffix.c - set f [open $fn]; set template [read $f]; close $f set instructions [lsort [Instruction info instances]] set labels {} set indices {} @@ -24,13 +21,20 @@ set statementIndex {} set statementNames {} + set ASSEMBLE_EMIT_CODE "" foreach s [lsort [Statement info instances -closure]] { if {[$s maxArgs] == 0} { puts stderr "ignore statement $s" continue } lappend statementIndex [$s cName]Idx lappend statementNames \"[$s name]\" + + set emitCode [$s getAsmEmitCode] + if {$emitCode ne ""} { + append ASSEMBLE_EMIT_CODE " case [$s cName]Idx:\n$emitCode\n break;\n\n" + } + set flags 0 if {[$s info has type ::Declaration]} { lappend flags ASM_INFO_DECL @@ -45,9 +49,11 @@ set STATEMENT_NAMES [join $statementNames ",\n "] set STATEMENT_INFO [join $statementInfo ",\n "] - #puts stderr statementIndex=$statementIndex - #puts stderr statementNames=$statementNames + set ASSEMBLE_CHECK_CODE "" + set fn $dirName/asmExecuteTemplate$suffix.c + set f [open $fn]; set template [read $f]; close $f + set f [open $dirName/nsfAsmExecute$suffix.c w] puts $f [subst -nocommand -nobackslash $template] close $f @@ -64,10 +70,16 @@ :property {maxArgs 0} :property {cArgs 0} + :property {asmCheckCode ""} + :property {asmEmitCode ""} + :public method cName {} { # prepend asm and capitalize first character return asm[string toupper [string range ${:name} 0 0]][string range ${:name} 1 end] } + :public method getAsmEmitCode {} { + return ${:asmEmitCode} + } } ###################################################################### @@ -87,6 +99,20 @@ :property {isJump false} :property {returnsResult false} + # The property "execNeedsProc" is just needed for call threading, + # where we have to pass proc via inst->clientData + :property {execNeedsProc false} + + :public method getAsmEmitCode {} { + # + # For every instruction, the c-code allocates an instruction record + # + append . \ + "\n\tinst = AsmInstructionNew(proc, [:cName], cArgs);" \ + "\n\tif (cArgs>0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);}" \ + ${:asmEmitCode} + } + :method "code get" {} { return ${:cCode} } @@ -147,14 +173,36 @@ # {obj a} Declaration create obj \ -mustContainPairs false \ - -minArgs 2 -maxArgs 2 + -minArgs 2 -maxArgs 2 \ + -asmEmitCode { + proc->slots[currentSlot] = argv[1]; + Tcl_IncrRefCount(proc->slots[currentSlot]); + proc->slotFlags[currentSlot] |= ASM_SLOT_MUST_DECR; + currentSlot ++; + } # {var obj 0} - # should force arg to "obj" # obj is intended to be the varname, but currently ignored Declaration create var \ - -minArgs 3 -maxArgs 3 -argTypes asmCmdArgTypes + -minArgs 3 -maxArgs 3 -argTypes asmStatementObjType \ + -asmEmitCode { + proc->slots[currentSlot] = NULL; + currentSlot ++; + } + # {integer int 0} + Declaration create integer \ + -minArgs 3 -maxArgs 3 -argTypes asmStatementIntType \ + -asmEmitCode { + { + int intValue; + Tcl_GetIntFromObj(interp, argv[2], &intValue); + proc->slots[currentSlot] = INT2PTR(intValue); + //fprintf(stderr, "setting slots [%d] = %d\n", currentSlot, intValue); + proc->slotFlags[currentSlot] |= ASM_SLOT_IS_INTEGER; + currentSlot ++; + } + } ###################################################################### @@ -169,7 +217,7 @@ # {eval obj 0 obj 1 obj 2} Instruction create dispatch \ -name "eval" \ - -minArgs 3 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmCmdArgTypes \ + -minArgs 3 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmStatementCmdType \ -returnsResult true \ -execCode { result = Tcl_EvalObjv(interp, ip->argc, ip->argv, 0); @@ -178,13 +226,40 @@ # {methodDelegateDispatch obj 0 obj 1 obj 2} Instruction create methodDelegateDispatch \ -name "methodDelegateDispatch" \ - -minArgs 5 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmCmdArgTypes \ + -minArgs 5 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmStatementCmdType \ + -asmEmitCode { + { Tcl_Command cmd = NULL; + NsfObject *object = NULL; + AsmResolverInfo *resInfo; + + if (strncmp(ObjStr(inst->argv[1]), "::nsf::methods::", 16) == 0) { + cmd = Tcl_GetCommandFromObj(interp, inst->argv[1]); + //fprintf(stderr, "%s: asmMethod cmd '%s' => %p\n", procName, ObjStr(inst->argv[1]), cmd); + } + if (strncmp(ObjStr(inst->argv[0]), "::nx::", 6) == 0) { + GetObjectFromObj(interp, inst->argv[0], &object); + //fprintf(stderr, "%s: asmMethod object '%s' => %p\n", procName, ObjStr(inst->argv[0]), object); + } + if (cmd && object) { + // experimental: bind obj and method + resInfo = NEW(AsmResolverInfo); // TODO: LEAK + resInfo->cmd = cmd; + resInfo->object = object; + inst->clientData = resInfo; + AsmInstructionSetCmd(inst, asmMethodDelegateDispatch11); + } else if (cmd) { + inst->clientData = cmd; + } else { + inst->clientData = NULL; + } + } + } \ -returnsResult true \ -execCode { // obj and method are unresolved result = GetObjectFromObj(interp, ip->argv[0], &object); if (likely(ip->clientData != NULL)) { - cmd = clientData; + cmd = ip->clientData; } else { cmd = Tcl_GetCommandFromObj(interp, ip->argv[1]); } @@ -212,16 +287,35 @@ # {methodSelfDispatch obj 0 obj 1 obj 2} Instruction create methodSelfDispatch \ - -minArgs 3 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmCmdArgTypes \ + -minArgs 3 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmStatementCmdType \ + -asmEmitCode { + { Tcl_Command cmd = NULL; + AsmResolverInfo *resInfo; + + if (strncmp(ObjStr(inst->argv[0]), "::nsf::methods::", 16) == 0) { + cmd = Tcl_GetCommandFromObj(interp, inst->argv[0]); + if (cmd) { + //fprintf(stderr, "%s: asmMethodSelfCmdDispatch cmd '%s' => %p\n", procName, ObjStr(inst->argv[0]), cmd); + AsmInstructionSetCmd(inst, asmMethodSelfCmdDispatch); + } + } else { + //fprintf(stderr, "%s: asmMethodSelfDispatch cmd '%s'\n", procName, ObjStr(inst->argv[0])); + } + resInfo = NEW(AsmResolverInfo); // TODO: LEAK + resInfo->cmd = cmd; + resInfo->proc = proc; + inst->clientData = resInfo; + } + } \ -returnsResult true \ -execCode { { AsmResolverInfo *resInfo = ip->clientData; Tcl_Command cmd = resInfo->cmd ? resInfo->cmd : Tcl_GetCommandFromObj(interp, ip->argv[0]); - result = MethodDispatch(resInfo->asmProc->currentObject, interp, + result = MethodDispatch(resInfo->proc->currentObject, interp, ip->argc, ip->argv, - cmd, resInfo->asmProc->currentObject, NULL, + cmd, resInfo->proc->currentObject, NULL, ObjStr(ip->argv[0]), 0, 0); } } @@ -235,34 +329,37 @@ { AsmResolverInfo *resInfo = ip->clientData; assert(resInfo->cmd != NULL); - result = Tcl_NRCallObjProc(interp, Tcl_Command_objProc(resInfo->cmd), resInfo->asmProc->currentObject, + result = Tcl_NRCallObjProc(interp, Tcl_Command_objProc(resInfo->cmd), resInfo->proc->currentObject, ip->argc, ip->argv); } } # {self} - # TODO: rename instruction to self ? why "method" - Instruction create methodSelf \ + + Instruction create self \ -minArgs 1 -maxArgs 1 \ + -execNeedsProc true \ -execCode { Tcl_SetObjResult(interp, proc->currentObject->cmdName); } - # {jump int 2} - # TODO: should force arg1 "int", maybe define later jump labels in asm source + # {jump instruction 2} + # TODO: maybe define later jump labels in asm source Instruction create jump \ - -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmCmdArgTypes \ + -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmStatementInstructionType \ + -execNeedsProc true \ -isJump true \ -execCode { //fprintf(stderr, "asmJump oc %d instructionIndex %d\n", ip->argc, PTR2INT(ip->argv[0])); ip = &proc->code[PTR2INT(ip->argv[0])]; } - # {jumpTrue int 6} - # TODO: should force arg1 "int", maybe define later jump labels in asm source + # {jumpTrue instruction 6} + # TODO: maybe define later jump labels in asm source Instruction create jumpTrue \ - -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmCmdArgTypes \ + -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmStatementInstructionType \ + -execNeedsProc true \ -isJump true \ -execCode { if (proc->status) { @@ -274,15 +371,16 @@ } } - # {leScalar int 4 int 7} - # TODO: should force arg1 & arg2 "int" - Instruction create leScalar \ - -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmCmdArgTypes \ + # {leIntObj slot 4 slot 7} + + Instruction create leIntObj \ + -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotType \ + -execNeedsProc true \ -execCode { { int value1, value2; Tcl_Obj *obj; - //fprintf(stderr, "asmLeScalar oc %d op1 %p op2 %p\n", ip->argc, ip->argv[0], ip->argv[1]); + //fprintf(stderr, "leIntObj oc %d op1 %p op2 %p\n", ip->argc, ip->argv[0], ip->argv[1]); // for the time being, we compare two int values obj = proc->slots[PTR2INT(ip->argv[0])]; @@ -303,67 +401,112 @@ } } + # {leInt slot 4 slot 7} - # {copyScalar int 6 obj 2} - # TODO: rename copyObj - # TODO: should force arg1 "int" + Instruction create leInt \ + -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotType \ + -execNeedsProc true \ + -execCode { + { + int value1, value2; + value1 = PTR2INT(proc->slots[PTR2INT(ip->argv[0])]); + value2 = PTR2INT(proc->slots[PTR2INT(ip->argv[1])]); + proc->status = value1 <= value2; + } + } - Instruction create copyScalar \ - -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmCmdArgTypes \ + + # {duplicateObj slot 6 obj 2} + # TODO: should force first arg "slot" + Instruction create duplicateObj \ + -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotObjArgType \ + -execNeedsProc true \ -execCode { indexValue = PTR2INT(ip->argv[0]); - //fprintf(stderr, "asmCopyScalar var[%d] = %s\n", indexValue, ObjStr(ip->argv[1])); + //fprintf(stderr, "duplicateObj var[%d] = %s\n", indexValue, ObjStr(ip->argv[1])); if (proc->slots[indexValue]) { Tcl_DecrRefCount(proc->slots[indexValue]); } proc->slots[indexValue] = Tcl_DuplicateObj(ip->argv[1]); - Tcl_IncrRefCount(proc->slots[indexValue]); // TODO: Leak? .. Clear all these vars when freeing the proc, or stack + Tcl_IncrRefCount(proc->slots[indexValue]); + proc->slotFlags[indexValue] |= ASM_SLOT_MUST_DECR; } - # {setScalar int 2 arg 0} - # TODO: should force arg1 "int" - Instruction create setScalar \ - -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmCmdArgTypes \ + # {setObj slot 2 arg 0} + # TODO: should force first arg "slot" + Instruction create setObj \ + -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotObjArgType \ + -execNeedsProc true \ -execCode { - indexValue = PTR2INT(ip->argv[0]); - //fprintf(stderr, "asmSetScalar var[%d] = %s\n", indexValue, ObjStr(ip->argv[1])); - proc->slots[indexValue] = ip->argv[1]; + //fprintf(stderr, "setObj var[%d] = %s\n", PTR2INT(ip->argv[0]), ObjStr(ip->argv[1])); + proc->slots[PTR2INT(ip->argv[0])] = ip->argv[1]; } - # {setScalarResult int 5} - # TODO: should force arg1 "int" - Instruction create setScalarResult \ - -minArgs 3 -maxArgs 3 -cArgs 2 -argTypes asmCmdArgTypes \ + # {setInt slot 6 int 0} + # TODO: should force first arg "slot" + Instruction create setInt \ + -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotIntType \ + -execNeedsProc true \ -execCode { - indexValue = PTR2INT(ip->argv[0]); - //fprintf(stderr, "asmSetScalar var[%d] = %s\n", indexValue, ObjStr(ip->argv[1])); - proc->slots[indexValue] = Tcl_GetObjResult(interp); + proc->slots[PTR2INT(ip->argv[0])] = ip->argv[1]; } + + # {setObjToResult slot 5} + Instruction create setObjToResult \ + -minArgs 3 -maxArgs 3 -cArgs 2 -argTypes asmStatementSlotType \ + -execNeedsProc true \ + -execCode { + //fprintf(stderr, "setObjToResult var[%d] = %s\n", PTR2INT(ip->argv[0]), ObjStr(ip->argv[1])); + proc->slots[PTR2INT(ip->argv[0])] = Tcl_GetObjResult(interp); + } - # {setResult int 6} - # TODO: should force arg1 "int" + # {setResult slot 6} Instruction create setResult \ - -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmCmdArgTypes \ + -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmStatementSlotType \ + -execNeedsProc true \ -execCode { - indexValue = PTR2INT(ip->argv[0]); - Tcl_SetObjResult(interp, proc->slots[indexValue]); - //fprintf(stderr, "asmSetResult index %d => '%s'\n", indexValue, ObjStr(proc->slots[indexValue])); + Tcl_SetObjResult(interp, proc->slots[PTR2INT(ip->argv[0])]); } + # {setResultInt slot 6} + Instruction create setResultInt \ + -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmStatementSlotType \ + -execNeedsProc true \ + -execCode { + Tcl_SetObjResult(interp, Tcl_NewIntObj(PTR2INT(proc->slots[PTR2INT(ip->argv[0])]))); + } # {store code 4 argv 2} Instruction create storeResult \ - -minArgs 5 -maxArgs 5 -cArgs 0 -argTypes asmAddrTypes \ - -execCode { + -minArgs 5 -maxArgs 5 -cArgs 0 -argTypes asmStatementStoreType \ + -asmEmitCode { + codeIndex = -1; + argvIndex = -1; + for (j = offset; j < argc; j += 2) { + int argIndex, intValue; + Tcl_GetIndexFromObj(interp, argv[j], asmStatementArgType, "asm internal arg type", 0, &argIndex); + Tcl_GetIntFromObj(interp, argv[j+1], &intValue); + switch (argIndex) { + case asmStatementArgTypeInstructionIdx: codeIndex = intValue; break; + case asmStatementArgTypeArgvIdx: argvIndex = intValue; break; + } + } + // TODO: CHECK codeIndex, argvIndex (>0, reasonable values) + //fprintf(stderr, "%p setting instruction %d => %d %d\n", patches, currentAsmInstruction, codeIndex, argvIndex); + patches->targetAsmInstruction = currentAsmInstruction; + patches->sourceAsmInstruction = codeIndex; + patches->argvIndex = argvIndex; + patches++; + } -execCode { ip->argv[0] = Tcl_GetObjResult(interp); Tcl_IncrRefCount(ip->argv[0]); } - # {incrScalar int 6 int 7} - # TODO: should force arg1&2 "int" - Instruction create incrScalar \ - -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmCmdArgTypes \ + # {incrObj slot 6 slot 7} + Instruction create incrObj \ + -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotType \ + -execNeedsProc true \ -execCode { { int intValue, incrValue; @@ -393,10 +536,27 @@ //fprintf(stderr, "updated %p var[%d] %p\n", intObj, PTR2INT(ip->argv[0]), proc->slots[PTR2INT(ip->argv[0])]); - Tcl_SetObjResult(interp, intObj); + //Tcl_SetObjResult(interp, intObj); } - } + } + # {incrInt slot 6 slot 7} + Instruction create incrInt \ + -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotType \ + -execNeedsProc true \ + -execCode { + { + int intValue, incrValue; + //fprintf(stderr, "incrInt var[%d] incr var[%d]\n", PTR2INT(ip->argv[0]), PTR2INT(ip->argv[1])); + intValue = PTR2INT(proc->slots[PTR2INT(ip->argv[0])]); + incrValue = PTR2INT(proc->slots[PTR2INT(ip->argv[1])]); + //fprintf(stderr, ".... intValue %d incr Value %d\n", intValue, incrValue); + + proc->slots[PTR2INT(ip->argv[0])] = INT2PTR(intValue + incrValue); + //fprintf(stderr, ".... [%d] => %d\n", PTR2INT(ip->argv[0]), intValue + incrValue); + } + } + } ######################################################################