2017-03-14 1 views
0

J'utilise tcl dans c et en général nous créons un nouvel espace de nom pour chaque exécution d'un script tcl. Si j'utilise proc dans le script, sera-t-il dans le même espace de noms? Comment proc est-il converti en bytecode? est-il converti sous le même espace de noms de l'appelant? Est-ce que ce sera sur un espace de noms différent et pourrait invalider le bytecode? Pouvez-vous s'il vous plaît également me donner une brève explication de ce qui est exactement tcl bytecode et comment nous obtenons des variables (locales et globales) des hachages, et comment upvar l'effet?Tcl bytecode et procs

Merci beaucoup !!!

Répondre

2

Chaque procédure dans Tcl sait quel est son espace de noms; c'est la même chose que l'espace de noms contenant son nom (il y en a toujours un, l'espace de noms global est appelé ::). En tant que tel, cela n'a probablement pas beaucoup de sens de créer un nouvel espace de noms pour chaque exécution. Le bytecode lui-même (qui s'exécute sur une sorte de machine à pile définie en tclExecute.c dans le code source Tcl) est créé lorsqu'il est nécessaire, ce qui est généralement le cas lorsque vous êtes sur le point d'exécuter la procédure pour la première fois. Vous pouvez imprimer le bytecode en utilisant la commande tcl::unsupported::disassemble:

% proc example {x} { 
    return [expr {$x * 2 + 3}] 
} 
% puts [tcl::unsupported::disassemble proc example] 
ByteCode 0x0x1008d1b10, refCt 1, epoch 15, interp 0x0x100829a10 (epoch 15) 
    Source "\n return [expr {$x * 2 + 3}]"... 
    Cmds 2, src 32, inst 9, litObjs 2, aux 0, stkDepth 2, code/src 0.00 
    Proc 0x0x103028010, refCt 1, args 1, compiled locals 1 
     slot 0, scalar, arg, "x" 
    Commands 2: 
     1: pc 0-8, src 5-30  2: pc 0-7, src 13-29 
    Command 1: "return [expr {$x * 2 + 3}]"... 
    Command 2: "expr {$x * 2 + 3}"... 
    (0) loadScalar1 %v0  # var "x" 
    (2) push1 0  # "2" 
    (4) mult 
    (5) push1 1  # "3" 
    (7) add 
    (8) done 

versions Nouveau-assez de Tcl 8.6 prennent également en charge tcl::unsupported::getbytecode, qui fournit un accès lisible par une machine aux mêmes sortes d'informations. Vous ne voulez pas vraiment analyser la sortie de disassemble.

L'appel d'une procédure à partir d'un espace de noms différent n'invalide pas le bytecode pour cette procédure. (Pourquoi cela serait-il désespérément inefficace pour le code de la bibliothèque!) Mais il existe des opérations qui savent comment accéder au monde extérieur. Faisons un exemple avec upvar:

% proc example2 {xvar} { 
    upvar 1 $xvar x 
    return [expr {[incr x] * 2 + 3}] 
} 
% puts [tcl::unsupported::disassemble proc example2] 
ByteCode 0x0x10300e610, refCt 1, epoch 15, interp 0x0x100829a10 (epoch 15) 
    Source "\n upvar 1 $xvar x\n return [expr {[incr x] * 2 +"... 
    Cmds 4, src 58, inst 33, litObjs 4, aux 0, stkDepth 2, code/src 0.00 
    Proc 0x0x103028390, refCt 1, args 1, compiled locals 2 
     slot 0, scalar, arg, "xvar" 
     slot 1, scalar, "x" 
    Commands 4: 
     1: pc 0-12, src 5-19  2: pc 13-31, src 25-56 
     3: pc 22-30, src 33-55  4: pc 22-24, src 40-45 
    Command 1: "upvar 1 $xvar x"... 
    (0) push1 0  # "1" 
    (2) loadScalar1 %v0  # var "xvar" 
    (4) upvar %v1 # var "x" 
    (9) pop 
    (10) nop 
    (11) nop 
    (12) nop 
    Command 2: "return [expr {[incr x] * 2 + 3}]"... 
    (13) startCommand +19 3  # next cmd at pc 32, 3 cmds start here 
    Command 3: "expr {[incr x] * 2 + 3}"... 
    Command 4: "incr x"... 
    (22) incrScalar1Imm %v1 +1 # var "x" 
    (25) push1 2 # "2" 
    (27) mult 
    (28) push1 3 # "3" 
    (30) add 
    (31) done 
    (32) done 

La séquence des opérations pour upvar lui-même de pousser sur la pile le paramètre de niveau et le nom de la variable à distance (qui, dans ce cas provient d'une variable passée en tant argument), puis le upvar %v1 qui lie l'entrée de table de variable locale à l'index 1 à la variable de portée 1 (l'appelant) appelée par le nom qui vient de xvar. La liaison est faite en faisant en fait la variable locale être un pointeur vers l'autre variable; une fois fabriqué, il est très efficace. La commande global utilise un mécanisme similaire mais légèrement différent (l'opcode nsupvar se lie à une variable dans un espace de nom nommé).

Il existe quelques opérations qui invalident le bytecode, mais il s'agit de relocaliser une procédure ou une commande dotée d'une fonction de compilation. Si vous n'utilisez pas rename, vous n'aurez probablement jamais besoin de vous en préoccuper (et c'est entièrement automatique).


Faire un upvar dans une procédure (généralement d'une autre procédure) est un peu différent, puisque vous regardez des variables par leur nom. La table de noms pour la table de variables locale fait partie des métadonnées de procédure, et toute variable qui n'y figure pas est stockée dans une table de hachage (utilisée lorsque vous avez un upvar dans la procédure qui utilise un nom non utilisé à d'autres fins comme variable à l'intérieur de ce proc, cela peut arriver même si ce n'est pas très commun).

Si vous voulez vraiment les détails, il n'y a pas de substitut pour lire le code source Tcl.Le bytecode est généré dans plusieurs endroits, mais le cœur de celui-ci est tclCompile.c; le moteur d'exécution associé est au tclExecute.c. Les procédures sont définies dans tclProc.c, les espaces de noms dans tclNamesp.c et les variables dans tclVar.c. Il y a probablement d'autres endroits pertinents à regarder, mais ce sont les principaux.