wip
This commit is contained in:
parent
d1483a0c15
commit
d8ed9550ef
8
Makefile
8
Makefile
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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); \
|
||||||
|
}))
|
||||||
|
@ -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];
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "native_types.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
|
|
||||||
struct backtrace_entry {
|
struct backtrace_entry {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
2
c/file.c
2
c/file.c
@ -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)
|
||||||
{
|
{
|
||||||
|
168
c/frame.c
168
c/frame.c
@ -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)) {
|
if (return_type != 'V') {
|
||||||
assert(nargs == 1);
|
assert(old_stack_ix == vm->current_frame->operand_stack_ix - 1);
|
||||||
assert(return_type == 'F');
|
} else {
|
||||||
uint32_t value = native_java_lang_math_sin_1(args);
|
assert(old_stack_ix == vm->current_frame->operand_stack_ix);
|
||||||
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;
|
|
||||||
bool java_misc_memory =
|
|
||||||
class_name_constant->utf8.length == java_misc_memory_length &&
|
|
||||||
hash_table_key_equal(class_name_constant->utf8.bytes, (const uint8_t *)"java/misc/Memory", class_name_constant->utf8.length);
|
|
||||||
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)
|
||||||
|
@ -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];
|
||||||
|
110
c/hash_table.c
110
c/hash_table.c
@ -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,
|
const uint8_t * key1,
|
||||||
int key,
|
int key1_length,
|
||||||
void * value)
|
const uint8_t * key2,
|
||||||
|
int key2_length,
|
||||||
|
const uint8_t * key3,
|
||||||
|
int key3_length,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e->key != nullptr) {
|
||||||
|
// allocate e from overflow
|
||||||
|
e->next = malloc_class_arena((sizeof (struct hash_table_entry)));
|
||||||
|
e->next->key = nullptr;
|
||||||
|
e->next->next = nullptr;
|
||||||
|
e = e->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hash_table_entry * hash_table_find_int(int hash_table_length,
|
static inline bool key_equal3(const uint8_t * a1, int a1_length,
|
||||||
struct hash_table_entry * entry,
|
const uint8_t * a2, int a2_length,
|
||||||
int key)
|
const uint8_t * a3, int a3_length,
|
||||||
|
const uint8_t * b)
|
||||||
{
|
{
|
||||||
return hash_table_find(hash_table_length,
|
for (int i = 0; i < a1_length; i++) {
|
||||||
entry,
|
if (a1[i] != b[i])
|
||||||
(const uint8_t *)&key,
|
return false;
|
||||||
4);
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
@ -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++) {
|
||||||
|
@ -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];
|
||||||
|
296
c/native.c
296
c/native.c
@ -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[] = {
|
||||||
|
{
|
||||||
|
.class_name = "java/lang/Math",
|
||||||
|
.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)
|
||||||
{
|
{
|
||||||
struct arrayref * arrayref = (struct arrayref *)args[0];
|
int native_length = (sizeof (native_method)) / (sizeof (native_method[0]));
|
||||||
print_string((const char *)arrayref->u8, arrayref->length);
|
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]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vm->native_hash_table.length = native_hash_table_length;
|
||||||
|
vm->native_hash_table.entry = native_hash_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
void native_java_io_printstream_write_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 this = args[0];
|
struct hash_table_entry * e = hash_table_find3(vm->native_hash_table.length,
|
||||||
struct arrayref * arrayref = (struct arrayref *)args[1];
|
vm->native_hash_table.entry,
|
||||||
print_string((const char *)arrayref->u8, arrayref->length);
|
class_name_constant,
|
||||||
}
|
class_name_length);
|
||||||
|
assert(e != nullptr);
|
||||||
void native_java_misc_memory_putU4_2(uint32_t * args)
|
assert(e->value != nullptr);
|
||||||
{
|
|
||||||
uint32_t * address = (uint32_t *)args[0];
|
|
||||||
uint32_t value = args[1];
|
|
||||||
*address = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void native_java_misc_memory_putU2_2(uint32_t * args)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
20
c/native.h
20
c/native.h
@ -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
41
c/native/loader.c
Normal 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
6
c/native/loader.h
Normal 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
24
c/native/math.c
Normal 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
9
c/native/math.h
Normal 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
75
c/native/memory.c
Normal 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
14
c/native/memory.h
Normal 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
9
c/native/printstream.c
Normal 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
7
c/native/printstream.h
Normal 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);
|
@ -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"
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
23
c/vm_instance.c
Normal 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
5
c/vm_instance.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "frame.h"
|
||||||
|
|
||||||
|
struct objectref * vm_instance_create(struct vm * vm, const char * class_name);
|
18
classes/java/lang/Class.java
Normal file
18
classes/java/lang/Class.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
24
classes/test/TestGeneric.java
Normal file
24
classes/test/TestGeneric.java
Normal 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
39
java.mk
@ -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 \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user