From 86e18a09449d2872d34f5ce441bf87eafd7656f0 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 19 Jan 2025 22:54:54 -0600 Subject: [PATCH] java.nio: partial Path/Files/FileSystem/InputStream implementation --- Makefile | 2 +- c/backtrace.h | 2 +- c/class_resolver.c | 1 - c/class_resolver.h | 52 ++---------- c/decode.h | 2 +- c/execute.h | 2 +- c/execute_helper.h | 5 -- c/{frame.h => frame_stack.h} | 81 ++++++++++++------- c/gc.c | 4 +- c/gc.h | 2 +- c/native.c | 21 +++++ c/native.h | 2 +- c/native/class.c | 1 + c/native/class.h | 2 +- c/native/libcinputstream.c | 38 +++++++++ c/native/libcinputstream.h | 9 +++ c/native/loader.c | 1 + c/native/loader.h | 2 +- c/native/math.h | 2 +- c/native/memory.h | 2 +- c/native/object.c | 1 + c/native/object.h | 2 +- c/native/printstream.c | 4 + c/native/printstream.h | 2 +- c/native/runtime.h | 2 +- c/native/system.h | 2 +- c/native_types.h | 1 - c/native_types_allocate.h | 3 +- c/{frame.c => vm.c} | 21 +++-- c/vm.h | 32 ++++++++ c/vm_instance.c | 1 + c/vm_instance.h | 2 +- classes/java/io/Closeable.java | 7 ++ classes/java/io/IOException.java | 4 + classes/java/io/InputStream.java | 72 +++++++++++++++++ classes/java/lang/Class.java | 2 +- classes/java/nio/file/FileSystem.java | 26 ++++++ classes/java/nio/file/FileSystems.java | 12 +++ classes/java/nio/file/Files.java | 15 ++++ classes/java/nio/file/OpenOption.java | 4 + classes/java/nio/file/Path.java | 7 ++ .../java/nio/file/spi/FileSystemProvider.java | 18 +++++ classes/jvm/internal/LibcFileSystem.java | 43 ++++++++++ .../jvm/internal/LibcFileSystemProvider.java | 26 ++++++ classes/jvm/internal/LibcInputStream.java | 25 ++++++ classes/jvm/internal/LibcPath.java | 43 ++++++++++ classes/test/TestInputStream.java | 16 ++++ java.mk | 3 +- 48 files changed, 517 insertions(+), 112 deletions(-) rename c/{frame.h => frame_stack.h} (82%) create mode 100644 c/native/libcinputstream.c create mode 100644 c/native/libcinputstream.h rename c/{frame.c => vm.c} (96%) create mode 100644 c/vm.h create mode 100644 classes/java/io/Closeable.java create mode 100644 classes/java/io/IOException.java create mode 100644 classes/java/io/InputStream.java create mode 100644 classes/java/nio/file/FileSystem.java create mode 100644 classes/java/nio/file/FileSystems.java create mode 100644 classes/java/nio/file/Files.java create mode 100644 classes/java/nio/file/OpenOption.java create mode 100644 classes/java/nio/file/Path.java create mode 100644 classes/java/nio/file/spi/FileSystemProvider.java create mode 100644 classes/jvm/internal/LibcFileSystem.java create mode 100644 classes/jvm/internal/LibcFileSystemProvider.java create mode 100644 classes/jvm/internal/LibcInputStream.java create mode 100644 classes/jvm/internal/LibcPath.java create mode 100644 classes/test/TestInputStream.java diff --git a/Makefile b/Makefile index 5704539..e5f3bf1 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protec CFLAGS += -I$(MAKEFILE_PATH)/ CFLAGS += -I$(MAKEFILE_PATH)/c CFLAGS += -DDEBUG -CFLAGS += -DDEBUG_PRINT +#CFLAGS += -DDEBUG_PRINT LDFLAGS = -lm OPT ?= -O0 DEPFLAGS = -MMD -MP diff --git a/c/backtrace.h b/c/backtrace.h index 539f28a..0fef3e6 100644 --- a/c/backtrace.h +++ b/c/backtrace.h @@ -1,7 +1,7 @@ #pragma once #include "native_types.h" -#include "frame.h" +#include "vm.h" struct backtrace_entry { struct class_file * class_file; diff --git a/c/class_resolver.c b/c/class_resolver.c index 50f4046..e867f57 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -13,7 +13,6 @@ #include "fatal.h" #include "parse_type.h" #include "find_attribute.h" -#include "frame.h" #include "native_types_allocate.h" #include "vm_instance.h" diff --git a/c/class_resolver.h b/c/class_resolver.h index 36a9c20..5a48e87 100644 --- a/c/class_resolver.h +++ b/c/class_resolver.h @@ -5,53 +5,7 @@ #include "class_file.h" #include "hash_table.h" #include "native_types.h" - -enum initialization_state { - CLASS_UNINITIALIZED, - CLASS_INITIALIZING, - CLASS_INITIALIZED, -}; - -struct method_entry { - struct class_entry * class_entry; - struct method_info * method_info; - struct Code_attribute * code_attribute; -}; - -union attribute_entry { - struct class_entry * class_entry; - struct method_entry * method_entry; - struct field_entry * field_entry; - struct objectref * string_objectref; -}; - -struct field_entry { - struct class_entry * class_entry; - struct field_info * field_info; - union { - int32_t instance_index; - int32_t static_index; - }; -}; - -struct class_entry { - struct class_file * class_file; - enum initialization_state initialization_state; - union attribute_entry * attribute_entry; - int32_t static_fields_count; - int32_t * static_fields; - int32_t instance_fields_count; - - struct { - int length; - struct hash_table_entry * entry; - } fields; - - struct { - int length; - struct hash_table_entry * entry; - } methods; -}; +#include "vm.h" struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** buffers, int length, @@ -94,3 +48,7 @@ bool class_resolver_instanceof(int class_hash_table_length, struct class_entry * origin_class_entry, const int class_index, struct objectref * objectref); + +struct objectref * class_resolver_lookup_string(struct vm * vm, + struct class_entry * class_entry, + const int string_index); diff --git a/c/decode.h b/c/decode.h index 838e3fb..55ccde9 100644 --- a/c/decode.h +++ b/c/decode.h @@ -1,6 +1,6 @@ #pragma once -#include "frame.h" +#include "vm.h" uint32_t decode_print_instruction(const uint8_t * code, uint32_t pc); void decode_execute_instruction(struct vm * vm, const uint8_t * code, uint32_t pc); diff --git a/c/execute.h b/c/execute.h index 79f7cf7..dc2fd3e 100644 --- a/c/execute.h +++ b/c/execute.h @@ -2,7 +2,7 @@ #include -#include "frame.h" +#include "vm.h" void op_aaload(struct vm * vm); void op_aastore(struct vm * vm); diff --git a/c/execute_helper.h b/c/execute_helper.h index 0465454..47086b1 100644 --- a/c/execute_helper.h +++ b/c/execute_helper.h @@ -1,8 +1,3 @@ -// declared here due to circular frame.h include in class_resolver.h -struct objectref * class_resolver_lookup_string(struct vm * vm, - struct class_entry * class_entry, - const int string_index); - static inline struct field_entry * field_entry_from_constant_index(int class_hash_table_length, struct hash_table_entry * class_hash_table, struct class_entry * origin_class_entry, diff --git a/c/frame.h b/c/frame_stack.h similarity index 82% rename from c/frame.h rename to c/frame_stack.h index 2ddc22a..d2f734f 100644 --- a/c/frame.h +++ b/c/frame_stack.h @@ -1,9 +1,56 @@ #pragma once +#include + +#include "vm.h" #include "assert.h" -#include "class_file.h" -#include "class_resolver.h" -#include "native_types.h" + +enum initialization_state { + CLASS_UNINITIALIZED, + CLASS_INITIALIZING, + CLASS_INITIALIZED, +}; + +struct method_entry { + struct class_entry * class_entry; + struct method_info * method_info; + struct Code_attribute * code_attribute; +}; + +union attribute_entry { + struct class_entry * class_entry; + struct method_entry * method_entry; + struct field_entry * field_entry; + struct objectref * string_objectref; +}; + +struct field_entry { + struct class_entry * class_entry; + struct field_info * field_info; + union { + int32_t instance_index; + int32_t static_index; + }; +}; + +struct class_entry { + struct class_file * class_file; + enum initialization_state initialization_state; + union attribute_entry * attribute_entry; + int32_t static_fields_count; + int32_t * static_fields; + int32_t instance_fields_count; + + struct { + int length; + struct hash_table_entry * entry; + } fields; + + struct { + int length; + struct hash_table_entry * entry; + } methods; +}; struct frame { struct class_entry * class_entry; @@ -27,20 +74,6 @@ struct stack { int32_t capacity; }; -struct vm { - struct stack frame_stack; - struct stack data_stack; - struct frame * current_frame; - struct { - int length; - struct hash_table_entry * entry; - } 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) { struct frame * frame = &stack->frame[stack->ix]; @@ -182,17 +215,3 @@ static inline double operand_stack_pop_f64(struct frame * frame) double f = *((double *)&value); return f; } - -bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry); -void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry); -void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry); -void vm_method_return(struct vm * vm); -void vm_execute(struct vm * vm); -struct vm * vm_start(int class_hash_table_length, - 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, - int main_class_name_length); -int descriptor_nargs(struct constant * descriptor_constant, uint8_t * return_type); -void vm_exception(struct vm * vm, struct objectref * objectref); diff --git a/c/gc.c b/c/gc.c index 2c95233..787fbd4 100644 --- a/c/gc.c +++ b/c/gc.c @@ -1,6 +1,8 @@ -#include "frame.h" +#include "gc.h" #include "memory_allocator.h" #include "printf.h" +#include "hash_table.h" +#include "native_types.h" static void walk_address(void * address); diff --git a/c/gc.h b/c/gc.h index 985c3ab..bd41b47 100644 --- a/c/gc.h +++ b/c/gc.h @@ -1,6 +1,6 @@ #pragma once -#include "frame.h" +#include "vm.h" void gc_mark(struct vm * vm); void gc_sweep(); diff --git a/c/native.c b/c/native.c index 45aaab0..b62ef24 100644 --- a/c/native.c +++ b/c/native.c @@ -4,6 +4,7 @@ #include "printf.h" #include "native.h" #include "native/class.h" +#include "native/libcinputstream.h" #include "native/loader.h" #include "native/math.h" #include "native/memory.h" @@ -160,6 +161,26 @@ const static struct native_method native_method[] = { .method_descriptor = "(Ljava/lang/Object;)I", .func = native_java_lang_system_hashcode_1, }, +#if !defined(__dreamcast__) + { + .class_name = "jvm/internal/LibcInputStream", + .method_name = "_open", + .method_descriptor = "([B)I", + .func = native_jvm_internal_libcinputstream_open_1, + }, + { + .class_name = "jvm/internal/LibcInputStream", + .method_name = "_close", + .method_descriptor = "(I)V", + .func = native_jvm_internal_libcinputstream_close_1, + }, + { + .class_name = "jvm/internal/LibcInputStream", + .method_name = "_read", + .method_descriptor = "(I)I", + .func = native_jvm_internal_libcinputstream_read_1, + }, +#endif }; struct hash_table_entry * native_init_hash_table(int * hash_table_length) diff --git a/c/native.h b/c/native.h index 65d7b4a..5c8b254 100644 --- a/c/native.h +++ b/c/native.h @@ -1,6 +1,6 @@ #pragma once -#include "frame.h" +#include "vm.h" void native_method_call(struct vm * vm, struct constant * class_name_constant, diff --git a/c/native/class.c b/c/native/class.c index 58f995f..5ca49c3 100644 --- a/c/native/class.c +++ b/c/native/class.c @@ -1,6 +1,7 @@ #include "class.h" #include "printf.h" #include "vm_instance.h" +#include "class_resolver.h" void native_java_lang_class_getname_1(struct vm * vm, uint32_t * args) { diff --git a/c/native/class.h b/c/native/class.h index 8f98d37..cbe7855 100644 --- a/c/native/class.h +++ b/c/native/class.h @@ -2,7 +2,7 @@ #include -#include "frame.h" +#include "vm.h" void native_java_lang_class_getname_1(struct vm * vm, uint32_t * args); void native_java_lang_class_getsuperclass_1(struct vm * vm, uint32_t * args); diff --git a/c/native/libcinputstream.c b/c/native/libcinputstream.c new file mode 100644 index 0000000..002e62e --- /dev/null +++ b/c/native/libcinputstream.c @@ -0,0 +1,38 @@ +#include + +#include "libcinputstream.h" +#include "assert.h" +#include "native_types.h" + +void native_jvm_internal_libcinputstream_open_1(struct vm * vm, uint32_t * args) +{ + struct arrayref * arrayref = (struct arrayref *)args[0]; + assert(arrayref != nullptr); + assert(arrayref->length > 0); + assert(arrayref->u8[arrayref->length - 1] == 0); + FILE * file = fopen((const char *)arrayref->u8, "rb"); + assert(file != nullptr); + + operand_stack_push_u32(vm->current_frame, (uint32_t)file); +} + +void native_jvm_internal_libcinputstream_close_1(struct vm * vm, uint32_t * args) +{ + FILE * file = (FILE *)args[0]; + assert(file != nullptr); + int ret = fclose(file); + assert(ret == 0); +} + +void native_jvm_internal_libcinputstream_read_1(struct vm * vm, uint32_t * args) +{ + FILE * file = (FILE *)args[0]; + assert(file != nullptr); + + uint8_t buf[1]; + int32_t size = fread(buf, 1, 1, file); + if (size == 0) + operand_stack_push_u32(vm->current_frame, (uint32_t)-1); + else + operand_stack_push_u32(vm->current_frame, (uint32_t)buf[0]); +} diff --git a/c/native/libcinputstream.h b/c/native/libcinputstream.h new file mode 100644 index 0000000..070327a --- /dev/null +++ b/c/native/libcinputstream.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include "vm.h" + +void native_jvm_internal_libcinputstream_open_1(struct vm * vm, uint32_t * args); +void native_jvm_internal_libcinputstream_close_1(struct vm * vm, uint32_t * args); +void native_jvm_internal_libcinputstream_read_1(struct vm * vm, uint32_t * args); diff --git a/c/native/loader.c b/c/native/loader.c index 7d30eba..7a344b1 100644 --- a/c/native/loader.c +++ b/c/native/loader.c @@ -4,6 +4,7 @@ #include "malloc.h" #include "loader.h" #include "native.h" +#include "class_resolver.h" static uint8_t loader_buffer[0x100000] __attribute__ ((aligned (32))); diff --git a/c/native/loader.h b/c/native/loader.h index f765fb3..30508cf 100644 --- a/c/native/loader.h +++ b/c/native/loader.h @@ -2,7 +2,7 @@ #include -#include "frame.h" +#include "vm.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); diff --git a/c/native/math.h b/c/native/math.h index 485ad85..be95c1b 100644 --- a/c/native/math.h +++ b/c/native/math.h @@ -2,7 +2,7 @@ #include -#include "frame.h" +#include "vm.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); diff --git a/c/native/memory.h b/c/native/memory.h index 112b4b3..ddfedc0 100644 --- a/c/native/memory.h +++ b/c/native/memory.h @@ -2,7 +2,7 @@ #include -#include "frame.h" +#include "vm.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); diff --git a/c/native/object.c b/c/native/object.c index 0d34cb8..cf2339b 100644 --- a/c/native/object.c +++ b/c/native/object.c @@ -1,5 +1,6 @@ #include "object.h" #include "vm_instance.h" +#include "native_types.h" void native_java_lang_object_getclass_1(struct vm * vm, uint32_t * args) { diff --git a/c/native/object.h b/c/native/object.h index b9740a7..54a5cdc 100644 --- a/c/native/object.h +++ b/c/native/object.h @@ -2,6 +2,6 @@ #include -#include "frame.h" +#include "vm.h" void native_java_lang_object_getclass_1(struct vm * vm, uint32_t * args); diff --git a/c/native/printstream.c b/c/native/printstream.c index 0574af8..4f1e2f1 100644 --- a/c/native/printstream.c +++ b/c/native/printstream.c @@ -5,18 +5,22 @@ void native_java_io_printstream_write_ba_1(struct vm * vm, uint32_t * args) { struct arrayref * arrayref = (struct arrayref *)args[0]; + assert(arrayref != nullptr); print_bytes(arrayref->u8, arrayref->length); } void native_java_io_printstream_write_ca_1(struct vm * vm, uint32_t * args) { struct arrayref * arrayref = (struct arrayref *)args[0]; + assert(arrayref != nullptr); print_chars(arrayref->u16, arrayref->length); } void native_java_io_printstream_write_s_1(struct vm * vm, uint32_t * args) { struct objectref * objectref = (struct objectref *)args[0]; + assert(objectref != nullptr); struct arrayref * arrayref = objectref->aref[0]; + assert(arrayref != nullptr); print_chars(arrayref->u16, arrayref->length); } diff --git a/c/native/printstream.h b/c/native/printstream.h index 0702c45..0996a1a 100644 --- a/c/native/printstream.h +++ b/c/native/printstream.h @@ -2,7 +2,7 @@ #include -#include "frame.h" +#include "vm.h" void native_java_io_printstream_write_ba_1(struct vm * vm, uint32_t * args); void native_java_io_printstream_write_ca_1(struct vm * vm, uint32_t * args); diff --git a/c/native/runtime.h b/c/native/runtime.h index d0edbab..32a9f42 100644 --- a/c/native/runtime.h +++ b/c/native/runtime.h @@ -2,7 +2,7 @@ #include -#include "frame.h" +#include "vm.h" void native_java_lang_runtime_freememory_0(struct vm * vm, uint32_t * args); void native_java_lang_runtime_gc_0(struct vm * vm, uint32_t * args); diff --git a/c/native/system.h b/c/native/system.h index b624b8e..0aef518 100644 --- a/c/native/system.h +++ b/c/native/system.h @@ -2,6 +2,6 @@ #include -#include "frame.h" +#include "vm.h" void native_java_lang_system_hashcode_1(struct vm * vm, uint32_t * args); diff --git a/c/native_types.h b/c/native_types.h index f5fefdf..c5a36af 100644 --- a/c/native_types.h +++ b/c/native_types.h @@ -3,7 +3,6 @@ #include #include "assert.h" -#include "class_resolver.h" #include "memory_allocator.h" enum tag_type { diff --git a/c/native_types_allocate.h b/c/native_types_allocate.h index 92c192f..fbf93cc 100644 --- a/c/native_types_allocate.h +++ b/c/native_types_allocate.h @@ -1,8 +1,9 @@ #pragma once #include "native_types.h" -#include "frame.h" #include "gc.h" +#include "vm.h" +#include "memory_allocator.h" static inline void * gc_memory_allocate(struct vm * vm, int size) { diff --git a/c/frame.c b/c/vm.c similarity index 96% rename from c/frame.c rename to c/vm.c index 0848a07..540e1cf 100644 --- a/c/frame.c +++ b/c/vm.c @@ -4,7 +4,6 @@ #include "class_file.h" #include "bytes.h" #include "decode.h" -#include "frame.h" #include "class_resolver.h" #include "printf.h" #include "string.h" @@ -104,20 +103,26 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry) for (int j = 0; j < field_info->attributes_count; j++) { if (field_info->attributes[j].attribute_name_index == constantvalue_name_index) { - struct attribute_info * attribute = &field_info->attributes[j]; - struct constant * constantvalue = &class_file->constant_pool[attribute->constantvalue->constantvalue_index - 1]; - assert(constantvalue->tag == CONSTANT_Integer); // also need to support CONSTANT_String - struct constant * name_constant = &class_file->constant_pool[field_info->name_index - 1]; assert(name_constant->tag == CONSTANT_Utf8); - struct field_entry * field_entry = class_resolver_lookup_field(class_entry->fields.length, class_entry->fields.entry, name_constant->utf8.bytes, name_constant->utf8.length); assert(field_entry != nullptr); - class_entry->static_fields[field_entry->static_index] = constantvalue->integer.bytes; - debugf(" constantvalue: %d\n", constantvalue->integer.bytes); + + struct attribute_info * attribute = &field_info->attributes[j]; + struct constant * constantvalue = &class_file->constant_pool[attribute->constantvalue->constantvalue_index - 1]; + if (constantvalue->tag == CONSTANT_Integer) { + class_entry->static_fields[field_entry->static_index] = constantvalue->integer.bytes; + } else if (constantvalue->tag == CONSTANT_String) { + struct objectref * objectref = class_resolver_lookup_string(vm, + class_entry, + attribute->constantvalue->constantvalue_index); + class_entry->static_fields[field_entry->static_index] = (int32_t)objectref; + } else { + assert(!"invalid constantvalue tag"); + } break; } diff --git a/c/vm.h b/c/vm.h new file mode 100644 index 0000000..226b17e --- /dev/null +++ b/c/vm.h @@ -0,0 +1,32 @@ +#pragma once + +#include "frame_stack.h" +#include "class_file.h" + +struct vm { + struct stack frame_stack; + struct stack data_stack; + struct frame * current_frame; + struct { + int length; + struct hash_table_entry * entry; + } class_hash_table; + struct { + int length; + struct hash_table_entry * entry; + } native_hash_table; +}; + +bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry); +void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry); +void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, struct method_entry * method_entry); +void vm_method_return(struct vm * vm); +void vm_execute(struct vm * vm); +struct vm * vm_start(int class_hash_table_length, + 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, + int main_class_name_length); +int descriptor_nargs(struct constant * descriptor_constant, uint8_t * return_type); +void vm_exception(struct vm * vm, struct objectref * objectref); diff --git a/c/vm_instance.c b/c/vm_instance.c index 91a2c91..0815c1d 100644 --- a/c/vm_instance.c +++ b/c/vm_instance.c @@ -1,6 +1,7 @@ #include "string.h" #include "native_types_allocate.h" #include "vm_instance.h" +#include "class_resolver.h" struct objectref * vm_instance_create(struct vm * vm, const char * class_name) { diff --git a/c/vm_instance.h b/c/vm_instance.h index b2af954..b6ef9a5 100644 --- a/c/vm_instance.h +++ b/c/vm_instance.h @@ -1,6 +1,6 @@ #pragma once -#include "frame.h" +#include "vm.h" struct objectref * vm_instance_create(struct vm * vm, const char * class_name); struct objectref * vm_instance_string_from_constant(struct vm * vm, struct constant * constant); diff --git a/classes/java/io/Closeable.java b/classes/java/io/Closeable.java new file mode 100644 index 0000000..a1a7c16 --- /dev/null +++ b/classes/java/io/Closeable.java @@ -0,0 +1,7 @@ +package java.io; + +public interface Closeable + extends AutoCloseable { + + void close() throws IOException; +} diff --git a/classes/java/io/IOException.java b/classes/java/io/IOException.java new file mode 100644 index 0000000..2b5d6cb --- /dev/null +++ b/classes/java/io/IOException.java @@ -0,0 +1,4 @@ +package java.io; + +public class IOException extends Exception { +} diff --git a/classes/java/io/InputStream.java b/classes/java/io/InputStream.java new file mode 100644 index 0000000..5fef0f6 --- /dev/null +++ b/classes/java/io/InputStream.java @@ -0,0 +1,72 @@ +package java.io; + +public abstract class InputStream + implements Closeable { + + public InputStream() { + } + + public int available() throws IOException { + return 0; + } + + public void close() throws IOException { + } + + public void mark(int readlimit) { + } + + public abstract int read() throws IOException; + + public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + + public int read(byte[] b, + int off, + int len) throws IOException { + if (off < 0 || len < 0 || len > b.length - off) + throw new IndexOutOfBoundsException(); + + if (b == null) + throw new NullPointerException(); + + for (int i = 0; i < len; i++) { + try { + int c = read(); + boolean endOfStream = c == -1; + if (endOfStream) { + if (i == 0) + return -1; + else + return i; + } + b[off + i] = (byte)c; + } catch (IOException e) { + if (i == 0) + throw e; + else + return i; + } + } + + return len; + } + + public void reset() throws IOException { + throw new IOException(); + } + + public long skip(long n) + throws IOException { + + long ni = n; + while (ni > 0L) { + int b = read(); + if (b < 0) + break; + ni -= 1; + } + return n - ni; + } +} diff --git a/classes/java/lang/Class.java b/classes/java/lang/Class.java index 80245bc..af3c6ca 100644 --- a/classes/java/lang/Class.java +++ b/classes/java/lang/Class.java @@ -1,7 +1,7 @@ package java.lang; public final class Class { - private Object klass; // struct class_entry * + private int class_entry; // is actually struct class_entry * private String name; private Class() { diff --git a/classes/java/nio/file/FileSystem.java b/classes/java/nio/file/FileSystem.java new file mode 100644 index 0000000..a290e2f --- /dev/null +++ b/classes/java/nio/file/FileSystem.java @@ -0,0 +1,26 @@ +package java.nio.file; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.spi.FileSystemProvider; + +public abstract class FileSystem + implements Closeable { + + protected FileSystem() { + } + + public abstract void close() + throws IOException; + + public abstract Path getPath(String first, + String... more); + + public abstract String getSeparator(); + + public abstract boolean isOpen(); + + public abstract boolean isReadOnly(); + + public abstract FileSystemProvider provider(); +} diff --git a/classes/java/nio/file/FileSystems.java b/classes/java/nio/file/FileSystems.java new file mode 100644 index 0000000..bb4d007 --- /dev/null +++ b/classes/java/nio/file/FileSystems.java @@ -0,0 +1,12 @@ +package java.nio.file; + +import jvm.internal.LibcFileSystem; + +public final class FileSystems { + private FileSystems() { + } + + public static FileSystem getDefault() { + return LibcFileSystem.getLibcFileSystem(); + } +} diff --git a/classes/java/nio/file/Files.java b/classes/java/nio/file/Files.java new file mode 100644 index 0000000..ab2eb96 --- /dev/null +++ b/classes/java/nio/file/Files.java @@ -0,0 +1,15 @@ +package java.nio.file; + +import java.io.IOException; +import java.io.InputStream; + +public final class Files { + + + public static InputStream newInputStream(Path path, + OpenOption... options) + throws IOException { + + return path.getFileSystem().provider().newInputStream(path, options); + } +} diff --git a/classes/java/nio/file/OpenOption.java b/classes/java/nio/file/OpenOption.java new file mode 100644 index 0000000..c444045 --- /dev/null +++ b/classes/java/nio/file/OpenOption.java @@ -0,0 +1,4 @@ +package java.nio.file; + +public interface OpenOption { +} diff --git a/classes/java/nio/file/Path.java b/classes/java/nio/file/Path.java new file mode 100644 index 0000000..6005a24 --- /dev/null +++ b/classes/java/nio/file/Path.java @@ -0,0 +1,7 @@ +package java.nio.file; + +public interface Path +// extends Comparable, Iterable +{ + FileSystem getFileSystem(); +} diff --git a/classes/java/nio/file/spi/FileSystemProvider.java b/classes/java/nio/file/spi/FileSystemProvider.java new file mode 100644 index 0000000..55aa6da --- /dev/null +++ b/classes/java/nio/file/spi/FileSystemProvider.java @@ -0,0 +1,18 @@ +package java.nio.file.spi; + +import java.nio.file.Path; +import java.nio.file.OpenOption; +import java.io.InputStream; +import java.io.IOException; + +public abstract class FileSystemProvider { + protected FileSystemProvider() { + } + + public InputStream newInputStream(Path path, + OpenOption... options) + throws IOException { + + throw new IOException(); + } +} diff --git a/classes/jvm/internal/LibcFileSystem.java b/classes/jvm/internal/LibcFileSystem.java new file mode 100644 index 0000000..4a02ec8 --- /dev/null +++ b/classes/jvm/internal/LibcFileSystem.java @@ -0,0 +1,43 @@ +package jvm.internal; + +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.nio.file.spi.FileSystemProvider; + +public class LibcFileSystem extends FileSystem { + private static final String separator = "/"; + + private static LibcFileSystem libcFileSystem = new LibcFileSystem(); + + public static LibcFileSystem getLibcFileSystem() { + return libcFileSystem; + } + + private LibcFileSystem() { + super(); + } + + public void close() { + // do nothing + } + + public Path getPath(String first, String ... more) { + return LibcPath.fromString(first, more); + } + + public String getSeparator() { + return LibcFileSystem.separator; + } + + public boolean isOpen() { + return true; + } + + public boolean isReadOnly() { + return false; + } + + public FileSystemProvider provider() { + return LibcFileSystemProvider.getLibcFileSystemProvider(); + } +} diff --git a/classes/jvm/internal/LibcFileSystemProvider.java b/classes/jvm/internal/LibcFileSystemProvider.java new file mode 100644 index 0000000..4656ebe --- /dev/null +++ b/classes/jvm/internal/LibcFileSystemProvider.java @@ -0,0 +1,26 @@ +package jvm.internal; + +import java.nio.file.Path; +import java.nio.file.OpenOption; +import java.nio.file.FileSystem; +import java.nio.file.spi.FileSystemProvider; +import java.io.InputStream; +import java.io.IOException; + +public class LibcFileSystemProvider extends FileSystemProvider { + private static LibcFileSystemProvider libcFileSystemProvider = new LibcFileSystemProvider(); + + private LibcFileSystemProvider() { + super(); + } + + public static LibcFileSystemProvider getLibcFileSystemProvider() { + return libcFileSystemProvider; + } + + public InputStream newInputStream(Path path, + OpenOption... options) + throws IOException { + return new LibcInputStream((LibcPath)path); + } +} diff --git a/classes/jvm/internal/LibcInputStream.java b/classes/jvm/internal/LibcInputStream.java new file mode 100644 index 0000000..ffd026b --- /dev/null +++ b/classes/jvm/internal/LibcInputStream.java @@ -0,0 +1,25 @@ +package jvm.internal; + +import java.io.InputStream; + +public class LibcInputStream extends InputStream { + private int file; // is actually FILE * + + private static native int _open(byte[] path); + + public LibcInputStream(LibcPath path) { + file = _open(path.path); + } + + private static native void _close(int file); + + public void close() { + _close(file); + } + + private static native int _read(int file); + + public int read() { + return _read(file); + } +} diff --git a/classes/jvm/internal/LibcPath.java b/classes/jvm/internal/LibcPath.java new file mode 100644 index 0000000..a4591f9 --- /dev/null +++ b/classes/jvm/internal/LibcPath.java @@ -0,0 +1,43 @@ +package jvm.internal; + +import java.nio.file.Path; +import java.nio.file.FileSystem; + +public class LibcPath implements Path { + public byte[] path; + + public LibcPath(byte[] path) { + this.path = path; + } + + private static int copyInto(byte[] dest, int offset, String s) { + int length = s.length(); + for (int i = 0; i < length; i++) { + dest[offset + i] = (byte)s.charAt(i); + } + return offset + length; + } + + public static LibcPath fromString(String first, String... more) { + int length = first.length(); + for (int i = 0; i < more.length; i++) { + length += more[i].length(); + } + length += more.length + 1; // including C string null terminator + + byte[] path = new byte[length]; + int offset = 0; + offset = copyInto(path, offset, first); + byte sep = (byte)'/'; + for (int i = 0; i < more.length; i++) { + path[offset++] = sep; + offset = copyInto(path, offset, more[i]); + } + + return new LibcPath(path); + } + + public FileSystem getFileSystem() { + return LibcFileSystem.getLibcFileSystem(); + } +} diff --git a/classes/test/TestInputStream.java b/classes/test/TestInputStream.java new file mode 100644 index 0000000..188e5ae --- /dev/null +++ b/classes/test/TestInputStream.java @@ -0,0 +1,16 @@ +package test; + +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.io.InputStream; +import java.io.IOException; + +class TestInputStream { + public static void main() throws IOException { + Path path = FileSystems.getDefault().getPath("/home/bilbo/source.txt"); + InputStream is = Files.newInputStream(path); + char c = (char)is.read(); + System.out.println(c); + } +} diff --git a/java.mk b/java.mk index 2585bad..ce4f1fb 100644 --- a/java.mk +++ b/java.mk @@ -15,7 +15,7 @@ OBJ = \ c/execute.o \ c/fatal.o \ c/find_attribute.o \ - c/frame.o \ + c/vm.o \ c/gc.o \ c/hash_table.o \ c/malloc.o \ @@ -42,6 +42,7 @@ MAIN_DREAMCAST_OBJ = \ MAIN_HOSTED_OBJ = \ c/file.o \ + c/native/libcinputstream.o \ c/main_hosted.o PRINT_CLASS_OBJ = \