diff --git a/desktop/glfw_gui/java/pom.xml b/desktop/glfw_gui/java/pom.xml index c85ad50de..fffa644ec 100755 --- a/desktop/glfw_gui/java/pom.xml +++ b/desktop/glfw_gui/java/pom.xml @@ -8,7 +8,7 @@ io.github.digitalgust glfw_gui ${project.groupId}:${project.artifactId} - 1.1.3 + 1.1.4 miniJVM desktop platform gui library https://github.com/digitalgust/miniJVM @@ -145,7 +145,7 @@ io.github.digitalgust minijvm_rt - 1.1.2 + 1.1.3 diff --git a/extlib/xgui/pom.xml b/extlib/xgui/pom.xml index 3132885d7..1ab28ddc1 100755 --- a/extlib/xgui/pom.xml +++ b/extlib/xgui/pom.xml @@ -9,7 +9,7 @@ io.github.digitalgust xgui ${project.groupId}:${project.artifactId} - 1.1.7 + 1.1.8 miniJVM mobile platform gui library https://github.com/digitalgust/miniJVM @@ -158,12 +158,12 @@ io.github.digitalgust glfw_gui - 1.1.3 + 1.1.4 io.github.digitalgust glfm_gui - 1.1.3 + 1.1.4 diff --git a/extlib/xgui/src/main/java/org/mini/apploader/GHomeButton.java b/extlib/xgui/src/main/java/org/mini/apploader/GHomeButton.java index 023a0ee15..2105f1a5a 100644 --- a/extlib/xgui/src/main/java/org/mini/apploader/GHomeButton.java +++ b/extlib/xgui/src/main/java/org/mini/apploader/GHomeButton.java @@ -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); } } } diff --git a/extlib/xgui/src/main/java/org/mini/apploader/MiniHttpServer.java b/extlib/xgui/src/main/java/org/mini/apploader/MiniHttpServer.java index dff1055d5..b29096e2b 100644 --- a/extlib/xgui/src/main/java/org/mini/apploader/MiniHttpServer.java +++ b/extlib/xgui/src/main/java/org/mini/apploader/MiniHttpServer.java @@ -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; diff --git a/extlib/xgui/src/main/java/org/mini/apploader/StandalongGuiAppClassLoader.java b/extlib/xgui/src/main/java/org/mini/apploader/StandalongGuiAppClassLoader.java index ea8935e92..6e137aba4 100644 --- a/extlib/xgui/src/main/java/org/mini/apploader/StandalongGuiAppClassLoader.java +++ b/extlib/xgui/src/main/java/org/mini/apploader/StandalongGuiAppClassLoader.java @@ -1,6 +1,7 @@ package org.mini.apploader; -import org.mini.reflect.Launcher; + +import org.mini.vm.VmUtil; import java.net.URL; @@ -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 { @@ -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; } } diff --git a/extlib/xgui/src/main/java/org/mini/gui/GContainer.java b/extlib/xgui/src/main/java/org/mini/gui/GContainer.java index 2164723f5..f485bab62 100755 --- a/extlib/xgui/src/main/java/org/mini/gui/GContainer.java +++ b/extlib/xgui/src/main/java/org/mini/gui/GContainer.java @@ -260,10 +260,12 @@ public T findByName(String name) { 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; @@ -287,7 +289,7 @@ T findSonByXY(float x, float y) { */ public 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) { diff --git a/minijvm/c/jvm/class.c b/minijvm/c/jvm/class.c index 6ac9543b4..1a824110f 100644 --- a/minijvm/c/jvm/class.c +++ b/minijvm/c/jvm/class.c @@ -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; @@ -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 @@ -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 diff --git a/minijvm/c/jvm/class_load.c b/minijvm/c/jvm/class_load.c index 955acbff8..bf13fc479 100644 --- a/minijvm/c/jvm/class_load.c +++ b/minijvm/c/jvm/class_load.c @@ -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) { @@ -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: @@ -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++]; @@ -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++]; @@ -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) { @@ -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; diff --git a/minijvm/c/jvm/garbage.c b/minijvm/c/jvm/garbage.c index dbfa6ad11..c74cbac93 100644 --- a/minijvm/c/jvm/garbage.c +++ b/minijvm/c/jvm/garbage.c @@ -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; @@ -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; @@ -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); diff --git a/minijvm/c/jvm/global.c b/minijvm/c/jvm/global.c index 67fe2ec8c..d65b76bac 100644 --- a/minijvm/c/jvm/global.c +++ b/minijvm/c/jvm/global.c @@ -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", @@ -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"; diff --git a/minijvm/c/jvm/interpreter.c b/minijvm/c/jvm/interpreter.c index f75caef29..7fa4da16f 100755 --- a/minijvm/c/jvm/interpreter.c +++ b/minijvm/c/jvm/interpreter.c @@ -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); @@ -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; @@ -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; @@ -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); diff --git a/minijvm/c/jvm/jdwp.c b/minijvm/c/jvm/jdwp.c index 1cefa49e6..fd1b9d820 100644 --- a/minijvm/c/jvm/jdwp.c +++ b/minijvm/c/jvm/jdwp.c @@ -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: @@ -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); diff --git a/minijvm/c/jvm/jit.c b/minijvm/c/jvm/jit.c index e63b9b441..9345b2828 100644 --- a/minijvm/c/jvm/jit.c +++ b/minijvm/c/jvm/jit.c @@ -50,7 +50,7 @@ SwitchTable *switchtable_create(Jit *jit, s32 size); s32 gen_jit_bytecode_func(struct sljit_compiler *C, MethodInfo *method, Runtime *runtime); -void _gen_jump_to_suspend_check(struct sljit_compiler *C, int offset); +void _gen_jump_to_suspend_check(struct sljit_compiler *C, s32 offset); void _gen_save_sp_ip(struct sljit_compiler *C); //------------------------ jit util ---------------------------- @@ -1026,7 +1026,7 @@ void _gen_jdwp(struct sljit_compiler *C) { // } } -void _gen_jump_to_suspend_check(struct sljit_compiler *C, int offset) { +void _gen_jump_to_suspend_check(struct sljit_compiler *C, s32 offset) { if (offset < 0) sljit_emit_ijump(C, SLJIT_FAST_CALL, SLJIT_IMM, SLJIT_FUNC_ADDR(check_suspend)); } @@ -1040,7 +1040,7 @@ s32 multiarray(Runtime *runtime, Utf8String *desc, s32 count) { #else s32 dim[count]; #endif - int i; + s32 i; for (i = 0; i < count; i++) dim[i] = pop_int(stack); @@ -1093,7 +1093,7 @@ s32 invokevirtual(Runtime *runtime, s32 idx) { static float frem(float value1, float value2) { - return value2 - ((int) (value2 / value1) * value1); + return value2 - ((s32) (value2 / value1) * value1); } static double drem_1(double value1, double value2) { @@ -1208,7 +1208,7 @@ s32 gen_jit_bytecode_func(struct sljit_compiler *C, MethodInfo *method, Runtime && utf8_equals_c(method->descriptor, "(J)V") && utf8_equals_c(method->name, "paint_title")) ) { - int debug = 1; + s32 debug = 1; } else { return JIT_GEN_ERROR; @@ -3347,7 +3347,7 @@ void construct_jit(MethodInfo *method, Runtime *runtime) { ca->jit.state = gen_jit_bytecode_func(C, method, runtime); if (ca->jit.state == JIT_GEN_SUCCESS) { - int debug = 1; + s32 debug = 1; } #if(JIT_CODE_DUMP) if (utf8_equals_c(runtime->method->_this_class->name, "org/mini/json/JsonParser") diff --git a/minijvm/c/jvm/jni_io.c b/minijvm/c/jvm/jni_io.c index 5df094512..85ccb3820 100644 --- a/minijvm/c/jvm/jni_io.c +++ b/minijvm/c/jvm/jni_io.c @@ -96,9 +96,9 @@ extern "C" { * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ -size_t strlcpy(char *dst, const char *src, size_t siz) { - char *d = dst; - const char *s = src; +size_t strlcpy(c8 *dst, const c8 *src, size_t siz) { + c8 *d = dst; + const c8 *s = src; size_t n = siz; /* Copy as many bytes as will fit */ @@ -135,9 +135,9 @@ size_t strlcpy(char *dst, const char *src, size_t siz) { * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ -static char *inet_ntop4(const unsigned char *src, char *dst, socklen_t size); +static c8 *inet_ntop4(const u8 *src, c8 *dst, socklen_t size); -static char *inet_ntop6(const unsigned char *src, char *dst, socklen_t size); +static c8 *inet_ntop6(const u8 *src, c8 *dst, socklen_t size); /* char * * inet_ntop(af, src, dst, size) @@ -147,12 +147,12 @@ static char *inet_ntop6(const unsigned char *src, char *dst, socklen_t size); * author: * Paul Vixie, 1996. */ -char *inet_ntop(int af, const void *src, char *dst, socklen_t size) { +c8 *inet_ntop(s32 af, const void *src, c8 *dst, socklen_t size) { switch (af) { case AF_INET: - return (inet_ntop4((const unsigned char *) src, dst, size)); + return (inet_ntop4((const u8 *) src, dst, size)); case AF_INET6: - return (inet_ntop6((const unsigned char *) src, dst, size)); + return (inet_ntop6((const u8 *) src, dst, size)); default: return (NULL); } @@ -170,10 +170,10 @@ char *inet_ntop(int af, const void *src, char *dst, socklen_t size) { * author: * Paul Vixie, 1996. */ -static char *inet_ntop4(const unsigned char *src, char *dst, socklen_t size) { - static const char fmt[] = "%u.%u.%u.%u"; - char tmp[sizeof "255.255.255.255"]; - int l; +static c8 *inet_ntop4(const u8 *src, c8 *dst, socklen_t size) { + static const c8 fmt[] = "%u.%u.%u.%u"; + c8 tmp[sizeof "255.255.255.255"]; + s32 l; l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); if (l <= 0 || (socklen_t) l >= size) { @@ -189,7 +189,7 @@ static char *inet_ntop4(const unsigned char *src, char *dst, socklen_t size) { * author: * Paul Vixie, 1996. */ -static char *inet_ntop6(const unsigned char *src, char *dst, socklen_t size) { +static c8 *inet_ntop6(const u8 *src, c8 *dst, socklen_t size) { /* * Note that int32_t and int16_t need only be "at least" large enough * to contain a value of the specified size. On some systems, like @@ -197,14 +197,14 @@ static char *inet_ntop6(const unsigned char *src, char *dst, socklen_t size) { * Keep this in mind if you think this function should have been coded * to use pointer overlays. All the world's not a VAX. */ - char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + c8 tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; struct { - int base, len; + s32 base, len; } best, cur; #define NS_IN6ADDRSZ 16 #define NS_INT16SZ 2 u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; - int i; + s32 i; /* * Preprocess: @@ -290,9 +290,9 @@ static char *inet_ntop6(const unsigned char *src, char *dst, socklen_t size) { * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ -static int inet_pton4(const char *src, u_char *dst); +static s32 inet_pton4(const c8 *src, u_char *dst); -static int inet_pton6(const char *src, u_char *dst); +static s32 inet_pton6(const c8 *src, u_char *dst); /* int * inet_pton(af, src, dst) @@ -305,12 +305,12 @@ static int inet_pton6(const char *src, u_char *dst); * author: * Paul Vixie, 1996. */ -int inet_pton(int af, const char *src, void *dst) { +s32 inet_pton(s32 af, const c8 *src, void *dst) { switch (af) { case AF_INET: - return (inet_pton4(src, (unsigned char *) dst)); + return (inet_pton4(src, (u8 *) dst)); case AF_INET6: - return (inet_pton6(src, (unsigned char *) dst)); + return (inet_pton6(src, (u8 *) dst)); default: return (-1); } @@ -327,9 +327,9 @@ int inet_pton(int af, const char *src, void *dst) { * author: * Paul Vixie, 1996. */ -static int inet_pton4(const char *src, u_char *dst) { - static const char digits[] = "0123456789"; - int saw_digit, octets, ch; +static s32 inet_pton4(const c8 *src, u_char *dst) { + static const c8 digits[] = "0123456789"; + s32 saw_digit, octets, ch; #define NS_INADDRSZ 4 u_char tmp[NS_INADDRSZ], *tp; @@ -337,7 +337,7 @@ static int inet_pton4(const char *src, u_char *dst) { octets = 0; *(tp = tmp) = 0; while ((ch = *src++) != '\0') { - const char *pch; + const c8 *pch; if ((pch = strchr(digits, ch)) != NULL) { u_int uiNew = *tp * 10 + (pch - digits); @@ -379,14 +379,14 @@ static int inet_pton4(const char *src, u_char *dst) { * author: * Paul Vixie, 1996. */ -static int inet_pton6(const char *src, u_char *dst) { - static const char xdigits_l[] = "0123456789abcdef", +static s32 inet_pton6(const c8 *src, u_char *dst) { + static const c8 xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; #define NS_IN6ADDRSZ 16 #define NS_INT16SZ 2 u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; - const char *xdigits, *curtok; - int ch, seen_xdigits; + const c8 *xdigits, *curtok; + s32 ch, seen_xdigits; u_int val; memset((tp = tmp), '\0', NS_IN6ADDRSZ); @@ -400,7 +400,7 @@ static int inet_pton6(const char *src, u_char *dst) { seen_xdigits = 0; val = 0; while ((ch = *src++) != '\0') { - const char *pch; + const c8 *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); @@ -448,8 +448,8 @@ static int inet_pton6(const char *src, u_char *dst) { * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ - const int n = tp - colonp; - int i; + const s32 n = tp - colonp; + s32 i; if (tp == endp) return (0); @@ -531,25 +531,25 @@ s32 sock_option(VmSock *vmsock, s32 opType, s32 opValue, s32 opValue2) { } case SOCK_OP_TYPE_REUSEADDR: {// s32 x = 1; - ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_REUSEADDR, (char *) &x, sizeof(x)); + ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_REUSEADDR, (c8 *) &x, sizeof(x)); vmsock->reuseaddr = 1; break; } case SOCK_OP_TYPE_RCVBUF: {//缓冲区设置 - int nVal = opValue;//设置为 opValue K - ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_RCVBUF, (const char *) &nVal, sizeof(nVal)); + s32 nVal = opValue;//设置为 opValue K + ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_RCVBUF, (const c8 *) &nVal, sizeof(nVal)); break; } case SOCK_OP_TYPE_SNDBUF: {//缓冲区设置 s32 nVal = opValue;//设置为 opValue K - ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_SNDBUF, (const char *) &nVal, sizeof(nVal)); + ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_SNDBUF, (const c8 *) &nVal, sizeof(nVal)); break; } case SOCK_OP_TYPE_TIMEOUT: { vmsock->rcv_time_out = opValue; #if __JVM_OS_MINGW__ || __JVM_OS_VS__ s32 nTime = opValue; - ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_RCVTIMEO, (const char *) &nTime, sizeof(nTime)); + ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_RCVTIMEO, (const c8 *) &nTime, sizeof(nTime)); #else struct timeval timeout = {opValue / 1000, (opValue % 1000) * 1000}; ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); @@ -565,12 +565,12 @@ s32 sock_option(VmSock *vmsock, s32 opType, s32 opValue, s32 opValue2) { // 如果m_sLinger.l_onoff=0;则功能和2.)作用相同; m_sLinger.l_onoff = opValue; m_sLinger.l_linger = opValue2;//(容许逗留的时间为5秒) - ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_RCVTIMEO, (const char *) &m_sLinger, sizeof(m_sLinger)); + ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_RCVTIMEO, (const c8 *) &m_sLinger, sizeof(m_sLinger)); break; } case SOCK_OP_TYPE_KEEPALIVE: { s32 val = opValue; - ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_RCVTIMEO, (const char *) &val, sizeof(val)); + ret = setsockopt(vmsock->contex.fd, SOL_SOCKET, SO_RCVTIMEO, (const c8 *) &val, sizeof(val)); break; } } @@ -588,7 +588,7 @@ s32 sock_get_option(VmSock *vmsock, s32 opType) { u_long flags = 1; ret = NO_ERROR == ioctlsocket(vmsock->contex.fd, FIONBIO, &flags); #else - int flags; + s32 flags; if ((flags = fcntl(vmsock->contex.fd, F_GETFL, NULL)) < 0) { ret = -1; } else { @@ -650,14 +650,14 @@ s32 sock_get_option(VmSock *vmsock, s32 opType) { } -s32 host_2_ip(c8 *hostname, char *buf, s32 buflen) { +s32 host_2_ip(c8 *hostname, c8 *buf, s32 buflen) { #if __JVM_OS_VS__ || __JVM_OS_MINGW__ WSADATA wsaData; WSAStartup(MAKEWORD(1, 1), &wsaData); #endif /* WIN32 */ struct addrinfo hints; struct addrinfo *result, *rp; - int s; + s32 s; struct sockaddr_in *ipv4; struct sockaddr_in6 *ipv6; @@ -1010,8 +1010,8 @@ s32 org_mini_net_SocketNative_getSockAddr(Runtime *runtime, JClass *clazz) { struct sockaddr_in *ipv4 = NULL; struct sockaddr_in6 *ipv6 = NULL; - char ipAddr[INET6_ADDRSTRLEN];//保存点分十进制的地址 - int port = -1; + c8 ipAddr[INET6_ADDRSTRLEN];//保存点分十进制的地址 + s32 port = -1; if (sock.ss_family == AF_INET) {// IPv4 address ipv4 = ((struct sockaddr_in *) &sock); port = ipv4->sin_port; @@ -1045,7 +1045,7 @@ s32 org_mini_net_SocketNative_host2ip(Runtime *runtime, JClass *clazz) { Instance *jbyte_arr = NULL; if (host) { - char buf[50]; + c8 buf[50]; s32 ret = host_2_ip(host->arr_body, buf, sizeof(buf)); if (ret >= 0) { s32 buflen = strlen(buf); @@ -1192,8 +1192,8 @@ s32 is_ascii(const c8 *str) { } //gpt -int is_utf8(const c8 *string) { - const unsigned char *bytes = (const unsigned char *) string; +s32 is_utf8(const c8 *string) { + const u8 *bytes = (const u8 *) string; while (*bytes) { if ((// ASCII // 0xxxxxxx @@ -1229,7 +1229,7 @@ int is_utf8(const c8 *string) { s32 is_platform_encoding_utf8() { s32 ret = 0; setlocale(LC_ALL, ""); - char *locstr = setlocale(LC_CTYPE, NULL); + c8 *locstr = setlocale(LC_CTYPE, NULL); Utf8String *utfs = utf8_create_c(locstr); utf8_lowercase(utfs); if (utf8_indexof_c(utfs, "utf-8") >= 0) { @@ -1246,7 +1246,7 @@ s32 conv_platform_encoding_2_unicode(ByteBuf *dst, const c8 *src) { setlocale(LC_ALL, ""); s32 len = (s32) strlen(src); bytebuf_expand(dst, len * sizeof(wchar_t)); - int read = mbstowcs((wchar_t *) dst->buf, src, len); + s32 read = mbstowcs((wchar_t *) dst->buf, src, len); setlocale(LC_ALL, "C"); return read; } diff --git a/minijvm/c/jvm/jni_reflect.c b/minijvm/c/jvm/jni_reflect.c index 33108d81b..93b818d0b 100644 --- a/minijvm/c/jvm/jni_reflect.c +++ b/minijvm/c/jvm/jni_reflect.c @@ -17,32 +17,32 @@ static c8 *JDWP_CLASS_METHOD = "org/mini/reflect/ReflectMethod"; static c8 *JDWP_CLASS_ARRAY = "org/mini/reflect/ReflectArray"; static c8 *JDWP_CLASS_RUNTIME = "org/mini/reflect/StackFrame"; static c8 *JDWP_CLASS_LOCALVARTABLE = "org/mini/reflect/LocalVarTable"; -static c8 *JDWP_CLASS_VALUETYPE = "org/mini/reflect/vm/ValueType"; +static c8 *JDWP_CLASS_VALUETYPE = "org/mini/vm/ValueType"; //======== native============================================================================ -s32 org_mini_reflect_vm_RefNative_refIdSize(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_refIdSize(Runtime *runtime, JClass *clazz) { push_int(runtime->stack, sizeof(__refer)); #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_refIdSize\n"); + jvm_printf("org_mini_vm_RefNative_refIdSize\n"); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_obj2id(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_obj2id(Runtime *runtime, JClass *clazz) { Instance *ins = (Instance *) localvar_getRefer(runtime->localvar, 0); Long2Double l2d; l2d.l = (u64) (intptr_t) ins; push_long(runtime->stack, l2d.l); #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_obj2id\n"); + jvm_printf("org_mini_vm_RefNative_obj2id\n"); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_id2obj(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_id2obj(Runtime *runtime, JClass *clazz) { Long2Double l2d; l2d.l = localvar_getLong(runtime->localvar, 0); __refer r = (__refer) (intptr_t) l2d.l;//这里不能直接转化,可能在外部发生了数据精度丢失,只能从低位强转 @@ -54,7 +54,7 @@ s32 org_mini_reflect_vm_RefNative_id2obj(Runtime *runtime, JClass *clazz) { return 0; } -s32 org_mini_reflect_vm_RefNative_getClasses(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_getClasses(Runtime *runtime, JClass *clazz) { Utf8String *ustr = utf8_create_c(STR_CLASS_JAVA_LANG_CLASS); Instance *jarr = NULL; @@ -85,12 +85,12 @@ s32 org_mini_reflect_vm_RefNative_getClasses(Runtime *runtime, JClass *clazz) { push_ref(runtime->stack, jarr);//先放入栈,再关联回收器,防止多线程回收 #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_getClasses\n"); + jvm_printf("org_mini_vm_RefNative_getClasses\n"); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_getBootstrapClassByName(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_getBootstrapClassByName(Runtime *runtime, JClass *clazz) { Instance *jstr = (Instance *) localvar_getRefer(runtime->localvar, 0); Utf8String *ustr = utf8_create(); jstring_2_utf8(jstr, ustr, runtime); @@ -106,7 +106,7 @@ s32 org_mini_reflect_vm_RefNative_getBootstrapClassByName(Runtime *runtime, JCla } -s32 org_mini_reflect_vm_RefNative_newWithoutInit(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_newWithoutInit(Runtime *runtime, JClass *clazz) { RuntimeStack *stack = runtime->stack; JClass *cl = insOfJavaLangClass_get_classHandle(runtime, (Instance *) localvar_getRefer(runtime->localvar, 0)); Instance *ins = NULL; @@ -124,14 +124,14 @@ s32 org_mini_reflect_vm_RefNative_newWithoutInit(Runtime *runtime, JClass *clazz } #if _JVM_DEBUG_LOG_LEVEL > 5 invoke_deepth(runtime); - jvm_printf("org_mini_reflect_vm_RefNative_newWithoutInit class:[%llx] ins:[%llx]\n", (s64) (intptr_t) cl, (s64) (intptr_t) ins); + jvm_printf("org_mini_vm_RefNative_newWithoutInit class:[%llx] ins:[%llx]\n", (s64) (intptr_t) cl, (s64) (intptr_t) ins); #endif return ret; } -s32 org_mini_reflect_vm_RefNative_setLocalVal(Runtime *runtime, JClass *clazz) { - int pos = 0; +s32 org_mini_vm_RefNative_setLocalVal(Runtime *runtime, JClass *clazz) { + s32 pos = 0; Long2Double l2d; l2d.l = l2d.l = localvar_getLong(runtime->localvar, pos); pos += 2; @@ -164,8 +164,8 @@ s32 org_mini_reflect_vm_RefNative_setLocalVal(Runtime *runtime, JClass *clazz) { return 0; } -s32 org_mini_reflect_vm_RefNative_getLocalVal(Runtime *runtime, JClass *clazz) { - int pos = 0; +s32 org_mini_vm_RefNative_getLocalVal(Runtime *runtime, JClass *clazz) { + s32 pos = 0; Long2Double l2d; l2d.l = l2d.l = localvar_getLong(runtime->localvar, pos); pos += 2; @@ -201,7 +201,7 @@ s32 org_mini_reflect_vm_RefNative_getLocalVal(Runtime *runtime, JClass *clazz) { } s32 org_mini_reflect_ReflectField_getFieldVal(Runtime *runtime, JClass *clazz) { - int pos = 0; + s32 pos = 0; Long2Double l2d; Instance *ins = localvar_getRefer(runtime->localvar, pos); pos++; @@ -244,7 +244,7 @@ s32 org_mini_reflect_ReflectField_getFieldVal(Runtime *runtime, JClass *clazz) { } s32 org_mini_reflect_ReflectField_setFieldVal(Runtime *runtime, JClass *clazz) { - int pos = 0; + s32 pos = 0; Long2Double l2d; Instance *ins = localvar_getRefer(runtime->localvar, pos); pos++; @@ -345,7 +345,7 @@ void _list_iter_getthread(ArrayListValue value, void *para) { } } -s32 org_mini_reflect_vm_RefNative_getThreads(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_getThreads(Runtime *runtime, JClass *clazz) { // garbage_thread_lock(); Utf8String *ustr = utf8_create_c(STR_CLASS_JAVA_LANG_THREAD); Instance *jarr = jarray_create_by_type_name(runtime, runtime->jvm->thread_list->length, ustr, NULL); @@ -366,12 +366,12 @@ s32 org_mini_reflect_vm_RefNative_getThreads(Runtime *runtime, JClass *clazz) { push_ref(runtime->stack, jarr);//先放入栈,再关联回收器,防止多线程回收 // garbage_thread_unlock(); #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_getThreads\n"); + jvm_printf("org_mini_vm_RefNative_getThreads\n"); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_getStatus(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_getStatus(Runtime *runtime, JClass *clazz) { Instance *thread = (Instance *) localvar_getRefer(runtime->localvar, 0); Runtime *trun = (Runtime *) jthread_get_stackframe_value(runtime->jvm, thread);//线程结束之后会清除掉runtime,因为其是一个栈变量,不可再用 if (trun) @@ -384,7 +384,7 @@ s32 org_mini_reflect_vm_RefNative_getStatus(Runtime *runtime, JClass *clazz) { return 0; } -s32 org_mini_reflect_vm_RefNative_suspendThread(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_suspendThread(Runtime *runtime, JClass *clazz) { Instance *thread = (Instance *) localvar_getRefer(runtime->localvar, 0); Runtime *trun = (Runtime *) jthread_get_stackframe_value(runtime->jvm, thread);//线程结束之后会清除掉runtime,因为其是一个栈变量,不可再用 if (trun) { @@ -398,7 +398,7 @@ s32 org_mini_reflect_vm_RefNative_suspendThread(Runtime *runtime, JClass *clazz) return 0; } -s32 org_mini_reflect_vm_RefNative_resumeThread(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_resumeThread(Runtime *runtime, JClass *clazz) { Instance *thread = (Instance *) localvar_getRefer(runtime->localvar, 0); Runtime *trun = (Runtime *) jthread_get_stackframe_value(runtime->jvm, thread);//线程结束之后会清除掉runtime,因为其是一个栈变量,不可再用 if (trun) { @@ -413,7 +413,7 @@ s32 org_mini_reflect_vm_RefNative_resumeThread(Runtime *runtime, JClass *clazz) } -s32 org_mini_reflect_vm_RefNative_getSuspendCount(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_getSuspendCount(Runtime *runtime, JClass *clazz) { Instance *thread = (Instance *) localvar_getRefer(runtime->localvar, 0); Runtime *trun = (Runtime *) jthread_get_stackframe_value(runtime->jvm, thread);//线程结束之后会清除掉runtime,因为其是一个栈变量,不可再用 if (trun) { @@ -426,10 +426,10 @@ s32 org_mini_reflect_vm_RefNative_getSuspendCount(Runtime *runtime, JClass *claz return 0; } -s32 org_mini_reflect_vm_RefNative_getFrameCount(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_getFrameCount(Runtime *runtime, JClass *clazz) { Instance *thread = (Instance *) localvar_getRefer(runtime->localvar, 0); Runtime *trun = (Runtime *) jthread_get_stackframe_value(runtime->jvm, thread);//线程结束之后会清除掉runtime,因为其是一个栈变量,不可再用 - int i = 0; + s32 i = 0; while (trun) { i++; trun = trun->son; @@ -439,7 +439,7 @@ s32 org_mini_reflect_vm_RefNative_getFrameCount(Runtime *runtime, JClass *clazz) return 0; } -s32 org_mini_reflect_vm_RefNative_stopThread(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_stopThread(Runtime *runtime, JClass *clazz) { Instance *thread = (Instance *) localvar_getRefer(runtime->localvar, 0); Long2Double l2d; l2d.l = localvar_getLong(runtime->localvar, 1); @@ -456,7 +456,7 @@ s32 org_mini_reflect_vm_RefNative_stopThread(Runtime *runtime, JClass *clazz) { } -s32 org_mini_reflect_vm_RefNative_getStackFrame(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_getStackFrame(Runtime *runtime, JClass *clazz) { Instance *thread = (Instance *) localvar_getRefer(runtime->localvar, 0); Runtime *trun = (Runtime *) jthread_get_stackframe_value(runtime->jvm, thread);//线程结束之后会清除掉runtime,因为其是一个栈变量,不可再用 if (trun) { @@ -468,31 +468,31 @@ s32 org_mini_reflect_vm_RefNative_getStackFrame(Runtime *runtime, JClass *clazz) } else push_long(runtime->stack, 0); #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_getStackFrame %llx\n", (u64) (intptr_t) trun); + jvm_printf("org_mini_vm_RefNative_getStackFrame %llx\n", (u64) (intptr_t) trun); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_getGarbageMarkCounter(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_getGarbageMarkCounter(Runtime *runtime, JClass *clazz) { push_int(runtime->stack, runtime->jvm->collector->mark_cnt); #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_getGarbageMarkCounter \n"); + jvm_printf("org_mini_vm_RefNative_getGarbageMarkCounter \n"); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_getGarbageStatus(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_getGarbageStatus(Runtime *runtime, JClass *clazz) { push_int(runtime->stack, runtime->jvm->collector->_garbage_thread_status);//先放入栈,再关联回收器,防止多线程回收 #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_getGarbageStatus %d\n", runtime->jvm->collector->_garbage_thread_status); + jvm_printf("org_mini_vm_RefNative_getGarbageStatus %d\n", runtime->jvm->collector->_garbage_thread_status); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_defineClass(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_defineClass(Runtime *runtime, JClass *clazz) { s32 pos = 0; Instance *cloader = localvar_getRefer(runtime->localvar, pos++); Instance *namejstr = localvar_getRefer(runtime->localvar, pos++); @@ -515,12 +515,12 @@ s32 org_mini_reflect_vm_RefNative_defineClass(Runtime *runtime, JClass *clazz) { // push_ref(runtime->stack, NULL); #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_defineClass %d\n", runtime->jvm->collector->_garbage_thread_status); + jvm_printf("org_mini_vm_RefNative_defineClass %d\n", runtime->jvm->collector->_garbage_thread_status); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_findLoadedClass0(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_findLoadedClass0(Runtime *runtime, JClass *clazz) { s32 pos = 0; Instance *jloader = localvar_getRefer(runtime->localvar, pos++); Instance *namejstr = localvar_getRefer(runtime->localvar, pos++); @@ -536,19 +536,19 @@ s32 org_mini_reflect_vm_RefNative_findLoadedClass0(Runtime *runtime, JClass *cla push_ref(runtime->stack, NULL); } #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_findLoadedClass0 \n"); + jvm_printf("org_mini_vm_RefNative_findLoadedClass0 \n"); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_findResource0(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_findResource0(Runtime *runtime, JClass *clazz) { push_ref(runtime->stack, NULL); return 0; } -s32 org_mini_reflect_vm_RefNative_initNativeClassLoader(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_initNativeClassLoader(Runtime *runtime, JClass *clazz) { s32 pos = 0; Instance *jloader = localvar_getRefer(runtime->localvar, pos++); Instance *parent = localvar_getRefer(runtime->localvar, pos++); @@ -563,12 +563,12 @@ s32 org_mini_reflect_vm_RefNative_initNativeClassLoader(Runtime *runtime, JClass #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_initNativeClassLoader \n"); + jvm_printf("org_mini_vm_RefNative_initNativeClassLoader \n"); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_destroyNativeClassLoader(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_destroyNativeClassLoader(Runtime *runtime, JClass *clazz) { s32 pos = 0; Instance *jloader = localvar_getRefer(runtime->localvar, pos++); Instance *parent = localvar_getRefer(runtime->localvar, pos++); @@ -578,12 +578,12 @@ s32 org_mini_reflect_vm_RefNative_destroyNativeClassLoader(Runtime *runtime, JCl PeerClassLoader *cloader = classLoaders_find_by_instance(jvm, jloader); #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_destroyNativeClassLoader \n"); + jvm_printf("org_mini_vm_RefNative_destroyNativeClassLoader \n"); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_getCallerClass(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_getCallerClass(Runtime *runtime, JClass *clazz) { s32 found = 0; if (runtime->parent) { if (runtime->parent->parent) { @@ -596,12 +596,12 @@ s32 org_mini_reflect_vm_RefNative_getCallerClass(Runtime *runtime, JClass *clazz } #if _JVM_DEBUG_LOG_LEVEL > 5 - jvm_printf("org_mini_reflect_vm_RefNative_getCallerClass\n"); + jvm_printf("org_mini_vm_RefNative_getCallerClass\n"); #endif return 0; } -s32 org_mini_reflect_vm_RefNative_addJarToClasspath(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_addJarToClasspath(Runtime *runtime, JClass *clazz) { s32 pos = 0; Instance *jstr = localvar_getRefer(runtime->localvar, pos++); Utf8String *ustr = utf8_create(); @@ -615,7 +615,7 @@ s32 org_mini_reflect_vm_RefNative_addJarToClasspath(Runtime *runtime, JClass *cl } s32 org_mini_reflect_ReflectClass_mapClass(Runtime *runtime, JClass *clazz) { - int pos = 0; + s32 pos = 0; Instance *ins = (Instance *) localvar_getRefer(runtime->localvar, pos++); Long2Double l2d; l2d.l = l2d.l = localvar_getLong(runtime->localvar, pos); @@ -701,7 +701,7 @@ s32 org_mini_reflect_ReflectClass_mapClass(Runtime *runtime, JClass *clazz) { } s32 org_mini_reflect_ReflectField_mapField(Runtime *runtime, JClass *clazz) { - int pos = 0; + s32 pos = 0; Instance *ins = (Instance *) localvar_getRefer(runtime->localvar, pos++); Long2Double l2d; l2d.l = l2d.l = localvar_getLong(runtime->localvar, pos); @@ -774,7 +774,7 @@ Instance *localVarTable2java(JClass *clazz, LocalVarTable *lvt, Runtime *runtime } s32 org_mini_reflect_ReflectMethod_mapMethod(Runtime *runtime, JClass *clazz) { - int pos = 0; + s32 pos = 0; Instance *ins = (Instance *) localvar_getRefer(runtime->localvar, pos++); Long2Double l2d; l2d.l = l2d.l = localvar_getLong(runtime->localvar, pos); @@ -967,7 +967,7 @@ s32 org_mini_reflect_ReflectMethod_invokeMethod(Runtime *runtime, JClass *clazz) } s32 org_mini_reflect_StackFrame_mapRuntime(Runtime *runtime, JClass *clazz) { - int pos = 0; + s32 pos = 0; Instance *ins = (Instance *) localvar_getRefer(runtime->localvar, pos++); Long2Double l2d; l2d.l = localvar_getLong(runtime->localvar, pos); @@ -1025,7 +1025,7 @@ s32 org_mini_reflect_ReflectMethod_findMethod0(Runtime *runtime, JClass *clazz) } s32 org_mini_reflect_ReflectMethod_getExceptionTypes0(Runtime *runtime, JClass *clazz) { - int pos = 0; + s32 pos = 0; Instance *ins = (Instance *) localvar_getRefer(runtime->localvar, pos++); Long2Double l2d; l2d.l = localvar_getLong(runtime->localvar, pos); @@ -1052,7 +1052,7 @@ s32 org_mini_reflect_ReflectMethod_getExceptionTypes0(Runtime *runtime, JClass * } s32 org_mini_reflect_ReflectArray_mapArray(Runtime *runtime, JClass *clazz) { - int pos = 0; + s32 pos = 0; Instance *ins = (Instance *) localvar_getRefer(runtime->localvar, pos++); Long2Double l2d; l2d.l = l2d.l = localvar_getLong(runtime->localvar, pos); @@ -1258,7 +1258,7 @@ s32 org_mini_reflect_DirectMemObj_copyFrom0(Runtime *runtime, JClass *clazz) { return ret; } -s32 org_mini_reflect_vm_RefNative_heap_calloc(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_calloc(Runtime *runtime, JClass *clazz) { s32 pos = 0; s32 size = localvar_getInt(runtime->localvar, pos++); @@ -1269,7 +1269,7 @@ s32 org_mini_reflect_vm_RefNative_heap_calloc(Runtime *runtime, JClass *clazz) { return 0; } -s32 org_mini_reflect_vm_RefNative_heap_free(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_free(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer ptr = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1279,7 +1279,7 @@ s32 org_mini_reflect_vm_RefNative_heap_free(Runtime *runtime, JClass *clazz) { return 0; } -s32 org_mini_reflect_vm_RefNative_heap_put_byte(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_put_byte(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer ptr = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1291,7 +1291,7 @@ s32 org_mini_reflect_vm_RefNative_heap_put_byte(Runtime *runtime, JClass *clazz) return 0; } -s32 org_mini_reflect_vm_RefNative_heap_get_byte(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_get_byte(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer ptr = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1301,7 +1301,7 @@ s32 org_mini_reflect_vm_RefNative_heap_get_byte(Runtime *runtime, JClass *clazz) return 0; } -s32 org_mini_reflect_vm_RefNative_heap_put_short(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_put_short(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer ptr = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1313,7 +1313,7 @@ s32 org_mini_reflect_vm_RefNative_heap_put_short(Runtime *runtime, JClass *clazz return 0; } -s32 org_mini_reflect_vm_RefNative_heap_get_short(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_get_short(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer ptr = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1323,7 +1323,7 @@ s32 org_mini_reflect_vm_RefNative_heap_get_short(Runtime *runtime, JClass *clazz return 0; } -s32 org_mini_reflect_vm_RefNative_heap_put_int(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_put_int(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer ptr = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1335,7 +1335,7 @@ s32 org_mini_reflect_vm_RefNative_heap_put_int(Runtime *runtime, JClass *clazz) return 0; } -s32 org_mini_reflect_vm_RefNative_heap_get_int(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_get_int(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer ptr = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1345,7 +1345,7 @@ s32 org_mini_reflect_vm_RefNative_heap_get_int(Runtime *runtime, JClass *clazz) return 0; } -s32 org_mini_reflect_vm_RefNative_heap_put_long(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_put_long(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer ptr = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1357,7 +1357,7 @@ s32 org_mini_reflect_vm_RefNative_heap_put_long(Runtime *runtime, JClass *clazz) return 0; } -s32 org_mini_reflect_vm_RefNative_heap_get_long(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_get_long(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer ptr = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1367,7 +1367,7 @@ s32 org_mini_reflect_vm_RefNative_heap_get_long(Runtime *runtime, JClass *clazz) return 0; } -s32 org_mini_reflect_vm_RefNative_heap_put_ref(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_put_ref(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer ptr = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1379,7 +1379,7 @@ s32 org_mini_reflect_vm_RefNative_heap_put_ref(Runtime *runtime, JClass *clazz) return 0; } -s32 org_mini_reflect_vm_RefNative_heap_get_ref(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_get_ref(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer ptr = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1389,7 +1389,7 @@ s32 org_mini_reflect_vm_RefNative_heap_get_ref(Runtime *runtime, JClass *clazz) return 0; } -s32 org_mini_reflect_vm_RefNative_heap_copy(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_copy(Runtime *runtime, JClass *clazz) { s32 pos = 0; __refer src = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1406,7 +1406,7 @@ s32 org_mini_reflect_vm_RefNative_heap_copy(Runtime *runtime, JClass *clazz) { return 0; } -s32 org_mini_reflect_vm_RefNative_heap_bin_search(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_bin_search(Runtime *runtime, JClass *clazz) { s32 pos = 0; c8 *src = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1442,7 +1442,7 @@ s32 org_mini_reflect_vm_RefNative_heap_bin_search(Runtime *runtime, JClass *claz return 0; } -s32 org_mini_reflect_vm_RefNative_heap_fill(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_fill(Runtime *runtime, JClass *clazz) { s32 pos = 0; c8 *src = (__refer) (intptr_t) localvar_getLong(runtime->localvar, pos); pos += 2; @@ -1467,7 +1467,7 @@ s32 org_mini_reflect_vm_RefNative_heap_fill(Runtime *runtime, JClass *clazz) { return 0; } -s32 org_mini_reflect_vm_RefNative_heap_little_endian(Runtime *runtime, JClass *clazz) { +s32 org_mini_vm_RefNative_heap_little_endian(Runtime *runtime, JClass *clazz) { push_int(runtime->stack, __JVM_LITTLE_ENDIAN__); return 0; } @@ -1625,51 +1625,51 @@ s32 com_misc_Unsafe_unpack(Runtime *runtime, JClass *clazz) { static java_native_method METHODS_REFLECT_TABLE[] = { - {"org/mini/reflect/vm/RefNative", "refIdSize", "()I", org_mini_reflect_vm_RefNative_refIdSize}, - {"org/mini/reflect/vm/RefNative", "obj2id", "(Ljava/lang/Object;)J", org_mini_reflect_vm_RefNative_obj2id}, - {"org/mini/reflect/vm/RefNative", "id2obj", "(J)Ljava/lang/Object;", org_mini_reflect_vm_RefNative_id2obj}, - {"org/mini/reflect/vm/RefNative", "getClasses", "()[Ljava/lang/Class;", org_mini_reflect_vm_RefNative_getClasses}, - {"org/mini/reflect/vm/RefNative", "getBootstrapClassByName", "(Ljava/lang/String;)Ljava/lang/Class;", org_mini_reflect_vm_RefNative_getBootstrapClassByName}, - {"org/mini/reflect/vm/RefNative", "newWithoutInit", "(Ljava/lang/Class;)Ljava/lang/Object;", org_mini_reflect_vm_RefNative_newWithoutInit}, - {"org/mini/reflect/vm/RefNative", "setLocalVal", "(JIBJI)I", org_mini_reflect_vm_RefNative_setLocalVal}, - {"org/mini/reflect/vm/RefNative", "getLocalVal", "(JILorg/mini/jdwp/type/ValueType;)I", org_mini_reflect_vm_RefNative_getLocalVal}, - {"org/mini/reflect/vm/RefNative", "getThreads", "()[Ljava/lang/Thread;", org_mini_reflect_vm_RefNative_getThreads}, - {"org/mini/reflect/vm/RefNative", "getStatus", "(Ljava/lang/Thread;)I", org_mini_reflect_vm_RefNative_getStatus}, - {"org/mini/reflect/vm/RefNative", "suspendThread", "(Ljava/lang/Thread;)I", org_mini_reflect_vm_RefNative_suspendThread}, - {"org/mini/reflect/vm/RefNative", "resumeThread", "(Ljava/lang/Thread;)I", org_mini_reflect_vm_RefNative_resumeThread}, - {"org/mini/reflect/vm/RefNative", "getSuspendCount", "(Ljava/lang/Thread;)I", org_mini_reflect_vm_RefNative_getSuspendCount}, - {"org/mini/reflect/vm/RefNative", "getFrameCount", "(Ljava/lang/Thread;)I", org_mini_reflect_vm_RefNative_getFrameCount}, - {"org/mini/reflect/vm/RefNative", "stopThread", "(Ljava/lang/Thread;J)I", org_mini_reflect_vm_RefNative_stopThread}, - {"org/mini/reflect/vm/RefNative", "getStackFrame", "(Ljava/lang/Thread;)J", org_mini_reflect_vm_RefNative_getStackFrame}, - {"org/mini/reflect/vm/RefNative", "getGarbageMarkCounter", "()I", org_mini_reflect_vm_RefNative_getGarbageMarkCounter}, - {"org/mini/reflect/vm/RefNative", "getGarbageStatus", "()I", org_mini_reflect_vm_RefNative_getGarbageStatus}, - {"org/mini/reflect/vm/RefNative", "getCallerClass", "()Ljava/lang/Class;", org_mini_reflect_vm_RefNative_getCallerClass}, - {"org/mini/reflect/vm/RefNative", "defineClass", "(Ljava/lang/ClassLoader;Ljava/lang/String;[BII)Ljava/lang/Class;", org_mini_reflect_vm_RefNative_defineClass}, - {"org/mini/reflect/vm/RefNative", "findLoadedClass0", "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;", org_mini_reflect_vm_RefNative_findLoadedClass0}, - {"org/mini/reflect/vm/RefNative", "findResource0", "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/net/URL;", org_mini_reflect_vm_RefNative_findResource0}, - {"org/mini/reflect/vm/RefNative", "initNativeClassLoader", "(Ljava/lang/ClassLoader;Ljava/lang/ClassLoader;)V", org_mini_reflect_vm_RefNative_initNativeClassLoader}, - {"org/mini/reflect/vm/RefNative", "destroyNativeClassLoader", "(Ljava/lang/ClassLoader;)V", org_mini_reflect_vm_RefNative_destroyNativeClassLoader}, - {"org/mini/reflect/vm/RefNative", "addJarToClasspath", "(Ljava/lang/String;)V", org_mini_reflect_vm_RefNative_addJarToClasspath}, - {"org/mini/reflect/vm/RefNative", "heap_calloc", "(I)J", org_mini_reflect_vm_RefNative_heap_calloc}, - {"org/mini/reflect/vm/RefNative", "heap_free", "(J)V", org_mini_reflect_vm_RefNative_heap_free}, - {"org/mini/reflect/vm/RefNative", "heap_put_byte", "(JIB)V", org_mini_reflect_vm_RefNative_heap_put_byte}, - {"org/mini/reflect/vm/RefNative", "heap_get_byte", "(JI)B", org_mini_reflect_vm_RefNative_heap_get_byte}, - {"org/mini/reflect/vm/RefNative", "heap_put_short", "(JIS)V", org_mini_reflect_vm_RefNative_heap_put_short}, - {"org/mini/reflect/vm/RefNative", "heap_get_short", "(JI)S", org_mini_reflect_vm_RefNative_heap_get_short}, - {"org/mini/reflect/vm/RefNative", "heap_put_int", "(JII)V", org_mini_reflect_vm_RefNative_heap_put_int}, - {"org/mini/reflect/vm/RefNative", "heap_get_int", "(JI)I", org_mini_reflect_vm_RefNative_heap_get_int}, - {"org/mini/reflect/vm/RefNative", "heap_put_long", "(JIJ)V", org_mini_reflect_vm_RefNative_heap_put_long}, - {"org/mini/reflect/vm/RefNative", "heap_get_long", "(JI)J", org_mini_reflect_vm_RefNative_heap_get_long}, - {"org/mini/reflect/vm/RefNative", "heap_put_float", "(JIF)V", org_mini_reflect_vm_RefNative_heap_put_int}, - {"org/mini/reflect/vm/RefNative", "heap_get_float", "(JI)F", org_mini_reflect_vm_RefNative_heap_get_int}, - {"org/mini/reflect/vm/RefNative", "heap_put_double", "(JID)V", org_mini_reflect_vm_RefNative_heap_put_long}, - {"org/mini/reflect/vm/RefNative", "heap_get_double", "(JI)D", org_mini_reflect_vm_RefNative_heap_get_long}, - {"org/mini/reflect/vm/RefNative", "heap_put_ref", "(JILjava/lang/Object;)V", org_mini_reflect_vm_RefNative_heap_put_ref}, - {"org/mini/reflect/vm/RefNative", "heap_get_ref", "(JI)Ljava/lang/Object;", org_mini_reflect_vm_RefNative_heap_get_ref}, - {"org/mini/reflect/vm/RefNative", "heap_copy", "(JIJII)V", org_mini_reflect_vm_RefNative_heap_copy}, - {"org/mini/reflect/vm/RefNative", "heap_bin_search", "(JIJI)I", org_mini_reflect_vm_RefNative_heap_bin_search}, - {"org/mini/reflect/vm/RefNative", "heap_fill", "(JIJI)V", org_mini_reflect_vm_RefNative_heap_fill}, - {"org/mini/reflect/vm/RefNative", "heap_endian", "()I", org_mini_reflect_vm_RefNative_heap_little_endian}, + {"org/mini/vm/RefNative", "refIdSize", "()I", org_mini_vm_RefNative_refIdSize}, + {"org/mini/vm/RefNative", "obj2id", "(Ljava/lang/Object;)J", org_mini_vm_RefNative_obj2id}, + {"org/mini/vm/RefNative", "id2obj", "(J)Ljava/lang/Object;", org_mini_vm_RefNative_id2obj}, + {"org/mini/vm/RefNative", "getClasses", "()[Ljava/lang/Class;", org_mini_vm_RefNative_getClasses}, + {"org/mini/vm/RefNative", "getBootstrapClassByName", "(Ljava/lang/String;)Ljava/lang/Class;", org_mini_vm_RefNative_getBootstrapClassByName}, + {"org/mini/vm/RefNative", "newWithoutInit", "(Ljava/lang/Class;)Ljava/lang/Object;", org_mini_vm_RefNative_newWithoutInit}, + {"org/mini/vm/RefNative", "setLocalVal", "(JIBJI)I", org_mini_vm_RefNative_setLocalVal}, + {"org/mini/vm/RefNative", "getLocalVal", "(JILorg/mini/jdwp/type/ValueType;)I", org_mini_vm_RefNative_getLocalVal}, + {"org/mini/vm/RefNative", "getThreads", "()[Ljava/lang/Thread;", org_mini_vm_RefNative_getThreads}, + {"org/mini/vm/RefNative", "getStatus", "(Ljava/lang/Thread;)I", org_mini_vm_RefNative_getStatus}, + {"org/mini/vm/RefNative", "suspendThread", "(Ljava/lang/Thread;)I", org_mini_vm_RefNative_suspendThread}, + {"org/mini/vm/RefNative", "resumeThread", "(Ljava/lang/Thread;)I", org_mini_vm_RefNative_resumeThread}, + {"org/mini/vm/RefNative", "getSuspendCount", "(Ljava/lang/Thread;)I", org_mini_vm_RefNative_getSuspendCount}, + {"org/mini/vm/RefNative", "getFrameCount", "(Ljava/lang/Thread;)I", org_mini_vm_RefNative_getFrameCount}, + {"org/mini/vm/RefNative", "stopThread", "(Ljava/lang/Thread;J)I", org_mini_vm_RefNative_stopThread}, + {"org/mini/vm/RefNative", "getStackFrame", "(Ljava/lang/Thread;)J", org_mini_vm_RefNative_getStackFrame}, + {"org/mini/vm/RefNative", "getGarbageMarkCounter", "()I", org_mini_vm_RefNative_getGarbageMarkCounter}, + {"org/mini/vm/RefNative", "getGarbageStatus", "()I", org_mini_vm_RefNative_getGarbageStatus}, + {"org/mini/vm/RefNative", "getCallerClass", "()Ljava/lang/Class;", org_mini_vm_RefNative_getCallerClass}, + {"org/mini/vm/RefNative", "defineClass", "(Ljava/lang/ClassLoader;Ljava/lang/String;[BII)Ljava/lang/Class;", org_mini_vm_RefNative_defineClass}, + {"org/mini/vm/RefNative", "findLoadedClass0", "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;", org_mini_vm_RefNative_findLoadedClass0}, + {"org/mini/vm/RefNative", "findResource0", "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/net/URL;", org_mini_vm_RefNative_findResource0}, + {"org/mini/vm/RefNative", "initNativeClassLoader", "(Ljava/lang/ClassLoader;Ljava/lang/ClassLoader;)V", org_mini_vm_RefNative_initNativeClassLoader}, + {"org/mini/vm/RefNative", "destroyNativeClassLoader", "(Ljava/lang/ClassLoader;)V", org_mini_vm_RefNative_destroyNativeClassLoader}, + {"org/mini/vm/RefNative", "addJarToClasspath", "(Ljava/lang/String;)V", org_mini_vm_RefNative_addJarToClasspath}, + {"org/mini/vm/RefNative", "heap_calloc", "(I)J", org_mini_vm_RefNative_heap_calloc}, + {"org/mini/vm/RefNative", "heap_free", "(J)V", org_mini_vm_RefNative_heap_free}, + {"org/mini/vm/RefNative", "heap_put_byte", "(JIB)V", org_mini_vm_RefNative_heap_put_byte}, + {"org/mini/vm/RefNative", "heap_get_byte", "(JI)B", org_mini_vm_RefNative_heap_get_byte}, + {"org/mini/vm/RefNative", "heap_put_short", "(JIS)V", org_mini_vm_RefNative_heap_put_short}, + {"org/mini/vm/RefNative", "heap_get_short", "(JI)S", org_mini_vm_RefNative_heap_get_short}, + {"org/mini/vm/RefNative", "heap_put_int", "(JII)V", org_mini_vm_RefNative_heap_put_int}, + {"org/mini/vm/RefNative", "heap_get_int", "(JI)I", org_mini_vm_RefNative_heap_get_int}, + {"org/mini/vm/RefNative", "heap_put_long", "(JIJ)V", org_mini_vm_RefNative_heap_put_long}, + {"org/mini/vm/RefNative", "heap_get_long", "(JI)J", org_mini_vm_RefNative_heap_get_long}, + {"org/mini/vm/RefNative", "heap_put_float", "(JIF)V", org_mini_vm_RefNative_heap_put_int}, + {"org/mini/vm/RefNative", "heap_get_float", "(JI)F", org_mini_vm_RefNative_heap_get_int}, + {"org/mini/vm/RefNative", "heap_put_double", "(JID)V", org_mini_vm_RefNative_heap_put_long}, + {"org/mini/vm/RefNative", "heap_get_double", "(JI)D", org_mini_vm_RefNative_heap_get_long}, + {"org/mini/vm/RefNative", "heap_put_ref", "(JILjava/lang/Object;)V", org_mini_vm_RefNative_heap_put_ref}, + {"org/mini/vm/RefNative", "heap_get_ref", "(JI)Ljava/lang/Object;", org_mini_vm_RefNative_heap_get_ref}, + {"org/mini/vm/RefNative", "heap_copy", "(JIJII)V", org_mini_vm_RefNative_heap_copy}, + {"org/mini/vm/RefNative", "heap_bin_search", "(JIJI)I", org_mini_vm_RefNative_heap_bin_search}, + {"org/mini/vm/RefNative", "heap_fill", "(JIJI)V", org_mini_vm_RefNative_heap_fill}, + {"org/mini/vm/RefNative", "heap_endian", "()I", org_mini_vm_RefNative_heap_little_endian}, {"org/mini/reflect/ReflectClass", "mapClass", "(J)V", org_mini_reflect_ReflectClass_mapClass}, {"org/mini/reflect/ReflectField", "mapField", "(J)V", org_mini_reflect_ReflectField_mapField}, {"org/mini/reflect/ReflectField", "getFieldVal", "(Ljava/lang/Object;J)J", org_mini_reflect_ReflectField_getFieldVal}, diff --git a/minijvm/c/jvm/jni_std.c b/minijvm/c/jvm/jni_std.c index c7808bd72..26fa4e936 100644 --- a/minijvm/c/jvm/jni_std.c +++ b/minijvm/c/jvm/jni_std.c @@ -703,9 +703,9 @@ s32 java_lang_String_replace0(Runtime *runtime, JClass *clazz) { u16 *dst_value = (u16 *) jstring_get_value_array(dst, runtime)->arr_body; ByteBuf *sb = bytebuf_create(count); - int i, j; + s32 i, j; for (i = 0; i < count;) { - int index = i + offset; + s32 index = i + offset; u16 ch = value[index]; s32 match = 0; if (ch == src_value[src_offset] && index + src_count <= offset + count) { diff --git a/minijvm/c/jvm/jvm.c b/minijvm/c/jvm/jvm.c index 36080658b..3d939d532 100644 --- a/minijvm/c/jvm/jvm.c +++ b/minijvm/c/jvm/jvm.c @@ -213,7 +213,7 @@ void classloaders_destroy_all(MiniJVM *jvm) { jvm->classloaders = NULL; } -void set_jvm_state(MiniJVM *jvm, int state) { +void set_jvm_state(MiniJVM *jvm, s32 state) { jvm->jvm_state = state; } @@ -221,11 +221,11 @@ s32 get_jvm_state(MiniJVM *jvm) { return jvm->jvm_state; } -void _on_jvm_sig_print(int no) { +void _on_jvm_sig_print(s32 no) { jvm_printf("[SIGNAL]jvm sig:%d errno: %d , %s\n", no, errno, strerror(errno)); } -void _on_jvm_sig(int no) { +void _on_jvm_sig(s32 no) { _on_jvm_sig_print(no); exit(no); } @@ -320,7 +320,7 @@ s32 jvm_init(MiniJVM *jvm, c8 *p_bootclasspath, c8 *p_classpath) { utf8_append_c(clsName, STR_CLASS_JAVA_LANG_THREAD); classes_load_get(NULL, clsName, runtime); utf8_clear(clsName); - utf8_append_c(clsName, STR_CLASS_ORG_MINI_REFLECT_LAUNCHER); + utf8_append_c(clsName, STR_CLASS_SUN_MISC_LAUNCHER); classes_load_get(NULL, clsName, runtime); //开始装载类 utf8_destory(clsName); @@ -398,7 +398,7 @@ s32 call_main(MiniJVM *jvm, c8 *p_mainclass, ArrayList *java_para) { Instance *arr = jarray_create_by_type_name(runtime, count, ustr, NULL); instance_hold_to_thread(arr, runtime); utf8_destory(ustr); - int i; + s32 i; for (i = 0; i < count; i++) { Utf8String *utfs = utf8_create_c(arraylist_get_value(java_para, i)); Instance *jstr = jstring_create(utfs, runtime); @@ -470,7 +470,9 @@ s32 call_method(MiniJVM *jvm, c8 *p_classname, c8 *p_methodname, c8 *p_methoddes if (_JVM_JDWP_ENABLE) { if (jvm->jdwp_enable) { if (jvm->jdwp_suspend_on_start)jthread_suspend(runtime); +#if _JVM_DEBUG_LOG_LEVEL > 0 jvm_printf("[JDWP]jdwp listening (port:%s) ...\n", JDWP_TCP_PORT); +#endif }//jdwp 会启动调试器 } runtime->method = NULL; diff --git a/minijvm/c/jvm/jvm.h b/minijvm/c/jvm/jvm.h index e5451484b..8d0c0e07b 100644 --- a/minijvm/c/jvm/jvm.h +++ b/minijvm/c/jvm/jvm.h @@ -27,7 +27,7 @@ extern "C" { //======================= micro define ============================= //_JVM_DEBUG 01=thread info, 02=garage&jit info , 03=class load, 04=method call, 06=all bytecode -#define _JVM_DEBUG_LOG_LEVEL 01 +#define _JVM_DEBUG_LOG_LEVEL 0 #define _JVM_DEBUG_LOG_TO_FILE 0 #define _JVM_DEBUG_GARBAGE_DUMP 0 #define _JVM_DEBUG_PROFILE 0 @@ -465,7 +465,7 @@ enum { THREAD_TYPE_JDWP, }; -extern char *STRS_CLASS_EXCEPTION[]; +extern c8 *STRS_CLASS_EXCEPTION[]; extern c8 const *STR_CLASS_JAVA_LANG_STRING; extern c8 const *STR_CLASS_JAVA_LANG_STRINGBUILDER; @@ -489,7 +489,7 @@ extern c8 const *STR_CLASS_JAVA_LANG_INVOKE_METHODTYPE; extern c8 const *STR_CLASS_JAVA_LANG_INVOKE_METHODHANDLE; extern c8 const *STR_CLASS_JAVA_LANG_INVOKE_METHODHANDLES_LOOKUP; extern c8 const *STR_CLASS_ORG_MINI_REFLECT_DIRECTMEMOBJ; -extern c8 const *STR_CLASS_ORG_MINI_REFLECT_LAUNCHER; +extern c8 const *STR_CLASS_SUN_MISC_LAUNCHER; extern c8 const *STR_CLASS_ORG_MINI_REFLECT_REFLECTMETHOD; extern c8 const *STR_FIELD_STACKFRAME; @@ -1681,9 +1681,9 @@ struct _JNIENV { Utf8String *(*utf8_create)(); - Utf8String *(*utf8_create_part_c)(char const *str, int start, int len); + Utf8String *(*utf8_create_part_c)(c8 const *str, s32 start, s32 len); - char const *(*utf8_cstr)(Utf8String *a1); + c8 const *(*utf8_cstr)(Utf8String *a1); void (*utf8_destory)(Utf8String *); @@ -1894,7 +1894,7 @@ s32 execute_method(MethodInfo *method, Runtime *runtime); s32 get_jvm_state(MiniJVM *jvm); -void set_jvm_state(MiniJVM *jvm, int state); +void set_jvm_state(MiniJVM *jvm, s32 state); //======================= ============================= diff --git a/minijvm/c/jvm/jvm_util.c b/minijvm/c/jvm/jvm_util.c index 945c2b72d..32b0d22f7 100644 --- a/minijvm/c/jvm/jvm_util.c +++ b/minijvm/c/jvm/jvm_util.c @@ -355,7 +355,7 @@ void vm_share_wait(MiniJVM *jvm) { void vm_share_timedwait(MiniJVM *jvm, s64 ms) { struct timespec t; - clock_gettime(CLOCK_REALTIME, &t); + timespec_get(&t, TIME_UTC); t.tv_sec += ms / 1000; t.tv_nsec += (ms % 1000) * 1000000; s32 ret = cnd_timedwait(&jvm->threadlock.thread_cond, &jvm->threadlock.mutex_lock, &t); @@ -406,7 +406,7 @@ s32 enc_get_utf8_size(const c8 *pInput) { s32 utf8_2_unicode(Utf8String *ustr, u16 *arr) { c8 const *pInput = utf8_cstr(ustr); //assert(pInput != NULL && Unic != NULL); - int outputSize = 0; //记录转换后的Unicode字符串的字节数 + s32 outputSize = 0; //记录转换后的Unicode字符串的字节数 // b1 表示UTF-8编码的pInput中的高字节, b2 表示次高字节, ... c8 b1, b2, b3, b4, b5, b6; s32 codepoint = 0; @@ -414,7 +414,7 @@ s32 utf8_2_unicode(Utf8String *ustr, u16 *arr) { while (*pInput) { //*Unic = 0x0; // 把 *Unic 初始化为全零 - int utfbytes = enc_get_utf8_size(pInput); + s32 utfbytes = enc_get_utf8_size(pInput); //printf("%d", utfbytes); codepoint = 0; switch (utfbytes) { @@ -521,11 +521,11 @@ s32 unicode_2_utf8(u16 *jchar_arr, Utf8String *ustr, s32 totalSize) { s32 unic = jchar_arr[i]; if (unic >= 0xd800 && unic <= 0xdbff) { if (i + 1 < totalSize) { - int c1 = jchar_arr[i + 1]; + s32 c1 = jchar_arr[i + 1]; if (c1 >= 0xdc00 && c1 <= 0xdfff) { i++; - int lead = unic & 0x3ff; - int trail = c1 & 0x3ff; + s32 lead = unic & 0x3ff; + s32 trail = c1 & 0x3ff; unic = (lead << 10) | trail | 0x10000; } } @@ -581,7 +581,7 @@ s32 unicode_2_utf8(u16 *jchar_arr, Utf8String *ustr, s32 totalSize) { * @param size len */ void swap_endian_little_big(u8 *ptr, s32 size) { - int i; + s32 i; for (i = 0; i < size / 2; i++) { u8 tmp = ptr[i]; ptr[i] = ptr[size - 1 - i]; @@ -823,10 +823,10 @@ void close_log() { #endif } -int jvm_printf(const char *format, ...) { +s32 jvm_printf(const c8 *format, ...) { va_list vp; va_start(vp, format); - int result = 0; + s32 result = 0; #if _JVM_DEBUG_LOG_TO_FILE if (logfile) { @@ -847,7 +847,7 @@ int jvm_printf(const char *format, ...) { void invoke_deepth(Runtime *runtime) { vm_share_lock(runtime->jvm); - int i = 0; + s32 i = 0; Runtime *r = runtime; while (r) { i++; @@ -1218,7 +1218,7 @@ Instance *jarray_multi_create(Runtime *runtime, s32 *dim, s32 dim_size, Utf8Stri jvm_printf("multi arr deep :%d type(%c) arr[%x] size:%d\n", deep, ch, arr, len); #endif if (ch == '[') { - int i; + s32 i; s64 val; for (i = 0; i < len; i++) { Instance *elem = jarray_multi_create(runtime, dim, dim_size, desc, deep + 1); @@ -1577,7 +1577,7 @@ u16 jstring_char_at(Instance *jstr, s32 index, Runtime *runtime) { s32 jstring_index_of(Instance *jstr, u16 ch, s32 startAt, Runtime *runtime) { c8 *fieldPtr = jstring_get_value_ptr(jstr, runtime); - Instance *ptr = (Instance *) getFieldRefer(fieldPtr);//char[]数组实例 + Instance *ptr = (Instance *) getFieldRefer(fieldPtr);//c8[]数组实例 if (ptr && ptr->arr_body && startAt >= 0) { u16 *jchar_arr = (u16 *) ptr->arr_body; s32 count = jstring_get_count(jstr, runtime); @@ -1600,8 +1600,8 @@ s32 jstring_equals(Instance *jstr1, Instance *jstr2, Runtime *runtime) { } else if (!jstr2) { return 0; } - Instance *arr1 = jstring_get_value_array(jstr1, runtime);//取得 char[] value - Instance *arr2 = jstring_get_value_array(jstr2, runtime);//取得 char[] value + Instance *arr1 = jstring_get_value_array(jstr1, runtime);//取得 c8[] value + Instance *arr2 = jstring_get_value_array(jstr2, runtime);//取得 c8[] value s32 count1 = 0, offset1 = 0, count2 = 0, offset2 = 0; //0长度字符串可能value[] 是空值,也可能不是空值但count是0 if (arr1) { @@ -1840,14 +1840,14 @@ void threadinfo_destory(JavaThreadInfo *threadInfo) { s64 currentTimeMillis() { struct timespec tv; - clock_gettime(CLOCK_REALTIME, &tv); + timespec_get(&tv, TIME_UTC); return ((s64) tv.tv_sec) * MILL_2_SEC_SCALE + tv.tv_nsec / NANO_2_MILLS_SCALE; } s64 nanoTime() { struct timespec tv; - clock_gettime(CLOCK_REALTIME, &tv); + timespec_get(&tv, TIME_UTC); if (!nano_sec_start_at) { nano_sec_start_at = ((s64) tv.tv_sec) * NANO_2_SEC_SCALE + tv.tv_nsec; @@ -1901,7 +1901,7 @@ void instance_release_from_thread(Instance *ins, Runtime *runtime) { } } -CStringArr *cstringarr_create(Instance *jstr_arr) { //byte[][] to char** +CStringArr *cstringarr_create(Instance *jstr_arr) { //byte[][] to c8** if (!jstr_arr)return NULL; CStringArr *cstr_arr = jvm_calloc(sizeof(CStringArr)); cstr_arr->arr_length = jstr_arr->arr_length; @@ -1956,7 +1956,7 @@ s32 _loadFileContents(c8 const *file, ByteBuf *buf) { FILE *pFile; long lSize; - char *buffer; + c8 *buffer; size_t result; /* 若要一个byte不漏地读入整个文件,只能采用二进制方式打开 */ diff --git a/minijvm/c/jvm/jvm_util.h b/minijvm/c/jvm/jvm_util.h index 578d48911..9feeba524 100644 --- a/minijvm/c/jvm/jvm_util.h +++ b/minijvm/c/jvm/jvm_util.h @@ -22,7 +22,7 @@ s32 isDir(Utf8String *path); s32 utf8_2_unicode(Utf8String *ustr, u16 *arr); -int unicode_2_utf8(u16 *jchar_arr, Utf8String *ustr, s32 totalSize); +s32 unicode_2_utf8(u16 *jchar_arr, Utf8String *ustr, s32 totalSize); void swap_endian_little_big(u8 *ptr, s32 size); @@ -58,7 +58,7 @@ void instance_release_from_thread(Instance *ref, Runtime *runtime); void instance_hold_to_thread(Instance *ins, Runtime *runtime); -int jvm_printf(const char *, ...); +s32 jvm_printf(const c8 *, ...); void invoke_deepth(Runtime *runtime); diff --git a/minijvm/c/main.c b/minijvm/c/main.c index f581de202..61a3b6843 100644 --- a/minijvm/c/main.c +++ b/minijvm/c/main.c @@ -26,6 +26,7 @@ int main(int argc, char **argv) { c8 *bootclasspath = NULL; c8 *classpath = NULL; c8 *main_name = NULL; + s32 print_version = 0; s32 main_set = 0; ArrayList *java_para = arraylist_create(0); s32 jdwp = 0; @@ -42,8 +43,9 @@ int main(int argc, char **argv) { s32 dpos = utf8_last_indexof_c(startup_dir, "/"); if (dpos > 0)utf8_substring(startup_dir, 0, dpos); utf8_append_c(startup_dir, "/"); +#if _JVM_DEBUG_LOG_LEVEL > 0 jvm_printf("App dir:%s\n", utf8_cstr(startup_dir)); - +#endif //default value { utf8_append(bootcp, startup_dir); @@ -127,6 +129,11 @@ int main(int argc, char **argv) { if (strcmp(argv[i], "-bootclasspath") == 0) { bootclasspath = argv[i + 1]; i++; + } else if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "--version") == 0) { + print_version = 1; + classpath = NULL; + main_name = "org.mini.vm.PrintVersion"; + i++; } else if (strcmp(argv[i], "-cp") == 0 || strcmp(argv[i], "-classpath") == 0) { classpath = argv[i + 1]; i++; diff --git a/minijvm/c/utils/spinlock.h b/minijvm/c/utils/spinlock.h index d873f7f30..0977b14c1 100755 --- a/minijvm/c/utils/spinlock.h +++ b/minijvm/c/utils/spinlock.h @@ -28,7 +28,7 @@ static inline s64 __sync_bool_compare_and_swap64(volatile s64* lock, s64 compara if (InterlockedCompareExchange64(lock, exchange, comparand) == comparand)return 1; else return 0; } -static inline int __sync_bool_compare_and_swap(volatile int *lock,int comparand, int exchange) { +static inline s32 __sync_bool_compare_and_swap(volatile s32 *lock,int comparand, s32 exchange) { //if *lock == comparand then *lock = exchange and return old *lock value if(InterlockedCompareExchange(lock, exchange, comparand) == comparand)return 1; else return 0; @@ -54,7 +54,7 @@ static inline int spin_lock_count(volatile spinlock_t *lock, s32 count) { int i; for (i = 0; i < count; i++) { // if *lock == 0,then *lock = 1 , return true else return false - if (lock->owner == thrd_current()) { + if (thrd_equal(lock->owner, thrd_current())) { lock->count++; return 0; } @@ -86,7 +86,7 @@ static inline int spin_lock(volatile spinlock_t *lock) { //} static inline int spin_unlock(volatile spinlock_t *lock) { - if (lock->owner != thrd_current()) { + if (!thrd_equal(lock->owner, thrd_current())) { return 1; } lock->count--; diff --git a/minijvm/java/pom.xml b/minijvm/java/pom.xml index d57537931..db1987bc0 100755 --- a/minijvm/java/pom.xml +++ b/minijvm/java/pom.xml @@ -8,7 +8,7 @@ io.github.digitalgust minijvm_rt ${project.groupId}:${project.artifactId} - 1.1.2 + 1.1.3 miniJVM runtime library https://github.com/digitalgust/miniJVM diff --git a/minijvm/java/src/main/java/java/lang/Class.java b/minijvm/java/src/main/java/java/lang/Class.java index e2d404a3d..6e8ce3d16 100644 --- a/minijvm/java/src/main/java/java/lang/Class.java +++ b/minijvm/java/src/main/java/java/lang/Class.java @@ -29,8 +29,8 @@ import org.mini.reflect.ReflectClass; import org.mini.reflect.ReflectField; import org.mini.reflect.ReflectMethod; -import org.mini.reflect.vm.RConst; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.RConst; +import org.mini.vm.RefNative; import java.lang.reflect.*; import java.util.HashMap; diff --git a/minijvm/java/src/main/java/java/lang/ClassLoader.java b/minijvm/java/src/main/java/java/lang/ClassLoader.java index 7809e2927..583407ee3 100755 --- a/minijvm/java/src/main/java/java/lang/ClassLoader.java +++ b/minijvm/java/src/main/java/java/lang/ClassLoader.java @@ -9,8 +9,8 @@ details. */ package java.lang; -import org.mini.reflect.Launcher; -import org.mini.reflect.vm.RefNative; +import sun.misc.Launcher; +import org.mini.vm.RefNative; import java.io.IOException; import java.io.InputStream; diff --git a/minijvm/java/src/main/java/java/lang/invoke/LambdaMetafactory.java b/minijvm/java/src/main/java/java/lang/invoke/LambdaMetafactory.java index 7af41de45..f14265d43 100644 --- a/minijvm/java/src/main/java/java/lang/invoke/LambdaMetafactory.java +++ b/minijvm/java/src/main/java/java/lang/invoke/LambdaMetafactory.java @@ -9,11 +9,10 @@ details. */ package java.lang.invoke; -import org.mini.reflect.vm.ByteCodeAssembler; -import org.mini.reflect.vm.ByteCodeAssembler.*; -import org.mini.reflect.vm.ByteCodeConstantPool; -import org.mini.reflect.vm.ByteCodeConstantPool.PoolEntry; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.ByteCodeAssembler; +import org.mini.vm.ByteCodeConstantPool; +import org.mini.vm.ByteCodeConstantPool.PoolEntry; +import org.mini.vm.RefNative; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -24,8 +23,8 @@ import java.util.Iterator; import java.util.List; -import static org.mini.reflect.vm.ByteCodeAssembler.*; -import static org.mini.reflect.vm.ByteCodeStream.*; +import static org.mini.vm.ByteCodeAssembler.*; +import static org.mini.vm.ByteCodeStream.*; // To understand what this is all about, please read: // diff --git a/minijvm/java/src/main/java/java/lang/invoke/MethodType.java b/minijvm/java/src/main/java/java/lang/invoke/MethodType.java index e2246b7d9..5ffa4d666 100755 --- a/minijvm/java/src/main/java/java/lang/invoke/MethodType.java +++ b/minijvm/java/src/main/java/java/lang/invoke/MethodType.java @@ -11,12 +11,12 @@ import org.mini.reflect.ReflectClass; import org.mini.reflect.ReflectMethod; -import org.mini.reflect.vm.ByteCodeAssembler; +import org.mini.vm.ByteCodeAssembler; import java.util.ArrayList; import java.util.List; -import static org.mini.reflect.vm.ByteCodeAssembler.*; +import static org.mini.vm.ByteCodeAssembler.*; public final class MethodType implements java.io.Serializable { diff --git a/minijvm/java/src/main/java/java/lang/reflect/Array.java b/minijvm/java/src/main/java/java/lang/reflect/Array.java index a336f50b6..9eace8fd1 100644 --- a/minijvm/java/src/main/java/java/lang/reflect/Array.java +++ b/minijvm/java/src/main/java/java/lang/reflect/Array.java @@ -27,7 +27,7 @@ package java.lang.reflect; import org.mini.reflect.ReflectArray; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.RefNative; /** * The Array class provides static methods to dynamically create diff --git a/minijvm/java/src/main/java/java/lang/reflect/Constructor.java b/minijvm/java/src/main/java/java/lang/reflect/Constructor.java index 214642e71..b9d762d4b 100755 --- a/minijvm/java/src/main/java/java/lang/reflect/Constructor.java +++ b/minijvm/java/src/main/java/java/lang/reflect/Constructor.java @@ -27,7 +27,7 @@ package java.lang.reflect; import org.mini.reflect.ReflectMethod; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.RefNative; /** * Constructor provides information about, and access to, a single diff --git a/minijvm/java/src/main/java/java/lang/reflect/Method.java b/minijvm/java/src/main/java/java/lang/reflect/Method.java index 534f42714..abdb2b80c 100755 --- a/minijvm/java/src/main/java/java/lang/reflect/Method.java +++ b/minijvm/java/src/main/java/java/lang/reflect/Method.java @@ -26,9 +26,8 @@ package java.lang.reflect; -import org.mini.reflect.ReflectField; import org.mini.reflect.ReflectMethod; -import org.mini.reflect.vm.RConst; +import org.mini.vm.RConst; import java.lang.annotation.Annotation; diff --git a/minijvm/java/src/main/java/java/net/URLClassLoader.java b/minijvm/java/src/main/java/java/net/URLClassLoader.java index b18aa5098..4ed7ab9d4 100755 --- a/minijvm/java/src/main/java/java/net/URLClassLoader.java +++ b/minijvm/java/src/main/java/java/net/URLClassLoader.java @@ -10,7 +10,7 @@ package java.net; -import org.mini.reflect.Launcher; +import org.mini.vm.VmUtil; public class URLClassLoader extends ClassLoader { @@ -41,7 +41,7 @@ protected Class findClass(String name) throws ClassNotFoundException { // 加载D盘根目录下指定类名的class String classname = name.replace('.', '/') + ".class"; - byte[] classData = Launcher.getFileData(classname, paths); + byte[] classData = VmUtil.getFileData(classname, paths); if (classData == null) { throw new ClassNotFoundException(); } else { @@ -50,7 +50,7 @@ protected Class findClass(String name) throws ClassNotFoundException { } protected URL findResource(String path) { - URL url = Launcher.getFileUrl(path, paths); + URL url = VmUtil.getFileUrl(path, paths); return url; } diff --git a/minijvm/java/src/main/java/java/nio/ByteBufferImpl.java b/minijvm/java/src/main/java/java/nio/ByteBufferImpl.java index 9364331b9..2aa10a23d 100644 --- a/minijvm/java/src/main/java/java/nio/ByteBufferImpl.java +++ b/minijvm/java/src/main/java/java/nio/ByteBufferImpl.java @@ -2,7 +2,7 @@ import org.mini.reflect.ReflectArray; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.RefNative; class ByteBufferImpl extends ByteBuffer { protected byte[] array; diff --git a/minijvm/java/src/main/java/java/nio/ByteOrder.java b/minijvm/java/src/main/java/java/nio/ByteOrder.java index 74957ee3d..5ffe910e3 100755 --- a/minijvm/java/src/main/java/java/nio/ByteOrder.java +++ b/minijvm/java/src/main/java/java/nio/ByteOrder.java @@ -10,7 +10,7 @@ package java.nio; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.RefNative; public final class ByteOrder { public static final ByteOrder BIG_ENDIAN = new ByteOrder("BIG_ENDIAN"); diff --git a/minijvm/java/src/main/java/java/util/Collections.java b/minijvm/java/src/main/java/java/util/Collections.java index 7b41a7f3c..df2790fb1 100644 --- a/minijvm/java/src/main/java/java/util/Collections.java +++ b/minijvm/java/src/main/java/java/util/Collections.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,22 @@ * questions. */ - - package java.util; - +import java.io.Serializable; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.IOException; import java.lang.reflect.Array; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; +import sun.misc.SharedSecrets; /** * This class consists exclusively of static methods that operate on or return @@ -55,17 +66,16 @@ * example, invoking the sort method on an unmodifiable list that is * already sorted may or may not throw UnsupportedOperationException. * - *

