From 1dcda3d2ad983af2a49472549a5095cc7d3e6694 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Mon, 6 Jan 2025 15:31:23 -0600 Subject: [PATCH] native_types: refactor primitive array operations --- Makefile | 2 +- c/execute.c | 175 ++++++++++++++------------------------ c/frame.c | 7 ++ c/native.c | 7 ++ c/native.h | 1 + c/native_types.h | 71 ++++++++++++++++ java/lang/Math.java | 2 + p/TestArray.java | 17 ---- p/TestFinally.java | 28 ++++++ p/TestPrimitiveArray.java | 100 ++++++++++++++++++++++ 10 files changed, 282 insertions(+), 128 deletions(-) create mode 100644 c/native_types.h delete mode 100644 p/TestArray.java create mode 100644 p/TestFinally.java create mode 100644 p/TestPrimitiveArray.java diff --git a/Makefile b/Makefile index da83501..04e6d61 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ CC ?= gcc ARCH = -m32 CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protector -std=c2x -g CFLAGS += -DDEBUG -CFLAGS += -DDEBUG_PRINT +#CFLAGS += -DDEBUG_PRINT LDFLAGS = -lm OPT ?= -O0 DEPFLAGS = -MMD -MP diff --git a/c/execute.c b/c/execute.c index d58f42b..b117458 100644 --- a/c/execute.c +++ b/c/execute.c @@ -7,14 +7,14 @@ #include "field_size.h" #include "debug.h" #include "parse_type.h" +#include "native_types.h" void op_aaload(struct vm * vm) { int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - uint32_t * referencearray = (uint32_t *)&arrayref[1]; - uint32_t value = referencearray[index]; + struct object_arrayref * arrayref = (struct object_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + uint32_t value = arrayref->u32[index]; operand_stack_push_u32(vm->current_frame, value); } @@ -22,10 +22,9 @@ void op_aastore(struct vm * vm) { uint32_t value = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int32_t * referencearray = (int32_t *)&arrayref[1]; - referencearray[index] = value; + struct object_arrayref * arrayref = (struct object_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + arrayref->u32[index] = value; } void op_aconst_null(struct vm * vm) @@ -66,15 +65,16 @@ void op_aload_3(struct vm * vm) void op_anewarray(struct vm * vm, uint32_t index) { int32_t count = operand_stack_pop_u32(vm->current_frame); - int32_t size = 4 * count + 4; - int32_t * arrayref = memory_allocate(size); + int32_t element_size = (sizeof (void *)); + int32_t size = element_size * count + (sizeof (struct object_arrayref)); + struct object_arrayref * arrayref = memory_allocate(size); assert(arrayref != nullptr); - arrayref[0] = count; + arrayref->length = count; /* All components of the new array are initialized to null, the default value for reference types */ for (int i = 0; i < count; i++) { - arrayref[i + 1] = 0; + arrayref->a[i] = nullptr; } operand_stack_push_u32(vm->current_frame, (uint32_t)arrayref); @@ -132,22 +132,19 @@ void op_athrow(struct vm * vm) void op_baload(struct vm * vm) { int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int8_t * bytearray = (int8_t *)&arrayref[1]; - int8_t value = bytearray[index]; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + int8_t value = arrayref->u8[index]; operand_stack_push_u32(vm->current_frame, value); } void op_bastore(struct vm * vm) { - int8_t value = operand_stack_pop_u32(vm->current_frame); + uint8_t value = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - debugf("%d %d\n", arrayref[0], index); - assert(arrayref[0] > 0 && index < arrayref[0]); - int8_t * bytearray = (int8_t *)&arrayref[1]; - bytearray[index] = value; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + arrayref->u8[index] = value; } void op_bipush(struct vm * vm, int32_t byte) @@ -163,10 +160,9 @@ void op_breakpoint(struct vm * vm) void op_caload(struct vm * vm) { int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - uint16_t * chararray = (uint16_t *)&arrayref[1]; - uint16_t value = chararray[index]; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + uint16_t value = arrayref->u16[index]; operand_stack_push_u32(vm->current_frame, value); } @@ -174,10 +170,9 @@ void op_castore(struct vm * vm) { uint16_t value = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - uint16_t * chararray = (uint16_t *)&arrayref[1]; - chararray[index] = value; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + arrayref->u16[index] = value; } void op_checkcast(struct vm * vm, uint32_t index) @@ -269,10 +264,9 @@ void op_dadd(struct vm * vm) void op_daload(struct vm * vm) { int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int64_t * longarray = (int64_t *)&arrayref[1]; - int64_t value = longarray[index]; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + uint64_t value = arrayref->u64[index]; operand_stack_push_u64(vm->current_frame, value); } @@ -280,10 +274,9 @@ void op_dastore(struct vm * vm) { int64_t value = operand_stack_pop_u64(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int64_t * longarray = (int64_t *)&arrayref[1]; - longarray[index] = value; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + arrayref->u64[index] = value; } void op_dcmpg(struct vm * vm) @@ -553,21 +546,19 @@ void op_fadd(struct vm * vm) void op_faload(struct vm * vm) { int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int32_t * intarray = (int32_t *)&arrayref[1]; - int32_t value = intarray[index]; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + uint32_t value = arrayref->u32[index]; operand_stack_push_u32(vm->current_frame, value); } void op_fastore(struct vm * vm) { - int32_t value = operand_stack_pop_u32(vm->current_frame); + uint32_t value = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int32_t * intarray = (int32_t *)&arrayref[1]; - intarray[index] = value; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + arrayref->u32[index] = value; } void op_fcmpg(struct vm * vm) @@ -881,10 +872,9 @@ void op_iadd(struct vm * vm) void op_iaload(struct vm * vm) { int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int32_t * intarray = (int32_t *)&arrayref[1]; - int32_t value = intarray[index]; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + int32_t value = arrayref->u32[index]; operand_stack_push_u32(vm->current_frame, value); } @@ -898,12 +888,11 @@ void op_iand(struct vm * vm) void op_iastore(struct vm * vm) { - int32_t value = operand_stack_pop_u32(vm->current_frame); + uint32_t value = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int32_t * intarray = (int32_t *)&arrayref[1]; - intarray[index] = value; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + arrayref->u32[index] = value; } void op_iconst_0(struct vm * vm) @@ -1460,10 +1449,9 @@ void op_ladd(struct vm * vm) void op_laload(struct vm * vm) { int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int64_t * longarray = (int64_t *)&arrayref[1]; - int64_t value = longarray[index]; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + int64_t value = arrayref->u64[index]; operand_stack_push_u64(vm->current_frame, value); } @@ -1477,12 +1465,11 @@ void op_land(struct vm * vm) void op_lastore(struct vm * vm) { - int64_t value = operand_stack_pop_u64(vm->current_frame); + uint64_t value = operand_stack_pop_u64(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int64_t * longarray = (int64_t *)&arrayref[1]; - longarray[index] = value; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + arrayref->u64[index] = value; } void op_lcmp(struct vm * vm) @@ -1824,55 +1811,25 @@ void op_new(struct vm * vm, uint32_t index) operand_stack_push_u32(vm->current_frame, (uint32_t)objectref); } -enum ARRAY_TYPE { - T_BOOLEAN = 4, // 1 byte - T_CHAR = 5, // 2 bytes - T_FLOAT = 6, // 4 bytes - T_DOUBLE = 7, // 8 bytes - T_BYTE = 8, // 1 byte - T_SHORT = 9, // 2 bytes - T_INT = 10, // 4 bytes - T_LONG = 11, // 8 bytes -}; void op_newarray(struct vm * vm, uint32_t atype) { - int32_t element_size = 0; - switch (atype) { - case T_BOOLEAN: [[fallthrough]]; // 1 byte - case T_BYTE: // 1 byte - element_size = 1; - break; - case T_CHAR: [[fallthrough]]; // 2 bytes - case T_SHORT: // 2 bytes - element_size = 2; - break; - case T_FLOAT: [[fallthrough]]; // 4 bytes - case T_INT: // 4 bytes - element_size = 4; - break; - case T_DOUBLE: [[fallthrough]]; // 8 bytes - case T_LONG: // 8 bytes - element_size = 8; - break; - default: - assert(false); - break; - } int32_t count = operand_stack_pop_u32(vm->current_frame); - int32_t size = element_size * count + 4; - int32_t * arrayref = memory_allocate(size); + int32_t element_size = array_element_size(atype); + int32_t size = element_size * count + (sizeof (struct primitive_arrayref)); + struct primitive_arrayref * arrayref = memory_allocate(size); assert(arrayref != nullptr); - arrayref[0] = count; + arrayref->length = count; /* Each of the elements of the new array is initialized to the default initial value (§2.3, §2.4) for the element type of the array type. */ /* round up u32_count, possibly initializing past the end of the array. This is acceptable because memory_allocate always allocates a multiple of 4 greater than or equal to `size`. */ - int32_t u32_count = (size - 4 + 3) / 4; + int32_t array_element_size = count * element_size; // bytes + int32_t u32_count = (array_element_size + 3) / 4; // u32 units for (int i = 0; i < u32_count; i++) { - arrayref[i + 1] = 0; + arrayref->u32[i] = 0; } operand_stack_push_u32(vm->current_frame, (uint32_t)arrayref); @@ -2014,10 +1971,9 @@ void op_return(struct vm * vm) void op_saload(struct vm * vm) { int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int16_t * shortarray = (int16_t *)&arrayref[1]; - int16_t value = shortarray[index]; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + int16_t value = arrayref->u16[index]; operand_stack_push_u32(vm->current_frame, value); } @@ -2025,10 +1981,9 @@ void op_sastore(struct vm * vm) { uint16_t value = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame); - int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); - assert(arrayref[0] > 0 && index < arrayref[0]); - int16_t * shortarray = (int16_t *)&arrayref[1]; - shortarray[index] = value; + struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); + arrayref->u16[index] = value; } void op_sipush(struct vm * vm, int32_t byte) diff --git a/c/frame.c b/c/frame.c index fd0d2d3..f3f612c 100644 --- a/c/frame.c +++ b/c/frame.c @@ -200,6 +200,13 @@ void vm_native_method_call(struct vm * vm, struct class_entry * class_entry, str operand_stack_push_u32(vm->current_frame, value); return; } + if (hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"abs", 3)) { + assert(nargs == 1); + assert(return_type == 'F'); + uint32_t value = native_java_lang_math_abs_1(args); + operand_stack_push_u32(vm->current_frame, value); + return; + } } } diff --git a/c/native.c b/c/native.c index 94807fd..46a003e 100644 --- a/c/native.c +++ b/c/native.c @@ -109,6 +109,13 @@ native_java_lang_math_cos_1(uint32_t * args) return *((uint32_t *)&value); } +uint32_t native_java_lang_math_abs_1(uint32_t * args) +{ + float arg = ((float *)args)[0]; + float value = __builtin_fabsf(arg); + return *((uint32_t *)&value); +} + #if defined(__dreamcast__) #include "resources.inc.c" #endif diff --git a/c/native.h b/c/native.h index d1bda9a..78c2d20 100644 --- a/c/native.h +++ b/c/native.h @@ -14,6 +14,7 @@ uint32_t native_java_misc_memory_getU1_1(uint32_t * args); void native_java_misc_memory_putSQ1_2(uint32_t * args); uint32_t native_java_lang_math_sin_1(uint32_t * args); uint32_t native_java_lang_math_cos_1(uint32_t * args); +uint32_t native_java_lang_math_abs_1(uint32_t * args); uint32_t java_misc_resource_getresource_1(uint32_t * args); uint32_t native_java_misc_memory_isbigendian(); uint32_t native_jvm_internal_loader_getbuffer(); diff --git a/c/native_types.h b/c/native_types.h new file mode 100644 index 0000000..0167dc9 --- /dev/null +++ b/c/native_types.h @@ -0,0 +1,71 @@ +#include + +#include "class_resolver.h" + +struct objectref { + struct class_entry * class_entry; + union { + void * field[0]; + }; +}; + +static_assert((sizeof (struct objectref)) == 4); + +struct primitive_arrayref { + int32_t length; + union { + uint8_t u8[0]; + uint16_t u16[0]; + uint32_t u32[0]; + uint64_t u64[0]; + }; +}; + +static_assert((sizeof (struct primitive_arrayref)) == 4); + +struct object_arrayref { + struct class_entry * class_entry; + int32_t length; + union { + struct objectref * a[0]; + uint32_t u32[0]; + }; +}; + +static_assert((sizeof (struct object_arrayref)) == 8); + +enum ARRAY_TYPE { + T_BOOLEAN = 4, // 1 byte + T_CHAR = 5, // 2 bytes + T_FLOAT = 6, // 4 bytes + T_DOUBLE = 7, // 8 bytes + T_BYTE = 8, // 1 byte + T_SHORT = 9, // 2 bytes + T_INT = 10, // 4 bytes + T_LONG = 11, // 8 bytes +}; + +static inline int array_element_size(int atype) +{ + switch (atype) { + case T_BOOLEAN: [[fallthrough]]; // 1 byte + case T_BYTE: // 1 byte + return 1; + break; + case T_CHAR: [[fallthrough]]; // 2 bytes + case T_SHORT: // 2 bytes + return 2; + break; + case T_FLOAT: [[fallthrough]]; // 4 bytes + case T_INT: // 4 bytes + return 4; + break; + case T_DOUBLE: [[fallthrough]]; // 8 bytes + case T_LONG: // 8 bytes + return 8; + break; + default: + assert(!"invalid atype"); + break; + } +} diff --git a/java/lang/Math.java b/java/lang/Math.java index 346652e..159ba15 100644 --- a/java/lang/Math.java +++ b/java/lang/Math.java @@ -17,4 +17,6 @@ public final class Math { public static native float sin(float a); public static native float cos(float a); + + public static native float abs(float a); } diff --git a/p/TestArray.java b/p/TestArray.java deleted file mode 100644 index 1bf9af2..0000000 --- a/p/TestArray.java +++ /dev/null @@ -1,17 +0,0 @@ -package p; - -class TestArray { - static char[] test() { - char[] a = {'a', 'b', 'c', 'd'}; - return a; - } - - static char test2(char[] c) { - return (char)((int)(c[0]) * 2); - } - - public static void main() { - char[] a = test(); - test2(a); - } -} diff --git a/p/TestFinally.java b/p/TestFinally.java new file mode 100644 index 0000000..a7abca4 --- /dev/null +++ b/p/TestFinally.java @@ -0,0 +1,28 @@ +package p; + +import java.lang.Exception; + +class TestFinally { + static void test() throws Exception { + try { + try { + System.out.println("try"); + throw new Exception("test exception"); + } catch (Exception e) { + System.out.println("catch"); + throw e; + } finally { + System.out.println("finally"); + } + } catch (Exception e) { + System.out.println("catch2"); + throw e; + } finally { + System.out.println("finally2 asdf"); + } + } + + public static void main(String[] args) throws Exception { + test(); + } +} diff --git a/p/TestPrimitiveArray.java b/p/TestPrimitiveArray.java new file mode 100644 index 0000000..c2e82c6 --- /dev/null +++ b/p/TestPrimitiveArray.java @@ -0,0 +1,100 @@ +package p; + +class TestPrimitiveArray { + static boolean testBool() { + boolean[] a = {true, false, true, false, true}; + int sum = 0; + for (int i = 0; i < a.length; i++) { + if (a[i] == true) { + sum += 1; + } else { + sum -= 1; + } + } + return sum == 1; + } + + static boolean testByte() { + byte[] a = {1, -1, 3, 4}; + int sum = 0; + for (int i = 0; i < a.length; i++) { + sum += a[i]; + } + return sum == 7; + } + + static boolean testChar() { + char[] a = {'a', 'b', 'c', 'd'}; + return + a[0] == 'a' && + a[1] == 'b' && + a[2] == 'c' && + a[3] == 'd'; + } + + static boolean testShort() { + short[] a = {-1234, 1234, 300, 400}; + int sum = 0; + for (int i = 0; i < a.length; i++) { + sum += a[i]; + } + return sum == 700; + } + + static boolean testInt() { + int[] a = {-12345678, 12345678, 3000000, 4000000}; + int sum = 0; + for (int i = 0; i < a.length; i++) { + sum += a[i]; + } + return sum == 7000000; + } + + static boolean epsilon(float a, float b) { + return Math.abs(a - b) < 0.0001f; + } + + static boolean testFloat() { + float[] a = {1.2f, -1.2f, 3.4f, 5.6f}; + float sum = 0; + for (int i = 0; i < a.length; i++) { + sum += a[i]; + } + return epsilon(sum, 9.0f); + } + + static boolean testLong() { + long[] a = {800000000000L, -800000000000L, 300000000000L, 400000000000L}; + long sum = 0; + for (int i = 0; i < a.length; i++) { + sum += a[i]; + } + return sum == 700000000000L; + } + + static boolean testDouble() { + double[] a = {9007199254740900.0, -1.0}; + double sum = 0; + for (int i = 0; i < a.length; i++) { + sum += a[i]; + } + return sum == 9007199254740899.0; + } + + public static void main() { + System.out.print("bool: "); + System.out.println(testBool()); + System.out.print("byte: "); + System.out.println(testByte()); + System.out.print("char: "); + System.out.println(testChar()); + System.out.print("short: "); + System.out.println(testShort()); + System.out.print("int: "); + System.out.println(testInt()); + System.out.print("long: "); + System.out.println(testLong()); + System.out.print("double: "); + System.out.println(testDouble()); + } +}