native: lookup native methods by hash table entry

This commit is contained in:
Zack Buhman 2025-01-10 17:51:57 -06:00
parent d1483a0c15
commit aaa55a4f9d
41 changed files with 756 additions and 509 deletions

View File

@ -3,11 +3,14 @@
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)/
CFLAGS += -I$(MAKEFILE_PATH)/c
CFLAGS += -DDEBUG CFLAGS += -DDEBUG
#CFLAGS += -DDEBUG_PRINT CFLAGS += -DDEBUG_PRINT
LDFLAGS = -lm LDFLAGS = -lm
OPT ?= -O0 OPT ?= -O0
DEPFLAGS = -MMD -MP DEPFLAGS = -MMD -MP
@ -22,7 +25,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,8 +7,9 @@ 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 += -I$(MAKEFILE_PATH)/
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

@ -1,25 +1,25 @@
#include "example/GdromClassLoader.class.h" #include "classes/example/GdromClassLoader.class.h"
#include "example/GdromDirectoryRecordHandler.class.h" #include "classes/example/GdromDirectoryRecordHandler.class.h"
#include "filesystem/iso9660/ByteParser.class.h" #include "classes/filesystem/iso9660/ByteParser.class.h"
#include "filesystem/iso9660/DirectoryRecord.class.h" #include "classes/filesystem/iso9660/DirectoryRecord.class.h"
#include "filesystem/iso9660/ExtentReader.class.h" #include "classes/filesystem/iso9660/ExtentReader.class.h"
#include "filesystem/iso9660/PrimaryVolumeDescriptor.class.h" #include "classes/filesystem/iso9660/PrimaryVolumeDescriptor.class.h"
#include "filesystem/iso9660/VolumeParser.class.h" #include "classes/filesystem/iso9660/VolumeParser.class.h"
#include "java/io/PrintStream.class.h" #include "classes/java/io/PrintStream.class.h"
#include "java/lang/DecimalDigits.class.h" #include "classes/java/lang/DecimalDigits.class.h"
#include "java/lang/Integer.class.h" #include "classes/java/lang/Integer.class.h"
#include "java/lang/Object.class.h" #include "classes/java/lang/Object.class.h"
#include "java/lang/String.class.h" #include "classes/java/lang/String.class.h"
#include "java/lang/System.class.h" #include "classes/java/lang/System.class.h"
#include "java/misc/Memory.class.h" #include "classes/java/misc/Memory.class.h"
#include "sega/dreamcast/gdrom/G1IF.class.h" #include "classes/sega/dreamcast/gdrom/G1IF.class.h"
#include "sega/dreamcast/gdrom/GdromIF.class.h" #include "classes/sega/dreamcast/gdrom/GdromIF.class.h"
#include "sega/dreamcast/gdrom/GdromBits.class.h" #include "classes/sega/dreamcast/gdrom/GdromBits.class.h"
#include "sega/dreamcast/gdrom/Gdrom.class.h" #include "classes/sega/dreamcast/gdrom/Gdrom.class.h"
#include "sega/dreamcast/gdrom/GdromExtentReader.class.h" #include "classes/sega/dreamcast/gdrom/GdromExtentReader.class.h"
#include "sega/dreamcast/gdrom/GdromCommandPacketFormat_cd_read.class.h" #include "classes/sega/dreamcast/gdrom/GdromCommandPacketFormat_cd_read.class.h"
#include "sega/dreamcast/gdrom/GdromCommandPacketFormat.class.h" #include "classes/sega/dreamcast/gdrom/GdromCommandPacketFormat.class.h"
#include "sega/dreamcast/gdrom/GdromCommandPacketFormat_get_toc.class.h" #include "classes/sega/dreamcast/gdrom/GdromCommandPacketFormat_get_toc.class.h"
#include "sega/dreamcast/gdrom/GdromCommandPacketInterface.class.h" #include "classes/sega/dreamcast/gdrom/GdromCommandPacketInterface.class.h"
#include "sega/dreamcast/gdrom/GdromProtocol.class.h" #include "classes/sega/dreamcast/gdrom/GdromProtocol.class.h"
#include "jvm/internal/Loader.class.h" #include "classes/jvm/internal/Loader.class.h"

