Permalänk
Medlem

dynamic dispatch i java

Jag tänkte höra om någon kan kolla om jag har förstått hur dynamic dispatch fungerar i java.

Kompilatorn skapar en virtual table för varje klass
Ett objekt skapas och läggs på heapen, medans en det finns en pekare till objektet på stacken.
När objektet skapas så skapas även en pekare till vilen virtual table som ska användas
Från virtual table hämtas informationen om hur funktionerna ska kopplas ihop och kopplingen görs.

Är detta korrekt? Har jag missat något?

Visa signatur

Du är min fiende tills motsatsen är bevisad, och bevisbördan ligger hos dig.

Permalänk
Medlem

Du har i stort sett rätt. Pekaren till objektet behöver dock inte ligga på stacken utan kan ju lika gärna ligga i ett fält till ett annat objekt (som ligger på heapen).

Vtabellen består huvudsakligen av en array av pekare till funktionskroppar (det kan tänkas att det finns ett par andra fält också som identifierar själva klassen). Själva dispatchkoden använder en förberäknad offset in i tabellen för att slå upp rätt implementation. Varje metod har en egen offset in i tabellen.

edit: Om man ska vara noga så behöver inte objektet ligga på heapen. Om kompilatorn kan se att objektet inte kan nå andra funktioner så kan den välja att stackallokera objektet istället. Den här optimeringen kallas Escape Analysis om du vill googla på det.

Visa signatur

Alla män är dödliga. Sokrates var dödlig. Alltså är alla män Sokrates.

Permalänk
Medlem

Värt att nämna är dock att Java inte (nödvändigtvis) har en vtable på samma sätt som i C++. Då Java har möjligheten att ha lite bättre koll på vilken typ ett objekt är i körtid så behöver den inte göra virtuella anrop via en indirektion som är nödvändigt i C++. Det gör att det inte är lika hög overhead på virtuella anrop. Sedan är det ju upp till en Java Virtual Machine (JVM) att avgöra hur den gör anropen och det är ju upp till den att välja hur den vill göra anropen.

Den mer officiella metoden för hur det fungerar i Java är att med varje objekt-allokering så skapas det i datautrymmet ett id till den klass som objektet är. Om jag inte minns fel så är overheaden på ett rent objekt i Java 3 bytes (med Suns 1.6+ JVM). Med hjälp av id:t till klassen så kan JVM:en lista ut vilken faktiskt metod det är som ska anropas.

//C

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av conio
Värt att nämna är dock att Java inte (nödvändigtvis) har en vtable på samma sätt som i C++. Då Java har möjligheten att ha lite bättre koll på vilken typ ett objekt är i körtid så behöver den inte göra virtuella anrop via en indirektion som är nödvändigt i C++. Det gör att det inte är lika hög overhead på virtuella anrop. Sedan är det ju upp till en Java Virtual Machine (JVM) att avgöra hur den gör anropen och det är ju upp till den att välja hur den vill göra anropen.

Den mer officiella metoden för hur det fungerar i Java är att med varje objekt-allokering så skapas det i datautrymmet ett id till den klass som objektet är. Om jag inte minns fel så är overheaden på ett rent objekt i Java 3 bytes (med Suns 1.6+ JVM). Med hjälp av id:t till klassen så kan JVM:en lista ut vilken faktiskt metod det är som ska anropas.

//C

Tre bytes låter lite lustigt. Hur du en länk till en sida där man kan läsa mer om det här?

Visa signatur

Alla män är dödliga. Sokrates var dödlig. Alltså är alla män Sokrates.

Permalänk
Medlem

Kan man tänka sig att det fungerar något i stil med

foo.bar() -> foo.vtable[”bar”].invoke() ?

Visa signatur

Du är min fiende tills motsatsen är bevisad, och bevisbördan ligger hos dig.

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av pSyChO
Kan man tänka sig att det fungerar något i stil med

foo.bar() -> foo.vtable[”bar”].invoke() ?

Ja, det är ett rimligt sätt att beskriva det på. På assemblernivån blir det typ:

mov eax, dword ptr [foo] ; lägg pekaren till vtabellen i register eax förutsatt att vtabellen ligger på offset 0
call dword ptr [eax + offset_of_bar] ; gör ett indirekt anrop genom eax

Visa signatur

Alla män är dödliga. Sokrates var dödlig. Alltså är alla män Sokrates.