This commit is contained in:
Zack Buhman 2025-01-10 17:51:57 -06:00
parent d1483a0c15
commit d8ed9550ef
33 changed files with 592 additions and 403 deletions

View File

@ -3,9 +3,11 @@
include java.mk include java.mk
MAKEFILE_PATH := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST)))))
CC ?= gcc CC ?= gcc
ARCH = -m32 ARCH = -m32
CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protector -std=c2x -g CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protector -std=c2x -g
CFLAGS += -I$(MAKEFILE_PATH)/c
CFLAGS += -DDEBUG CFLAGS += -DDEBUG
#CFLAGS += -DDEBUG_PRINT #CFLAGS += -DDEBUG_PRINT
LDFLAGS = -lm LDFLAGS = -lm
@ -22,7 +24,11 @@ main: $(OBJ) $(MAIN_HOSTED_OBJ)
$(CC) $(ARCH) $(LDFLAGS) $^ -o $@ $(CC) $(ARCH) $(LDFLAGS) $^ -o $@
clean: clean:
rm -f main print_class c/*.o c/*.d *.elf *.bin rm -f main print_class *.elf *.bin
find -P \
-regextype posix-egrep \
-regex '.*\.(o|d|gch)$$' \
-exec rm {} \;
.SUFFIXES: .SUFFIXES:
.INTERMEDIATE: .INTERMEDIATE:

View File

@ -7,7 +7,7 @@ LIB ?= $(MAKEFILE_PATH)/dreamcast
CFLAGS += -D__dreamcast__ CFLAGS += -D__dreamcast__
CFLAGS += -DDEBUG CFLAGS += -DDEBUG
#CFLAGS += -DDEBUG_PRINT #CFLAGS += -DDEBUG_PRINT
CFLAGS += -I$(MAKEFILE_PATH) CFLAGS += -I$(MAKEFILE_PATH)/c
CFLAGS += -I$(MAKEFILE_PATH)/dreamcast/ CFLAGS += -I$(MAKEFILE_PATH)/dreamcast/
CFLAGS += -Wno-error=strict-aliasing -fno-strict-aliasing CFLAGS += -Wno-error=strict-aliasing -fno-strict-aliasing
CARCH = -m4-single -ml CARCH = -m4-single -ml

View File

@ -1,3 +1,15 @@
#pragma once #pragma once
#include <assert.h> extern void __assert_fail (const char *__assertion, const char *__file,
unsigned int __line, const char *__function)
__attribute__ ((__noreturn__));
#define __ASSERT_FUNCTION __func__
#define assert(expr) \
((void) sizeof ((expr) ? 1 : 0), __extension__ ({ \
if (expr) \
; /* empty */ \
else \
__assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION); \
}))

View File

