native_types: refactor primitive array operations

This commit is contained in:
Zack Buhman 2025-01-06 15:31:23 -06:00
parent 6f8477e5f0
commit 1dcda3d2ad
10 changed files with 282 additions and 128 deletions

View File

@ -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

View File

@ -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)

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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();

71
c/native_types.h Normal file
View File

@ -0,0 +1,71 @@
#include <stdint.h>
#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;
}
}

View File

@ -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);
}

View File

@ -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);
}
}

28
p/TestFinally.java Normal file
View File

@ -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();
}
}

100
p/TestPrimitiveArray.java Normal file
View File

@ -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());
}
}