Рубрики
Без рубрики

Насколько похоже выполнение Java и JavaScript?

В этой статье я сравню выполнение Java и JavaScript. Я намеренно избегаю буквы “л”… Помеченный javascript, java, компиляторами.

В этой статье я сравню выполнение Java и JavaScript. Я намеренно избегаю многих подробностей о памяти, так как это совершенно другая тема.

С каждым проходящим тактом процессор выполняет одну микроинструкцию. Это строки, биты которых управляют управляющими линиями центрального процессора. Мы получаем серию микроинструкций путем перевода инструкции (часто называемой машинным кодом). Набор всех доступных инструкций для процессора называется архитектурой набора инструкций (ISA), которая в некотором смысле является API процессора вашего компьютера.

исходный код -> инструкции (теперь внутри процессора) -> микроинструкции (выполняются каждый такт)

Инструкции в программе могут быть взяты компилятором и превращены в машинный код (инструкции). Лучшим примером этого является C. Однако разные процессоры предоставляют разные архитектуры набора команд. Означает ли это, что мы должны написать другой компилятор для каждого процессора? (Да, это так.) Это проблема, поскольку компиляторы выполняют все больше и больше работы для программиста.

Мы можем решить эту проблему, сохранив все добавленные функции в нашем исполнителе программ неизменными, за исключением процессора. Если мы виртуализируем процессор и предоставим ISA, специально разработанный для выполнения рассматриваемого языка, у нас теперь есть компонент, который мы можем вводить и выводить при переходе с одной ОС на другую (предположительно, с разными процессорами).

Как упоминалось выше, оба рассматриваемых языка (Java и JavaScript) обеспечивают абстракцию поверх машинного кода для управления этой сложностью. Эта “абстракция машинного кода” называется байт-кодом. В Java это файлы .class , а в JavaScript они варьируются в зависимости от рассматриваемого движка. Чтобы увидеть байт-код, используемый движком V8 (тот, который используется в Node.js и Chrome), выполните его с флагом --печать байт-кода .

Чтобы запустить программу JavaScript исключительно с V8 (исключая среду выполнения узла), установите V8 и запустите v8 hello.js (где hello.js это ваша программа) например v8 --печать байт-кода hello.js (Потому что просмотр байт-кода среды выполнения узла не является лучшим для образовательных целей).

Когда я говорю “виртуализация процессора”, я имею в виду, что мы выполняем программу на виртуальной машине. У нас есть некая сущность (либо интерпретатор JVM, либо исполнитель байт-кода Ignition), которая знает, как выполнить свою версию байт-кода. То, что мы здесь используем, называется виртуальной машиной процесса . Это резко контрастирует с системной виртуальной машиной , которая имеет собственную гостевую операционную систему (например, VMware). Виртуальная машина процесса намного легче, и ее единственной целью является выполнение программы. Чтобы быть ясным, он дополнительно виртуализирует другие вещи, такие как память, что означает, что существует сопоставление. Для простоты отображение – это просто прямое отображение . Обратите внимание, что память уже виртуализирована в ОС хоста; блоки памяти, выделенные процессу, кажутся непрерывными, но это не гарантируется. Самое сложное, что мы абстрагируем, – это процессор и его машинный код.

В JVM, например, интерпретатор берет строку байт-кода и знает, как ее выполнить, не обеспечивая дальнейшего перевода в машинный код.

В V8 интерпретатор зажигания действует аналогичным образом. он берет инструкцию из проанализированного AST , превращает ее в байт-код и выполняет ее самостоятельно.

Давайте углубимся в детали этих двух вопросов.

Допустим, у нас есть исходный код Java. Мы используем компилятор Java (javac), чтобы превратить его в байт-код (файлы .class). Затем мы передаем его в JVM.

JVM принимает его, и после некоторых шагов инициализации (загрузка класса, проверка байт-кода и т.д.) оператор байт-кода поступает в интерпретатор, который его выполняет.

По мере продолжения выполнения, если какой-либо фрагмент кода (например, функция) был выполнен определенное количество раз (т.Е. он “горячий”), механизм выполнения JVM содержит оптимизирующий JIT компилятор, который превратит его в машинный код, позволяя ему выполняться быстрее.

Обратите внимание, что “JIT-компилятор” в этом случае переходит от байт-кода к машинному коду. JIT-компиляция Javascript, напротив, переходит от исходного кода к байт-коду.

В отличие от этого, JavaScript компилируется JIT. Это означает, что нет этапа предварительной компиляции до того, как он будет передан в механизм выполнения; мы передаем движку необработанный исходный код.

Скажем, у нас есть исходный код JavaScript. Он анализируется и превращается в AST. Затем он подается в систему зажигания, интерпретатор V8. Зажигание превращает это в байт-код и выполняет его.

Как и раньше, если мы обнаружим горячую функцию, у нас есть оптимизирующий компилятор, который превратит ее в машинный код. В V8 эта сущность называется Турбовентилятор .

Собираюсь украсть фотографию Франциски Хинкельманн из ее замечательного поста в блоге на эту тему.

Примечание – Выше я говорил о виртуальных машинах процессов. V8 довольно скуден в таких внутренних деталях, но я прочитал достаточно, чтобы убедить себя, что они используют виртуальную машину процесса. (См. здесь , здесь и здесь ).

  • Оба они выполняются внутри виртуальных машин процесса. У них обоих есть свой собственный “байт-код”, который является всего лишь абстракцией машинного кода. Эти виртуальные машины процесса выполняют соответствующий байт-код.
  • Они оба используют один и тот же подход к “горячему” коду. То есть оптимизирующий компилятор превращает байт-код в машинный код, используя информацию о профилировании, накопленную во время выполнения.

Здесь есть одно существенное отличие — JavaScript компилируется JIT, а Java – нет. Из-за этого между языком JavaScript и его механизмом выполнения (в данном случае V8) нет абстракции. Это означает, что невозможно использовать V8 для выполнения на другом языке.

JVM, с другой стороны, знает только о байт-коде файла .class . Это дает место для другого языка, который может компилироваться в файлы .class. Введите Scala, Groovy, Clojure и Kotlin.

Это иронично, потому что этот уровень абстракции существует только потому, что возникла необходимость отправлять байт-код по сети примерно в то время, когда появилась Java (ранние дни Всемирной паутины, когда Java поддерживалась в браузере). В настоящее время это не имеет значения вообще . В наши дни мы отправляем исходный код JavaScript по сети, и браузер использует механизм выполнения (например, V8) для его выполнения.

Я нахожу этот момент увлекательным, и я считаю, что эта косвенность может привести к тому, что JVM останется на очень долгое время, потому что мы можем использовать ее, даже если мы не хотим использовать Java. Это привлекательно для разработчиков языков, потому что более половины работы выполняется за них — все, что им нужно сделать, это разработать спецификацию языка и компилятор для .класс байт-код.

После исследования и написания этой статьи я пришел к выводу, что способ выполнения языков JVM и JavaScript намного ближе, чем я предполагал изначально. Надеюсь, ты чему-то научился.

Первоначально опубликовано здесь .

Оригинал: “https://dev.to/alexhwoods/how-similar-is-the-execution-of-java-and-javascript-3548”