@ -4,22 +4,16 @@
#include "find_attribute.h" #include "find_attribute.h"
#include "memory_allocator.h" #include "memory_allocator.h"
#include "native_types_allocate.h" #include "native_types_allocate.h"
#include "vm_instance.h"
struct objectref * backtrace_allocate(struct vm * vm) struct objectref * backtrace_allocate(struct vm * vm)
{ {
struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length, struct objectref * objectref = vm_instance_create(vm, "java/lang/Backtrace");
vm->class_hash_table.entry, assert(objectref != nullptr);
(const uint8_t *)"java/lang/Backtrace", assert(objectref->class_entry->instance_fields_count >= 1);
19);
debugf("backtrace class entry: %p\n", class_entry);
assert(class_entry->instance_fields_count >= 1);
struct objectref * objectref = obj_allocate(vm, class_entry->instance_fields_count);
objectref->class_entry = class_entry;
int num_entries = vm->frame_stack.ix; int num_entries = vm->frame_stack.ix;
struct arrayref * arrayref = prim_array_allocate(vm, (sizeof (struct backtrace_entry)), num_entries); struct arrayref * arrayref = prim_array_allocate(vm, (sizeof (struct backtrace_entry)), num_entries);
arrayref->length = num_entries;
arrayref->class_entry = nullptr; arrayref->class_entry = nullptr;
struct backtrace_entry * backtrace_entry = (struct backtrace_entry *)&arrayref->u32[0]; struct backtrace_entry * backtrace_entry = (struct backtrace_entry *)&arrayref->u32[0];

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "native_types.h"
#include "frame.h" #include "frame.h"
struct backtrace_entry { struct backtrace_entry {

View File

@ -15,6 +15,7 @@
#include "find_attribute.h" #include "find_attribute.h"
#include "frame.h" #include "frame.h"
#include "native_types_allocate.h" #include "native_types_allocate.h"
#include "vm_instance.h"
static int field_info_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)
{ {
@ -219,7 +220,7 @@ struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** buff
int length, int length,
int * hash_table_length) int * hash_table_length)
{ {
int class_hash_table_length = hash_table_next_power_of_two(hash_table_next_power_of_two(length * 2)); int class_hash_table_length = hash_table_next_power_of_two(length * 2);
uint32_t class_hash_table_size = (sizeof (struct hash_table_entry)) * class_hash_table_length; uint32_t class_hash_table_size = (sizeof (struct hash_table_entry)) * class_hash_table_length;
struct hash_table_entry * class_hash_table = malloc_class_arena(class_hash_table_size); struct hash_table_entry * class_hash_table = malloc_class_arena(class_hash_table_size);
hash_table_init(class_hash_table_length, class_hash_table); hash_table_init(class_hash_table_length, class_hash_table);
@ -605,12 +606,6 @@ struct objectref * class_resolver_lookup_string(struct vm * vm,
struct constant * utf8_constant = &class_entry->class_file->constant_pool[string_constant->string.string_index - 1]; struct constant * utf8_constant = &class_entry->class_file->constant_pool[string_constant->string.string_index - 1];
assert(utf8_constant->tag == CONSTANT_Utf8); assert(utf8_constant->tag == CONSTANT_Utf8);
struct class_entry * string_class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
vm->class_hash_table.entry,
(const uint8_t *)"java/lang/String",
16);
debugf("string class entry: %p\n", string_class_entry);
int32_t count = utf8_constant->utf8.length; int32_t count = utf8_constant->utf8.length;
struct arrayref * arrayref = prim_array_allocate(vm, 1, count); struct arrayref * arrayref = prim_array_allocate(vm, 1, count);
assert(arrayref != nullptr); assert(arrayref != nullptr);
@ -620,14 +615,9 @@ struct objectref * class_resolver_lookup_string(struct vm * vm,
arrayref->u8[i] = utf8_constant->utf8.bytes[i]; arrayref->u8[i] = utf8_constant->utf8.bytes[i];
} }
assert(string_class_entry != nullptr); struct objectref * objectref = vm_instance_create(vm, "java/lang/String");
int fields_count = string_class_entry->instance_fields_count;
struct objectref * objectref = obj_allocate(vm, fields_count);
assert(objectref != nullptr); assert(objectref != nullptr);
objectref->class_entry = string_class_entry; assert(objectref->class_entry->instance_fields_count >= 1);
for (int i = 0; i < fields_count; i++) {
objectref->oref[i] = nullptr;
}
objectref->aref[0] = arrayref; objectref->aref[0] = arrayref;
// cache the result // cache the result

View File

@ -74,7 +74,6 @@ void op_anewarray(struct vm * vm, uint32_t index)
int32_t count = operand_stack_pop_u32(vm->current_frame); int32_t count = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = ref_array_allocate(vm, count); struct arrayref * arrayref = ref_array_allocate(vm, count);
assert(arrayref != nullptr); assert(arrayref != nullptr);
arrayref->length = count;
arrayref->class_entry = class_entry; arrayref->class_entry = class_entry;
/* All components of the new array are initialized to null, the default value /* All components of the new array are initialized to null, the default value
@ -1171,8 +1170,6 @@ void op_invokevirtual(struct vm * vm, uint32_t index)
assert(interfacemethodref_constant->tag == CONSTANT_Methodref); assert(interfacemethodref_constant->tag == CONSTANT_Methodref);
struct constant * nameandtype_constant = &origin_class_entry->class_file->constant_pool[interfacemethodref_constant->interfacemethodref.name_and_type_index - 1]; struct constant * nameandtype_constant = &origin_class_entry->class_file->constant_pool[interfacemethodref_constant->interfacemethodref.name_and_type_index - 1];
assert(nameandtype_constant->tag == CONSTANT_NameAndType); assert(nameandtype_constant->tag == CONSTANT_NameAndType);
struct constant * method_name_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
assert(method_name_constant->tag == CONSTANT_Utf8);
struct constant * method_descriptor_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1]; struct constant * method_descriptor_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
assert(method_descriptor_constant->tag == CONSTANT_Utf8); assert(method_descriptor_constant->tag == CONSTANT_Utf8);
@ -1665,7 +1662,6 @@ static struct arrayref * _multiarray(struct vm * vm, int32_t * dims, int num_dim
arrayref = prim_array_allocate(vm, element_size, count); arrayref = prim_array_allocate(vm, element_size, count);
} }
assert(arrayref != nullptr); assert(arrayref != nullptr);
arrayref->length = count;
arrayref->class_entry = nullptr; arrayref->class_entry = nullptr;
int32_t array_element_size = count * element_size; // bytes int32_t array_element_size = count * element_size; // bytes
@ -1749,7 +1745,6 @@ void op_newarray(struct vm * vm, uint32_t atype)
int32_t element_size = array_element_size(atype); int32_t element_size = array_element_size(atype);
struct arrayref * arrayref = prim_array_allocate(vm, element_size, count); struct arrayref * arrayref = prim_array_allocate(vm, element_size, count);
assert(arrayref != nullptr); assert(arrayref != nullptr);
arrayref->length = count;
arrayref->class_entry = nullptr; arrayref->class_entry = nullptr;
/* Each of the elements of the new array is initialized to the default initial /* Each of the elements of the new array is initialized to the default initial

View File

@ -1,9 +1,9 @@
#include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "file.h" #include "file.h"
#include "assert.h"
uint8_t * file_read(const char * path, size_t * file_size) uint8_t * file_read(const char * path, size_t * file_size)
{ {

166
c/frame.c
View File

@ -171,165 +171,35 @@ void vm_native_method_call(struct vm * vm, struct class_entry * class_entry, str
args[nargs - i - 1] = value; args[nargs - i - 1] = value;
} }
debugf("native:\n "); debugf("native: ");
struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->this_class - 1]; struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->this_class - 1];
assert(class_constant->tag == CONSTANT_Class);
struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1]; struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
assert(class_name_constant->tag == CONSTANT_Utf8);
debug_print__constant__utf8_string(class_name_constant); debug_print__constant__utf8_string(class_name_constant);
debugs(" "); debugs(" ");
struct constant * method_name_constant = &class_entry->class_file->constant_pool[method_entry->method_info->name_index - 1]; struct constant * method_name_constant = &class_entry->class_file->constant_pool[method_entry->method_info->name_index - 1];
assert(method_name_constant->tag == CONSTANT_Utf8);
debug_print__constant__utf8_string(method_name_constant); debug_print__constant__utf8_string(method_name_constant);
debugs(" ");
struct constant * method_descriptor_constant = &class_entry->class_file->constant_pool[method_entry->method_info->descriptor_index - 1];
assert(method_descriptor_constant->tag == CONSTANT_Utf8);
debug_print__constant__utf8_string(method_descriptor_constant);
debugc('\n'); debugc('\n');
int old_stack_ix = vm->current_frame->operand_stack_ix;
int java_lang_math_length = 14; native_method_call(vm,
bool java_lang_math = class_name_constant,
class_name_constant->utf8.length == java_lang_math_length && method_name_constant,
hash_table_key_equal(class_name_constant->utf8.bytes, (const uint8_t *)"java/lang/Math", class_name_constant->utf8.length); method_descriptor_constant,
if (java_lang_math) { args);
if (method_name_constant->utf8.length == 3) {
if (hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"sin", 3)) {
assert(nargs == 1);
assert(return_type == 'F');
uint32_t value = native_java_lang_math_sin_1(args);
operand_stack_push_u32(vm->current_frame, value);
return;
}
if (hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"cos", 3)) {
assert(nargs == 1);
assert(return_type == 'F');
uint32_t value = native_java_lang_math_cos_1(args);
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;
}
}
}
int java_misc_memory_length = 16; if (return_type != 'V') {
bool java_misc_memory = assert(old_stack_ix == vm->current_frame->operand_stack_ix - 1);
class_name_constant->utf8.length == java_misc_memory_length && } else {
hash_table_key_equal(class_name_constant->utf8.bytes, (const uint8_t *)"java/misc/Memory", class_name_constant->utf8.length); assert(old_stack_ix == vm->current_frame->operand_stack_ix);
if (java_misc_memory) {
if (method_name_constant->utf8.length == 5) {
if (hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"putU", 4)) {
assert(nargs == 2);
assert(return_type == 'V');
switch (method_name_constant->utf8.bytes[4]) {
case '4': native_java_misc_memory_putU4_2(args); break;
case '2': native_java_misc_memory_putU2_2(args); break;
case '1': native_java_misc_memory_putU1_2(args); break;
default: assert(false);
} }
return;
}
if (hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"getU", 4)) {
assert(nargs == 1);
assert(return_type == 'I');
uint32_t value;
switch (method_name_constant->utf8.bytes[4]) {
case '4': value = native_java_misc_memory_getU4_1(args); break;
case '2': value = native_java_misc_memory_getU2_1(args); break;
case '1': value = native_java_misc_memory_getU1_1(args); break;
default: assert(false);
}
operand_stack_push_u32(vm->current_frame, value);
return;
}
}
if (method_name_constant->utf8.length == 6) {
if (hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"putSQ", 5)) {
assert(nargs == 2);
assert(return_type == 'V');
switch (method_name_constant->utf8.bytes[5]) {
//case '2': value = native_java_misc_memory_putSQ2_2(args); break;
case '1': native_java_misc_memory_putSQ1_2(args); break;
default: assert(false);
}
return;
}
}
if (method_name_constant->utf8.length == 11) {
if (hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"isBigEndian", 11)) {
assert(nargs == 0);
assert(return_type == 'Z');
uint32_t value = native_java_misc_memory_isbigendian();
operand_stack_push_u32(vm->current_frame, value);
return;
}
}
}
int java_misc_resource_length = 18;
bool java_misc_resource =
class_name_constant->utf8.length == java_misc_resource_length &&
hash_table_key_equal(class_name_constant->utf8.bytes, (const uint8_t *)"java/misc/Resource", class_name_constant->utf8.length);
if (java_misc_resource) {
int getresource_length = 11;
bool getresource =
method_name_constant->utf8.length == getresource_length &&
hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"getResource", method_name_constant->utf8.length);
if (getresource) {
assert(nargs == 1);
assert(return_type == '[');
uint32_t value = java_misc_resource_getresource_1(args);
operand_stack_push_u32(vm->current_frame, value);
return;
}
}
int java_io_printstream_length = 19;
bool java_io_printstream =
class_name_constant->utf8.length == java_io_printstream_length &&
hash_table_key_equal(class_name_constant->utf8.bytes, (const uint8_t *)"java/io/PrintStream", class_name_constant->utf8.length);
if (java_io_printstream) {
int write_length = 5;
bool write =
method_name_constant->utf8.length == write_length &&
hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"write", method_name_constant->utf8.length);
if (write) {
if (nargs == 1) {
assert(return_type == 'V');
native_java_io_printstream_write_1(args);
return;
} else if (nargs == 2) {
assert(return_type == 'V');
native_java_io_printstream_write_2(args);
return;
}
}
}
int jvm_internal_loader_length = 19;
bool jvm_internal_loader =
class_name_constant->utf8.length == jvm_internal_loader_length &&
hash_table_key_equal(class_name_constant->utf8.bytes, (const uint8_t *)"jvm/internal/Loader", class_name_constant->utf8.length);
if (jvm_internal_loader) {
if (method_name_constant->utf8.length == 4) {
if (hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"load", 4)) {
assert(nargs == 2);
assert(return_type == 'V');
native_jvm_internal_loader_load(args);
return;
}
}
if (method_name_constant->utf8.length == 9) {
if (hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"getBuffer", 9)) {
assert(nargs == 0);
assert(return_type == 'I');
uint32_t value = native_jvm_internal_loader_getbuffer();
operand_stack_push_u32(vm->current_frame, value);
return;
}
}
}
assert(false);
} }
void vm_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry, int nargs, uint8_t return_type) void vm_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry, int nargs, uint8_t return_type)

View File

@ -35,7 +35,12 @@ struct vm {
int length; int length;
struct hash_table_entry * entry; struct hash_table_entry * entry;
} class_hash_table; } class_hash_table;
struct {
int length;
struct hash_table_entry * entry;
} native_hash_table;
}; };
static inline struct frame * stack_push_frame(struct stack * stack, int num_frames) static inline struct frame * stack_push_frame(struct stack * stack, int num_frames)
{ {
struct frame * frame = &stack->frame[stack->ix]; struct frame * frame = &stack->frame[stack->ix];

View File

@ -186,26 +186,100 @@ struct hash_table_entry * hash_table_find2(int hash_table_length,
return nullptr; return nullptr;
} }
/* struct hash_table_entry * hash_table_add3(int hash_table_length,
void hash_table_add_int(int hash_table_length,
struct hash_table_entry * entry, struct hash_table_entry * entry,
int key, const uint8_t * key1,
int key1_length,
const uint8_t * key2,
int key2_length,
const uint8_t * key3,
int key3_length,
void * value) void * value)
{ {
hash_table_add(hash_table_length, assert(hash_table_length != 0);
entry, assert((hash_table_length & (hash_table_length - 1)) == 0);
(const uint8_t *)&key, uint32_t hash = fnv_offset_basis;
4, hash = fnv_1(hash, key1, key1_length);
value); hash = fnv_1(hash, key2, key2_length);
hash = fnv_1(hash, key3, key3_length);
hash &= (hash_table_length - 1);
struct hash_table_entry * e = &entry[hash];
while (e->next != nullptr) {
e = e->next;
} }
struct hash_table_entry * hash_table_find_int(int hash_table_length, if (e->key != nullptr) {
struct hash_table_entry * entry, // allocate e from overflow
int key) e->next = malloc_class_arena((sizeof (struct hash_table_entry)));
{ e->next->key = nullptr;
return hash_table_find(hash_table_length, e->next->next = nullptr;
entry, e = e->next;
(const uint8_t *)&key, }
4);
uint8_t * key_copy = malloc_class_arena(key1_length + key2_length + key3_length);
for (int i = 0; i < key1_length; i++) key_copy[i] = key1[i];
for (int i = 0; i < key2_length; i++) key_copy[key1_length + i] = key2[i];
for (int i = 0; i < key3_length; i++) key_copy[key1_length + key2_length + i] = key3[i];
e->key = key_copy;
e->key_length = key1_length + key2_length + key3_length;
e->value = value;
return e;
}
static inline bool key_equal3(const uint8_t * a1, int a1_length,
const uint8_t * a2, int a2_length,
const uint8_t * a3, int a3_length,
const uint8_t * b)
{
for (int i = 0; i < a1_length; i++) {
if (a1[i] != b[i])
return false;
}
for (int i = 0; i < a2_length; i++) {
if (a2[i] != b[a1_length + i])
return false;
}
for (int i = 0; i < a3_length; i++) {
if (a3[i] != b[a1_length + a2_length + i])
return false;
}
return true;
}
struct hash_table_entry * hash_table_find3(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key1,
int key1_length,
const uint8_t * key2,
int key2_length,
const uint8_t * key3,
int key3_length)
{
if (hash_table_length == 0)
return nullptr;
assert((hash_table_length & (hash_table_length - 1)) == 0);
uint32_t hash = fnv_offset_basis;
hash = fnv_1(hash, key1, key1_length);
hash = fnv_1(hash, key2, key2_length);
hash = fnv_1(hash, key3, key3_length);
hash &= (hash_table_length - 1);
struct hash_table_entry * e = &entry[hash];
while (e != nullptr && e->key != nullptr) {
bool equal =
e->key_length == (key1_length + key2_length + key3_length) &&
key_equal3(key1, key1_length,
key2, key2_length,
key3, key3_length,
e->key);
if (equal) {
return e;
}
e = e->next;
}
return nullptr;
} }
*/

View File

@ -40,6 +40,25 @@ struct hash_table_entry * hash_table_find2(int hash_table_length,
const uint8_t * key2, const uint8_t * key2,
int key2_length); int key2_length);
struct hash_table_entry * hash_table_add3(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key1,
int key1_length,
const uint8_t * key2,
int key2_length,
const uint8_t * key3,
int key3_length,
void * value);
struct hash_table_entry * hash_table_find3(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key1,
int key1_length,
const uint8_t * key2,
int key2_length,
const uint8_t * key3,
int key3_length);
static inline bool hash_table_key_equal(const uint8_t * a, const uint8_t * b, int length) static inline bool hash_table_key_equal(const uint8_t * a, const uint8_t * b, int length)
{ {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {

View File

@ -1,5 +1,4 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "printf.h" #include "printf.h"
#include "frame.h" #include "frame.h"
@ -11,6 +10,8 @@
#include "backtrace.h" #include "backtrace.h"
#include "gc.h" #include "gc.h"
void * memset(void * s, int c, size_t n);
static struct hash_table_entry * load_from_filenames(const char * filenames[], int length, int * hash_table_length) static struct hash_table_entry * load_from_filenames(const char * filenames[], int length, int * hash_table_length)
{ {
uint8_t * buffers[length]; uint8_t * buffers[length];

View File

@ -1,166 +1,144 @@
#include "native.h" #include "native.h"
#include "printf.h" #include "native/math.h"
#include "string.h" #include "native/memory.h"
#include "malloc.h" #include "native/.h"
#include "memory_allocator.h" #include "native/loader.h"
#include "class_resolver.h"
#include "frame.h"
void native_java_io_printstream_write_1(uint32_t * args) typedef void (native_func_t*)(struct vm * vm, uint32_t * args);
struct native_method {
const char * class_name;
const char * method_name;
const char * method_descriptor;
native_func_t func;
};
const static struct native_method native_method[] = {
{ {
struct arrayref * arrayref = (struct arrayref *)args[0]; .class_name = "java/lang/Math",
print_string((const char *)arrayref->u8, arrayref->length); .method_name = "sin",
.method_descriptor = "(F)F",
.func = native_java_lang_math_sin_1,
},
{
.class_name = "java/lang/Math",
.method_name = "cos",
.method_descriptor = "(F)F",
.func = native_java_lang_math_cos_1,
},
{
.class_name = "javva/lang/Math",
.method_name = "abs",
.method_descriptor = "(F)F",
.func = native_java_lang_math_abs_1,
},
{
.class_name = "java/misc/Memory",
.method_name = "putU4",
.method_descriptor = "(II)V",
.func = native_java_misc_memory_putU4_2,
},
{
.class_name = "java/misc/Memory",
.method_name = "putU2",
.method_descriptor = "(II)V",
.func = native_java_misc_memory_putU2_2,
},
{
.class_name = "java/misc/Memory",
.method_name = "putU1",
.method_descriptor = "(II)V",
.func = native_java_misc_memory_putU1_2,
},
{
.class_name = "java/misc/Memory",
.method_name = "getU4",
.method_descriptor = "(I)I",
.func = native_java_misc_memory_getU4_1,
},
{
.class_name = "java/misc/Memory",
.method_name = "getU2",
.method_descriptor = "(I)I",
.func = native_java_misc_memory_getU2_1,
},
{
.class_name = "java/misc/Memory",
.method_name = "getU1",
.method_descriptor = "(I)I",
.func = native_java_misc_memory_getU1_1,
},
{
.class_name = "java/misc/Memory",
.method_name = "putSQ1",
.method_descriptor = "(Ljava/lang/Object;I)V",
.func = native_java_misc_memory_putSQ1_2,
},
{
.class_name = "java/misc/Memory",
.method_name = "isBigEndian",
.method_descriptor = "()Z",
.func = native_java_misc_memory_isbigendian_0,
},
{
.class_name = "java/io/PrintStream",
.method_name = "write",
.method_descriptor = "([B)V",
},
{
.class_name = "jvm/internal/Loader",
.method_name = "load",
.method_descriptor = "([II)V",
.func = native_jvm_internal_loader_load_2,
},
{
.class_name = "jvm/internal/Loader",
.method_name = "getBuffer",
.method_descriptor = "()I",
.func = native_jvm_internal_loader_getbuffer_0,
},
};
void native_init_hash_table(struct vm * vm)
{
int native_length = (sizeof (native_method)) / (sizeof (native_method[0]));
int native_hash_table_length = hash_table_next_power_of_two(native_length * 2);
uint32_t native_hash_table_size = (sizeof (struct hash_table_entry)) * native_hash_table_length;
struct hash_table_entry * native_hash_table = malloc_native_arena(native_hash_table_size);
hash_table_init(native_hash_table_length, native_hash_table);
for (int i = 0; i < native_length; i++) {
int class_name_length = string_length(native_method[i].class_name);
int method_name_length = string_length(native_method[i].method_name);
int method_descriptor_length = string_length(native_method[i].method_descriptor);
hash_table_add3(native_hash_table_length,
native_hash_table,
native_method[i].class_name,
class_name_length,
native_method[i].method_name,
method_name_length,
native_method[i].method_descriptor,
method_descriptor_length,
&native_method[i]
);
} }
void native_java_io_printstream_write_2(uint32_t * args) vm->native_hash_table.length = native_hash_table_length;
{ vm->native_hash_table.entry = native_hash_table;
//uint32_t this = args[0];
struct arrayref * arrayref = (struct arrayref *)args[1];
print_string((const char *)arrayref->u8, arrayref->length);
} }
void native_java_misc_memory_putU4_2(uint32_t * args) void native_method_call(struct vm * vm,
struct constant * class_name_constant,
struct constant * method_name_constant,
struct constant * method_descriptor_constant,
uint32_t * args)
{ {
uint32_t * address = (uint32_t *)args[0]; struct hash_table_entry * e = hash_table_find3(vm->native_hash_table.length,
uint32_t value = args[1]; vm->native_hash_table.entry,
*address = value; class_name_constant,
} class_name_length);
assert(e != nullptr);
void native_java_misc_memory_putU2_2(uint32_t * args) assert(e->value != nullptr);
{
uint16_t * address = (uint16_t *)args[0];
uint16_t value = args[1];
*address = value;
}
void native_java_misc_memory_putU1_2(uint32_t * args)
{
uint8_t * address = (uint8_t *)args[0];
uint8_t value = args[1];
*address = value;
}
uint32_t native_java_misc_memory_getU4_1(uint32_t * args)
{
uint32_t * address = (uint32_t *)args[0];
uint32_t value = *address;
return value;
}
uint32_t native_java_misc_memory_getU2_1(uint32_t * args)
{
uint16_t * address = (uint16_t *)args[0];
uint16_t value = *address;
return value;
}
uint32_t native_java_misc_memory_getU1_1(uint32_t * args)
{
uint8_t * address = (uint8_t *)args[0];
uint8_t value = *address;
return value;
}
extern uint32_t store_queue[0x4000000] __asm("store_queue");
void native_java_misc_memory_putSQ1_2(uint32_t * args)
{
#if defined(__dreamcast__)
struct objectref * objectref = (struct objectref *)args[0];
uint32_t address = (uint32_t)args[1];
store_queue[0] = objectref->u32[0];
store_queue[1] = objectref->u32[1];
store_queue[2] = objectref->u32[2];
store_queue[3] = objectref->u32[3];
store_queue[4] = objectref->u32[4];
store_queue[5] = objectref->u32[5];
store_queue[6] = objectref->u32[6];
store_queue[7] = objectref->u32[7];
*((uint32_t*)0xff000038) = ((address >> 26) & 0b111) << 2;
__asm__ volatile ("pref @%0"
: // output
: "r" (&store_queue[0]) // input
: "memory");
#endif
}
uint32_t __attribute__ ((noinline)) __attribute__ ((optimize(0)))
native_java_lang_math_sin_1(uint32_t * args)
{
float arg = ((float *)args)[0];
float value = __builtin_sinf(arg);
return *((uint32_t *)&value);
}
uint32_t __attribute__ ((noinline)) __attribute__ ((optimize(0)))
native_java_lang_math_cos_1(uint32_t * args)
{
float arg = ((float *)args)[0];
float value = __builtin_cosf(arg);
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
uint32_t java_misc_resource_getresource_1(uint32_t * args)
{
struct objectref * objectref = (struct objectref *)args[0];
struct arrayref * arrayref = objectref->aref[0];
#if defined(__dreamcast__)
uint32_t resource = find_resource(arrayref->u8, arrayref->length);
return resource;
#else
(void)arrayref;
return 0;
#endif
}
uint32_t native_java_misc_memory_isbigendian()
{
return (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
}
static uint8_t loader_buffer[0x100000] __attribute__ ((aligned (32)));
uint32_t native_jvm_internal_loader_getbuffer()
{
return (uint32_t)&loader_buffer[0];
}
extern struct vm vm;
void native_jvm_internal_loader_load(uint32_t * args)
{
struct arrayref * arrayref = (struct arrayref *)args[0];
const uint8_t ** buffers = (const uint8_t **)&arrayref->u32[0];
int32_t num_buffers = (int32_t)args[1];
printf("num_buffers: %d\n", num_buffers);
printf("loader_buffer[0]: %p ; buffers[0]: %p\n", &loader_buffer[0], (uint32_t)buffers[0]);
const uint8_t * main_class = (const uint8_t *)"Main";
int main_class_length = string_length((const char *)main_class);
memory_reset_free_list();
malloc_class_arena_reset();
int class_hash_table_length;
struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers(buffers,
num_buffers,
&class_hash_table_length);
vm_start(class_hash_table_length,
class_hash_table,
main_class,
main_class_length);
} }

View File

@ -1,21 +1 @@
#pragma once #pragma once
#include <stdint.h>
void native_java_io_printstream_write(uint32_t * arrayref);
void native_java_io_printstream_write_1(uint32_t * args);
void native_java_io_printstream_write_2(uint32_t * args);
void native_java_misc_memory_putU4_2(uint32_t * args);
void native_java_misc_memory_putU2_2(uint32_t * args);
void native_java_misc_memory_putU1_2(uint32_t * args);
uint32_t native_java_misc_memory_getU4_1(uint32_t * args);
uint32_t native_java_misc_memory_getU2_1(uint32_t * args);
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();
void native_jvm_internal_loader_load(uint32_t * args);

41
c/native/loader.c Normal file
View File

@ -0,0 +1,41 @@
#include "native_types.h"
#include "internal.h"
#include "printf.h"
#include "string.h"
#include "malloc.h"
#include "frame.h"
static uint8_t loader_buffer[0x100000] __attribute__ ((aligned (32)));
void native_jvm_internal_loader_getbuffer_0(struct vm * vm, uint32_t * args)
{
uint32_t value = (uint32_t)&loader_buffer[0];
operand_stack_push_u32(vm->current_frame, value);
}
extern struct vm vm;
void native_jvm_internal_loader_load_2(struct vm * vm, uint32_t * args)
{
struct arrayref * arrayref = (struct arrayref *)args[0];
const uint8_t ** buffers = (const uint8_t **)&arrayref->u32[0];
int32_t num_buffers = (int32_t)args[1];
debugf("num_buffers: %d\n", num_buffers);
debugf("loader_buffer[0]: %p ; buffers[0]: %p\n", &loader_buffer[0], (uint32_t)buffers[0]);
const uint8_t * main_class = (const uint8_t *)"Main";
int main_class_length = string_length((const char *)main_class);
memory_reset_free_list();
malloc_class_arena_reset();
int class_hash_table_length;
struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers(buffers,
num_buffers,
&class_hash_table_length);
vm_start(class_hash_table_length,
class_hash_table,
main_class,
main_class_length);
}

6
c/native/loader.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <stdint.h>
void native_jvm_internal_loader_getbuffer_0(struct vm * vm, uint32_t * args);
void native_jvm_internal_loader_load_2(struct vm * vm, uint32_t * args);

24
c/native/math.c Normal file
View File

@ -0,0 +1,24 @@
#include "math.h"
void __attribute__ ((noinline)) __attribute__ ((optimize(0)))
native_java_lang_math_sin_1(struct vm * vm, uint32_t * args)
{
float arg = ((float *)args)[0];
float value = __builtin_sinf(arg);
operand_stack_push_u32(vm->current_frame, value);
}
void __attribute__ ((noinline)) __attribute__ ((optimize(0)))
native_java_lang_math_cos_1(struct vm * vm, uint32_t * args)
{
float arg = ((float *)args)[0];
float value = __builtin_cosf(arg);
operand_stack_push_u32(vm->current_frame, value);
}
void native_java_lang_math_abs_1(struct vm * vm, uint32_t * args)
{
float arg = ((float *)args)[0];
float value = __builtin_fabsf(arg);
operand_stack_push_u32(vm->current_frame, value);
}

9
c/native/math.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <stdint.h>
#include "frame.h"
void native_java_lang_math_sin_1(struct vm * vm, uint32_t * args);
void native_java_lang_math_cos_1(struct vm * vm, uint32_t * args);
void native_java_lang_math_abs_1(struct vm * vm, uint32_t * args);

75
c/native/memory.c Normal file
View File

@ -0,0 +1,75 @@
#include "native_types.h"
#include "memory.h"
void native_java_misc_memory_putU4_2(struct vm * vm, uint32_t * args)
{
uint32_t * address = (uint32_t *)args[0];
uint32_t value = args[1];
*address = value;
}
void native_java_misc_memory_putU2_2(struct vm * vm, uint32_t * args)
{
uint16_t * address = (uint16_t *)args[0];
uint16_t value = args[1];
*address = value;
}
void native_java_misc_memory_putU1_2(struct vm * vm, uint32_t * args)
{
uint8_t * address = (uint8_t *)args[0];
uint8_t value = args[1];
*address = value;
}
void native_java_misc_memory_getU4_1(struct vm * vm, uint32_t * args)
{
uint32_t * address = (uint32_t *)args[0];
uint32_t value = *address;
operand_stack_push_u32(vm->current_frame, value);
}
void native_java_misc_memory_getU2_1(struct vm * vm, uint32_t * args)
{
uint16_t * address = (uint16_t *)args[0];
uint16_t value = *address;
operand_stack_push_u32(vm->current_frame, value);
}
void native_java_misc_memory_getU1_1(struct vm * vm, uint32_t * args)
{
uint8_t * address = (uint8_t *)args[0];
uint8_t value = *address;
operand_stack_push_u32(vm->current_frame, value);
}
extern uint32_t store_queue[0x4000000] __asm("store_queue");
void native_java_misc_memory_putSQ1_2(struct vm * vm, uint32_t * args)
{
#if defined(__dreamcast__)
struct objectref * objectref = (struct objectref *)args[0];
uint32_t address = (uint32_t)args[1];
store_queue[0] = objectref->u32[0];
store_queue[1] = objectref->u32[1];
store_queue[2] = objectref->u32[2];
store_queue[3] = objectref->u32[3];
store_queue[4] = objectref->u32[4];
store_queue[5] = objectref->u32[5];
store_queue[6] = objectref->u32[6];
store_queue[7] = objectref->u32[7];
*((uint32_t*)0xff000038) = ((address >> 26) & 0b111) << 2;
__asm__ volatile ("pref @%0"
: // output
: "r" (&store_queue[0]) // input
: "memory");
#endif
}
void native_java_misc_memory_isbigendian_0(struct vm * vm, uint32_t * args)
{
uint32_t value = (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
operand_stack_push_u32(vm->current_frame, value);
}

14
c/native/memory.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include <stdint.h>
#include "frame.h"
void native_java_misc_memory_putU4_2(struct vm * vm, uint32_t * args);
void native_java_misc_memory_putU2_2(struct vm * vm, uint32_t * args);
void native_java_misc_memory_putU1_2(struct vm * vm, uint32_t * args);
void native_java_misc_memory_getU4_1(struct vm * vm, uint32_t * args);
void native_java_misc_memory_getU2_1(struct vm * vm, uint32_t * args);
void native_java_misc_memory_getU1_1(struct vm * vm, uint32_t * args);
void native_java_misc_memory_putSQ1_2(struct vm * vm, uint32_t * args);
void native_java_misc_memory_isbigendian_0(struct vm * vm, uint32_t * args);

9
c/native/printstream.c Normal file
View File

@ -0,0 +1,9 @@
#include "native_types.h"
#include "printstream.h"
#include "printf.h"
void native_java_io_printstream_write_1(struct vm * vm, uint32_t * args)
{
struct arrayref * arrayref = (struct arrayref *)args[0];
print_string((const char *)arrayref->u8, arrayref->length);
}

7
c/native/printstream.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
#include "frame.h"
void native_java_io_printstream_write_1(struct vm * vm, uint32_t * args);

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <assert.h>
#include "assert.h"
#include "class_resolver.h" #include "class_resolver.h"
#include "memory_allocator.h" #include "memory_allocator.h"

View File

@ -21,6 +21,7 @@ static inline struct arrayref * prim_array_allocate(struct vm * vm, int element_
if (arrayref != nullptr) { if (arrayref != nullptr) {
arrayref->tag.type = TAG_TYPE_PRIM_ARRAY; arrayref->tag.type = TAG_TYPE_PRIM_ARRAY;
arrayref->tag.mark = 0; arrayref->tag.mark = 0;
arrayref->length = count;
} }
return arrayref; return arrayref;
} }
@ -32,6 +33,7 @@ static inline struct arrayref * ref_array_allocate(struct vm * vm, int count)
if (arrayref != nullptr) { if (arrayref != nullptr) {
arrayref->tag.type = TAG_TYPE_REF_ARRAY; arrayref->tag.type = TAG_TYPE_REF_ARRAY;
arrayref->tag.mark = 0; arrayref->tag.mark = 0;
arrayref->length = count;
} }
return arrayref; return arrayref;
} }

View File

@ -1,8 +1,8 @@
#include <stdio.h> #include <stdio.h>
#include <stddef.h> #include <stddef.h>
#include <assert.h>
#include "hash_table.h" #include "hash_table.h"
#include "assert.h"
static const char * names[] = { static const char * names[] = {
"java/beans/Introspector.java", "java/beans/Introspector.java",

23
c/vm_instance.c Normal file
View File

@ -0,0 +1,23 @@
#include "string.h"
#include "native_types_allocate.h"
#include "vm_instance.h"
struct objectref * vm_instance_create(struct vm * vm, const char * class_name)
{
struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
vm->class_hash_table.entry,
(const uint8_t *)class_name,
string_length(class_name));
assert(class_entry != nullptr);
struct objectref * objectref = obj_allocate(vm, class_entry->instance_fields_count);
if (objectref != nullptr) {
objectref->class_entry = class_entry;
for (int i = 0; i < class_entry->instance_fields_count; i++) {
objectref->oref[i] = nullptr;
}
}
return objectref;
}

5
c/vm_instance.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include "frame.h"
struct objectref * vm_instance_create(struct vm * vm, const char * class_name);

View File

@ -0,0 +1,18 @@
package java.lang;
public class Class {
private Object object;
private String name;
private Class() {
}
private native String getClassName();
public String getName() {
if (this.name == null) {
this.name = getClassName();
}
return this.name;
}
}

View File

@ -3,7 +3,12 @@ package java.lang;
public class Object { public class Object {
public Object() {} public Object() {}
public final native Class getClass();
public native int hashCode();
public String toString() { public String toString() {
return "Object"; return null;
//return getClass().getName() + "@" + Integer.toString(hashCode());
} }
} }

View File

@ -12,7 +12,4 @@ public class Memory {
public static native void putSQ1(Object object, int address); public static native void putSQ1(Object object, int address);
public static native boolean isBigEndian(); public static native boolean isBigEndian();
// .length of the returned byte array must not be accessed
public static native byte[] wrapAddress(int address);
} }

View File

@ -0,0 +1,24 @@
package test;
class Test<T> {
T obj;
Test(T obj) {
this.obj = obj;
}
public T getObject() {
return this.obj;
}
}
class TestGeneric {
public static void main(String[] args)
{
Test<Integer> ti = new Test<Integer>(15);
System.out.println(ti.getObject());
Test<String> ts = new Test<String>("GeeksForGeeks");
System.out.println(ts.getObject());
}
}

39
java.mk
View File

@ -6,25 +6,30 @@
javac -Xlint:-options --source 8 --target 8 --boot-class-path . $(<:classes/%=%) javac -Xlint:-options --source 8 --target 8 --boot-class-path . $(<:classes/%=%)
OBJ = \ OBJ = \
c/decode.o \
c/class_file.o \
c/debug_class_file.o \
c/malloc.o \
c/execute.o \
c/memory_allocator.o \
c/class_resolver.o \
c/hash_table.o \
c/frame.o \
c/printf.o \
c/parse.o \
c/unparse.o \
c/native.o \
c/debug.o \
c/fatal.o \
c/parse_type.o \
c/backtrace.o \ c/backtrace.o \
c/class_file.o \
c/class_resolver.o \
c/debug.o \
c/debug_class_file.o \
c/decode.o \
c/execute.o \
c/fatal.o \
c/find_attribute.o \ c/find_attribute.o \
c/gc.o c/frame.o \
c/gc.o \
c/hash_table.o \
c/malloc.o \
c/memory_allocator.o \
c/native.o \
c/native/internal.o \
c/native/math.o \
c/native/memory.o \
c/native/printstream.o \
c/parse.o \
c/parse_type.o \
c/printf.o \
c/unparse.o \
c/vm_instance.o
MAIN_DREAMCAST_OBJ = \ MAIN_DREAMCAST_OBJ = \
c/main_dreamcast.o \ c/main_dreamcast.o \