Accueil Ti-Gen Foire Aux Questions Chat sur le chan #tigcc sur IRC
Liste des membres Rechercher Aide
Bienvenue Invité !   Se connecter             Mes sujets   
Administrer
0 membre(s) et 1 visiteur(s) actif(s) durant les 5 dernières minutes Utilisateurs actifs : Aucun membre + 1 visiteur
Avant de poster sur le forum, il y a des régles de bases à respecter pour une bonne entente et un respect de tous.
Veuillez lire la charte du forum.
  :: Index » Forum Ti68K » Programmation C » Orienté objet avec TIGCC (113 réponse(s))
./REPRISE DU POST PRECEDENT (post n°76)   Marquer comme non lu.
Onur Ecrit le: Samedi 21 octobre 2006 à 16:35 Déconnecté(e)    Voir le profil de Onur Envoyer un email à Onur Visiter le site WEB de Onur Envoyer un message privé à Onur  


Pour les spécs, tout ce que je veux, c'est qu'on puisse hériter et gérer un minimum de polymorphisme pour faire ce que j'ai dit plus haut... Càd hériter d'une classe Sprite dont l'affichage et les collisions dans une map sont automatiquement gérés grace à des routines écrites en asm.

La, je sais pas si vous vous rendez compte, mais j'ai l'impression qu'on design d'un outil qui va vraiment apporter à la communauté. Et le fait que l'auteur ne soit pas un waporman me plait bcp. (Parce qu'il y en avait marre des mecs qui viennent poster pour faire un compilo et qui foutent rien, bref)
Je ne veux pas faire quelque chose de bien, je cherche l'excellence:ETP Studio...


et autres projets à finir avant 2010
    
./Post n°77   Marquer comme non lu.
Quésoft Ecrit le: Samedi 21 octobre 2006 à 17:34 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Onur :
Pour les spécs, tout ce que je veux, c'est qu'on puisse hériter et gérer un minimum de polymorphisme pour faire ce que j'ai dit plus haut... Càd hériter d'une classe Sprite dont l'affichage et les collisions dans une map sont automatiquement gérés grace à des routines écrites en asm.


Il me serait impensable de ne pas supporter le polymorphisme (à quoi servirait l'OO, alors ?). Il y aura des interface aussi (comme en moka). Alors ce que vous voullez faire sera possible.

BTW, voici un 'vrai' message d'erreur (proche de ce que vous voulliez, je crois). Le parseur ne reconnaît à peu près rien encore, mais cet output vient vraiment de la fonction que j'ai codé pour afficher les erreurs de compilation:


Error (file 'test.m', line 7): 'class' expected after 'public' keyword.
public crap
          ^
Preprocessing failed: 1 errors, 0 warnings.


(en fait, modifié un peu parce que le nombre d'erreur affiché n'était pas bon à cause que je suis en train de faire des modifs)

Onur :
La, je sais pas si vous vous rendez compte, mais j'ai l'impression qu'on design d'un outil qui va vraiment apporter à la communauté. Et le fait que l'auteur ne soit pas un waporman me plait bcp.


C'est ça l'objectif. #oui# c'est bien d'avoir du feedback et des conseils en cours de développement.

Onur :
(Parce qu'il y en avait marre des mecs qui viennent poster pour faire un compilo et qui foutent rien, bref)


Je suis content de constater qu'avoir sorti Moka m'aura donné au moins du crédit :)
-Edité le Samedi 21 octobre 2006 à 17:36 par Quésoft-
    
./Post n°78   Marquer comme non lu.
geogeo Ecrit le: Samedi 21 octobre 2006 à 18:21 Déconnecté(e)    Voir le profil de geogeo Envoyer un email à geogeo Visiter le site WEB de geogeo Envoyer un message privé à geogeo  


Onur :
(Parce qu'il y en avait marre des mecs qui viennent poster pour faire un compilo et qui foutent rien, bref)


?
Webmaster du site.
Programmeur sur TI68K. Arkanoid, Nebulus, GFA-Basic.

Plus d'informations sur GFA-Basic (un langage Basic pour TI68K).
http://www.tigen.org/gfabasic
    
./Post n°79   Marquer comme non lu.
Kevin Kofler Ecrit le: Samedi 21 octobre 2006 à 22:37 Déconnecté(e)    Voir le profil de Kevin Kofler Envoyer un email à Kevin Kofler Visiter le site WEB de Kevin Kofler Envoyer un message privé à Kevin Kofler  


Pollux :
Ben pourquoi #confus# Les seules garanties dont on a besoin qui ne soient pas dans le standard C, c'est :
- une structure locale dont on passe l'adresse à une fonction externe est toujours allouée sur la pile

C'est probablement faux depuis GCC 4.0: le scalar replacement of aggregates en combinaison avec life range splitting et/ou inlining peut détruire cette présupposition (même si j'avoue que je ne suis pas sûr que ces combinaisons d'optimisations soient employées par GCC, les optimisations individuelles le sont).

- la pile se trouve toujours *après* a7

Vrai avec TIGCC, mais faux sur pas mal d'autres plateformes. De plus "%a7" n'est pas portable. Et si on met de la buffer overflow protection dans TIGCC (GCC 4.1 gère déjà ça, c'est juste que TIGCCLIB ne le gère pas à l'heure actuelle.), alors tu ne pourras plus lire et écrire n'importe où sur la pile.

- si la fonction f appelle la fonction g les variables locales de g seront toujours avant celles de f

Faux après inlining.

Je pense pas qu'un compilo TI ait l'intention de violer ces conventions :)

Si, TIGCC a cette intention, et c'est probablement déjà le cas.

(la seule qui soit un peu problématique, c'est la 1ère : un compilo qui se rend compte qu'une fonction n'est pas réentrante pourrait en principe décider d'allouer une structure locale dans le segment data, mais l'intérêt me paraît limité et en tout cas ce n'est implémenté ni dans gtc ni dans gcc, aux dernières nouvelles)

Il n'y a pas que ça: après inlining et élimination de la prise d'adresse, la structure peut être scalarisée. De plus, le temps de vie de la structure peut être splitté, et ensuite la structure scalarisée en dehors des zones où l'adresse est prise.

Et tu fais quoi si la valeur aléatoire que tu scannes est par hasard dans un tableau de données? Plantage! #roll#

Ben oui, mais dans la mesure où c'est randomisé ce n'est pas une vulnérabilité qui peut être exploitée : c'est qqch qui ne peut arriver qu'avec une probabilité bornée (si le marqueur est sur 64 bits, la probabilité que le bug arrive est très faible même si tu laisses tourner ta caltos 24h/24 pendant plusieurs millénaires %) y a sûrement plus de chances qu'un rayon cosmique altère un bit de ta ram bien avant...)

La probabilité est différente de 0, en tant que mathématicien, ça me suffit pour dire que c'est une solution foireuse.
Et sinon, je peux te raconter l'histoire de enter_ghost_space qui avait une probabilité très faible de foirer (si c'était copié au mauvais endroit de la RAM). Manque de chance, après installation d'une version particulière de PreOs, le lanceur ttstart courant à cette époque était copié exactement à cet endroit => boum! enter_ghost_space a été corrigé depuis, et PreOs a changé de taille aussi, donc ça a été oublié, mais c'était un superbe exemple de ce qui se passe si on fait confiance à ce que la probabilité qu'un truc foire soit faible.