View File

@ -1,25 +1,25 @@
(const uint8_t *)&_binary_example_GdromClassLoader_class_start, (const uint8_t *)&_binary_classes_example_GdromClassLoader_class_start,
(const uint8_t *)&_binary_example_GdromDirectoryRecordHandler_class_start, (const uint8_t *)&_binary_classes_example_GdromDirectoryRecordHandler_class_start,
(const uint8_t *)&_binary_filesystem_iso9660_ByteParser_class_start, (const uint8_t *)&_binary_classes_filesystem_iso9660_ByteParser_class_start,
(const uint8_t *)&_binary_filesystem_iso9660_DirectoryRecord_class_start, (const uint8_t *)&_binary_classes_filesystem_iso9660_DirectoryRecord_class_start,
(const uint8_t *)&_binary_filesystem_iso9660_ExtentReader_class_start, (const uint8_t *)&_binary_classes_filesystem_iso9660_ExtentReader_class_start,
(const uint8_t *)&_binary_filesystem_iso9660_PrimaryVolumeDescriptor_class_start, (const uint8_t *)&_binary_classes_filesystem_iso9660_PrimaryVolumeDescriptor_class_start,
(const uint8_t *)&_binary_filesystem_iso9660_VolumeParser_class_start, (const uint8_t *)&_binary_classes_filesystem_iso9660_VolumeParser_class_start,
(const uint8_t *)&_binary_java_io_PrintStream_class_start, (const uint8_t *)&_binary_classes_java_io_PrintStream_class_start,
(const uint8_t *)&_binary_java_lang_DecimalDigits_class_start, (const uint8_t *)&_binary_classes_java_lang_DecimalDigits_class_start,
(const uint8_t *)&_binary_java_lang_Integer_class_start, (const uint8_t *)&_binary_classes_java_lang_Integer_class_start,
(const uint8_t *)&_binary_java_lang_Object_class_start, (const uint8_t *)&_binary_classes_java_lang_Object_class_start,
(const uint8_t *)&_binary_java_lang_String_class_start, (const uint8_t *)&_binary_classes_java_lang_String_class_start,
(const uint8_t *)&_binary_java_lang_System_class_start, (const uint8_t *)&_binary_classes_java_lang_System_class_start,
(const uint8_t *)&_binary_java_misc_Memory_class_start, (const uint8_t *)&_binary_classes_java_misc_Memory_class_start,
(const uint8_t *)&_binary_sega_dreamcast_gdrom_G1IF_class_start, (const uint8_t *)&_binary_classes_sega_dreamcast_gdrom_G1IF_class_start,
(const uint8_t *)&_binary_sega_dreamcast_gdrom_GdromIF_class_start, (const uint8_t *)&_binary_classes_sega_dreamcast_gdrom_GdromIF_class_start,
(const uint8_t *)&_binary_sega_dreamcast_gdrom_GdromBits_class_start, (const uint8_t *)&_binary_classes_sega_dreamcast_gdrom_GdromBits_class_start,
(const uint8_t *)&_binary_sega_dreamcast_gdrom_Gdrom_class_start, (const uint8_t *)&_binary_classes_sega_dreamcast_gdrom_Gdrom_class_start,
(const uint8_t *)&_binary_sega_dreamcast_gdrom_GdromExtentReader_class_start, (const uint8_t *)&_binary_classes_sega_dreamcast_gdrom_GdromExtentReader_class_start,
(const uint8_t *)&_binary_sega_dreamcast_gdrom_GdromCommandPacketFormat_cd_read_class_start, (const uint8_t *)&_binary_classes_sega_dreamcast_gdrom_GdromCommandPacketFormat_cd_read_class_start,
(const uint8_t *)&_binary_sega_dreamcast_gdrom_GdromCommandPacketFormat_class_start, (const uint8_t *)&_binary_classes_sega_dreamcast_gdrom_GdromCommandPacketFormat_class_start,
(const uint8_t *)&_binary_sega_dreamcast_gdrom_GdromCommandPacketFormat_get_toc_class_start, (const uint8_t *)&_binary_classes_sega_dreamcast_gdrom_GdromCommandPacketFormat_get_toc_class_start,
(const uint8_t *)&_binary_sega_dreamcast_gdrom_GdromCommandPacketInterface_class_start, (const uint8_t *)&_binary_classes_sega_dreamcast_gdrom_GdromCommandPacketInterface_class_start,
(const uint8_t *)&_binary_sega_dreamcast_gdrom_GdromProtocol_class_start, (const uint8_t *)&_binary_classes_sega_dreamcast_gdrom_GdromProtocol_class_start,
(const uint8_t *)&_binary_jvm_internal_Loader_class_start, (const uint8_t *)&_binary_classes_jvm_internal_Loader_class_start,

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,13 +1,15 @@
#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"
#include "printf.h"
uint8_t * file_read(const char * path, size_t * file_size) uint8_t * file_read(const char * path, size_t * file_size)
{ {
int ret; int ret;
debugf("file_read: ", path);
FILE * f = fopen(path, "rb"); FILE * f = fopen(path, "rb");
assert(f != nullptr); assert(f != nullptr);
ret = fseek(f, 0L, SEEK_END); ret = fseek(f, 0L, SEEK_END);

170
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)
@ -587,6 +457,8 @@ void vm_execute(struct vm * vm)
struct vm * vm_start(int class_hash_table_length, struct vm * vm_start(int class_hash_table_length,
struct hash_table_entry * class_hash_table, struct hash_table_entry * class_hash_table,
int native_hash_table_length,
struct hash_table_entry * native_hash_table,
const uint8_t * main_class_name, const uint8_t * main_class_name,
int main_class_name_length) int main_class_name_length)
{ {
@ -611,6 +483,8 @@ struct vm * vm_start(int class_hash_table_length,
static struct vm vm; static struct vm vm;
vm.class_hash_table.length = class_hash_table_length; vm.class_hash_table.length = class_hash_table_length;
vm.class_hash_table.entry = class_hash_table; vm.class_hash_table.entry = class_hash_table;
vm.native_hash_table.length = native_hash_table_length;
vm.native_hash_table.entry = native_hash_table;
vm.frame_stack.ix = 0; vm.frame_stack.ix = 0;
vm.frame_stack.capacity = 1024; vm.frame_stack.capacity = 1024;

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];
@ -185,6 +190,8 @@ void vm_method_return(struct vm * vm);
void vm_execute(struct vm * vm); void vm_execute(struct vm * vm);
struct vm * vm_start(int class_hash_table_length, struct vm * vm_start(int class_hash_table_length,
struct hash_table_entry * class_hash_table, struct hash_table_entry * class_hash_table,
int native_hash_table_length,
struct hash_table_entry * native_hash_table,
const uint8_t * main_class_name, const uint8_t * main_class_name,
int main_class_name_length); int main_class_name_length);
int descriptor_nargs(struct constant * descriptor_constant, uint8_t * return_type); int descriptor_nargs(struct constant * descriptor_constant, uint8_t * return_type);

View File

@ -186,26 +186,105 @@ 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);
printf("hash: %d %u %p\n", hash_table_length, hash, value);
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);
printf("hash: %d %u\n", hash_table_length, hash);
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

@ -2,15 +2,13 @@
#include "string.h" #include "string.h"
#include "class_resolver.h" #include "class_resolver.h"
#include "frame.h" #include "native.h"
#include "printf.h"
#include "malloc.h" #include "malloc.h"
#include "memory_allocator.h"
#include "sh7091_scif.h"
#include "classpath.h" #include "classpath.h"
#include "sh7091_scif.h"
void main() void main()
{ {
scif_init(0); scif_init(0);
@ -36,9 +34,15 @@ void main()
class_file_buffers_length, class_file_buffers_length,
&class_hash_table_length); &class_hash_table_length);
int native_hash_table_length;
struct hash_table_entry * native_hash_table = native_init_hash_table(&native_hash_table_length);
struct vm * vm = vm_start(class_hash_table_length, struct vm * vm = vm_start(class_hash_table_length,
class_hash_table, class_hash_table,
native_hash_table_length,
native_hash_table,
main_class, main_class,
main_class_length); main_class_length);
vm_execute(vm); vm_execute(vm);
} }

View File

@ -1,15 +1,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "printf.h" #include "printf.h"
#include "frame.h"
#include "class_resolver.h" #include "class_resolver.h"
#include "string.h" #include "string.h"
#include "file.h" #include "file.h"
#include "malloc.h" #include "malloc.h"
#include "native.h"
#include "memory_allocator.h" #include "memory_allocator.h"
#include "backtrace.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)
{ {
@ -49,15 +48,17 @@ int main(int argc, const char * argv[])
int class_hash_table_length; int class_hash_table_length;
struct hash_table_entry * class_hash_table = load_from_filenames(class_filenames, num_class_filenames, &class_hash_table_length); struct hash_table_entry * class_hash_table = load_from_filenames(class_filenames, num_class_filenames, &class_hash_table_length);
int native_hash_table_length;
struct hash_table_entry * native_hash_table = native_init_hash_table(&native_hash_table_length);
debugf("vm_start\n"); debugf("vm_start\n");
struct vm * vm = vm_start(class_hash_table_length, struct vm * vm = vm_start(class_hash_table_length,
class_hash_table, class_hash_table,
native_hash_table_length,
native_hash_table,
main_class, main_class,
main_class_length); main_class_length);
vm_execute(vm); vm_execute(vm);
gc_mark(vm);
gc_sweep();
} }

