Skip to content

Instantly share code, notes, and snippets.

@RevolvingMadness
Created December 26, 2025 02:41
Show Gist options
  • Select an option

  • Save RevolvingMadness/9129719a54f0b0ccbcc4fb206816fd44 to your computer and use it in GitHub Desktop.

Select an option

Save RevolvingMadness/9129719a54f0b0ccbcc4fb206816fd44 to your computer and use it in GitHub Desktop.
The code for my JVM interpreter in Minecraft
// SCORE: bc
let classfile_raw: value = storage bc:parser/classfile raw
let classfile_index: value = score index bc
let tag_utf8: value = 1
let tag_integer: value = 3
let tag_float: value = 4
let tag_long: value = 5
let tag_double: value = 6
let tag_class: value = 7
let tag_string: value = 8
let tag_fieldref: value = 9
let tag_methodref: value = 10
let tag_interface_methodref: value = 11
let tag_name_and_type: value = 12
let tag_method_handle: value = 15
let tag_method_type: value = 16
let tag_invoke_dynamic: value = 18
// SCORE: parser_parse_u1
let parse_u1_output: value = score output parser_parse_u1
mcfunction bc:parser/parse_u1 {
if !classfile_raw[classfile_index] {
return 1
}
parse_u1_output = classfile_raw[classfile_index]
classfile_index += 1
}
// SCORE: parser_parse_u2
let parser_parse_u2_output: value = score output parser_parse_u2
mcfunction bc:parser/parse_u2 {
if !classfile_raw[classfile_index] {
return 1
}
let copied: data = classfile_raw
let first: score = (copied[classfile_index]) * 256
classfile_index += 1
if !copied[classfile_index] {
return 1
}
first += copied[classfile_index]
classfile_index += 1
parser_parse_u2_output = first
}
// SCORE: parser_parse_u4_part
let parse_u4_part_output: value = score output parser_parse_u4_part
mcfunction bc:parser/parse_u4_part {
if !classfile_raw[classfile_index] {
return 1
}
let copied: data = classfile_raw
let first: score = (copied[classfile_index]) * 256
classfile_index += 1
if !copied[classfile_index] {
return 1
}
first += copied[classfile_index]
classfile_index += 1
parse_u4_part_output = first
}
let parser_parse_bytes_length: value = storage bc:parser/parse_bytes length
let parser_parse_bytes_output: value = storage bc:parser/parse_bytes output
mcfunction bc:parser/parse_bytes {
parser_parse_bytes_output = []
if !classfile_raw[classfile_index] {
return 1
}
let offset: score = 0
while offset < parser_parse_bytes_length {
let byte: value = classfile_raw[classfile_index]
append parser_parse_bytes_output byte
offset += 1
classfile_index += 1
}
}
let constant_pool_raw: value = storage bc:parser/classfile classfile.constant_pool_raw
mcfunction bc:parser/constant_pool/parse {
function bc:parser/parse_u2
let constant_pool_entries: score = parser_parse_u2_output
constant_pool_raw = [{}]
let index: score = 1
while index < constant_pool_entries {
function bc:parser/parse_u1
let tag: score = parse_u1_output
let entry: data = {tag: tag}
let parsed_slots: score = 1
if tag == tag_utf8 {
function bc:parser/parse_u2
parser_parse_bytes_length = parser_parse_u2_output
function bc:parser/parse_bytes
entry.value = parser_parse_bytes_output
} else if tag == tag_class {
function bc:parser/parse_u2
entry.name_index = parser_parse_u2_output
} else if tag == tag_string {
function bc:parser/parse_u2
entry.string_index = parser_parse_u2_output
} else if tag == tag_fieldref || tag == tag_methodref || tag == tag_interface_methodref {
function bc:parser/parse_u2
entry.class_index = parser_parse_u2_output
function bc:parser/parse_u2
entry.name_and_type_index = parser_parse_u2_output
} else if tag == tag_name_and_type {
function bc:parser/parse_u2
entry.name_index = parser_parse_u2_output
function bc:parser/parse_u2
entry.descriptor_index = parser_parse_u2_output
} else {
tellraw @a {text: "Failed to parse CP entry", color: "red"}
index = constant_pool_entries
}
append constant_pool_raw entry
index += parsed_slots
}
}
// SCORE: byte_to_string
let byte_to_string_byte: value = score byte byte_to_string
let byte_to_string_output: value = storage bc:parser/byte_to_string output
mcfunction bc:parser/byte_to_string {
if (byte_to_string_byte >= 32 && byte_to_string_byte <= 44) {
function bc:parser/byte_to_string/part_0
} else if (byte_to_string_byte >= 45 && byte_to_string_byte <= 57) {
function bc:parser/byte_to_string/part_1
} else if (byte_to_string_byte >= 58 && byte_to_string_byte <= 70) {
function bc:parser/byte_to_string/part_2
} else if (byte_to_string_byte >= 71 && byte_to_string_byte <= 83) {
function bc:parser/byte_to_string/part_3
} else if (byte_to_string_byte >= 84 && byte_to_string_byte <= 96) {
function bc:parser/byte_to_string/part_4
} else if (byte_to_string_byte >= 97 && byte_to_string_byte <= 109) {
function bc:parser/byte_to_string/part_5
} else if (byte_to_string_byte >= 110 && byte_to_string_byte <= 122) {
function bc:parser/byte_to_string/part_6
} else if (byte_to_string_byte >= 123 && byte_to_string_byte <= 126) {
function bc:parser/byte_to_string/part_7
}
}
mcfunction bc:parser/byte_to_string/part_0 {
if (byte_to_string_byte == 32) {
byte_to_string_output = " "
} else if (byte_to_string_byte == 33) {
byte_to_string_output = "!"
} else if (byte_to_string_byte == 34) {
byte_to_string_output = "\""
} else if (byte_to_string_byte == 35) {
byte_to_string_output = "#"
} else if (byte_to_string_byte == 36) {
byte_to_string_output = "$"
} else if (byte_to_string_byte == 37) {
byte_to_string_output = "%"
} else if (byte_to_string_byte == 38) {
byte_to_string_output = "&"
} else if (byte_to_string_byte == 39) {
byte_to_string_output = "'"
} else if (byte_to_string_byte == 40) {
byte_to_string_output = "("
} else if (byte_to_string_byte == 41) {
byte_to_string_output = ")"
} else if (byte_to_string_byte == 42) {
byte_to_string_output = "*"
} else if (byte_to_string_byte == 43) {
byte_to_string_output = "+"
} else if (byte_to_string_byte == 44) {
byte_to_string_output = ","
}
}
mcfunction bc:parser/byte_to_string/part_1 {
if (byte_to_string_byte == 45) {
byte_to_string_output = "-"
} else if (byte_to_string_byte == 46) {
byte_to_string_output = "."
} else if (byte_to_string_byte == 47) {
byte_to_string_output = "/"
} else if (byte_to_string_byte == 48) {
byte_to_string_output = "0"
} else if (byte_to_string_byte == 49) {
byte_to_string_output = "1"
} else if (byte_to_string_byte == 50) {
byte_to_string_output = "2"
} else if (byte_to_string_byte == 51) {
byte_to_string_output = "3"
} else if (byte_to_string_byte == 52) {
byte_to_string_output = "4"
} else if (byte_to_string_byte == 53) {
byte_to_string_output = "5"
} else if (byte_to_string_byte == 54) {
byte_to_string_output = "6"
} else if (byte_to_string_byte == 55) {
byte_to_string_output = "7"
} else if (byte_to_string_byte == 56) {
byte_to_string_output = "8"
} else if (byte_to_string_byte == 57) {
byte_to_string_output = "9"
}
}
mcfunction bc:parser/byte_to_string/part_2 {
if (byte_to_string_byte == 58) {
byte_to_string_output = ":"
} else if (byte_to_string_byte == 59) {
byte_to_string_output = ";"
} else if (byte_to_string_byte == 60) {
byte_to_string_output = "<"
} else if (byte_to_string_byte == 61) {
byte_to_string_output = "="
} else if (byte_to_string_byte == 62) {
byte_to_string_output = ">"
} else if (byte_to_string_byte == 63) {
byte_to_string_output = "?"
} else if (byte_to_string_byte == 64) {
byte_to_string_output = "@"
} else if (byte_to_string_byte == 65) {
byte_to_string_output = "A"
} else if (byte_to_string_byte == 66) {
byte_to_string_output = "B"
} else if (byte_to_string_byte == 67) {
byte_to_string_output = "C"
} else if (byte_to_string_byte == 68) {
byte_to_string_output = "D"
} else if (byte_to_string_byte == 69) {
byte_to_string_output = "E"
} else if (byte_to_string_byte == 70) {
byte_to_string_output = "F"
}
}
mcfunction bc:parser/byte_to_string/part_3 {
if (byte_to_string_byte == 71) {
byte_to_string_output = "G"
} else if (byte_to_string_byte == 72) {
byte_to_string_output = "H"
} else if (byte_to_string_byte == 73) {
byte_to_string_output = "I"
} else if (byte_to_string_byte == 74) {
byte_to_string_output = "J"
} else if (byte_to_string_byte == 75) {
byte_to_string_output = "K"
} else if (byte_to_string_byte == 76) {
byte_to_string_output = "L"
} else if (byte_to_string_byte == 77) {
byte_to_string_output = "M"
} else if (byte_to_string_byte == 78) {
byte_to_string_output = "N"
} else if (byte_to_string_byte == 79) {
byte_to_string_output = "O"
} else if (byte_to_string_byte == 80) {
byte_to_string_output = "P"
} else if (byte_to_string_byte == 81) {
byte_to_string_output = "Q"
} else if (byte_to_string_byte == 82) {
byte_to_string_output = "R"
} else if (byte_to_string_byte == 83) {
byte_to_string_output = "S"
}
}
mcfunction bc:parser/byte_to_string/part_4 {
if (byte_to_string_byte == 84) {
byte_to_string_output = "T"
} else if (byte_to_string_byte == 85) {
byte_to_string_output = "U"
} else if (byte_to_string_byte == 86) {
byte_to_string_output = "V"
} else if (byte_to_string_byte == 87) {
byte_to_string_output = "W"
} else if (byte_to_string_byte == 88) {
byte_to_string_output = "X"
} else if (byte_to_string_byte == 89) {
byte_to_string_output = "Y"
} else if (byte_to_string_byte == 90) {
byte_to_string_output = "Z"
} else if (byte_to_string_byte == 91) {
byte_to_string_output = "["
} else if (byte_to_string_byte == 92) {
byte_to_string_output = "\\"
} else if (byte_to_string_byte == 93) {
byte_to_string_output = "]"
} else if (byte_to_string_byte == 94) {
byte_to_string_output = "^"
} else if (byte_to_string_byte == 95) {
byte_to_string_output = "_"
} else if (byte_to_string_byte == 96) {
byte_to_string_output = "`"
}
}
mcfunction bc:parser/byte_to_string/part_5 {
if (byte_to_string_byte == 97) {
byte_to_string_output = "a"
} else if (byte_to_string_byte == 98) {
byte_to_string_output = "b"
} else if (byte_to_string_byte == 99) {
byte_to_string_output = "c"
} else if (byte_to_string_byte == 100) {
byte_to_string_output = "d"
} else if (byte_to_string_byte == 101) {
byte_to_string_output = "e"
} else if (byte_to_string_byte == 102) {
byte_to_string_output = "f"
} else if (byte_to_string_byte == 103) {
byte_to_string_output = "g"
} else if (byte_to_string_byte == 104) {
byte_to_string_output = "h"
} else if (byte_to_string_byte == 105) {
byte_to_string_output = "i"
} else if (byte_to_string_byte == 106) {
byte_to_string_output = "j"
} else if (byte_to_string_byte == 107) {
byte_to_string_output = "k"
} else if (byte_to_string_byte == 108) {
byte_to_string_output = "l"
} else if (byte_to_string_byte == 109) {
byte_to_string_output = "m"
}
}
mcfunction bc:parser/byte_to_string/part_6 {
if (byte_to_string_byte == 110) {
byte_to_string_output = "n"
} else if (byte_to_string_byte == 111) {
byte_to_string_output = "o"
} else if (byte_to_string_byte == 112) {
byte_to_string_output = "p"
} else if (byte_to_string_byte == 113) {
byte_to_string_output = "q"
} else if (byte_to_string_byte == 114) {
byte_to_string_output = "r"
} else if (byte_to_string_byte == 115) {
byte_to_string_output = "s"
} else if (byte_to_string_byte == 116) {
byte_to_string_output = "t"
} else if (byte_to_string_byte == 117) {
byte_to_string_output = "u"
} else if (byte_to_string_byte == 118) {
byte_to_string_output = "v"
} else if (byte_to_string_byte == 119) {
byte_to_string_output = "w"
} else if (byte_to_string_byte == 120) {
byte_to_string_output = "x"
} else if (byte_to_string_byte == 121) {
byte_to_string_output = "y"
} else if (byte_to_string_byte == 122) {
byte_to_string_output = "z"
}
}
mcfunction bc:parser/byte_to_string/part_7 {
if (byte_to_string_byte == 123) {
byte_to_string_output = "{"
} else if (byte_to_string_byte == 124) {
byte_to_string_output = "|"
} else if (byte_to_string_byte == 125) {
byte_to_string_output = "}"
} else if (byte_to_string_byte == 126) {
byte_to_string_output = "~"
}
}
let bytes_to_string_bytes: value = storage bc:parser/bytes_to_string bytes
let bytes_to_string_output: value = storage bc:parser/bytes_to_string output
mcfunction bc:parser/bytes_to_string {
bytes_to_string_output = ""
for byte in bytes_to_string_bytes {
byte_to_string_byte = byte
function bc:parser/byte_to_string
bytes_to_string_output = "$(bytes_to_string_output)$(byte_to_string_output)"
}
}
// SCORE: resolve_cp_utf8
let resolve_cp_utf8_index: value = score index resolve_cp_utf8
let resolve_cp_utf8_output: value = storage bc:parser/resolve_cp_utf8 output
mcfunction bc:parser/resolve_cp_utf8 {
resolve_cp_utf8_output = "INVALID_UTF8_INDEX"
let entry: data = constant_pool_raw[resolve_cp_utf8_index]
if entry && entry.tag == tag_utf8 {
bytes_to_string_bytes = entry.value
function bc:parser/bytes_to_string
resolve_cp_utf8_output = bytes_to_string_output
}
}
// SCORE: resolve_class_name
let resolve_class_name_index: value = score index resolve_class_name
let resolve_class_name_output: value = storage bc:parser/resolve_class_name output
mcfunction bc:parser/resolve_class_name {
resolve_class_name_output = "INVALID_CLASS_INDEX"
let entry: data = constant_pool_raw[resolve_class_name_index]
if entry && entry.tag == tag_class {
resolve_cp_utf8_index = entry.name_index
function bc:parser/resolve_cp_utf8
resolve_class_name_output = resolve_cp_utf8_output
}
}
let owner_struct_stack: value = storage bc:parser/parse_attributes owner_struct_stack
let current_owner_struct: value = storage bc:parser/parse_attributes owner_struct_stack[-1]
let attribute_stack: value = storage bc:parser/parse_attributes attribute_stack
let current_attribute: value = storage bc:parser/parse_attributes attribute_stack[-1]
let parse_attributes_is_class_attributes: score = 0
mcfunction bc:parser/parse_attributes {
function bc:parser/parse_u2
let attributes_count: score = parser_parse_u2_output
current_owner_struct.attributes_count = attributes_count
let index: score = 0
while index < attributes_count {
append attribute_stack {}
let attribute: value = current_attribute
function bc:parser/parse_u2
attribute.attribute_name_index = parser_parse_u2_output
resolve_cp_utf8_index = parser_parse_u2_output
function bc:parser/resolve_cp_utf8
attribute.name = resolve_cp_utf8_output
if attribute.name == "INVALID_UTF8_INDEX" {
tellraw @a "invalid"
index = attributes_count
}
function bc:parser/parse_u4_part
attribute.attribute_length.upper = parse_u4_part_output
function bc:parser/parse_u4_part
attribute.attribute_length.lower = parse_u4_part_output
if attribute.name == "Code" {
function bc:parser/parse_u2
attribute.max_stack = parser_parse_u2_output
function bc:parser/parse_u2
attribute.max_locals = parser_parse_u2_output
function bc:parser/parse_u4_part
let code_length_upper: score = parse_u4_part_output
function bc:parser/parse_u4_part
let code_length_lower: score = parse_u4_part_output
parser_parse_bytes_length = code_length_lower
function bc:parser/parse_bytes
attribute.code = parser_parse_bytes_output
function bc:parser/parse_u2
let exception_table_length: score = parser_parse_u2_output
let exception_table: value = attribute.exception_table
exception_table = []
if exception_table_length != 0 {
tellraw @a {text: "TODO", color: "red"}
}
let index: score = 0
while index < exception_table_length {
append exception_table {}
let exception_table_entry: value = exception_table[-1]
function bc:parser/parse_u2
exception_table_entry.start_pc = parser_parse_u2_output
function bc:parser/parse_u2
exception_table_entry.end_pc = parser_parse_u2_output
function bc:parser/parse_u2
exception_table_entry.handler_pc = parser_parse_u2_output
function bc:parser/parse_u2
exception_table_entry.catch_type = parser_parse_u2_output
}
append owner_struct_stack attribute
function bc:parser/parse_attributes
attribute = owner_struct_stack[-1]
remove owner_struct_stack[-1]
} else if attribute.name == "LineNumberTable" {
function bc:parser/parse_u2
let line_number_table_length: score = parser_parse_u2_output
let line_number_table: value = attribute.line_number_table
line_number_table = []
let index: score = 0
while index < line_number_table_length {
append line_number_table {}
let line_number_table_entry: value = line_number_table[-1]
function bc:parser/parse_u2
line_number_table_entry.start_pc = parser_parse_u2_output
function bc:parser/parse_u2
line_number_table_entry.line_number = parser_parse_u2_output
index += 1
}
} else if attribute.name == "SourceFile" && parse_attributes_is_class_attributes {
function bc:parser/parse_u2
attribute.sourcefile_index = parser_parse_u2_output
resolve_cp_utf8_index = parser_parse_u2_output
function bc:parser/resolve_cp_utf8
attribute.sourcefile = resolve_cp_utf8_output
} else {
tellraw @a ["Unknown attribute ", attribute.name]
}
append current_owner_struct.attributes attribute
remove attribute_stack[-1]
index += 1
}
parse_attributes_is_class_attributes = 0
}
mcfunction bc:parser/parse_interfaces {
function bc:parser/parse_u2
let interfaces_count: score = parser_parse_u2_output
storage bc:parser/classfile classfile.interfaces_count = interfaces_count
storage bc:parser/classfile classfile.interfaces_indices = []
let index: score = 0
while index < interfaces_count {
function bc:parser/parse_u2
append storage bc:parser/classfile classfile.interfaces_indices parser_parse_u2_output
index += 1
}
if interfaces_count != 0 {
tellraw @a {text: "TODO interfaces", color: "red"}
}
}
mcfunction bc:parser/parse_fields {
function bc:parser/parse_u2
let fields_count: score = parser_parse_u2_output
storage bc:parser/classfile classfile.fields_count = fields_count
let fields: value = storage bc:parser/classfile classfile.fields
fields = []
let index: score = 0
while index < fields_count {
let field: data = {}
function bc:parser/parse_u2
field.access_flags = parser_parse_u2_output
function bc:parser/parse_u2
field.name_index = parser_parse_u2_output
function bc:parser/parse_u2
field.descriptor_index = parser_parse_u2_output
resolve_cp_utf8_index = field.name_index
function bc:parser/resolve_cp_utf8
field.name = resolve_cp_utf8_output
resolve_cp_utf8_index = field.descriptor_index
function bc:parser/resolve_cp_utf8
field.descriptor = resolve_cp_utf8_output
append owner_struct_stack field
function bc:parser/parse_attributes
field = owner_struct_stack[-1]
remove owner_struct_stack[-1]
append fields field
index += 1
}
}
mcfunction bc:parser/parse_methods {
function bc:parser/parse_u2
let methods_count: score = parser_parse_u2_output
storage bc:parser/classfile classfile.methods_count = methods_count
let methods: value = storage bc:parser/classfile classfile.methods
methods = []
let index: score = 0
while index < methods_count {
let method: data = {}
function bc:parser/parse_u2
method.access_flags = parser_parse_u2_output
function bc:parser/parse_u2
method.name_index = parser_parse_u2_output
function bc:parser/parse_u2
method.descriptor_index = parser_parse_u2_output
resolve_cp_utf8_index = method.name_index
function bc:parser/resolve_cp_utf8
method.name = resolve_cp_utf8_output
resolve_cp_utf8_index = method.descriptor_index
function bc:parser/resolve_cp_utf8
method.descriptor = resolve_cp_utf8_output
append owner_struct_stack method
function bc:parser/parse_attributes
method = owner_struct_stack[-1]
remove owner_struct_stack[-1]
append methods method
index += 1
}
}
let constant_pool: value = storage bc:parser/classfile classfile.constant_pool
mcfunction bc:parser/resolve_constant_pool_for_interpreter {
constant_pool = [{}]
let index: score = 1
let len: score = constant_pool_raw
while index < constant_pool_raw {
let raw_entry: data = constant_pool_raw[index]
if raw_entry {
let tag: value = raw_entry.tag
if tag == tag_utf8 {
append `constant_pool` [tag_utf8, raw_entry.value]
} else if tag == tag_integer {
append `constant_pool` [tag_integer, raw_entry.value]
} else if tag == tag_float {
append `constant_pool` [tag_float, raw_entry.value]
} else if tag == tag_long {
append `constant_pool` [tag_long, raw_entry.value]
} else if tag == tag_double {
append `constant_pool` [tag_double, raw_entry.value]
} else if tag == tag_class {
append `constant_pool` [tag_class, raw_entry.name_index]
} else if tag == tag_string {
append `constant_pool` [tag_string, raw_entry.string_index]
} else if tag == tag_fieldref || tag == tag_methodref || tag == tag_interface_methodref {
append `constant_pool` [tag, raw_entry.class_index, raw_entry.name_and_type_index]
} else if tag == tag_name_and_type {
append `constant_pool` [tag_name_and_type, raw_entry.name_index, raw_entry.descriptor_index]
} else {
append `constant_pool` raw_entry
}
} else {
append constant_pool {}
}
index += 1
}
}
mcfunction bc:parser/parse {
classfile_index = 0
function bc:parser/parse_u4_part
storage bc:parser/classfile classfile.magic.upper = parse_u4_part_output
function bc:parser/parse_u4_part
storage bc:parser/classfile classfile.magic.lower = parse_u4_part_output
if storage bc:parser/classfile classfile.magic.upper != 51966 || storage bc:parser/classfile classfile.magic.lower != 47806 {
tellraw @a {text: "Invalid classfile", color: "red"}
return 1
}
function bc:parser/parse_u2
storage bc:parser/classfile classfile.minor_version = parser_parse_u2_output
function bc:parser/parse_u2
storage bc:parser/classfile classfile.major_version = parser_parse_u2_output
function bc:parser/constant_pool/parse
function bc:parser/parse_u2
storage bc:parser/classfile classfile.access_flags = parser_parse_u2_output
function bc:parser/parse_u2
storage bc:parser/classfile classfile.this_class_index = parser_parse_u2_output
function bc:parser/parse_u2
storage bc:parser/classfile classfile.super_class_index = parser_parse_u2_output
function bc:parser/parse_interfaces
function bc:parser/parse_fields
function bc:parser/parse_methods
append owner_struct_stack storage bc:parser/classfile classfile
parse_attributes_is_class_attributes = 1
function bc:parser/parse_attributes
storage bc:parser/classfile classfile = owner_struct_stack[-1]
remove owner_struct_stack[-1]
resolve_class_name_index = storage bc:parser/classfile classfile.this_class_index
function bc:parser/resolve_class_name
storage bc:parser/classfile classfile.this_class = resolve_class_name_output
if storage bc:parser/classfile classfile.super_class_index != 0 {
resolve_class_name_index = storage bc:parser/classfile classfile.super_class_index
function bc:parser/resolve_class_name
storage bc:parser/classfile classfile.super_class = resolve_class_name_output
} else {
storage bc:parser/classfile classfile.super_class = "java/lang/Object"
}
storage bc:parser/classfile classfile.name = storage bc:parser/classfile classfile.this_class
function bc:parser/resolve_constant_pool_for_interpreter
}
// ----------------------------------------------------------------
let jvm_interpreter: value = storage bc:parser/interpreter interpreter
let stack_frames: value = jvm_interpreter.stack_frames
let frame: value = stack_frames[-1]
let parsed_class_data: value = storage bc:parser/interpreter parsed_class_data
// SCORE: interpreter_parse_u2
let interpreter_parse_u2_output: value = score output interpreter_parse_u2
mcfunction bc:interpreter/parse_u2 {
if !frame.bytecode[frame.pc] {
return 1
}
let copied: data = frame.bytecode
let first: score = (copied[frame.pc]) * 256
frame.pc += 1
if !copied[frame.pc] {
return 1
}
first += copied[frame.pc]
frame.pc += 1
interpreter_parse_u2_output = first
}
// SCORE: interpreter_parse_i2
let interpreter_parse_i2_output: value = score output interpreter_parse_i2
mcfunction bc:interpreter/parse_i2 {
if !frame.bytecode[frame.pc] {
return 1
}
let copied: data = frame.bytecode
let first: score = (copied[frame.pc]) * 256
frame.pc += 1
if !copied[frame.pc] {
return 1
}
first += copied[frame.pc]
frame.pc += 1
if first >= 0x8000 {
first -= 0x10000
}
interpreter_parse_i2_output = first
}
let load_class_data_class_data: value = storage bc:interpreter/load_class_data class_data
mcfunction bc:interpreter/load_class_data {
let class_name: value = load_class_data_class_data.name
tellraw @a ["Loading class data for '", class_name, "'"]
jvm_interpreter.loaded_classes."$(class_name)" = load_class_data_class_data
}
let class_files_to_load: value = storage bc:parser/interpreter class_files_to_load
mcfunction bc:init {
parsed_class_data = {}
stack_frames = []
class_files_to_load = [
["Main", [202, 254, 186, 190, 0, 0, 0, 69, 0, 28, 10, 0, 2, 0, 3, 7, 0, 4, 12, 0, 5, 0, 6, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 9, 0, 8, 0, 9, 7, 0, 10, 12, 0, 11, 0, 12, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 121, 115, 116, 101, 109, 1, 0, 3, 111, 117, 116, 1, 0, 21, 76, 106, 97, 118, 97, 47, 105, 111, 47, 80, 114, 105, 110, 116, 83, 116, 114, 101, 97, 109, 59, 10, 0, 14, 0, 15, 7, 0, 16, 12, 0, 17, 0, 18, 1, 0, 19, 106, 97, 118, 97, 47, 105, 111, 47, 80, 114, 105, 110, 116, 83, 116, 114, 101, 97, 109, 1, 0, 7, 112, 114, 105, 110, 116, 108, 110, 1, 0, 4, 40, 73, 41, 86, 7, 0, 20, 1, 0, 4, 77, 97, 105, 110, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 4, 109, 97, 105, 110, 1, 0, 22, 40, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86, 1, 0, 13, 83, 116, 97, 99, 107, 77, 97, 112, 84, 97, 98, 108, 101, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 9, 77, 97, 105, 110, 46, 106, 97, 118, 97, 0, 33, 0, 19, 0, 2, 0, 0, 0, 0, 0, 2, 0, 1, 0, 5, 0, 6, 0, 1, 0, 21, 0, 0, 0, 29, 0, 1, 0, 1, 0, 0, 0, 5, 42, 183, 0, 1, 177, 0, 0, 0, 1, 0, 22, 0, 0, 0, 6, 0, 1, 0, 0, 0, 1, 0, 9, 0, 23, 0, 24, 0, 1, 0, 21, 0, 0, 0, 105, 0, 2, 0, 4, 0, 0, 0, 36, 8, 60, 4, 61, 5, 62, 29, 27, 163, 0, 20, 178, 0, 7, 28, 182, 0, 13, 28, 29, 104, 61, 132, 3, 1, 167, 255, 237, 178, 0, 7, 28, 182, 0, 13, 177, 0, 0, 0, 2, 0, 22, 0, 0, 0, 34, 0, 8, 0, 0, 0, 3, 0, 2, 0, 5, 0, 4, 0, 7, 0, 11, 0, 8, 0, 18, 0, 10, 0, 22, 0, 7, 0, 28, 0, 13, 0, 35, 0, 14, 0, 25, 0, 0, 0, 11, 0, 2, 254, 0, 6, 1, 1, 1, 250, 0, 21, 0, 1, 0, 26, 0, 0, 0, 2, 0, 27]]
]
}
let run_method_by_name_class_name: value = storage bc:interpreter/run_method_by_name class_name
let run_method_by_name_method_name: value = storage bc:interpreter/run_method_by_name method_name
let run_method_by_name_descriptor: value = storage bc:interpreter/run_method_by_name descriptor
let run_method_by_name_args: value = storage bc:interpreter/run_method_by_name args
let new_stack_frame_method_info: value = storage bc:interpreter/new_stack_frame method_info
let new_stack_frame_args: value = storage bc:interpreter/new_stack_frame args
let new_stack_frame_class_file_data: value = storage bc:interpreter/new_stack_frame class_file_data
mcfunction bc:interpreter/new_stack_frame {
tellraw @a "Creating a new stack frame"
append stack_frames {}
let stack_frame: value = stack_frames[-1]
stack_frame.method_info = new_stack_frame_method_info
let code_attribute: data = {}
reverse_for attribute in new_stack_frame_method_info.attributes {
if attribute.name == "Code" {
code_attribute = attribute
}
}
if code_attribute == {} {
tellraw @a "No code attribute"
return fail
}
stack_frame.max_locals = code_attribute.max_locals
stack_frame.max_stack = code_attribute.max_stack
stack_frame.locals = []
let index: score = 0
while index < stack_frame.max_locals {
append stack_frame.locals {}
index += 1
}
stack_frame.operand_stack = []
stack_frame.bytecode = code_attribute.code
stack_frame.pc = 0
stack_frame.class_file_data = new_stack_frame_class_file_data
let is_static: score = new_stack_frame_method_info.access_flags & 0x0008
let current_local_index: score = 0
let args_for_params: data = {}
if is_static == 0 {
if new_stack_frame_args {
let args_copy: data = new_stack_frame_args
stack_frame.locals[current_local_index] = args_copy[0]
remove args_copy[0]
current_local_index += 1
args_for_params = args_copy
} else {
args_for_params = []
}
} else {
args_for_params = new_stack_frame_args
}
for argument in args_for_params {
stack_frame.locals[current_local_index] = argument
current_local_index += 1
}
}
let current_class_data: value = stack_frames[-1].class_file_data
// SCORE get_cp_entry
let get_cp_entry_index: score = score index get_cp_entry
let get_cp_entry_class_data: data = storage bc:interpreter/get_cp_entry class_data
let get_cp_entry_output: data = storage bc:interpreter/get_cp_entry output
mcfunction bc:interpreter/get_cp_entry {
if get_cp_entry_class_data == {} {
get_cp_entry_class_data = current_class_data
}
get_cp_entry_output = get_cp_entry_class_data.constant_pool[get_cp_entry_index]
get_cp_entry_class_data = {}
}
let get_utf8_from_cp_index: score = score index get_utf8_from_cp
let get_utf8_from_cp_class_data: data = storage bc:interpreter/get_utf8_from_cp class_data
let get_utf8_from_cp_output: data = storage bc:interpreter/get_utf8_from_cp output
mcfunction bc:interpreter/get_utf8_from_cp {
get_cp_entry_index = get_utf8_from_cp_index
get_cp_entry_class_data = get_utf8_from_cp_class_data
function bc:interpreter/get_cp_entry
let tag: score = get_cp_entry_output[0]
let value: data = get_cp_entry_output[1]
if tag != tag_utf8 {
tellraw @a {text: "Expected utf8", color: "red"}
}
bytes_to_string_bytes = value
function bc:parser/bytes_to_string
get_utf8_from_cp_output = bytes_to_string_output
}
// SCORE: parse_descriptor_for_arg_count
let parse_descriptor_for_arg_count_descriptor: value = storage bc:parse_descriptor_for_arg_count descriptor
let parse_descriptor_for_arg_count_output: value = score output parse_descriptor_for_arg_count
mcfunction bc:interpreter/parse_descriptor_for_arg_count {
parse_descriptor_for_arg_count_output = 0
let in_args: score = 0
let type_parsing_state: score = 0
let early_return: score = 0
string_for char in parse_descriptor_for_arg_count_descriptor {
if !early_return {
if char == "(" {
in_args = 1
} else if char == ")" {
early_return = 1
} else if in_args {
if type_parsing_state == 0 {
parse_descriptor_for_arg_count_output += 1
if char == "L" {
type_parsing_state = 1
} else if char == "[" {
type_parsing_state = 2
}
} else if type_parsing_state == 1 && char == ";" {
type_parsing_state = 0
} else if type_parsing_state == 2 {
if char != "[" && char != "L" {
type_parsing_state = 0
}
}
}
}
}
}
mcfunction bc:interpreter/execute {
tellraw @a "Executing..."
tellraw @a ""
let index: score = 1
let early_return: score = 0
while !early_return && stack_frames[-1] {
let stack_frames_len: score = stack_frames
let bytecode_len: score = frame.bytecode
if frame.pc >= bytecode_len {
if stack_frames_len > 1 {
remove stack_frames[-1]
} else {
early_return = 1
}
} else {
let opcode: score = frame.bytecode[frame.pc]
let old_pc: score = frame.pc
frame.pc += 1
if opcode == 0xB2 {
tellraw @a[tag=opcode] "getstatic"
function bc:interpreter/parse_u2
let field_ref_index: score = interpreter_parse_u2_output
get_cp_entry_index = field_ref_index
get_cp_entry_class_data = frame.class_file_data
function bc:interpreter/get_cp_entry
let field_ref_cp_type: score = get_cp_entry_output[0]
let field_entry_index: score = get_cp_entry_output[1]
let name_and_type_index: score = get_cp_entry_output[2]
get_cp_entry_index = field_entry_index
get_cp_entry_class_data = frame.class_file_data
function bc:interpreter/get_cp_entry
let class_tag: score = get_cp_entry_output[0]
let field_entry_class_index: score = get_cp_entry_output[1]
get_utf8_from_cp_index = field_entry_class_index
get_utf8_from_cp_class_data = frame.class_file_data
function bc:interpreter/get_utf8_from_cp
let target_class_name_for_field: data = get_utf8_from_cp_output
get_utf8_from_cp_index = field_entry_class_index
get_utf8_from_cp_class_data = frame.class_file_data
function bc:interpreter/get_utf8_from_cp
let target_class_name: data = get_utf8_from_cp_output
get_cp_entry_index = name_and_type_index
get_cp_entry_class_data = frame.class_file_data
function bc:interpreter/get_cp_entry
let name_and_type_tag: score = get_cp_entry_output[0]
let name_index: score = get_cp_entry_output[1]
let descriptor_index: score = get_cp_entry_output[2]
get_utf8_from_cp_index = name_index
get_utf8_from_cp_class_data = frame.class_file_data
function bc:interpreter/get_utf8_from_cp
let field_name: data = get_utf8_from_cp_output
get_utf8_from_cp_index = descriptor_index
get_utf8_from_cp_class_data = frame.class_file_data
function bc:interpreter/get_utf8_from_cp
let field_descriptor: data = get_utf8_from_cp_output
let target_class_data: value = jvm_interpreter.loaded_classes."$(target_class_name_for_field)"
if !target_class_data {
tellraw @a {text: "Class for getstatic not found.", color: "red"}
}
if target_class_name == "java/lang/System" && field_name == "out" {
if !jvm_interpreter.object_heap.SYSTEM_OUT_STREAM {
jvm_interpreter.object_heap.SYSTEM_OUT_STREAM = {
type: "java/io/PrintStream",
"_class_data": {}
}
}
append frame.operand_stack {
type: "reference",
id: "SYSTEM_OUT_STREAM"
}
} else if field_name == "Companion" {
tellraw @a {text: "TODO companion", color: "yellow"}
} else {
if !target_class_data.static_fields {
target_class_data.static_fields = []
}
let static_fields: value = target_class_data.static_fields
if static_fields."$(field_name)" {
append frame.operand_stack static_fields."$(field_name)"
} else {
tellraw @a {text: "Static field not found", color: "red"}
}
}
} else if opcode == 0x12 {
tellraw @a[tag=opcode] "ldc"
let constant_index: score = frame.bytecode[frame.pc]
frame.pc += 1
get_cp_entry_index = constant_index
get_cp_entry_class_data = frame.class_file_data
function bc:interpreter/get_cp_entry
let cp_entry_type: data = get_cp_entry_output[0]
let cp_val_or_idx: data = get_cp_entry_output[1]
if cp_entry_type == tag_string {
get_utf8_from_cp_index = cp_val_or_idx
get_utf8_from_cp_class_data = frame.class_file_data
function bc:interpreter/get_utf8_from_cp
append frame.operand_stack get_utf8_from_cp_output
} else if cp_entry_type == tag_integer {
append frame.operand_stack cp_val_or_idx
} else if cp_entry_type == tag_float {
append frame.operand_stack cp_val_or_idx
} else {
tellraw @a cp_entry_type
tellraw @a {text: "ldc for cp type {} not implemented", color: "red"}
}
index += 1
} else if opcode == 0xB6 {
tellraw @a[tag=opcode] "invokevirtual"
function bc:interpreter/parse_u2
let method_ref_index: score = interpreter_parse_u2_output
get_cp_entry_index = method_ref_index
get_cp_entry_class_data = frame.class_file_data
function bc:interpreter/get_cp_entry
let method_tag: score = get_cp_entry_output[0]
let class_idx_on_ref: score = get_cp_entry_output[1]
let name_and_type_index: score = get_cp_entry_output[2]
get_cp_entry_index = name_and_type_index
get_cp_entry_class_data = frame.class_file_data
function bc:interpreter/get_cp_entry
let name_and_type_tag: score = get_cp_entry_output[0]
let name_index: score = get_cp_entry_output[1]
let descriptor_index: score = get_cp_entry_output[2]
get_utf8_from_cp_index = name_index
get_utf8_from_cp_class_data = frame.class_file_data
function bc:interpreter/get_utf8_from_cp
let method_name: data = get_utf8_from_cp_output
get_utf8_from_cp_index = descriptor_index
get_utf8_from_cp_class_data = frame.class_file_data
function bc:interpreter/get_utf8_from_cp
let method_descriptor: data = get_utf8_from_cp_output
parse_descriptor_for_arg_count_descriptor = method_descriptor
function bc:interpreter/parse_descriptor_for_arg_count
let num_args: score = parse_descriptor_for_arg_count_output
let old_args_for_method_params: data = []
let index: score = 0
while index < num_args {
append old_args_for_method_params frame.operand_stack[-1]
remove frame.operand_stack[-1]
index += 1
}
let args_for_method_params: data = []
index = 0
while index < num_args {
append args_for_method_params old_args_for_method_params[0]
remove old_args_for_method_params[0]
index += 1
}
if !frame.operand_stack[-1] {
tellraw @a {text: "Attempt to call {} on null object", color: "red"}
}
let obj_ref_this: data = frame.operand_stack[-1]
remove frame.operand_stack[-1]
let obj_data: data = jvm_interpreter.object_heap."$(obj_ref_this.id)"
let actual_obj_type_name: value = obj_data.type
// TODO create insert statement
let all_args_for_call: data = []
append all_args_for_call obj_ref_this
for argument in args_for_method_params {
append all_args_for_call argument
}
if actual_obj_type_name == "java/lang/StringBuilder" {
tellraw @a ["StringBuilder.", method_name, " not implemented"]
} else if actual_obj_type_name == "java/io/PrintStream" {
if method_name == "println" {
tellraw @a ["stdout: ", args_for_method_params[0]]
} else {
tellraw @a ["PrintStream.", method_name, " not implemented"]
}
} else {
// TODO dynamic dispatch?
}
} else if opcode == 0xB1 {
tellraw @a[tag=opcode] "return (void)"
remove stack_frames[-1]
let len: score = stack_frames
if len == 0 {
early_return = 1
}
} else if opcode >= 0x02 && opcode <= 0x08 {
tellraw @a[tag=opcode] "iconst_m1 -> iconst_5"
let value: score = opcode - 0x03
if opcode == 0x02 {
value -= 1
}
append frame.operand_stack value
} else if opcode == 0x3C {
tellraw @a[tag=opcode] "istore_1"
frame.locals[1] = frame.operand_stack[-1]
remove frame.operand_stack[-1]
} else if opcode == 0x3D {
tellraw @a[tag=opcode] "istore_2"
frame.locals[2] = frame.operand_stack[-1]
remove frame.operand_stack[-1]
} else if opcode == 0x1B {
tellraw @a[tag=opcode] "iload_1"
append frame.operand_stack frame.locals[1]
} else if opcode == 0x1C {
tellraw @a[tag=opcode] "iload_2"
append frame.operand_stack frame.locals[2]
} else if opcode == 0x60 {
tellraw @a[tag=opcode] "iadd"
let len: score = frame.operand_stack
if len < 2 {
tellraw @a {text: "Stack underflow for iadd", color: "red"}
} else {
let value2: score = frame.operand_stack[-1]
remove frame.operand_stack[-1]
let value1: score = frame.operand_stack[-1]
remove frame.operand_stack[-1]
append frame.operand_stack value1 + value2
}
} else if opcode == 0x3E {
tellraw @a[tag=opcode] "istore_3"
frame.locals[3] = frame.operand_stack[-1]
remove frame.operand_stack[-1]
} else if opcode == 0x1D {
tellraw @a[tag=opcode] "iload_3"
append frame.operand_stack frame.locals[3]
} else if opcode == 0xA3 {
tellraw @a[tag=opcode] "if_icmpgt"
function bc:interpreter/parse_u2
let offset: score = interpreter_parse_u2_output
let value2: score = frame.operand_stack[-1]
remove frame.operand_stack[-1]
let value1: score = frame.operand_stack[-1]
remove frame.operand_stack[-1]
if value1 > value2 {
frame.pc = old_pc + offset
}
} else if opcode == 0x68 {
tellraw @a[tag=opcode] "imul"
let value2: score = frame.operand_stack[-1]
remove frame.operand_stack[-1]
let value1: score = frame.operand_stack[-1]
remove frame.operand_stack[-1]
append frame.operand_stack value1 * value2
} else if opcode == 0x84 {
tellraw @a[tag=opcode] "iinc"
let index: score = frame.bytecode[frame.pc]
frame.pc += 1
let const_val_byte: score = frame.bytecode[frame.pc]
frame.pc += 1
frame.locals[index] += const_val_byte
} else if opcode == 0x01 {
tellraw @a[tag=opcode] "aconst_null"
append frame.operand_stack {}
} else if opcode == 0xA7 {
tellraw @a[tag=opcode] "goto"
function bc:interpreter/parse_i2
frame.pc = old_pc + interpreter_parse_i2_output
} else {
tellraw @a ["Unknown opcode ", opcode]
early_return = 1
}
}
}
}
mcfunction bc:interpreter/run_method_by_name {
if !jvm_interpreter.loaded_classes."$(run_method_by_name_class_name)" {
tellraw @a "Not loaded"
return fail
}
let class_data: value = jvm_interpreter.loaded_classes."$(run_method_by_name_class_name)"
let method_info: data = {}
for method in class_data.methods {
if method.name == run_method_by_name_method_name && method.descriptor == run_method_by_name_descriptor {
method_info = method
}
}
if !method_info {
tellraw @a "Method not found"
return fail
}
tellraw @a "Found method"
if method_info.access_flags & 0x0100 {
tellraw @a "Native"
} else {
new_stack_frame_method_info = method_info
new_stack_frame_args = run_method_by_name_args
new_stack_frame_class_file_data = class_data
function bc:interpreter/new_stack_frame
function bc:interpreter/execute
}
}
mcfunction bc:main {
function bc:init
for class_file_to_load in class_files_to_load {
let name: value = class_file_to_load[0]
let raw_data: value = class_file_to_load[1]
classfile_raw = raw_data
function bc:parser/parse
let class_data: value = storage bc:parser/classfile classfile
load_class_data_class_data = class_data
function bc:interpreter/load_class_data
parsed_class_data."$(name)" = class_data
}
let object_stub_class_data: data = {
"name": "java/lang/Object",
"methods": [
{
"name": "getClass",
"descriptor": "()Ljava/lang/Class;",
"access_flags": 0x0101,
"attributes": []
},
{
"name": "<init>",
"descriptor": "()V",
"access_flags": 0x0001,
"attributes": [
{"name": "Code", "max_stack": 0, "max_locals": 1, "code": [177]}
]
}
],
"constant_pool": [{}],
"super_class": "",
"fields": [],
"access_flags": 0x0001
}
load_class_data_class_data = object_stub_class_data
function bc:interpreter/load_class_data
let system_stub_class_data: data = {
"name": "java/lang/System",
"methods": [],
"fields": [
{
"name": "out",
"descriptor": "Ljava/io/PrintStream;",
"access_flags": 0x0019
}
],
"constant_pool": [{}],
"super_class": "java/lang/Object",
"access_flags": 0x0001
}
load_class_data_class_data = system_stub_class_data
function bc:interpreter/load_class_data
let print_stream_stub_class_data: data = {
"name": "java/io/PrintStream",
"methods": [
{
"name": "println",
"descriptor": "(Ljava/lang/String;)V",
"access_flags": 0x0001,
"attributes": []
},
{
"name": "println",
"descriptor": "(I)V",
"access_flags": 0x0001,
"attributes": []
},
{
"name": "println",
"descriptor": "(Ljava/lang/Object;)V",
"access_flags": 0x0001,
"attributes": []
}
],
"fields": [],
"constant_pool": [{}],
"super_class": "java/lang/Object",
"access_flags": 0x0001
}
load_class_data_class_data = print_stream_stub_class_data
function bc:interpreter/load_class_data
let main_class_data: value = parsed_class_data.Main
let main_class_actual_name: value = main_class_data.name
tellraw @a ["Locating Main method in class ", main_class_actual_name]
let main_method_name_to_run: value = "main"
let main_method_descriptor_to_run: value = "([Ljava/lang/String;)V"
let main_method_args_to_run: value = [
{"type": "array", "element_type": "Ljava/lang/String;", "value": []}
]
let found: score = 0
if main_class_data.methods {
for method in main_class_data.methods {
if method.name == main_method_name_to_run && method.descriptor == main_method_descriptor_to_run {
found = 1
}
}
}
if !found {
tellraw @a "Not found"
}
run_method_by_name_class_name = main_class_actual_name
run_method_by_name_method_name = main_method_name_to_run
run_method_by_name_descriptor = main_method_descriptor_to_run
run_method_by_name_args = main_method_args_to_run
function bc:interpreter/run_method_by_name
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment