Теоретически, можно взять любой интерпретатор для языка и превратить его в компилятор, который генерирует нативный код на этом языке. Это связано с рядом уравнений, называемых проекциями Футамуры . Идея высокого уровня заключается в том, чтобы «обмануть» то, как вы определяете компилятор. Предположим, что для некоторого языка L у меня есть интерпретатор I (p), который, учитывая программу p, написанную на языке L, интерпретирует эту программу. Теперь я предполагаю, что интерпретатор I представлен непосредственно в машинном коде. Далее предположим, что у меня есть программа с именем mix
, которая, учитывая программу машинного кода и последовательность ввода этой программы, создает новую программу машинного кода, которая является исходной программой с фиксированным входным значением, указанным для указанного ввода. Например, если я скомпилировал эту программу на C ++:
#include <iostream>
using namespace std;
int main() {
string message;
cin >> message;
cout << message << endl;
}
А затем использовал mix
, чтобы смешать программу с вводом «Hello», я бы получил программу, которая всегда печатает сообщение «Hello». Другими словами, это было бы так, как если бы я написал эту программу:
#include <iostream>
using namespace std;
int main() {
cout << "Hello" << endl;
}
Оказывается, возможно построить эту программу. Я мог бы сделать это, например, просматривая машинный код, просматривая каждое место, в котором вы пытаетесь прочитать ввод с консоли, а затем заменяя его на код, вызывающий функцию, которая вместо этого считывает жестко закодированную строку.
Теперь рассмотрим, что произойдет, если вы запустите эту mix
программу, взяв в качестве входных данных интерпретатор I и некоторую программу p. Тогда результатом этого будет программа машинного кода, которая эквивалентна программе, которую я запускаю на входе p. Другими словами, вы только что создали программу с машинным кодом, которая имитирует то, что произойдет, если вы запустите интерпретатор программы - это программа с машинным кодом, которая выполняет программу p!
Конечно, эта конструкция совершенно нецелесообразна. Насколько мне известно, никто не написал mix
, и если бы они это сделали, любая программа, которую вы сделали, превратив интерпретатор в компилятор, была бы крайне неэффективна, потому что она вообще не была бы оптимизирована.
Что касается вашего первоначального вопроса о том, можете ли вы взять JIT JVM и использовать его для создания необработанного машинного кода для Java-программы, я не уверен, поскольку я не смотрел на исходный код, но я сильно сомневаюсь в этом , Машинный код почти наверняка содержит хуки, которые будут вызывать JVM для конкретных задач (например, сборка мусора, загрузка классов и т. Д.), Что приведет к тому, что сгенерированный код не будет работать в автономной среде. Тем не менее, это действительно крутая идея, чтобы попытаться сделать это, и я надеюсь, что этот ответ проливает некоторый свет на теорию, стоящую за ним!