Выражение 1+1
будет компилироваться в следующий байт-код:
iconst_1
iconst_1
add
(На самом деле, оно просто компилируется в iconst_2
, потому что компилятор Java выполняет свертывание констант, но давайте проигнорируем это дляцели этого ответа.)
Таким образом, чтобы точно узнать, что интерпретатор делает для этих инструкций, мы должны взглянуть на его исходный код .Соответствующие разделы для const_1
и add
начинаются с строки 983 и строки 1221 соответственно, поэтому давайте посмотрим:
#define OPC_CONST_n(opcode, const_type, value) \
CASE(opcode): \
SET_STACK_ ## const_type(value, 0); \
UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
OPC_CONST_n(_iconst_m1, INT, -1);
OPC_CONST_n(_iconst_0, INT, 0);
OPC_CONST_n(_iconst_1, INT, 1);
// goes on for several other constants
//...
#define OPC_INT_BINARY(opcname, opname, test) \
CASE(_i##opcname): \
if (test && (STACK_INT(-1) == 0)) { \
VM_JAVA_ERROR(vmSymbols::java_lang_ArithmeticException(), \
"/ by zero", note_div0Check_trap); \
} \
SET_STACK_INT(VMint##opname(STACK_INT(-2), \
STACK_INT(-1)), \
-2); \
UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); \
// and then the same thing for longs instead of ints
OPC_INT_BINARY(add, Add, 0);
// other operators
Все этонаходится внутри оператора switch, который проверяет код операции текущей инструкции.
Если мы расширим макромагию, заменим окружающий код предельно упрощенным шаблоном и сделаем некоторые упрощающие предположения (такие как стек, состоящий только изиз int
с), мы в итоге получим что-то вроде этого:
enum OpCode {
_iconst_1, _iadd
};
// ...
int* stack = new int[calculate_maximum_stack_size()];
size_t top_of_stack = 0;
size_t program_counter = 0;
while(program_counter < program_size) {
switch(opcodes[pc]) {
case _iconst_1:
// SET_STACK_INT(1, 0);
stack[top_of_stack] = 1;
// UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
program_counter += 1;
top_of_stack += 1;
break;
case _iadd:
// SET_STACK_INT(VMintAdd(STACK_INT(-2), STACK_INT(-1)), -2);
stack[top_of_stack - 2] = stack[top_of_stack - 1] + stack[top_of_stack - 2];
// UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
program_counter += 1;
top_of_stack += -1;
break;
}
Так что для 1+1
последовательность операций будет такой:
stack[0] = 1;
stack[1] = 1;
stack[0] = stack[1] + stack[0];
И top_of_stack
будетбудет 1, поэтому мы закончили бы стеком, который содержит значение 2
в качестве единственного элемента.