Skip to content

Commit

Permalink
update minijvm api
Browse files Browse the repository at this point in the history
  • Loading branch information
digitalgust committed Mar 1, 2024
2 parents 4eb7684 + 8c405ca commit 57f6073
Show file tree
Hide file tree
Showing 53 changed files with 4,518 additions and 2,374 deletions.
4 changes: 2 additions & 2 deletions desktop/glfw_gui/java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<groupId>io.github.digitalgust</groupId>
<artifactId>glfw_gui</artifactId>
<name>${project.groupId}:${project.artifactId}</name>
<version>1.1.3</version>
<version>1.1.4</version>
<description>miniJVM desktop platform gui library</description>
<url>https://github.com/digitalgust/miniJVM</url>

Expand Down Expand Up @@ -145,7 +145,7 @@
<dependency>
<groupId>io.github.digitalgust</groupId>
<artifactId>minijvm_rt</artifactId>
<version>1.1.2</version>
<version>1.1.3</version>
</dependency>
</dependencies>

Expand Down
6 changes: 3 additions & 3 deletions extlib/xgui/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<groupId>io.github.digitalgust</groupId>
<artifactId>xgui</artifactId>
<name>${project.groupId}:${project.artifactId}</name>
<version>1.1.7</version>
<version>1.1.8</version>
<description>miniJVM mobile platform gui library</description>
<url>https://github.com/digitalgust/miniJVM</url>