This class is a member of the - * + *

This class is a member of the + * * Java Collections Framework. * * @author Josh Bloch * @author Neal Gafter - * @version 1.89, 07/28/04 - * @see Collection - * @see Set - * @see List - * @see Map + * @see Collection + * @see Set + * @see List + * @see Map * @since 1.2 */ @@ -81,7 +91,7 @@ private Collections() { * two implementations, one of which is appropriate for RandomAccess * lists, the other for "sequential." Often, the random access variant * yields better performance on small sequential access lists. The - * tuning parameters below determine the cutoff point for what constitutes + * tuning parameters below determine the cutoff point for what constitutes * a "small" sequential access list for each algorithm. The values below * were empirically determined to work well for LinkedList. Hopefully * they should be reasonable for other sequential access List @@ -101,119 +111,103 @@ private Collections() { /** * Sorts the specified list into ascending order, according to the - * natural ordering of its elements. All elements in the list must - * implement the Comparable interface. Furthermore, all elements - * in the list must be mutually comparable (that is, - * e1.compareTo(e2) must not throw a ClassCastException - * for any elements e1 and e2 in the list).

- * - * This sort is guaranteed to be stable: equal elements will - * not be reordered as a result of the sort.

+ * {@linkplain Comparable natural ordering} of its elements. + * All elements in the list must implement the {@link Comparable} + * interface. Furthermore, all elements in the list must be + * mutually comparable (that is, {@code e1.compareTo(e2)} + * must not throw a {@code ClassCastException} for any elements + * {@code e1} and {@code e2} in the list). * - * The specified list must be modifiable, but need not be resizable.

+ *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. * - * The sorting algorithm is a modified mergesort (in which the merge is - * omitted if the highest element in the low sublist is less than the - * lowest element in the high sublist). This algorithm offers guaranteed - * n log(n) performance. + *

The specified list must be modifiable, but need not be resizable. * - * This implementation dumps the specified list into an array, sorts - * the array, and iterates over the list resetting each element - * from the corresponding position in the array. This avoids the - * n2 log(n) performance that would result from attempting - * to sort a linked list in place. + * @implNote + * This implementation defers to the {@link List#sort(Comparator)} + * method using the specified list and a {@code null} comparator. * + * @param the class of the objects in the list * @param list the list to be sorted. * @throws ClassCastException if the list contains elements that are not - * mutually comparable (for example, strings and integers). + * mutually comparable (for example, strings and integers). * @throws UnsupportedOperationException if the specified list's - * list-iterator does not support the set operation. - * @see Comparable + * list-iterator does not support the {@code set} operation. + * @throws IllegalArgumentException (optional) if the implementation + * detects that the natural ordering of the list elements is + * found to violate the {@link Comparable} contract + * @see List#sort(Comparator) */ + @SuppressWarnings("unchecked") public static > void sort(List list) { - Object[] a = list.toArray(); - Arrays.sort(a); - ListIterator i = list.listIterator(); - for (int j=0; jmutually * comparable using the specified comparator (that is, - * c.compare(e1, e2) must not throw a ClassCastException - * for any elements e1 and e2 in the list).

+ * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} + * for any elements {@code e1} and {@code e2} in the list). * - * This sort is guaranteed to be stable: equal elements will - * not be reordered as a result of the sort.

+ *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. * - * The sorting algorithm is a modified mergesort (in which the merge is - * omitted if the highest element in the low sublist is less than the - * lowest element in the high sublist). This algorithm offers guaranteed - * n log(n) performance. + *

The specified list must be modifiable, but need not be resizable. * - * The specified list must be modifiable, but need not be resizable. - * This implementation dumps the specified list into an array, sorts - * the array, and iterates over the list resetting each element - * from the corresponding position in the array. This avoids the - * n2 log(n) performance that would result from attempting - * to sort a linked list in place. + * @implNote + * This implementation defers to the {@link List#sort(Comparator)} + * method using the specified list and comparator. * + * @param the class of the objects in the list * @param list the list to be sorted. * @param c the comparator to determine the order of the list. A - * null value indicates that the elements' natural + * {@code null} value indicates that the elements' natural * ordering should be used. * @throws ClassCastException if the list contains elements that are not - * mutually comparable using the specified comparator. + * mutually comparable using the specified comparator. * @throws UnsupportedOperationException if the specified list's - * list-iterator does not support the set operation. - * @see Comparator + * list-iterator does not support the {@code set} operation. + * @throws IllegalArgumentException (optional) if the comparator is + * found to violate the {@link Comparator} contract + * @see List#sort(Comparator) */ + @SuppressWarnings({"unchecked", "rawtypes"}) public static void sort(List list, Comparator c) { - Object[] a = list.toArray(); - Arrays.sort(a, (Comparator)c); - ListIterator i = list.listIterator(); - for (int j=0; jnatural ordering of its elements (as by the - * sort(List) method, above) prior to making this call. If it is - * not sorted, the results are undefined. If the list contains multiple - * elements equal to the specified object, there is no guarantee which one - * will be found.

+ * according to the {@linkplain Comparable natural ordering} of its + * elements (as by the {@link #sort(List)} method) prior to making this + * call. If it is not sorted, the results are undefined. If the list + * contains multiple elements equal to the specified object, there is no + * guarantee which one will be found. * - * This method runs in log(n) time for a "random access" list (which + *

This method runs in log(n) time for a "random access" list (which * provides near-constant-time positional access). If the specified list * does not implement the {@link RandomAccess} interface and is large, * this method will do an iterator-based binary search that performs * O(n) link traversals and O(log n) element comparisons. * + * @param the class of the objects in the list * @param list the list to be searched. * @param key the key to be searched for. - * @return index of the search key, if it is contained in the list; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the list: the index of the first - * element greater than the key, or list.size(), if all - * elements in the list are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. + * @return the index of the search key, if it is contained in the list; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the list: the index of the first + * element greater than the key, or list.size() if all + * elements in the list are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. * @throws ClassCastException if the list contains elements that are not - * mutually comparable (for example, strings and - * integers), or the search key in not mutually comparable - * with the elements of the list. - * @see Comparable - * @see #sort(List) + * mutually comparable (for example, strings and + * integers), or the search key is not mutually comparable + * with the elements of the list. */ public static int binarySearch(List> list, T key) { @@ -224,35 +218,34 @@ int binarySearch(List> list, T key) { } private static - int indexedBinarySearch(List> list, T key) - { - int low = 0; - int high = list.size()-1; + int indexedBinarySearch(List> list, T key) { + int low = 0; + int high = list.size()-1; - while (low <= high) { - int mid = (low + high) >> 1; - Comparable midVal = list.get(mid); - int cmp = midVal.compareTo(key); + while (low <= high) { + int mid = (low + high) >>> 1; + Comparable midVal = list.get(mid); + int cmp = midVal.compareTo(key); - if (cmp < 0) - low = mid + 1; - else if (cmp > 0) - high = mid - 1; - else - return mid; // key found - } - return -(low + 1); // key not found + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found } private static int iteratorBinarySearch(List> list, T key) { - int low = 0; - int high = list.size()-1; + int low = 0; + int high = list.size()-1; ListIterator> i = list.listIterator(); while (low <= high) { - int mid = (low + high) >> 1; + int mid = (low + high) >>> 1; Comparable midVal = get(i, mid); int cmp = midVal.compareTo(key); @@ -271,7 +264,7 @@ else if (cmp > 0) * list listIterator. */ private static T get(ListIterator i, int index) { - T obj = null; + T obj = null; int pos = i.nextIndex(); if (pos <= index) { do { @@ -288,41 +281,42 @@ private static T get(ListIterator i, int index) { /** * Searches the specified list for the specified object using the binary * search algorithm. The list must be sorted into ascending order - * according to the specified comparator (as by the Sort(List, - * Comparator) method, above), prior to making this call. If it is + * according to the specified comparator (as by the + * {@link #sort(List, Comparator) sort(List, Comparator)} + * method), prior to making this call. If it is * not sorted, the results are undefined. If the list contains multiple * elements equal to the specified object, there is no guarantee which one - * will be found.

+ * will be found. * - * This method runs in log(n) time for a "random access" list (which + *

This method runs in log(n) time for a "random access" list (which * provides near-constant-time positional access). If the specified list * does not implement the {@link RandomAccess} interface and is large, * this method will do an iterator-based binary search that performs * O(n) link traversals and O(log n) element comparisons. * + * @param the class of the objects in the list * @param list the list to be searched. * @param key the key to be searched for. - * @param c the comparator by which the list is ordered. A - * null value indicates that the elements' natural - * ordering should be used. - * @return index of the search key, if it is contained in the list; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the list: the index of the first - * element greater than the key, or list.size(), if all - * elements in the list are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. + * @param c the comparator by which the list is ordered. + * A null value indicates that the elements' + * {@linkplain Comparable natural ordering} should be used. + * @return the index of the search key, if it is contained in the list; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the list: the index of the first + * element greater than the key, or list.size() if all + * elements in the list are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. * @throws ClassCastException if the list contains elements that are not - * mutually comparable using the specified comparator, - * or the search key in not mutually comparable with the - * elements of the list using this comparator. - * @see Comparable - * @see #sort(List, Comparator) + * mutually comparable using the specified comparator, + * or the search key is not mutually comparable with the + * elements of the list using this comparator. */ + @SuppressWarnings("unchecked") public static int binarySearch(List list, T key, Comparator c) { if (c==null) - return binarySearch((List) list, key); + return binarySearch((List>) list, key); if (list instanceof RandomAccess || list.size() int binarySearch(List list, T key, Comparator int indexedBinarySearch(List l, T key, Comparator c) { - int low = 0; - int high = l.size()-1; + int low = 0; + int high = l.size()-1; - while (low <= high) { - int mid = (low + high) >> 1; - T midVal = l.get(mid); - int cmp = c.compare(midVal, key); + while (low <= high) { + int mid = (low + high) >>> 1; + T midVal = l.get(mid); + int cmp = c.compare(midVal, key); - if (cmp < 0) - low = mid + 1; - else if (cmp > 0) - high = mid - 1; - else - return mid; // key found - } - return -(low + 1); // key not found + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found } private static int iteratorBinarySearch(List l, T key, Comparator c) { - int low = 0; - int high = l.size()-1; + int low = 0; + int high = l.size()-1; ListIterator i = l.listIterator(); while (low <= high) { - int mid = (low + high) >> 1; + int mid = (low + high) >>> 1; T midVal = get(i, mid); int cmp = c.compare(midVal, key); @@ -369,9 +363,6 @@ else if (cmp > 0) return -(low + 1); // key not found } - private interface SelfComparable extends Comparable {} - - /** * Reverses the order of the elements in the specified list.

* @@ -379,18 +370,22 @@ private interface SelfComparable extends Comparable {} * * @param list the list whose elements are to be reversed. * @throws UnsupportedOperationException if the specified list or - * its list-iterator does not support the set method. + * its list-iterator does not support the set operation. */ + @SuppressWarnings({"rawtypes", "unchecked"}) public static void reverse(List list) { int size = list.size(); if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) { for (int i=0, mid=size>>1, j=size-1; i>1; i list) { /** * Randomly permutes the specified list using a default source of * randomness. All permutations occur with approximately equal - * likelihood.

+ * likelihood. * - * The hedge "approximately" is used in the foregoing description because + *

The hedge "approximately" is used in the foregoing description because * default source of randomness is only approximately an unbiased source * of independently chosen bits. If it were a perfect source of randomly * chosen bits, then the algorithm would choose permutations with perfect - * uniformity.

+ * uniformity. * - * This implementation traverses the list backwards, from the last element - * up to the second, repeatedly swapping a randomly selected element into - * the "current position". Elements are randomly selected from the + *

This implementation traverses the list backwards, from the last + * element up to the second, repeatedly swapping a randomly selected element + * into the "current position". Elements are randomly selected from the * portion of the list that runs from the first element to the current - * position, inclusive.

+ * position, inclusive. * - * This method runs in linear time. If the specified list does not + *

This method runs in linear time. If the specified list does not * implement the {@link RandomAccess} interface and is large, this * implementation dumps the specified list into an array before shuffling * it, and dumps the shuffled array back into the list. This avoids the @@ -423,12 +418,16 @@ public static void reverse(List list) { * * @param list the list to be shuffled. * @throws UnsupportedOperationException if the specified list or - * its list-iterator does not support the set method. + * its list-iterator does not support the set operation. */ public static void shuffle(List list) { - shuffle(list, r); + Random rnd = r; + if (rnd == null) + r = rnd = new Random(); // harmless race. + shuffle(list, rnd); } - private static Random r = new Random(); + + private static Random r; /** * Randomly permute the specified list using the specified source of @@ -453,19 +452,23 @@ public static void shuffle(List list) { * @throws UnsupportedOperationException if the specified list or its * list-iterator does not support the set operation. */ + @SuppressWarnings({"rawtypes", "unchecked"}) public static void shuffle(List list, Random rnd) { int size = list.size(); if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) { for (int i=size; i>1; i--) swap(list, i-1, rnd.nextInt(i)); } else { - Object arr[] = list.toArray(); + Object[] arr = list.toArray(); // Shuffle array for (int i=size; i>1; i--) swap(arr, i-1, rnd.nextInt(i)); // Dump array back into list + // instead of using a raw type here, it's possible to capture + // the wildcard but it will require a call to a supplementary + // private method ListIterator it = list.listIterator(); for (int i=0; i list, Random rnd) { * || j < 0 || j >= list.size()). * @since 1.4 */ + @SuppressWarnings({"rawtypes", "unchecked"}) public static void swap(List list, int i, int j) { - final List l = list; - l.set(i, l.set(j, l.get(i))); + // instead of using a raw type here, it's possible to capture + // the wildcard but it will require a call to a supplementary + // private method + final List l = list; + l.set(i, l.set(j, l.get(i))); } /** @@ -507,10 +514,11 @@ private static void swap(Object[] arr, int i, int j) { * * This method runs in linear time. * + * @param the class of the objects in the list * @param list the list to be filled with the specified element. * @param obj The element with which to fill the specified list. * @throws UnsupportedOperationException if the specified list or its - * list-iterator does not support the set operation. + * list-iterator does not support the set operation. */ public static void fill(List list, T obj) { int size = list.size(); @@ -536,6 +544,7 @@ public static void fill(List list, T obj) { * * This method runs in linear time. * + * @param the class of the objects in the lists * @param dest The destination list. * @param src The source list. * @throws IndexOutOfBoundsException if the destination list is too small @@ -549,12 +558,12 @@ public static void copy(List dest, List src) { throw new IndexOutOfBoundsException("Source does not fit in dest"); if (srcSize < COPY_THRESHOLD || - (src instanceof RandomAccess && dest instanceof RandomAccess)) { + (src instanceof RandomAccess && dest instanceof RandomAccess)) { for (int i=0; i di=dest.listIterator(); - ListIterator si=src.listIterator(); + ListIterator si=src.listIterator(); for (int i=0; i void copy(List dest, List src) { * This method iterates over the entire collection, hence it requires * time proportional to the size of the collection. * + * @param the class of the objects in the collection * @param coll the collection whose minimum element is to be determined. * @return the minimum element of the given collection, according * to the natural ordering of its elements. * @throws ClassCastException if the collection contains elements that are - * not mutually comparable (for example, strings and - * integers). + * not mutually comparable (for example, strings and + * integers). * @throws NoSuchElementException if the collection is empty. * @see Comparable */ public static > T min(Collection coll) { - Iterator i = coll.iterator(); - T candidate = i.next(); + Iterator i = coll.iterator(); + T candidate = i.next(); - while(i.hasNext()) { - T next = i.next(); - if (next.compareTo(candidate) < 0) - candidate = next; - } - return candidate; + while (i.hasNext()) { + T next = i.next(); + if (next.compareTo(candidate) < 0) + candidate = next; + } + return candidate; } /** @@ -606,6 +616,7 @@ public static > T min(Collection the class of the objects in the collection * @param coll the collection whose minimum element is to be determined. * @param comp the comparator with which to determine the minimum element. * A null value indicates that the elements' natural @@ -613,23 +624,24 @@ public static > T min(Collectionmutually comparable using the specified comparator. + * not mutually comparable using the specified comparator. * @throws NoSuchElementException if the collection is empty. * @see Comparable */ + @SuppressWarnings({"unchecked", "rawtypes"}) public static T min(Collection coll, Comparator comp) { if (comp==null) - return (T)min((Collection) (Collection) coll); + return (T)min((Collection) coll); - Iterator i = coll.iterator(); - T candidate = i.next(); + Iterator i = coll.iterator(); + T candidate = i.next(); - while(i.hasNext()) { - T next = i.next(); - if (comp.compare(next, candidate) < 0) - candidate = next; - } - return candidate; + while (i.hasNext()) { + T next = i.next(); + if (comp.compare(next, candidate) < 0) + candidate = next; + } + return candidate; } /** @@ -644,25 +656,26 @@ public static T min(Collection coll, Comparator comp * This method iterates over the entire collection, hence it requires * time proportional to the size of the collection. * + * @param the class of the objects in the collection * @param coll the collection whose maximum element is to be determined. * @return the maximum element of the given collection, according * to the natural ordering of its elements. * @throws ClassCastException if the collection contains elements that are - * not mutually comparable (for example, strings and + * not mutually comparable (for example, strings and * integers). * @throws NoSuchElementException if the collection is empty. * @see Comparable */ public static > T max(Collection coll) { - Iterator i = coll.iterator(); - T candidate = i.next(); + Iterator i = coll.iterator(); + T candidate = i.next(); - while(i.hasNext()) { - T next = i.next(); - if (next.compareTo(candidate) > 0) - candidate = next; - } - return candidate; + while (i.hasNext()) { + T next = i.next(); + if (next.compareTo(candidate) > 0) + candidate = next; + } + return candidate; } /** @@ -676,6 +689,7 @@ public static > T max(Collection the class of the objects in the collection * @param coll the collection whose maximum element is to be determined. * @param comp the comparator with which to determine the maximum element. * A null value indicates that the elements' natural @@ -683,23 +697,24 @@ public static > T max(Collectionmutually comparable using the specified comparator. + * not mutually comparable using the specified comparator. * @throws NoSuchElementException if the collection is empty. * @see Comparable */ + @SuppressWarnings({"unchecked", "rawtypes"}) public static T max(Collection coll, Comparator comp) { if (comp==null) - return (T)max((Collection) (Collection) coll); + return (T)max((Collection) coll); - Iterator i = coll.iterator(); - T candidate = i.next(); + Iterator i = coll.iterator(); + T candidate = i.next(); - while(i.hasNext()) { - T next = i.next(); - if (comp.compare(next, candidate) > 0) - candidate = next; - } - return candidate; + while (i.hasNext()) { + T next = i.next(); + if (comp.compare(next, candidate) > 0) + candidate = next; + } + return candidate; } /** @@ -730,7 +745,7 @@ public static T max(Collection coll, Comparator comp * Collections.rotate(l.subList(1, 4), -1); * * The resulting list is [a, c, d, b, e]. - * + * *

To move more than one element forward, increase the absolute value * of the rotation distance. To move elements backward, use a positive * shift distance. @@ -754,14 +769,14 @@ public static T max(Collection coll, Comparator comp * constraints on this value; it may be zero, negative, or * greater than list.size(). * @throws UnsupportedOperationException if the specified list or - * its list-iterator does not support the set method. + * its list-iterator does not support the set operation. * @since 1.4 */ public static void rotate(List list, int distance) { if (list instanceof RandomAccess || list.size() < ROTATE_THRESHOLD) - rotate1((List)list, distance); + rotate1(list, distance); else - rotate2((List)list, distance); + rotate2(list, distance); } private static void rotate1(List list, int distance) { @@ -783,14 +798,14 @@ private static void rotate1(List list, int distance) { i -= size; displaced = list.set(i, displaced); nMoved ++; - } while(i != cycleStart); + } while (i != cycleStart); } } private static void rotate2(List list, int distance) { int size = list.size(); if (size == 0) - return; + return; int mid = -distance % size; if (mid < 0) mid += size; @@ -809,6 +824,7 @@ private static void rotate2(List list, int distance) { * (oldVal==null ? e==null : oldVal.equals(e)). * (This method has no effect on the size of the list.) * + * @param the class of the objects in the list * @param list the list in which replacement is to occur. * @param oldVal the old value to be replaced. * @param newVal the new value with which oldVal is to be @@ -817,7 +833,7 @@ private static void rotate2(List list, int distance) { * e such that * (oldVal==null ? e==null : oldVal.equals(e)). * @throws UnsupportedOperationException if the specified list or - * its list-iterator does not support the set method. + * its list-iterator does not support the set operation. * @since 1.4 */ public static boolean replaceAll(List list, T oldVal, T newVal) { @@ -864,9 +880,9 @@ public static boolean replaceAll(List list, T oldVal, T newVal) { * Returns the starting position of the first occurrence of the specified * target list within the specified source list, or -1 if there is no * such occurrence. More formally, returns the lowest index i - * such that source.subList(i, i+target.size()).equals(target), + * such that {@code source.subList(i, i+target.size()).equals(target)}, * or -1 if there is no such index. (Returns -1 if - * target.size() > source.size().) + * {@code target.size() > source.size()}) * *

This implementation uses the "brute force" technique of scanning * over the source list, looking for a match with the target at each @@ -886,8 +902,8 @@ public static int indexOfSubList(List source, List target) { int maxCandidate = sourceSize - targetSize; if (sourceSize < INDEXOFSUBLIST_THRESHOLD || - (source instanceof RandomAccess&&target instanceof RandomAccess)) { - nextCand: + (source instanceof RandomAccess&&target instanceof RandomAccess)) { + nextCand: for (int candidate = 0; candidate <= maxCandidate; candidate++) { for (int i=0, j=candidate; i source, List target) { } } else { // Iterator version of above algorithm ListIterator si = source.listIterator(); - nextCand: + nextCand: for (int candidate = 0; candidate <= maxCandidate; candidate++) { ListIterator ti = target.listIterator(); for (int i=0; i source, List target) { * Returns the starting position of the last occurrence of the specified * target list within the specified source list, or -1 if there is no such * occurrence. More formally, returns the highest index i - * such that source.subList(i, i+target.size()).equals(target), + * such that {@code source.subList(i, i+target.size()).equals(target)}, * or -1 if there is no such index. (Returns -1 if - * target.size() > source.size().) + * {@code target.size() > source.size()}) * *

This implementation uses the "brute force" technique of iterating * over the source list, looking for a match with the target at each @@ -939,8 +955,8 @@ public static int lastIndexOfSubList(List source, List target) { int maxCandidate = sourceSize - targetSize; if (sourceSize < INDEXOFSUBLIST_THRESHOLD || - source instanceof RandomAccess) { // Index access version - nextCand: + source instanceof RandomAccess) { // Index access version + nextCand: for (int candidate = maxCandidate; candidate >= 0; candidate--) { for (int i=0, j=candidate; i source, List target) { if (maxCandidate < 0) return -1; ListIterator si = source.listIterator(maxCandidate); - nextCand: + nextCand: for (int candidate = maxCandidate; candidate >= 0; candidate--) { ListIterator ti = target.listIterator(); for (int i=0; i source, List target) { * that the backing collection is a set or a list.

* * The returned collection will be serializable if the specified collection - * is serializable. + * is serializable. * + * @param the class of the objects in the collection * @param c the collection for which an unmodifiable view is to be - * returned. + * returned. * @return an unmodifiable view of the specified collection. */ public static Collection unmodifiableCollection(Collection c) { - return new UnmodifiableCollection(c); + return new UnmodifiableCollection<>(c); } /** * @serial include */ - static class UnmodifiableCollection implements Collection { - // use serialVersionUID from JDK 1.2.2 for interoperability - private static final long serialVersionUID = 1820017752578914078L; + static class UnmodifiableCollection implements Collection, Serializable { + private static final long serialVersionUID = 1820017752578914078L; - Collection c; + final Collection c; - UnmodifiableCollection(Collection c) { + UnmodifiableCollection(Collection c) { if (c==null) throw new NullPointerException(); this.c = c; } - public int size() {return c.size();} - public boolean isEmpty() {return c.isEmpty();} - public boolean contains(Object o) {return c.contains(o);} - public Object[] toArray() {return c.toArray();} - public T[] toArray(T[] a) {return c.toArray(a);} + public int size() {return c.size();} + public boolean isEmpty() {return c.isEmpty();} + public boolean contains(Object o) {return c.contains(o);} + public Object[] toArray() {return c.toArray();} + public T[] toArray(T[] a) {return c.toArray(a);} public String toString() {return c.toString();} - public Iterator iterator() { - return new Iterator() { - Iterator i = c.iterator(); + public Iterator iterator() { + return new Iterator() { + private final Iterator i = c.iterator(); - public boolean hasNext() {return i.hasNext();} - public E next() {return i.next();} - public void remove() { - throw new UnsupportedOperationException(); + public boolean hasNext() {return i.hasNext();} + public E next() {return i.next();} + public void remove() { + throw new UnsupportedOperationException(); } - }; + @Override + public void forEachRemaining(Consumer action) { + // Use backing collection version + i.forEachRemaining(action); + } + }; } - public boolean add(E o){ - throw new UnsupportedOperationException(); + public boolean add(E e) { + throw new UnsupportedOperationException(); } - public boolean remove(Object o) { - throw new UnsupportedOperationException(); + public boolean remove(Object o) { + throw new UnsupportedOperationException(); } - public boolean containsAll(Collection coll) { - return c.containsAll(coll); + public boolean containsAll(Collection coll) { + return c.containsAll(coll); + } + public boolean addAll(Collection coll) { + throw new UnsupportedOperationException(); + } + public boolean removeAll(Collection coll) { + throw new UnsupportedOperationException(); + } + public boolean retainAll(Collection coll) { + throw new UnsupportedOperationException(); } - public boolean addAll(Collection coll) { - throw new UnsupportedOperationException(); + public void clear() { + throw new UnsupportedOperationException(); } - public boolean removeAll(Collection coll) { - throw new UnsupportedOperationException(); + + // Override default methods in Collection + @Override + public void forEach(Consumer action) { + c.forEach(action); } - public boolean retainAll(Collection coll) { - throw new UnsupportedOperationException(); + @Override + public boolean removeIf(Predicate filter) { + throw new UnsupportedOperationException(); } - public void clear() { - throw new UnsupportedOperationException(); + @SuppressWarnings("unchecked") + @Override + public Spliterator spliterator() { + return (Spliterator)c.spliterator(); } +// @SuppressWarnings("unchecked") +// @Override +// public Stream stream() { +// return (Stream)c.stream(); +// } +// @SuppressWarnings("unchecked") +// @Override +// public Stream parallelStream() { +// return (Stream)c.parallelStream(); +// } } /** @@ -1064,26 +1110,26 @@ public void clear() { * iterator, result in an UnsupportedOperationException.

* * The returned set will be serializable if the specified set - * is serializable. + * is serializable. * + * @param the class of the objects in the set * @param s the set for which an unmodifiable view is to be returned. * @return an unmodifiable view of the specified set. */ - public static Set unmodifiableSet(Set s) { - return new UnmodifiableSet(s); + return new UnmodifiableSet<>(s); } /** * @serial include */ static class UnmodifiableSet extends UnmodifiableCollection - implements Set{ - private static final long serialVersionUID = -9215047833775013803L; + implements Set, Serializable { + private static final long serialVersionUID = -9215047833775013803L; - UnmodifiableSet(Set s) {super(s);} - public boolean equals(Object o) {return c.equals(o);} - public int hashCode() {return c.hashCode();} + UnmodifiableSet(Set s) {super(s);} + public boolean equals(Object o) {return o == this || c.equals(o);} + public int hashCode() {return c.hashCode();} } /** @@ -1096,41 +1142,131 @@ static class UnmodifiableSet extends UnmodifiableCollection * an UnsupportedOperationException.

* * The returned sorted set will be serializable if the specified sorted set - * is serializable. + * is serializable. * + * @param the class of the objects in the set * @param s the sorted set for which an unmodifiable view is to be - * returned. + * returned. * @return an unmodifiable view of the specified sorted set. */ public static SortedSet unmodifiableSortedSet(SortedSet s) { - return new UnmodifiableSortedSet(s); + return new UnmodifiableSortedSet<>(s); } /** * @serial include */ static class UnmodifiableSortedSet - extends UnmodifiableSet - implements SortedSet{ - private static final long serialVersionUID = -4929149591599911165L; - private SortedSet ss; + extends UnmodifiableSet + implements SortedSet, Serializable { + private static final long serialVersionUID = -4929149591599911165L; + private final SortedSet ss; - UnmodifiableSortedSet(SortedSet s) {super(s); ss = s;} + UnmodifiableSortedSet(SortedSet s) {super(s); ss = s;} public Comparator comparator() {return ss.comparator();} public SortedSet subSet(E fromElement, E toElement) { - return new UnmodifiableSortedSet(ss.subSet(fromElement,toElement)); + return new UnmodifiableSortedSet<>(ss.subSet(fromElement,toElement)); } public SortedSet headSet(E toElement) { - return new UnmodifiableSortedSet(ss.headSet(toElement)); + return new UnmodifiableSortedSet<>(ss.headSet(toElement)); } public SortedSet tailSet(E fromElement) { - return new UnmodifiableSortedSet(ss.tailSet(fromElement)); + return new UnmodifiableSortedSet<>(ss.tailSet(fromElement)); + } + + public E first() {return ss.first();} + public E last() {return ss.last();} + } + + /** + * Returns an unmodifiable view of the specified navigable set. This method + * allows modules to provide users with "read-only" access to internal + * navigable sets. Query operations on the returned navigable set "read + * through" to the specified navigable set. Attempts to modify the returned + * navigable set, whether direct, via its iterator, or via its + * {@code subSet}, {@code headSet}, or {@code tailSet} views, result in + * an {@code UnsupportedOperationException}.

+ * + * The returned navigable set will be serializable if the specified + * navigable set is serializable. + * + * @param the class of the objects in the set + * @param s the navigable set for which an unmodifiable view is to be + * returned + * @return an unmodifiable view of the specified navigable set + * @since 1.8 + */ + public static NavigableSet unmodifiableNavigableSet(NavigableSet s) { + return new UnmodifiableNavigableSet<>(s); + } + + /** + * Wraps a navigable set and disables all of the mutative operations. + * + * @param type of elements + * @serial include + */ + static class UnmodifiableNavigableSet + extends UnmodifiableSortedSet + implements NavigableSet, Serializable { + + private static final long serialVersionUID = -6027448201786391929L; + + /** + * A singleton empty unmodifiable navigable set used for + * {@link #emptyNavigableSet()}. + * + * @param type of elements, if there were any, and bounds + */ + private static class EmptyNavigableSet extends UnmodifiableNavigableSet + implements Serializable { + private static final long serialVersionUID = -6291252904449939134L; + + public EmptyNavigableSet() { + super(new TreeSet()); + } + + private Object readResolve() { return EMPTY_NAVIGABLE_SET; } + } + + @SuppressWarnings("rawtypes") + private static final NavigableSet EMPTY_NAVIGABLE_SET = + new EmptyNavigableSet<>(); + + /** + * The instance we are protecting. + */ + private final NavigableSet ns; + + UnmodifiableNavigableSet(NavigableSet s) {super(s); ns = s;} + + public E lower(E e) { return ns.lower(e); } + public E floor(E e) { return ns.floor(e); } + public E ceiling(E e) { return ns.ceiling(e); } + public E higher(E e) { return ns.higher(e); } + public E pollFirst() { throw new UnsupportedOperationException(); } + public E pollLast() { throw new UnsupportedOperationException(); } + public NavigableSet descendingSet() + { return new UnmodifiableNavigableSet<>(ns.descendingSet()); } + public Iterator descendingIterator() + { return descendingSet().iterator(); } + + public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { + return new UnmodifiableNavigableSet<>( + ns.subSet(fromElement, fromInclusive, toElement, toInclusive)); + } + + public NavigableSet headSet(E toElement, boolean inclusive) { + return new UnmodifiableNavigableSet<>( + ns.headSet(toElement, inclusive)); } - public E first() {return ss.first();} - public E last() {return ss.last();} + public NavigableSet tailSet(E fromElement, boolean inclusive) { + return new UnmodifiableNavigableSet<>( + ns.tailSet(fromElement, inclusive)); + } } /** @@ -1145,73 +1281,91 @@ public SortedSet tailSet(E fromElement) { * is serializable. Similarly, the returned list will implement * {@link RandomAccess} if the specified list does. * + * @param the class of the objects in the list * @param list the list for which an unmodifiable view is to be returned. * @return an unmodifiable view of the specified list. */ public static List unmodifiableList(List list) { - return (list instanceof RandomAccess ? - new UnmodifiableRandomAccessList(list) : - new UnmodifiableList(list)); + return (list instanceof RandomAccess ? + new UnmodifiableRandomAccessList<>(list) : + new UnmodifiableList<>(list)); } /** * @serial include */ static class UnmodifiableList extends UnmodifiableCollection - implements List { - static final long serialVersionUID = -283967356065247728L; - List list; + implements List { + private static final long serialVersionUID = -283967356065247728L; + + final List list; - UnmodifiableList(List list) { - super(list); - this.list = list; - } + UnmodifiableList(List list) { + super(list); + this.list = list; + } - public boolean equals(Object o) {return list.equals(o);} - public int hashCode() {return list.hashCode();} + public boolean equals(Object o) {return o == this || list.equals(o);} + public int hashCode() {return list.hashCode();} - public E get(int index) {return list.get(index);} - public E set(int index, E element) { - throw new UnsupportedOperationException(); + public E get(int index) {return list.get(index);} + public E set(int index, E element) { + throw new UnsupportedOperationException(); + } + public void add(int index, E element) { + throw new UnsupportedOperationException(); } - public void add(int index, E element) { - throw new UnsupportedOperationException(); + public E remove(int index) { + throw new UnsupportedOperationException(); } - public E remove(int index) { - throw new UnsupportedOperationException(); + public int indexOf(Object o) {return list.indexOf(o);} + public int lastIndexOf(Object o) {return list.lastIndexOf(o);} + public boolean addAll(int index, Collection c) { + throw new UnsupportedOperationException(); + } + + @Override + public void replaceAll(UnaryOperator operator) { + throw new UnsupportedOperationException(); } - public int indexOf(Object o) {return list.indexOf(o);} - public int lastIndexOf(Object o) {return list.lastIndexOf(o);} - public boolean addAll(int index, Collection c) { - throw new UnsupportedOperationException(); + @Override + public void sort(Comparator c) { + throw new UnsupportedOperationException(); } - public ListIterator listIterator() {return listIterator(0);} - public ListIterator listIterator(final int index) { - return new ListIterator() { - ListIterator i = list.listIterator(index); + public ListIterator listIterator() {return listIterator(0);} + + public ListIterator listIterator(final int index) { + return new ListIterator() { + private final ListIterator i + = list.listIterator(index); - public boolean hasNext() {return i.hasNext();} - public E next() {return i.next();} - public boolean hasPrevious() {return i.hasPrevious();} - public E previous() {return i.previous();} - public int nextIndex() {return i.nextIndex();} - public int previousIndex() {return i.previousIndex();} + public boolean hasNext() {return i.hasNext();} + public E next() {return i.next();} + public boolean hasPrevious() {return i.hasPrevious();} + public E previous() {return i.previous();} + public int nextIndex() {return i.nextIndex();} + public int previousIndex() {return i.previousIndex();} - public void remove() { - throw new UnsupportedOperationException(); + public void remove() { + throw new UnsupportedOperationException(); } - public void set(E o) { - throw new UnsupportedOperationException(); + public void set(E e) { + throw new UnsupportedOperationException(); + } + public void add(E e) { + throw new UnsupportedOperationException(); } - public void add(E o) { - throw new UnsupportedOperationException(); + + @Override + public void forEachRemaining(Consumer action) { + i.forEachRemaining(action); } - }; - } + }; + } - public List subList(int fromIndex, int toIndex) { - return new UnmodifiableList(list.subList(fromIndex, toIndex)); + public List subList(int fromIndex, int toIndex) { + return new UnmodifiableList<>(list.subList(fromIndex, toIndex)); } /** @@ -1228,8 +1382,8 @@ public List subList(int fromIndex, int toIndex) { */ private Object readResolve() { return (list instanceof RandomAccess - ? new UnmodifiableRandomAccessList(list) - : this); + ? new UnmodifiableRandomAccessList<>(list) + : this); } } @@ -1237,15 +1391,15 @@ private Object readResolve() { * @serial include */ static class UnmodifiableRandomAccessList extends UnmodifiableList - implements RandomAccess + implements RandomAccess { UnmodifiableRandomAccessList(List list) { super(list); } - public List subList(int fromIndex, int toIndex) { - return new UnmodifiableRandomAccessList( - list.subList(fromIndex, toIndex)); + public List subList(int fromIndex, int toIndex) { + return new UnmodifiableRandomAccessList<>( + list.subList(fromIndex, toIndex)); } private static final long serialVersionUID = -2542308836966382001L; @@ -1257,7 +1411,7 @@ public List subList(int fromIndex, int toIndex) { * deserialization. */ private Object writeReplace() { - return new UnmodifiableList(list); + return new UnmodifiableList<>(list); } } @@ -1270,75 +1424,137 @@ private Object writeReplace() { * UnsupportedOperationException.

* * The returned map will be serializable if the specified map - * is serializable. + * is serializable. * + * @param the class of the map keys + * @param the class of the map values * @param m the map for which an unmodifiable view is to be returned. * @return an unmodifiable view of the specified map. */ public static Map unmodifiableMap(Map m) { - return new UnmodifiableMap(m); + return new UnmodifiableMap<>(m); } /** * @serial include */ - private static class UnmodifiableMap implements Map { - // use serialVersionUID from JDK 1.2.2 for interoperability - private static final long serialVersionUID = -1034234728574286014L; + private static class UnmodifiableMap implements Map, Serializable { + private static final long serialVersionUID = -1034234728574286014L; - private final Map m; + private final Map m; - UnmodifiableMap(Map m) { + UnmodifiableMap(Map m) { if (m==null) throw new NullPointerException(); this.m = m; } - public int size() {return m.size();} - public boolean isEmpty() {return m.isEmpty();} - public boolean containsKey(Object key) {return m.containsKey(key);} - public boolean containsValue(Object val) {return m.containsValue(val);} - public V get(Object key) {return m.get(key);} + public int size() {return m.size();} + public boolean isEmpty() {return m.isEmpty();} + public boolean containsKey(Object key) {return m.containsKey(key);} + public boolean containsValue(Object val) {return m.containsValue(val);} + public V get(Object key) {return m.get(key);} - public V put(K key, V value) { - throw new UnsupportedOperationException(); + public V put(K key, V value) { + throw new UnsupportedOperationException(); } - public V remove(Object key) { - throw new UnsupportedOperationException(); + public V remove(Object key) { + throw new UnsupportedOperationException(); } - public void putAll(Map t) { - throw new UnsupportedOperationException(); + public void putAll(Map m) { + throw new UnsupportedOperationException(); } - public void clear() { - throw new UnsupportedOperationException(); + public void clear() { + throw new UnsupportedOperationException(); } - private transient Set keySet = null; - private transient Set> entrySet = null; - private transient Collection values = null; + private transient Set keySet; + private transient Set> entrySet; + private transient Collection values; - public Set keySet() { - if (keySet==null) - keySet = unmodifiableSet(m.keySet()); - return keySet; - } + public Set keySet() { + if (keySet==null) + keySet = unmodifiableSet(m.keySet()); + return keySet; + } - public Set> entrySet() { - if (entrySet==null) - entrySet = new UnmodifiableEntrySet(m.entrySet()); - return entrySet; - } + public Set> entrySet() { + if (entrySet==null) + entrySet = new UnmodifiableEntrySet<>(m.entrySet()); + return entrySet; + } - public Collection values() { - if (values==null) - values = unmodifiableCollection(m.values()); - return values; - } + public Collection values() { + if (values==null) + values = unmodifiableCollection(m.values()); + return values; + } - public boolean equals(Object o) {return m.equals(o);} - public int hashCode() {return m.hashCode();} + public boolean equals(Object o) {return o == this || m.equals(o);} + public int hashCode() {return m.hashCode();} public String toString() {return m.toString();} + // Override default methods in Map + @Override + @SuppressWarnings("unchecked") + public V getOrDefault(Object k, V defaultValue) { + // Safe cast as we don't change the value + return ((Map)m).getOrDefault(k, defaultValue); + } + + @Override + public void forEach(BiConsumer action) { + m.forEach(action); + } + + @Override + public void replaceAll(BiFunction function) { + throw new UnsupportedOperationException(); + } + + @Override + public V putIfAbsent(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfAbsent(K key, Function mappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfPresent(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V compute(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V merge(K key, V value, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + /** * We need this class in addition to UnmodifiableSet as * Map.Entries themselves permit modification of the backing Map @@ -1348,47 +1564,127 @@ public Collection values() { * @serial include */ static class UnmodifiableEntrySet - extends UnmodifiableSet> { - private static final long serialVersionUID = 7854390611657943733L; + extends UnmodifiableSet> { + private static final long serialVersionUID = 7854390611657943733L; + @SuppressWarnings({"unchecked", "rawtypes"}) UnmodifiableEntrySet(Set> s) { - super((Set>)(Set)s); + // Need to cast to raw in order to work around a limitation in the type system + super((Set)s); } - public Iterator> iterator() { - return new Iterator>() { - Iterator> i = c.iterator(); - public boolean hasNext() { - return i.hasNext(); - } - public Map.Entry next() { - return new UnmodifiableEntry(i.next()); - } - public void remove() { - throw new UnsupportedOperationException(); - } - }; + static Consumer> entryConsumer(Consumer> action) { + return e -> action.accept(new UnmodifiableEntry<>(e)); + } + + public void forEach(Consumer> action) { + Objects.requireNonNull(action); + c.forEach(entryConsumer(action)); + } + + static final class UnmodifiableEntrySetSpliterator + implements Spliterator> { + final Spliterator> s; + + UnmodifiableEntrySetSpliterator(Spliterator> s) { + this.s = s; + } + + @Override + public boolean tryAdvance(Consumer> action) { + Objects.requireNonNull(action); + return s.tryAdvance(entryConsumer(action)); + } + + @Override + public void forEachRemaining(Consumer> action) { + Objects.requireNonNull(action); + s.forEachRemaining(entryConsumer(action)); + } + + @Override + public Spliterator> trySplit() { + Spliterator> split = s.trySplit(); + return split == null + ? null + : new UnmodifiableEntrySetSpliterator<>(split); + } + + @Override + public long estimateSize() { + return s.estimateSize(); + } + + @Override + public long getExactSizeIfKnown() { + return s.getExactSizeIfKnown(); + } + + @Override + public int characteristics() { + return s.characteristics(); + } + + @Override + public boolean hasCharacteristics(int characteristics) { + return s.hasCharacteristics(characteristics); + } + + @Override + public Comparator> getComparator() { + return s.getComparator(); + } + } + + @SuppressWarnings("unchecked") + public Spliterator> spliterator() { + return new UnmodifiableEntrySetSpliterator<>( + (Spliterator>) c.spliterator()); } +// @Override +// public Stream> stream() { +// return StreamSupport.stream(spliterator(), false); +// } +// +// @Override +// public Stream> parallelStream() { +// return StreamSupport.stream(spliterator(), true); +// } +// +// public Iterator> iterator() { +// return new Iterator>() { +// private final Iterator> i = c.iterator(); +// +// public boolean hasNext() { +// return i.hasNext(); +// } +// public Map.Entry next() { +// return new UnmodifiableEntry<>(i.next()); +// } +// public void remove() { +// throw new UnsupportedOperationException(); +// } +// }; +// } + + @SuppressWarnings("unchecked") public Object[] toArray() { Object[] a = c.toArray(); for (int i=0; i((Map.Entry)a[i]); + a[i] = new UnmodifiableEntry<>((Map.Entry)a[i]); return a; } + @SuppressWarnings("unchecked") public T[] toArray(T[] a) { // We don't pass a to c.toArray, to avoid window of // vulnerability wherein an unscrupulous multithreaded client // could get his hands on raw (unwrapped) Entries from c. - Object[] arr = - c.toArray( - a.length==0 ? a : - (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), 0) - ); + Object[] arr = c.toArray(a.length==0 ? a : Arrays.copyOf(a, 0)); for (int i=0; i((Map.Entry)arr[i]); + arr[i] = new UnmodifiableEntry<>((Map.Entry)arr[i]); if (arr.length > a.length) return (T[])arr; @@ -1408,7 +1704,8 @@ public T[] toArray(T[] a) { public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; - return c.contains(new UnmodifiableEntry((Map.Entry) o)); + return c.contains( + new UnmodifiableEntry<>((Map.Entry) o)); } /** @@ -1417,10 +1714,10 @@ public boolean contains(Object o) { * when o is a Map.Entry, and calls o.setValue. */ public boolean containsAll(Collection coll) { - Iterator e = coll.iterator(); - while (e.hasNext()) - if (!contains(e.next())) // Invokes safe contains() above + for (Object e : coll) { + if (!contains(e)) // Invokes safe contains() above return false; + } return true; } public boolean equals(Object o) { @@ -1429,7 +1726,7 @@ public boolean equals(Object o) { if (!(o instanceof Set)) return false; - Set s = (Set) o; + Set s = (Set) o; if (s.size() != c.size()) return false; return containsAll(s); // Invokes safe containsAll() above @@ -1445,22 +1742,25 @@ public boolean equals(Object o) { private static class UnmodifiableEntry implements Map.Entry { private Map.Entry e; - UnmodifiableEntry(Map.Entry e) {this.e = e;} + UnmodifiableEntry(Map.Entry e) + {this.e = Objects.requireNonNull(e);} - public K getKey() {return e.getKey();} - public V getValue() {return e.getValue();} + public K getKey() {return e.getKey();} + public V getValue() {return e.getValue();} public V setValue(V value) { throw new UnsupportedOperationException(); } - public int hashCode() {return e.hashCode();} + public int hashCode() {return e.hashCode();} public boolean equals(Object o) { + if (this == o) + return true; if (!(o instanceof Map.Entry)) return false; - Map.Entry t = (Map.Entry)o; + Map.Entry t = (Map.Entry)o; return eq(e.getKey(), t.getKey()) && - eq(e.getValue(), t.getValue()); + eq(e.getValue(), t.getValue()); } - public String toString() {return e.toString();} + public String toString() {return e.toString();} } } } @@ -1475,44 +1775,181 @@ public boolean equals(Object o) { * an UnsupportedOperationException.

* * The returned sorted map will be serializable if the specified sorted map - * is serializable. + * is serializable. * + * @param the class of the map keys + * @param the class of the map values * @param m the sorted map for which an unmodifiable view is to be - * returned. + * returned. * @return an unmodifiable view of the specified sorted map. */ public static SortedMap unmodifiableSortedMap(SortedMap m) { - return new UnmodifiableSortedMap(m); + return new UnmodifiableSortedMap<>(m); } /** * @serial include */ static class UnmodifiableSortedMap - extends UnmodifiableMap - implements SortedMap { - private static final long serialVersionUID = -8806743815996713206L; + extends UnmodifiableMap + implements SortedMap, Serializable { + private static final long serialVersionUID = -8806743815996713206L; + + private final SortedMap sm; + + UnmodifiableSortedMap(SortedMap m) {super(m); sm = m; } + public Comparator comparator() { return sm.comparator(); } + public SortedMap subMap(K fromKey, K toKey) + { return new UnmodifiableSortedMap<>(sm.subMap(fromKey, toKey)); } + public SortedMap headMap(K toKey) + { return new UnmodifiableSortedMap<>(sm.headMap(toKey)); } + public SortedMap tailMap(K fromKey) + { return new UnmodifiableSortedMap<>(sm.tailMap(fromKey)); } + public K firstKey() { return sm.firstKey(); } + public K lastKey() { return sm.lastKey(); } + } + + /** + * Returns an unmodifiable view of the specified navigable map. This method + * allows modules to provide users with "read-only" access to internal + * navigable maps. Query operations on the returned navigable map "read + * through" to the specified navigable map. Attempts to modify the returned + * navigable map, whether direct, via its collection views, or via its + * {@code subMap}, {@code headMap}, or {@code tailMap} views, result in + * an {@code UnsupportedOperationException}.

+ * + * The returned navigable map will be serializable if the specified + * navigable map is serializable. + * + * @param the class of the map keys + * @param the class of the map values + * @param m the navigable map for which an unmodifiable view is to be + * returned + * @return an unmodifiable view of the specified navigable map + * @since 1.8 + */ + public static NavigableMap unmodifiableNavigableMap(NavigableMap m) { + return new UnmodifiableNavigableMap<>(m); + } - private SortedMap sm; + /** + * @serial include + */ + static class UnmodifiableNavigableMap + extends UnmodifiableSortedMap + implements NavigableMap, Serializable { + private static final long serialVersionUID = -4858195264774772197L; + + /** + * A class for the {@link EMPTY_NAVIGABLE_MAP} which needs readResolve + * to preserve singleton property. + * + * @param type of keys, if there were any, and of bounds + * @param type of values, if there were any + */ + private static class EmptyNavigableMap extends UnmodifiableNavigableMap + implements Serializable { - UnmodifiableSortedMap(SortedMap m) {super(m); sm = m;} + private static final long serialVersionUID = -2239321462712562324L; - public Comparator comparator() {return sm.comparator();} + EmptyNavigableMap() { super(new TreeMap()); } - public SortedMap subMap(K fromKey, K toKey) { - return new UnmodifiableSortedMap(sm.subMap(fromKey, toKey)); + @Override + public NavigableSet navigableKeySet() + { return emptyNavigableSet(); } + + private Object readResolve() { return EMPTY_NAVIGABLE_MAP; } } - public SortedMap headMap(K toKey) { - return new UnmodifiableSortedMap(sm.headMap(toKey)); + + /** + * Singleton for {@link emptyNavigableMap()} which is also immutable. + */ + private static final EmptyNavigableMap EMPTY_NAVIGABLE_MAP = + new EmptyNavigableMap<>(); + + /** + * The instance we wrap and protect. + */ + private final NavigableMap nm; + + UnmodifiableNavigableMap(NavigableMap m) + {super(m); nm = m;} + + public K lowerKey(K key) { return nm.lowerKey(key); } + public K floorKey(K key) { return nm.floorKey(key); } + public K ceilingKey(K key) { return nm.ceilingKey(key); } + public K higherKey(K key) { return nm.higherKey(key); } + + @SuppressWarnings("unchecked") + public Entry lowerEntry(K key) { + Entry lower = (Entry) nm.lowerEntry(key); + return (null != lower) + ? new UnmodifiableEntrySet.UnmodifiableEntry<>(lower) + : null; } - public SortedMap tailMap(K fromKey) { - return new UnmodifiableSortedMap(sm.tailMap(fromKey)); + + @SuppressWarnings("unchecked") + public Entry floorEntry(K key) { + Entry floor = (Entry) nm.floorEntry(key); + return (null != floor) + ? new UnmodifiableEntrySet.UnmodifiableEntry<>(floor) + : null; + } + + @SuppressWarnings("unchecked") + public Entry ceilingEntry(K key) { + Entry ceiling = (Entry) nm.ceilingEntry(key); + return (null != ceiling) + ? new UnmodifiableEntrySet.UnmodifiableEntry<>(ceiling) + : null; } - public K firstKey() {return sm.firstKey();} - public K lastKey() {return sm.lastKey();} - } + @SuppressWarnings("unchecked") + public Entry higherEntry(K key) { + Entry higher = (Entry) nm.higherEntry(key); + return (null != higher) + ? new UnmodifiableEntrySet.UnmodifiableEntry<>(higher) + : null; + } + + @SuppressWarnings("unchecked") + public Entry firstEntry() { + Entry first = (Entry) nm.firstEntry(); + return (null != first) + ? new UnmodifiableEntrySet.UnmodifiableEntry<>(first) + : null; + } + + @SuppressWarnings("unchecked") + public Entry lastEntry() { + Entry last = (Entry) nm.lastEntry(); + return (null != last) + ? new UnmodifiableEntrySet.UnmodifiableEntry<>(last) + : null; + } + + public Entry pollFirstEntry() + { throw new UnsupportedOperationException(); } + public Entry pollLastEntry() + { throw new UnsupportedOperationException(); } + public NavigableMap descendingMap() + { return unmodifiableNavigableMap(nm.descendingMap()); } + public NavigableSet navigableKeySet() + { return unmodifiableNavigableSet(nm.navigableKeySet()); } + public NavigableSet descendingKeySet() + { return unmodifiableNavigableSet(nm.descendingKeySet()); } + + public NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { + return unmodifiableNavigableMap( + nm.subMap(fromKey, fromInclusive, toKey, toInclusive)); + } + + public NavigableMap headMap(K toKey, boolean inclusive) + { return unmodifiableNavigableMap(nm.headMap(toKey, inclusive)); } + public NavigableMap tailMap(K fromKey, boolean inclusive) + { return unmodifiableNavigableMap(nm.tailMap(fromKey, inclusive)); } + } // Synch Wrappers @@ -1523,11 +1960,12 @@ public SortedMap tailMap(K fromKey) { * through the returned collection.

* * It is imperative that the user manually synchronize on the returned - * collection when iterating over it: + * collection when traversing it via {@link Iterator}, {@link Spliterator} + * or {@link Stream}: *

      *  Collection c = Collections.synchronizedCollection(myCollection);
      *     ...
-     *  synchronized(c) {
+     *  synchronized (c) {
      *      Iterator i = c.iterator(); // Must be in the synchronized block
      *      while (i.hasNext())
      *         foo(i.next());
@@ -1535,95 +1973,115 @@ public SortedMap tailMap(K fromKey) {
      * 
* Failure to follow this advice may result in non-deterministic behavior. * - *

The returned collection does not pass the hashCode - * and equals operations through to the backing collection, but - * relies on Object's equals and hashCode methods. This is + *

The returned collection does not pass the {@code hashCode} + * and {@code equals} operations through to the backing collection, but + * relies on {@code Object}'s equals and hashCode methods. This is * necessary to preserve the contracts of these operations in the case * that the backing collection is a set or a list.

* * The returned collection will be serializable if the specified collection - * is serializable. + * is serializable. * + * @param the class of the objects in the collection * @param c the collection to be "wrapped" in a synchronized collection. * @return a synchronized view of the specified collection. */ public static Collection synchronizedCollection(Collection c) { - return new SynchronizedCollection(c); + return new SynchronizedCollection<>(c); } static Collection synchronizedCollection(Collection c, Object mutex) { - return new SynchronizedCollection(c, mutex); + return new SynchronizedCollection<>(c, mutex); } /** * @serial include */ - static class SynchronizedCollection implements Collection { - // use serialVersionUID from JDK 1.2.2 for interoperability - private static final long serialVersionUID = 3053995032091335093L; + static class SynchronizedCollection implements Collection, Serializable { + private static final long serialVersionUID = 3053995032091335093L; - Collection c; // Backing Collection - Object mutex; // Object on which to synchronize + final Collection c; // Backing Collection + final Object mutex; // Object on which to synchronize - SynchronizedCollection(Collection c) { - if (c==null) - throw new NullPointerException(); - this.c = c; + SynchronizedCollection(Collection c) { + this.c = Objects.requireNonNull(c); mutex = this; } - SynchronizedCollection(Collection c, Object mutex) { - this.c = c; - this.mutex = mutex; + + SynchronizedCollection(Collection c, Object mutex) { + this.c = Objects.requireNonNull(c); + this.mutex = Objects.requireNonNull(mutex); } - public int size() { - synchronized(mutex) {return c.size();} + public int size() { + synchronized (mutex) {return c.size();} } - public boolean isEmpty() { - synchronized(mutex) {return c.isEmpty();} + public boolean isEmpty() { + synchronized (mutex) {return c.isEmpty();} } - public boolean contains(Object o) { - synchronized(mutex) {return c.contains(o);} + public boolean contains(Object o) { + synchronized (mutex) {return c.contains(o);} } - public Object[] toArray() { - synchronized(mutex) {return c.toArray();} + public Object[] toArray() { + synchronized (mutex) {return c.toArray();} } - public T[] toArray(T[] a) { - synchronized(mutex) {return c.toArray(a);} + public T[] toArray(T[] a) { + synchronized (mutex) {return c.toArray(a);} } - public Iterator iterator() { + public Iterator iterator() { return c.iterator(); // Must be manually synched by user! } - public boolean add(E o) { - synchronized(mutex) {return c.add(o);} + public boolean add(E e) { + synchronized (mutex) {return c.add(e);} } - public boolean remove(Object o) { - synchronized(mutex) {return c.remove(o);} + public boolean remove(Object o) { + synchronized (mutex) {return c.remove(o);} } - public boolean containsAll(Collection coll) { - synchronized(mutex) {return c.containsAll(coll);} + public boolean containsAll(Collection coll) { + synchronized (mutex) {return c.containsAll(coll);} + } + public boolean addAll(Collection coll) { + synchronized (mutex) {return c.addAll(coll);} + } + public boolean removeAll(Collection coll) { + synchronized (mutex) {return c.removeAll(coll);} + } + public boolean retainAll(Collection coll) { + synchronized (mutex) {return c.retainAll(coll);} } - public boolean addAll(Collection coll) { - synchronized(mutex) {return c.addAll(coll);} + public void clear() { + synchronized (mutex) {c.clear();} } - public boolean removeAll(Collection coll) { - synchronized(mutex) {return c.removeAll(coll);} + public String toString() { + synchronized (mutex) {return c.toString();} } - public boolean retainAll(Collection coll) { - synchronized(mutex) {return c.retainAll(coll);} + // Override default methods in Collection + @Override + public void forEach(Consumer consumer) { + synchronized (mutex) {c.forEach(consumer);} } - public void clear() { - synchronized(mutex) {c.clear();} + @Override + public boolean removeIf(Predicate filter) { + synchronized (mutex) {return c.removeIf(filter);} } - public String toString() { - synchronized(mutex) {return c.toString();} + @Override + public Spliterator spliterator() { + return c.spliterator(); // Must be manually synched by user! } -// private void writeObject(ObjectOutputStream s) throws IOException { -// synchronized(mutex) {s.defaultWriteObject();} +// @Override +// public Stream stream() { +// return c.stream(); // Must be manually synched by user! +// } +// @Override +// public Stream parallelStream() { +// return c.parallelStream(); // Must be manually synched by user! // } + private void writeObject(ObjectOutputStream s) throws IOException { + synchronized (mutex) {s.defaultWriteObject();} + } } /** @@ -1637,7 +2095,7 @@ public String toString() { *

      *  Set s = Collections.synchronizedSet(new HashSet());
      *      ...
-     *  synchronized(s) {
+     *  synchronized (s) {
      *      Iterator i = s.iterator(); // Must be in the synchronized block
      *      while (i.hasNext())
      *          foo(i.next());
@@ -1648,37 +2106,40 @@ public String toString() {
      * 

The returned set will be serializable if the specified set is * serializable. * + * @param the class of the objects in the set * @param s the set to be "wrapped" in a synchronized set. * @return a synchronized view of the specified set. */ public static Set synchronizedSet(Set s) { - return new SynchronizedSet(s); + return new SynchronizedSet<>(s); } static Set synchronizedSet(Set s, Object mutex) { - return new SynchronizedSet(s, mutex); + return new SynchronizedSet<>(s, mutex); } /** * @serial include */ static class SynchronizedSet - extends SynchronizedCollection - implements Set { - private static final long serialVersionUID = 487447009682186044L; + extends SynchronizedCollection + implements Set { + private static final long serialVersionUID = 487447009682186044L; - SynchronizedSet(Set s) { + SynchronizedSet(Set s) { super(s); } - SynchronizedSet(Set s, Object mutex) { + SynchronizedSet(Set s, Object mutex) { super(s, mutex); } - public boolean equals(Object o) { - synchronized(mutex) {return c.equals(o);} + public boolean equals(Object o) { + if (this == o) + return true; + synchronized (mutex) {return c.equals(o);} } - public int hashCode() { - synchronized(mutex) {return c.hashCode();} + public int hashCode() { + synchronized (mutex) {return c.hashCode();} } } @@ -1692,9 +2153,9 @@ public int hashCode() { * sorted set when iterating over it or any of its subSet, * headSet, or tailSet views. *

-     *  SortedSet s = Collections.synchronizedSortedSet(new HashSortedSet());
+     *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
      *      ...
-     *  synchronized(s) {
+     *  synchronized (s) {
      *      Iterator i = s.iterator(); // Must be in the synchronized block
      *      while (i.hasNext())
      *          foo(i.next());
@@ -1702,10 +2163,10 @@ public int hashCode() {
      * 
* or: *
-     *  SortedSet s = Collections.synchronizedSortedSet(new HashSortedSet());
+     *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
      *  SortedSet s2 = s.headSet(foo);
      *      ...
-     *  synchronized(s) {  // Note: s, not s2!!!
+     *  synchronized (s) {  // Note: s, not s2!!!
      *      Iterator i = s2.iterator(); // Must be in the synchronized block
      *      while (i.hasNext())
      *          foo(i.next());
@@ -1716,65 +2177,181 @@ public int hashCode() {
      * 

The returned sorted set will be serializable if the specified * sorted set is serializable. * + * @param the class of the objects in the set * @param s the sorted set to be "wrapped" in a synchronized sorted set. * @return a synchronized view of the specified sorted set. */ public static SortedSet synchronizedSortedSet(SortedSet s) { - return new SynchronizedSortedSet(s); + return new SynchronizedSortedSet<>(s); } /** * @serial include */ static class SynchronizedSortedSet - extends SynchronizedSet - implements SortedSet + extends SynchronizedSet + implements SortedSet { - private static final long serialVersionUID = 8695801310862127406L; + private static final long serialVersionUID = 8695801310862127406L; - private SortedSet ss; + private final SortedSet ss; - SynchronizedSortedSet(SortedSet s) { + SynchronizedSortedSet(SortedSet s) { super(s); ss = s; } - SynchronizedSortedSet(SortedSet s, Object mutex) { + SynchronizedSortedSet(SortedSet s, Object mutex) { super(s, mutex); ss = s; } - public Comparator comparator() { - synchronized(mutex) {return ss.comparator();} + public Comparator comparator() { + synchronized (mutex) {return ss.comparator();} } public SortedSet subSet(E fromElement, E toElement) { - synchronized(mutex) { - return new SynchronizedSortedSet( - ss.subSet(fromElement, toElement), mutex); + synchronized (mutex) { + return new SynchronizedSortedSet<>( + ss.subSet(fromElement, toElement), mutex); } } public SortedSet headSet(E toElement) { - synchronized(mutex) { - return new SynchronizedSortedSet(ss.headSet(toElement), mutex); + synchronized (mutex) { + return new SynchronizedSortedSet<>(ss.headSet(toElement), mutex); } } public SortedSet tailSet(E fromElement) { - synchronized(mutex) { - return new SynchronizedSortedSet(ss.tailSet(fromElement),mutex); + synchronized (mutex) { + return new SynchronizedSortedSet<>(ss.tailSet(fromElement),mutex); } } public E first() { - synchronized(mutex) {return ss.first();} + synchronized (mutex) {return ss.first();} } public E last() { - synchronized(mutex) {return ss.last();} + synchronized (mutex) {return ss.last();} } } /** - * Returns a synchronized (thread-safe) list backed by the specified - * list. In order to guarantee serial access, it is critical that + * Returns a synchronized (thread-safe) navigable set backed by the + * specified navigable set. In order to guarantee serial access, it is + * critical that all access to the backing navigable set is + * accomplished through the returned navigable set (or its views).

+ * + * It is imperative that the user manually synchronize on the returned + * navigable set when iterating over it or any of its {@code subSet}, + * {@code headSet}, or {@code tailSet} views. + *

+     *  NavigableSet s = Collections.synchronizedNavigableSet(new TreeSet());
+     *      ...
+     *  synchronized (s) {
+     *      Iterator i = s.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * 
+ * or: + *
+     *  NavigableSet s = Collections.synchronizedNavigableSet(new TreeSet());
+     *  NavigableSet s2 = s.headSet(foo, true);
+     *      ...
+     *  synchronized (s) {  // Note: s, not s2!!!
+     *      Iterator i = s2.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned navigable set will be serializable if the specified + * navigable set is serializable. + * + * @param the class of the objects in the set + * @param s the navigable set to be "wrapped" in a synchronized navigable + * set + * @return a synchronized view of the specified navigable set + * @since 1.8 + */ + public static NavigableSet synchronizedNavigableSet(NavigableSet s) { + return new SynchronizedNavigableSet<>(s); + } + + /** + * @serial include + */ + static class SynchronizedNavigableSet + extends SynchronizedSortedSet + implements NavigableSet + { + private static final long serialVersionUID = -5505529816273629798L; + + private final NavigableSet ns; + + SynchronizedNavigableSet(NavigableSet s) { + super(s); + ns = s; + } + + SynchronizedNavigableSet(NavigableSet s, Object mutex) { + super(s, mutex); + ns = s; + } + public E lower(E e) { synchronized (mutex) {return ns.lower(e);} } + public E floor(E e) { synchronized (mutex) {return ns.floor(e);} } + public E ceiling(E e) { synchronized (mutex) {return ns.ceiling(e);} } + public E higher(E e) { synchronized (mutex) {return ns.higher(e);} } + public E pollFirst() { synchronized (mutex) {return ns.pollFirst();} } + public E pollLast() { synchronized (mutex) {return ns.pollLast();} } + + public NavigableSet descendingSet() { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(ns.descendingSet(), mutex); + } + } + + public Iterator descendingIterator() + { synchronized (mutex) { return descendingSet().iterator(); } } + + public NavigableSet subSet(E fromElement, E toElement) { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(ns.subSet(fromElement, true, toElement, false), mutex); + } + } + public NavigableSet headSet(E toElement) { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(ns.headSet(toElement, false), mutex); + } + } + public NavigableSet tailSet(E fromElement) { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(ns.tailSet(fromElement, true), mutex); + } + } + + public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), mutex); + } + } + + public NavigableSet headSet(E toElement, boolean inclusive) { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(ns.headSet(toElement, inclusive), mutex); + } + } + + public NavigableSet tailSet(E fromElement, boolean inclusive) { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(ns.tailSet(fromElement, inclusive), mutex); + } + } + } + + /** + * Returns a synchronized (thread-safe) list backed by the specified + * list. In order to guarantee serial access, it is critical that * all access to the backing list is accomplished * through the returned list.

* @@ -1783,7 +2360,7 @@ public E last() { *

      *  List list = Collections.synchronizedList(new ArrayList());
      *      ...
-     *  synchronized(list) {
+     *  synchronized (list) {
      *      Iterator i = list.iterator(); // Must be in synchronized block
      *      while (i.hasNext())
      *          foo(i.next());
@@ -1794,86 +2371,98 @@ public E last() {
      * 

The returned list will be serializable if the specified list is * serializable. * + * @param the class of the objects in the list * @param list the list to be "wrapped" in a synchronized list. * @return a synchronized view of the specified list. */ public static List synchronizedList(List list) { - return (list instanceof RandomAccess ? - new SynchronizedRandomAccessList(list) : - new SynchronizedList(list)); + return (list instanceof RandomAccess ? + new SynchronizedRandomAccessList<>(list) : + new SynchronizedList<>(list)); } static List synchronizedList(List list, Object mutex) { - return (list instanceof RandomAccess ? - new SynchronizedRandomAccessList(list, mutex) : - new SynchronizedList(list, mutex)); + return (list instanceof RandomAccess ? + new SynchronizedRandomAccessList<>(list, mutex) : + new SynchronizedList<>(list, mutex)); } /** * @serial include */ static class SynchronizedList - extends SynchronizedCollection - implements List { - static final long serialVersionUID = -7754090372962971524L; + extends SynchronizedCollection + implements List { + private static final long serialVersionUID = -7754090372962971524L; - List list; + final List list; - SynchronizedList(List list) { - super(list); - this.list = list; - } - SynchronizedList(List list, Object mutex) { + SynchronizedList(List list) { + super(list); + this.list = list; + } + SynchronizedList(List list, Object mutex) { super(list, mutex); - this.list = list; + this.list = list; } - public boolean equals(Object o) { - synchronized(mutex) {return list.equals(o);} + public boolean equals(Object o) { + if (this == o) + return true; + synchronized (mutex) {return list.equals(o);} } - public int hashCode() { - synchronized(mutex) {return list.hashCode();} + public int hashCode() { + synchronized (mutex) {return list.hashCode();} } - public E get(int index) { - synchronized(mutex) {return list.get(index);} + public E get(int index) { + synchronized (mutex) {return list.get(index);} } - public E set(int index, E element) { - synchronized(mutex) {return list.set(index, element);} + public E set(int index, E element) { + synchronized (mutex) {return list.set(index, element);} } - public void add(int index, E element) { - synchronized(mutex) {list.add(index, element);} + public void add(int index, E element) { + synchronized (mutex) {list.add(index, element);} } - public E remove(int index) { - synchronized(mutex) {return list.remove(index);} + public E remove(int index) { + synchronized (mutex) {return list.remove(index);} } - public int indexOf(Object o) { - synchronized(mutex) {return list.indexOf(o);} + public int indexOf(Object o) { + synchronized (mutex) {return list.indexOf(o);} } - public int lastIndexOf(Object o) { - synchronized(mutex) {return list.lastIndexOf(o);} + public int lastIndexOf(Object o) { + synchronized (mutex) {return list.lastIndexOf(o);} } - public boolean addAll(int index, Collection c) { - synchronized(mutex) {return list.addAll(index, c);} + public boolean addAll(int index, Collection c) { + synchronized (mutex) {return list.addAll(index, c);} } - public ListIterator listIterator() { - return list.listIterator(); // Must be manually synched by user + public ListIterator listIterator() { + return list.listIterator(); // Must be manually synched by user } - public ListIterator listIterator(int index) { - return list.listIterator(index); // Must be manually synched by user + public ListIterator listIterator(int index) { + return list.listIterator(index); // Must be manually synched by user } - public List subList(int fromIndex, int toIndex) { - synchronized(mutex) { - return new SynchronizedList(list.subList(fromIndex, toIndex), - mutex); + public List subList(int fromIndex, int toIndex) { + synchronized (mutex) { + return new SynchronizedList<>(list.subList(fromIndex, toIndex), + mutex); } } + @Override + public void replaceAll(UnaryOperator operator) { + synchronized (mutex) {list.replaceAll(operator);} + } + @Override + public void sort(Comparator c) { + synchronized (mutex) {list.sort(c);} + } + /** * SynchronizedRandomAccessList instances are serialized as * SynchronizedList instances to allow them to be deserialized @@ -1888,8 +2477,8 @@ public List subList(int fromIndex, int toIndex) { */ private Object readResolve() { return (list instanceof RandomAccess - ? new SynchronizedRandomAccessList(list) - : this); + ? new SynchronizedRandomAccessList<>(list) + : this); } } @@ -1897,25 +2486,25 @@ private Object readResolve() { * @serial include */ static class SynchronizedRandomAccessList - extends SynchronizedList - implements RandomAccess { + extends SynchronizedList + implements RandomAccess { SynchronizedRandomAccessList(List list) { super(list); } - SynchronizedRandomAccessList(List list, Object mutex) { + SynchronizedRandomAccessList(List list, Object mutex) { super(list, mutex); } - public List subList(int fromIndex, int toIndex) { - synchronized(mutex) { - return new SynchronizedRandomAccessList( - list.subList(fromIndex, toIndex), mutex); + public List subList(int fromIndex, int toIndex) { + synchronized (mutex) { + return new SynchronizedRandomAccessList<>( + list.subList(fromIndex, toIndex), mutex); } } - static final long serialVersionUID = 1530674583602358482L; + private static final long serialVersionUID = 1530674583602358482L; /** * Allows instances to be deserialized in pre-1.4 JREs (which do @@ -1924,7 +2513,7 @@ public List subList(int fromIndex, int toIndex) { * deserialization. */ private Object writeReplace() { - return new SynchronizedList(list); + return new SynchronizedList<>(list); } } @@ -1941,7 +2530,7 @@ private Object writeReplace() { * ... * Set s = m.keySet(); // Needn't be in synchronized block * ... - * synchronized(m) { // Synchronizing on m, not s! + * synchronized (m) { // Synchronizing on m, not s! * Iterator i = s.iterator(); // Must be in synchronized block * while (i.hasNext()) * foo(i.next()); @@ -1952,105 +2541,157 @@ private Object writeReplace() { *

The returned map will be serializable if the specified map is * serializable. * + * @param the class of the map keys + * @param the class of the map values * @param m the map to be "wrapped" in a synchronized map. * @return a synchronized view of the specified map. */ public static Map synchronizedMap(Map m) { - return new SynchronizedMap(m); + return new SynchronizedMap<>(m); } /** * @serial include */ private static class SynchronizedMap - implements Map { - // use serialVersionUID from JDK 1.2.2 for interoperability - private static final long serialVersionUID = 1978198479659022715L; + implements Map, Serializable { + private static final long serialVersionUID = 1978198479659022715L; - private Map m; // Backing Map - Object mutex; // Object on which to synchronize + private final Map m; // Backing Map + final Object mutex; // Object on which to synchronize - SynchronizedMap(Map m) { - if (m==null) - throw new NullPointerException(); - this.m = m; + SynchronizedMap(Map m) { + this.m = Objects.requireNonNull(m); mutex = this; } - SynchronizedMap(Map m, Object mutex) { + SynchronizedMap(Map m, Object mutex) { this.m = m; this.mutex = mutex; } - public int size() { - synchronized(mutex) {return m.size();} + public int size() { + synchronized (mutex) {return m.size();} } - public boolean isEmpty(){ - synchronized(mutex) {return m.isEmpty();} + public boolean isEmpty() { + synchronized (mutex) {return m.isEmpty();} } - public boolean containsKey(Object key) { - synchronized(mutex) {return m.containsKey(key);} + public boolean containsKey(Object key) { + synchronized (mutex) {return m.containsKey(key);} } - public boolean containsValue(Object value){ - synchronized(mutex) {return m.containsValue(value);} + public boolean containsValue(Object value) { + synchronized (mutex) {return m.containsValue(value);} } - public V get(Object key) { - synchronized(mutex) {return m.get(key);} + public V get(Object key) { + synchronized (mutex) {return m.get(key);} } - public V put(K key, V value) { - synchronized(mutex) {return m.put(key, value);} + public V put(K key, V value) { + synchronized (mutex) {return m.put(key, value);} } - public V remove(Object key) { - synchronized(mutex) {return m.remove(key);} + public V remove(Object key) { + synchronized (mutex) {return m.remove(key);} } - public void putAll(Map map) { - synchronized(mutex) {m.putAll(map);} + public void putAll(Map map) { + synchronized (mutex) {m.putAll(map);} + } + public void clear() { + synchronized (mutex) {m.clear();} } - public void clear() { - synchronized(mutex) {m.clear();} - } - private transient Set keySet = null; - private transient Set> entrySet = null; - private transient Collection values = null; + private transient Set keySet; + private transient Set> entrySet; + private transient Collection values; - public Set keySet() { - synchronized(mutex) { + public Set keySet() { + synchronized (mutex) { if (keySet==null) - keySet = new SynchronizedSet(m.keySet(), mutex); + keySet = new SynchronizedSet<>(m.keySet(), mutex); return keySet; } - } + } - public Set> entrySet() { - synchronized(mutex) { + public Set> entrySet() { + synchronized (mutex) { if (entrySet==null) - entrySet = new SynchronizedSet>((Set>)m.entrySet(), mutex); + entrySet = new SynchronizedSet<>(m.entrySet(), mutex); return entrySet; } - } + } - public Collection values() { - synchronized(mutex) { + public Collection values() { + synchronized (mutex) { if (values==null) - values = new SynchronizedCollection(m.values(), mutex); + values = new SynchronizedCollection<>(m.values(), mutex); return values; } } - public boolean equals(Object o) { - synchronized(mutex) {return m.equals(o);} + public boolean equals(Object o) { + if (this == o) + return true; + synchronized (mutex) {return m.equals(o);} } - public int hashCode() { - synchronized(mutex) {return m.hashCode();} + public int hashCode() { + synchronized (mutex) {return m.hashCode();} } - public String toString() { - synchronized(mutex) {return m.toString();} + public String toString() { + synchronized (mutex) {return m.toString();} + } + + // Override default methods in Map + @Override + public V getOrDefault(Object k, V defaultValue) { + synchronized (mutex) {return m.getOrDefault(k, defaultValue);} + } + @Override + public void forEach(BiConsumer action) { + synchronized (mutex) {m.forEach(action);} + } + @Override + public void replaceAll(BiFunction function) { + synchronized (mutex) {m.replaceAll(function);} + } + @Override + public V putIfAbsent(K key, V value) { + synchronized (mutex) {return m.putIfAbsent(key, value);} + } + @Override + public boolean remove(Object key, Object value) { + synchronized (mutex) {return m.remove(key, value);} + } + @Override + public boolean replace(K key, V oldValue, V newValue) { + synchronized (mutex) {return m.replace(key, oldValue, newValue);} + } + @Override + public V replace(K key, V value) { + synchronized (mutex) {return m.replace(key, value);} + } + @Override + public V computeIfAbsent(K key, + Function mappingFunction) { + synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);} + } + @Override + public V computeIfPresent(K key, + BiFunction remappingFunction) { + synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);} + } + @Override + public V compute(K key, + BiFunction remappingFunction) { + synchronized (mutex) {return m.compute(key, remappingFunction);} + } + @Override + public V merge(K key, V value, + BiFunction remappingFunction) { + synchronized (mutex) {return m.merge(key, value, remappingFunction);} + } + + private void writeObject(ObjectOutputStream s) throws IOException { + synchronized (mutex) {s.defaultWriteObject();} } -// private void writeObject(ObjectOutputStream s) throws IOException { -// synchronized(mutex) {s.defaultWriteObject();} -// } } /** @@ -2064,11 +2705,11 @@ public String toString() { * collections views of any of its subMap, headMap or * tailMap views. *

-     *  SortedMap m = Collections.synchronizedSortedMap(new HashSortedMap());
+     *  SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
      *      ...
      *  Set s = m.keySet();  // Needn't be in synchronized block
      *      ...
-     *  synchronized(m) {  // Synchronizing on m, not s!
+     *  synchronized (m) {  // Synchronizing on m, not s!
      *      Iterator i = s.iterator(); // Must be in synchronized block
      *      while (i.hasNext())
      *          foo(i.next());
@@ -2076,12 +2717,12 @@ public String toString() {
      * 
* or: *
-     *  SortedMap m = Collections.synchronizedSortedMap(new HashSortedMap());
+     *  SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
      *  SortedMap m2 = m.subMap(foo, bar);
      *      ...
      *  Set s2 = m2.keySet();  // Needn't be in synchronized block
      *      ...
-     *  synchronized(m) {  // Synchronizing on m, not m2 or s2!
+     *  synchronized (m) {  // Synchronizing on m, not m2 or s2!
      *      Iterator i = s.iterator(); // Must be in synchronized block
      *      while (i.hasNext())
      *          foo(i.next());
@@ -2092,73 +2733,235 @@ public String toString() {
      * 

The returned sorted map will be serializable if the specified * sorted map is serializable. * + * @param the class of the map keys + * @param the class of the map values * @param m the sorted map to be "wrapped" in a synchronized sorted map. * @return a synchronized view of the specified sorted map. */ public static SortedMap synchronizedSortedMap(SortedMap m) { - return new SynchronizedSortedMap(m); + return new SynchronizedSortedMap<>(m); } - /** * @serial include */ static class SynchronizedSortedMap - extends SynchronizedMap - implements SortedMap + extends SynchronizedMap + implements SortedMap { - private static final long serialVersionUID = -8798146769416483793L; + private static final long serialVersionUID = -8798146769416483793L; - private SortedMap sm; + private final SortedMap sm; - SynchronizedSortedMap(SortedMap m) { + SynchronizedSortedMap(SortedMap m) { super(m); sm = m; } - SynchronizedSortedMap(SortedMap m, Object mutex) { + SynchronizedSortedMap(SortedMap m, Object mutex) { super(m, mutex); sm = m; } - public Comparator comparator() { - synchronized(mutex) {return sm.comparator();} + public Comparator comparator() { + synchronized (mutex) {return sm.comparator();} } public SortedMap subMap(K fromKey, K toKey) { - synchronized(mutex) { - return new SynchronizedSortedMap( - sm.subMap(fromKey, toKey), mutex); + synchronized (mutex) { + return new SynchronizedSortedMap<>( + sm.subMap(fromKey, toKey), mutex); } } public SortedMap headMap(K toKey) { - synchronized(mutex) { - return new SynchronizedSortedMap(sm.headMap(toKey), mutex); + synchronized (mutex) { + return new SynchronizedSortedMap<>(sm.headMap(toKey), mutex); } } public SortedMap tailMap(K fromKey) { - synchronized(mutex) { - return new SynchronizedSortedMap(sm.tailMap(fromKey),mutex); + synchronized (mutex) { + return new SynchronizedSortedMap<>(sm.tailMap(fromKey),mutex); } } public K firstKey() { - synchronized(mutex) {return sm.firstKey();} + synchronized (mutex) {return sm.firstKey();} } public K lastKey() { - synchronized(mutex) {return sm.lastKey();} + synchronized (mutex) {return sm.lastKey();} + } + } + + /** + * Returns a synchronized (thread-safe) navigable map backed by the + * specified navigable map. In order to guarantee serial access, it is + * critical that all access to the backing navigable map is + * accomplished through the returned navigable map (or its views).

+ * + * It is imperative that the user manually synchronize on the returned + * navigable map when iterating over any of its collection views, or the + * collections views of any of its {@code subMap}, {@code headMap} or + * {@code tailMap} views. + *

+     *  NavigableMap m = Collections.synchronizedNavigableMap(new TreeMap());
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * 
+ * or: + *
+     *  NavigableMap m = Collections.synchronizedNavigableMap(new TreeMap());
+     *  NavigableMap m2 = m.subMap(foo, true, bar, false);
+     *      ...
+     *  Set s2 = m2.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not m2 or s2!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned navigable map will be serializable if the specified + * navigable map is serializable. + * + * @param the class of the map keys + * @param the class of the map values + * @param m the navigable map to be "wrapped" in a synchronized navigable + * map + * @return a synchronized view of the specified navigable map. + * @since 1.8 + */ + public static NavigableMap synchronizedNavigableMap(NavigableMap m) { + return new SynchronizedNavigableMap<>(m); + } + + /** + * A synchronized NavigableMap. + * + * @serial include + */ + static class SynchronizedNavigableMap + extends SynchronizedSortedMap + implements NavigableMap + { + private static final long serialVersionUID = 699392247599746807L; + + private final NavigableMap nm; + + SynchronizedNavigableMap(NavigableMap m) { + super(m); + nm = m; + } + SynchronizedNavigableMap(NavigableMap m, Object mutex) { + super(m, mutex); + nm = m; + } + + public Entry lowerEntry(K key) + { synchronized (mutex) { return nm.lowerEntry(key); } } + public K lowerKey(K key) + { synchronized (mutex) { return nm.lowerKey(key); } } + public Entry floorEntry(K key) + { synchronized (mutex) { return nm.floorEntry(key); } } + public K floorKey(K key) + { synchronized (mutex) { return nm.floorKey(key); } } + public Entry ceilingEntry(K key) + { synchronized (mutex) { return nm.ceilingEntry(key); } } + public K ceilingKey(K key) + { synchronized (mutex) { return nm.ceilingKey(key); } } + public Entry higherEntry(K key) + { synchronized (mutex) { return nm.higherEntry(key); } } + public K higherKey(K key) + { synchronized (mutex) { return nm.higherKey(key); } } + public Entry firstEntry() + { synchronized (mutex) { return nm.firstEntry(); } } + public Entry lastEntry() + { synchronized (mutex) { return nm.lastEntry(); } } + public Entry pollFirstEntry() + { synchronized (mutex) { return nm.pollFirstEntry(); } } + public Entry pollLastEntry() + { synchronized (mutex) { return nm.pollLastEntry(); } } + + public NavigableMap descendingMap() { + synchronized (mutex) { + return + new SynchronizedNavigableMap<>(nm.descendingMap(), mutex); + } + } + + public NavigableSet keySet() { + return navigableKeySet(); + } + + public NavigableSet navigableKeySet() { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(nm.navigableKeySet(), mutex); + } + } + + public NavigableSet descendingKeySet() { + synchronized (mutex) { + return new SynchronizedNavigableSet<>(nm.descendingKeySet(), mutex); + } + } + + + public SortedMap subMap(K fromKey, K toKey) { + synchronized (mutex) { + return new SynchronizedNavigableMap<>( + nm.subMap(fromKey, true, toKey, false), mutex); + } + } + public SortedMap headMap(K toKey) { + synchronized (mutex) { + return new SynchronizedNavigableMap<>(nm.headMap(toKey, false), mutex); + } + } + public SortedMap tailMap(K fromKey) { + synchronized (mutex) { + return new SynchronizedNavigableMap<>(nm.tailMap(fromKey, true),mutex); + } + } + + public NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { + synchronized (mutex) { + return new SynchronizedNavigableMap<>( + nm.subMap(fromKey, fromInclusive, toKey, toInclusive), mutex); + } + } + + public NavigableMap headMap(K toKey, boolean inclusive) { + synchronized (mutex) { + return new SynchronizedNavigableMap<>( + nm.headMap(toKey, inclusive), mutex); + } + } + + public NavigableMap tailMap(K fromKey, boolean inclusive) { + synchronized (mutex) { + return new SynchronizedNavigableMap<>( + nm.tailMap(fromKey, inclusive), mutex); + } } } // Dynamically typesafe collection wrappers /** - * Returns a dynamically typesafe view of the specified collection. Any - * attempt to insert an element of the wrong type will result in an - * immediate ClassCastException. Assuming a collection contains - * no incorrectly typed elements prior to the time a dynamically typesafe - * view is generated, and that all subsequent access to the collection - * takes place through the view, it is guaranteed that the - * collection cannot contain an incorrectly typed element. + * Returns a dynamically typesafe view of the specified collection. + * Any attempt to insert an element of the wrong type will result in an + * immediate {@link ClassCastException}. Assuming a collection + * contains no incorrectly typed elements prior to the time a + * dynamically typesafe view is generated, and that all subsequent + * access to the collection takes place through the view, it is + * guaranteed that the collection cannot contain an incorrectly + * typed element. * *

The generics mechanism in the language provides compile-time * (static) type checking, but it is possible to defeat this mechanism @@ -2170,7 +2973,7 @@ public K lastKey() { * inserting an element of the wrong type. * *

Another use of dynamically typesafe views is debugging. Suppose a - * program fails with a ClassCastException, indicating that an + * program fails with a {@code ClassCastException}, indicating that an * incorrectly typed element was put into a parameterized collection. * Unfortunately, the exception can occur at any time after the erroneous * element is inserted, so it typically provides little or no information @@ -2178,14 +2981,14 @@ public K lastKey() { * one can quickly determine its source by temporarily modifying the * program to wrap the collection with a dynamically typesafe view. * For example, this declaration: - *

-     *     Collection<String> c = new HashSet<String>();
-     * 
+ *
 {@code
+     *     Collection c = new HashSet<>();
+     * }
* may be replaced temporarily by this one: - *
-     *     Collection<String> c = Collections.checkedCollection(
-     *         new HashSet<String>(), String.class);
-     * 
+ *
 {@code
+     *     Collection c = Collections.checkedCollection(
+     *         new HashSet<>(), String.class);
+     * }
* Running the program again will cause it to fail at the point where * an incorrectly typed element is inserted into the collection, clearly * identifying the source of the problem. Once the problem is fixed, the @@ -2193,55 +2996,69 @@ public K lastKey() { * *

The returned collection does not pass the hashCode and equals * operations through to the backing collection, but relies on - * Object's equals and hashCode methods. This + * {@code Object}'s {@code equals} and {@code hashCode} methods. This * is necessary to preserve the contracts of these operations in the case * that the backing collection is a set or a list. * *

The returned collection will be serializable if the specified * collection is serializable. * + *

Since {@code null} is considered to be a value of any reference + * type, the returned collection permits insertion of null elements + * whenever the backing collection does. + * + * @param the class of the objects in the collection * @param c the collection for which a dynamically typesafe view is to be - * returned - * @param type the type of element that c is permitted to hold + * returned + * @param type the type of element that {@code c} is permitted to hold * @return a dynamically typesafe view of the specified collection * @since 1.5 */ public static Collection checkedCollection(Collection c, Class type) { - return new CheckedCollection(c, type); + return new CheckedCollection<>(c, type); + } + + @SuppressWarnings("unchecked") + static T[] zeroLengthArray(Class type) { + return (T[]) Array.newInstance(type, 0); } - + /** * @serial include */ - static class CheckedCollection implements Collection { + static class CheckedCollection implements Collection, Serializable { private static final long serialVersionUID = 1578914078182001775L; final Collection c; final Class type; - void typeCheck(Object o) { - if (!type.isInstance(o)) - throw new ClassCastException("Attempt to insert " + - o.getClass() + " element into collection with element type " - + type); + @SuppressWarnings("unchecked") + E typeCheck(Object o) { + if (o != null && !type.isInstance(o)) + throw new ClassCastException(badElementMsg(o)); + return (E) o; + } + + private String badElementMsg(Object o) { + return "Attempt to insert " + o.getClass() + + " element into collection with element type " + type; } CheckedCollection(Collection c, Class type) { - if (c==null || type == null) - throw new NullPointerException(); - this.c = c; - this.type = type; + this.c = Objects.requireNonNull(c, "c"); + this.type = Objects.requireNonNull(type, "type"); } - public int size() { return c.size(); } - public boolean isEmpty() { return c.isEmpty(); } - public boolean contains(Object o) { return c.contains(o); } - public Object[] toArray() { return c.toArray(); } - public T[] toArray(T[] a) { return c.toArray(a); } - public String toString() { return c.toString(); } - public Iterator iterator() { return c.iterator(); } - public boolean remove(Object o) { return c.remove(o); } + public int size() { return c.size(); } + public boolean isEmpty() { return c.isEmpty(); } + public boolean contains(Object o) { return c.contains(o); } + public Object[] toArray() { return c.toArray(); } + public T[] toArray(T[] a) { return c.toArray(a); } + public String toString() { return c.toString(); } + public boolean remove(Object o) { return c.remove(o); } + public void clear() { c.clear(); } + public boolean containsAll(Collection coll) { return c.containsAll(coll); } @@ -2251,123 +3068,213 @@ public boolean removeAll(Collection coll) { public boolean retainAll(Collection coll) { return c.retainAll(coll); } - public void clear() { - c.clear(); + + public Iterator iterator() { + // JDK-6363904 - unwrapped iterator could be typecast to + // ListIterator with unsafe set() + final Iterator it = c.iterator(); + return new Iterator() { + public boolean hasNext() { return it.hasNext(); } + public E next() { return it.next(); } + public void remove() { it.remove(); }}; } - public boolean add(E o){ - typeCheck(o); - return c.add(o); + public boolean add(E e) { return c.add(typeCheck(e)); } + + private E[] zeroLengthElementArray; // Lazily initialized + + private E[] zeroLengthElementArray() { + return zeroLengthElementArray != null ? zeroLengthElementArray : + (zeroLengthElementArray = zeroLengthArray(type)); } - public boolean addAll(Collection coll) { - /* - * Dump coll into an array of the required type. This serves - * three purposes: it insulates us from concurrent changes in - * the contents of coll, it type-checks all of the elements in - * coll, and it provides all-or-nothing semantics(which we - * wouldn't get if we type-checked each element as we added it). - */ - E[] a = null; + @SuppressWarnings("unchecked") + Collection checkedCopyOf(Collection coll) { + Object[] a; try { - a = coll.toArray(zeroLengthElementArray()); - } catch(ArrayStoreException e) { - throw new ClassCastException(); + E[] z = zeroLengthElementArray(); + a = coll.toArray(z); + // Defend against coll violating the toArray contract + if (a.getClass() != z.getClass()) + a = Arrays.copyOf(a, a.length, z.getClass()); + } catch (ArrayStoreException ignore) { + // To get better and consistent diagnostics, + // we call typeCheck explicitly on each element. + // We call clone() to defend against coll retaining a + // reference to the returned array and storing a bad + // element into it after it has been type checked. + a = coll.toArray().clone(); + for (Object o : a) + typeCheck(o); } - - boolean result = false; - for (E e : a) - result |= c.add(e); - return result; + // A slight abuse of the type system, but safe here. + return (Collection) Arrays.asList(a); } - private E[] zeroLengthElementArray = null; // Lazily initialized + public boolean addAll(Collection coll) { + // Doing things this way insulates us from concurrent changes + // in the contents of coll and provides all-or-nothing + // semantics (which we wouldn't get if we type-checked each + // element as we added it) + return c.addAll(checkedCopyOf(coll)); + } + + // Override default methods in Collection + @Override + public void forEach(Consumer action) {c.forEach(action);} + @Override + public boolean removeIf(Predicate filter) { + return c.removeIf(filter); + } + @Override + public Spliterator spliterator() {return c.spliterator();} +// @Override +// public Stream stream() {return c.stream();} +// @Override +// public Stream parallelStream() {return c.parallelStream();} + } - /* - * We don't need locking or volatile, because it's OK if we create - * several zeroLengthElementArrays, and they're immutable. - */ - E[] zeroLengthElementArray() { - if (zeroLengthElementArray == null) - zeroLengthElementArray = (E[]) Array.newInstance(type, 0); - return zeroLengthElementArray; + /** + * Returns a dynamically typesafe view of the specified queue. + * Any attempt to insert an element of the wrong type will result in + * an immediate {@link ClassCastException}. Assuming a queue contains + * no incorrectly typed elements prior to the time a dynamically typesafe + * view is generated, and that all subsequent access to the queue + * takes place through the view, it is guaranteed that the + * queue cannot contain an incorrectly typed element. + * + *

A discussion of the use of dynamically typesafe views may be + * found in the documentation for the {@link #checkedCollection + * checkedCollection} method. + * + *

The returned queue will be serializable if the specified queue + * is serializable. + * + *

Since {@code null} is considered to be a value of any reference + * type, the returned queue permits insertion of {@code null} elements + * whenever the backing queue does. + * + * @param the class of the objects in the queue + * @param queue the queue for which a dynamically typesafe view is to be + * returned + * @param type the type of element that {@code queue} is permitted to hold + * @return a dynamically typesafe view of the specified queue + * @since 1.8 + */ + public static Queue checkedQueue(Queue queue, Class type) { + return new CheckedQueue<>(queue, type); + } + + /** + * @serial include + */ + static class CheckedQueue + extends CheckedCollection + implements Queue, Serializable + { + private static final long serialVersionUID = 1433151992604707767L; + final Queue queue; + + CheckedQueue(Queue queue, Class elementType) { + super(queue, elementType); + this.queue = queue; } + + public E element() {return queue.element();} + public boolean equals(Object o) {return o == this || c.equals(o);} + public int hashCode() {return c.hashCode();} + public E peek() {return queue.peek();} + public E poll() {return queue.poll();} + public E remove() {return queue.remove();} + public boolean offer(E e) {return queue.offer(typeCheck(e));} } /** * Returns a dynamically typesafe view of the specified set. * Any attempt to insert an element of the wrong type will result in - * an immediate ClassCastException. Assuming a set contains + * an immediate {@link ClassCastException}. Assuming a set contains * no incorrectly typed elements prior to the time a dynamically typesafe * view is generated, and that all subsequent access to the set * takes place through the view, it is guaranteed that the * set cannot contain an incorrectly typed element. * *

A discussion of the use of dynamically typesafe views may be - * found in the documentation for the {@link #checkedCollection checkedCollection} - * method. + * found in the documentation for the {@link #checkedCollection + * checkedCollection} method. * *

The returned set will be serializable if the specified set is * serializable. * + *

Since {@code null} is considered to be a value of any reference + * type, the returned set permits insertion of null elements whenever + * the backing set does. + * + * @param the class of the objects in the set * @param s the set for which a dynamically typesafe view is to be - * returned - * @param type the type of element that s is permitted to hold + * returned + * @param type the type of element that {@code s} is permitted to hold * @return a dynamically typesafe view of the specified set * @since 1.5 */ public static Set checkedSet(Set s, Class type) { - return new CheckedSet(s, type); + return new CheckedSet<>(s, type); } - + /** * @serial include */ static class CheckedSet extends CheckedCollection - implements Set + implements Set, Serializable { private static final long serialVersionUID = 4694047833775013803L; CheckedSet(Set s, Class elementType) { super(s, elementType); } - public boolean equals(Object o) { return c.equals(o); } + public boolean equals(Object o) { return o == this || c.equals(o); } public int hashCode() { return c.hashCode(); } } /** - * Returns a dynamically typesafe view of the specified sorted set. Any - * attempt to insert an element of the wrong type will result in an - * immediate ClassCastException. Assuming a sorted set contains - * no incorrectly typed elements prior to the time a dynamically typesafe - * view is generated, and that all subsequent access to the sorted set - * takes place through the view, it is guaranteed that the sorted - * set cannot contain an incorrectly typed element. + * Returns a dynamically typesafe view of the specified sorted set. + * Any attempt to insert an element of the wrong type will result in an + * immediate {@link ClassCastException}. Assuming a sorted set + * contains no incorrectly typed elements prior to the time a + * dynamically typesafe view is generated, and that all subsequent + * access to the sorted set takes place through the view, it is + * guaranteed that the sorted set cannot contain an incorrectly + * typed element. * *

A discussion of the use of dynamically typesafe views may be - * found in the documentation for the {@link #checkedCollection checkedCollection} - * method. + * found in the documentation for the {@link #checkedCollection + * checkedCollection} method. * *

The returned sorted set will be serializable if the specified sorted * set is serializable. * + *

Since {@code null} is considered to be a value of any reference + * type, the returned sorted set permits insertion of null elements + * whenever the backing sorted set does. + * + * @param the class of the objects in the set * @param s the sorted set for which a dynamically typesafe view is to be - * returned - * @param type the type of element that s is permitted to hold + * returned + * @param type the type of element that {@code s} is permitted to hold * @return a dynamically typesafe view of the specified sorted set * @since 1.5 */ public static SortedSet checkedSortedSet(SortedSet s, Class type) { - return new CheckedSortedSet(s, type); + return new CheckedSortedSet<>(s, type); } /** * @serial include */ static class CheckedSortedSet extends CheckedSet - implements SortedSet + implements SortedSet, Serializable { private static final long serialVersionUID = 1599911165492914959L; + private final SortedSet ss; CheckedSortedSet(SortedSet s, Class type) { @@ -2380,115 +3287,214 @@ static class CheckedSortedSet extends CheckedSet public E last() { return ss.last(); } public SortedSet subSet(E fromElement, E toElement) { - return new CheckedSortedSet(ss.subSet(fromElement,toElement), - type); + return checkedSortedSet(ss.subSet(fromElement,toElement), type); } public SortedSet headSet(E toElement) { - return new CheckedSortedSet(ss.headSet(toElement), type); + return checkedSortedSet(ss.headSet(toElement), type); } public SortedSet tailSet(E fromElement) { - return new CheckedSortedSet(ss.tailSet(fromElement), type); + return checkedSortedSet(ss.tailSet(fromElement), type); } } /** - * Returns a dynamically typesafe view of the specified list. - * Any attempt to insert an element of the wrong type will result in - * an immediate ClassCastException. Assuming a list contains - * no incorrectly typed elements prior to the time a dynamically typesafe - * view is generated, and that all subsequent access to the list - * takes place through the view, it is guaranteed that the - * list cannot contain an incorrectly typed element. + * Returns a dynamically typesafe view of the specified navigable set. + * Any attempt to insert an element of the wrong type will result in an + * immediate {@link ClassCastException}. Assuming a navigable set + * contains no incorrectly typed elements prior to the time a + * dynamically typesafe view is generated, and that all subsequent + * access to the navigable set takes place through the view, it is + * guaranteed that the navigable set cannot contain an incorrectly + * typed element. * *

A discussion of the use of dynamically typesafe views may be - * found in the documentation for the {@link #checkedCollection checkedCollection} - * method. + * found in the documentation for the {@link #checkedCollection + * checkedCollection} method. * - *

The returned list will be serializable if the specified list is - * serializable. + *

The returned navigable set will be serializable if the specified + * navigable set is serializable. * - * @param list the list for which a dynamically typesafe view is to be - * returned - * @param type the type of element that list is permitted to hold - * @return a dynamically typesafe view of the specified list - * @since 1.5 + *

Since {@code null} is considered to be a value of any reference + * type, the returned navigable set permits insertion of null elements + * whenever the backing sorted set does. + * + * @param the class of the objects in the set + * @param s the navigable set for which a dynamically typesafe view is to be + * returned + * @param type the type of element that {@code s} is permitted to hold + * @return a dynamically typesafe view of the specified navigable set + * @since 1.8 */ - public static List checkedList(List list, Class type) { - return (list instanceof RandomAccess ? - new CheckedRandomAccessList(list, type) : - new CheckedList(list, type)); + public static NavigableSet checkedNavigableSet(NavigableSet s, + Class type) { + return new CheckedNavigableSet<>(s, type); } /** * @serial include */ - static class CheckedList extends CheckedCollection - implements List + static class CheckedNavigableSet extends CheckedSortedSet + implements NavigableSet, Serializable { - static final long serialVersionUID = 65247728283967356L; - final List list; + private static final long serialVersionUID = -5429120189805438922L; - CheckedList(List list, Class type) { - super(list, type); - this.list = list; + private final NavigableSet ns; + + CheckedNavigableSet(NavigableSet s, Class type) { + super(s, type); + ns = s; } - public boolean equals(Object o) { return list.equals(o); } - public int hashCode() { return list.hashCode(); } - public E get(int index) { return list.get(index); } - public E remove(int index) { return list.remove(index); } - public int indexOf(Object o) { return list.indexOf(o); } - public int lastIndexOf(Object o) { return list.lastIndexOf(o); } + public E lower(E e) { return ns.lower(e); } + public E floor(E e) { return ns.floor(e); } + public E ceiling(E e) { return ns.ceiling(e); } + public E higher(E e) { return ns.higher(e); } + public E pollFirst() { return ns.pollFirst(); } + public E pollLast() {return ns.pollLast(); } + public NavigableSet descendingSet() + { return checkedNavigableSet(ns.descendingSet(), type); } + public Iterator descendingIterator() + {return checkedNavigableSet(ns.descendingSet(), type).iterator(); } + + public NavigableSet subSet(E fromElement, E toElement) { + return checkedNavigableSet(ns.subSet(fromElement, true, toElement, false), type); + } + public NavigableSet headSet(E toElement) { + return checkedNavigableSet(ns.headSet(toElement, false), type); + } + public NavigableSet tailSet(E fromElement) { + return checkedNavigableSet(ns.tailSet(fromElement, true), type); + } + + public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { + return checkedNavigableSet(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), type); + } + + public NavigableSet headSet(E toElement, boolean inclusive) { + return checkedNavigableSet(ns.headSet(toElement, inclusive), type); + } + + public NavigableSet tailSet(E fromElement, boolean inclusive) { + return checkedNavigableSet(ns.tailSet(fromElement, inclusive), type); + } + } + + /** + * Returns a dynamically typesafe view of the specified list. + * Any attempt to insert an element of the wrong type will result in + * an immediate {@link ClassCastException}. Assuming a list contains + * no incorrectly typed elements prior to the time a dynamically typesafe + * view is generated, and that all subsequent access to the list + * takes place through the view, it is guaranteed that the + * list cannot contain an incorrectly typed element. + * + *

A discussion of the use of dynamically typesafe views may be + * found in the documentation for the {@link #checkedCollection + * checkedCollection} method. + * + *

The returned list will be serializable if the specified list + * is serializable. + * + *

Since {@code null} is considered to be a value of any reference + * type, the returned list permits insertion of null elements whenever + * the backing list does. + * + * @param the class of the objects in the list + * @param list the list for which a dynamically typesafe view is to be + * returned + * @param type the type of element that {@code list} is permitted to hold + * @return a dynamically typesafe view of the specified list + * @since 1.5 + */ + public static List checkedList(List list, Class type) { + return (list instanceof RandomAccess ? + new CheckedRandomAccessList<>(list, type) : + new CheckedList<>(list, type)); + } + + /** + * @serial include + */ + static class CheckedList + extends CheckedCollection + implements List + { + private static final long serialVersionUID = 65247728283967356L; + final List list; + + CheckedList(List list, Class type) { + super(list, type); + this.list = list; + } + + public boolean equals(Object o) { return o == this || list.equals(o); } + public int hashCode() { return list.hashCode(); } + public E get(int index) { return list.get(index); } + public E remove(int index) { return list.remove(index); } + public int indexOf(Object o) { return list.indexOf(o); } + public int lastIndexOf(Object o) { return list.lastIndexOf(o); } public E set(int index, E element) { - typeCheck(element); - return list.set(index, element); + return list.set(index, typeCheck(element)); } public void add(int index, E element) { - typeCheck(element); - list.add(index, element); + list.add(index, typeCheck(element)); } public boolean addAll(int index, Collection c) { - // See CheckCollection.addAll, above, for an explanation - E[] a = null; - try { - a = c.toArray(zeroLengthElementArray()); - } catch(ArrayStoreException e) { - throw new ClassCastException(); - } - - return list.addAll(index, Arrays.asList(a)); + return list.addAll(index, checkedCopyOf(c)); } public ListIterator listIterator() { return listIterator(0); } public ListIterator listIterator(final int index) { - return new ListIterator() { - ListIterator i = list.listIterator(index); + final ListIterator i = list.listIterator(index); + return new ListIterator() { public boolean hasNext() { return i.hasNext(); } public E next() { return i.next(); } public boolean hasPrevious() { return i.hasPrevious(); } public E previous() { return i.previous(); } public int nextIndex() { return i.nextIndex(); } public int previousIndex() { return i.previousIndex(); } - public void remove() { i.remove(); } + public void remove() { i.remove(); } - public void set(E o) { - typeCheck(o); - i.set(o); + public void set(E e) { + i.set(typeCheck(e)); } - public void add(E o) { - typeCheck(o); - i.add(o); + public void add(E e) { + i.add(typeCheck(e)); + } + + @Override + public void forEachRemaining(Consumer action) { + i.forEachRemaining(action); } }; } public List subList(int fromIndex, int toIndex) { - return new CheckedList(list.subList(fromIndex, toIndex), type); + return new CheckedList<>(list.subList(fromIndex, toIndex), type); + } + + /** + * {@inheritDoc} + * + * @throws ClassCastException if the class of an element returned by the + * operator prevents it from being added to this collection. The + * exception may be thrown after some elements of the list have + * already been replaced. + */ + @Override + public void replaceAll(UnaryOperator operator) { + Objects.requireNonNull(operator); + list.replaceAll(e -> typeCheck(operator.apply(e))); + } + + @Override + public void sort(Comparator c) { + list.sort(c); } } @@ -2496,7 +3502,7 @@ public List subList(int fromIndex, int toIndex) { * @serial include */ static class CheckedRandomAccessList extends CheckedList - implements RandomAccess + implements RandomAccess { private static final long serialVersionUID = 1638200125423088369L; @@ -2505,20 +3511,20 @@ static class CheckedRandomAccessList extends CheckedList } public List subList(int fromIndex, int toIndex) { - return new CheckedRandomAccessList( - list.subList(fromIndex, toIndex), type); + return new CheckedRandomAccessList<>( + list.subList(fromIndex, toIndex), type); } } /** - * Returns a dynamically typesafe view of the specified map. Any attempt - * to insert a mapping whose key or value have the wrong type will result - * in an immediate ClassCastException. Similarly, any attempt to - * modify the value currently associated with a key will result in an - * immediate ClassCastException, whether the modification is - * attempted directly through the map itself, or through a {@link - * Map.Entry} instance obtained from the map's {@link Map#entrySet() - * entry set} view. + * Returns a dynamically typesafe view of the specified map. + * Any attempt to insert a mapping whose key or value have the wrong + * type will result in an immediate {@link ClassCastException}. + * Similarly, any attempt to modify the value currently associated with + * a key will result in an immediate {@link ClassCastException}, + * whether the modification is attempted directly through the map + * itself, or through a {@link Map.Entry} instance obtained from the + * map's {@link Map#entrySet() entry set} view. * *

Assuming a map contains no incorrectly typed keys or values * prior to the time a dynamically typesafe view is generated, and @@ -2527,29 +3533,37 @@ public List subList(int fromIndex, int toIndex) { * map cannot contain an incorrectly typed key or value. * *

A discussion of the use of dynamically typesafe views may be - * found in the documentation for the {@link #checkedCollection checkedCollection} - * method. + * found in the documentation for the {@link #checkedCollection + * checkedCollection} method. * *

The returned map will be serializable if the specified map is * serializable. * + *

Since {@code null} is considered to be a value of any reference + * type, the returned map permits insertion of null keys or values + * whenever the backing map does. + * + * @param the class of the map keys + * @param the class of the map values * @param m the map for which a dynamically typesafe view is to be - * returned - * @param keyType the type of key that m is permitted to hold - * @param valueType the type of value that m is permitted to hold + * returned + * @param keyType the type of key that {@code m} is permitted to hold + * @param valueType the type of value that {@code m} is permitted to hold * @return a dynamically typesafe view of the specified map * @since 1.5 */ - public static Map checkedMap(Map m, Class keyType, + public static Map checkedMap(Map m, + Class keyType, Class valueType) { - return new CheckedMap(m, keyType, valueType); + return new CheckedMap<>(m, keyType, valueType); } /** * @serial include */ - private static class CheckedMap implements Map + private static class CheckedMap + implements Map, Serializable { private static final long serialVersionUID = 5742860141034234728L; @@ -2558,23 +3572,37 @@ private static class CheckedMap implements Map final Class valueType; private void typeCheck(Object key, Object value) { - if (!keyType.isInstance(key)) - throw new ClassCastException("Attempt to insert " + - key.getClass() + " key into collection with key type " - + keyType); + if (key != null && !keyType.isInstance(key)) + throw new ClassCastException(badKeyMsg(key)); + + if (value != null && !valueType.isInstance(value)) + throw new ClassCastException(badValueMsg(value)); + } + + private BiFunction typeCheck( + BiFunction func) { + Objects.requireNonNull(func); + return (k, v) -> { + V newValue = func.apply(k, v); + typeCheck(k, newValue); + return newValue; + }; + } - if (!valueType.isInstance(value)) - throw new ClassCastException("Attempt to insert " + - value.getClass() +" value into collection with value type " - + valueType); + private String badKeyMsg(Object key) { + return "Attempt to insert " + key.getClass() + + " key into map with key type " + keyType; + } + + private String badValueMsg(Object value) { + return "Attempt to insert " + value.getClass() + + " value into map with value type " + valueType; } CheckedMap(Map m, Class keyType, Class valueType) { - if (m == null || keyType == null || valueType == null) - throw new NullPointerException(); - this.m = m; - this.keyType = keyType; - this.valueType = valueType; + this.m = Objects.requireNonNull(m); + this.keyType = Objects.requireNonNull(keyType); + this.valueType = Objects.requireNonNull(valueType); } public int size() { return m.size(); } @@ -2586,7 +3614,7 @@ private void typeCheck(Object key, Object value) { public void clear() { m.clear(); } public Set keySet() { return m.keySet(); } public Collection values() { return m.values(); } - public boolean equals(Object o) { return m.equals(o); } + public boolean equals(Object o) { return o == this || m.equals(o); } public int hashCode() { return m.hashCode(); } public String toString() { return m.toString(); } @@ -2595,53 +3623,101 @@ public V put(K key, V value) { return m.put(key, value); } + @SuppressWarnings("unchecked") public void putAll(Map t) { - // See CheckCollection.addAll, above, for an explanation - K[] keys = null; - try { - keys = t.keySet().toArray(zeroLengthKeyArray()); - } catch(ArrayStoreException e) { - throw new ClassCastException(); - } - V[] values = null; - try { - values = t.values().toArray(zeroLengthValueArray()); - } catch(ArrayStoreException e) { - throw new ClassCastException(); + // Satisfy the following goals: + // - good diagnostics in case of type mismatch + // - all-or-nothing semantics + // - protection from malicious t + // - correct behavior if t is a concurrent map + Object[] entries = t.entrySet().toArray(); + List> checked = new ArrayList<>(entries.length); + for (Object o : entries) { + Map.Entry e = (Map.Entry) o; + Object k = e.getKey(); + Object v = e.getValue(); + typeCheck(k, v); + checked.add( + new AbstractMap.SimpleImmutableEntry<>((K)k, (V)v)); } + for (Map.Entry e : checked) + m.put(e.getKey(), e.getValue()); + } - if (keys.length != values.length) - throw new ConcurrentModificationException(); + private transient Set> entrySet; - for (int i = 0; i < keys.length; i++) - m.put(keys[i], values[i]); + public Set> entrySet() { + if (entrySet==null) + entrySet = new CheckedEntrySet<>(m.entrySet(), valueType); + return entrySet; + } + + // Override default methods in Map + @Override + public void forEach(BiConsumer action) { + m.forEach(action); } - // Lazily initialized - private K[] zeroLengthKeyArray = null; - private V[] zeroLengthValueArray = null; + @Override + public void replaceAll(BiFunction function) { + m.replaceAll(typeCheck(function)); + } - /* - * We don't need locking or volatile, because it's OK if we create - * several zeroLengthValueArrays, and they're immutable. - */ - private K[] zeroLengthKeyArray() { - if (zeroLengthKeyArray == null) - zeroLengthKeyArray = (K[])Array.newInstance(keyType, 0); - return zeroLengthKeyArray; + @Override + public V putIfAbsent(K key, V value) { + typeCheck(key, value); + return m.putIfAbsent(key, value); } - private V[] zeroLengthValueArray() { - if (zeroLengthValueArray == null) - zeroLengthValueArray = (V[]) Array.newInstance(valueType, 0); - return zeroLengthValueArray; + + @Override + public boolean remove(Object key, Object value) { + return m.remove(key, value); } - private transient Set> entrySet = null; + @Override + public boolean replace(K key, V oldValue, V newValue) { + typeCheck(key, newValue); + return m.replace(key, oldValue, newValue); + } - public Set> entrySet() { - if (entrySet==null) - entrySet = new CheckedEntrySet(m.entrySet(), valueType); - return entrySet; + @Override + public V replace(K key, V value) { + typeCheck(key, value); + return m.replace(key, value); + } + + @Override + public V computeIfAbsent(K key, + Function mappingFunction) { + Objects.requireNonNull(mappingFunction); + return m.computeIfAbsent(key, k -> { + V value = mappingFunction.apply(k); + typeCheck(k, value); + return value; + }); + } + + @Override + public V computeIfPresent(K key, + BiFunction remappingFunction) { + return m.computeIfPresent(key, typeCheck(remappingFunction)); + } + + @Override + public V compute(K key, + BiFunction remappingFunction) { + return m.compute(key, typeCheck(remappingFunction)); + } + + @Override + public V merge(K key, V value, + BiFunction remappingFunction) { + Objects.requireNonNull(remappingFunction); + return m.merge(key, value, (v1, v2) -> { + V newValue = remappingFunction.apply(v1, v2); + typeCheck(null, newValue); + return newValue; + }); } /** @@ -2653,50 +3729,42 @@ public Set> entrySet() { * @serial exclude */ static class CheckedEntrySet implements Set> { - Set> s; - Class valueType; + private final Set> s; + private final Class valueType; CheckedEntrySet(Set> s, Class valueType) { this.s = s; this.valueType = valueType; } - public int size() { return s.size(); } - public boolean isEmpty() { return s.isEmpty(); } - public String toString() { return s.toString(); } - public int hashCode() { return s.hashCode(); } - public boolean remove(Object o) { return s.remove(o); } - public boolean removeAll(Collection coll) { - return s.removeAll(coll); - } - public boolean retainAll(Collection coll) { - return s.retainAll(coll); - } - public void clear() { - s.clear(); - } + public int size() { return s.size(); } + public boolean isEmpty() { return s.isEmpty(); } + public String toString() { return s.toString(); } + public int hashCode() { return s.hashCode(); } + public void clear() { s.clear(); } - public boolean add(Map.Entry o){ + public boolean add(Map.Entry e) { throw new UnsupportedOperationException(); } public boolean addAll(Collection> coll) { throw new UnsupportedOperationException(); } - public Iterator> iterator() { - return new Iterator>() { - Iterator> i = s.iterator(); + final Iterator> i = s.iterator(); + final Class valueType = this.valueType; + return new Iterator>() { public boolean hasNext() { return i.hasNext(); } public void remove() { i.remove(); } public Map.Entry next() { - return new CheckedEntry(i.next(), valueType); + return checkedEntry(i.next(), valueType); } }; } + @SuppressWarnings("unchecked") public Object[] toArray() { Object[] source = s.toArray(); @@ -2705,28 +3773,27 @@ public Object[] toArray() { * s.toArray returns an array of something other than Object */ Object[] dest = (CheckedEntry.class.isInstance( - source.getClass().getComponentType()) ? source : - new Object[source.length]); + source.getClass().getComponentType()) ? source : + new Object[source.length]); for (int i = 0; i < source.length; i++) - dest[i] = new CheckedEntry((Map.Entry)source[i], - valueType); + dest[i] = checkedEntry((Map.Entry)source[i], + valueType); return dest; } + @SuppressWarnings("unchecked") public T[] toArray(T[] a) { // We don't pass a to s.toArray, to avoid window of // vulnerability wherein an unscrupulous multithreaded client // could get his hands on raw (unwrapped) Entries from s. - Object[] arr = s.toArray(a.length==0 ? a : - (T[])Array.newInstance(a.getClass().getComponentType(), 0) - ); + T[] arr = s.toArray(a.length==0 ? a : Arrays.copyOf(a, 0)); for (int i=0; i((Map.Entry)arr[i], - valueType); + arr[i] = (T) checkedEntry((Map.Entry)arr[i], + valueType); if (arr.length > a.length) - return (T[])arr; + return arr; System.arraycopy(arr, 0, a, 0, arr.length); if (a.length > arr.length) @@ -2743,32 +3810,62 @@ public T[] toArray(T[] a) { public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry) o; return s.contains( - new CheckedEntry((Map.Entry) o, valueType)); + (e instanceof CheckedEntry) ? e : checkedEntry(e, valueType)); } /** - * The next two methods are overridden to protect against - * an unscrupulous collection whose contains(Object o) method - * senses when o is a Map.Entry, and calls o.setValue. + * The bulk collection methods are overridden to protect + * against an unscrupulous collection whose contains(Object o) + * method senses when o is a Map.Entry, and calls o.setValue. */ - public boolean containsAll(Collection coll) { - Iterator e = coll.iterator(); - while (e.hasNext()) - if (!contains(e.next())) // Invokes safe contains() above + public boolean containsAll(Collection c) { + for (Object o : c) + if (!contains(o)) // Invokes safe contains() above return false; return true; } + public boolean remove(Object o) { + if (!(o instanceof Map.Entry)) + return false; + return s.remove(new AbstractMap.SimpleImmutableEntry + <>((Map.Entry)o)); + } + + public boolean removeAll(Collection c) { + return batchRemove(c, false); + } + public boolean retainAll(Collection c) { + return batchRemove(c, true); + } + private boolean batchRemove(Collection c, boolean complement) { + Objects.requireNonNull(c); + boolean modified = false; + Iterator> it = iterator(); + while (it.hasNext()) { + if (c.contains(it.next()) != complement) { + it.remove(); + modified = true; + } + } + return modified; + } + public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Set)) return false; Set that = (Set) o; - if (that.size() != s.size()) - return false; - return containsAll(that); // Invokes safe containsAll() above + return that.size() == s.size() + && containsAll(that); // Invokes safe containsAll() above + } + + static CheckedEntry checkedEntry(Map.Entry e, + Class valueType) { + return new CheckedEntry<>(e, valueType); } /** @@ -2776,15 +3873,15 @@ public boolean equals(Object o) { * the client from modifying the backing Map, by short-circuiting * the setValue method, and it protects the backing Map against * an ill-behaved Map.Entry that attempts to modify another - * Map Entry when asked to perform an equality check. + * Map.Entry when asked to perform an equality check. */ - private static class CheckedEntry implements Map.Entry { - private Map.Entry e; - private Class valueType; + private static class CheckedEntry implements Map.Entry { + private final Map.Entry e; + private final Class valueType; - CheckedEntry(Map.Entry e, Class valueType) { - this.e = e; - this.valueType = valueType; + CheckedEntry(Map.Entry e, Class valueType) { + this.e = Objects.requireNonNull(e); + this.valueType = Objects.requireNonNull(valueType); } public K getKey() { return e.getKey(); } @@ -2792,35 +3889,38 @@ private static class CheckedEntry implements Map.Entry { public int hashCode() { return e.hashCode(); } public String toString() { return e.toString(); } - public V setValue(V value) { - if (!valueType.isInstance(value)) - throw new ClassCastException("Attempt to insert " + - value.getClass() + - " value into collection with value type " + valueType); + if (value != null && !valueType.isInstance(value)) + throw new ClassCastException(badValueMsg(value)); return e.setValue(value); } + private String badValueMsg(Object value) { + return "Attempt to insert " + value.getClass() + + " value into map with value type " + valueType; + } + public boolean equals(Object o) { + if (o == this) + return true; if (!(o instanceof Map.Entry)) return false; - Map.Entry t = (Map.Entry)o; - return eq(e.getKey(), t.getKey()) && - eq(e.getValue(), t.getValue()); + return e.equals(new AbstractMap.SimpleImmutableEntry + <>((Map.Entry)o)); } } } } /** - * Returns a dynamically typesafe view of the specified sorted map. Any - * attempt to insert a mapping whose key or value have the wrong type will - * result in an immediate ClassCastException. Similarly, any - * attempt to modify the value currently associated with a key will result - * in an immediate ClassCastException, whether the modification - * is attempted directly through the map itself, or through a {@link - * Map.Entry} instance obtained from the map's {@link Map#entrySet() entry - * set} view. + * Returns a dynamically typesafe view of the specified sorted map. + * Any attempt to insert a mapping whose key or value have the wrong + * type will result in an immediate {@link ClassCastException}. + * Similarly, any attempt to modify the value currently associated with + * a key will result in an immediate {@link ClassCastException}, + * whether the modification is attempted directly through the map + * itself, or through a {@link Map.Entry} instance obtained from the + * map's {@link Map#entrySet() entry set} view. * *

Assuming a map contains no incorrectly typed keys or values * prior to the time a dynamically typesafe view is generated, and @@ -2829,34 +3929,40 @@ public boolean equals(Object o) { * map cannot contain an incorrectly typed key or value. * *

A discussion of the use of dynamically typesafe views may be - * found in the documentation for the {@link #checkedCollection checkedCollection} - * method. + * found in the documentation for the {@link #checkedCollection + * checkedCollection} method. * *

The returned map will be serializable if the specified map is * serializable. * + *

Since {@code null} is considered to be a value of any reference + * type, the returned map permits insertion of null keys or values + * whenever the backing map does. + * + * @param the class of the map keys + * @param the class of the map values * @param m the map for which a dynamically typesafe view is to be - * returned - * @param keyType the type of key that m is permitted to hold - * @param valueType the type of value that m is permitted to hold + * returned + * @param keyType the type of key that {@code m} is permitted to hold + * @param valueType the type of value that {@code m} is permitted to hold * @return a dynamically typesafe view of the specified map * @since 1.5 */ public static SortedMap checkedSortedMap(SortedMap m, Class keyType, Class valueType) { - return new CheckedSortedMap(m, keyType, valueType); + return new CheckedSortedMap<>(m, keyType, valueType); } /** * @serial include */ static class CheckedSortedMap extends CheckedMap - implements SortedMap + implements SortedMap, Serializable { private static final long serialVersionUID = 1599671320688067438L; - private SortedMap sm; + private final SortedMap sm; CheckedSortedMap(SortedMap m, Class keyType, Class valueType) { @@ -2869,277 +3975,877 @@ static class CheckedSortedMap extends CheckedMap public K lastKey() { return sm.lastKey(); } public SortedMap subMap(K fromKey, K toKey) { - return new CheckedSortedMap(sm.subMap(fromKey, toKey), - keyType, valueType); + return checkedSortedMap(sm.subMap(fromKey, toKey), + keyType, valueType); } - public SortedMap headMap(K toKey) { - return new CheckedSortedMap(sm.headMap(toKey), - keyType, valueType); + return checkedSortedMap(sm.headMap(toKey), keyType, valueType); } - public SortedMap tailMap(K fromKey) { - return new CheckedSortedMap(sm.tailMap(fromKey), - keyType, valueType); + return checkedSortedMap(sm.tailMap(fromKey), keyType, valueType); } } - // Miscellaneous - /** - * The empty set (immutable). This set is serializable. + * Returns a dynamically typesafe view of the specified navigable map. + * Any attempt to insert a mapping whose key or value have the wrong + * type will result in an immediate {@link ClassCastException}. + * Similarly, any attempt to modify the value currently associated with + * a key will result in an immediate {@link ClassCastException}, + * whether the modification is attempted directly through the map + * itself, or through a {@link Map.Entry} instance obtained from the + * map's {@link Map#entrySet() entry set} view. * - * @see #emptySet() - */ - public static final Set EMPTY_SET = new EmptySet(); - - /** - * Returns the empty set (immutable). This set is serializable. - * Unlike the like-named field, this method is parameterized. + *

Assuming a map contains no incorrectly typed keys or values + * prior to the time a dynamically typesafe view is generated, and + * that all subsequent access to the map takes place through the view + * (or one of its collection views), it is guaranteed that the + * map cannot contain an incorrectly typed key or value. * - *

This example illustrates the type-safe way to obtain an empty set: - *

-     *     Set<String> s = Collections.emptySet();
-     * 
- * Implementation note: Implementations of this method need not - * create a separate Set object for each call. Using this - * method is likely to have comparable cost to using the like-named - * field. (Unlike this method, the field does not provide type safety.) + *

A discussion of the use of dynamically typesafe views may be + * found in the documentation for the {@link #checkedCollection + * checkedCollection} method. * - * @see #EMPTY_SET - * @since 1.5 + *

The returned map will be serializable if the specified map is + * serializable. + * + *

Since {@code null} is considered to be a value of any reference + * type, the returned map permits insertion of null keys or values + * whenever the backing map does. + * + * @param type of map keys + * @param type of map values + * @param m the map for which a dynamically typesafe view is to be + * returned + * @param keyType the type of key that {@code m} is permitted to hold + * @param valueType the type of value that {@code m} is permitted to hold + * @return a dynamically typesafe view of the specified map + * @since 1.8 */ - public static final Set emptySet() { - return (Set) EMPTY_SET; + public static NavigableMap checkedNavigableMap(NavigableMap m, + Class keyType, + Class valueType) { + return new CheckedNavigableMap<>(m, keyType, valueType); } /** * @serial include */ - private static class EmptySet extends AbstractSet { - // use serialVersionUID from JDK 1.2.2 for interoperability - private static final long serialVersionUID = 1582296315990362920L; - - public Iterator iterator() { - return new Iterator() { - public boolean hasNext() { - return false; - } - public Object next() { - throw new NoSuchElementException(); - } - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - public int size() {return 0;} + static class CheckedNavigableMap extends CheckedSortedMap + implements NavigableMap, Serializable + { + private static final long serialVersionUID = -4852462692372534096L; - public boolean contains(Object obj) {return false;} + private final NavigableMap nm; - // Preserves singleton property - private Object readResolve() { - return EMPTY_SET; + CheckedNavigableMap(NavigableMap m, + Class keyType, Class valueType) { + super(m, keyType, valueType); + nm = m; } - } - /** - * The empty list (immutable). This list is serializable. - * - * @see #emptyList() - */ - public static final List EMPTY_LIST = new EmptyList(); + public Comparator comparator() { return nm.comparator(); } + public K firstKey() { return nm.firstKey(); } + public K lastKey() { return nm.lastKey(); } - /** - * Returns the empty list (immutable). This list is serializable. - * - *

This example illustrates the type-safe way to obtain an empty list: - *

-     *     List<String> s = Collections.emptyList();
-     * 
- * Implementation note: Implementations of this method need not - * create a separate List object for each call. Using this - * method is likely to have comparable cost to using the like-named - * field. (Unlike this method, the field does not provide type safety.) - * - * @see #EMPTY_LIST - * @since 1.5 - */ - public static final List emptyList() { - return (List) EMPTY_LIST; - } + public Entry lowerEntry(K key) { + Entry lower = nm.lowerEntry(key); + return (null != lower) + ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(lower, valueType) + : null; + } - /** - * @serial include - */ - private static class EmptyList - extends AbstractList - implements RandomAccess { - // use serialVersionUID from JDK 1.2.2 for interoperability - private static final long serialVersionUID = 8842843931221139166L; + public K lowerKey(K key) { return nm.lowerKey(key); } - public int size() {return 0;} + public Entry floorEntry(K key) { + Entry floor = nm.floorEntry(key); + return (null != floor) + ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(floor, valueType) + : null; + } - public boolean contains(Object obj) {return false;} + public K floorKey(K key) { return nm.floorKey(key); } - public Object get(int index) { - throw new IndexOutOfBoundsException("Index: "+index); + public Entry ceilingEntry(K key) { + Entry ceiling = nm.ceilingEntry(key); + return (null != ceiling) + ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(ceiling, valueType) + : null; } - // Preserves singleton property - private Object readResolve() { - return EMPTY_LIST; + public K ceilingKey(K key) { return nm.ceilingKey(key); } + + public Entry higherEntry(K key) { + Entry higher = nm.higherEntry(key); + return (null != higher) + ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(higher, valueType) + : null; } - } - /** - * The empty map (immutable). This map is serializable. - * - * @see #emptyMap() - * @since 1.3 - */ - public static final Map EMPTY_MAP = new EmptyMap(); + public K higherKey(K key) { return nm.higherKey(key); } - /** - * Returns the empty map (immutable). This map is serializable. - * - *

This example illustrates the type-safe way to obtain an empty set: - *

-     *     Map<String, Date> s = Collections.emptyMap();
-     * 
- * Implementation note: Implementations of this method need not - * create a separate Map object for each call. Using this - * method is likely to have comparable cost to using the like-named - * field. (Unlike this method, the field does not provide type safety.) - * - * @see #EMPTY_MAP - * @since 1.5 - */ - public static final Map emptyMap() { - return (Map) EMPTY_MAP; - } + public Entry firstEntry() { + Entry first = nm.firstEntry(); + return (null != first) + ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(first, valueType) + : null; + } - private static class EmptyMap - extends AbstractMap { + public Entry lastEntry() { + Entry last = nm.lastEntry(); + return (null != last) + ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(last, valueType) + : null; + } - private static final long serialVersionUID = 6428348081105594320L; + public Entry pollFirstEntry() { + Entry entry = nm.pollFirstEntry(); + return (null == entry) + ? null + : new CheckedMap.CheckedEntrySet.CheckedEntry<>(entry, valueType); + } - public int size() {return 0;} + public Entry pollLastEntry() { + Entry entry = nm.pollLastEntry(); + return (null == entry) + ? null + : new CheckedMap.CheckedEntrySet.CheckedEntry<>(entry, valueType); + } - public boolean isEmpty() {return true;} + public NavigableMap descendingMap() { + return checkedNavigableMap(nm.descendingMap(), keyType, valueType); + } - public boolean containsKey(Object key) {return false;} + public NavigableSet keySet() { + return navigableKeySet(); + } - public boolean containsValue(Object value) {return false;} + public NavigableSet navigableKeySet() { + return checkedNavigableSet(nm.navigableKeySet(), keyType); + } - public Object get(Object key) {return null;} + public NavigableSet descendingKeySet() { + return checkedNavigableSet(nm.descendingKeySet(), keyType); + } - public Set keySet() {return Collections.emptySet();} + @Override + public NavigableMap subMap(K fromKey, K toKey) { + return checkedNavigableMap(nm.subMap(fromKey, true, toKey, false), + keyType, valueType); + } - public Collection values() {return Collections.emptySet();} + @Override + public NavigableMap headMap(K toKey) { + return checkedNavigableMap(nm.headMap(toKey, false), keyType, valueType); + } - public Set> entrySet() { - return Collections.emptySet(); - } + @Override + public NavigableMap tailMap(K fromKey) { + return checkedNavigableMap(nm.tailMap(fromKey, true), keyType, valueType); + } - public boolean equals(Object o) { - return (o instanceof Map) && ((Map)o).size()==0; + public NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { + return checkedNavigableMap(nm.subMap(fromKey, fromInclusive, toKey, toInclusive), keyType, valueType); } - public int hashCode() {return 0;} + public NavigableMap headMap(K toKey, boolean inclusive) { + return checkedNavigableMap(nm.headMap(toKey, inclusive), keyType, valueType); + } - // Preserves singleton property - private Object readResolve() { - return EMPTY_MAP; + public NavigableMap tailMap(K fromKey, boolean inclusive) { + return checkedNavigableMap(nm.tailMap(fromKey, inclusive), keyType, valueType); } } + // Empty collections + /** - * Returns an immutable set containing only the specified object. - * The returned set is serializable. + * Returns an iterator that has no elements. More precisely, * - * @param o the sole object to be stored in the returned set. - * @return an immutable set containing only the specified object. + *
    + *
  • {@link Iterator#hasNext hasNext} always returns {@code + * false}.
  • + *
  • {@link Iterator#next next} always throws {@link + * NoSuchElementException}.
  • + *
  • {@link Iterator#remove remove} always throws {@link + * IllegalStateException}.
  • + *
+ * + *

Implementations of this method are permitted, but not + * required, to return the same object from multiple invocations. + * + * @param type of elements, if there were any, in the iterator + * @return an empty iterator + * @since 1.7 */ - public static Set singleton(T o) { - return new SingletonSet(o); + @SuppressWarnings("unchecked") + public static Iterator emptyIterator() { + return (Iterator) EmptyIterator.EMPTY_ITERATOR; } - /** + private static class EmptyIterator implements Iterator { + static final EmptyIterator EMPTY_ITERATOR + = new EmptyIterator<>(); + + public boolean hasNext() { return false; } + public E next() { throw new NoSuchElementException(); } + public void remove() { throw new IllegalStateException(); } + @Override + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + } + } + + /** + * Returns a list iterator that has no elements. More precisely, + * + *
    + *
  • {@link Iterator#hasNext hasNext} and {@link + * ListIterator#hasPrevious hasPrevious} always return {@code + * false}.
  • + *
  • {@link Iterator#next next} and {@link ListIterator#previous + * previous} always throw {@link NoSuchElementException}.
  • + *
  • {@link Iterator#remove remove} and {@link ListIterator#set + * set} always throw {@link IllegalStateException}.
  • + *
  • {@link ListIterator#add add} always throws {@link + * UnsupportedOperationException}.
  • + *
  • {@link ListIterator#nextIndex nextIndex} always returns + * {@code 0}.
  • + *
  • {@link ListIterator#previousIndex previousIndex} always + * returns {@code -1}.
  • + *
+ * + *

Implementations of this method are permitted, but not + * required, to return the same object from multiple invocations. + * + * @param type of elements, if there were any, in the iterator + * @return an empty list iterator + * @since 1.7 + */ + @SuppressWarnings("unchecked") + public static ListIterator emptyListIterator() { + return (ListIterator) EmptyListIterator.EMPTY_ITERATOR; + } + + private static class EmptyListIterator + extends EmptyIterator + implements ListIterator + { + static final EmptyListIterator EMPTY_ITERATOR + = new EmptyListIterator<>(); + + public boolean hasPrevious() { return false; } + public E previous() { throw new NoSuchElementException(); } + public int nextIndex() { return 0; } + public int previousIndex() { return -1; } + public void set(E e) { throw new IllegalStateException(); } + public void add(E e) { throw new UnsupportedOperationException(); } + } + + /** + * Returns an enumeration that has no elements. More precisely, + * + *
    + *
  • {@link Enumeration#hasMoreElements hasMoreElements} always + * returns {@code false}.
  • + *
  • {@link Enumeration#nextElement nextElement} always throws + * {@link NoSuchElementException}.
  • + *
+ * + *

Implementations of this method are permitted, but not + * required, to return the same object from multiple invocations. + * + * @param the class of the objects in the enumeration + * @return an empty enumeration + * @since 1.7 + */ + @SuppressWarnings("unchecked") + public static Enumeration emptyEnumeration() { + return (Enumeration) EmptyEnumeration.EMPTY_ENUMERATION; + } + + private static class EmptyEnumeration implements Enumeration { + static final EmptyEnumeration EMPTY_ENUMERATION + = new EmptyEnumeration<>(); + + public boolean hasMoreElements() { return false; } + public E nextElement() { throw new NoSuchElementException(); } + } + + /** + * The empty set (immutable). This set is serializable. + * + * @see #emptySet() + */ + @SuppressWarnings("rawtypes") + public static final Set EMPTY_SET = new EmptySet<>(); + + /** + * Returns an empty set (immutable). This set is serializable. + * Unlike the like-named field, this method is parameterized. + * + *

This example illustrates the type-safe way to obtain an empty set: + *

+     *     Set<String> s = Collections.emptySet();
+     * 
+ * @implNote Implementations of this method need not create a separate + * {@code Set} object for each call. Using this method is likely to have + * comparable cost to using the like-named field. (Unlike this method, the + * field does not provide type safety.) + * + * @param the class of the objects in the set + * @return the empty set + * + * @see #EMPTY_SET + * @since 1.5 + */ + @SuppressWarnings("unchecked") + public static final Set emptySet() { + return (Set) EMPTY_SET; + } + + /** * @serial include */ - private static class SingletonSet - extends AbstractSet + private static class EmptySet + extends AbstractSet + implements Serializable { - // use serialVersionUID from JDK 1.2.2 for interoperability - private static final long serialVersionUID = 3193687207550431679L; + private static final long serialVersionUID = 1582296315990362920L; + + public Iterator iterator() { return emptyIterator(); } + + public int size() {return 0;} + public boolean isEmpty() {return true;} + + public boolean contains(Object obj) {return false;} + public boolean containsAll(Collection c) { return c.isEmpty(); } - final private E element; + public Object[] toArray() { return new Object[0]; } - SingletonSet(E o) {element = o;} + public T[] toArray(T[] a) { + if (a.length > 0) + a[0] = null; + return a; + } + + // Override default methods in Collection + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + } + @Override + public boolean removeIf(Predicate filter) { + Objects.requireNonNull(filter); + return false; + } + @Override + public Spliterator spliterator() { return Spliterators.emptySpliterator(); } + + // Preserves singleton property + private Object readResolve() { + return EMPTY_SET; + } + } + + /** + * Returns an empty sorted set (immutable). This set is serializable. + * + *

This example illustrates the type-safe way to obtain an empty + * sorted set: + *

 {@code
+     *     SortedSet s = Collections.emptySortedSet();
+     * }
+ * + * @implNote Implementations of this method need not create a separate + * {@code SortedSet} object for each call. + * + * @param type of elements, if there were any, in the set + * @return the empty sorted set + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static SortedSet emptySortedSet() { + return (SortedSet) UnmodifiableNavigableSet.EMPTY_NAVIGABLE_SET; + } + + /** + * Returns an empty navigable set (immutable). This set is serializable. + * + *

This example illustrates the type-safe way to obtain an empty + * navigable set: + *

 {@code
+     *     NavigableSet s = Collections.emptyNavigableSet();
+     * }
+ * + * @implNote Implementations of this method need not + * create a separate {@code NavigableSet} object for each call. + * + * @param type of elements, if there were any, in the set + * @return the empty navigable set + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static NavigableSet emptyNavigableSet() { + return (NavigableSet) UnmodifiableNavigableSet.EMPTY_NAVIGABLE_SET; + } + + /** + * The empty list (immutable). This list is serializable. + * + * @see #emptyList() + */ + @SuppressWarnings("rawtypes") + public static final List EMPTY_LIST = new EmptyList<>(); + + /** + * Returns an empty list (immutable). This list is serializable. + * + *

This example illustrates the type-safe way to obtain an empty list: + *

+     *     List<String> s = Collections.emptyList();
+     * 
+ * + * @implNote + * Implementations of this method need not create a separate List + * object for each call. Using this method is likely to have comparable + * cost to using the like-named field. (Unlike this method, the field does + * not provide type safety.) + * + * @param type of elements, if there were any, in the list + * @return an empty immutable list + * + * @see #EMPTY_LIST + * @since 1.5 + */ + @SuppressWarnings("unchecked") + public static final List emptyList() { + return (List) EMPTY_LIST; + } + + /** + * @serial include + */ + private static class EmptyList + extends AbstractList + implements RandomAccess, Serializable { + private static final long serialVersionUID = 8842843931221139166L; public Iterator iterator() { - return new Iterator() { - private boolean hasNext = true; - public boolean hasNext() { - return hasNext; + return emptyIterator(); + } + public ListIterator listIterator() { + return emptyListIterator(); + } + + public int size() {return 0;} + public boolean isEmpty() {return true;} + + public boolean contains(Object obj) {return false;} + public boolean containsAll(Collection c) { return c.isEmpty(); } + + public Object[] toArray() { return new Object[0]; } + + public T[] toArray(T[] a) { + if (a.length > 0) + a[0] = null; + return a; + } + + public E get(int index) { + throw new IndexOutOfBoundsException("Index: "+index); + } + + public boolean equals(Object o) { + return (o instanceof List) && ((List)o).isEmpty(); + } + + public int hashCode() { return 1; } + + @Override + public boolean removeIf(Predicate filter) { + Objects.requireNonNull(filter); + return false; + } + @Override + public void replaceAll(UnaryOperator operator) { + Objects.requireNonNull(operator); + } + @Override + public void sort(Comparator c) { + } + + // Override default methods in Collection + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + } + + @Override + public Spliterator spliterator() { return Spliterators.emptySpliterator(); } + + // Preserves singleton property + private Object readResolve() { + return EMPTY_LIST; + } + } + + /** + * The empty map (immutable). This map is serializable. + * + * @see #emptyMap() + * @since 1.3 + */ + @SuppressWarnings("rawtypes") + public static final Map EMPTY_MAP = new EmptyMap<>(); + + /** + * Returns an empty map (immutable). This map is serializable. + * + *

This example illustrates the type-safe way to obtain an empty map: + *

+     *     Map<String, Date> s = Collections.emptyMap();
+     * 
+ * @implNote Implementations of this method need not create a separate + * {@code Map} object for each call. Using this method is likely to have + * comparable cost to using the like-named field. (Unlike this method, the + * field does not provide type safety.) + * + * @param the class of the map keys + * @param the class of the map values + * @return an empty map + * @see #EMPTY_MAP + * @since 1.5 + */ + @SuppressWarnings("unchecked") + public static final Map emptyMap() { + return (Map) EMPTY_MAP; + } + + /** + * Returns an empty sorted map (immutable). This map is serializable. + * + *

This example illustrates the type-safe way to obtain an empty map: + *

 {@code
+     *     SortedMap s = Collections.emptySortedMap();
+     * }
+ * + * @implNote Implementations of this method need not create a separate + * {@code SortedMap} object for each call. + * + * @param the class of the map keys + * @param the class of the map values + * @return an empty sorted map + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static final SortedMap emptySortedMap() { + return (SortedMap) UnmodifiableNavigableMap.EMPTY_NAVIGABLE_MAP; + } + + /** + * Returns an empty navigable map (immutable). This map is serializable. + * + *

This example illustrates the type-safe way to obtain an empty map: + *

 {@code
+     *     NavigableMap s = Collections.emptyNavigableMap();
+     * }
+ * + * @implNote Implementations of this method need not create a separate + * {@code NavigableMap} object for each call. + * + * @param the class of the map keys + * @param the class of the map values + * @return an empty navigable map + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static final NavigableMap emptyNavigableMap() { + return (NavigableMap) UnmodifiableNavigableMap.EMPTY_NAVIGABLE_MAP; + } + + /** + * @serial include + */ + private static class EmptyMap + extends AbstractMap + implements Serializable + { + private static final long serialVersionUID = 6428348081105594320L; + + public int size() {return 0;} + public boolean isEmpty() {return true;} + public boolean containsKey(Object key) {return false;} + public boolean containsValue(Object value) {return false;} + public V get(Object key) {return null;} + public Set keySet() {return emptySet();} + public Collection values() {return emptySet();} + public Set> entrySet() {return emptySet();} + + public boolean equals(Object o) { + return (o instanceof Map) && ((Map)o).isEmpty(); + } + + public int hashCode() {return 0;} + + // Override default methods in Map + @Override + @SuppressWarnings("unchecked") + public V getOrDefault(Object k, V defaultValue) { + return defaultValue; + } + + @Override + public void forEach(BiConsumer action) { + Objects.requireNonNull(action); + } + + @Override + public void replaceAll(BiFunction function) { + Objects.requireNonNull(function); + } + + @Override + public V putIfAbsent(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfAbsent(K key, + Function mappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfPresent(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V compute(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V merge(K key, V value, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + // Preserves singleton property + private Object readResolve() { + return EMPTY_MAP; + } + } + + // Singleton collections + + /** + * Returns an immutable set containing only the specified object. + * The returned set is serializable. + * + * @param the class of the objects in the set + * @param o the sole object to be stored in the returned set. + * @return an immutable set containing only the specified object. + */ + public static Set singleton(T o) { + return new SingletonSet<>(o); + } + + static Iterator singletonIterator(final E e) { + return new Iterator() { + private boolean hasNext = true; + public boolean hasNext() { + return hasNext; + } + public E next() { + if (hasNext) { + hasNext = false; + return e; } - public E next() { - if (hasNext) { - hasNext = false; - return element; - } - throw new NoSuchElementException(); + throw new NoSuchElementException(); + } + public void remove() { + throw new UnsupportedOperationException(); + } + @Override + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + if (hasNext) { + action.accept(e); + hasNext = false; } - public void remove() { - throw new UnsupportedOperationException(); + } + }; + } + + /** + * Creates a {@code Spliterator} with only the specified element + * + * @param Type of elements + * @return A singleton {@code Spliterator} + */ + static Spliterator singletonSpliterator(final T element) { + return new Spliterator() { + long est = 1; + + @Override + public Spliterator trySplit() { + return null; + } + + @Override + public boolean tryAdvance(Consumer consumer) { + Objects.requireNonNull(consumer); + if (est > 0) { + est--; + consumer.accept(element); + return true; } - }; + return false; + } + + @Override + public void forEachRemaining(Consumer consumer) { + tryAdvance(consumer); + } + + @Override + public long estimateSize() { + return est; + } + + @Override + public int characteristics() { + int value = (element != null) ? Spliterator.NONNULL : 0; + + return value | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.IMMUTABLE | + Spliterator.DISTINCT | Spliterator.ORDERED; + } + }; + } + + /** + * @serial include + */ + private static class SingletonSet + extends AbstractSet + implements Serializable + { + private static final long serialVersionUID = 3193687207550431679L; + + private final E element; + + SingletonSet(E e) {element = e;} + + public Iterator iterator() { + return singletonIterator(element); } public int size() {return 1;} public boolean contains(Object o) {return eq(o, element);} + + // Override default methods for Collection + @Override + public void forEach(Consumer action) { + action.accept(element); + } + @Override + public Spliterator spliterator() { + return singletonSpliterator(element); + } + @Override + public boolean removeIf(Predicate filter) { + throw new UnsupportedOperationException(); + } } /** * Returns an immutable list containing only the specified object. * The returned list is serializable. * + * @param the class of the objects in the list * @param o the sole object to be stored in the returned list. * @return an immutable list containing only the specified object. * @since 1.3 */ public static List singletonList(T o) { - return new SingletonList(o); + return new SingletonList<>(o); } + /** + * @serial include + */ private static class SingletonList - extends AbstractList - implements RandomAccess { + extends AbstractList + implements RandomAccess, Serializable { - static final long serialVersionUID = 3093736618740652951L; + private static final long serialVersionUID = 3093736618740652951L; private final E element; SingletonList(E obj) {element = obj;} + public Iterator iterator() { + return singletonIterator(element); + } + public int size() {return 1;} public boolean contains(Object obj) {return eq(obj, element);} public E get(int index) { if (index != 0) - throw new IndexOutOfBoundsException("Index: "+index+", Size: 1"); + throw new IndexOutOfBoundsException("Index: "+index+", Size: 1"); return element; } + + // Override default methods for Collection + @Override + public void forEach(Consumer action) { + action.accept(element); + } + @Override + public boolean removeIf(Predicate filter) { + throw new UnsupportedOperationException(); + } + @Override + public void replaceAll(UnaryOperator operator) { + throw new UnsupportedOperationException(); + } + @Override + public void sort(Comparator c) { + } + @Override + public Spliterator spliterator() { + return singletonSpliterator(element); + } } /** * Returns an immutable map, mapping only the specified key to the * specified value. The returned map is serializable. * + * @param the class of the map keys + * @param the class of the map values * @param key the sole key to be stored in the returned map. * @param value the value to which the returned map maps key. * @return an immutable map containing only the specified key-value @@ -3147,89 +4853,117 @@ public E get(int index) { * @since 1.3 */ public static Map singletonMap(K key, V value) { - return new SingletonMap(key, value); + return new SingletonMap<>(key, value); } + /** + * @serial include + */ private static class SingletonMap - extends AbstractMap { - private static final long serialVersionUID = -6979724477215052911L; + extends AbstractMap + implements Serializable { + private static final long serialVersionUID = -6979724477215052911L; private final K k; - private final V v; + private final V v; SingletonMap(K key, V value) { k = key; v = value; } - public int size() {return 1;} - - public boolean isEmpty() {return false;} + public int size() {return 1;} + public boolean isEmpty() {return false;} + public boolean containsKey(Object key) {return eq(key, k);} + public boolean containsValue(Object value) {return eq(value, v);} + public V get(Object key) {return (eq(key, k) ? v : null);} - public boolean containsKey(Object key) {return eq(key, k);} + private transient Set keySet; + private transient Set> entrySet; + private transient Collection values; - public boolean containsValue(Object value) {return eq(value, v);} + public Set keySet() { + if (keySet==null) + keySet = singleton(k); + return keySet; + } - public V get(Object key) {return (eq(key, k) ? v : null);} + public Set> entrySet() { + if (entrySet==null) + entrySet = Collections.>singleton( + new SimpleImmutableEntry<>(k, v)); + return entrySet; + } - private transient Set keySet = null; - private transient Set> entrySet = null; - private transient Collection values = null; + public Collection values() { + if (values==null) + values = singleton(v); + return values; + } - public Set keySet() { - if (keySet==null) - keySet = singleton(k); - return keySet; - } + // Override default methods in Map + @Override + public V getOrDefault(Object key, V defaultValue) { + return eq(key, k) ? v : defaultValue; + } - public Set> entrySet() { - if (entrySet==null) - entrySet = singleton((Map.Entry)new ImmutableEntry(k, v)); - return entrySet; - } + @Override + public void forEach(BiConsumer action) { + action.accept(k, v); + } - public Collection values() { - if (values==null) - values = singleton(v); - return values; - } + @Override + public void replaceAll(BiFunction function) { + throw new UnsupportedOperationException(); + } - private static class ImmutableEntry - implements Map.Entry { - final K k; - final V v; + @Override + public V putIfAbsent(K key, V value) { + throw new UnsupportedOperationException(); + } - ImmutableEntry(K key, V value) { - k = key; - v = value; - } + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } - public K getKey() {return k;} + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + } - public V getValue() {return v;} + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + } - public V setValue(V value) { - throw new UnsupportedOperationException(); - } + @Override + public V computeIfAbsent(K key, + Function mappingFunction) { + throw new UnsupportedOperationException(); + } - public boolean equals(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry)o; - return eq(e.getKey(), k) && eq(e.getValue(), v); - } + @Override + public V computeIfPresent(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } - public int hashCode() { - return ((k==null ? 0 : k.hashCode()) ^ - (v==null ? 0 : v.hashCode())); - } + @Override + public V compute(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } - public String toString() { - return k+"="+v; - } + @Override + public V merge(K key, V value, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); } } + // Miscellaneous + /** * Returns an immutable list consisting of n copies of the * specified object. The newly allocated data object is tiny (it contains @@ -3237,35 +4971,38 @@ public String toString() { * combination with the List.addAll method to grow lists. * The returned list is serializable. * + * @param the class of the object to copy and of the objects + * in the returned list. * @param n the number of elements in the returned list. * @param o the element to appear repeatedly in the returned list. * @return an immutable list consisting of n copies of the - * specified object. - * @throws IllegalArgumentException if n < 0. + * specified object. + * @throws IllegalArgumentException if {@code n < 0} * @see List#addAll(Collection) * @see List#addAll(int, Collection) */ public static List nCopies(int n, T o) { - return new CopiesList(n, o); + if (n < 0) + throw new IllegalArgumentException("List length = " + n); + return new CopiesList<>(n, o); } /** * @serial include */ private static class CopiesList - extends AbstractList - implements RandomAccess + extends AbstractList + implements RandomAccess, Serializable { - static final long serialVersionUID = 2739099268398711800L; + private static final long serialVersionUID = 2739099268398711800L; - int n; - E element; + final int n; + final E element; - CopiesList(int n, E o) { - if (n < 0) - throw new IllegalArgumentException("List length = " + n); + CopiesList(int n, E e) { + assert n >= 0; this.n = n; - element = o; + element = e; } public int size() { @@ -3276,81 +5013,207 @@ public boolean contains(Object obj) { return n != 0 && eq(obj, element); } + public int indexOf(Object o) { + return contains(o) ? 0 : -1; + } + + public int lastIndexOf(Object o) { + return contains(o) ? n - 1 : -1; + } + public E get(int index) { - if (index<0 || index>=n) + if (index < 0 || index >= n) throw new IndexOutOfBoundsException("Index: "+index+ - ", Size: "+n); + ", Size: "+n); return element; } + + public Object[] toArray() { + final Object[] a = new Object[n]; + if (element != null) + Arrays.fill(a, 0, n, element); + return a; + } + + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + final int n = this.n; + if (a.length < n) { + a = (T[])java.lang.reflect.Array + .newInstance(a.getClass().getComponentType(), n); + if (element != null) + Arrays.fill(a, 0, n, element); + } else { + Arrays.fill(a, 0, n, element); + if (a.length > n) + a[n] = null; + } + return a; + } + + public List subList(int fromIndex, int toIndex) { + if (fromIndex < 0) + throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); + if (toIndex > n) + throw new IndexOutOfBoundsException("toIndex = " + toIndex); + if (fromIndex > toIndex) + throw new IllegalArgumentException("fromIndex(" + fromIndex + + ") > toIndex(" + toIndex + ")"); + return new CopiesList<>(toIndex - fromIndex, element); + } + + @Override + public int hashCode() { + if (n == 0) return 1; + // hashCode of n repeating elements is 31^n + elementHash * Sum(31^k, k = 0..n-1) + // this implementation completes in O(log(n)) steps taking advantage of + // 31^(2*n) = (31^n)^2 and Sum(31^k, k = 0..(2*n-1)) = Sum(31^k, k = 0..n-1) * (31^n + 1) + int pow = 31; + int sum = 1; + for (int i = Integer.numberOfLeadingZeros(n) + 1; i < Integer.SIZE; i++) { + sum *= pow + 1; + pow *= pow; + if ((n << i) < 0) { + pow *= 31; + sum = sum * 31 + 1; + } + } + return pow + sum * (element == null ? 0 : element.hashCode()); + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (o instanceof CopiesList) { + CopiesList other = (CopiesList) o; + return n == other.n && (n == 0 || eq(element, other.element)); + } + if (!(o instanceof List)) + return false; + + int remaining = n; + E e = element; + Iterator itr = ((List) o).iterator(); + if (e == null) { + while (itr.hasNext() && remaining-- > 0) { + if (itr.next() != null) + return false; + } + } else { + while (itr.hasNext() && remaining-- > 0) { + if (!e.equals(itr.next())) + return false; + } + } + return remaining == 0 && !itr.hasNext(); + } + + // Override default methods in Collection +// @Override +// public Stream stream() { +// return IntStream.range(0, n).mapToObj(i -> element); +// } +// +// @Override +// public Stream parallelStream() { +// return IntStream.range(0, n).parallel().mapToObj(i -> element); +// } +// +// @Override +// public Spliterator spliterator() { +// return stream().spliterator(); +// } + + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + SharedSecrets.getJavaOISAccess().checkArray(ois, Object[].class, n); + } } /** - * Returns a comparator that imposes the reverse of the natural - * ordering on a collection of objects that implement the - * Comparable interface. (The natural ordering is the ordering - * imposed by the objects' own compareTo method.) This enables a + * Returns a comparator that imposes the reverse of the natural + * ordering on a collection of objects that implement the + * {@code Comparable} interface. (The natural ordering is the ordering + * imposed by the objects' own {@code compareTo} method.) This enables a * simple idiom for sorting (or maintaining) collections (or arrays) of - * objects that implement the Comparable interface in - * reverse-natural-order. For example, suppose a is an array of + * objects that implement the {@code Comparable} interface in + * reverse-natural-order. For example, suppose {@code a} is an array of * strings. Then:
-     * 		Arrays.sort(a, Collections.reverseOrder());
+     *          Arrays.sort(a, Collections.reverseOrder());
      * 
sorts the array in reverse-lexicographic (alphabetical) order.

* * The returned comparator is serializable. * - * @return a comparator that imposes the reverse of the natural - * ordering on a collection of objects that implement - * the Comparable interface. + * @param the class of the objects compared by the comparator + * @return A comparator that imposes the reverse of the natural + * ordering on a collection of objects that implement + * the Comparable interface. * @see Comparable */ + @SuppressWarnings("unchecked") public static Comparator reverseOrder() { - return (Comparator) REVERSE_ORDER; + return (Comparator) ReverseComparator.REVERSE_ORDER; } - private static final Comparator REVERSE_ORDER = new ReverseComparator(); - /** * @serial include */ - private static class ReverseComparator - implements Comparator> { + private static class ReverseComparator + implements Comparator>, Serializable { - // use serialVersionUID from JDK 1.2.2 for interoperability - private static final long serialVersionUID = 7207038068494060240L; + private static final long serialVersionUID = 7207038068494060240L; + + static final ReverseComparator REVERSE_ORDER + = new ReverseComparator(); public int compare(Comparable c1, Comparable c2) { return c2.compareTo(c1); } + + private Object readResolve() { return Collections.reverseOrder(); } + + @Override + public Comparator> reversed() { + return Comparator.naturalOrder(); + } } /** * Returns a comparator that imposes the reverse ordering of the specified - * comparator. If the specified comparator is null, this method is + * comparator. If the specified comparator is {@code null}, this method is * equivalent to {@link #reverseOrder()} (in other words, it returns a - * comparator that imposes the reverse of the natural ordering on a - * collection of objects that implement the Comparable interface). + * comparator that imposes the reverse of the natural ordering on + * a collection of objects that implement the Comparable interface). * *

The returned comparator is serializable (assuming the specified - * comparator is also serializable or null). + * comparator is also serializable or {@code null}). * - * @return a comparator that imposes the reverse ordering of the - * specified comparator. + * @param the class of the objects compared by the comparator + * @param cmp a comparator who's ordering is to be reversed by the returned + * comparator or {@code null} + * @return A comparator that imposes the reverse ordering of the + * specified comparator. * @since 1.5 */ public static Comparator reverseOrder(Comparator cmp) { if (cmp == null) - return new ReverseComparator(); // Unchecked warning!! - - return new ReverseComparator2(cmp); + return reverseOrder(); + + if (cmp instanceof ReverseComparator2) + return ((ReverseComparator2)cmp).cmp; + + return new ReverseComparator2<>(cmp); } - + /** * @serial include */ - private static class ReverseComparator2 implements Comparator + private static class ReverseComparator2 implements Comparator, + Serializable { private static final long serialVersionUID = 4374092139857L; - + /** * The comparator specified in the static factory. This will never * be null, as the static factory returns a ReverseComparator @@ -3358,16 +5221,31 @@ private static class ReverseComparator2 implements Comparator * * @serial */ - private Comparator cmp; - + final Comparator cmp; + ReverseComparator2(Comparator cmp) { -// assert cmp != null; + assert cmp != null; this.cmp = cmp; } - + public int compare(T t1, T t2) { return cmp.compare(t2, t1); } + + public boolean equals(Object o) { + return (o == this) || + (o instanceof ReverseComparator2 && + cmp.equals(((ReverseComparator2)o).cmp)); + } + + public int hashCode() { + return cmp.hashCode() ^ Integer.MIN_VALUE; + } + + @Override + public Comparator reversed() { + return cmp; + } } /** @@ -3375,23 +5253,24 @@ public int compare(T t1, T t2) { * interoperability with legacy APIs that require an enumeration * as input. * + * @param the class of the objects in the collection * @param c the collection for which an enumeration is to be returned. * @return an enumeration over the specified collection. * @see Enumeration */ -// public static Enumeration enumeration(final Collection c) { -// return new Enumeration() { -// Iterator i = c.iterator(); -// -// public boolean hasMoreElements() { -// return i.hasNext(); -// } -// -// public T nextElement() { -// return i.next(); -// } -// }; -// } + public static Enumeration enumeration(final Collection c) { + return new Enumeration() { + private final Iterator i = c.iterator(); + + public boolean hasMoreElements() { + return i.hasNext(); + } + + public T nextElement() { + return i.next(); + } + }; + } /** * Returns an array list containing the elements returned by the @@ -3400,6 +5279,7 @@ public int compare(T t1, T t2) { * legacy APIs that return enumerations and new APIs that require * collections. * + * @param the class of the objects returned by the enumeration * @param e enumeration providing elements for the returned * array list * @return an array list containing the elements returned @@ -3408,18 +5288,20 @@ public int compare(T t1, T t2) { * @see Enumeration * @see ArrayList */ -// public static ArrayList list(Enumeration e) { -// ArrayList l = new ArrayList(); -// while (e.hasMoreElements()) -// l.add(e.nextElement()); -// return l; -// } + public static ArrayList list(Enumeration e) { + ArrayList l = new ArrayList<>(); + while (e.hasMoreElements()) + l.add(e.nextElement()); + return l; + } /** * Returns true if the specified arguments are equal, or both null. + * + * NB: Do not replace with Object.equals until JDK-8015417 is resolved. */ - private static boolean eq(Object o1, Object o2) { - return (o1==null ? o2==null : o1.equals(o2)); + static boolean eq(Object o1, Object o2) { + return o1==null ? o2==null : o1.equals(o2); } /** @@ -3431,65 +5313,113 @@ private static boolean eq(Object o1, Object o2) { * @param c the collection in which to determine the frequency * of o * @param o the object whose frequency is to be determined + * @return the number of elements in {@code c} equal to {@code o} * @throws NullPointerException if c is null * @since 1.5 */ -// public static int frequency(Collection c, Object o) { -// int result = 0; -// if (o == null) { -// for (Object e : c) -// if (e == null) -// result++; -// } else { -// for (Object e : c) -// if (o.equals(e)) -// result++; -// } -// return result; -// } + public static int frequency(Collection c, Object o) { + int result = 0; + if (o == null) { + for (Object e : c) + if (e == null) + result++; + } else { + for (Object e : c) + if (o.equals(e)) + result++; + } + return result; + } /** - * Returns true if the two specified collections have no + * Returns {@code true} if the two specified collections have no * elements in common. * *

Care must be exercised if this method is used on collections that - * do not comply with the general contract for Collection. + * do not comply with the general contract for {@code Collection}. * Implementations may elect to iterate over either collection and test * for containment in the other collection (or to perform any equivalent * computation). If either collection uses a nonstandard equality test - * (as does a {@link SortedSet} whose ordering is not compatible with - * equals, or the key set of an {@link IdentityHashMap}), both + * (as does a {@link SortedSet} whose ordering is not compatible with + * equals, or the key set of an {@link IdentityHashMap}), both * collections must use the same nonstandard equality test, or the * result of this method is undefined. * + *

Care must also be exercised when using collections that have + * restrictions on the elements that they may contain. Collection + * implementations are allowed to throw exceptions for any operation + * involving elements they deem ineligible. For absolute safety the + * specified collections should contain only elements which are + * eligible elements for both collections. + * *

Note that it is permissible to pass the same collection in both - * parameters, in which case the method will return true if and only if - * the collection is empty. + * parameters, in which case the method will return {@code true} if and + * only if the collection is empty. * * @param c1 a collection * @param c2 a collection - * @throws NullPointerException if either collection is null + * @return {@code true} if the two specified collections have no + * elements in common. + * @throws NullPointerException if either collection is {@code null}. + * @throws NullPointerException if one collection contains a {@code null} + * element and {@code null} is not an eligible element for the other collection. + * (optional) + * @throws ClassCastException if one collection contains an element that is + * of a type which is ineligible for the other collection. + * (optional) * @since 1.5 */ -// public static boolean disjoint(Collection c1, Collection c2) { -// /* -// * We're going to iterate through c1 and test for inclusion in c2. -// * If c1 is a Set and c2 isn't, swap the collections. Otherwise, -// * place the shorter collection in c1. Hopefully this heuristic -// * will minimize the cost of the operation. -// */ -// if ((c1 instanceof Set) && !(c2 instanceof Set) || -// (c1.size() > c2.size())) { -// Collection tmp = c1; -// c1 = c2; -// c2 = tmp; -// } -// -// for (Object e : c1) -// if (c2.contains(e)) -// return false; -// return true; -// } + public static boolean disjoint(Collection c1, Collection c2) { + // The collection to be used for contains(). Preference is given to + // the collection who's contains() has lower O() complexity. + Collection contains = c2; + // The collection to be iterated. If the collections' contains() impl + // are of different O() complexity, the collection with slower + // contains() will be used for iteration. For collections who's + // contains() are of the same complexity then best performance is + // achieved by iterating the smaller collection. + Collection iterate = c1; + + // Performance optimization cases. The heuristics: + // 1. Generally iterate over c1. + // 2. If c1 is a Set then iterate over c2. + // 3. If either collection is empty then result is always true. + // 4. Iterate over the smaller Collection. + if (c1 instanceof Set) { + // Use c1 for contains as a Set's contains() is expected to perform + // better than O(N/2) + iterate = c2; + contains = c1; + } else if (!(c2 instanceof Set)) { + // Both are mere Collections. Iterate over smaller collection. + // Example: If c1 contains 3 elements and c2 contains 50 elements and + // assuming contains() requires ceiling(N/2) comparisons then + // checking for all c1 elements in c2 would require 75 comparisons + // (3 * ceiling(50/2)) vs. checking all c2 elements in c1 requiring + // 100 comparisons (50 * ceiling(3/2)). + int c1size = c1.size(); + int c2size = c2.size(); + if (c1size == 0 || c2size == 0) { + // At least one collection is empty. Nothing will match. + return true; + } + + if (c1size > c2size) { + iterate = c2; + contains = c1; + } + } + + for (Object e : iterate) { + if (contains.contains(e)) { + // Found a common element. Collections are not disjoint. + return false; + } + } + + // No common elements were found. + return true; + } /** * Adds all of the specified elements to the specified collection. @@ -3504,54 +5434,185 @@ private static boolean eq(Object o1, Object o2) { * Collections.addAll(flavors, "Peaches 'n Plutonium", "Rocky Racoon"); * * + * @param the class of the elements to add and of the collection * @param c the collection into which elements are to be inserted - * @param a the elements to insert into c + * @param elements the elements to insert into c * @return true if the collection changed as a result of the call * @throws UnsupportedOperationException if c does not support - * the add method + * the add operation * @throws NullPointerException if elements contains one or more - * null values and c does not support null elements, or + * null values and c does not permit null elements, or * if c or elements are null - * @throws IllegalArgumentException if some aspect of a value in + * @throws IllegalArgumentException if some property of a value in * elements prevents it from being added to c * @see Collection#addAll(Collection) * @since 1.5 */ - public static boolean addAll(Collection c, T... a) { + @SafeVarargs + public static boolean addAll(Collection c, T... elements) { boolean result = false; - for (T e : a) - result |= c.add(e); + for (T element : elements) + result |= c.add(element); return result; } - - /** - * Returns an enumeration over the specified collection. This provides - * interoperability with legacy APIs that require an enumeration - * as input. + + /** + * Returns a set backed by the specified map. The resulting set displays + * the same ordering, concurrency, and performance characteristics as the + * backing map. In essence, this factory method provides a {@link Set} + * implementation corresponding to any {@link Map} implementation. There + * is no need to use this method on a {@link Map} implementation that + * already has a corresponding {@link Set} implementation (such as {@link + * HashMap} or {@link TreeMap}). * - * @param the class of the objects in the collection - * @param c the collection for which an enumeration is to be returned. - * @return an enumeration over the specified collection. - * @see Enumeration + *

Each method invocation on the set returned by this method results in + * exactly one method invocation on the backing map or its keySet + * view, with one exception. The addAll method is implemented + * as a sequence of put invocations on the backing map. + * + *

The specified map must be empty at the time this method is invoked, + * and should not be accessed directly after this method returns. These + * conditions are ensured if the map is created empty, passed directly + * to this method, and no reference to the map is retained, as illustrated + * in the following code fragment: + *

+     *    Set<Object> weakHashSet = Collections.newSetFromMap(
+     *        new WeakHashMap<Object, Boolean>());
+     * 
+ * + * @param the class of the map keys and of the objects in the + * returned set + * @param map the backing map + * @return the set backed by the map + * @throws IllegalArgumentException if map is not empty + * @since 1.6 */ - public static Enumeration enumeration(final Collection c) { - return new Enumeration() { - private final Iterator i = c.iterator(); + public static Set newSetFromMap(Map map) { + return new SetFromMap<>(map); + } - public boolean hasMoreElements() { - return i.hasNext(); - } + /** + * @serial include + */ + private static class SetFromMap extends AbstractSet + implements Set, Serializable + { + private final Map m; // The backing map + private transient Set s; // Its keySet + + SetFromMap(Map map) { + if (!map.isEmpty()) + throw new IllegalArgumentException("Map is non-empty"); + m = map; + s = map.keySet(); + } + + public void clear() { m.clear(); } + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean contains(Object o) { return m.containsKey(o); } + public boolean remove(Object o) { return m.remove(o) != null; } + public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; } + public Iterator iterator() { return s.iterator(); } + public Object[] toArray() { return s.toArray(); } + public T[] toArray(T[] a) { return s.toArray(a); } + public String toString() { return s.toString(); } + public int hashCode() { return s.hashCode(); } + public boolean equals(Object o) { return o == this || s.equals(o); } + public boolean containsAll(Collection c) {return s.containsAll(c);} + public boolean removeAll(Collection c) {return s.removeAll(c);} + public boolean retainAll(Collection c) {return s.retainAll(c);} + // addAll is the only inherited implementation + + // Override default methods in Collection + @Override + public void forEach(Consumer action) { + s.forEach(action); + } + @Override + public boolean removeIf(Predicate filter) { + return s.removeIf(filter); + } + + @Override + public Spliterator spliterator() {return s.spliterator();} +// @Override +// public Stream stream() {return s.stream();} +// @Override +// public Stream parallelStream() {return s.parallelStream();} + + private static final long serialVersionUID = 2454657854757543876L; + + private void readObject(java.io.ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + stream.defaultReadObject(); + s = m.keySet(); + } + } - public T nextElement() { - return i.next(); - } - }; + /** + * Returns a view of a {@link Deque} as a Last-in-first-out (Lifo) + * {@link Queue}. Method add is mapped to push, + * remove is mapped to pop and so on. This + * view can be useful when you would like to use a method + * requiring a Queue but you need Lifo ordering. + * + *

Each method invocation on the queue returned by this method + * results in exactly one method invocation on the backing deque, with + * one exception. The {@link Queue#addAll addAll} method is + * implemented as a sequence of {@link Deque#addFirst addFirst} + * invocations on the backing deque. + * + * @param the class of the objects in the deque + * @param deque the deque + * @return the queue + * @since 1.6 + */ + public static Queue asLifoQueue(Deque deque) { + return new AsLIFOQueue<>(deque); } - public static ArrayList list(Enumeration e) { - ArrayList l = new ArrayList(); - while (e.hasMoreElements()) - l.add(e.nextElement()); - return l; + /** + * @serial include + */ + static class AsLIFOQueue extends AbstractQueue + implements Queue, Serializable { + private static final long serialVersionUID = 1802017725587941708L; + private final Deque q; + AsLIFOQueue(Deque q) { this.q = q; } + public boolean add(E e) { q.addFirst(e); return true; } + public boolean offer(E e) { return q.offerFirst(e); } + public E poll() { return q.pollFirst(); } + public E remove() { return q.removeFirst(); } + public E peek() { return q.peekFirst(); } + public E element() { return q.getFirst(); } + public void clear() { q.clear(); } + public int size() { return q.size(); } + public boolean isEmpty() { return q.isEmpty(); } + public boolean contains(Object o) { return q.contains(o); } + public boolean remove(Object o) { return q.remove(o); } + public Iterator iterator() { return q.iterator(); } + public Object[] toArray() { return q.toArray(); } + public T[] toArray(T[] a) { return q.toArray(a); } + public String toString() { return q.toString(); } + public boolean containsAll(Collection c) {return q.containsAll(c);} + public boolean removeAll(Collection c) {return q.removeAll(c);} + public boolean retainAll(Collection c) {return q.retainAll(c);} + // We use inherited addAll; forwarding addAll would be wrong + + // Override default methods in Collection + @Override + public void forEach(Consumer action) {q.forEach(action);} + @Override + public boolean removeIf(Predicate filter) { + return q.removeIf(filter); + } + @Override + public Spliterator spliterator() {return q.spliterator();} +// @Override +// public Stream stream() {return q.stream();} +// @Override +// public Stream parallelStream() {return q.parallelStream();} } } diff --git a/minijvm/java/src/main/java/org/mini/fs/InnerFile.java b/minijvm/java/src/main/java/org/mini/fs/InnerFile.java index 5f747c9aa..65f53e382 100644 --- a/minijvm/java/src/main/java/org/mini/fs/InnerFile.java +++ b/minijvm/java/src/main/java/org/mini/fs/InnerFile.java @@ -6,12 +6,10 @@ package org.mini.fs; import org.mini.net.SocketNative; -import org.mini.reflect.vm.RefNative; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; /** * diff --git a/minijvm/java/src/main/java/org/mini/reflect/DirectMemObj.java b/minijvm/java/src/main/java/org/mini/reflect/DirectMemObj.java index f6a1e2e1e..4c706c964 100644 --- a/minijvm/java/src/main/java/org/mini/reflect/DirectMemObj.java +++ b/minijvm/java/src/main/java/org/mini/reflect/DirectMemObj.java @@ -5,8 +5,8 @@ */ package org.mini.reflect; -import org.mini.reflect.vm.RConst; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.RConst; +import org.mini.vm.RefNative; import java.lang.reflect.Array; diff --git a/minijvm/java/src/main/java/org/mini/reflect/ReflectClass.java b/minijvm/java/src/main/java/org/mini/reflect/ReflectClass.java index bda691fe6..6e74879eb 100644 --- a/minijvm/java/src/main/java/org/mini/reflect/ReflectClass.java +++ b/minijvm/java/src/main/java/org/mini/reflect/ReflectClass.java @@ -5,7 +5,7 @@ */ package org.mini.reflect; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.RefNative; import java.util.ArrayList; import java.util.List; diff --git a/minijvm/java/src/main/java/org/mini/reflect/ReflectField.java b/minijvm/java/src/main/java/org/mini/reflect/ReflectField.java index 96368dd7a..9eac54b22 100644 --- a/minijvm/java/src/main/java/org/mini/reflect/ReflectField.java +++ b/minijvm/java/src/main/java/org/mini/reflect/ReflectField.java @@ -5,8 +5,8 @@ */ package org.mini.reflect; -import org.mini.reflect.vm.RConst; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.RConst; +import org.mini.vm.RefNative; import java.lang.reflect.Type; diff --git a/minijvm/java/src/main/java/org/mini/reflect/ReflectMethod.java b/minijvm/java/src/main/java/org/mini/reflect/ReflectMethod.java index c3b78ecb0..4e6386474 100644 --- a/minijvm/java/src/main/java/org/mini/reflect/ReflectMethod.java +++ b/minijvm/java/src/main/java/org/mini/reflect/ReflectMethod.java @@ -5,8 +5,7 @@ */ package org.mini.reflect; -import org.mini.reflect.vm.RConst; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.RConst; import java.lang.reflect.Type; import java.util.List; diff --git a/minijvm/java/src/main/java/org/mini/reflect/StackFrame.java b/minijvm/java/src/main/java/org/mini/reflect/StackFrame.java index 8dc1ab36e..bfb040a60 100644 --- a/minijvm/java/src/main/java/org/mini/reflect/StackFrame.java +++ b/minijvm/java/src/main/java/org/mini/reflect/StackFrame.java @@ -5,7 +5,7 @@ */ package org.mini.reflect; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.RefNative; /** * diff --git a/minijvm/java/src/main/java/org/mini/reflect/vm/ByteCodeAssembler.java b/minijvm/java/src/main/java/org/mini/vm/ByteCodeAssembler.java old mode 100755 new mode 100644 similarity index 92% rename from minijvm/java/src/main/java/org/mini/reflect/vm/ByteCodeAssembler.java rename to minijvm/java/src/main/java/org/mini/vm/ByteCodeAssembler.java index 0825c3c72..b8b0c68dc --- a/minijvm/java/src/main/java/org/mini/reflect/vm/ByteCodeAssembler.java +++ b/minijvm/java/src/main/java/org/mini/vm/ByteCodeAssembler.java @@ -1,134 +1,134 @@ -/* Copyright (c) 2008-2015, Avian Contributors - - Permission to use, copy, modify, and/or distribute this software - for any purpose with or without fee is hereby granted, provided - that the above copyright notice and this permission notice appear - in all copies. - - There is NO WARRANTY for this software. See license.txt for - details. */ -package org.mini.reflect.vm; - -import org.mini.reflect.vm.ByteCodeConstantPool.PoolEntry; - -import java.util.List; -import java.io.OutputStream; -import java.io.IOException; -import static org.mini.reflect.vm.ByteCodeStream.write2; -import static org.mini.reflect.vm.ByteCodeStream.write4; - -public class ByteCodeAssembler { - - public static final int ACC_PUBLIC = 1 << 0; - public static final int ACC_STATIC = 1 << 3; - - public static final int aaload = 0x32; - public static final int aastore = 0x53; - public static final int aload = 0x19; - public static final int aload_0 = 0x2a; - public static final int aload_1 = 0x2b; - public static final int astore_0 = 0x4b; - public static final int anewarray = 0xbd; - public static final int areturn = 0xb0; - public static final int dload = 0x18; - public static final int dreturn = 0xaf; - public static final int dup = 0x59; - public static final int fload = 0x17; - public static final int freturn = 0xae; - public static final int getfield = 0xb4; - public static final int goto_ = 0xa7; - public static final int iload = 0x15; - public static final int invokeinterface = 0xb9; - public static final int invokespecial = 0xb7; - public static final int invokestatic = 0xb8; - public static final int invokevirtual = 0xb6; - public static final int ireturn = 0xac; - public static final int jsr = 0xa8; - public static final int ldc_w = 0x13; - public static final int lload = 0x16; - public static final int lreturn = 0xad; - public static final int new_ = 0xbb; - public static final int pop = 0x57; - public static final int putfield = 0xb5; - public static final int ret = 0xa9; - public static final int return_ = 0xb1; - - public static void writeClass(OutputStream out, - List pool, - int name, - int super_, - int[] interfaces, - FieldData[] fields, - MethodData[] methods) - throws IOException { - int codeAttributeName = ByteCodeConstantPool.addUtf8(pool, "Code"); - - write4(out, 0xCAFEBABE); - write2(out, 0); // minor version - write2(out, 50); // major version - - write2(out, pool.size() + 1); - for (PoolEntry e : pool) { - e.writeTo(out); - } - - write2(out, ACC_PUBLIC); // flags - write2(out, name + 1); - write2(out, super_ + 1); - - write2(out, interfaces.length); - for (int i : interfaces) { - write2(out, i + 1); - } - - write2(out, fields.length); - for (FieldData f : fields) { - write2(out, f.flags); - write2(out, f.nameIndex + 1); - write2(out, f.specIndex + 1); - write2(out, 0); // attribute count - } - - write2(out, methods.length); - for (MethodData m : methods) { - write2(out, m.flags); - write2(out, m.nameIndex + 1); - write2(out, m.specIndex + 1); - - write2(out, 1); // attribute count - write2(out, codeAttributeName + 1); - write4(out, m.code.length); - out.write(m.code); - } - - write2(out, 0); // attribute count - } - - public static class MethodData { - - public final int flags; - public final int nameIndex; - public final int specIndex; - public final byte[] code; - - public MethodData(int flags, int nameIndex, int specIndex, byte[] code) { - this.flags = flags; - this.nameIndex = nameIndex; - this.specIndex = specIndex; - this.code = code; - } - } - - public static class FieldData { - - public final int flags; - public final int nameIndex; - public final int specIndex; - - public FieldData(int flags, int nameIndex, int specIndex) { - this.flags = flags; - this.nameIndex = nameIndex; - this.specIndex = specIndex; - } - } -} +/* Copyright (c) 2008-2015, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ +package org.mini.vm; + +import org.mini.vm.ByteCodeConstantPool.PoolEntry; + +import java.util.List; +import java.io.OutputStream; +import java.io.IOException; +import static org.mini.vm.ByteCodeStream.write2; +import static org.mini.vm.ByteCodeStream.write4; + +public class ByteCodeAssembler { + + public static final int ACC_PUBLIC = 1 << 0; + public static final int ACC_STATIC = 1 << 3; + + public static final int aaload = 0x32; + public static final int aastore = 0x53; + public static final int aload = 0x19; + public static final int aload_0 = 0x2a; + public static final int aload_1 = 0x2b; + public static final int astore_0 = 0x4b; + public static final int anewarray = 0xbd; + public static final int areturn = 0xb0; + public static final int dload = 0x18; + public static final int dreturn = 0xaf; + public static final int dup = 0x59; + public static final int fload = 0x17; + public static final int freturn = 0xae; + public static final int getfield = 0xb4; + public static final int goto_ = 0xa7; + public static final int iload = 0x15; + public static final int invokeinterface = 0xb9; + public static final int invokespecial = 0xb7; + public static final int invokestatic = 0xb8; + public static final int invokevirtual = 0xb6; + public static final int ireturn = 0xac; + public static final int jsr = 0xa8; + public static final int ldc_w = 0x13; + public static final int lload = 0x16; + public static final int lreturn = 0xad; + public static final int new_ = 0xbb; + public static final int pop = 0x57; + public static final int putfield = 0xb5; + public static final int ret = 0xa9; + public static final int return_ = 0xb1; + + public static void writeClass(OutputStream out, + List pool, + int name, + int super_, + int[] interfaces, + FieldData[] fields, + MethodData[] methods) + throws IOException { + int codeAttributeName = ByteCodeConstantPool.addUtf8(pool, "Code"); + + write4(out, 0xCAFEBABE); + write2(out, 0); // minor version + write2(out, 50); // major version + + write2(out, pool.size() + 1); + for (PoolEntry e : pool) { + e.writeTo(out); + } + + write2(out, ACC_PUBLIC); // flags + write2(out, name + 1); + write2(out, super_ + 1); + + write2(out, interfaces.length); + for (int i : interfaces) { + write2(out, i + 1); + } + + write2(out, fields.length); + for (FieldData f : fields) { + write2(out, f.flags); + write2(out, f.nameIndex + 1); + write2(out, f.specIndex + 1); + write2(out, 0); // attribute count + } + + write2(out, methods.length); + for (MethodData m : methods) { + write2(out, m.flags); + write2(out, m.nameIndex + 1); + write2(out, m.specIndex + 1); + + write2(out, 1); // attribute count + write2(out, codeAttributeName + 1); + write4(out, m.code.length); + out.write(m.code); + } + + write2(out, 0); // attribute count + } + + public static class MethodData { + + public final int flags; + public final int nameIndex; + public final int specIndex; + public final byte[] code; + + public MethodData(int flags, int nameIndex, int specIndex, byte[] code) { + this.flags = flags; + this.nameIndex = nameIndex; + this.specIndex = specIndex; + this.code = code; + } + } + + public static class FieldData { + + public final int flags; + public final int nameIndex; + public final int specIndex; + + public FieldData(int flags, int nameIndex, int specIndex) { + this.flags = flags; + this.nameIndex = nameIndex; + this.specIndex = specIndex; + } + } +} diff --git a/minijvm/java/src/main/java/org/mini/reflect/vm/ByteCodeConstantPool.java b/minijvm/java/src/main/java/org/mini/vm/ByteCodeConstantPool.java old mode 100755 new mode 100644 similarity index 94% rename from minijvm/java/src/main/java/org/mini/reflect/vm/ByteCodeConstantPool.java rename to minijvm/java/src/main/java/org/mini/vm/ByteCodeConstantPool.java index a2fe0d8b7..80a87609c --- a/minijvm/java/src/main/java/org/mini/reflect/vm/ByteCodeConstantPool.java +++ b/minijvm/java/src/main/java/org/mini/vm/ByteCodeConstantPool.java @@ -1,279 +1,279 @@ -/* Copyright (c) 2008-2015, Avian Contributors - - Permission to use, copy, modify, and/or distribute this software - for any purpose with or without fee is hereby granted, provided - that the above copyright notice and this permission notice appear - in all copies. - - There is NO WARRANTY for this software. See license.txt for - details. */ -package org.mini.reflect.vm; - -import java.util.List; -import java.io.OutputStream; -import java.io.IOException; -import static org.mini.reflect.vm.ByteCodeStream.write1; -import static org.mini.reflect.vm.ByteCodeStream.write2; -import static org.mini.reflect.vm.ByteCodeStream.write4; - -public class ByteCodeConstantPool { - - private static final int CONSTANT_Integer = 3; - private static final int CONSTANT_Utf8 = 1; - private static final int CONSTANT_String = 8; - private static final int CONSTANT_Class = 7; - private static final int CONSTANT_NameAndType = 12; - private static final int CONSTANT_Fieldref = 9; - private static final int CONSTANT_Methodref = 10; - private static final int CONSTANT_InterfaceMethodref = 11; - - public static int add(List pool, PoolEntry e) { - int i = 0; - for (PoolEntry existing : pool) { - if (existing.equals(e)) { - return i; - } else { - ++i; - } - } - pool.add(e); - return pool.size() - 1; - } - - public static int addInteger(List pool, int value) { - return add(pool, new IntegerPoolEntry(value)); - } - - public static int addUtf8(List pool, String value) { - return add(pool, new Utf8PoolEntry(value)); - } - - public static int addString(List pool, String value) { - return add(pool, new StringPoolEntry(addUtf8(pool, value))); - } - - public static int addClass(List pool, String name) { -// System.out.println("addClass:" + pool + ", " + name); - return add(pool, new ClassPoolEntry(addUtf8(pool, name))); - } - - public static int addNameAndType(List pool, - String name, - String type) { - return add(pool, new NameAndTypePoolEntry(addUtf8(pool, name), - addUtf8(pool, type))); - } - - public static int addFieldRef(List pool, - String className, - String name, - String spec) { - return add(pool, new FieldRefPoolEntry(addClass(pool, className), - addNameAndType(pool, name, spec))); - } - - public static int addMethodRef(List pool, - String className, - String name, - String spec) { - return add(pool, new MethodRefPoolEntry(addClass(pool, className), - addNameAndType(pool, name, spec))); - } - - public static int addInterfaceMethodRef(List pool, - String interfaceName, - String name, - String spec) { - return add(pool, new InterfaceMethodRefPoolEntry(addClass(pool, interfaceName), - addNameAndType(pool, name, spec))); - } - - public interface PoolEntry { - - public void writeTo(OutputStream out) throws IOException; - } - - private static class IntegerPoolEntry implements PoolEntry { - - private final int value; - - public IntegerPoolEntry(int value) { - this.value = value; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_Integer); - write4(out, value); - } - - public boolean equals(Object o) { - return o instanceof IntegerPoolEntry - && ((IntegerPoolEntry) o).value == value; - } - } - - private static class Utf8PoolEntry implements PoolEntry { - - private final String data; - - public Utf8PoolEntry(String data) { - this.data = data; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_Utf8); - byte[] bytes = data.getBytes(); - write2(out, bytes.length); - out.write(bytes); - } - - public boolean equals(Object o) { - return o instanceof Utf8PoolEntry - && ((Utf8PoolEntry) o).data.equals(data); - } - } - - private static class StringPoolEntry implements PoolEntry { - - private final int valueIndex; - - public StringPoolEntry(int valueIndex) { - this.valueIndex = valueIndex; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_String); - write2(out, valueIndex + 1); - } - - public boolean equals(Object o) { - return o instanceof StringPoolEntry - && ((StringPoolEntry) o).valueIndex == valueIndex; - } - } - - private static class ClassPoolEntry implements PoolEntry { - - private final int nameIndex; - - public ClassPoolEntry(int nameIndex) { - this.nameIndex = nameIndex; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_Class); - write2(out, nameIndex + 1); - } - - public boolean equals(Object o) { - return o instanceof ClassPoolEntry - && ((ClassPoolEntry) o).nameIndex == nameIndex; - } - } - - private static class NameAndTypePoolEntry implements PoolEntry { - - private final int nameIndex; - private final int typeIndex; - - public NameAndTypePoolEntry(int nameIndex, int typeIndex) { - this.nameIndex = nameIndex; - this.typeIndex = typeIndex; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_NameAndType); - write2(out, nameIndex + 1); - write2(out, typeIndex + 1); - } - - public boolean equals(Object o) { - if (o instanceof NameAndTypePoolEntry) { - NameAndTypePoolEntry other = (NameAndTypePoolEntry) o; - return other.nameIndex == nameIndex && other.typeIndex == typeIndex; - } else { - return false; - } - } - } - - private static class FieldRefPoolEntry implements PoolEntry { - - private final int classIndex; - private final int nameAndTypeIndex; - - public FieldRefPoolEntry(int classIndex, int nameAndTypeIndex) { - this.classIndex = classIndex; - this.nameAndTypeIndex = nameAndTypeIndex; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_Fieldref); - write2(out, classIndex + 1); - write2(out, nameAndTypeIndex + 1); - } - - public boolean equals(Object o) { - if (o instanceof FieldRefPoolEntry) { - FieldRefPoolEntry other = (FieldRefPoolEntry) o; - return other.classIndex == classIndex && other.nameAndTypeIndex == nameAndTypeIndex; - } else { - return false; - } - } - } - - private static class MethodRefPoolEntry implements PoolEntry { - - private final int classIndex; - private final int nameAndTypeIndex; - - public MethodRefPoolEntry(int classIndex, int nameAndTypeIndex) { - this.classIndex = classIndex; - this.nameAndTypeIndex = nameAndTypeIndex; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_Methodref); - write2(out, classIndex + 1); - write2(out, nameAndTypeIndex + 1); - } - - public boolean equals(Object o) { - if (o instanceof MethodRefPoolEntry) { - MethodRefPoolEntry other = (MethodRefPoolEntry) o; - return other.classIndex == classIndex - && other.nameAndTypeIndex == nameAndTypeIndex; - } else { - return false; - } - } - } - - private static class InterfaceMethodRefPoolEntry implements PoolEntry { - - private final int classIndex; - private final int nameAndTypeIndex; - - public InterfaceMethodRefPoolEntry(int classIndex, int nameAndTypeIndex) { - this.classIndex = classIndex; - this.nameAndTypeIndex = nameAndTypeIndex; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_InterfaceMethodref); - write2(out, classIndex + 1); - write2(out, nameAndTypeIndex + 1); - } - - public boolean equals(Object o) { - if (o instanceof InterfaceMethodRefPoolEntry) { - InterfaceMethodRefPoolEntry other = (InterfaceMethodRefPoolEntry) o; - return other.classIndex == classIndex - && other.nameAndTypeIndex == nameAndTypeIndex; - } else { - return false; - } - } - } -} +/* Copyright (c) 2008-2015, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ +package org.mini.vm; + +import java.util.List; +import java.io.OutputStream; +import java.io.IOException; +import static org.mini.vm.ByteCodeStream.write1; +import static org.mini.vm.ByteCodeStream.write2; +import static org.mini.vm.ByteCodeStream.write4; + +public class ByteCodeConstantPool { + + private static final int CONSTANT_Integer = 3; + private static final int CONSTANT_Utf8 = 1; + private static final int CONSTANT_String = 8; + private static final int CONSTANT_Class = 7; + private static final int CONSTANT_NameAndType = 12; + private static final int CONSTANT_Fieldref = 9; + private static final int CONSTANT_Methodref = 10; + private static final int CONSTANT_InterfaceMethodref = 11; + + public static int add(List pool, PoolEntry e) { + int i = 0; + for (PoolEntry existing : pool) { + if (existing.equals(e)) { + return i; + } else { + ++i; + } + } + pool.add(e); + return pool.size() - 1; + } + + public static int addInteger(List pool, int value) { + return add(pool, new IntegerPoolEntry(value)); + } + + public static int addUtf8(List pool, String value) { + return add(pool, new Utf8PoolEntry(value)); + } + + public static int addString(List pool, String value) { + return add(pool, new StringPoolEntry(addUtf8(pool, value))); + } + + public static int addClass(List pool, String name) { +// System.out.println("addClass:" + pool + ", " + name); + return add(pool, new ClassPoolEntry(addUtf8(pool, name))); + } + + public static int addNameAndType(List pool, + String name, + String type) { + return add(pool, new NameAndTypePoolEntry(addUtf8(pool, name), + addUtf8(pool, type))); + } + + public static int addFieldRef(List pool, + String className, + String name, + String spec) { + return add(pool, new FieldRefPoolEntry(addClass(pool, className), + addNameAndType(pool, name, spec))); + } + + public static int addMethodRef(List pool, + String className, + String name, + String spec) { + return add(pool, new MethodRefPoolEntry(addClass(pool, className), + addNameAndType(pool, name, spec))); + } + + public static int addInterfaceMethodRef(List pool, + String interfaceName, + String name, + String spec) { + return add(pool, new InterfaceMethodRefPoolEntry(addClass(pool, interfaceName), + addNameAndType(pool, name, spec))); + } + + public interface PoolEntry { + + public void writeTo(OutputStream out) throws IOException; + } + + private static class IntegerPoolEntry implements PoolEntry { + + private final int value; + + public IntegerPoolEntry(int value) { + this.value = value; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Integer); + write4(out, value); + } + + public boolean equals(Object o) { + return o instanceof IntegerPoolEntry + && ((IntegerPoolEntry) o).value == value; + } + } + + private static class Utf8PoolEntry implements PoolEntry { + + private final String data; + + public Utf8PoolEntry(String data) { + this.data = data; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Utf8); + byte[] bytes = data.getBytes(); + write2(out, bytes.length); + out.write(bytes); + } + + public boolean equals(Object o) { + return o instanceof Utf8PoolEntry + && ((Utf8PoolEntry) o).data.equals(data); + } + } + + private static class StringPoolEntry implements PoolEntry { + + private final int valueIndex; + + public StringPoolEntry(int valueIndex) { + this.valueIndex = valueIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_String); + write2(out, valueIndex + 1); + } + + public boolean equals(Object o) { + return o instanceof StringPoolEntry + && ((StringPoolEntry) o).valueIndex == valueIndex; + } + } + + private static class ClassPoolEntry implements PoolEntry { + + private final int nameIndex; + + public ClassPoolEntry(int nameIndex) { + this.nameIndex = nameIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Class); + write2(out, nameIndex + 1); + } + + public boolean equals(Object o) { + return o instanceof ClassPoolEntry + && ((ClassPoolEntry) o).nameIndex == nameIndex; + } + } + + private static class NameAndTypePoolEntry implements PoolEntry { + + private final int nameIndex; + private final int typeIndex; + + public NameAndTypePoolEntry(int nameIndex, int typeIndex) { + this.nameIndex = nameIndex; + this.typeIndex = typeIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_NameAndType); + write2(out, nameIndex + 1); + write2(out, typeIndex + 1); + } + + public boolean equals(Object o) { + if (o instanceof NameAndTypePoolEntry) { + NameAndTypePoolEntry other = (NameAndTypePoolEntry) o; + return other.nameIndex == nameIndex && other.typeIndex == typeIndex; + } else { + return false; + } + } + } + + private static class FieldRefPoolEntry implements PoolEntry { + + private final int classIndex; + private final int nameAndTypeIndex; + + public FieldRefPoolEntry(int classIndex, int nameAndTypeIndex) { + this.classIndex = classIndex; + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Fieldref); + write2(out, classIndex + 1); + write2(out, nameAndTypeIndex + 1); + } + + public boolean equals(Object o) { + if (o instanceof FieldRefPoolEntry) { + FieldRefPoolEntry other = (FieldRefPoolEntry) o; + return other.classIndex == classIndex && other.nameAndTypeIndex == nameAndTypeIndex; + } else { + return false; + } + } + } + + private static class MethodRefPoolEntry implements PoolEntry { + + private final int classIndex; + private final int nameAndTypeIndex; + + public MethodRefPoolEntry(int classIndex, int nameAndTypeIndex) { + this.classIndex = classIndex; + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Methodref); + write2(out, classIndex + 1); + write2(out, nameAndTypeIndex + 1); + } + + public boolean equals(Object o) { + if (o instanceof MethodRefPoolEntry) { + MethodRefPoolEntry other = (MethodRefPoolEntry) o; + return other.classIndex == classIndex + && other.nameAndTypeIndex == nameAndTypeIndex; + } else { + return false; + } + } + } + + private static class InterfaceMethodRefPoolEntry implements PoolEntry { + + private final int classIndex; + private final int nameAndTypeIndex; + + public InterfaceMethodRefPoolEntry(int classIndex, int nameAndTypeIndex) { + this.classIndex = classIndex; + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_InterfaceMethodref); + write2(out, classIndex + 1); + write2(out, nameAndTypeIndex + 1); + } + + public boolean equals(Object o) { + if (o instanceof InterfaceMethodRefPoolEntry) { + InterfaceMethodRefPoolEntry other = (InterfaceMethodRefPoolEntry) o; + return other.classIndex == classIndex + && other.nameAndTypeIndex == nameAndTypeIndex; + } else { + return false; + } + } + } +} diff --git a/minijvm/java/src/main/java/org/mini/reflect/vm/ByteCodeStream.java b/minijvm/java/src/main/java/org/mini/vm/ByteCodeStream.java old mode 100755 new mode 100644 similarity index 95% rename from minijvm/java/src/main/java/org/mini/reflect/vm/ByteCodeStream.java rename to minijvm/java/src/main/java/org/mini/vm/ByteCodeStream.java index 8b5aaeead..cdb137299 --- a/minijvm/java/src/main/java/org/mini/reflect/vm/ByteCodeStream.java +++ b/minijvm/java/src/main/java/org/mini/vm/ByteCodeStream.java @@ -1,86 +1,86 @@ -/* Copyright (c) 2008-2015, Avian Contributors - - Permission to use, copy, modify, and/or distribute this software - for any purpose with or without fee is hereby granted, provided - that the above copyright notice and this permission notice appear - in all copies. - - There is NO WARRANTY for this software. See license.txt for - details. */ -package org.mini.reflect.vm; - -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; -import java.io.EOFException; - -public abstract class ByteCodeStream { - - public static void write1(OutputStream out, int v) throws IOException { - out.write(v & 0xFF); - } - - public static int read1(InputStream in) throws IOException { - return in.read(); - } - - public static void write2(OutputStream out, int v) throws IOException { - out.write((v >>> 8) & 0xFF); - out.write((v) & 0xFF); - } - - public static int read2(InputStream in) throws IOException { - int b1 = in.read(); - int b2 = in.read(); - if (b2 == -1) { - throw new EOFException(); - } - return ((b1 << 8) | (b2 & 0xFF)); - } - - public static void write4(OutputStream out, int v) throws IOException { - out.write((v >>> 24) & 0xFF); - out.write((v >>> 16) & 0xFF); - out.write((v >>> 8) & 0xFF); - out.write((v) & 0xFF); - } - - public static int read4(InputStream in) throws IOException { - int b1 = in.read(); - int b2 = in.read(); - int b3 = in.read(); - int b4 = in.read(); - if (b4 == -1) { - throw new EOFException(); - } - return ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); - } - - public static void write8(OutputStream out, long v) throws IOException { - write4(out, (int) (v >>> 32) & 0xFFFFFFFF); - write4(out, (int) (v) & 0xFFFFFFFF); - } - - public static long read8(InputStream in) throws IOException { - long b1 = in.read(); - long b2 = in.read(); - long b3 = in.read(); - long b4 = in.read(); - long b5 = in.read(); - long b6 = in.read(); - long b7 = in.read(); - long b8 = in.read(); - if (b8 == -1) { - throw new EOFException(); - } - return ((b1 << 56) | (b2 << 48) | (b3 << 40) | (b4 << 32) - | (b5 << 24) | (b6 << 16) | (b7 << 8) | (b8)); - } - - public static void set4(byte[] array, int offset, int v) { - array[offset] = (byte) ((v >>> 24) & 0xFF); - array[offset + 1] = (byte) ((v >>> 16) & 0xFF); - array[offset + 2] = (byte) ((v >>> 8) & 0xFF); - array[offset + 3] = (byte) ((v) & 0xFF); - } -} +/* Copyright (c) 2008-2015, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ +package org.mini.vm; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.io.EOFException; + +public abstract class ByteCodeStream { + + public static void write1(OutputStream out, int v) throws IOException { + out.write(v & 0xFF); + } + + public static int read1(InputStream in) throws IOException { + return in.read(); + } + + public static void write2(OutputStream out, int v) throws IOException { + out.write((v >>> 8) & 0xFF); + out.write((v) & 0xFF); + } + + public static int read2(InputStream in) throws IOException { + int b1 = in.read(); + int b2 = in.read(); + if (b2 == -1) { + throw new EOFException(); + } + return ((b1 << 8) | (b2 & 0xFF)); + } + + public static void write4(OutputStream out, int v) throws IOException { + out.write((v >>> 24) & 0xFF); + out.write((v >>> 16) & 0xFF); + out.write((v >>> 8) & 0xFF); + out.write((v) & 0xFF); + } + + public static int read4(InputStream in) throws IOException { + int b1 = in.read(); + int b2 = in.read(); + int b3 = in.read(); + int b4 = in.read(); + if (b4 == -1) { + throw new EOFException(); + } + return ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); + } + + public static void write8(OutputStream out, long v) throws IOException { + write4(out, (int) (v >>> 32) & 0xFFFFFFFF); + write4(out, (int) (v) & 0xFFFFFFFF); + } + + public static long read8(InputStream in) throws IOException { + long b1 = in.read(); + long b2 = in.read(); + long b3 = in.read(); + long b4 = in.read(); + long b5 = in.read(); + long b6 = in.read(); + long b7 = in.read(); + long b8 = in.read(); + if (b8 == -1) { + throw new EOFException(); + } + return ((b1 << 56) | (b2 << 48) | (b3 << 40) | (b4 << 32) + | (b5 << 24) | (b6 << 16) | (b7 << 8) | (b8)); + } + + public static void set4(byte[] array, int offset, int v) { + array[offset] = (byte) ((v >>> 24) & 0xFF); + array[offset + 1] = (byte) ((v >>> 16) & 0xFF); + array[offset + 2] = (byte) ((v >>> 8) & 0xFF); + array[offset + 3] = (byte) ((v) & 0xFF); + } +} diff --git a/minijvm/java/src/main/java/org/mini/reflect/vm/LambdaUtil.java b/minijvm/java/src/main/java/org/mini/vm/LambdaUtil.java similarity index 97% rename from minijvm/java/src/main/java/org/mini/reflect/vm/LambdaUtil.java rename to minijvm/java/src/main/java/org/mini/vm/LambdaUtil.java index 4a545ea5b..3c28a8893 100644 --- a/minijvm/java/src/main/java/org/mini/reflect/vm/LambdaUtil.java +++ b/minijvm/java/src/main/java/org/mini/vm/LambdaUtil.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package org.mini.reflect.vm; +package org.mini.vm; import org.mini.reflect.ReflectMethod; diff --git a/minijvm/java/src/main/java/org/mini/vm/PrintVersion.java b/minijvm/java/src/main/java/org/mini/vm/PrintVersion.java new file mode 100644 index 000000000..2a83520da --- /dev/null +++ b/minijvm/java/src/main/java/org/mini/vm/PrintVersion.java @@ -0,0 +1,11 @@ +package org.mini.vm; + +public class PrintVersion { + public static void main(String[] args) { + + System.out.println("minijvm version \"" + System.getProperty("java.version") + "\""); + System.out.println("minijvm SE Runtime Environment (" + System.getProperty("java.version") + "-b01)"); + String arch = RefNative.refIdSize() == 8 ? "64" : "32"; + System.out.println("minijvm " + arch + "-Bit Server VM (build 1.0-b01, mixed mode)"); + } +} diff --git a/minijvm/java/src/main/java/org/mini/reflect/vm/RConst.java b/minijvm/java/src/main/java/org/mini/vm/RConst.java similarity index 96% rename from minijvm/java/src/main/java/org/mini/reflect/vm/RConst.java rename to minijvm/java/src/main/java/org/mini/vm/RConst.java index 4bf37aa43..98faae632 100644 --- a/minijvm/java/src/main/java/org/mini/reflect/vm/RConst.java +++ b/minijvm/java/src/main/java/org/mini/vm/RConst.java @@ -1,79 +1,79 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.mini.reflect.vm; - -/** - * - * @author gust - */ -public class RConst { - - static public final int ACC_PUBLIC = 0x0001; - static public final int ACC_PRIVATE = 0x0002; - static public final int ACC_PROTECTED = 0x0004; - static public final int ACC_STATIC = 0x0008; - static public final int ACC_FINAL = 0x0010; - static public final int ACC_SYNCHRONIZED = 0x0020; - static public final int ACC_VOLATILE = 0x0040; - static public final int ACC_TRANSIENT = 0x0080; - static public final int ACC_NATIVE = 0x0100; - static public final int ACC_INTERFACE = 0x0200; - static public final int ACC_ABSTRACT = 0x0400; - static public final int ACC_STRICT = 0x0800; - - public static final byte TAG_ARRAY = 91; // '[' - an array object (objectID size). - public static final byte TAG_BYTE = 66; // 'B' - a byte TAG_value (1 byte). - public static final byte TAG_CHAR = 67; // 'C' - a character value (2 bytes). - public static final byte TAG_OBJECT = 76; // 'L' - an object (objectID size). - public static final byte TAG_FLOAT = 70; // 'F' - a float value (4 bytes). - public static final byte TAG_DOUBLE = 68; // 'D' - a double value (8 bytes). - public static final byte TAG_INT = 73; // 'I' - an int value (4 bytes). - public static final byte TAG_LONG = 74; // 'J' - a long value (8 bytes). - public static final byte TAG_SHORT = 83; // 'S' - a short value (2 bytes). - public static final byte TAG_VOID = 86; // 'V' - a void value (no bytes). - public static final byte TAG_BOOLEAN = 90; // 'Z' - a boolean value (1 byte). - public static final byte TAG_STRING = 115; // 's' - a String object (objectID size). - public static final byte TAG_THREAD = 116; // 't' - a Thread object (objectID size). - public static final byte TAG_THREAD_GROUP = 103; // 'g' - a ThreadGroup object (objectID size). - public static final byte TAG_CLASS_LOADER = 108; // 'l' - a ClassLoader object (objectID size). - public static final byte TAG_CLASS_OBJECT = 99; // 'c' - a class object object (objectID size). - - public static char getBytes(byte type) { - char bytes = '0'; - switch (type) { - case TAG_BYTE: - case TAG_BOOLEAN: - bytes = '1'; - break; - case TAG_SHORT: - case TAG_CHAR: - bytes = '2'; - break; - case TAG_INT: - case TAG_FLOAT: - bytes = '4'; - break; - case TAG_LONG: - case TAG_DOUBLE: - bytes = '8'; - break; - case TAG_ARRAY: - case TAG_OBJECT: - case TAG_STRING: - case TAG_THREAD: - case TAG_THREAD_GROUP: - case TAG_CLASS_LOADER: - case TAG_CLASS_OBJECT: - bytes = 'R'; - break; - case TAG_VOID: - bytes = '0'; - break; - } - return bytes; - - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.mini.vm; + +/** + * + * @author gust + */ +public class RConst { + + static public final int ACC_PUBLIC = 0x0001; + static public final int ACC_PRIVATE = 0x0002; + static public final int ACC_PROTECTED = 0x0004; + static public final int ACC_STATIC = 0x0008; + static public final int ACC_FINAL = 0x0010; + static public final int ACC_SYNCHRONIZED = 0x0020; + static public final int ACC_VOLATILE = 0x0040; + static public final int ACC_TRANSIENT = 0x0080; + static public final int ACC_NATIVE = 0x0100; + static public final int ACC_INTERFACE = 0x0200; + static public final int ACC_ABSTRACT = 0x0400; + static public final int ACC_STRICT = 0x0800; + + public static final byte TAG_ARRAY = 91; // '[' - an array object (objectID size). + public static final byte TAG_BYTE = 66; // 'B' - a byte TAG_value (1 byte). + public static final byte TAG_CHAR = 67; // 'C' - a character value (2 bytes). + public static final byte TAG_OBJECT = 76; // 'L' - an object (objectID size). + public static final byte TAG_FLOAT = 70; // 'F' - a float value (4 bytes). + public static final byte TAG_DOUBLE = 68; // 'D' - a double value (8 bytes). + public static final byte TAG_INT = 73; // 'I' - an int value (4 bytes). + public static final byte TAG_LONG = 74; // 'J' - a long value (8 bytes). + public static final byte TAG_SHORT = 83; // 'S' - a short value (2 bytes). + public static final byte TAG_VOID = 86; // 'V' - a void value (no bytes). + public static final byte TAG_BOOLEAN = 90; // 'Z' - a boolean value (1 byte). + public static final byte TAG_STRING = 115; // 's' - a String object (objectID size). + public static final byte TAG_THREAD = 116; // 't' - a Thread object (objectID size). + public static final byte TAG_THREAD_GROUP = 103; // 'g' - a ThreadGroup object (objectID size). + public static final byte TAG_CLASS_LOADER = 108; // 'l' - a ClassLoader object (objectID size). + public static final byte TAG_CLASS_OBJECT = 99; // 'c' - a class object object (objectID size). + + public static char getBytes(byte type) { + char bytes = '0'; + switch (type) { + case TAG_BYTE: + case TAG_BOOLEAN: + bytes = '1'; + break; + case TAG_SHORT: + case TAG_CHAR: + bytes = '2'; + break; + case TAG_INT: + case TAG_FLOAT: + bytes = '4'; + break; + case TAG_LONG: + case TAG_DOUBLE: + bytes = '8'; + break; + case TAG_ARRAY: + case TAG_OBJECT: + case TAG_STRING: + case TAG_THREAD: + case TAG_THREAD_GROUP: + case TAG_CLASS_LOADER: + case TAG_CLASS_OBJECT: + bytes = 'R'; + break; + case TAG_VOID: + bytes = '0'; + break; + } + return bytes; + + } +} diff --git a/minijvm/java/src/main/java/org/mini/reflect/vm/RefNative.java b/minijvm/java/src/main/java/org/mini/vm/RefNative.java similarity index 96% rename from minijvm/java/src/main/java/org/mini/reflect/vm/RefNative.java rename to minijvm/java/src/main/java/org/mini/vm/RefNative.java index 10ab35a42..2e17a9df5 100644 --- a/minijvm/java/src/main/java/org/mini/reflect/vm/RefNative.java +++ b/minijvm/java/src/main/java/org/mini/vm/RefNative.java @@ -1,109 +1,109 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.mini.reflect.vm; - -import java.net.URL; - -/** - * @author gust - */ -public class RefNative { - - - public static native int refIdSize(); - - public static native long obj2id(Object o); - - public static native Object id2obj(long objId); - - public static native Class[] getClasses(); - - public static native Class getBootstrapClassByName(String className);//only get bootstrap class, other return null - - public static native int setLocalVal(long frame, int slot, byte type, long value, int bytes); - - public static native int getLocalVal(long frame, int slot, ValueType val); - - public static native Object newWithoutInit(Class cl); - - //thread method - static public native Thread[] getThreads(); - - static public native int getStatus(Thread t); - - static public native int suspendThread(Thread t); - - static public native int resumeThread(Thread t); - - static public native int getSuspendCount(Thread t); - - static public native int getFrameCount(Thread t); - - static public native int stopThread(Thread t, long objid); - - static public native long getStackFrame(Thread t); - - // - public static native int getGarbageMarkCounter(); - - public static native int getGarbageStatus(); - - public static native Class defineClass(ClassLoader cloader, String name, byte[] bytecodes, int offset, int length); - - public static native void addJarToClasspath(String jarFullPath); - - public static native Class findLoadedClass0(ClassLoader loader, String name); - - public static native URL findResource0(ClassLoader loader, String path); - - // - // - public static native long heap_calloc(int capacity); - - public static native void heap_free(long memAddr); - - public static native void heap_put_byte(long memAddr, int byteIndex, byte value); - - public static native byte heap_get_byte(long memAddr, int byteIndex); - - public static native void heap_put_short(long memAddr, int byteIndex, short value); - - public static native short heap_get_short(long memAddr, int byteIndex); - - public static native void heap_put_int(long memAddr, int byteIndex, int value); - - public static native int heap_get_int(long memAddr, int byteIndex); - - public static native void heap_put_long(long memAddr, int byteIndex, long value); - - public static native long heap_get_long(long memAddr, int byteIndex); - - public static native void heap_put_float(long memAddr, int byteIndex, float value); - - public static native float heap_get_float(long memAddr, int byteIndex); - - public static native void heap_put_double(long memAddr, int byteIndex, double value); - - public static native double heap_get_double(long memAddr, int byteIndex); - - public static native void heap_put_ref(long memAddr, int byteIndex, Object value); - - public static native Object heap_get_ref(long memAddr, int byteIndex); - - public static native void heap_copy(long srcMemAddr, int srcPos, long destMemAddr, int destPos, int length); - - public static native int heap_bin_search(long srcMemAddr, int srcLen, long keyMemAddr, int keyLen); - - public static native void heap_fill(long srcMemAddr, int srcLen, long valMemAddr, int valLen); - - public static native int heap_endian(); - - public static native Class getCallerClass(); - - public static native void initNativeClassLoader(ClassLoader cloader, ClassLoader parent); - - public static native void destroyNativeClassLoader(ClassLoader cloader); -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.mini.vm; + +import java.net.URL; + +/** + * @author gust + */ +public class RefNative { + + + public static native int refIdSize(); + + public static native long obj2id(Object o); + + public static native Object id2obj(long objId); + + public static native Class[] getClasses(); + + public static native Class getBootstrapClassByName(String className);//only get bootstrap class, other return null + + public static native int setLocalVal(long frame, int slot, byte type, long value, int bytes); + + public static native int getLocalVal(long frame, int slot, ValueType val); + + public static native Object newWithoutInit(Class cl); + + //thread method + static public native Thread[] getThreads(); + + static public native int getStatus(Thread t); + + static public native int suspendThread(Thread t); + + static public native int resumeThread(Thread t); + + static public native int getSuspendCount(Thread t); + + static public native int getFrameCount(Thread t); + + static public native int stopThread(Thread t, long objid); + + static public native long getStackFrame(Thread t); + + // + public static native int getGarbageMarkCounter(); + + public static native int getGarbageStatus(); + + public static native Class defineClass(ClassLoader cloader, String name, byte[] bytecodes, int offset, int length); + + public static native void addJarToClasspath(String jarFullPath); + + public static native Class findLoadedClass0(ClassLoader loader, String name); + + public static native URL findResource0(ClassLoader loader, String path); + + // + // + public static native long heap_calloc(int capacity); + + public static native void heap_free(long memAddr); + + public static native void heap_put_byte(long memAddr, int byteIndex, byte value); + + public static native byte heap_get_byte(long memAddr, int byteIndex); + + public static native void heap_put_short(long memAddr, int byteIndex, short value); + + public static native short heap_get_short(long memAddr, int byteIndex); + + public static native void heap_put_int(long memAddr, int byteIndex, int value); + + public static native int heap_get_int(long memAddr, int byteIndex); + + public static native void heap_put_long(long memAddr, int byteIndex, long value); + + public static native long heap_get_long(long memAddr, int byteIndex); + + public static native void heap_put_float(long memAddr, int byteIndex, float value); + + public static native float heap_get_float(long memAddr, int byteIndex); + + public static native void heap_put_double(long memAddr, int byteIndex, double value); + + public static native double heap_get_double(long memAddr, int byteIndex); + + public static native void heap_put_ref(long memAddr, int byteIndex, Object value); + + public static native Object heap_get_ref(long memAddr, int byteIndex); + + public static native void heap_copy(long srcMemAddr, int srcPos, long destMemAddr, int destPos, int length); + + public static native int heap_bin_search(long srcMemAddr, int srcLen, long keyMemAddr, int keyLen); + + public static native void heap_fill(long srcMemAddr, int srcLen, long valMemAddr, int valLen); + + public static native int heap_endian(); + + public static native Class getCallerClass(); + + public static native void initNativeClassLoader(ClassLoader cloader, ClassLoader parent); + + public static native void destroyNativeClassLoader(ClassLoader cloader); +} diff --git a/minijvm/java/src/main/java/org/mini/reflect/vm/ValueType.java b/minijvm/java/src/main/java/org/mini/vm/ValueType.java similarity index 90% rename from minijvm/java/src/main/java/org/mini/reflect/vm/ValueType.java rename to minijvm/java/src/main/java/org/mini/vm/ValueType.java index bf1717a3a..8e3ea6819 100644 --- a/minijvm/java/src/main/java/org/mini/reflect/vm/ValueType.java +++ b/minijvm/java/src/main/java/org/mini/vm/ValueType.java @@ -1,28 +1,28 @@ - -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.mini.reflect.vm; - -/** - * - * @author gust - */ -public class ValueType { - - public byte type; - public long value; - public char bytes; - - public ValueType(byte type) { - this.type = type; - bytes = RConst.getBytes(type); - } - - - public String toString() { - return (char) type + "|" + bytes + "|" + Long.toString(value, 16); - } + +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.mini.vm; + +/** + * + * @author gust + */ +public class ValueType { + + public byte type; + public long value; + public char bytes; + + public ValueType(byte type) { + this.type = type; + bytes = RConst.getBytes(type); + } + + + public String toString() { + return (char) type + "|" + bytes + "|" + Long.toString(value, 16); + } } \ No newline at end of file diff --git a/minijvm/java/src/main/java/org/mini/reflect/Launcher.java b/minijvm/java/src/main/java/org/mini/vm/VmUtil.java similarity index 50% rename from minijvm/java/src/main/java/org/mini/reflect/Launcher.java rename to minijvm/java/src/main/java/org/mini/vm/VmUtil.java index e0643b3ab..94dd85592 100644 --- a/minijvm/java/src/main/java/org/mini/reflect/Launcher.java +++ b/minijvm/java/src/main/java/org/mini/vm/VmUtil.java @@ -1,99 +1,12 @@ -package org.mini.reflect; +package org.mini.vm; -import org.mini.reflect.vm.RefNative; import org.mini.zip.Zip; import java.io.File; import java.io.RandomAccessFile; import java.net.URL; -public class Launcher { - - static ExtClassLoader extcl = new ExtClassLoader(null); - static ClassLoader systemClassLoader = new AppClassLoader(extcl); - - /** - * the console application main class loader - */ - static public class AppClassLoader extends ClassLoader { - String[] paths; - - public AppClassLoader(ClassLoader p) { - super(p); - String s = System.getProperty("java.class.path"); - paths = s.split(File.pathSeparator); - //for (String ps : paths) System.out.println("AppCL:" + ps); - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - - // 加载D盘根目录下指定类名的class - String classname = name.replace('.', '/') + ".class"; - byte[] classData = Launcher.getFileData(classname, paths); - if (classData == null) { - throw new ClassNotFoundException(name); - } else { - return defineClass(name, classData, 0, classData.length); - } - } - - protected URL findResource(String path) { - URL url = Launcher.getFileUrl(path, paths); - return url; - } - } - - /** - * the jvm runtime class loader - */ - static public class ExtClassLoader extends ClassLoader { - String[] paths; - - public ExtClassLoader(ClassLoader parent) { - String s = System.getProperty("sun.boot.class.path"); - paths = s.split(File.pathSeparator); - //for (String ps : paths) System.out.println("ExtCL:" + ps); - } - - protected Class findClass(String name) throws ClassNotFoundException { - return RefNative.getBootstrapClassByName(name); - } - - protected URL findResource(String path) { - URL url = Launcher.getFileUrl(path, paths); - return url; - } - } - - //======================================================================= - - public static ExtClassLoader getExtClassLoader() { - return extcl; - } - - public static ClassLoader getSystemClassLoader() { - return systemClassLoader; - } - - public static String getBootstrapClassPath() { - return System.getProperty("sun.boot.class.path"); - } - - /** - * this method is used for vm - * - * @param name - * @param classLoader - * @return - * @throws ClassNotFoundException - */ - static Class loadClass(String name, ClassLoader classLoader) throws ClassNotFoundException { - name = name.replace('/', '.'); - Class c = (classLoader == null ? getSystemClassLoader() : classLoader).loadClass(name); - return c; - } - +public class VmUtil { /** * find a file bytes from classes paths * diff --git a/minijvm/java/src/main/java/sun/misc/Launcher.java b/minijvm/java/src/main/java/sun/misc/Launcher.java new file mode 100644 index 000000000..95024d405 --- /dev/null +++ b/minijvm/java/src/main/java/sun/misc/Launcher.java @@ -0,0 +1,96 @@ +package sun.misc; + +import org.mini.vm.RefNative; +import org.mini.vm.VmUtil; + +import java.io.File; +import java.net.URL; + +public class Launcher { + + static ExtClassLoader extcl = new ExtClassLoader(null); + static ClassLoader systemClassLoader = new AppClassLoader(extcl); + + /** + * the console application main class loader + */ + static public class AppClassLoader extends ClassLoader { + String[] paths; + + public AppClassLoader(ClassLoader p) { + super(p); + String s = System.getProperty("java.class.path"); + paths = s.split(File.pathSeparator); + //for (String ps : paths) System.out.println("AppCL:" + ps); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + + // 加载D盘根目录下指定类名的class + String classname = name.replace('.', '/') + ".class"; + byte[] classData = VmUtil.getFileData(classname, paths); + if (classData == null) { + throw new ClassNotFoundException(name); + } else { + return defineClass(name, classData, 0, classData.length); + } + } + + protected URL findResource(String path) { + URL url = VmUtil.getFileUrl(path, paths); + return url; + } + } + + /** + * the jvm runtime class loader + */ + static public class ExtClassLoader extends ClassLoader { + String[] paths; + + public ExtClassLoader(ClassLoader parent) { + String s = System.getProperty("sun.boot.class.path"); + paths = s.split(File.pathSeparator); + //for (String ps : paths) System.out.println("ExtCL:" + ps); + } + + protected Class findClass(String name) throws ClassNotFoundException { + return RefNative.getBootstrapClassByName(name); + } + + protected URL findResource(String path) { + URL url = VmUtil.getFileUrl(path, paths); + return url; + } + } + + //======================================================================= + + public static ExtClassLoader getExtClassLoader() { + return extcl; + } + + public static ClassLoader getSystemClassLoader() { + return systemClassLoader; + } + + public static String getBootstrapClassPath() { + return System.getProperty("sun.boot.class.path"); + } + + /** + * this method is used for vm + * + * @param name + * @param classLoader + * @return + * @throws ClassNotFoundException + */ + static Class loadClass(String name, ClassLoader classLoader) throws ClassNotFoundException { + name = name.replace('/', '.'); + Class c = (classLoader == null ? getSystemClassLoader() : classLoader).loadClass(name); + return c; + } + +} diff --git a/minijvm/java/src/main/java/sun/misc/Unsafe.java b/minijvm/java/src/main/java/sun/misc/Unsafe.java index 6dad87d96..2ef460492 100755 --- a/minijvm/java/src/main/java/sun/misc/Unsafe.java +++ b/minijvm/java/src/main/java/sun/misc/Unsafe.java @@ -10,8 +10,8 @@ package sun.misc; -import org.mini.reflect.vm.RConst; -import org.mini.reflect.vm.RefNative; +import org.mini.vm.RConst; +import org.mini.vm.RefNative; import java.lang.reflect.Field; diff --git a/minijvm/java/src/main/resource/sys.properties b/minijvm/java/src/main/resource/sys.properties index 91a636f7b..3af707c05 100644 --- a/minijvm/java/src/main/resource/sys.properties +++ b/minijvm/java/src/main/resource/sys.properties @@ -5,7 +5,7 @@ file.encoding=utf-8 java.class.path=jvm_set_value : classpath jvm startup with -cp java.home= java.vendor=org.minijvm -java.vendor.url= +java.vendor.url=https://github.com/digitalgust/miniJVM java.version=1.0 line.separator=jvm_set_value: posix="\n" windows="\r\n" os.arch= diff --git a/mobile/java/glfm_gui/pom.xml b/mobile/java/glfm_gui/pom.xml index 813da4250..6ee0c199c 100755 --- a/mobile/java/glfm_gui/pom.xml +++ b/mobile/java/glfm_gui/pom.xml @@ -8,7 +8,7 @@ io.github.digitalgust glfm_gui ${project.groupId}:${project.artifactId} - 1.1.3 + 1.1.4 miniJVM mobile platform gui library https://github.com/digitalgust/miniJVM @@ -144,7 +144,7 @@ io.github.digitalgust minijvm_rt - 1.1.2 + 1.1.3