- ne pas considérer le constructeur comme une fonction opaque, mais appeler à la fin du constructeur une fonction opaque qui aurait pour paramètre la structure (ou utiliser un asm() vide pour ne générer aucun code) -- idéal niveau performance :)

Mais une fois de plus un hack qui peut foirer (ce n'est pas parce que l'adresse est prise à cet endroit que la structure va vivre sur la pile partout et pas juste à cet endroit). Et vu comment évolue GCC, je dirais même qu'il va foirer tôt ou tard (peut-être déjà avec GCC 4.1, peut-être avec GCC 5.0 ou 6.0, je n'en sais rien).

Quésoft :
Également l'overhead d'un TRY ... FINALLY représente quoi à peu près ?

Ça dépend, j'ai bien peur qu'il faudra utiliser du volatile à plusieurs endroits, et ça, ça peut coûter. :(

C'est pourquoi le but de ce préprocesseur est de produire du ANSI-C: il va pouvoir servir sur les environnements qui n'ont pas de GCC ou d'autres compilateurs C++.

Pas de GCC? Tu penses à quoi comme environnements?! Les environnements qui ont un compilateur C potable ont aussi un GCC. Si tu penses à des trucs comme les Z80, déjà les programmes C sont gros, alors si en plus tu mets de l'OO par dessus...

Pollux :
Je ne pense pas qu'un frontend spécifique à un compilo soit une très bonne idée : tu perds la portabilité, et ça risque d'être bien plus compliqué à écrire (et surtout à maintenir).

En revanche, un frontend peut faire plus de trucs et plus proprement.

Si tu as besoin d'un truc comme le support des exceptions, je pense que la meilleure idée serait plutôt de patcher juste ce qu'il faut dans le compilateur C pour qu'il te fournisse les informations dont tu as besoin (où sont les objets sur la pile, etc)

Sauf que je ne risque pas de merger un patch de ce type dans TIGCC.

Tu veux utiliser atexit dans chaque fonction ? Pourquoi ? #confus#

Parce qu'il veut permettre l'utilisation de exit. AMHA, exit est limite inutile dans TIGCC (et Sebastian disait carrément qu'il a mal à l'estomac dès que le mot "exit" tombe vu que ça ne fait aucun nettoyage). Je ne vois pas pourquoi ça devrait être différent si on rajoute de l'OO.

peut-être qu'on pourra le copier quand même sur la pile si LeafNode a un constructeur de copie, mais il y a peut-être de très bonnes raisons pour qu'il n'en ait pas et alors on est foutu.

En C++, la règle est simple, tous les objets qui font un malloc doivent avoir un constructeur de copie. (Ce constructeur de copie peut être privé, ce qui fait que les copies sont interdites.)

Mais il y a encore un problème : si maintenant j'ai une fonction CreateNode() qui peut créer soit un LeafNode soit un InnerNode (et qui renvoie donc un Node), qu'est-ce qu'il va se passer si je fais
auto Node node = CreateNode(plop);

En C++, si je me rappelle bien, le constructeur de copie (explicit ou par défaut) de Node est utilisé et le résultat est un Node, plus un LeafNode.

Et sinon, plus que les objets locaux, ce sont les exceptions qui posent problème. Avec les objets dynamiquement alloués, il y a l'astuce de demander un delete explicit qui contourne ce problème. Je me demande si ce ne serait pas le plus simple de virer les exceptions tout simplement. À la limite, on pourrait permettre les exceptions AMS à condition que les objets locaux soient volatile et qu'un destroy explicit (comme delete, mais sur un local) soit dans le FINALLY, et la destruction automatique ne serait assurée que si on n'utilise pas d'exceptions du tout.
Membre de l'équipe de TIGCC: http://tigcc.ticalc.org
Mainteneur du portage Linux/Unix de TIGCC: http://tigcc.ticalc.org/linux/
Membre de l'équipe de CalcForge: http://www.calcforge.org:70/

Participez à la reprise de Ti-Gen!
    
./Post n°80   Marquer comme non lu.
Kevin Kofler Ecrit le: Samedi 21 octobre 2006 à 22:47 Déconnecté(e)    Voir le profil de Kevin Kofler Envoyer un email à Kevin Kofler Visiter le site WEB de Kevin Kofler Envoyer un message privé à Kevin Kofler  


PS: C'est tout à fait possible de faire de l'OO sans exceptions, Qt n'utilise pas du tout les exceptions, et est même généralement compilé avec -fno-exceptions (pour la performance).
Membre de l'équipe de TIGCC: http://tigcc.ticalc.org
Mainteneur du portage Linux/Unix de TIGCC: http://tigcc.ticalc.org/linux/
Membre de l'équipe de CalcForge: http://www.calcforge.org:70/

Participez à la reprise de Ti-Gen!
    
./Post n°81   Marquer comme non lu.
Quésoft Ecrit le: Samedi 21 octobre 2006 à 23:53 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Kevin Kofler :
La probabilité est différente de 0, en tant que mathématicien, ça me suffit pour dire que c'est une solution foireuse.
Et sinon, je peux te raconter l'histoire de enter_ghost_space qui avait une probabilité très faible de foirer (si c'était copié au mauvais endroit de la RAM). Manque de chance, après installation d'une version particulière de PreOs, le lanceur ttstart courant à cette époque était copié exactement à cet endroit => boum! enter_ghost_space a été corrigé depuis, et PreOs a changé de taille aussi, donc ça a été oublié, mais c'était un superbe exemple de ce qui se passe si on fait confiance à ce que la probabilité qu'un truc foire soit faible.