View File

@ -1,166 +1,168 @@
#include "native.h" #include "hash_table.h"
#include "printf.h"
#include "string.h"
#include "malloc.h" #include "malloc.h"
#include "memory_allocator.h" #include "string.h"
#include "class_resolver.h" #include "printf.h"
#include "frame.h" #include "native.h"
#include "native/math.h"
#include "native/memory.h"
#include "native/printstream.h"
#include "native/loader.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",
.func = native_java_io_printstream_write_1,
},
{
.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,
},
};
struct hash_table_entry * native_init_hash_table(int * hash_table_length)
{
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_class_arena(native_hash_table_size);
hash_table_init(native_hash_table_length, native_hash_table);
for (int i = 0; i < native_length; i++) {
assert(native_method[i].class_name != nullptr);
assert(native_method[i].method_name != nullptr);
assert(native_method[i].method_descriptor != nullptr);
assert(native_method[i].func != nullptr);
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);
debugf("native_init_hash_table add: %s %s %s → %p\n",
native_method[i].class_name,
native_method[i].method_name,
native_method[i].method_descriptor,
native_method[i].func
);
hash_table_add3(native_hash_table_length,
native_hash_table,
(const uint8_t *)native_method[i].class_name,
class_name_length,
(const uint8_t *)native_method[i].method_name,
method_name_length,
(const uint8_t *)native_method[i].method_descriptor,
method_descriptor_length,
native_method[i].func
);
} }
void native_java_io_printstream_write_2(uint32_t * args) *hash_table_length = native_hash_table_length;
{ return 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->utf8.bytes,
} class_name_constant->utf8.length,
method_name_constant->utf8.bytes,
void native_java_misc_memory_putU2_2(uint32_t * args) method_name_constant->utf8.length,
{ method_descriptor_constant->utf8.bytes,
uint16_t * address = (uint16_t *)args[0]; method_descriptor_constant->utf8.length
uint16_t value = args[1]; );
*address = value; assert(e != nullptr);
} assert(e->value != nullptr);
void native_java_misc_memory_putU1_2(uint32_t * args) native_func_t func = (native_func_t)e->value;
{ func(vm, 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,10 @@
#pragma once #pragma once
#include <stdint.h> #include "frame.h"
void native_java_io_printstream_write(uint32_t * arrayref); void native_method_call(struct vm * vm,
void native_java_io_printstream_write_1(uint32_t * args); struct constant * class_name_constant,
void native_java_io_printstream_write_2(uint32_t * args); struct constant * method_name_constant,
void native_java_misc_memory_putU4_2(uint32_t * args); struct constant * method_descriptor_constant,
void native_java_misc_memory_putU2_2(uint32_t * args); uint32_t * args);
void native_java_misc_memory_putU1_2(uint32_t * args); struct hash_table_entry * native_init_hash_table(int * hash_table_length);
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);

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

@ -0,0 +1,42 @@
#include "native_types.h"
#include "printf.h"
#include "string.h"
#include "malloc.h"
#include "loader.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,
vm->native_hash_table.length,
vm->native_hash_table.entry,
main_class,
main_class_length);
}

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

