Let's give meaning to it all.
Christian Gram Kalhauge
What is the semantics of a program?
Name some ways can you describe the semantics of a program?
What does it mean to interpret a piece of code?
Gentzen-style proofs
It's Meaning
Meaning by specification

The flowchart from the original paper on semantics Assigning Meaning to Programs
by Robert W. Floyd. The program computes the sum of an array.
Hoare Triplet
Example: Composition
Meaning by mapping
x + 5Meaning by execution
But there is more...
A Transition system is a triplet where is the set of program states, is the transition relation (defined by the single step semantics) and are possible initial states.
$ javap -cp target/classes -c jpamb.cases.Simplejq '.methods[] | select(.name=="assertFalse") | .code.bytecode' \
target/decompiled/jpamb/cases/Simple.json[
{ "opr": "get", "field": { "class": "jpamb/cases/Simple", "name": "$assertionsDisabled", "type": "boolean" }, "static": true },
{ "opr": "ifz", "condition": "ne", "target": 6 },
{ "opr": "new", "class": "java/lang/AssertionError" },
{ "opr": "dup", "words": 1 },
{ "opr": "invoke", "access": "special", "method": { "args": [], "is_interface": false, "name": "<init>", "ref": { "kind": "class", "name": "java/lang/AssertionError" }, "returns": null }, },
{ "opr": "throw" },
{ "opr": "return", "type": null }
]| in# | opr | stack | description |
|---|---|---|---|
00 | get | [] | Get the assertionsDisabled boolean and put it on the stack |
01 | ifz | [bool] | if it is not equal to zero (false) jump to the 6th instruction (i.e. return) |
02 | new | [] | otherwise create a new AssertionError object. |
03 | dup | [ref] | dublicate the reference |
04 | invoke | [ref, ref] | call the init method on the AssertionErrror (consuming the top ref erence). |
05 | throw | [ref] | throw the assertion error. |
06 | return | [] | otherwise return. |
$ uv run jpamb inspect "jpamb.cases.Simple.assertBoolean:(Z)V"--format=...
Look at the solutions/syntactic/src/syntactic_bytecode.py
Follow along in solutions/dynamic and src/jvm/state.py
def step(bc: Bytecode, s: State) -> State | str:
...>>> pc = PC(method, offset)
>>> pc += n # add n to the offset
>>> pc %= n # replace the offest with n>>> suite, eff = jpamb.setup()
>>> bc = jpamb.Bytecode(suite, eff, {})
>>> bc[pc]class OperandStack:
operands: deque[StackValue]class Locals:
locals: list[StackValue | None]class Frame:
locals: Locals
stack: OperandStack
pc: PCdef step(bc: jpamb.Bytecode, state: State) -> tuple[PC, State | str]:
frame = state.frames.peek()
opr = bc[frame.pc]
pc, output = frame.pc, state # Default to outputting the state
print(f"Stepping {pc}:\n > {opr}", file=sys.stderr)
match opr:
# The opcodes to handle ...
return pc, outputcase jvm.Push(type=t, value=v):
if t is not jvm.Int():
raise NotImplementedError(f"Don't know how to handle {t}")
frame.stack.push(StackInt(v))
frame.pc += 1case jvm.Load(type=jvm.Int(), index=n):
v = frame.locals[n]
frame.stack.push(v)
frame.pc += 1class State:
heap: Heap
frames: CallStackor
In Python
case jvm.Return(type=jvm.Int()):
v1 = frame.stack.pop()
state.frames.pop()
if state.frames:
frame = state.frames.peek()
frame.stack.push(v1)
frame.pc += 1
else:
output = "ok"In Python
case jvm.Binary(type=jvm.Int(), operant=op):
v2, v1 = frame.stack.pop(), frame.stack.pop()
assert isinstance(v1, jvmc.StackInt), f"expected int, but got {v1}"
assert isinstance(v2, jvmc.StackInt), f"expected int, but got {v2}"
value: int | str = binary(op, v1.value, v2.value)
if isinstance(value, str):
output = value
else:
frame.stack.push(jvmc.StackInt(value))
frame.pc += 1In Python
def binary(op, v1: int, v2: int) -> int | str:
match op:
case jvm.BinaryOpr.Div:
try:
return v1 // v2
except ZeroDivisionError:
return "divide by zero"
case a:
raise NotImplementedError(f"Unhandled binary {op!r}")It's now up to you!
jvm2json/CODEC.txt at kalhauge/jvm2json: the decompiled codec (search for <ByteCodeInst>).
Chapter 4. The class File Format: the class file format. And, finally
Chapter 6. The Java Virtual Machine Instruction Set: the official specification of each instruction.
Write an interpreter
$ jpamb -vv interpret --filter Simple --step-wise dynamic-interpreterStart small, one method at a time. You don't have to cover the entire language.
It's okay to hack some things, like getting
the $assertionsDisabled static field. You can assume that is always be false.
Print out the state to stderr at every step, this will help you debug (already done in the example)
Use the --step-wise flag to run the last failed case next time.
What is the semantics of a program?
Name some ways can you describe the semantics of a program?
What does it mean to interpret a piece of code?