On parle de moins d'une chance sur 4G (par instance de 4 octets de donnée, par exemple) pour 32bit et 16T pour 14bit... Il n'y en a qui parle de 'intelligent design' pour moins que ça :P

Personnelement, j'admet que ce n'est pas 'clean', même si ce n'est pas vraiment risqué.

- ne pas considérer le constructeur comme une fonction opaque, mais appeler à la fin du constructeur une fonction opaque qui aurait pour paramètre la structure (ou utiliser un asm() vide pour ne générer aucun code) -- idéal niveau performance :)

Mais une fois de plus un hack qui peut foirer (ce n'est pas parce que l'adresse est prise à cet endroit que la structure va vivre sur la pile partout et pas juste à cet endroit). Et vu comment évolue GCC, je dirais même qu'il va foirer tôt ou tard (peut-être déjà avec GCC 4.1, peut-être avec GCC 5.0 ou 6.0, je n'en sais rien).

Kevin Kofler :
Également l'overhead d'un TRY ... FINALLY représente quoi à peu près ?

Ça dépend, j'ai bien peur qu'il faudra utiliser du volatile à plusieurs endroits, et ça, ça peut coûter. :(


J'ai compilé un petit test pour avoir une idée et je pense que ce ne sera pas long que l'on va rentrer dans notre argent en adoptant une autre méthode: plusieurs dizaines d'octets par bloc TRY ... FINALLY.

Kevin Kofler :
Pas de GCC? Tu penses à quoi comme environnements?! Les environnements qui ont un compilateur C potable ont aussi un GCC. Si tu penses à des trucs comme les Z80, déjà les programmes C sont gros, alors si en plus tu mets de l'OO par dessus...


En tk, ça va marcher aussi avec GCC. L'avantage est que l'on a pas de besoin d'adapter le code pour chaque version de GCC.

Pour le Z80, je crois que leur C est du KnR avec certaines features manquantes (reste que l'ANSI C peut compiler du KnR, alors s'il ne manque pas de features critiques, je pourrai produire du code KnR).

Kevin Kofler :
Sauf que je ne risque pas de merger un patch de ce type dans TIGCC.


C'est pourquoi je préfère un truc clean et simple (mais pas codé bourrin).

Kevin Kofler :
Parce qu'il veut permettre l'utilisation de exit. AMHA, exit est limite inutile dans TIGCC (et Sebastian disait carrément qu'il a mal à l'estomac dès que le mot "exit" tombe vu que ça ne fait aucun nettoyage). Je ne vois pas pourquoi ça devrait être différent si on rajoute de l'OO.

Je suis le premier à être d'accord, mais je crois qu'il est raisonable de s'attendre à ce que exit soit utilisé par les programmeurs (on ne parle plus d'une chance pour 4 milliard).