Expand Down Expand Up @@ -158,12 +158,12 @@
<dependency>
<groupId>io.github.digitalgust</groupId>
<artifactId>glfw_gui</artifactId>
<version>1.1.3</version>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>io.github.digitalgust</groupId>
<artifactId>glfm_gui</artifactId>
<version>1.1.3</version>
<version>1.1.4</version>
</dependency>
</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public void action(GObject gobj) {
GApplication app = GCallBack.getInstance().getApplication();
if (app != AppManager.getInstance()) {
app.pauseApp();
AppManager.getInstance().mainSlot.moveTo(1, 0);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
package org.mini.apploader;

import org.mini.reflect.ReflectArray;
import org.mini.reflect.vm.RefNative;
import org.mini.vm.RefNative;

import java.io.*;
import java.net.ServerSocket;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.mini.apploader;

import org.mini.reflect.Launcher;

import org.mini.vm.VmUtil;

import java.net.URL;

Expand All @@ -19,7 +20,7 @@ protected Class<?> findClass(String name) throws ClassNotFoundException {

// 加载D盘根目录下指定类名的class
String classname = name.replace('.', '/') + ".class";
byte[] classData = Launcher.getFileData(classname, jarPath);
byte[] classData = VmUtil.getFileData(classname, jarPath);
if (classData == null) {
throw new ClassNotFoundException();
} else {
Expand All @@ -28,7 +29,7 @@ protected Class<?> findClass(String name) throws ClassNotFoundException {
}

protected URL findResource(String path) {
URL url = Launcher.getFileUrl(path, jarPath);
URL url = VmUtil.getFileUrl(path, jarPath);
return url;
}
}
8 changes: 5 additions & 3 deletions extlib/xgui/src/main/java/org/mini/gui/GContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,12 @@ public <T extends GObject> T findByName(String name) {
<T extends GObject> T findSonByXY(float x, float y) {
GObject front = null, mid = null, back = null, menu = null;
synchronized (elements) {
for (int i = 0, imax = elements.size(); i < imax; i++) {
for (int i = elements.size() - 1; i >= 0; i--) {
GObject nko = elements.get(i);
if (nko.isInArea(x, y)) {
if (nko.isMenu()) {
if (nko.getLayer() == LAYER_INNER) {
return (T) nko;
} else if (nko.isMenu()) {
return (T) nko;
} else if (nko.isFront()) {
front = nko;
Expand All @@ -287,7 +289,7 @@ <T extends GObject> T findSonByXY(float x, float y) {
*/
public <T extends GObject> T findByXY(float x, float y) {
synchronized (elements) {
for (int i = 0; i < elements.size(); i++) {
for (int i = elements.size() - 1; i >= 0; i--) {
GObject nko = elements.get(i);
if (nko.isInArea(x, y)) {
if (nko instanceof GContainer) {
Expand Down
10 changes: 5 additions & 5 deletions minijvm/c/jvm/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ s32 class_prepar(Instance *loader, JClass *clazz, Runtime *runtime) {

find_supers(clazz, runtime);

int i;
s32 i;

// if (utf8_equals_c(clazz->name, "espresso/parser/JavaParser")) {
// int debug = 1;
Expand Down Expand Up @@ -271,9 +271,9 @@ s32 class_prepar(Instance *loader, JClass *clazz, Runtime *runtime) {
jvm_runtime_cache->doubleclass = clazz;
jvm_runtime_cache->double_value = find_fieldInfo_by_name_c(STR_CLASS_JAVA_LANG_DOUBLE, "value", "D", NULL, runtime);
jvm_runtime_cache->double_valueOf = find_methodInfo_by_name_c(STR_CLASS_JAVA_LANG_DOUBLE, "valueOf", "(D)Ljava/lang/Double;", NULL, runtime);
} else if (utf8_equals_c(clazz->name, STR_CLASS_ORG_MINI_REFLECT_LAUNCHER)) {
jvm_runtime_cache->launcher_loadClass = find_methodInfo_by_name_c(STR_CLASS_ORG_MINI_REFLECT_LAUNCHER, "loadClass", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/Class;", NULL, runtime);
jvm_runtime_cache->launcher_getSystemClassLoader = find_methodInfo_by_name_c(STR_CLASS_ORG_MINI_REFLECT_LAUNCHER, "getSystemClassLoader", "()Ljava/lang/ClassLoader;", NULL, runtime);
} else if (utf8_equals_c(clazz->name, STR_CLASS_SUN_MISC_LAUNCHER)) {
jvm_runtime_cache->launcher_loadClass = find_methodInfo_by_name_c(STR_CLASS_SUN_MISC_LAUNCHER, "loadClass", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/Class;", NULL, runtime);
jvm_runtime_cache->launcher_getSystemClassLoader = find_methodInfo_by_name_c(STR_CLASS_SUN_MISC_LAUNCHER, "getSystemClassLoader", "()Ljava/lang/ClassLoader;", NULL, runtime);
} else if (utf8_equals_c(clazz->name, STR_CLASS_JAVA_LANG_REF_REFERENCE)) {
jvm_runtime_cache->reference_target = find_fieldInfo_by_name_c(STR_CLASS_JAVA_LANG_REF_REFERENCE, "target", STR_INS_JAVA_LANG_OBJECT, NULL, runtime);
jvm_runtime_cache->reference_target->is_ref_target = 1;//mark as weakreference.target field
Expand Down Expand Up @@ -352,7 +352,7 @@ void class_clinit(JClass *clazz, Runtime *runtime) {
if (clazz->finalizeMethod && utf8_equals_c(clazz->finalizeMethod->_this_class->name, STR_CLASS_JAVA_LANG_OBJECT)) {
clazz->finalizeMethod = NULL;
} else {
int debug = 1;
s32 debug = 1;
}

// init javastring
Expand Down
28 changes: 23 additions & 5 deletions minijvm/c/jvm/class_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ void *_parseCPInvokeDynamic(JClass *_this, ByteBuf *buf, s32 index) {
}

s32 _class_constant_pool_destory(JClass *clazz) {
int i;
s32 i;
for (i = 0; i < clazz->constant_item_count; i++) {
ConstantItem *cptr = clazz->constant_item_ptr[i];
if (cptr) {
Expand Down Expand Up @@ -739,7 +739,7 @@ void _changeBytesOrder(MethodInfo *method) {
// if (utf8_equals_c(method->name, "test_typecast"))
// jvm_printf("%8d, %s\n", pc, inst_name[cur_inst]);
} else {
int debug = 1;
// int debug = 1;
}
switch (cur_inst) {
case op_nop:
Expand Down Expand Up @@ -1065,7 +1065,7 @@ void _changeBytesOrder(MethodInfo *method) {
*((s32 *) addr) = i2c.i;
s32 i, key;

int offset = default_offset;
s32 offset = default_offset;
for (i = 0; i < n; i++) {
i2c.c3 = ip[pos++];
i2c.c2 = ip[pos++];
Expand Down Expand Up @@ -1418,7 +1418,7 @@ s32 _convert_to_code_attribute(CodeAttribute *ca, AttributeInfo *attr, JClass *c
ca->exception_table_length = s2c.s;
s32 bytelen = sizeof(ExceptionTable) * ca->exception_table_length;
ca->exception_table = jvm_calloc(bytelen);
int i;
s32 i;
for (i = 0; i < 4 * ca->exception_table_length; i++) {
s2c.c1 = attr->info[info_p++];
s2c.c0 = attr->info[info_p++];
Expand Down Expand Up @@ -1540,7 +1540,7 @@ s32 parseMethodPara(Utf8String *methodType, Utf8String *out) {
Utf8String *para = utf8_create_copy(methodType);
utf8_substring(para, utf8_indexof_c(para, "(") + 1, utf8_last_indexof_c(para, ")"));
//从后往前拆分方法参数,从栈中弹出放入本地变量
int i = 0;
s32 i = 0;
while (para->length > 0) {
c8 ch = utf8_char_at(para, 0);
switch (ch) {
Expand Down Expand Up @@ -1877,6 +1877,24 @@ JClass *class_parse(Instance *loader, ByteBuf *bytebuf, Runtime *runtime) {
}
return tmpclazz;
}
/**
* Loads a Java class from the classpath using specified ClassLoader or the bootstrap classloader.
*
* @param jloader The Instance pointer representing the ClassLoader to use for loading, or NULL for the bootstrap classloader.
* @param pClassName The Utf8String containing the fully-qualified name of the class to load.
* @param runtime A pointer to the Runtime instance that represents the current execution context.
* @return A JClass* pointer to the loaded class on success; NULL if the class could not be found or loaded.
* This function performs the following steps:
* 1. Copies and normalizes the class name (replacing '.' with '/').
* 2. Tries to find the class in the JVM's classes map using the given ClassLoader.
* If the class name starts with "[", it creates an array class instead.
* 3. If the class is not found, attempts to load the ".class" file from the classpath associated with the ClassLoader.
* 4. Parses the loaded bytecode into a JClass structure using `class_parse`.
* 5. If loading through ClassLoader fails, and a custom `launcher_loadClass` method is available, calls this method to attempt loading.
* 6. Cleans up resources and returns the loaded class, or NULL if the class was not found or could not be loaded.
* 7. Logs debug information if the class cannot be found and `_JVM_DEBUG_LOG_LEVEL > 2`.
*/

JClass *load_class(Instance *jloader, Utf8String *pClassName, Runtime *runtime) {
if (!pClassName)return NULL;
Expand Down
55 changes: 46 additions & 9 deletions minijvm/c/jvm/garbage.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,22 @@ s64 gc_sum_heap(GcCollector *collector) {
return hsize;
}
//============================== thread_run() =====================================
/**
* Garbage Collection Thread Function.
*
* @param para A pointer to the GcCollector instance which provides garbage collection context.
* @return 0 on successful termination of the thread.
* This function implements a dedicated garbage collection thread that performs the following tasks:
* 1. Continuously monitors the JVM's heap status and garbage collection parameters.
* It uses `currentTimeMillis()` to track time and `gc_sum_heap` to get current heap usage.
* 2. Checks the garbage collector thread's status (`collector->_garbage_thread_status`) and pauses or terminates as needed.
* 3. If the specified garbage collection period has elapsed (determined by `jvm->garbage_collect_period_ms`) or the heap usage exceeds a pre-defined threshold (`jvm->max_heap_size * jvm->heap_overload_percent / 100`),
* it initiates a garbage collection cycle with `_garbage_collect`.
* 4. Updates the last garbage collection timestamp (`collector->lastgc`) after successfully completing a GC cycle.
* 5. Sleeps for 1 second if no garbage collection is required.
* 6. When signaled to stop, changes the garbage collector thread status to `GARBAGE_THREAD_DEAD` and exits gracefully using `thrd_exit(0)`.
*/

s32 _gc_thread_run(void *para) {
GcCollector *collector = (GcCollector *) para;
Expand Down Expand Up @@ -288,11 +304,27 @@ s32 _gc_thread_run(void *para) {


/**
* 查找所有实例,如果发现没有被引用时 mb->garbage_mark ,
* 去除掉此对象对其他对象的引用,并销毁对象
* Executes a full garbage collection cycle.
*
* @return ret
* @param collector A pointer to the GcCollector instance that manages garbage collection for the JVM.
* @return The number of objects deleted during this GC cycle.
* This function performs a complete garbage collection process, including:
* 1. Initiates garbage collection by setting the `isgc` flag and recording the start time.
* 2. Pauses the world by stopping all threads and preparing resources for GC using `_gc_pause_the_world`.
* If pausing fails, resumes the world and returns -1.
* 3. Merges temporary object lists into the main list and copies references from runtime stacks.
* 4. Begins the mark phase with `_gc_big_search`, incrementing the mark counter and marking reachable objects.
* 5. Processes finalize methods for eligible objects and enqueues weak references for objects no longer reachable.
* Re-marks these objects for collection on the next cycle.
* 6. Clears unreachable objects, updates total memory usage stats, and destroys them.
* 7. Updates the count of live objects and heap size after clearing dead objects.
* 8. Logs performance metrics related to GC timing.
* 9. Resumes the world and unlocks shared resources.
* 10. Optionally calls `jvm_squeeze` if MEM_ALLOC_LTALLOC is defined.
* 11. Resets the `isgc` flag and returns the number of deleted objects.
*/

s64 _garbage_collect(GcCollector *collector) {
collector->isgc = 1;
s64 mem_total = 0, mem_free = 0;
Expand Down Expand Up @@ -614,15 +646,20 @@ void _gc_copy_objs(MiniJVM *jvm) {
}

/**
* 判定某个对象是否被所有线程的runtime引用
* 被运行时的栈或局部变量所引用,
* 这两种情况下,对象是不能被释放的
* Copies object references from a thread's runtime stack and temporary holder for garbage collection.
*
* @param pruntime son of runtime
* @return how many marked
* @param pruntime A pointer to the Runtime instance representing the current thread.
* @return 0 on successful completion.
* This function performs the following actions:
* 1. Retrieves the GcCollector instance associated with the JVM.
* 2. Adds the thread's JavaThreadInfo (`pruntime->thrd_info->jthread`) to the collector's runtime reference copy list (`collector->runtime_refer_copy`).
* 3. Resets the free stack space by marking the current stack pointer as the clean point, and clears unused stack entries.
* 4. Iterates over the stack of the given thread's Runtime and adds each non-null reference value found in the StackEntry to the reference copy list.
* 5. Traverses the temporary holder list (`runtime->thrd_info->tmp_holder`) for the thread and adds each MemoryBlock to the reference copy list.
* 6. Upon completion, it signals that the references have been copied and are ready for garbage collection.
*/


s32 _gc_copy_objs_from_thread(Runtime *pruntime) {
GcCollector *collector = pruntime->jvm->collector;
arraylist_push_back_unsafe(collector->runtime_refer_copy, pruntime->thrd_info->jthread);
Expand Down
4 changes: 2 additions & 2 deletions minijvm/c/jvm/global.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ s32 DATA_TYPE_BYTES[DATATYPE_COUNT] = {0, 0, 0, 0,
};


char *STRS_CLASS_EXCEPTION[] = {
c8 *STRS_CLASS_EXCEPTION[] = {
"java.lang.OutOfMemoryError",
"java.lang.VirtualMachineError",
"java.lang.NoClassDefFoundError",
Expand Down Expand Up @@ -68,7 +68,7 @@ c8 const *STR_CLASS_JAVA_LANG_INVOKE_METHODHANDLES_LOOKUP = "java/lang/invoke/Me
c8 const *STR_CLASS_JAVA_LANG_STACKTRACE = "java/lang/StackTraceElement";
c8 const *STR_CLASS_JAVA_LANG_THROWABLE = "java/lang/Throwable";
c8 const *STR_CLASS_ORG_MINI_REFLECT_DIRECTMEMOBJ = "org/mini/reflect/DirectMemObj";
c8 const *STR_CLASS_ORG_MINI_REFLECT_LAUNCHER = "org/mini/reflect/Launcher";
c8 const *STR_CLASS_SUN_MISC_LAUNCHER = "sun/misc/Launcher";
c8 const *STR_CLASS_ORG_MINI_REFLECT_REFLECTMETHOD = "org/mini/reflect/ReflectMethod";

c8 const *STR_FIELD_STACKFRAME = "stackFrame";
Expand Down
8 changes: 4 additions & 4 deletions minijvm/c/jvm/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ s32 invokedynamic_prepare(Runtime *runtime, BootstrapMethod *bootMethod, Constan
} else {
s32 ret = execute_method_impl(boot_m, runtime);
if (ret == RUNTIME_STATUS_NORMAL) {
MethodInfo *finder = find_methodInfo_by_name_c("org/mini/reflect/vm/LambdaUtil",
MethodInfo *finder = find_methodInfo_by_name_c("org/mini/vm/LambdaUtil",
"getMethodInfoHandle",
"(Ljava/lang/invoke/CallSite;)J", NULL,
runtime);
Expand Down Expand Up @@ -390,7 +390,7 @@ static inline void _optimize_empty_method_call(MethodInfo *subm, CodeAttribute *
}


static inline int _optimize_inline_getter(JClass *clazz, s32 cfrIdx, Runtime *runtime) {
static inline s32 _optimize_inline_getter(JClass *clazz, s32 cfrIdx, Runtime *runtime) {

RuntimeStack *stack = runtime->stack;
FieldInfo *fi = class_get_constant_fieldref(clazz, cfrIdx)->fieldInfo;
Expand Down Expand Up @@ -445,7 +445,7 @@ static inline int _optimize_inline_getter(JClass *clazz, s32 cfrIdx, Runtime *ru
return RUNTIME_STATUS_NORMAL;
}

static inline int _optimize_inline_setter(JClass *clazz, s32 cfrIdx, Runtime *runtime) {
static inline s32 _optimize_inline_setter(JClass *clazz, s32 cfrIdx, Runtime *runtime) {

RuntimeStack *stack = runtime->stack;
FieldInfo *fi = class_get_constant_fieldref(clazz, cfrIdx)->fieldInfo;
Expand Down Expand Up @@ -1809,7 +1809,7 @@ s32 execute_method_impl(MethodInfo *method, Runtime *pruntime) {
--sp;
fval1 = (sp - 0)->fvalue;
fval2 = (sp - 1)->fvalue;
f32 v = fval2 - ((int) (fval2 / fval1) * fval1);
f32 v = fval2 - ((s32) (fval2 / fval1) * fval1);
#if _JVM_DEBUG_LOG_LEVEL > 5
invoke_deepth(runtime);
jvm_printf("frem: %f\n", (sp - 1)->fvalue);
Expand Down
6 changes: 3 additions & 3 deletions minijvm/c/jvm/jdwp.c
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ s32 getClassType(JClass *clazz) {


c8 getSimpleTag(u8 type) {
char bytes = '0';
c8 bytes = '0';
switch (type) {
case JDWP_TAG_BYTE:
case JDWP_TAG_BOOLEAN:
Expand Down Expand Up @@ -642,10 +642,10 @@ void writeValueType(JdwpPacket *res, ValueType *vt) {
jdwppacket_write_byte(res, (s8) vt->value);
break;
case '2':
jdwppacket_write_short(res, (short) vt->value);
jdwppacket_write_short(res, (s16) vt->value);
break;
case '4':
jdwppacket_write_int(res, (int) vt->value);
jdwppacket_write_int(res, (s32) vt->value);
break;
case '8':
jdwppacket_write_long(res, vt->value);
Expand Down
Loading

0 comments on commit 57f6073

Please sign in to comment.