@ -0,0 +1,8 @@
#pragma once
#include <stdint.h>
#include "frame.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());
}
}

View File

@ -1,26 +1,26 @@
CLASS_PATH = \ CLASS_PATH = \
example/GdromClassLoader.class.o \ classes/example/GdromClassLoader.class.o \
example/GdromDirectoryRecordHandler.class.o \ classes/example/GdromDirectoryRecordHandler.class.o \
filesystem/iso9660/ByteParser.class.o \ classes/filesystem/iso9660/ByteParser.class.o \
filesystem/iso9660/DirectoryRecord.class.o \ classes/filesystem/iso9660/DirectoryRecord.class.o \
filesystem/iso9660/ExtentReader.class.o \ classes/filesystem/iso9660/ExtentReader.class.o \
filesystem/iso9660/PrimaryVolumeDescriptor.class.o \ classes/filesystem/iso9660/PrimaryVolumeDescriptor.class.o \
filesystem/iso9660/VolumeParser.class.o \ classes/filesystem/iso9660/VolumeParser.class.o \
java/io/PrintStream.class.o \ classes/java/io/PrintStream.class.o \
java/lang/DecimalDigits.class.o \ classes/java/lang/DecimalDigits.class.o \
java/lang/Integer.class.o \ classes/java/lang/Integer.class.o \
java/lang/Object.class.o \ classes/java/lang/Object.class.o \
java/lang/String.class.o \ classes/java/lang/String.class.o \
java/lang/System.class.o \ classes/java/lang/System.class.o \
java/misc/Memory.class.o \ classes/java/misc/Memory.class.o \
sega/dreamcast/gdrom/G1IF.class.o \ classes/sega/dreamcast/gdrom/G1IF.class.o \
sega/dreamcast/gdrom/GdromIF.class.o \ classes/sega/dreamcast/gdrom/GdromIF.class.o \
sega/dreamcast/gdrom/GdromBits.class.o \ classes/sega/dreamcast/gdrom/GdromBits.class.o \
sega/dreamcast/gdrom/Gdrom.class.o \ classes/sega/dreamcast/gdrom/Gdrom.class.o \
sega/dreamcast/gdrom/GdromExtentReader.class.o \ classes/sega/dreamcast/gdrom/GdromExtentReader.class.o \
sega/dreamcast/gdrom/GdromCommandPacketFormat_cd_read.class.o \ classes/sega/dreamcast/gdrom/GdromCommandPacketFormat_cd_read.class.o \
sega/dreamcast/gdrom/GdromCommandPacketFormat.class.o \ classes/sega/dreamcast/gdrom/GdromCommandPacketFormat.class.o \
sega/dreamcast/gdrom/GdromCommandPacketFormat_get_toc.class.o \ classes/sega/dreamcast/gdrom/GdromCommandPacketFormat_get_toc.class.o \
sega/dreamcast/gdrom/GdromCommandPacketInterface.class.o \ classes/sega/dreamcast/gdrom/GdromCommandPacketInterface.class.o \
sega/dreamcast/gdrom/GdromProtocol.class.o \ classes/sega/dreamcast/gdrom/GdromProtocol.class.o \
jvm/internal/Loader.class.o classes/jvm/internal/Loader.class.o

View File