Kevin Kofler :

Et sinon, plus que les objets locaux, ce sont les exceptions qui posent problème. Avec les objets dynamiquement alloués, il y a l'astuce de demander un delete explicit qui contourne ce problème. Je me demande si ce ne serait pas le plus simple de virer les exceptions tout simplement. À la limite, on pourrait permettre les exceptions AMS à condition que les objets locaux soient volatile et qu'un destroy explicit (comme delete, mais sur un local) soit dans le FINALLY, et la destruction automatique ne serait assurée que si on n'utilise pas d'exceptions du tout.


Pour ce préprocesseur, je n'evisage pas fournir un support out of the box pour les exceptions (le programmeur utilisera les exception C et sera vigilant pour la finalisation). Moka bidouillait avec les exceptions TIGCC pour pouvoir fournir un système semblable à Java (ça marchait acceptablement).

Kevin Kofler :
PS: C'est tout à fait possible de faire de l'OO sans exceptions, Qt n'utilise pas du tout les exceptions, et est même généralement compilé avec -fno-exceptions (pour la performance).


Effectivement, mais les exceptions permettent dans certains contextes de faire du code plus élégant.
    
./Post n°82   Marquer comme non lu.
Quésoft Ecrit le: Dimanche 22 octobre 2006 à 00:45 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Voici un autre avant gout des messages d'erreurs de compilation (qui donne une idée d'où je suis rendu dans le parsing):


Error (file 'test.m', line 7): unexpected 'final' keyword after 'public' keyword. 'final' was already specified in this class declaration.
public final abstract final class int
                          ^
Preprocessing failed: 1 errors, 0 warnings.
    
./Post n°83   Marquer comme non lu.
Pollux Ecrit le: Dimanche 22 octobre 2006 à 01:08 Déconnecté(e)    Voir le profil de Pollux Envoyer un email à Pollux Envoyer un message privé à Pollux  

