Kod bajtowy Perla

W tym artykule szczegółowo zbadamy temat Kod bajtowy Perla, który w ostatnich latach przykuł uwagę i zainteresowanie wielu osób. Zagłębimy się w jego pochodzenie, obecne znaczenie i wpływ na różne obszary codziennego życia. Przeanalizujemy także różne perspektywy i opinie istniejące wokół Kod bajtowy Perla, aby zapewnić naszym czytelnikom pełny i zrównoważony pogląd. Mamy nadzieję, że poprzez ten artykuł zaoferujemy głębsze i bogatsze zrozumienie Kod bajtowy Perla, a także zachęcimy do debaty i refleksji wokół tego fascynującego tematu.

Kod bajtowy Perla używany w Perlu 5 jest maszyną stosową z operacjami umiarkowanie wysokiego poziomu. Perl 6 używać będzie maszyny wirtualnej Parrot.

Wynikiem kompilacji:

print "Hello, world!\n";

jest następujący bytecode:

OP     enter
COP    nextstate
OP     pushmark
SVOP   const PV "Hello, world!\n"
LISTOP print
LISTOP leave

Klasy opcodów

Opcody są pogrupowane w kilka klas zależnie od tego na jakich argumentach działają. Klasy te to:

  • OP – ogólna klasa,
  • COP – informacja dla debugera,
  • SVOP – operacje na skalarach,
  • PADOP,
  • UNOP – operacje unarne,
  • LOGOP – operacje logiczne (sterujące),
  • BINOP – operacje binarne,
  • LISTOP – operacje działające na listach,
  • PMOP – operacje na wyrażeniach regularnych,
  • LOOPOP – operacje pętli,

Stos

Stos nie zawiera obiektów, a jedynie wskaźniki do nich.

Żeby wywołać operacje unarną lub binarną umieszczamy jej argumenty na stosie i wywołujemy ją.

Na przykład operacja unarna UNOP negate pobierze najwyższy element ze stosu i wstawi na stos jego zanegowaną wartość, operacja binarna BINOP add pobierze dwa najwyższe elementy ze stosu i wstawi ich sumę.

Żeby wywołać operację wymagającą większej ilości argumentów:

  • zaznaczamy za pomocą OP pushmark, że zaczyna się nowa ramka stosu,
  • umieszczamy na stosie wszystkie argumenty zaczynając od pierwszego,
  • wywołujemy odpowiednią operację (np. LISTOP print), lub umieszczamy na stosie adres funkcji do wywołania (PADOP gv GV *foo), po czym ją wywołujemy za pomocą UNOP entersub.

Przykład wywołania $x = "Hello, world!\n":

COP    nextstate
SVOP   const PV "Hello, world!\n"
PADOP  gvsv GV *x
BINOP  sassign

Przykład wywołania $x = -$y:

PADOP  gvsv GV *y
UNOP   negate
PADOP  gvsv GV *x
BINOP  sassign

Przykład wywołania $x = $y + $z:

PADOP  gvsv GV *y
PADOP  gvsv GV *z
BINOP  add
PADOP  gvsv GV *x
BINOP  sassign

Przykład wywołania print(1,2,3):

OP     pushmark
SVOP   const IV 1
SVOP   const IV 2
SVOP   const IV 3
LISTOP print

Przykład wywołania foo(1,2,3):

COP    nextstate
OP     pushmark
SVOP   const IV 1
SVOP   const IV 2
SVOP   const IV 3
PADOP  gv GV *foo
UNOP   entersub

Operacje na zmiennych skalarnych

Opcode PADOP gvsv umieszcza na stosie adres zmiennej.
Opcode SVOP const umieszcza na stosie stałą.

Opcode BINOP sassign przypisuje zmiennej, odnośnik do której adres znajduje się na najwyższej pozycji stosu. Adres zostaje zdjęty ze stosu, ale wartość zostaje.

Przykład wywołania $x = $y:

PADOP gvsv  GV *y
PADOP gvsv  GV *x
BINOP sassign

Przykład wywołania $x = $y = $z:

PADOP  gvsv GV *z
PADOP  gvsv GV *y
BINOP  sassign
PADOP  gvsv GV *x
BINOP  sassign

Operacje na liczbach

Podstawowe operacje arytmetyczne to:

Operacja Perl Bytecode
dodawanie $x + $y BINOP add
odejmowanie $x – $y BINOP substract
mnożenie $x * $y BINOP multiply
dzielenie $x / $y BINOP divide
reszta modulo $x % $y BINOP modulo
bitowe AND $x & $y BINOP bit_and
bitowe OR $x | $y BINOP bit_or
bitowe XOR $x ^ $y BINOP bit_xor
negacja arytmetyczna -$x UNOP negate
negacja bitowa ~$x UNOP complement
sinus sin($x) UNOP sin
cosinus cos($x) UNOP cos
funkcja wykładnicza exp($x) UNOP exp
logarytm log($x) UNOP log
pierwiastek sqrt($x) UNOP sqrt
większe $x > $y BINOP gt
większe równe $x >= $y BINOP ge
mniejsze $x < $y BINOP lt
mniejsze równe $x <= $y BINOP le
równe $x == $y BINOP eq
nierówne $x != $y BINOP ne
porównanie $x <=> $y BINOP ncmp
przesunięcie bitowe w lewo $x << $y BINOP left_shift
przesunięcie bitowe w prawo $x >> $y BINOP right_shift
preinkrementacja ++$x UNOP preinc
predekrementacja --$x UNOP predec
postinkrementacja $x++ UNOP postinc
postdekrementacja $y-- UNOP postdec

Operatory ++ i -- działają też na łańcuchach. Wersje pre- i post- różnią się tym, co zostaje na stosie.

Operacje na łańcuchach znaków

Operacja Perl Bytecode
sklejenie $x . $y BINOP concat
długość length($x) UNOP length
zamiana wszystkich liter na wielkie uc($x) UNOP uc
zamiana wszystkich liter na małe lc($x) UNOP lc
zamiana pierwszego znaku na wielką literę ucfirst($x) UNOP ucfirst
zamiana pierwszego znaku na małą literę lcfirst($x) UNOP lcfirst
większe $x gt $y BINOP sgt
większe równe $x ge $y BINOP sge
mniejsze $x lt $y BINOP slt
mniejsze równe $x le $y BINOP sle
równe $x eq $y BINOP seq
nierówne $x ne $y BINOP sne
porównanie $x cmp $y BINOP scmp