Index: asm.tcl =================================================================== diff -u -N --- asm.tcl (revision 0) +++ asm.tcl (revision 04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb) @@ -0,0 +1,288 @@ +package req nx::test +nx::Test parameter count 100000 +#nx::Test parameter count 10 + +proc sum10.tcl {} { + set sum 0 + for {set i 0} {$i < 100} {incr i} { + incr sum $i + } + return $sum +} +nsf::asm::proc sum10.asm1 {} { + {obj sum} + {obj i} + {obj 0} + {obj 1} + {obj 100} + {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} +} + +? {sum10.tcl} "4950" +? {sum10.asm1} "4950" + +#exit + +proc incr1.tcl {x} { + incr x +} +# currently we have to set the local var of the argument +nsf::asm::proc incr1.asm1 {x} { + {obj x} + {obj 1} + {cmd ::set obj 0 arg 0} + {cmd ::incr obj 0 obj 1} +} +nsf::asm::proc incr1.asm2 {x} { + {obj x} + {obj 1} + {var obj 0} + {setScalar int 2 arg 0} + {incrScalar int 2 int 1} +} +? {incr1.tcl 10} "11" +? {incr1.asm1 10} "11" +? {incr1.asm2 10} "11" + +proc incr2.tcl {x} { + set a $x + incr a +} +nsf::asm::proc incr2.asm1 {x} { + {obj a} + {obj 1} + {cmd ::set obj 0 arg 0} + {cmd ::incr obj 0 obj 1} +} +nsf::asm::proc incr2.asm2 {x} { + {obj a} + {obj 1} + {var obj 0} + {setScalar int 2 arg 0} + {incrScalar int 2 int 1} +} +? {incr2.tcl 13} "14" +? {incr2.asm1 13} "14" +? {incr2.asm2 13} "14" + +proc foo.tcl {x} { + set a 1 + set b $x + incr a [incr b] + return $a +} +nsf::asm::proc foo.asm1 {x} { + {obj a} + {obj b} + {obj 1} + {cmd ::set obj 0 obj 2} + {cmd ::set obj 1 arg 0} + {cmd ::incr obj 1} + {store code 4 argv 2} + {cmd ::incr obj 0 result 3} + {cmd ::set obj 0} +} +nsf::asm::proc foo.asm2 {x} { + {obj a} + {obj b} + {obj 1} + {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} + {cmd ::set obj 0} +} +? {foo.tcl 100} "102" +? {foo.asm1 100} "102" +? {foo.asm2 100} "102" +#exit + + +proc bar.tcl {x} {concat [format %c 64] - [format %c 65] - $x} +nsf::asm::proc bar.asm {x} { + {obj %c} + {obj -} + {obj 64} + {obj 65} + {cmd ::format obj 0 obj 2} + {store code 4 argv 1} + {cmd ::format obj 0 obj 3} + {store code 4 argv 3} + {cmd ::concat result 1 obj 1 result 3 obj 1 arg 0} +} +#puts [bar.asm 123] +? {bar.tcl 123} "@ - A - 123" +? {bar.asm 123} "@ - A - 123" + +proc create1.tcl {} {nx::Object create o1} +nsf::asm::proc create1.asm1 {} { + {obj ::nx::Object} + {obj create} + {obj o1} + {eval obj 0 obj 1 obj 2} +} +nsf::asm::proc create1.asm2 {} { + {obj create} + {obj o1} + {cmd ::nx::Object obj 0 obj 1} +} +nsf::asm::proc create1.asm3 {} { + {obj nx::Object} + {obj ::nsf::methods::class::create} + {obj o1} + {methodDelegateDispatch obj 0 obj 1 obj 2} +} +nsf::asm::proc create1.asm4 {} { + {obj ::nx::Object} + {obj ::nsf::methods::class::create} + {obj o1} + {methodDelegateDispatch obj 0 obj 1 obj 2} +} + +? {create1.tcl} "::o1" +? {create1.asm1} "::o1" +? {create1.asm2} "::o1" +? {create1.asm3} "::o1" +? {create1.asm4} "::o1" + +proc create2.tcl {} {nx::Object create o1;o1 destroy;::nsf::object::exists o1} +nsf::asm::proc create2.asm1 {} { + {obj create} + {obj o1} + {obj destroy} + {cmd ::nx::Object obj 0 obj 1} + {eval obj 1 obj 2} + {cmd ::nsf::object::exists obj 1} +} +nsf::asm::proc create2.asm2 {} { + {obj o1} + {obj nx::Object} + {obj ::nsf::methods::class::create} + {obj ::nsf::methods::object::destroy} + {methodDelegateDispatch obj 1 obj 2 obj 0} + {methodDelegateDispatch obj 0 obj 3} + {cmd ::nsf::object::exists obj 0} +} +nsf::asm::proc create2.asm3 {} { + {obj o1} + {obj ::nx::Object} + {obj ::nsf::methods::class::create} + {obj ::nsf::methods::object::destroy} + {methodDelegateDispatch obj 1 obj 2 obj 0} + {methodDelegateDispatch obj 0 obj 3} + {cmd ::nsf::object::exists obj 0} +} +? {create2.tcl} 0 +? {create2.asm1} 0 +? {create2.asm2} 0 +? {create2.asm3} 0 + +proc check_obj.tcl {} {::nsf::object::exists o1} +nsf::asm::proc check_obj.asm1 {} { + {obj o1} + {cmd ::nsf::object::exists obj 0} +} +nsf::asm::proc check_obj.asm2 {} { + {obj o1} + {obj ::nsf::object::exists} + {eval obj 1 obj 0} +} +? {check_obj.tcl} 0 +? {check_obj.asm1} 0 +? {check_obj.asm2} 0 + +nx::Object create o { + set :x 1 +} +nsf::method::create o check_obj.tcl {} {::nsf::object::exists o1} +nsf::method::asmcreate o check_obj.asm1 {} { + {obj o1} + {cmd ::nsf::object::exists obj 0} +} +nsf::method::asmcreate o check_obj.asm2 {} { + {obj o1} + {obj ::nsf::object::exists} + {eval obj 1 obj 0} +} +? {o check_obj.tcl} 0 +? {o check_obj.asm1} 0 +? {o check_obj.asm2} 0 + +# info exists is byte-compiled +nsf::method::create o check_var1.tcl {} {info exists :x} +nsf::method::asmcreate o check_var1.asm1 {} { + {obj exists} + {obj :x} + {cmd ::info obj 0 obj 1} +} +? {o check_var1.tcl} 1 +? {o check_var1.asm1} 1 + +# check for existence via method +nsf::method::create o check_var2.tcl {} { + : ::nsf::methods::object::exists x +} +nsf::method::asmcreate o check_var2.asm1 {} { + {obj :} + {obj ::nsf::methods::object::exists} + {obj x} + {eval obj 0 obj 1 obj 2} +} +nsf::method::asmcreate o check_var2.asm2 {} { + {obj ::o} + {obj ::nsf::methods::object::exists} + {obj x} + {methodDelegateDispatch obj 0 obj 1 obj 2} +} +nsf::method::asmcreate o check_var2.asm3 {} { + {obj nsf::methods::object::exists} + {obj x} + {methodSelfDispatch obj 0 obj 1} +} +nsf::method::asmcreate o check_var2.asm4 {} { + {obj ::nsf::methods::object::exists} + {obj x} + {methodSelfDispatch obj 0 obj 1} +} +? {o check_var2.tcl} 1 +? {o check_var2.asm1} 1 +? {o check_var2.asm2} 1 +? {o check_var2.asm3} 1 +? {o check_var2.asm4} 1 + +# +# self +# +nsf::method::create o self.tcl {} { + self +} +nsf::method::asmcreate o self.asm1 {} { + {obj self} + {eval obj 0} +} +nsf::method::asmcreate o self.asm2 {} { + {cmd self} +} +nsf::method::asmcreate o self.asm3 {} { + {self} +} + +? {o self.tcl} ::o +? {o self.asm1} ::o +? {o self.asm2} ::o +? {o self.asm3} ::o + Index: generic/asmExecuteTemplateLabelThreading.c =================================================================== diff -u -N --- generic/asmExecuteTemplateLabelThreading.c (revision 0) +++ generic/asmExecuteTemplateLabelThreading.c (revision 04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb) @@ -0,0 +1,85 @@ + +enum instructionIdx { + IDX_objProc, + $INSTRUCTION_INDICES, + IDX_NULL +}; + +enum asmStatementIndex { + asmCmdIdx, + $STATEMENT_INDICES +}; + +static CONST char *asmStatementNames[] = { + "cmd", + $STATEMENT_NAMES, + NULL +}; + +enum asmCmdArgIndex {asmCmdArgArgIdx, asmCmdArgIntIdx, asmCmdArgObjIdx, asmCmdArgResultIdx, asmCmdArgVarIdx}; +static CONST char *asmCmdArgTypes[] = {"arg", "int", "obj", "result", "var", NULL}; + +enum asmAddrIndex {asmAddrCodeIdx, asmAddrArgvIdx}; +static CONST char *asmAddrTypes[] = {"code", "argv", NULL}; + +static AsmStatementInfo asmStatementInfo[] = { + /* asmCmdIdx, */ + {ASM_INFO_PAIRS|ASM_INFO_SKIP1, NULL, 2, -1, NR_PAIRS1}, + $STATEMENT_INFO +}; + +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; + + static void *instructionLabel[] = { + &&INST_objProc, + $INSTRUCTION_LABELS, + &&INST_NULL + }; + + + /* + * Place a copy of the actual argument into locals. + */ + for (i=1; i < argc; i++) { + proc->locals[i-1] = argv[i]; + } + /* + * Update all references to compiled arguments. + */ + for (i=0; i < proc->nrAsmArgReferences; i++) { + AsmArgReference *arPtr = &proc->argReferences[i]; + *(arPtr->objPtr) = proc->locals[arPtr->argNr]; + } + + /* + * Set the instruction pointer to the begin of the code. + */ + ip = proc->code; + proc->status = 0; + + //fprintf(stderr, "AsmExecute jumps to %p\n", ip); + + goto *instructionLabel[ip->labelIdx]; + + INST_NULL: + return result; + + EXEC_RESULT_CODE_HANDLER: + if (likely(result == TCL_OK)) { + ip++; + goto *instructionLabel[ip->labelIdx]; + } else { + return result; + } + + INST_objProc: + result = (*ip->cmd)(ip->clientData, interp, ip->argc, ip->argv); + goto EXEC_RESULT_CODE_HANDLER; + + $GENERATED_INSTRUCTIONS +} Index: generic/genAssemble.tcl =================================================================== diff -u -N --- generic/genAssemble.tcl (revision 0) +++ generic/genAssemble.tcl (revision 04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb) @@ -0,0 +1,406 @@ +package require nx + +###################################################################### +# The code engine +###################################################################### + +nsf::proc generate {threadingType:class} { + 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 {} + foreach instruction $instructions { + append GENERATED_INSTRUCTIONS [$instruction generate] \n + lappend labels &&[$instruction labelName] + lappend indices IDX_[$instruction cName] + } + Instruction mixin delete ${threadingType}::Instruction + set INSTRUCTION_LABELS [join $labels ",\n "] + set INSTRUCTION_INDICES [join $indices ",\n "] + + set statementIndex {} + set statementNames {} + 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 flags 0 + if {[$s info has type ::Declaration]} { + lappend flags ASM_INFO_DECL + } + if {[$s mustContainPairs]} { + lappend flags ASM_INFO_PAIRS + } + lappend statementInfo \ + "/* [$s cName] */\n {[join $flags |], [$s argTypes], [$s minArgs], [$s maxArgs], [$s cArgs]}" + } + set STATEMENT_INDICES [join $statementIndex ",\n "] + set STATEMENT_NAMES [join $statementNames ",\n "] + set STATEMENT_INFO [join $statementInfo ",\n "] + + #puts stderr statementIndex=$statementIndex + #puts stderr statementNames=$statementNames + + set f [open $dirName/nsfAsmExecute$suffix.c w] + puts $f [subst -nocommand -nobackslash $template] + close $f +} + +###################################################################### +# Basic Class for Instructions and Declarations +###################################################################### +nx::Class create Statement { + :property {name "[namespace tail [self]]"} + :property {mustContainPairs true} + :property {argTypes NULL} + :property {minArgs 0} + :property {maxArgs 0} + :property {cArgs 0} + + :public method cName {} { + # prepend asm and capitalize first character + return asm[string toupper [string range ${:name} 0 0]][string range ${:name} 1 end] + } +} + +###################################################################### +# Basic Class for Instructions and Declarations +###################################################################### +nx::Class create Declaration -superclass Statement { +} + +###################################################################### +# Basic Class for defining Instructions independent of the code +# generator (label threading, call threading) +###################################################################### + +nx::Class create Instruction -superclass Statement { + :property {execCode ""} + + :property {isJump false} + :property {returnsResult false} + + :method "code get" {} { + return ${:cCode} + } + + :method "code append" {value} { + append :cCode $value + } + + :method "code mustAssign" {value} { + if {![regexp "\\m${value}\\M\\s*=" ${:cCode}]} { + error "code does not assign variable '$value': ${:cCode}" + } + } +} + +###################################################################### +# Code Generator for Label Threading +###################################################################### + +nx::Class create LabelThreading { + nx::Class create [self]::Instruction { + # + # This Class is designed as a mixin class for Instruction + # + :public method labelName {} { + return INST_[:cName] + } + :method nextInstruction {} { + if {[:isJump]} { + :code mustAssign ip + :code append "\n goto *instructionLabel\[ip->labelIdx];\n" + } else { + :code append "\n ip++;\n goto *instructionLabel\[ip->labelIdx];\n" + } + } + :public method "code generate" {} { + :code append ${:execCode} + if {[:returnsResult]} { + :code mustAssign result + :code append " goto EXEC_RESULT_CODE_HANDLER;\n" + } + } + + :public method generate {} { + :code append [:labelName]:\n + :code generate + :nextInstruction + return [:code get] + } + } +} + +namespace eval ::asm { + ###################################################################### + # Declarations + ###################################################################### + + # {obj a} + Declaration create obj \ + -mustContainPairs false \ + -minArgs 2 -maxArgs 2 + + # {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 + + + + ###################################################################### + # Instructions + ###################################################################### + + # {noop} + Instruction create noop \ + -mustContainPairs false \ + -minArgs 1 -maxArgs 1 + + # {eval obj 0 obj 1 obj 2} + Instruction create dispatch \ + -name "eval" \ + -minArgs 3 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmCmdArgTypes \ + -returnsResult true \ + -execCode { + result = Tcl_EvalObjv(interp, ip->argc, ip->argv, 0); + } + + # {methodDelegateDispatch obj 0 obj 1 obj 2} + Instruction create methodDelegateDispatch \ + -name "methodDelegateDispatch" \ + -minArgs 5 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmCmdArgTypes \ + -returnsResult true \ + -execCode { + // obj and method are unresolved + result = GetObjectFromObj(interp, ip->argv[0], &object); + if (likely(ip->clientData != NULL)) { + cmd = clientData; + } else { + cmd = Tcl_GetCommandFromObj(interp, ip->argv[1]); + } + //fprintf(stderr, "cmd %p object %p\n", cmd, object); + result = MethodDispatch(object, interp, ip->argc-1, ip->argv+1, cmd, object, NULL, + ObjStr(ip->argv[1]), 0, 0); + } + + # methodDelegateDispatch11 is an optimized variant of + # methodDelegateDispatch, emitted alternatively by the assembler for + # the above instruction. + Instruction create methodDelegateDispatch11 \ + -returnsResult true \ + -execCode { + // obj and method are resolved + { + AsmResolverInfo *resInfo = ip->clientData; + result = MethodDispatch(resInfo->object, interp, ip->argc-1, ip->argv+1, + resInfo->cmd, resInfo->object, NULL, + ObjStr(ip->argv[1]), 0, 0); + } + } + + + # {methodSelfDispatch obj 0 obj 1 obj 2} + + Instruction create methodSelfDispatch \ + -minArgs 3 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmCmdArgTypes \ + -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, + ip->argc, ip->argv, + cmd, resInfo->asmProc->currentObject, NULL, + ObjStr(ip->argv[0]), 0, 0); + } + } + + # methodSelfCmdDispatch is an optimized variant of + # methodSelfDispatch, emitted alternatively by the assembler for the + # above instruction. + Instruction create methodSelfCmdDispatch \ + -returnsResult true \ + -execCode { + { + AsmResolverInfo *resInfo = ip->clientData; + assert(resInfo->cmd != NULL); + result = Tcl_NRCallObjProc(interp, Tcl_Command_objProc(resInfo->cmd), resInfo->asmProc->currentObject, + ip->argc, ip->argv); + } + } + + # {self} + # TODO: rename instruction to self ? why "method" + Instruction create methodSelf \ + -minArgs 1 -maxArgs 1 \ + -execCode { + Tcl_SetObjResult(interp, proc->currentObject->cmdName); + } + + + # {jump int 2} + # TODO: should force arg1 "int", maybe define later jump labels in asm source + Instruction create jump \ + -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmCmdArgTypes \ + -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 + Instruction create jumpTrue \ + -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmCmdArgTypes \ + -isJump true \ + -execCode { + if (proc->status) { + //fprintf(stderr, "asmJumpTrue jump oc %d instructionIndex %d\n", ip->argc, PTR2INT(ip->argv[0])); + ip = &proc->code[PTR2INT(ip->argv[0])]; + } else { + //fprintf(stderr, "asmJumpTrue fall through\n"); + ip++; + } + } + + # {leScalar int 4 int 7} + # TODO: should force arg1 & arg2 "int" + Instruction create leScalar \ + -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmCmdArgTypes \ + -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]); + + // for the time being, we compare two int values + obj = proc->slots[PTR2INT(ip->argv[0])]; + if (likely(obj->typePtr == Nsf_OT_intType)) { + value1 = obj->internalRep.longValue; + } else { + Tcl_GetIntFromObj(interp, obj, &value1); + } + obj = proc->slots[PTR2INT(ip->argv[1])]; + if (likely(obj->typePtr == Nsf_OT_intType)) { + value2 = obj->internalRep.longValue; + } else { + Tcl_GetIntFromObj(interp, obj, &value2); + } + //fprintf(stderr, "asmLeScalar oc %d op1 %d op2 %d => %d\n", ip->argc, value1, value2, value1 <= value2); + + proc->status = value1 <= value2; + } + } + + + # {copyScalar int 6 obj 2} + # TODO: rename copyObj + # TODO: should force arg1 "int" + + Instruction create copyScalar \ + -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmCmdArgTypes \ + -execCode { + indexValue = PTR2INT(ip->argv[0]); + //fprintf(stderr, "asmCopyScalar 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 + } + + + # {setScalar int 2 arg 0} + # TODO: should force arg1 "int" + Instruction create setScalar \ + -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmCmdArgTypes \ + -execCode { + indexValue = PTR2INT(ip->argv[0]); + //fprintf(stderr, "asmSetScalar var[%d] = %s\n", indexValue, ObjStr(ip->argv[1])); + proc->slots[indexValue] = ip->argv[1]; + } + + # {setScalarResult int 5} + # TODO: should force arg1 "int" + Instruction create setScalarResult \ + -minArgs 3 -maxArgs 3 -cArgs 2 -argTypes asmCmdArgTypes \ + -execCode { + indexValue = PTR2INT(ip->argv[0]); + //fprintf(stderr, "asmSetScalar var[%d] = %s\n", indexValue, ObjStr(ip->argv[1])); + proc->slots[indexValue] = Tcl_GetObjResult(interp); + } + + # {setResult int 6} + # TODO: should force arg1 "int" + Instruction create setResult \ + -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmCmdArgTypes \ + -execCode { + indexValue = PTR2INT(ip->argv[0]); + Tcl_SetObjResult(interp, proc->slots[indexValue]); + //fprintf(stderr, "asmSetResult index %d => '%s'\n", indexValue, ObjStr(proc->slots[indexValue])); + } + + + # {store code 4 argv 2} + Instruction create storeResult \ + -minArgs 5 -maxArgs 5 -cArgs 0 -argTypes asmAddrTypes \ + -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 \ + -execCode { + { + int intValue, incrValue; + Tcl_Obj *intObj, *incrObj; + + //fprintf(stderr, "asmIncrScalar var[%d] incr var[%d], ", PTR2INT(ip->argv[0]), PTR2INT(ip->argv[1])); + + intObj = proc->slots[PTR2INT(ip->argv[0])]; + incrObj = proc->slots[PTR2INT(ip->argv[1])]; + + if (likely(intObj->typePtr == Nsf_OT_intType)) { + intValue = intObj->internalRep.longValue; + } else { + Tcl_GetIntFromObj(interp, intObj, &intValue); + } + + if (likely(incrObj->typePtr == Nsf_OT_intType)) { + incrValue = incrObj->internalRep.longValue; + } else { + Tcl_GetIntFromObj(interp, incrObj, &incrValue); + } + + //fprintf(stderr, "%d + %d = %d,", intValue, incrValue, intValue + incrValue); + + Tcl_InvalidateStringRep(intObj); + intObj->internalRep.longValue = (long)(intValue + incrValue); + + //fprintf(stderr, "updated %p var[%d] %p\n", intObj, PTR2INT(ip->argv[0]), proc->slots[PTR2INT(ip->argv[0])]); + + Tcl_SetObjResult(interp, intObj); + } + } + +} + +###################################################################### +# generate the code +###################################################################### + +generate ::LabelThreading \ No newline at end of file Index: generic/nsf.c =================================================================== diff -u -N -r7def5bc35b6d31f0390d943d6d2221f8938b0e8a -r04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb --- generic/nsf.c (.../nsf.c) (revision 7def5bc35b6d31f0390d943d6d2221f8938b0e8a) +++ generic/nsf.c (.../nsf.c) (revision 04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb) @@ -1,3 +1,4 @@ +#define NSF_ASSEMBLE 1 /* * nsf.c -- * @@ -221,7 +222,9 @@ static Tcl_ObjCmdProc NsfObjscopedMethod; static Tcl_ObjCmdProc NsfSetterMethod; static Tcl_ObjCmdProc NsfProcAliasMethod; +static Tcl_ObjCmdProc NsfAsmProc; + /* prototypes for methods called directly when CallDirectly() returns NULL */ static int NsfCAllocMethod(Tcl_Interp *interp, NsfClass *cl, Tcl_Obj *nameObj); static int NsfCCreateMethod(Tcl_Interp *interp, NsfClass *cl, CONST char *name, int objc, Tcl_Obj *CONST objv[]); @@ -770,7 +773,6 @@ #include "nsfStack.c" - /*********************************************************************** * Value added replacements of Tcl functions ***********************************************************************/ @@ -9421,6 +9423,13 @@ return result; } +#if !defined(NSF_ASSEMBLE) +static int NsfAsmProc(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) { + return TCL_OK; +} +#endif + /* *---------------------------------------------------------------------- * MethodDispatchCsc -- @@ -9672,7 +9681,8 @@ } else if (proc == NsfForwardMethod || proc == NsfObjscopedMethod || - proc == NsfSetterMethod + proc == NsfSetterMethod || + proc == NsfAsmProc ) { TclCmdClientData *tcd = (TclCmdClientData *)cp; @@ -11950,7 +11960,7 @@ Tcl_PushCallFrame(interp, (Tcl_CallFrame *)framePtr, nsPtr, 0); /* create the method in the provided namespace */ - result = Tcl_ProcObjCmd(0, interp, 4, ov); + result = Tcl_ProcObjCmd(NULL, interp, 4, ov); if (result == TCL_OK) { /* retrieve the defined proc */ Proc *procPtr = FindProcMethod(nsPtr, methodName); @@ -12082,7 +12092,7 @@ } /************************************************************************** - * Begin Definition of Parameter procs (Tcl Procs with Parameter handling) + * Begin Definition of nsf::proc (Tcl Procs with Parameter handling) **************************************************************************/ /* *---------------------------------------------------------------------- @@ -12310,8 +12320,7 @@ * * TODO: the current 1 cmd + 1 proc implementation is not robust * against renaming and partial deletions (deletion of the - * stub). The sketched variant should be better and should be - * examined first in detail. + * stub). * * Results: * Tcl return code. @@ -12544,7 +12553,7 @@ return TCL_OK; } /************************************************************************** - * End Definition of Parameter procs (Tcl Procs with Parameter handling) + * End Definition of nsf::proc (Tcl Procs with Parameter handling) **************************************************************************/ /* @@ -17857,6 +17866,16 @@ return 0; } +#if defined(NSF_ASSEMBLE) +# include "nsfAssemble.c" +#else +static int +NsfAsmMethodCreateCmd(Tcl_Interp *interp, NsfObject *defObject, + int withInner_namespace, int withPer_object, NsfObject *regObject, + Tcl_Obj *nameObj, Tcl_Obj *argumentsObj, Tcl_Obj *bodyObj) { + return TCL_OK; +} +#endif /*********************************************************************** * Begin generated Next Scripting commands @@ -18051,6 +18070,52 @@ } /* +cmd asmproc NsfAsmProcCmd { + {-argName "-ad" -required 0} + {-argName "procName" -required 1 -type tclobj} + {-argName "arguments" -required 1 -type tclobj} + {-argName "body" -required 1 -type tclobj} +} +*/ +#if !defined(NSF_ASSEMBLE) +static int +NsfAsmProcCmd(Tcl_Interp *interp, int with_ad, Tcl_Obj *nameObj, Tcl_Obj *arguments, Tcl_Obj *body) { + return TCL_OK; +} +#else +static int +NsfAsmProcCmd(Tcl_Interp *interp, int with_ad, Tcl_Obj *nameObj, Tcl_Obj *arguments, Tcl_Obj *body) { + NsfParsedParam parsedParam; + int result; + /* + * Parse argument list "arguments" to determine if we should provide + * nsf parameter handling. + */ + result = ParamDefsParse(interp, nameObj, arguments, + NSF_DISALLOWED_ARG_METHOD_PARAMETER, 0, + &parsedParam); + if (result != TCL_OK) { + return result; + } + + if (parsedParam.paramDefs) { + /* + * We need parameter handling. + */ + result = NsfAsmProcAddParam(interp, &parsedParam, nameObj, body, with_ad); + + } else { + /* + * No parameter handling needed. + */ + result = NsfAsmProcAddArgs(interp, arguments, nameObj, body, with_ad); + } + + return result; +} +#endif + +/* cmd configure NsfConfigureCmd { {-argName "configureoption" -required 1 -type "debug|dtrace|filter|profile|softrecreate|objectsystems|keepinitcmd|checkresults|checkarguments"} {-argName "value" -required 0 -type tclobj} @@ -19772,13 +19837,13 @@ * later. */ result = NsfProcAdd(interp, &parsedParam, ObjStr(nameObj), body, with_ad); - + } else { /* * No parameter handling needed. A plain Tcl proc is added. */ Tcl_Obj *ov[4]; - + ov[0] = NULL; ov[1] = nameObj; ov[2] = arguments; Index: generic/nsfAPI.decls =================================================================== diff -u -N -r28648322161a72f3a5e0458fdefc110326322cba -r04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb --- generic/nsfAPI.decls (.../nsfAPI.decls) (revision 28648322161a72f3a5e0458fdefc110326322cba) +++ generic/nsfAPI.decls (.../nsfAPI.decls) (revision 04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb) @@ -29,6 +29,13 @@ cmd __profile_get NsfProfileGetDataStub {} cmd __unset_unknown_args NsfUnsetUnknownArgsCmd {} +cmd "asm::proc" NsfAsmProcCmd { + {-argName "-ad" -required 0 -nrargs 0} + {-argName "procName" -required 1 -type tclobj} + {-argName "arguments" -required 1 -type tclobj} + {-argName "body" -required 1 -type tclobj} +} + cmd configure NsfConfigureCmd { {-argName "configureoption" -required 1 -type "debug|dtrace|filter|profile|softrecreate|objectsystems|keepinitcmd|checkresults|checkarguments"} {-argName "value" -required 0 -type tclobj} @@ -91,6 +98,17 @@ {-argName "-precondition" -type tclobj} {-argName "-postcondition" -type tclobj} } {-nxdoc 1} + +cmd method::asmcreate NsfAsmMethodCreateCmd { + {-argName "object" -required 1 -type object} + {-argName "-inner-namespace" -nrargs 0} + {-argName "-per-object" -nrargs 0} + {-argName "-reg-object" -required 0 -nrargs 1 -type object} + {-argName "name" -required 1 -type tclobj} + {-argName "arguments" -required 1 -type tclobj} + {-argName "body" -required 1 -type tclobj} +} + cmd "method::delete" NsfMethodDeleteCmd { {-argName "object" -required 1 -type object} {-argName "-per-object" -nrargs 0} @@ -173,6 +191,7 @@ {-argName "arguments" -required 1 -type tclobj} {-argName "body" -required 1 -type tclobj} } {-nxdoc 1} + cmd relation NsfRelationCmd { {-argName "object" -required 1 -type object} {-argName "relationtype" -required 1 -type "object-mixin|class-mixin|object-filter|class-filter|class|superclass|rootclass"} Index: generic/nsfAPI.h =================================================================== diff -u -N -r7def5bc35b6d31f0390d943d6d2221f8938b0e8a -r04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb --- generic/nsfAPI.h (.../nsfAPI.h) (revision 7def5bc35b6d31f0390d943d6d2221f8938b0e8a) +++ generic/nsfAPI.h (.../nsfAPI.h) (revision 04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb) @@ -238,6 +238,8 @@ static int NsfClassInfoSlotobjectsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfClassInfoSubclassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfClassInfoSuperclassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfAsmMethodCreateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfAsmProcCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfColonCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfConfigureCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfCurrentCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); @@ -336,6 +338,8 @@ static int NsfClassInfoSlotobjectsMethod(Tcl_Interp *interp, NsfClass *cl, int withClosure, int withSource, NsfClass *withType, CONST char *pattern); static int NsfClassInfoSubclassMethod(Tcl_Interp *interp, NsfClass *cl, int withClosure, CONST char *patternString, NsfObject *patternObject); static int NsfClassInfoSuperclassMethod(Tcl_Interp *interp, NsfClass *cl, int withClosure, Tcl_Obj *pattern); +static int NsfAsmMethodCreateCmd(Tcl_Interp *interp, NsfObject *object, int withInner_namespace, int withPer_object, NsfObject *withReg_object, Tcl_Obj *name, Tcl_Obj *arguments, Tcl_Obj *body); +static int NsfAsmProcCmd(Tcl_Interp *interp, int withAd, Tcl_Obj *procName, Tcl_Obj *arguments, Tcl_Obj *body); static int NsfColonCmd(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int NsfConfigureCmd(Tcl_Interp *interp, int configureoption, Tcl_Obj *value); static int NsfCurrentCmd(Tcl_Interp *interp, int currentoption); @@ -435,6 +439,8 @@ NsfClassInfoSlotobjectsMethodIdx, NsfClassInfoSubclassMethodIdx, NsfClassInfoSuperclassMethodIdx, + NsfAsmMethodCreateCmdIdx, + NsfAsmProcCmdIdx, NsfColonCmdIdx, NsfConfigureCmdIdx, NsfCurrentCmdIdx, @@ -1001,6 +1007,53 @@ } static int +NsfAsmMethodCreateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + ParseContext pc; + (void)clientData; + + if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], + method_definitions[NsfAsmMethodCreateCmdIdx].paramDefs, + method_definitions[NsfAsmMethodCreateCmdIdx].nrParameters, 0, 1, + &pc) == TCL_OK)) { + NsfObject *object = (NsfObject *)pc.clientData[0]; + int withInner_namespace = (int )PTR2INT(pc.clientData[1]); + int withPer_object = (int )PTR2INT(pc.clientData[2]); + NsfObject *withReg_object = (NsfObject *)pc.clientData[3]; + Tcl_Obj *name = (Tcl_Obj *)pc.clientData[4]; + Tcl_Obj *arguments = (Tcl_Obj *)pc.clientData[5]; + Tcl_Obj *body = (Tcl_Obj *)pc.clientData[6]; + + assert(pc.status == 0); + return NsfAsmMethodCreateCmd(interp, object, withInner_namespace, withPer_object, withReg_object, name, arguments, body); + + } else { + return TCL_ERROR; + } +} + +static int +NsfAsmProcCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + ParseContext pc; + (void)clientData; + + if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], + method_definitions[NsfAsmProcCmdIdx].paramDefs, + method_definitions[NsfAsmProcCmdIdx].nrParameters, 0, 1, + &pc) == TCL_OK)) { + int withAd = (int )PTR2INT(pc.clientData[0]); + Tcl_Obj *procName = (Tcl_Obj *)pc.clientData[1]; + Tcl_Obj *arguments = (Tcl_Obj *)pc.clientData[2]; + Tcl_Obj *body = (Tcl_Obj *)pc.clientData[3]; + + assert(pc.status == 0); + return NsfAsmProcCmd(interp, withAd, procName, arguments, body); + + } else { + return TCL_ERROR; + } +} + +static int NsfColonCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { (void)clientData; @@ -2494,6 +2547,21 @@ {"-closure", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, +{"::nsf::method::asmcreate", NsfAsmMethodCreateCmdStub, 7, { + {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertToObject, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, + {"-inner-namespace", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"-per-object", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"-reg-object", 0, 1, Nsf_ConvertToObject, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, + {"name", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"arguments", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"body", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, +{"::nsf::asm::proc", NsfAsmProcCmdStub, 4, { + {"-ad", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"procName", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"arguments", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"body", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, {"::nsf::colon", NsfColonCmdStub, 1, { {"args", 0, 1, ConvertToNothing, NULL,NULL,"allargs",NULL,NULL,NULL,NULL,NULL}} }, Index: generic/nsfAPI.nxdocindex =================================================================== diff -u -N -rc03f5a73e6aba594682fe6dbae0621b37bb2599d -r04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb --- generic/nsfAPI.nxdocindex (.../nsfAPI.nxdocindex) (revision c03f5a73e6aba594682fe6dbae0621b37bb2599d) +++ generic/nsfAPI.nxdocindex (.../nsfAPI.nxdocindex) (revision 04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb) @@ -5,6 +5,7 @@ set ::nxdoc::include(::nsf::__profile_clear) 0 set ::nxdoc::include(::nsf::__profile_get) 0 set ::nxdoc::include(::nsf::__unset_unknown_args) 0 +set ::nxdoc::include(::nsf::asm::proc) 0 set ::nxdoc::include(::nsf::configure) 1 set ::nxdoc::include(::nsf::colon) 0 set ::nxdoc::include(::nsf::directdispatch) 0 @@ -16,6 +17,7 @@ set ::nxdoc::include(::nsf::method::alias) 1 set ::nxdoc::include(::nsf::method::assertion) 1 set ::nxdoc::include(::nsf::method::create) 1 +set ::nxdoc::include(::nsf::method::asmcreate) 0 set ::nxdoc::include(::nsf::method::delete) 1 set ::nxdoc::include(::nsf::method::forward) 1 set ::nxdoc::include(::nsf::method::property) 1 Index: library/lib/nx-test.tcl =================================================================== diff -u -N -raca47b6a2e650115cb1b517e62c6d1c33bdc89c6 -r04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb --- library/lib/nx-test.tcl (.../nx-test.tcl) (revision aca47b6a2e650115cb1b517e62c6d1c33bdc89c6) +++ library/lib/nx-test.tcl (.../nx-test.tcl) (revision 04e3056621ba12a8eacb56a92f5d3d00fdbbbfbb) @@ -39,10 +39,13 @@ # and (2) destroys all created objects on exit (auto cleanup) # # General limitation: namespace resolving differs in nested evals - # from global evals. So, this approach is not suitable for all test + # from global evals. So, this approach is not suitable for all tests # (but for most). # - # Current limitations: just for nx::Objects, no method/mixin cleanup/var cleanup + # Current limitations: + # - cleanup for for nx::Objects, + # - no method/mixin cleanup + # - no var cleanup # set :case $name @@ -103,10 +106,13 @@ } if {[:verbose]} {puts stderr "running test $c times"} if {$c > 1} { + set r0 [time {time {::namespace eval ${:namespace} ";"} $c}] + regexp {^(-?[0-9]+) +} $r0 _ mS0 set r1 [time {time {::namespace eval ${:namespace} ${:cmd}} $c}] + #puts stderr "running {time {::namespace eval ${:namespace} ${:cmd}} $c} => $r1" regexp {^(-?[0-9]+) +} $r1 _ mS1 - set ms [expr {$mS1*1.0/$c}] - puts stderr "[set :name]:\t[format %6.2f $ms] mms, ${:msg}" + set ms [expr {($mS1 - $mS0) * 1.0 / $c}] + puts stderr "[set :name]:\t[format %6.2f $ms] mms, ${:msg} (overhead [format %.2f [expr {$mS0*1.0/$c}]])" } else { puts stderr "[set :name]: ${:msg} ok" }