Self modifying code
 
2. De techniek

Self modifying code is een programmeertechniek waarbij, in een lopend programma, instructies van dat programma veranderd worden. Het doel van het gebruik van self modifying code is veelal een besparing te maken in het gebruik van ruimte en/of tijd.

Voor het beschrijven van (delen van) programma's zullen wij een taal gebruiken die veel weg heeft van assemblertalen, dit omdat self modifying code niet door reguliere talen ondersteund wordt. In onze taal zijn instructies atomair en kan het veranderen van instructies relatief duidelijker worden weergegeven. Om de leesbaarheid te bevorderen hebben we enkele instructies complexer gelaten dan gebruikelijk is in assemblertalen. De taal is bedoeld om voorbeelden te illustreren en niet om direct geïmplementeerd te worden. De volgorde van de operanden bij instructies zijn eerst bronoperanden, dan doeloperanden.

Met het veranderen van bestaande instructies kan het gedrag van een programma veranderd worden, zonder test en sprong instructies te gebruiken.

var a

proc b
   ...
   if(a=0) statement 1  
   else    statement 2  
   ...

proc c
   ...
   move 1,a
   ...
proc b
   ...
x: statement 1
   ...

proc c
   ...
   move 'statement 2',x
   ...
(a)(b)
figuur 2.1

In figuur 2.1 a staat een deel van een programma met een test instructie op een globale variabele. Op een gegeven moment wordt het gedrag van procedure b veranderd door procedure c, doordat deze de globale variabele a veranderd. Procedure c zou ook instructies van procedure b kunnen veranderen, zoals in 2.1 b.

Wat opvalt is de lengte van de code. Het gebruik van self modifying code kan de lengte van een programma, en daarmee de looptijd, soms verkorten. Vooral in programmadelen waar testinstructies binnen lussen voorkomen leent self modifying code zich als hulpmiddel om programma's sneller en kleiner te maken.

In figuur 2.2 a is een deel van een programma gegeven met een lus, met daarin testinstructies. Om dit programma sneller te maken zou de testinstructie buiten de lus gehaald kunnen worden (zoals in 2.2 b). Dit zorgt voor een onoverzichtelijk programma, vooral als er veel testinstructies in de lus staan. Er zou ook self modifying code gebruikt kunnen worden om de 2.2 c variant te maken die en snel en redelijk leesbaar is.

var a

   ...
   move calc.,a
   ...
   loop
   do {
      ...
      if(a=0) st. 1  
      else    st. 2
      ...
   } od
   ...
var a

   ...
   move calc,a  
   ...
   if(a=0)
   {
     loop
     do {
        ...
        st. 1
        ...
     } od
   }
   else
   {
     loop
     do {
        ...
        st. 2
        ...
     } od
   }
   ...
var a

   ...
   move calc,a
   if(a=0) move 'st. 1',x
   else    move 'st. 2',x
   ...
   loop
   do {
      ...
x:    st. 1
      ...
   } od
   ...
(a)(b)(c)
figuur 2.2

De hoeveelheid instructies die zich binnen de lus bevinden zijn aanzienlijk verkleind, wat voor tijdwinst zorgt. Er moeten dan wel eerst wat kosten gemaakt worden om de code tot de goede vorm te wijzigen. Vooral als in de lus veel vervangbare testinstructies staan en de lus vaak wordt uitgevoerd, zorgt dit voor een aanzienlijke winst.

Self modifying code is echter een techniek die geen structurele versnelling, in de zin van tijdscomplexiteit, met zich meebrengt. Het beste wat te bereiken valt is versnelling met een constante factor. Dit is eenvoudig in te zien bij figuur 2.1. Elke vorm van self modifying code is in één of andere vorm een variant van de code in figuur 2.1 b. Deze is weer gewoon te schrijven als in figuur 2.1 a. Zowel de tests gevolgd door de instructie als alleen de instructie kosten een constante hoeveelheid tijd. Dit betekent niet dat een constante versnelling niet mooi is.

Self modifying code is een techniek waarbij dynamisch instructies veranderd worden, waardoor nieuwe mogelijkheden van code bekeken kunnen worden. Het wordt vaak gebruikt om een programma kleiner of sneller te maken.