Kevin>
pitié, pas un troll de 3 km :(

Pour faire simple : je ne suis convaincu par aucun de tes arguments (par exemple le compilo ne peut pas changer l'adresse de la structure entre l'appel du constructeur et l'appel d'ER_throw, parce que ce sont tous les deux boîtes noires communiquant potentiellement entre elles), par contre il y a un truc auquel je n'avais pas pensé et qui casse *vraiment* tout : c'est que le compilo peut théoriquement dupliquer la structure (ou pire, copier un bout de la structure sans copier le reste), du coup ben on ne peut absolument pas faire confiance au contenu de la pile même s'il a le bon marqueur :( Vivement un compilo qui supporterait les types linéaires =)

Donc il vaut mieux se rabattre sur la solution propre : faire une liste chaînée de "paquets de n objets", un paquet correspondant à une fonction -- le coût serait de 4+2n octets à écrire sur la pile plus la lecture/écriture du pointeur de liste chaînée. C'est pas non plus démesuré ^^
    
./Post n°84   Marquer comme non lu.
Quésoft Ecrit le: Dimanche 22 octobre 2006 à 14:29 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Pollux :

Donc il vaut mieux se rabattre sur la solution propre : faire une liste chaînée de "paquets de n objets", un paquet correspondant à une fonction -- le coût serait de 4+2n octets à écrire sur la pile plus la lecture/écriture du pointeur de liste chaînée. C'est pas non plus démesuré ^^


Que voulez-vous dire par 'un paquet correspondant à une fonction' ... que chaque classe d'objet aurait son node dans la liste du finaliseur ?

On peut penser faire une liste double (pointeur vers l'objet, pointeur vers la fonction de finalization), pour la vitesse et pour éviter un nombre trop grand d'allocation (plus gros footprint au fur et à mesure que N augmente, par contre). Qu'est-ce que ça vous dit ?

On peut pointer sur 'free(void *)' en TIGCC (i.e. c'est une 'vraie' fonction) ?
-Edité le Dimanche 22 octobre 2006 à 17:53 par Quésoft-
    
./Post n°85   Marquer comme non lu.
Onur Ecrit le: Dimanche 22 octobre 2006 à 16:46 Déconnecté(e)    Voir le profil de Onur Envoyer un email à Onur Visiter le site WEB de Onur Envoyer un message privé à Onur  


geogeo :
Onur :
(Parce qu'il y en avait marre des mecs qui viennent poster pour faire un compilo et qui foutent rien, bref)


?


Je parlais de GC et d'autres qui sont venus poster dans le forum.
-Edité le Dimanche 22 octobre 2006 à 16:50 par Onur-
Je ne veux pas faire quelque chose de bien, je cherche l'excellence:ETP Studio...


et autres projets à finir avant 2010
    
./Post n°86   Marquer comme non lu.
geogeo Ecrit le: Dimanche 22 octobre 2006 à 17:05 Déconnecté(e)    Voir le profil de geogeo Envoyer un email à geogeo Visiter le site WEB de geogeo Envoyer un message privé à geogeo  


ah ok parce que pour GFA Basic v2 y a plus de 6000 lignes réécrites à l'heure actuelle...

Concernant la programmation objet j'ai un peu cherché sur le net et j'ai trouvé ça:
http://nosicalanguage.free.fr/?fr
C'est une surcouche du C on écrit en objet dans un langage défini qui est transformé en C.
Webmaster du site.
Programmeur sur TI68K. Arkanoid, Nebulus, GFA-Basic.

Plus d'informations sur GFA-Basic (un langage Basic pour TI68K).
http://www.tigen.org/gfabasic
    
./Post n°87   Marquer comme non lu.
Quésoft Ecrit le: Dimanche 22 octobre 2006 à 17:52 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Merci pour le lien.

J'ai regardé ça un peu et ça ressemble beaucoup à ce que l'on veut faire. Par contre, je ne pense pas que l'on peut s'en servir de façon minimaliste (juste le support classes, par exemple).

Nosica semble être un Moka de plus grande qualité (mieux featuré, mais plus gros).
-Edité le Dimanche 22 octobre 2006 à 17:58 par Quésoft-
    
./Post n°88   Marquer comme non lu.
Pollux Ecrit le: Lundi 23 octobre 2006 à 18:29 Déconnecté(e)    Voir le profil de Pollux Envoyer un email à Pollux Envoyer un message privé à Pollux  

Quésoft :
Pollux :

Donc il vaut mieux se rabattre sur la solution propre : faire une liste chaînée de "paquets de n objets", un paquet correspondant à une fonction -- le coût serait de 4+2n octets à écrire sur la pile plus la lecture/écriture du pointeur de liste chaînée. C'est pas non plus démesuré ^^


Que voulez-vous dire par 'un paquet correspondant à une fonction' ... que chaque classe d'objet aurait son node dans la liste du finaliseur ?

Que plutôt que d'avoir une entrée par objet dans la liste chaînée (ce qui serait coûteux du point de vue temps de mise à jour), on peut regrouper tous les objets d'une même fonction dans un gros bloc contigu... (regroupant tout un tas de classes différentes)


Euh sinon tu comptes implémenter les types génériques ?


On peut pointer sur 'free(void *)' en TIGCC (i.e. c'est une 'vraie' fonction) ?

Oui, enfin de toute façon vu la lenteur de l'appel du tios c'est pas grave si tu passes par un wrapper (et si ça trouve ça sera peut-être plus économique en place de passer par un wrapper :))
    
./Post n°89   Marquer comme non lu.
Quésoft Ecrit le: Lundi 23 octobre 2006 à 20:25 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Pollux :

Que voulez-vous dire par 'un paquet correspondant à une fonction' ... que chaque classe d'objet aurait son node dans la liste du finaliseur ?

Que plutôt que d'avoir une entrée par objet dans la liste chaînée (ce qui serait coûteux du point de vue temps de mise à jour), on peut regrouper tous les objets d'une même fonction dans un gros bloc contigu... (regroupant tout un tas de classes différentes)


Et la solution d'utiliser une double liste ? Cette liste fonctionne comme une pile, alors le temps de traitement lorsque l'on quitte un scope et que l'on doit libérer les objets locaux est assez faible ... Dans ce contexte, une ArrayList dynamique sera plus rapide qu'une liste chaînée, non ?

Pollux :
Euh sinon tu comptes implémenter les types génériques ?


Peut être dans un deuxième temps. Anyway, si on a une classe qui manipule des objets implémentant une certaine interface, on obtient quelque chose de comparable, non ?
    
./Post n°90   Marquer comme non lu.
Pollux Ecrit le: Lundi 23 octobre 2006 à 23:19 Déconnecté(e)    Voir le profil de Pollux Envoyer un email à Pollux Envoyer un message privé à Pollux  

Quésoft :
Et la solution d'utiliser une double liste ? Cette liste fonctionne comme une pile, alors le temps de traitement lorsque l'on quitte un scope et que l'on doit libérer les objets locaux est assez faible ... Dans ce contexte, une ArrayList dynamique sera plus rapide qu'une liste chaînée, non ?

C'est-à-dire, tu parles d'un tableau "plat" global avec tous les objets à libérer, ou d'autre chose ?

Pollux :
Euh sinon tu comptes implémenter les types génériques ?


Peut être dans un deuxième temps. Anyway, si on a une classe qui manipule des objets implémentant une certaine interface, on obtient quelque chose de comparable, non ?

Pas tout à fait, parce qu'on peut avoir envie que les fonctions de la classe renvoient le type exact d'objet manipulé et pas juste l'interface générique dont la classe a besoin (ex : un vector<int> renvoie un int quand on fait v[i], pas juste un Object), et on peut aussi avoir envie de ne pas encapsuler le int dans un objet, pour pouvoir le stocker en mémoire directement en tant qu'entier... Enfin si tu te contentes du premier point ça sera facile à implémenter en tant que surcouche :) (c'est juste une question de typage, ça ne change rien au code généré)
    
./Post n°91   Marquer comme non lu.
Kevin Kofler Ecrit le: Mardi 24 octobre 2006 à 02:51 Déconnecté(e)    Voir le profil de Kevin Kofler Envoyer un email à Kevin Kofler Visiter le site WEB de Kevin Kofler Envoyer un message privé à Kevin Kofler  


Quésoft :
J'ai compilé un petit test pour avoir une idée et je pense que ce ne sera pas long que l'on va rentrer dans notre argent en adoptant une autre méthode: plusieurs dizaines d'octets par bloc TRY ... FINALLY.

Hmmm, ça c'est un bon argument. Il y a aussi un autre problème, c'est que ça consomme beaucoup de place sur la pile, donc les niveaux d'appels de fonction sont assez limités s'il y a des TRY...FINALLY...ENDFINAL partout.

Pour le Z80, je crois que leur C est du KnR avec certaines features manquantes (reste que l'ANSI C peut compiler du KnR, alors s'il ne manque pas de features critiques, je pourrai produire du code KnR).

Le problème n'est pas ça, c'est surtout que le code sorti par tous les compilateurs courants est très sous-optimal par rapport à quelque chose écrite directement en assembleur, et que ça devient pire si tu rajoutes de l'objet par dessus. Maintenant, essaie de faire rentrer ça dans les 8 KO qui sont le maximum que la TI-83+ permet d'exécuter (le reste est protégé contre l'exécution) et tu dois avoir beaucoup de chance pour qu'un Hello World passe.

Je suis le premier à être d'accord, mais je crois qu'il est raisonable de s'attendre à ce que exit soit utilisé par les programmeurs (on ne parle plus d'une chance pour 4 milliard).

Ce n'est pas raisonnable, la documentation dit noir sur blanc que exit ne fait aucun nettoyage, je ne vois pas pourquoi ça devrait être différent pour les objets locaux.

A priori, si tu penses vraiment que des gens utilisent exit dans une librairie, je peux interdire ça (à plusieurs niveaux: je peux retirer la définition si _GENERIC_ARCHIVE est défini et je peux aussi détecter ça dans ar-tigcc (ou ld-tigcc pour les DLLs) et donner un message d'erreur là).

Pollux :
par exemple le compilo ne peut pas changer l'adresse de la structure entre l'appel du constructeur et l'appel d'ER_throw, parce que ce sont tous les deux boîtes noires communiquant potentiellement entre elles

ER_throw n'est pas une boîte noire, c'est un builtin.

Et sinon, je ne suis pas sûr que ça:
struct foo {int toto};
struct foo *global;
void f(struct foo *bar)
{
  global=bar;
}
void g(void)
{
  global->toto=123;
}
void h(void)
{
  struct foo baz;
  f(&baz);
  g();
}

soit valide (en tout cas je vois ça comme un hack grossier et, si le standard C permet ce code, je verrais bien un flag de même type que -ffast-math ou -fmerge-all-constants qui interdit ça dans le but de mieux optimiser).

Donc il vaut mieux se rabattre sur la solution propre : faire une liste chaînée de "paquets de n objets", un paquet correspondant à une fonction -- le coût serait de 4+2n octets à écrire sur la pile plus la lecture/écriture du pointeur de liste chaînée. C'est pas non plus démesuré ^^

La solution propre, ça s'appelle l'unwinding DWARF2. Mais il faut faire un frontend (ou un compilateur à part entière, mais alors adieu les optimisations de GCC!) pour ça, pas un préprocesseur.

geogeo: GFA Basic n'est pas vraiment un compilateur. C'est un tokéniseur et un interpréteur. Mais c'est vrai qu'un tokéniseur fonctionne à peu près comme un compilateur et que l'abus de langage d'appeler ça des "compilateurs" est courant à cause de Java. (Il y a de vrais compilateurs Java, GCJ par exemple. Mais javac n'est pas un compilateur.)
Membre de l'équipe de TIGCC: http://tigcc.ticalc.org
Mainteneur du portage Linux/Unix de TIGCC: http://tigcc.ticalc.org/linux/
Membre de l'équipe de CalcForge: http://www.calcforge.org:70/

Participez à la reprise de Ti-Gen!
    
./Post n°92   Marquer comme non lu.
Quésoft Ecrit le: Mardi 24 octobre 2006 à 16:56 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Pollux :
Quésoft :
Et la solution d'utiliser une double liste ? Cette liste fonctionne comme une pile, alors le temps de traitement lorsque l'on quitte un scope et que l'on doit libérer les objets locaux est assez faible ... Dans ce contexte, une ArrayList dynamique sera plus rapide qu'une liste chaînée, non ?

C'est-à-dire, tu parles d'un tableau "plat" global avec tous les objets à libérer, ou d'autre chose ?


Oui.

1er appel de fct.
stack des objets locaux et finaliseurs de la fonction dans le tableau
2e appel de fct.
stack des objets locaux et finaliseurs de la fonction dans le tableau
fin 2e fct
liberation des objets locaux de la fonction
fin 1e fct
liberation des objets locaux de la fonction

C'est le scénario classique. Un tableau sera très rapide dans ce cas là. Le problème c'est les exceptions (comme le soulignait Kevin) et les exits (ce dernier est moins problématique: on s'en sort avec une fct atexit).

Pollux :
Peut être dans un deuxième temps. Anyway, si on a une classe qui manipule des objets implémentant une certaine interface, on obtient quelque chose de comparable, non ?

Pas tout à fait, parce qu'on peut avoir envie que les fonctions de la classe renvoient le type exact d'objet manipulé et pas juste l'interface générique dont la classe a besoin (ex : un vector<int> renvoie un int quand on fait v[i], pas juste un Object), et on peut aussi avoir envie de ne pas encapsuler le int dans un objet, pour pouvoir le stocker en mémoire directement en tant qu'entier... Enfin si tu te contentes du premier point ça sera facile à implémenter en tant que surcouche :) (c'est juste une question de typage, ça ne change rien au code généré)


C'est vrai que c'est utile, je n'avais pas pensé à ça. Par contre, comme c'est du 'sucre', ce sera surement dans un 2e temps.
    
./Post n°93   Marquer comme non lu.
Quésoft Ecrit le: Mardi 24 octobre 2006 à 17:20 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Kevin Kofler :
Quésoft :
J'ai compilé un petit test pour avoir une idée et je pense que ce ne sera pas long que l'on va rentrer dans notre argent en adoptant une autre méthode: plusieurs dizaines d'octets par bloc TRY ... FINALLY.

Hmmm, ça c'est un bon argument. Il y a aussi un autre problème, c'est que ça consomme beaucoup de place sur la pile, donc les niveaux d'appels de fonction sont assez limités s'il y a des TRY...FINALLY...ENDFINAL partout.


Effectivement.

Kevin Kofler :
Le problème n'est pas ça, c'est surtout que le code sorti par tous les compilateurs courants est très sous-optimal par rapport à quelque chose écrite directement en assembleur, et que ça devient pire si tu rajoutes de l'objet par dessus. Maintenant, essaie de faire rentrer ça dans les 8 KO qui sont le maximum que la TI-83+ permet d'exécuter (le reste est protégé contre l'exécution) et tu dois avoir beaucoup de chance pour qu'un Hello World passe.


Je pense qu'un hello world présent dans une méthode appelée dynamiquement rentrera dans 8K ... En tk, c'est plus par principe de produire le code C le plus optimizé possible, qu'il roulle sur ti-89 ou sur intel.

Kevin Kofler :
A priori, si tu penses vraiment que des gens utilisent exit dans une librairie, je peux interdire ça (à plusieurs niveaux: je peux retirer la définition si _GENERIC_ARCHIVE est défini et je peux aussi détecter ça dans ar-tigcc (ou ld-tigcc pour les DLLs) et donner un message d'erreur là).


Si on peut se permettre d'assumer que exit ne sera pas utilisé, tant mieux. En passant, vous aviez raison lorsque vous disiez que c'était les exceptions qui donneraient de la difficulté... On peut penser spotter les throws et ajouter du code avant que l'exception soit lancée, mais ça ne résolve pas les cas où l'exception vient d'une fonction de la librairie qui call tios.

Kevin Kofler :
Mais il faut faire un frontend (ou un compilateur à part entière, mais alors adieu les optimisations de GCC!) pour ça, pas un préprocesseur.


Je crois que l'on ne peut pas se permettre de dire adieu à ces optimisations...

Kevin Kofler :
geogeo: GFA Basic n'est pas vraiment un compilateur. C'est un tokéniseur et un interpréteur. Mais c'est vrai qu'un tokéniseur fonctionne à peu près comme un compilateur et que l'abus de langage d'appeler ça des "compilateurs" est courant à cause de Java. (Il y a de vrais compilateurs Java, GCJ par exemple. Mais javac n'est pas un compilateur.)


En effet, on commence par tokeniser, puis on produit du code en parsant les tokens.

Mais ... Le bytecode n'est pas plutôt du code machine pour une machine virtuelle ? Ça doit ressembler à du code machine, non ? Il me semble que la tokenisation d'un interpréteur est différente: les structures de controles de haut niveau y sont, etc.
    
./Post n°94   Marquer comme non lu.
Kevin Kofler Ecrit le: Mardi 24 octobre 2006 à 18:51 Déconnecté(e)    Voir le profil de Kevin Kofler Envoyer un email à Kevin Kofler Visiter le site WEB de Kevin Kofler Envoyer un message privé à Kevin Kofler  


Quésoft :
Je crois que l'on ne peut pas se permettre de dire adieu à ces optimisations...

Moi non plus. (Je pense que ETP devrait aussi être un frontend GCC.)

Mais ... Le bytecode n'est pas plutôt du code machine pour une machine virtuelle ?

La "machine virtuelle" n'est autre qu'un interpréteur ou un JIT, je ne vois pas en quoi ça se distingue de l'habituel language interprété. Oui, c'est plus bas-niveau, mais ça reste interprété ou JITté.
Membre de l'équipe de TIGCC: http://tigcc.ticalc.org
Mainteneur du portage Linux/Unix de TIGCC: http://tigcc.ticalc.org/linux/
Membre de l'équipe de CalcForge: http://www.calcforge.org:70/

Participez à la reprise de Ti-Gen!
    
./Post n°95   Marquer comme non lu.
Quésoft Ecrit le: Mardi 24 octobre 2006 à 20:12 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Je pense que dans le cas des exceptions, il faut se garder une liste de pointeurs.

Imaginons l'implémentation suivante pour les objets locaux:


struct ObjList {
void **l; //listes des objets
void (**fcts) (void *obj); // liste des fonctions de finalisation
size_t maxSize; //Taille maximale de la liste dynamique
void **l_top; //Pointe sur le dernier objet.
void **f_top; //Pointe sur la dernière fonction.
};

struct ErrStk {
void ***tries; // Pointeurs vers la liste des objets
size_t maxSize; //Taille maximale de la liste dynamique
void ***top; //Pointe sur le dessus de la pile tries
};

struct ObjList objList;
struct ErrStk errStk;

/* ... */

//initialisation

objList.l = malloc(TAILLE_INITIALE * sizeof(void *));
objList.l_top = objList.l;
objList.fcts = malloc(TAILLE_INITIALE * sizeof(void (*) (void*)));
objList.f_top = objList.fcts;
objList.maxSize = TAILLE_INITIALE;
errStk.tries = malloc(TAILLE_INITIALE * sizeof(void **));
errStk.maxSize = TAILLE_INITIALE;
errStk.top = errStk.tries;

/* ... */

void add_localObject(void *obj, void (*fct) (void *obj)) {
  /*routine de l'allocation dynamique*/
  *(objList.l_top++) = obj;
  *(objList.f_top++) = fct;
}

void remove_localObject() {
  (*(--objList.f_top))(--objList.l_top);//utiliser la fonction pour finaliser le dernier objet dans la liste
}

void stack_try() {
  /*routine de l'allocation dynamique*/

  *(errStk.top++) = objList.l_top;
}

void unstack_try() {
  void **p = *(--errStk.l);

  while (objList.l_top != p) {
    remove_localObject();
  }
}


Le code suivant:


void prem() {
 Object a;
  TRY
    /* code */
    deus();
    /* code */
  ONERR
   /*code*/
  ENDTRY
}

void deus() {

  TRY
    /* code */
    tres();
    /* code */
  FINALLY
   /*code*/
  ENDTRY

tres();
}

void tres() {
 Object o1, o2;

  Er_throw(1);
}


Pourait être converti en:


void prem() {
  Object a;
  add_local_object(&a, desctructeur_de_a);

  TRY
    stack_try();
    /* code */
    deus();
    /* code */
  ONERR
  unstack_try();
   /*code*/
  ENDTRY

  remove_localObject();
}

void deus() {

  TRY
    stack_try();
    /* code */
    tres();
    /* code */
   FINALLY
   /*code*/
  unstack_try();
  ENDTRY

  tres();
}

void tres() {
 Object o1, o2;
  add_local_object(&o1, desctructeur_de_o1);
  add_local_object(&o1, desctructeur_de_o1);

  Er_throw(1);


  remove_localObject();
  remove_localObject();
}


Soyez indulgent pour les erreurs, ça fait un bout que je n'ai pas joué avec les pointeurs vers des fonctions. Le but était de donner l'algorithme que je considère le plus clean.
-Edité le Mardi 24 octobre 2006 à 23:34 par Quésoft-
-Edité le Mardi 24 octobre 2006 à 23:35 par Quésoft-
    
  :: Index » Forum Ti68K » Programmation C » Orienté objet avec TIGCC (113 réponse(s))
Pages : 5/6     « 1 2 3 4 [5] 6 » »|

.Répondre à ce sujet
Les boutons de code
[B]old[I]talic[U]nderline[S]trikethrough[L]ine Flip Hori[Z]ontallyFlip [V]erticallySha[D]ow[G]low[S]poilerCode [G][C]ite
Bullet [L]istList Item [K] Link [H][E]mail[P]icture SmileysHelp
Couleurs :
Saisissez votre message
Activer les smileys
     

Forum de Ti-Gen v3.0 Copyright ©2004 by Geoffrey ANNEHEIM
Webmaster: Kevin KOFLER, Content Admins: list, Server Admins: Tyler CASSIDY and Kevin KOFLER, DNS Admin: squalyl
Page générée en 54.47ms avec 18 requetes