@ -39,27 +39,29 @@ function classpath_inc_c () {
function make_header () { function make_header () {
while read line; do while read line; do
truncate -s0 "${line}.h" local filename="${line}.h"
local name0="${line//\//_}" local name0="${line//\//_}"
local name1="${name0//$/_}" local name1="${name0//$/_}"
local name="${name1//./_}" local name="${name1//./_}"
echo '#pragma once' > "${line}.h" truncate -s0 "${filename}"
echo '' >> "${line}.h"
echo '#include <stdint.h>' >> "${line}.h" echo '#pragma once' > "${filename}"
echo '' >> "${line}.h" echo '' >> "${filename}"
echo '#ifdef __cplusplus' >> "${line}.h" echo '#include <stdint.h>' >> "${filename}"
echo 'extern C {' >> "${line}.h" echo '' >> "${filename}"
echo '#endif' >> "${line}.h" echo '#ifdef __cplusplus' >> "${filename}"
echo '' >> "${line}.h" echo 'extern C {' >> "${filename}"
echo "extern uint32_t _binary_${name}_start __asm(\"_binary_${name}_start\");" >> "${line}.h" echo '#endif' >> "${filename}"
echo "extern uint32_t _binary_${name}_end __asm(\"_binary_${name}_end\");" >> "${line}.h" echo '' >> "${filename}"
echo "extern uint32_t _binary_${name}_size __asm(\"_binary_${name}_size\");" >> "${line}.h" echo "extern uint32_t _binary_${name}_start __asm(\"_binary_${name}_start\");" >> "${filename}"
echo '' >> "${line}.h" echo "extern uint32_t _binary_${name}_end __asm(\"_binary_${name}_end\");" >> "${filename}"
echo '#ifdef __cplusplus' >> "${line}.h" echo "extern uint32_t _binary_${name}_size __asm(\"_binary_${name}_size\");" >> "${filename}"
echo '}' >> "${line}.h" echo '' >> "${filename}"
echo '#endif' >> "${line}.h" echo '#ifdef __cplusplus' >> "${filename}"
echo '}' >> "${filename}"
echo '#endif' >> "${filename}"
done done
} }
@ -102,7 +104,7 @@ function boot_classes () {
local length=${#boot_classes[@]} local length=${#boot_classes[@]}
for ((i=0;i<length;i++)); do for ((i=0;i<length;i++)); do
local class="${boot_classes[i]}" local class="classes/${boot_classes[i]}"
echo "$class" echo "$class"
done done
} }
@ -111,7 +113,7 @@ function boot_sources () {
local length=${#boot_classes[@]} local length=${#boot_classes[@]}
for ((i=0;i<length;i++)); do for ((i=0;i<length;i++)); do
local class="${boot_classes[i]}" local class="classes/${boot_classes[i]}"
local source="${class%.class}.java" local source="${class%.class}.java"
if [ -f "$source" ]; then if [ -f "$source" ]; then
echo "$source" echo "$source"
@ -151,7 +153,7 @@ function application_classes () {
local length=${#application_classes[@]} local length=${#application_classes[@]}
for ((i=0;i<length;i++)); do for ((i=0;i<length;i++)); do
local class="${application_classes[i]}" local class="classes/${application_classes[i]}"
echo "$class" echo "$class"
done done
} }
@ -160,7 +162,7 @@ function application_sources () {
local length=${#application_classes[@]} local length=${#application_classes[@]}
for ((i=0;i<length;i++)); do for ((i=0;i<length;i++)); do
local class="${application_classes[i]}" local class="classes/${application_classes[i]}"
local source="${class%.class}.java" local source="${class%.class}.java"
if [ -f "$source" ]; then if [ -f "$source" ]; then
echo "$source" echo "$source"
@ -176,6 +178,7 @@ function find_sources () {
find model/ example/ sega/ java/ filesystem/ -name '*.java' -not -name 'Test*' | sort find model/ example/ sega/ java/ filesystem/ -name '*.java' -not -name 'Test*' | sort
} }
set -eux
find . -name '*.class' -exec rm -f {} \; find . -name '*.class' -exec rm -f {} \;

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/loader.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 \