Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions _clojure_jvm/01_jvm.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ Each release of the Java platform has a corresponding JDK for development.

## Java Virtual Machine

The JVM is a virtual machine which defines its own instruction set, referred to a Java bytecode. The process of locating, loading, verifying and executing this bytecode is
define by the [JVM specification](https://docs.oracle.com/javase/specs/jvms/se20/html/index.html). After installing a Java distribution, the JVM can be invoked via the `java`
The JVM is a virtual machine which defines its own instruction set, referred to as Java bytecode. The process of locating, loading, verifying and executing this bytecode is
defined by the [JVM specification](https://docs.oracle.com/javase/specs/jvms/se20/html/index.html). After installing a Java distribution, the JVM can be invoked via the `java`
command.

## Java Development Kit
Expand Down
12 changes: 6 additions & 6 deletions _clojure_jvm/02_basic_java.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ This outputs a `Hello.class` file in the `./test` directory. The `main` method c

## Entry point

Java program execution begins from a named class specified to the java runtime. In this previous example this was the class `test.Hello`.
Java program execution begins from a named class specified to the Java runtime. In the previous example this was the class `test.Hello`.
The JVM loads this class and executes its `main` method, which must have the signature `public static void main(String[])` i.e. a static
method called `main` which takes a single string array parameter. This array receives all the argument provided to the `java` command which
method called `main` which takes a single String array parameter. This array receives all the arguments provided to the `java` command which
do not configure the execution of the JVM itself.

## Loading classes
Expand Down Expand Up @@ -72,12 +72,12 @@ change back to the parent directory where the `Hello.java` file is defined
### System classes

The `test.Hello` class makes reference to another class `java.lang.System` which is defined by the core Java library. Since there's no `java/lang/System.class` file
under the current directory, you might wonder how it is loaded. The answer is that the bootstrap classloader has its own internal mechanism for locating core library classes.
The only requirement for classloaders is that they can resolve and load classes given their full (binary) names. There is no requirement that these exist as `.class` files on
disk. They can be loaded from the network, a database or defined dynamically depending on how the classloader is implemented. The bootstrap classloader knows where to locate
under the current directory, you might wonder how it is loaded. The answer is that the bootstrap class loader has its own internal mechanism for locating core library classes.
The only requirement for class loaders is that they can resolve and load classes given their full (binary) names. There is no requirement that these exist as `.class` files on
disk. They can be loaded from the network, a database or defined dynamically depending on how the class loader is implemented. The bootstrap class loader knows where to locate
core Java classes and loads them as required.

Older JVMs (before version 9) did ship core Java classes in a Java archive. This was usually located at `jre/lib/rt.jar` within the JVM distribution. The bootstrap classloader
Older JVMs (before version 9) did ship core Java classes in a Java archive. This was usually located at `jre/lib/rt.jar` within the JVM distribution. The bootstrap class loader
was additionally configured with a 'bootstrap classpath' containing this core archive. Since the advent of Java modules in Java 9, core classes are distributed in a more efficient
format.

Expand Down
38 changes: 19 additions & 19 deletions _clojure_jvm/03_class_files.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ They contain a sequence of sections

1. [Magic number](#magic-number)
2. [Version number](#version-number)
3. [Constant pool](#constant-pool)
4. [Class properties](#class-properties)
3. [Class properties](#class-properties)
4. [Constant pool](#constant-pool)
5. Interfaces
6. Fields
7. [Methods](#methods)
Expand Down Expand Up @@ -68,8 +68,8 @@ which means it is only supported by versions 14 or higher of the JVM. Attempting

## Class properties

The `flags`, `this_class` and `super_class` entries define the access properties and names of the defined class and its direct superclass. The `Hello` does not explicitly
declare a superclass, so it is implicitly `java.lang.Object`.
The `flags`, `this_class` and `super_class` entries define the access properties and names of the defined class and its direct superclass. The `test.Hello` class does not explicitly
declare a superclass, so it is implicitly a subclass of `java.lang.Object`.

## Constant pool

Expand All @@ -88,12 +88,12 @@ Within class files, descriptors are used to define the types of fields and metho
#### Field descriptors

JVM types are either one of the primitive types, an object type or an array type. The grammar for
fields descriptors denote one of these three possibilities.
field descriptors denotes one of these three possibilities.

The primitive types are `byte`, `char`, `double`, `float`, `int`, `long`, `short` and `boolean` and these are denoted as `B`, `C`, `D`, `F`, `I`, `J`, `S` and `Z` respectively within
The primitive types are `byte`, `char`, `double`, `float`, `int`, `long`, `short` and `boolean`, denoted as `B`, `C`, `D`, `F`, `I`, `J`, `S` and `Z` respectively within
the field descriptor grammar. For example, a descriptor of `J` indicates a field of the primitive `long` type.

Object types are defined with the literal `L` followed by the binary name of the class type followed by the literal ';'. For example a field of type `java.lang.Thead` has a descriptor of `Ljava/lang/Thread;`.
Object types are defined with the literal `L` followed by the binary name of the class type followed by the literal `;`. For example a field of type `java.lang.Thead` has a descriptor of `Ljava/lang/Thread;`.

Array types are defined with the literal `[` followed by the element type. So an array of `java.lang.Thread` references has a descriptor of `[Ljava/lang/Thread;` and an array of primitive `int` values
has a descriptor of `[I`.
Expand All @@ -103,7 +103,7 @@ has a descriptor of `[I`.
Methods take a (possibly empty) collection of arguments and optionally return a value. Methods which do not return a value are given a return type of `void` (denoted by `V`) within method descriptors.
Methods which return a value use the grammar for field descriptors to denote the return type.

Method descriptors consist of a literal `(`, the corresponding field descriptor for each parameter type in sequence, a literal `)` followed by the return type descriptor. This can be either `V` for `void` methods,
Method descriptors consist of a literal `(`, the corresponding field descriptor for each parameter type in sequence, a literal `)` followed by the return type descriptor. This can be either `V` for `void` methods
or a field descriptor for the return type.

For example the method `public String test(int i, boolean b, Object o)` has a method descriptor of `(IZLjava/lang/Object;)Ljava/lang/String;`.
Expand All @@ -119,7 +119,7 @@ Here are the references made by the `test.Hello` class:
| #8 | `java/lang/System` | Class | Class which defines the static `out` field |
| #7 | `java/lang/System::out` | Field | Reference to the `out` field of the `java.lang.System` class |
| #12 | `Ljava/io/PrintStream;` | Type reference | The declared type of the `System.out` field |
| #13 | | String | The string constant "Hello world!" |
| #13 | | String | The String constant "Hello world!" |
| #16 | `java/io/PrintStream` | Class | Type defining the `println` method |
| #15 | `java/io/PrintStream::println` | Method | The `println` method used to write to the console |
| #21 | `test/Hello` | Class | The class defined by this class file. The `this_class` property contains this index into the constant pool |
Expand All @@ -131,7 +131,7 @@ Entries in the method table define the name, attributes (access modifiers etc.)

### Instruction format

JVM instructions are variable-length and consist of an `opcode` which defines the operation, and a (possibly empty) sequence of operands. `javap` displays
JVM instructions are variable-length and consist of an `opcode`, which defines the operation, and a (possibly empty) sequence of operands. `javap` displays
each instruction in the following format:

<index> <opcode> [ <operand1>, ..., <operandN> ] [ <comment> ]
Expand All @@ -150,9 +150,9 @@ store values from the top of the stack into local variables, and some consume mu

#### Arguments

In order to invoke a method, its arguments are pushed in order onto the operand stack, and the method is invoked via a method reference in the class constant pool.
In order to invoke a method, its arguments are pushed in order onto the operand stack and the method is invoked via a method reference in the class constant pool.

Instance methods are invoked via the `invokevirtual` instruction, and have a first argument which is a reference to the object the method is being invoked on (the receiver).
Instance methods are invoked via the `invokevirtual` instruction and have a first argument which is a reference to the object the method is being invoked on (the receiver).
Static methods are invoked with `invokestatic` and only the explicit arguments are pushed prior to invocation.

Within a method, the arguments are loaded onto the operand stack with a family of opcode instructions (`aload`, `iload` etc.).
Expand All @@ -176,9 +176,9 @@ public test.Hello();
line 3: 0
```

The constructor declares no format parameters, and returns `void` as shown by the descriptor. It does require a single parameter however - the
The constructor declares no formal parameters and returns `void` as shown by the descriptor. It does require a single parameter however - the
reference to the new object being initialised. This is loaded onto the operand stack with the [aload_0](https://docs.oracle.com/javase/specs/jvms/se20/html/jvms-6.html#jvms-6.5.aload_n)
instruction. The `java.lang.Object` constructor is then invoked in the same way, passing the reference just loaded as the first argument. The [invokespecial](https://docs.oracle.com/javase/specs/jvms/se20/html/jvms-6.html#jvms-6.5.invokespecial)
instruction. The `java.lang.Object` constructor is then invoked in the same way, passing the reference just loaded as the first argument. The [invokespecial](https://docs.oracle.com/javase/specs/jvms/se20/html/jvms-6.html#jvms-6.5.invokespecial) instruction
is similar to `invokevirtual` and `invokestatic` but is required to invoke constructors and superclass methods. The operand to the `invokespecial` instruction is an index into the constant pool
of the `test.Hello` class. The element at index `#1` is a method reference to the `java/lang/Object.<init>` method as indicated by the comment.

Expand All @@ -199,14 +199,14 @@ public static void main(java.lang.String[]);
line 6: 8
```

As indicated by the descriptor, The `main` method defines a single `String[]` parameter and has a return type of `void`.
As indicated by the descriptor, the `main` method defines a single `String[]` parameter and has a return type of `void`.
The flags also indicate the method is `static` and `public`.

The [getstatic](https://docs.oracle.com/javase/specs/jvms/se20/html/jvms-6.html#jvms-6.5.getstatic) instruction, loads a field reference onto the operand stack. The operand of `#7` is the index of the reference to the
The [getstatic](https://docs.oracle.com/javase/specs/jvms/se20/html/jvms-6.html#jvms-6.5.getstatic) instruction loads a field reference onto the operand stack. The operand of `#7` is the index of the reference to the
`System.out` field within the constant pool of the `test.Hello` class.

The literal string "Hello world!" is pushed onto the operand stack with the [ldc](https://docs.oracle.com/javase/specs/jvms/se20/html/jvms-6.html#jvms-6.5.ldc) instruction. The operand of
`#13` is the index of the string within the class constant pool.
The String "Hello world!" is pushed onto the operand stack with the [ldc](https://docs.oracle.com/javase/specs/jvms/se20/html/jvms-6.html#jvms-6.5.ldc) instruction. The operand of
`#13` is the index of the String within the class constant pool.

At this point the operand stack contains the arguments to the `java.io.PrintStream.<println>` method - the receiver (the contents of the `System.out` field), and the string to write. The
At this point the operand stack contains the arguments to the `java.io.PrintStream.<println>` method - the receiver (the contents of the `System.out` field), and the String to write. The
method is invoked with [invokevirtual](https://docs.oracle.com/javase/specs/jvms/se20/html/jvms-6.html#jvms-6.5.invokevirtual) using the method reference in the class constant pool.
10 changes: 5 additions & 5 deletions _clojure_jvm/04_jar_files.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: JAR Files
---

So far we've seen how Java source files are compiled into binary class files, and how these are located at runtime when the containing directory is placed on the classpath.
This approach works for the single file application developed previously, but most applications consist of many classes, and make use of libraries which themselves define classes
This approach works for the single file application developed previously, but most applications consist of many classes and make use of libraries which themselves define classes
and interfaces of their own. Managing and publishing directories of class files would be cumbersome, but fortunately Java defines a standard for packaging related classes into a single
file called a Java ARchive, or JAR file.

Expand All @@ -30,7 +30,7 @@ __src/libhello/MessageSink.java__
{% include code/jar/src/libhello/MessageSink.java %}
```

In addition, we define a source of messages read from the command-line, and a sink which writes messages a `PrintStream`:
In addition, we define a source of messages read from the command-line, and a sink which writes messages to a `PrintStream`:

__src/libhello/CommandLineMessageSource.java__
```java
Expand Down Expand Up @@ -59,7 +59,7 @@ this creates a `libhello.jar` file in the current directory. We can list the con
jar --list --file libhello.jar

This shows the archive contains the `.class` files as their expected locations on the classpath, along with a `META-INF/MANIFEST.MF` file.
This file is called the `_manifest` file and is described [below](#manifest-files).
This file is called the _manifest_ file and is described [below](#manifest-files).

```
{% include code/jar/jar_list %}
Expand Down Expand Up @@ -103,7 +103,7 @@ which we can then execute by placing both the lib and app JARs on the classpath:
## Manifest files

When listing the contents of the JAR file above, we saw a `META-INF/MANIFEST.MF` file included. The `META-INF` directory within a JAR contains
files used to configure aspects of the JVM. The `MANIFEST.MF` file contain various sections of key-value pairs used to describe the contents of the JAR.
files used to configure aspects of the JVM. The `MANIFEST.MF` file contains various sections of key-value pairs used to describe the contents of the JAR.
The format of the `META-INF` directory and `MANIFEST.MF` files are described in detail within the [JAR file specification](https://docs.oracle.com/en/java/javase/20/docs/specs/jar/jar.html).

The `jar` tool can be used to extract the contents of the default manifest file:
Expand Down Expand Up @@ -168,7 +168,7 @@ and run it with the `-jar` option as before:
### File collisions

When building the uberjar above, we simply overwrote (using the `-o` option for `unzip`) any existing files within `libhello.jar`
when extracting the `echo.jar` file. This file for our simple application since there are no collisions, except for the default manifest
when extracting the `echo.jar` file. This is fine for our simple application since there are no collisions, except for the default manifest
files in the two files, which should be the same. However, this simple strategy may not work for more complicated applications. It's possible
that different JAR files will contain different files at the same path which need special handling to produce the corresponding file in the
output JAR. One example is libraries which configure [ServiceLoader](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html)
Expand Down
Loading