13.2 Віртуальна машина Java
Типи даних, з якими працює Java VM, підрозділяються напримітивні і по посиланню. Більшість примітивних типівданих Java VM є також примітивними типами в мові Java.До них відносяться:
byte - 1-байтне ціле зі знаком;
short - 2-байтне ціле зі знаком;
int – 4- байтне ціле зі знаком;
long - 8- байтне ціле зі знаком;
float – 4-байтне число з плаваючою точкою;
double – 8- байтне число з плаваючою точкою;
char - 2-байтний символ Unicode.
На відміну від інших мов програмування, розміри типів вмові Java і в Java VM є постійними, не залежними відплатформи. Java VM не оперує типом boolean, яка є примітивним типом мови Java. Для виразів мови, що оперуютьцим типом, компілятор Java генерує коди, що оперуютьтипом int. Примітивний тип returnAddress в Java VM не має відповідності в мові Java. Тип return Address є покажчиком на команду байт-кода Java і використовується як операнд команд передачі управління.
Типи з посиланнями в Java VM і в мові Java є посиланнями (покажчиками) на об'єкти - екземпляри класів, масиви і інтерфейси (екземпляри класів, що реалізують інтерфейси). Специфікації Java VM не визначають внутрішню структуру об'єктів, в більшості сучасних Java VM посилання на об'єкт є покажчиком на дескриптор об'єкта, в якому, в свою чергу містяться два покажчика:
• на об'єкт типу Class, який представляє інформацію типу, в тому числі методи і статичні дані класу;
• на пам'ять, виділену для локальних даних об'єкта в купі.
Всі покажчики, з якими працює Java VM, є покажчиками в плоскому 32-розрядному адресному просторі, хоча в реалізаціях Java VM для 64-розрядних платформ можуть використовуватися і 64-розрядні покажчики.
Основні області пам'яті, з якими працює Java VM, показані на малюнку 13.2.
Область пам'яті, звана купою, поділяється на дві частини: область класів і область динамічно розподіляє пам'яті (іноді купою називають тільки цю частину пам'яті). Купа створюється при запуску Java VM. Конкретні реалізації Java VM можуть забезпечувати управління початковим розміром купи і розширення купи при необхідності.
Клас є основною програмною одиницею платформи Java, що об'єднує в собі дані і методи їх обробки. При завантаженні класу для нього виділяється пам'ять в області класів. Кожен клас представляється двома структурами пам'яті: областю методів і пулом констант. Область методів містить виконувану частину класу - байт-коди методів класу, а також таблицю символічних посилань на зовнішні методи та змінні. Пул констант містить літерали класу.
В області динамічного розподілу виділяється пам'ять для розміщення об'єктів. Управління цією областю пам'яті ми розглядаємо в окремому розділі.
Java VM підтримує паралельне виконання декількох ниток. Для кожної нитки при її створенні Java VM створює набір регістрів і стек нитки.
Набір регістрів включає в себе чотири 32-розрядних регістра:
• ПК - регістр-покажчик на команду;
• optop - регістр-покажчик на вершину стека операндів поточного кадру;
• var - регістр-покажчик на масив локальних змінних поточного кадру;
• frame - регістр-покажчик на середу виконання поточного методу.
Стек нитки являє собою стек у традиційному розумінні, тобто, спискову структуру даних, що обслуговується з дисципліни "останнім прийшов - першим пішов». Елементами стека є кадри (кадр) методів. У традиційних блокових мовах програмування за допомогою стека забезпечуються вкладені виклики процедур. Аналогічним чином Java VM через стек нитки забезпечує вкладені виклики методів, представляючи кожен метод кадром в стеці. Новий кадр створюється і поміщається в вершину стека при виклику методу. Кадр, розташований у вершині стека є поточним, він відповідає методу, виконуваному в нитки в поточний момент. При поверненні з методу його кадр видаляється з стека. Управління початковим розміром стека нитки і можливість його динамічного розширення залежить від реалізації Java VM. Специфікації Java VM не вимагають розміщення стека нитки в безперервній області пам'яті.
Кадр, як було сказано, створюється динамічно та містить три основні області.
• набір локальних змінних екземпляра класу, на який посилається регістр VAR;
• стек операндів, на який посилається регістр optop;
• структури середовища виконання, на яку посилається регістр кадру.
Ці області показані на малюнку 13.3.
Набір локальних змінних являє собою масив 32-розрядних слів. Дані подвійної точності (типи long і double) займають по два суміжних слова в цьому масиві. Розмір цього масиву фіксований для методу, так як число локальних змінних методу стає відомим вже на етапі компіляції. Операнди команд байт-коду, які оперують локальними змінними, представляються індексами в цьому масиві.
Java VM є стековой машиною. Це означає, що в ній немає регістрів загального призначення, і операції виробляються над даними, що знаходяться в стеці. Цій меті служить стек операндів, що виділяється у складі кожного кадру. При виконанні команд байт-коду Java, що змінюють дані, операнди таких команд вибираються з стека операндів, в той же стек поміщаються і результати виконання команд.
Сердовище виконання методу містить інформацію, необхідну для динамічного зв'язування, повернення з методу та обробки виключень. Код класу (розміщений в області класу) звертається до зовнішніх методів і змінним, використовуючи символічні посилання. Динамічне компонування переводить символьні посилання в фактичні. Середовище виконання містить посилання на таблицю символів методу, через яку здійснюються звертання до зовнішніх методів і змінним.
У середовищі виконання міститься також інформація, необхідна для повернення з методу: покажчик на кадр зухвалого методу, значення регістра PC для повернення, вміст регістрів зухвалого методу і покажчик на область для запису значення, що повертається.
Інформація обробки виключень містить посилання на секції обробки виключень в методі класу.
Через середовище виконання також відбуваються звернення до даних, що містяться в області класу, в тому числі, до констант і до змінних класу.
Команди Java VM складаються з однобітних коду операції, а також можуть містити операнди. Число і розмір операндів визначаються кодом операції, деякі команди не мають операндів. Основний алгоритм роботи Java VM зводиться до найпростішого циклу, наведеному на малюнку 13.4.
Кожен з типів даних Java VM обробляється своїми командами. Основні типи команд Java VM:
• Команди завантаження і збереження, у тому числі:
Про завантаження в стек локальної змінної;
Про збереження значення зі стека в локальній змінній;
Про завантаження в стек константи (з пулу констант).
• Команди маніпулювання значеннями (більшість цих операцій працюють з операндами з стека і поміщають результат в стек), у тому числі:
Про арифметичні операції;
про побітові логічні операції;
Про зрушення;
про інкремент (операція працює з операндом - локальної змінної).
• Команди перетворення типів.
• Команди створення посилальних даних і доступу до них, у тому числі:
створення екземплярів класу;
Про доступу до полів класу;
створення масивів;
Про читання в стек і збереження елементів масивів;
Про отримання властивостей масивів та об'єктів.
• Команди прямого маніпулювання зі стеком.
• Команди передачі управління, в тому числі:
Про безумовний перехід;
про умовний перехід;
перехід по множинному вибору.
• Команди виклику методів і повернення (включаючи спеціальні команди виклику синхронізованих методів).
• Команди генерації та обробки виключень.
Прийняті в специфікаціях Java VM структури даних і алгоритми такі, що дозволяють реалізувати віртуальну машину з мінімальними витратами пам'яті і зробити її роботу максимально ефективною.
Іншим ключовим елементом специфікацій Java є файл класу. Кожен файл класу описує один клас або інтерфейс. Файл класу містить потік байт, структурований певним чином. Всі реалізації компілятора Java повинні генерувати файли класів, структура яких відповідає визначеній у специфікаціях. Все реалізації Java VM повинні "розуміти" структуру файли класу, відповідну певної в специфікаціях.
Основні компоненти файлу класу наступні:
• Деяка Верифікаційна інформація: "магічне число", - сигнатура файлу класу, номер версії.
• Прапор доступу, що відображає модифікатори, задані у визначенні класу (державні, остаточному, абстрактні і т.д.), а також ознака класу або інтерфейсу.
• Пул констант - таблиця структур, що представляють різні рядкові константи - імена класів і інтерфейсів, полів, методів і інші константи, на які є посилання в файлі класу.
• Посилання на імена цього-класу та суперкласу в пулі констант.
• Перелік інтерфейсів, реалізованих класом (у вигляді посилань в пул констант).
• Опис полів класу із зазначенням їхніх імен, типів, модифікаторів і т.д.
• Методи класу - кожен метод представляється у вигляді певної структури, в якій міститься опис методу (ім'я, модифікатори, і т.д.), одним з атрибутів цієї структури є масив байт-кодів методу.
Багато компонентів файлу класу (пул констант, перелік інтерфейсів і ін) Мають нефіксовану довжину, такі компоненти передаються 2-байтним полем, що містить їх довжину.
