Skip to content

Preparting a Class for Execution

Andrew Binstock edited this page Nov 20, 2024 · 1 revision

Per the JVM spec, after a class is parsed and loaded into the method area, it must go through a multi-step process before being ready for use. These are:

  1. Format checking (section 4.8), which includes checking that:
  • First four bytes contain the magic number

  • All predefined attributes (except of a specific few) are of the proper length

  • The class is not truncated, nor does it have extra bytes at the end

  • Constant pool entries satisfy the documented constraints

  • Field and method references in the constant pool have valid names, types,and descriptors

    --As of Jacobin v. 0.6.0, we do all these things (and have for a while).

  1. Link-time Verification of class files (section 4.10)
  • Check bytecodes are correct and have correct arguments (section 4.10.2.2)

  • No operand stack overflows or underflows

  • Making sure final classes are not subclasssed

  • Making sure final methods are not overridden

  • Checking that every class has a superclass

  • This is done using "verification by type checking"

    -- As of Jacobin v. 0.6.0, we do some of these things, but not before hand. This results in a major performance penalty in the interpreter as values are checked repeatedly inside bytecodes (especially in loops)

  1. Preparation (section 5.4.2)
  • Creating the static fields for a class and initializing them to their default values
  1. Resolution (section 5.4.3)
  • Resolution of symbolic references in the constant pool (CP). This saves these bytecodes from needing to look them up every time: anewarray, checkcast, getfield, getstatic, instanceof, invokedynamic, invokeinterface, invokespecial, invokestatic, invokevirtual, ldc, ldc_w, ldc2_w, multianewarray, new, putfield, and putstatic
  • Validation that the preceding instructions operate on the correct fields. For example that getfield does not try to access a static field.
  • Access control is also verified in this step
  1. Initialization (section 5.5)
  • Calling the method, if any,
  • Instantiating an going through steps 1-5 here for any superclasses.

The steps prior to initialization are collectively called linking a class (or interface).


Steps 3-5 are very partially implemented in Jacobin as of v. 0.6.200 and frequently performed as needed during bytecode execution in the interpreter.

The interpreter in the Jacobin JVM has advanced sufficiently that it makes sense to start opening tasks to expand the linking and initialization of a class. Currently, tasks JACOBIN-616 through JACOBIN-618 address the need to work on these matters.