From 08f1fe0aa6a122af1cb6f6229f614ec3727ea9cf Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Thu, 26 Dec 2024 05:16:55 -0600 Subject: [PATCH] native_java_io_printstream_write --- .gitignore | 1 + Makefile | 4 +- Makefile.dreamcast.mk | 10 ++- c/class_resolver.c | 13 ++-- c/class_resolver.h | 4 +- c/decode.c | 3 + c/frame.c | 118 +++++++++++++++++++++++------------- c/hash_table.c | 11 +--- c/hash_table.h | 18 +++--- c/main_dreamcast.c | 34 +++++------ c/main_hosted.c | 16 +---- c/native.c | 22 +++++++ c/native.h | 7 +++ c/printf.h | 7 +++ java.mk | 5 +- java/io/PrintStream.class.h | 15 +++++ java/io/PrintStream.java | 35 +++++++++++ java/lang/Object.class.h | 15 +++++ java/lang/Object.java | 2 +- java/lang/String.class.h | 15 +++++ java/lang/String.java | 2 +- java/lang/System.class.h | 15 +++++ java/lang/System.java | 13 ++++ p/Native.class.h | 15 +++++ p/Native.java | 10 +++ 25 files changed, 300 insertions(+), 110 deletions(-) create mode 100644 c/native.c create mode 100644 c/native.h create mode 100644 java/io/PrintStream.class.h create mode 100644 java/io/PrintStream.java create mode 100644 java/lang/Object.class.h create mode 100644 java/lang/String.class.h create mode 100644 java/lang/System.class.h create mode 100644 java/lang/System.java create mode 100644 p/Native.class.h create mode 100644 p/Native.java diff --git a/.gitignore b/.gitignore index fdeb6ca..3126a34 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.csv *.class *.out +*.elf main print_class __pycache__ \ No newline at end of file diff --git a/Makefile b/Makefile index 0515af8..9aaf4b8 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,9 @@ include java.mk CC ?= gcc ARCH = -m32 -CFLAGS ?= -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protector -std=c2x -DDEBUG -g +CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protector -std=c2x -g +CFLAGS += -DDEBUG +#CFLAGS += -DDEBUG_PRINT OPT ?= -O0 DEPFLAGS = -MMD -MP diff --git a/Makefile.dreamcast.mk b/Makefile.dreamcast.mk index 624c35f..0e32c28 100644 --- a/Makefile.dreamcast.mk +++ b/Makefile.dreamcast.mk @@ -4,7 +4,9 @@ OPT = -O0 MAKEFILE_PATH := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST))))) LIB ?= $(MAKEFILE_PATH)/dreamcast -CFLAGS += -D__dreamcast__ -DDEBUG +CFLAGS += -D__dreamcast__ +CFLAGS += -DDEBUG +#CFLAGS += -DDEBUG_PRINT CFLAGS += -I$(MAKEFILE_PATH) CFLAGS += -I$(MAKEFILE_PATH)/dreamcast/ CARCH = -m4-single -ml @@ -45,7 +47,11 @@ LIBGCC_OBJ = \ libgcc/_div_table.o CLASS_FILES = \ - p/Multiply.class.o + p/Native.class.o \ + java/lang/String.class.o \ + java/lang/System.class.o \ + java/io/PrintStream.class.o \ + java/lang/Object.class.o main.elf: LDSCRIPT = $(LIB)/main.lds main.elf: $(START_OBJ) $(OBJ) $(MAIN_OBJ) $(MAIN_DREAMCAST_OBJ) $(LIBGCC_OBJ) $(CLASS_FILES) diff --git a/c/class_resolver.c b/c/class_resolver.c index 6cd290d..84a24a2 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -147,9 +147,7 @@ static void class_resolver_allocate_attribute_entry(struct class_entry * class_e class_entry->attribute_entry = attribute_entry; } -struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** class_names, - const int * class_names_length, - const uint8_t ** buffers, +struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** buffers, int length, int * hash_table_length) { @@ -167,10 +165,15 @@ struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** clas class_entry[i].class_file = class_file; class_entry[i].initialization_state = CLASS_UNINITIALIZED; + struct constant * class_constant = &class_file->constant_pool[class_file->this_class - 1]; + assert(class_constant->tag == CONSTANT_Class); + struct constant * class_name_constant = &class_file->constant_pool[class_constant->class.name_index - 1]; + assert(class_name_constant->tag == CONSTANT_Utf8); + hash_table_add(class_hash_table_length, class_hash_table, - class_names[i], - class_names_length[i], + class_name_constant->utf8.bytes, + class_name_constant->utf8.length, &class_entry[i]); // make hash table for interfaces diff --git a/c/class_resolver.h b/c/class_resolver.h index 793a3fa..c30619a 100644 --- a/c/class_resolver.h +++ b/c/class_resolver.h @@ -48,9 +48,7 @@ struct class_entry { } methods; }; -struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** class_names, - const int * class_names_length, - const uint8_t ** buffers, +struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** buffers, int length, int * hash_table_length); struct class_entry * class_resolver_lookup_class(int class_hash_table_length, diff --git a/c/decode.c b/c/decode.c index 0162701..2686c5c 100644 --- a/c/decode.c +++ b/c/decode.c @@ -94,4 +94,7 @@ static inline int32_t aligned_s4(const void * buf) #define WIDE_NEXT_PC 0 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" #include "decode.inc.c" +#pragma GCC diagnostic pop diff --git a/c/frame.c b/c/frame.c index 94683c5..468ec69 100644 --- a/c/frame.c +++ b/c/frame.c @@ -9,6 +9,7 @@ #include "class_resolver.h" #include "printf.h" #include "string.h" +#include "native.h" struct Code_attribute * get_code_attribute(int code_name_index, int attributes_count, @@ -194,18 +195,49 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry) return true; } -void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info) +void vm_native_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info, int nargs, uint8_t return_type) { - /* If the method is not native, the nargs argument values are popped from the - operand stack. A new frame is created on the Java Virtual Machine stack for - the method being invoked. The nargs argument values are consecutively made - the values of local variables of the new frame, with arg1 in local variable - 0 (or, if arg1 is of type long or double, in local variables 0 and 1) and - so on. The new frame is then made current, and the Java Virtual Machine pc - is set to the opcode of the first instruction of the method to be - invoked. Execution continues with the first instruction of the method. - */ + debugf("vm_static_native_method_call: nargs %d\n", nargs); + uint32_t args[nargs]; + for (int i = 0; i < nargs; i++) { + uint32_t value = operand_stack_pop_u32(vm->current_frame); + debugf("args[%d] = %x\n", nargs - i - 1, value); + args[nargs - i - 1] = value; + } + + debugf("native:\n "); + struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->this_class - 1]; + struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1]; + print_constant(class_name_constant); + debugf(" "); + struct constant * method_name_constant = &class_entry->class_file->constant_pool[method_info->name_index - 1]; + print_constant(method_name_constant); + + 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) { + native_java_io_printstream_write_1(args); + return; + } else if (nargs == 2) { + native_java_io_printstream_write_2(args); + return; + } + } + } + assert(false); +} + +void vm_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info, int nargs, uint8_t return_type) +{ int code_name_index = find_code_name_index(class_entry->class_file); assert(code_name_index > 0); @@ -222,11 +254,8 @@ void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, st vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, code->max_stack); vm->current_frame->operand_stack_ix = 0; vm->current_frame->initialization_frame = 0; + vm->current_frame->return_type = return_type; - struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1]; - int nargs = descriptor_nargs(descriptor_constant, &vm->current_frame->return_type); - nargs += 1; - debugf("nargs+1: %d\n", nargs); for (int i = 0; i < nargs; i++) { uint32_t value = operand_stack_pop_u32(old_frame); debugf("local[%d] = %x\n", nargs - i - 1, value); @@ -240,6 +269,31 @@ void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, st debugf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix); } +void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info) +{ + /* If the method is not native, the nargs argument values are popped from the + operand stack. A new frame is created on the Java Virtual Machine stack for + the method being invoked. The nargs argument values are consecutively made + the values of local variables of the new frame, with arg1 in local variable + 0 (or, if arg1 is of type long or double, in local variables 0 and 1) and + so on. The new frame is then made current, and the Java Virtual Machine pc + is set to the opcode of the first instruction of the method to be + invoked. Execution continues with the first instruction of the method. + */ + + uint8_t return_type; + struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1]; + int nargs = descriptor_nargs(descriptor_constant, &return_type); + nargs += 1; + debugf("nargs+1: %d\n", nargs); + + if (method_info->access_flags & METHOD_ACC_NATIVE) { + vm_native_method_call(vm, class_entry, method_info, nargs, return_type); + } else { + vm_method_call(vm, class_entry, method_info, nargs, return_type); + } +} + void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info) { /* If the method is not native, the nargs argument values are popped from the @@ -252,38 +306,16 @@ void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, str invoked. Execution continues with the first instruction of the method. */ - int code_name_index = find_code_name_index(class_entry->class_file); - assert(code_name_index > 0); - - struct Code_attribute * code = get_code_attribute(code_name_index, - method_info->attributes_count, - method_info->attributes); - assert(code != nullptr); - - struct frame * old_frame = vm->current_frame; - - vm->current_frame = stack_push_frame(&vm->frame_stack, 1); - vm->current_frame->code = code; - vm->current_frame->local_variable = stack_push_data(&vm->data_stack, code->max_locals); - vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, code->max_stack); - vm->current_frame->operand_stack_ix = 0; - vm->current_frame->initialization_frame = 0; - + uint8_t return_type; struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1]; - int nargs = descriptor_nargs(descriptor_constant, &vm->current_frame->return_type); + int nargs = descriptor_nargs(descriptor_constant, &return_type); debugf("nargs %d\n", nargs); - for (int i = 0; i < nargs; i++) { - uint32_t value = operand_stack_pop_u32(old_frame); - debugf("local[%d] = %x\n", nargs - i - 1, value); - vm->current_frame->local_variable[nargs - i - 1] = value; + + if (method_info->access_flags & METHOD_ACC_NATIVE) { + vm_native_method_call(vm, class_entry, method_info, nargs, return_type); + } else { + vm_method_call(vm, class_entry, method_info, nargs, return_type); } - ; - - vm->current_frame->pc = 0; - vm->current_frame->class_entry = class_entry; - vm->current_frame->method = method_info; - - debugf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix); } void vm_method_return(struct vm * vm) diff --git a/c/hash_table.c b/c/hash_table.c index b5c00b4..3b1742e 100644 --- a/c/hash_table.c +++ b/c/hash_table.c @@ -77,15 +77,6 @@ void hash_table_add(int hash_table_length, e->value = value; } -static inline bool key_equal(const uint8_t * a, const uint8_t * b, int length) -{ - for (int i = 0; i < length; i++) { - if (a[i] != b[i]) - return false; - } - return true; -} - struct hash_table_entry * hash_table_find(int hash_table_length, struct hash_table_entry * entry, const uint8_t * key, @@ -99,7 +90,7 @@ struct hash_table_entry * hash_table_find(int hash_table_length, while (e != nullptr && e->key != nullptr) { //debugf("key find: %p ", e->key); //print_key(e->key, e->key_length); - if (e->key_length == key_length && key_equal(key, e->key, e->key_length)) { + if (e->key_length == key_length && hash_table_key_equal(key, e->key, e->key_length)) { return e; } e = e->next; diff --git a/c/hash_table.h b/c/hash_table.h index fc88ebc..62cab18 100644 --- a/c/hash_table.h +++ b/c/hash_table.h @@ -40,13 +40,11 @@ struct hash_table_entry * hash_table_find2(int hash_table_length, const uint8_t * key2, int key2_length); -/* -void hash_table_add_int(int hash_table_length, - struct hash_table_entry * entry, - int key, - void * value); - -struct hash_table_entry * hash_table_find_int(int hash_table_length, - struct hash_table_entry * entry, - int key); -*/ +static inline bool hash_table_key_equal(const uint8_t * a, const uint8_t * b, int length) +{ + for (int i = 0; i < length; i++) { + if (a[i] != b[i]) + return false; + } + return true; +} diff --git a/c/main_dreamcast.c b/c/main_dreamcast.c index 13bbc37..ccced72 100644 --- a/c/main_dreamcast.c +++ b/c/main_dreamcast.c @@ -7,31 +7,31 @@ #include "sh7091_scif.h" -#include "p/Multiply.class.h" +#include "p/Native.class.h" +#include "java/lang/String.class.h" +#include "java/lang/System.class.h" +#include "java/io/PrintStream.class.h" +#include "java/lang/Object.class.h" void main() { scif_init(0); - const uint8_t * class_names[1]; - int class_names_length[1]; + const uint8_t * class_file_buffers[] = { + (const uint8_t *)&_binary_p_Native_class_start, + (const uint8_t *)&_binary_java_lang_String_class_start, + (const uint8_t *)&_binary_java_lang_System_class_start, + (const uint8_t *)&_binary_java_io_PrintStream_class_start, + (const uint8_t *)&_binary_java_lang_Object_class_start, + }; + int class_file_buffers_length = (sizeof (class_file_buffers)) / (sizeof (class_file_buffers[0])); - class_names[0] = (const uint8_t *)"p/Multiply"; - class_names_length[0] = string_length((const char *)class_names[0]); - - const uint8_t * buffers[1]; - buffers[0] = (const uint8_t *)&_binary_p_Multiply_class_start; - - const uint8_t * main_class = class_names[0]; - int main_class_length = class_names_length[0]; - - int length = (sizeof (class_names)) / (sizeof (class_names[0])); + const uint8_t * main_class = (const uint8_t *)"p/Native"; + int main_class_length = string_length((const char *)main_class); int class_hash_table_length; - struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers(class_names, - class_names_length, - buffers, - length, + struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers(class_file_buffers, + class_file_buffers_length, &class_hash_table_length); vm_start(class_hash_table_length, diff --git a/c/main_hosted.c b/c/main_hosted.c index 5220462..aacc7c4 100644 --- a/c/main_hosted.c +++ b/c/main_hosted.c @@ -9,29 +9,15 @@ static struct hash_table_entry * load_from_filenames(const char * filenames[], int length, int * hash_table_length) { - const uint8_t ** class_names = (const uint8_t **)filenames; - int class_names_length[length]; uint8_t * buffers[length]; size_t file_size[length]; for (int i = 0; i < length; i++) { - uint32_t filename_length = string_length(filenames[i]); - const char * suffix = ".class"; - uint32_t suffix_length = string_length(suffix); - const char * filename_suffix = &filenames[i][filename_length - suffix_length]; - if (filename_length <= suffix_length || !string_equal(suffix, filename_suffix)) { - printf("invalid class filename: %s\n", filenames[i]); - continue; - } - class_names_length[i] = filename_length - suffix_length; printf("load class: %s\n", filenames[i]); - buffers[i] = file_read(filenames[i], &file_size[i]); } - struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers(class_names, - class_names_length, - (const uint8_t **)buffers, + struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers((const uint8_t **)buffers, length, hash_table_length); diff --git a/c/native.c b/c/native.c new file mode 100644 index 0000000..4bed98b --- /dev/null +++ b/c/native.c @@ -0,0 +1,22 @@ +#include "native.h" +#include "printf.h" + +void native_java_io_printstream_write(uint32_t * arrayref) +{ + uint32_t length = arrayref[0]; + char * buf = (char *)&arrayref[1]; + print_string(buf, length); +} + +void native_java_io_printstream_write_1(uint32_t * args) +{ + uint32_t * arrayref = (uint32_t *)args[0]; + native_java_io_printstream_write(arrayref); +} + +void native_java_io_printstream_write_2(uint32_t * args) +{ + //uint32_t this = args[0]; + uint32_t * arrayref = (uint32_t *)args[1]; + native_java_io_printstream_write(arrayref); +} diff --git a/c/native.h b/c/native.h new file mode 100644 index 0000000..1744ae5 --- /dev/null +++ b/c/native.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +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); diff --git a/c/printf.h b/c/printf.h index fcbeaa2..cd462ce 100644 --- a/c/printf.h +++ b/c/printf.h @@ -25,9 +25,16 @@ void print_cstring(const char * s); void _printf(const char * format, ...); #define printf(...) _printf(__VA_ARGS__) + +#if defined(DEBUG_PRINT) #define debugf(...) _printf(__VA_ARGS__) #define debugc(c) print_char(c) #define debugs(s) print_cstring(s) +#else +#define debugf(...) +#define debugc(c) +#define debugs(c) +#endif #ifdef __cplusplus } diff --git a/java.mk b/java.mk index 15cf965..c0ff2ca 100644 --- a/java.mk +++ b/java.mk @@ -1,7 +1,7 @@ %.class: %.java javac $< -java/lang/%.class: java/lang/%.java +java/%.class: java/%.java javac --source 8 --target 8 --boot-class-path . $< OBJ = \ @@ -16,7 +16,8 @@ OBJ = \ c/frame.o \ c/printf.o \ c/parse.o \ - c/unparse.o + c/unparse.o \ + c/native.o MAIN_DREAMCAST_OBJ = \ c/sh7091_scif.o \ diff --git a/java/io/PrintStream.class.h b/java/io/PrintStream.class.h new file mode 100644 index 0000000..e4bc2ef --- /dev/null +++ b/java/io/PrintStream.class.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_java_io_PrintStream_class_start __asm("_binary_java_io_PrintStream_class_start"); +extern uint32_t _binary_java_io_PrintStream_class_end __asm("_binary_java_io_PrintStream_class_end"); +extern uint32_t _binary_java_io_PrintStream_class_size __asm("_binary_java_io_PrintStream_class_size"); + +#ifdef __cplusplus +} +#endif diff --git a/java/io/PrintStream.java b/java/io/PrintStream.java new file mode 100644 index 0000000..9a74412 --- /dev/null +++ b/java/io/PrintStream.java @@ -0,0 +1,35 @@ +package java.io; + +import java.lang.String; + +public class PrintStream +{ + public PrintStream() { + } + + private final byte[] newline = {'\n'}; + + public static native void write(byte[] buf); + + public void println() { + write(newline); + } + + public void println(byte[] buf) { + write(buf); + write(newline); + } + + public void println(String s) { + write(s.getBytes()); + write(newline); + } + + public void print(byte[] buf) { + write(buf); + } + + public void print(String s) { + write(s.getBytes()); + } +} diff --git a/java/lang/Object.class.h b/java/lang/Object.class.h new file mode 100644 index 0000000..dddaf89 --- /dev/null +++ b/java/lang/Object.class.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_java_lang_Object_class_start __asm("_binary_java_lang_Object_class_start"); +extern uint32_t _binary_java_lang_Object_class_end __asm("_binary_java_lang_Object_class_end"); +extern uint32_t _binary_java_lang_Object_class_size __asm("_binary_java_lang_Object_class_size"); + +#ifdef __cplusplus +} +#endif diff --git a/java/lang/Object.java b/java/lang/Object.java index 3677589..3822387 100644 --- a/java/lang/Object.java +++ b/java/lang/Object.java @@ -1,5 +1,5 @@ package java.lang; -class Object { +public class Object { public Object() {} } diff --git a/java/lang/String.class.h b/java/lang/String.class.h new file mode 100644 index 0000000..de6b587 --- /dev/null +++ b/java/lang/String.class.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_java_lang_String_class_start __asm("_binary_java_lang_String_class_start"); +extern uint32_t _binary_java_lang_String_class_end __asm("_binary_java_lang_String_class_end"); +extern uint32_t _binary_java_lang_String_class_size __asm("_binary_java_lang_String_class_size"); + +#ifdef __cplusplus +} +#endif diff --git a/java/lang/String.java b/java/lang/String.java index 533a522..bf55646 100644 --- a/java/lang/String.java +++ b/java/lang/String.java @@ -1,6 +1,6 @@ package java.lang; -class String { +public class String { private final byte[] value; public String() { diff --git a/java/lang/System.class.h b/java/lang/System.class.h new file mode 100644 index 0000000..75ac0a4 --- /dev/null +++ b/java/lang/System.class.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_java_lang_System_class_start __asm("_binary_java_lang_System_class_start"); +extern uint32_t _binary_java_lang_System_class_end __asm("_binary_java_lang_System_class_end"); +extern uint32_t _binary_java_lang_System_class_size __asm("_binary_java_lang_System_class_size"); + +#ifdef __cplusplus +} +#endif diff --git a/java/lang/System.java b/java/lang/System.java new file mode 100644 index 0000000..c7e2da8 --- /dev/null +++ b/java/lang/System.java @@ -0,0 +1,13 @@ +package java.lang; + +import java.io.PrintStream; + +public final class System { + public static PrintStream out = null; + + private System() { + } + static { + out = new PrintStream(); + } +} diff --git a/p/Native.class.h b/p/Native.class.h new file mode 100644 index 0000000..4bfda70 --- /dev/null +++ b/p/Native.class.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_p_Native_class_start __asm("_binary_p_Native_class_start"); +extern uint32_t _binary_p_Native_class_end __asm("_binary_p_Native_class_end"); +extern uint32_t _binary_p_Native_class_size __asm("_binary_p_Native_class_size"); + +#ifdef __cplusplus +} +#endif diff --git a/p/Native.java b/p/Native.java new file mode 100644 index 0000000..a35c7e2 --- /dev/null +++ b/p/Native.java @@ -0,0 +1,10 @@ +package p; + +import java.io.IOException; + +class Native { + public static void main() { + String foo = "hello Dreamcast"; + System.out.println(foo); + } +}