-
Notifications
You must be signed in to change notification settings - Fork 2
JAL Syntax Guide
Welcome to JAL (Java Assembly Language) — a powerful and expressive assembly-like language designed specifically for JVM bytecode manipulation and development.
This document provides a detailed user-oriented explanation of JAL’s syntax and usage so you can write and understand JAL source files with confidence.
[このページは日本語でもご覧いただけます。](JAL 構文ガイド)
JAL is an assembly language tailored for the Java Virtual Machine (JVM). It exposes JVM bytecode instructions in a human-readable, structured format while adding several usability improvements to make low-level JVM programming more accessible.
The language lets you define classes, interfaces, fields, methods, and the instructions inside those methods — all using syntax closely related to JVM bytecode, but enhanced for clarity and ease of use.
A JAL source file may define one or more classes or interfaces. The declaration syntax resembles Java but is simplified and specialized for bytecode-level details:
class MyClass (major_version=55, minor_version=0) {
// class body here
}
-
classorinterfacekeywords start declarations. - Version numbers specify the target JVM version.
- Classes may extend superclasses and implement interfaces with metadata.
JAL allows embedding detailed metadata about classes directly within the class declaration. These metadata properties control fundamental class attributes relevant to the JVM runtime and class file structure:
-
major_versionandminor_version
Specify the class file version, which determines the minimum JVM version required to load this class. For example,major_version=55targets Java 11. -
super_class
Defines the fully qualified superclass that this class extends. If omitted, the default superclass isjava/lang/Object.
Example:super_class=java/lang/Number -
interfaces
Lists one or more fully qualified interfaces that the class implements. Multiple interfaces are comma-separated:interfaces=java/io/Serializable,java/lang/Cloneable
These metadata are declared inside parentheses immediately after the class name and separated by commas if multiple:
class MyClass (
major_version=55,
minor_version=0,
super_class=java/lang/Object,
interfaces=java/io/Serializable,java/lang/Cloneable
) {
// class body
}
Using class metadata ensures that the generated class files conform to desired JVM specifications and inheritances without additional boilerplate code inside the class body.
You can specify JVM access flags such as public, private, protected, static, final, abstract, etc., on classes, methods, and fields:
public static final class MyClass { ... }
private volatile int myField;
protected synchronized void myMethod() { ... }
These modifiers map directly to JVM access flags, controlling visibility and behavior.
Fields are declared by specifying modifiers, a name, a type descriptor, and optionally an initial constant value:
private static final myField: I = 123;
Here, I is the JVM type descriptor for int.
Methods are defined with modifiers, a name, and a method descriptor indicating argument types and return type:
public static main([Ljava/lang/String;)V {
// instructions here
}
- Method names can be normal identifiers or special JVM method names like
<init>(constructor) and<clinit>(static initializer). - Method descriptors follow JVM format, e.g.,
([Ljava/lang/String;)Vmeans method takes a String array and returns void.
Inside method bodies, you write JVM bytecode instructions line by line, each corresponding to a JVM opcode. JAL supports the full set of JVM instructions as tokens.
Example:
getstatic java/lang/System->out:Ljava/io/PrintStream;
ldc "Hello, World!"
invokevirtual java/io/PrintStream->println(Ljava/lang/String;)V
return
- Instructions may take arguments: literals, references to fields/methods/classes, labels, or numeric constants.
- References to members follow the syntax:
<owner_class>/<field_or_method_name>:<type_descriptor>or<owner_class>-><method_name><method_descriptor>. - Literal strings and numeric constants can be used as instruction operands (e.g.,
ldc "string"orbipush 10).
You can declare labels to mark positions in code for jumps, branches, exception handlers, etc.:
loopStart:
iload_0
ifeq loopEnd
iinc 0 1
goto loopStart
loopEnd:
Labels end with a colon (:) and can be referenced by jump instructions.
JAL allows declaration of exception handling regions using label-based syntax inside method bodies:
tryStart: [~tryEnd, java/lang/Exception: catchStart, ->finallyStart]
tryEnd:
catchStart:
finallyStart:
- This declares a try block starting at
tryStartending attryEnd. - Catches
java/lang/ExceptionatcatchStart. - Finally block starts at
finallyStart. - This syntax clearly maps to JVM exception tables but is much more readable.
JAL uses JVM standard type descriptors to specify types:
| Descriptor | Type | Example Usage |
|---|---|---|
B |
byte | myField: B |
C |
char | charVal: C |
D |
double | doubleVal: D |
F |
float | floatVal: F |
I |
int | intVal: I |
J |
long | longVal: J |
S |
short | shortVal: S |
Z |
boolean | boolVal: Z |
V |
void | Used only in methods |
L<classname>; |
Object type | Ljava/lang/String; |
Arrays are indicated by preceding with [, e.g., [I for int array.
Method descriptors specify argument types and return type, enclosed in parentheses, e.g.:
([Ljava/lang/String;)V
()Ljava/lang/String;
([IIDLjava/lang/Object;[Ljava/lang/String;)[Ljava/lang/String;
Means method takes an array of Strings and returns void.
In JAL, when you refer to fields or methods inside instructions, you must specify them explicitly to avoid ambiguity and to directly map JVM semantics.
-
owner_classis the fully qualified JVM internal class name (using/as separator). -
field_nameis the field identifier. -
type_descriptoris the JVM type descriptor of the field.
Example:
java/lang/System/out:Ljava/io/PrintStream;
This refers to the out static field in the java.lang.System class, which is of type java.io.PrintStream.
-
owner_classis the fully qualified JVM internal class name. -
method_nameis the method identifier (can be special names like<init>or<clinit>). -
method_descriptorfollows JVM specification describing argument and return types.
Example:
java/io/PrintStream->println(Ljava/lang/String;)V
Refers to the println method in java.io.PrintStream that takes a String and returns void.
When the field or method belongs to the current class (the one being defined), you can omit the owner_class part for convenience. This allows writing cleaner and more concise code without losing clarity.
-
Field Reference in Current Class:
fieldName:type_descriptor
Instead of writingmy/package/MyClass/myField:I, you can just writemyField:I. -
Method Reference in Current Class:
methodName(method_descriptor)
Instead ofmy/package/MyClass->myMethod()V, you can writemyMethod()V.
This shorthand is especially useful when invoking or accessing your own class’s members, reducing noise while keeping code straightforward.
// Accessing a field in another class
getstatic java/lang/System/out:Ljava/io/PrintStream;
// Invoking a method in another class
invokevirtual java/io/PrintStream->println(Ljava/lang/String;)V;
// Accessing a field in the current class (owner class omitted)
getfield myField:I;
// Invoking a method in the current class (owner class omitted)
invokevirtual ->helperMethod()V;
- The omitted
owner_classalways refers to the class currently being compiled. - Omitting owner_class is only allowed when referencing members defined in the current class.
- When referencing external classes, the full qualified
owner_classmust be provided to avoid ambiguity. - This design balances explicitness and brevity, helping you write cleaner JAL code.
JAL supports naming local variables, not just numeric slots, improving readability:
istore 0 [->example]
iload example
Here, slot 0 is named example, making code easier to follow.
All local variables can be named but it is not mandatory. You can still use numeric slots directly if preferred.
JAL compiler automatically generates StackMapFrames required by JVM verification, eliminating the tedious manual management of stack frames.
Structured try-catch-finally exception handling declarations via labels make writing exception handling straightforward and readable.
- Declare a class or interface with optional versioning and inheritance metadata.
- Define fields and methods with access modifiers.
- Write method bodies as sequences of instructions with optional labels.
- Use JVM standard type descriptors for fields, method arguments, and return types.
- Use labels to structure control flow and exception handling.
- Reference JVM classes, methods, and fields using explicit owner/member/type syntax.
- Leverage named locals for clearer code.
- Use exception handler blocks via label directives.
- Let the compiler handle low-level JVM StackMapFrames automatically.
public class FizzBuzz (
major_version=55,
minor_version=0) {
public static main([Ljava/lang/String;)V {
// int i = 1;
iconst_1
istore_1 // Store the value of i in local variable 1
LoopStart:
// if (i >= 101) goto LoopEnd;
iload_1
bipush 101
if_icmpge LoopEnd
// if (i % 15 = 0)
iload_1
bipush 15
irem
ifne NotFizzBuzz
// System.out.println("FizzBuzz");
getstatic java/lang/System->out:Ljava/io/PrintStream;
ldc "FizzBuzz"
invokevirtual java/io/PrintStream->println(Ljava/lang/String;)V
goto LoopIncrement
NotFizzBuzz:
// else if (i % 3 == 0)
iload_1
iconst_3
irem
ifne NotFizz
// System.out.println("Fizz");
getstatic java/lang/System->out:Ljava/io/PrintStream;
ldc "Fizz"
invokevirtual java/io/PrintStream->println(Ljava/lang/String;)V
goto LoopIncrement
NotFizz:
// else if (i % 5 == 0)
iload_1
iconst_5
irem
ifne PrintNumber
// System.out.println("Buzz");
getstatic java/lang/System->out:Ljava/io/PrintStream;
ldc "Buzz"
invokevirtual java/io/PrintStream->println(Ljava/lang/String;)V
goto LoopIncrement
PrintNumber:
getstatic java/lang/System->out:Ljava/io/PrintStream;
iload_1
invokevirtual java/io/PrintStream->println(I)V
LoopIncrement:
// i++
iinc
goto LoopStart
LoopEnd:
// return;
return
}
}
You can find more examples in the JAL example files directory.
JAL brings JVM bytecode development into a clearer, more maintainable syntax that bridges assembly-level control with user-friendly features like named locals and structured exception directives.
This documentation covers core syntax and concepts to get started writing JAL code for JVM-level programming and experimentation.
Happy bytecoding!