[<модификаторы_доступа>] <имя_метода>(<тип_параметра_1>,<тип_параметра_2>, ... ,<тип_параметра_n>):<тип_возвращаемого_значения> [throws <класс_исключения_1>, ... , <класс_исключения_n>];
% для методов с модификатором abstract нижележащая часть описания
% отсутствует
maxstack <число>;
maxlocals <число>;
[<метка_1>:]
<команда_1>;
...
[<метка_n>:]
<команда_n>;
[
protected_blocks;
{<класс_исключения>|finally} <метка> : <метка> > <метка>;
...
{<класс_исключения>|finally} <метка> : <метка> > <метка>;
]
end;
Здесь модификаторы_доступа - ключевые слова: public, protected, private, static, final, abstract, соответствующие следующим флагам доступа метода: ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_ABSTRACT. Повторение одинаковых модификаторов доступа в заголовке одного метода и сочетания модификаторов, соответствующие запрещенным сочетаниям флагов доступа (см. The Java Virtual Machine Specification), вызываютошибкувременикомпиляции. Методы интерфейса обязательно должны быть объявлены с модификаторами public и abstract. Имя_метода - корректный идентификатор, либо <init> или <clinit> для конструкторов и статических инициализаторов. Типы параметров и тип возвращаемого значения должны быть именами классов, либо именами примитивных типов, принятыми в языке Java (byte, short, int, long, char, float, double, boolean). Кроме того, тип возвращаемого значения может быть указан как void. После ключевого слова throws в заголовке метода могут быть перечислены через запятую имена классов исключений, генерируемых методом. Для методов, не являющихся абстрактными, после заголовка обязательно записываются предложения maxstack и maxlocals, в которых указывается размер стека операндов и области локальных переменных метода (в четырехбайтных ячейках). Затем следует код метода в виде последовательности команд, разделенных точками с запятыми. Каждой команде может предшествовать метка, отделяемая от нее двоеточием. Метка должна быть корректным. Каждая команда может иметь не более одной метки, и каждая метка должна предшествовать той или иной команде. Однако, имеется специальная псевдокоманда none, для которой не генерируется какой-либо код (пустая команда). Ее можно использовать, если необходимо расположить более одной метки у одной команды или поместить метку в конец метода. После ключевого слова protected_blocks могут быть перечислены защищенные блоки (обработчики исключений) метода. Описание каждого защищенного блока состоит из имени класса исключения или ключевого слова finally и трех меток, разделенных символами ‘:’ и ‘>’. Первая из них указывает на начало защищенного блока, вторая на его конец, третья - на место в коде метода, куда переходит управление при возникновении исключения или при выходе из защищенного блока в случае finally.
Используемые в коде мнемонические имена команд совпадают с принятыми в TheJavaVirtualMachineSpecification. Однако, как исключение, префикс wide не рассматривается как отдельная команда, вместо этого команды, его имеющие, записываются как wide_<имя_команды>. Форматы записи команд:
· <мнемоническое_имя>;Такуюформуимеютследующиекоманды: aaload, aastore, aconst_null, aload_0, aload_1, aload_2, aload_3 ,areturn, arraylength, astore_0, astore_1, astore_2, astore_3, athrow, baload, bastore, caload, castore, d2f, d2i, d2l, dadd, daload, dastore, dcmpg, dcmpl, dconst_0, dconst_1, ddiv, dload_0, dload_1, dload_2, dload_3, dmul, dneg, drem, dreturn, dstore_0, dstore_1, dstore_2, dstore_3, dsub, dup, dup2, dup2_x1, dup2_x2, dup_x1, dup_x2, f2d, f2i, f2l, fadd, faload, fastore, fcmpg, fcmpl, fconst_0, fconst_1, fconst_2, fdiv, fload_0, fload_1, fload_2, fload_3, fmul, fneg, frem, freturn, fstore_0, fstore_1, fstore_2, fstore_3, fsub, i2b, i2c, i2d, i2f, i2l, i2s, iadd, iaload, iand, iastore, iconst_0, iconst_1, iconst_2, iconst_3, iconst_4, iconst_5, iconst_m1, idiv, iload_0, iload_1, iload_2, iload_3, imul, ineg, ior, irem, ireturn, ishl, ishr, istore_0, istore_1, istore_2, istore_3, isub, iushr, ixor, l2d, l2f, l2i, ladd, laload, land, lastore, lcmp, lconst_0, lconst_1, ldiv, lload_0, lload_1, lload_2, lload_3, lmul, lneg, lor, lrem, lreturn, lshl, lshr, lstore_0, lstore_1, lstore_2, lstore_3, lsub, lushr, lxor, monitorenter, monitorexit, nop, pop, pop2, return, saload, sastore, swap;
· <мнемоническое_имя> <метка>; Такуюформуимеюткомандыперехода: goto, goto_w, if_acmpeq, if_acmpne, if_acmpge, if_acmpgt, if_icmple, if_icmplt, if_icmpne, ifeq, ifge, ifgt, ifle, iflt, ifne, ifnonull, ifnull, jsr, jsr_w;
· <мнемоническое_имя> <целоечисло>; Числодолжноудовлетворятьограничениямконкретнойкоманды: aload, astore, dload, dstore, fload, fstore, iload, istore, lload, lstore, ret, bipush, sipush, wide_aload, wide_astore, wide_dload, wide_dstore, wide_fload, wide_fstore, wide_iload, wide_istore, wide_lload, wide_lstore, wide_ret;
· <мнемоническое_имя> {<полное_имя_класса>|@}::<имя_поля>:<тип_поля>; Тип_поля - имя примитивного типа, принятое в языке Java, либо имя класса. Команды: getfield, putfield, getstatic, putstatic;
· <мнемоническое_имя> {<полное_имя_класса>|@}::<имя_метода>(<тип_параметра_1>, ... , <тип_параметра_n>):<тип_возвращаемого значения>; Здесь типы параметров и возвращаемого значения - имена примитивных типов, принятые в языке Java, имена классов, либо (только для возвращаемого значения) void. Команды: invokespecial, invokestatic, invokevirtual;
· <мнемоническое_имя> <полное_имя_класса>; Такой формат имеют следующие команды: anewarray, checkcast, instanceof, new;
· <мнемоническое_имя> <целое_число_индекс_переменной> <целое_число>; Команды: iinc, wide_iinc;
· <мнемоническое_имя> <тип> <константа>; - команды ldc, ldc_w, ldc_2w. Здесьтип - int, float, string (для ldc, ldc_w), double, long (для ldc_2w). Константа должна иметь соответствующий тип (целые числа записываются обычным способом, вещественные - в десятичной или экспоненциальной форме, в формате, принятом в Java, строки записываются в двойных кавычках, при этом две двойные кавычки внутри строки интерпретируются как одна двойная кавычка в строке);
· invokeinterface <имя_интерфейса>::<имя_метода>(<тип_аргумента_1>, ... , <тип_аргумента_2>):<тип_возвращаемого_значения> <целое_число>; - типы - аналогично другим командам вызова методов;
· multianewarray <полное_имя_класса> <число_измерений>;
· newarray {boolean|char|float|double|byte|short|int|long};
· tableswitch <число_1>:<число_n> default: <метка_0> <число_1>:<метка_1> ... <число_n>:<метка_n>; Здесь числа число_1 ... число_n должны быть последовательными целыми числами. При этом числа, указанные сразу после мнемонического имени команды, должны совпадать с границами диапазона чисел, для которых указаны метки перехода.lookupswitchdefault:<метка_0> <число_1>:<метка_1> ... <число_n>:<метка_n>; Здесь среди чисел, для которых указаны метки перехода, не должно быть одинаковых. Эти числа должны быть целыми, они не обязаны быть упорядочены по возрастанию, сортировка происходит при обработке команды компилятором.
Для тестирования компилятора использовались, в частности, следующие примеры:
%файл Summator.jsm
public class Summator;
fields;
private m_i:int;
methods;
%Конструктор. Заносит в поле m_i целое число, содержащееся в строке,
%передаваемой в качестве параметра. В случае, если строка не содержит
%правильной записи целого числа, либо это число отрицательное,
%то выводится сообщение об ошибке.
public <init>(java.lang.String):void;
maxstack 4;
maxlocals 2;
aload_0; %this
dup;
invokespecial java.lang.Object::<init>():void;
aload_1; %arg1
begin_try:
invokestatic java.lang.Integer::parseInt(java.lang.String):int;
dup;
iconst_0;
if_icmpge end_try;
new java.lang.Exception;
dup;
invokespecial java.lang.Exception::<init>():void;
athrow;
end_try:
putfield @::m_i:int;
return;
exception:
pop;
getstatic java.lang.System::out:java.io.PrintStream;
ldc string "Invalid argument";
invokevirtual java.io.PrintStream::println(java.lang.String):void;
return;
protected_blocks;
java.lang.Exception
begin_try : end_try > exception;
end;
%возвращает сумму натуральных чисел от 1 до m_i.
public getSum():int;
maxstack 3;
maxlocals 2;
iconst_0;
istore_1;
aload_0; %this
getfield @::m_i:int;
loop:
dup;
iload_1; %result
iadd;
istore_1; %result
iconst_1;
isub;
dup;
iconst_0;
if_icmpgt loop;
pop;
iload_1; %result
ireturn;
end;
%возвращает значение поля m_i
public getI():int;
maxstack 1;
maxlocals 1;
aload_0; %this
getfield @::m_i:int;
ireturn;
end;
%файл Switches.jsm
public class Switches;
fields;
methods;
%оба метода функционально эквивалентны следующей функции, написанной на Java.
% static int function(int i) {
% switch(i) {
% case 1: return 2;
% case 2: return -1;
% default: return 0;
% }
% }
public static lookup(int):int;
maxstack 1;
maxlocals 1;
iload_0;
lookupswitch
default : l_def
1 : l_1
2 : l_2;
l_def:
iconst_0;
ireturn;
l_1:
iconst_2;
ireturn;
l_2:
iconst_m1;
ireturn;
end;
public static table(int):int;
maxstack 1;
maxlocals 1;
iload_0;
tableswitch 1:2
default : l_def
1 : l_1
2 : l_2;
l_def:
iconst_0;
ireturn;
l_1:
iconst_2;
ireturn;
l_2:
iconst_m1;
ireturn;
end;
Следующий пример представляет собой программу, состоящую из 5 классов.
%-------------------------------------------------------------%
%файл Figure.jsm
public interface Figure;
methods;
public abstract getArea():double;
%-------------------------------------------------------------%
%-------------------------------------------------------------%
%файл Circle.jsm
public class Circle;
implements Figure;
fields;
private m_radius:double;
methods;
public <init>(double):void;
maxstack 4;
maxlocals 3;
aload_0;
invokespecial java.lang.Object::<init>():void;
dload_1;
dconst_0;
dcmpg;
ifge l_endif;
new java.lang.IllegalArgumentException;
dup;
invokespecial java.lang.IllegalArgumentException::<init>():void;
athrow;
l_endif:
aload_0;
dload_1;
putfield @::m_radius:double;
return;
end;
public getArea():double;
maxstack 4;
maxlocals 1;
aload_0;
getfield @::m_radius:double;
aload_0;
getfield @::m_radius:double;
dmul;
ldc2_w double 3.14159265;
dmul;
dreturn;
end;
%-------------------------------------------------------------%
%-------------------------------------------------------------%
%файл Rectangle.jsm
public class Rectangle;
implements Figure;
fields;
private m_a:double;
private m_b:double;
methods;
public <init>(double, double):void;
maxstack 4;
maxlocals 5;
aload_0;
invokespecial java.lang.Object::<init>():void;
dload_1;
dconst_0;
dcmpl;
iflt l_error;
dload_3;
dconst_0;
dcmpl;
ifge l_endif;
l_error:
new java.lang.IllegalArgumentException;
dup;
invokespecial java.lang.IllegalArgumentException::<init>():void;
athrow;
l_endif:
aload_0;
dload_1;
putfield @::m_a:double;
aload_0;
dload_3;
putfield @::m_b:double;
return;