diff --git a/c/class_resolver.c b/c/class_resolver.c index 1cec31a..cacd8a4 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -9,6 +9,7 @@ #include "debug_class_file.h" #include "memory_allocator.h" #include "printf.h" +#include "field_size.h" static void class_resolver_create_interfaces_hash_table(struct class_entry * class_entry) { @@ -23,29 +24,13 @@ static void class_resolver_create_interfaces_hash_table(struct class_entry * cla */ } -static int field_size(struct class_file * class_file, struct field_info * field_info) +static int field_info_field_size(struct class_file * class_file, struct field_info * field_info) { struct constant * field_descriptor_constant = &class_file->constant_pool[field_info->descriptor_index - 1]; #ifdef DEBUG assert(field_descriptor_constant->tag == CONSTANT_Utf8); #endif - - switch (field_descriptor_constant->utf8.bytes[0]) { - case 'B': [[fallthrough]]; - case 'C': [[fallthrough]]; - case 'F': [[fallthrough]]; - case 'I': [[fallthrough]]; - case 'L': [[fallthrough]]; - case 'S': [[fallthrough]]; - case 'Z': [[fallthrough]]; - case '[': - return 1; - case 'D': [[fallthrough]]; - case 'J': - return 2; - default: - assert(false); - } + return field_size(field_descriptor_constant->utf8.bytes[0]); } static int32_t class_resolver_create_fields_hash_table(struct class_entry * class_entry) @@ -72,10 +57,10 @@ static int32_t class_resolver_create_fields_hash_table(struct class_entry * clas if (field_info->access_flags & FIELD_ACC_STATIC) { field_entry[i].static_index = static_index; - static_index += field_size(class_file, field_info); + static_index += field_info_field_size(class_file, field_info); } else { field_entry[i].instance_index = instance_index; - instance_index += field_size(class_file, field_info); + instance_index += field_info_field_size(class_file, field_info); } field_entry[i].field_info = field_info; diff --git a/c/execute.c b/c/execute.c index a932df9..8a19c4b 100644 --- a/c/execute.c +++ b/c/execute.c @@ -4,6 +4,7 @@ #include "class_resolver.h" #include "execute_helper.h" #include "printf.h" +#include "field_size.h" void op_aaload(struct vm * vm) { @@ -1596,9 +1597,45 @@ void op_monitorexit(struct vm * vm) assert(!"op_monitorexit"); } +static int32_t * _multiarray(int32_t * dims, int num_dimensions, int level, uint8_t * type) +{ + int32_t count = dims[level]; + int32_t element_size = field_size_array(*type); + int32_t size = element_size * count + 4; + int32_t * arrayref = memory_allocate(size); + arrayref[0] = count; + + int32_t u32_count = (size - 4 + 3) / 4; + for (int i = 0; i < u32_count; i++) { + if (level == num_dimensions - 1) { + arrayref[i + 1] = 0; + } else { + assert(*type == '['); + arrayref[1 + i] = (int32_t)_multiarray(dims, num_dimensions, level + 1, type + 1); + } + } + return arrayref; +} + void op_multianewarray(struct vm * vm, uint32_t index, uint32_t dimensions) { - assert(!"op_multianewarray"); + struct constant * class_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1]; + assert(class_constant->tag == CONSTANT_Class); + struct constant * type_constant = &vm->current_frame->class_entry->class_file->constant_pool[class_constant->class.name_index - 1]; + assert(type_constant->tag == CONSTANT_Utf8); + + // The run-time constant pool entry at the index must be a symbolic reference + // to a class, array, or interface type + uint8_t * type = type_constant->utf8.bytes; + assert(*type == '['); + + assert(dimensions > 0); + int32_t dims[dimensions]; + for (int i = 0; i < dimensions; i++) { + dims[dimensions - i - 1] = operand_stack_pop_u32(vm->current_frame); + } + int32_t * arrayref = _multiarray(dims, dimensions, 0, type + 1); + operand_stack_push_u32(vm->current_frame, (uint32_t)arrayref); } void op_new(struct vm * vm, uint32_t index) diff --git a/c/field_size.h b/c/field_size.h new file mode 100644 index 0000000..0017ffb --- /dev/null +++ b/c/field_size.h @@ -0,0 +1,43 @@ +#pragma once + +static inline int field_size(uint8_t c) +{ + switch (c) { + case 'B': [[fallthrough]]; + case 'C': [[fallthrough]]; + case 'F': [[fallthrough]]; + case 'I': [[fallthrough]]; + case 'L': [[fallthrough]]; + case 'S': [[fallthrough]]; + case 'Z': [[fallthrough]]; + case '[': + return 1; + case 'D': [[fallthrough]]; + case 'J': + return 2; + default: + assert(false); + } +} + +static inline int field_size_array(uint8_t c) +{ + switch (c) { + case 'Z': [[fallthrough]]; // boolean + case 'B': // byte + return 1; + case 'C': [[fallthrough]]; // char + case 'S': // short + return 2; + case 'F': [[fallthrough]]; // float + case 'I': [[fallthrough]]; // int + case 'L': [[fallthrough]]; // classref + case '[': // arrayref + return 4; + case 'D': [[fallthrough]]; + case 'J': + return 8; + default: + assert(false); + } +} diff --git a/p/MultiArray.java b/p/MultiArray.java new file mode 100644 index 0000000..702f18f --- /dev/null +++ b/p/MultiArray.java @@ -0,0 +1,19 @@ +package p; + +class MultiArray { + static int test() { + byte[][][] arr = new byte[10][20][30]; + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 20; j++) { + for (int k = 0; k < 30; k++) { + arr[i][j][k] = (byte)(i * j * k); + } + } + } + return arr[2][9][4]; + } + + public static void main() { + test(); + } +} diff --git a/p/WideInstruction.java b/p/WideInstruction.java index 12af047..d89c00b 100644 --- a/p/WideInstruction.java +++ b/p/WideInstruction.java @@ -18,7 +18,7 @@ class WideInstruction { k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57 = 42; - for (int i = 0; i < 256; i += 1024) { + for (int i = 0; i < 2560; i += 1024) { k57 += 360; }