[Compiler building] method invocation

Pagina: 1
Acties:

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Topicstarter
Hoi ;)

Heb zelf een compiler geschreven die een java-achtig taaltje omzet in ANSI-C. Nu zit ik bij het genereren van C code voor het aanroepen van methods met een probleempje.

Deze code: obj.f(1,2,3); Waar obj van class-type 'A' is vertaalt naar iets als dit in ansi-c (zonder type casts etc om het duidelijk te houden)

((tmp = (obj))->vtable->f_A)(tmp, 1, 2, 3);

Uit het object wordt dus via zijn virtual/dispatch table het functie adres gehaald, en die wordt dan aangeroepen met het object als argument ('this' pointer)

Het gaat eigenlijk om die 'tmp'. Die is nodig omdat 'obj' ook een expressie kan zijn, bv een functie-call resultaat. Ik kan die expressie dus niet 2x evalueren, want dan zou ik een functie twee keer aan kunnen roepen.
(bv.: ((tmp = (foo()))->vtable->f_A(tmp, 1, 2, 3);)

Nou werkt het met die tmp op zich goed, maar ansi-C heet geen regels voor de orde van evaluatie van functie argumenten (woei). Dit is niet juist in ansi-c:

foo(buffer[2], buffer = null); (want als rechts naar links dan null[2], crash)

Dit gaat bij mij fout als ik deze code compile:

obj1.f(obj2.g(), 2, 3);

Vertaald naar:

((tmp = (obj1))->vtable->f_A)(tmp, ((tmp = (obj2))->vtable->g_B)(tmp), 2, 3);

Heeft iemand een idee om dit makkelijk en snel op te lossen? Dus niet met een lijst structuur van temporaries oid, ik kan ook niet in assembler het op de stack pushen (wat ideaal zou zijn). En ik wil dus ook geen stack data structuur gebruiken ervoor.

Als het niet duidelijk is (kan gebeuren ;) ) reply ik wel met meer info... Thnx :)

[ Voor 4% gewijzigd door Zoijar op 27-11-2002 21:09 ]


  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
waarom doe je het niet gewoon in twee statements: eerst tmp = (expr), en dan tmp->vtable->bla(tmp, ...) ?

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Topicstarter
Dan zou het dit worden:

((tmp1 = (obj1))->vtable->f_A)(tmp1, ((tmp2 = (obj2))->vtable->g_B)(tmp2), 2, 3);

en dan heb ik een onbekend aantal verschillende 'tmp' vars nodig heb, en dus een dynamische lijst oid moet gebruiken. Vroeg me af of ik daar niet onderuit kon...
Met stack zoiets: (als je stack de pointer die je pushed en popped ook weer returned)

(stack_push(obj)->vtable->f_A)(stack_pop(), ((stack_push(obj2))->vtable->g_B)(stack_pop()), 2, 3);

Maar dat lijkt me een stuk trager...misschien moet ik het toch maar zo doen dan. Vroeg me af o iemand een beter idee had.

  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Dan zou het dit worden:

((tmp1 = (obj1))->vtable->f_A)(tmp1, ((tmp2 = (obj2))->vtable->g_B)(tmp2), 2, 3);
Ik bedoel zoiets:

C:
1
2
3
tmp1 = (obj1);
tmp2 = (obj2);
(tmp1->vtable->f_A)(tmp1, (tmp2->vtable->g_B)(tmp2), 2, 3);

Maar zoals jij zegt kan ook idd (is ei'k hetzelfde, maar met minder code :)). Dan krijg wel een willekeurig aantal tmp variabelen, maar je hoeft ze niet in een dynamische lijst op te slaan omdat de compiler weet hoeveel het er zijn.

[ Voor 19% gewijzigd door marcusk op 27-11-2002 22:16 ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Topicstarter
Ik moet ze wel ergens declareren als void* s. in ansi-c kan je alleen declareren aan het begin van een scope-block. En ik genereer recursief code, dus ik kan wat jij zegt niet doen. Ik kan namelijk alleen "generate_expression" aanroepen op functie argumenten. Zelfs als ik alle argumenten als tmp's opsla in tmp1-2-3-etc, dan kan ik geen nieuw scope block beginnen in een expressie... bah :P lastig... het hele gebeuren moet een expressie zijn, eventueel kan je meerdere dingen doen door een komma expressie te gebruiken. Heb ik ook al mee gespeeld. dus zoiets als: (tmp1 = obj, tmp1->vtable->f_A)(tmp1, 1, 2, 3);

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Ik neem aan dat je ergens wel wat bronnen kan raadplegen. Kijk dan eens in dit boek:

Modern Compiler Implemenation in Java/C/ML en dan het hoofdstuk "Basic Blocks and Traces". Hier wordt in de sectie "Canonical Trees" uitgelegd hoe je side-effects uit expressie bomen kunt tillen. De beschrijving is gebaseerd op een meer assembly achtige intermediate representation, maar je kan het veel algemener toepassen. Ik heb het toevallig een tijdje geleden geschreven voor een meer C achtige taal.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Zoijar: in ansi-c kan je alleen declareren aan het begin van een scope-block.
Je kan natuurlijk wel alle willekeurige eenvoudige statements vervangen door compound statement (scope-block). Je moet dus op statement niveau het probleem gaan oplossen en niet pas als je al een expressie moet gaan genereren. Voordat je de statement gaat genereren waarin de temporaries gebruikt moeten gaan worden, moet je dus eerst een compound statement genereren ipv de eenvoudige statement.

Samenvatting: niet het probleem oplossen als je met de problemen zit, maar het probleem voorkomen zolang je het kan oplossen ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Topicstarter
Ok thanks :) Ik heb wel "Modern compiler design" gelezen, en kan me nu herinneren dat er daar bij garbage collection iets over het verwijderen van side-effect werd geschreven. Zal het nog is lezen. Heb nu wel al iets met compound statements, kan dan gewoon steeds tmp1 tm x declareren omdat ik toch in een andere scope zit, wel handig.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Thunking:
code:
1
2
3
4
void f_A_thunk( void* this, int a, int b, int c )
{
  this->vtable->f_A( this, a, b, c );
}

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Topicstarter
Dat is wel een goed idee... Dan heb ik ook meteen geen echt verschil meer tussen statische en dynamische calls. Als er scope resolution is roep ik (f_A_"scope")("generate expr", args) aan en anders (f_A)("generate expr", args).

C compiler optimized die extra call er wel uit toch?
Pagina: 1