Co to jest ramka mapy stosu

Ostatnio patrzyłem na Java virtual Machine Specifications (JVMS), aby spróbować lepiej zrozumieć, co sprawia, że moje programy działają, ale znalazłem sekcję, której nie do końca rozumiem...

Sekcja 4.7.4 opisuje atrybut StackMapTable , a w tej sekcji dokument zawiera szczegóły dotyczące ramek map stosu. Problem w tym, że to trochę słowne i uczę się najlepiej na przykładzie, a nie przez czytanie.

Rozumiem, że pierwsza ramka mapy stosu pochodzi z deskryptora metody, ale nie rozumiem jak (co podobno jest wyjaśnione tutaj .) Również nie do końca rozumiem, co robią ramki map stosu. Zakładam, że są one podobne do bloków w Javie, ale wygląda na to, że nie można mieć ramek map stosu wewnątrz siebie.

W każdym razie mam dwa konkretne pytania:

  • do czego służą ramki map stosu?
  • Jak wygląda pierwsza ramka mapy stosu stworzony?

I jedno pytanie ogólne:

  • Czy ktoś może podać wyjaśnienie mniej słowne i łatwiejsze do zrozumienia niż to podane w JVMS?
Author: Raedwald, 2014-08-03

1 answers

Java wymaga weryfikacji wszystkich załadowanych klas w celu zachowania bezpieczeństwa piaskownicy i zapewnienia, że kod jest bezpieczny do optymalizacji. Zauważ, że odbywa się to na poziomie kodu bajtowego, więc weryfikacja Nie weryfikuje niezmienniki języka Java , tylko sprawdza, czy bajt ma sens zgodnie z regułami dla kodu bajtowego.

Między innymi weryfikacja kodu bajtowego zapewnia, że instrukcje są dobrze uformowane, że wszystkie skoki są poprawnymi instrukcjami wewnątrz metody, a wszystkie instrukcje operują na wartościach właściwego typu. Ostatni to miejsce, w którym pojawia się Mapa stosu.

Rzecz w tym, że bytecode sam w sobie nie zawiera jawnych informacji o typie. Typy są określane pośrednio poprzez analizę przepływu danych. Na przykład instrukcja iconst tworzy wartość całkowitą. Jeśli przechowujesz go w slocie 1, slot ten ma teraz int. Jeśli control flow połączy się z kodem, który zamiast tego przechowuje float, slot jest teraz uważany za nieprawidłowy typ, co oznacza, że nie możesz zrobić nic więcej z tą wartością, dopóki nie nadpisasz jej.

Historycznie, weryfikator bajtów wywnioskował wszystkie typy używając tych reguł przepływu danych. Niestety, nie jest możliwe wyciągnięcie wszystkich typów w jednym liniowym przejściu przez kod bajtowy, ponieważ skok wsteczny może unieważnić już wnioskowane typy. Klasyczny weryfikator rozwiązał to poprzez iterację kodu, aż wszystko przestało się zmieniać, potencjalnie wymaga wielokrotnych przejść.

Jednak weryfikacja powoduje, że ładowanie klas jest powolne w Javie. Oracle zdecydowało się rozwiązać ten problem, dodając nowy, szybszy weryfikator, który może weryfikować bajt kodu w jednym przejściu. W tym celu wymagały, aby wszystkie nowe klasy zaczynające się w Javie 7 (z Javą 6 w stanie przejściowym) nosiły metadane o swoich typach, tak aby kod bajtowy mógł zostać zweryfikowany w jednym przejściu. Ponieważ sam format kodu bajtowego nie może zostać zmieniony, informacje tego typu są przechowywane oddzielnie w atrybucie o nazwie StackMapTable.

Zwykłe przechowywanie Typu dla każdej pojedynczej wartości w każdym punkcie kodu zajmowałoby oczywiście dużo miejsca i byłoby bardzo marnotrawne. Aby metadane były mniejsze i bardziej wydajne, postanowiono, że wymienia tylko typy na pozycjach, które są celem skoków . Jeśli się nad tym zastanowić, jest to jedyny czas, kiedy potrzebujesz dodatkowych informacji, aby przeprowadzić weryfikację pojedynczego przejścia. Pomiędzy celami skokowymi cała kontrola przepływ jest liniowy, więc można wnioskować typy pomiędzy pozycjami za pomocą starych reguł wnioskowania.

Każda pozycja, w której typy są wyraźnie wymienione, jest znana jako ramka mapy stosu. Atrybut StackMapTable zawiera listę ramek w kolejności, chociaż są one zwykle wyrażone jako różnica w stosunku do poprzedniej ramki w celu zmniejszenia rozmiaru danych. Jeżeli w metodzie nie ma ramek, co występuje, gdy przepływ sterowania nigdy się nie łączy( tzn. CFG jest drzewem), wtedy atrybut StackMapTable może być całkowicie pominięte.

To jest podstawowa idea działania StackMapTable i dlaczego została dodana. Ostatnie pytanie dotyczy sposobu tworzenia domyślnej ramki początkowej. Odpowiedź jest oczywiście taka, że na początku metody stos operandu jest pusty, a gniazda zmiennych lokalnych mają typy podane przez typy parametrów metody, które są określone z metody decriptor.

Jeśli jesteś przyzwyczajony do Javy, istnieje kilka drobnych różnic w sposobie działania typów parametrów metod na poziomie kodu bajtowego. Po pierwsze, metody wirtualne mają domyślnie this jako pierwszy parametr. Drugi, boolean, byte, char, i short nie istnieją na poziomie kodu bajtowego. Zamiast tego wszystkie są realizowane jako ints za kulisami.

 135
Author: Antimony,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-17 19:00:32