├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── README_en.md ├── docs └── CONTRIBUTING.md ├── src └── autorun │ ├── jdk │ ├── lang │ │ └── reflect │ │ │ └── Reflect.md │ └── tools │ │ ├── HSDB.md │ │ ├── HSDIS.md │ │ ├── JDB.md │ │ ├── JINFO.md │ │ ├── JITWATCH.md │ │ ├── JMAP.md │ │ ├── JPS.md │ │ ├── JSADEBUGD.md │ │ ├── JSTACK.md │ │ ├── JSTAT.md │ │ └── img │ │ └── jinfo │ │ ├── jinfo_flags1.png │ │ └── jinfo_sysprops1.png │ ├── jvm │ ├── bytecode │ │ └── BYTE_CODE.md │ ├── catalog │ │ ├── back.md │ │ ├── catalog.md │ │ └── img │ │ │ └── catalog.png │ ├── classfile │ │ └── Classfile_Parser.md │ ├── enviment │ │ ├── ENVIMENT_INIT.md │ │ ├── IDE_DEBUG.md │ │ └── img │ │ │ ├── build_succ.png │ │ │ ├── config_succ.png │ │ │ ├── ide_debug_ec_1.png │ │ │ ├── ide_debug_ec_2.png │ │ │ ├── ide_debug_ec_3.png │ │ │ ├── ide_debug_ec_4.png │ │ │ └── languages_label.png │ ├── jit │ │ └── JIT1.md │ ├── jni │ │ ├── HelloJni.cpp │ │ ├── HelloJni.h │ │ ├── HelloJni.java │ │ ├── JNIEnvAPI.md │ │ ├── JNI_INIT.md │ │ ├── README.md │ │ ├── base │ │ │ ├── jawt_md.h │ │ │ ├── jni.h │ │ │ └── jni_md.h │ │ ├── build_jni.sh │ │ └── img │ │ │ └── JNI_INIT_process.png │ ├── jvmti │ │ ├── JVMTI.md │ │ ├── README.md │ │ ├── antimodule │ │ │ └── antimodule.cpp │ │ ├── faketime │ │ │ └── faketime.cpp │ │ ├── heapsampler │ │ │ └── heapsampler.cpp │ │ ├── jvmti.h │ │ ├── methodCalledCount │ │ │ └── methodCalledCount.cpp │ │ ├── richNPE │ │ │ └── richNPE.cpp │ │ ├── stackframe │ │ │ ├── StackFrame.java │ │ │ └── stackframe.cpp │ │ └── vmtrace │ │ │ └── vmtrace.cpp │ ├── mem_pool │ │ └── MEMORY_POOL_INIT.md │ ├── method │ │ ├── CALL_STUB.md │ │ ├── JAVA_CALLS.md │ │ └── imgs │ │ │ ├── java_calls_1.png │ │ │ └── java_type_mapping_c_type.png │ ├── oop │ │ ├── Compressed_Oops.md │ │ ├── Klass.md │ │ ├── Memory_Weave.md │ │ ├── OOP.md │ │ └── img │ │ │ ├── compressed_oops_1.png │ │ │ ├── compressed_oops_2.png │ │ │ ├── gt1.8.jpg │ │ │ ├── lt1.7.png │ │ │ ├── object_header.png │ │ │ └── object_store.png │ └── start │ │ ├── README.md │ │ ├── README2.md │ │ ├── README3.md │ │ ├── README4.md │ │ └── img │ │ └── jvm启动流程图1.png │ └── other │ └── tools │ ├── GDB.md │ ├── NM.md │ └── TOP.md └── test └── autorun └── jvm └── jni ├── HelloJni.java └── HelloJniTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea 3 | .DS_Store 4 | target 5 | /dist/ 6 | *.class 7 | cmake-build-debug 8 | *.out 9 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | project(jvm_study) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | include_directories("$JAVA_HOME/include") 7 | add_executable(jvm_study 8 | src/autorun/jvm/jni/HelloJni.h src/autorun/jvm/jni/HelloJni.cpp 9 | # src/autorun/jvm/jni/base/jni.h src/autorun/jvm/jni/base/jni_md.h 10 | ) 11 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | https://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | https://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jvm-study 2 | ## jvm-study是什么 3 | 4 | > 这是一个学习JVM源码的仓库. 通过这个仓库,可以学习到JVM相关的知识. 5 | 6 | ## jvm 学习大纲 7 | 8 | ### 1. 编译JVM 9 | * [x] [1.1 OpenJDK编译教程](src/autorun/jvm/enviment/ENVIMENT_INIT.md) 10 | * [x] [1.2 配置调试环境](src/autorun/jvm/enviment/IDE_DEBUG.md)
11 | 12 | ### 2. JNI 13 | * [x] [2.1 初识JNI](src/autorun/jvm/jni/README.md)
14 | * [x] [2.2 JNIEnv相关API](src/autorun/jvm/jni/JNIEnvAPI.md)
15 | * [x] [2.3 JNI初始化过程](src/autorun/jvm/jni/JNI_INIT.md) 16 | 17 | ### 3. jvm启动流程剖析 18 | * [x] [3.1 jvm启动流程1](src/autorun/jvm/start/README.md)
19 | * [ ] [3.2 jvm启动流程2](src/autorun/jvm/start/README2.md)
20 | * [ ] [3.3 jvm启动流程3](src/autorun/jvm/start/README3.md)
21 | * [ ] [3.4 jvm启动流程4](src/autorun/jvm/start/README4.md)
22 | 23 | ### 4. 面向对象OOP模型 24 | * [ ] [4.1 OOP KLASS模型](src/autorun/jvm/oop/OOP.md)
25 | * [ ] [4.2 指针压缩](src/autorun/jvm/oop/Compressed_Oops.md)
26 | * [ ] [4.3 内存编织](src/autorun/jvm/oop/Memory_Weave.md)
27 | 28 | ### 5. 方法调用 29 | * [ ] [5.1 CallStub栈帧的创建](src/autorun/jvm/method/CALL_STUB.md)
30 | * [ ] [5.2 Java方法调用过程](src/autorun/jvm/method/JAVA_CALLS.md)
31 | 32 | ### 6. JVMTI 33 | * [x] [6.1 初识JVMTI](src/autorun/jvm/jvmti/JVMTI.md) 34 | * [x] [6.2 使用JVMTI扩展NPE](src/autorun/jvm/jvmti/richNPE/richNPE.cpp) JEP358[^1] 35 | * [x] [6.3 使用JVMTI统计每个方法的调用次数](src/autorun/jvm/jvmti/methodCalledCount/methodCalledCount.cpp) 36 | ## 工具篇 37 | ### 1. JDK自带工具 38 | * [X] [1.1 JINFO查看及修改运行时参数](src/autorun/jdk/tools/JINFO.md)
39 | * [ ] [1.2 JSTACK线程相关都靠我](src/autorun/jdk/tools/JSTACK.md)
40 | 41 | ## Contributing 42 | 43 | 如果您希望为本项目做出贡献,您可以在这里找到更多信息. 我们感谢您做的出任何贡献. 44 | 45 | [^1]: https://openjdk.java.net/jeps/358 46 | 47 | -------------------------------------------------------------------------------- /README_en.md: -------------------------------------------------------------------------------- 1 | # jvm-study 2 | ## What is the jvm-study? 3 | 4 | > This is a repository for learning JVM source code. Through this repository, you can learn JVM related knowledge. 5 | 6 | ## JVM Study Outline 7 | 8 | ### 1. Compile JVM 9 | * [x] [1.1 OpenJDK Compile Tutorial](src/autorun/jvm/enviment/ENVIMENT_INIT.md) 10 | * [x] [1.2 Configuring the debugging environment](src/autorun/jvm/enviment/IDE_DEBUG.md)
11 | 12 | ### 2. JNI(Java Native Interface) 13 | * [x] [2.1 Learn about JNI](src/autorun/jvm/jni/README.md)
14 | * [x] [2.2 JNIEnv API](src/autorun/jvm/jni/JNIEnvAPI.md)
15 | * [x] [2.3 JNI Initialization process](src/autorun/jvm/jni/JNI_INIT.md) 16 | 17 | ### 3. JVM Start-up process profiling 18 | * [x] [3.1 JVM Start-up process 1](src/autorun/jvm/start/README.md)
19 | * [ ] [3.2 JVM Start-up process 2](src/autorun/jvm/start/README2.md)
20 | * [ ] [3.3 JVM Start-up process 3](src/autorun/jvm/start/README3.md)
21 | * [ ] [3.4 JVM Start-up process 4](src/autorun/jvm/start/README4.md)
22 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 向jvm-study贡献代码 2 | 3 | ## 我们欢迎所有的贡献 4 | 5 | - 任何与Java相关的内容(包括并限于JVM) 6 | 7 | ## 先决条件 8 | 9 | - 熟悉[Git](https://git-scm.com/)
10 | 11 | ## 贡献内容 12 | 13 | 如果想要贡献内容,您可以提交一个pull request. 14 | 15 | 关于什么是`pr`, 请参考这篇文章 [文章1](https://www.jianshu.com/p/a31a888ac46b) 16 | [文章2](https://blog.csdn.net/qq_33429968/article/details/62219783) 17 | 18 | 如果是命令行玩家请参考此文章: [命令行如何提交pr](http://www.ruanyifeng.com/blog/2017/07/pull_request.html) 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/autorun/jdk/lang/reflect/Reflect.md: -------------------------------------------------------------------------------- 1 | # 反射知识点 2 | 3 | ```java 4 | String val = System.getProperty("sun.reflect.noInflation"); 5 | if (val != null && val.equals("true")) { 6 | 7 | sun.reflect.ReflectionFactory#newMethodAccessor 8 | if (noInflation) { 9 | // ASM 生成字节码 10 | sun.reflect.MethodAccessorGenerator#generate 11 | } else { 12 | sun.reflect.NativeMethodAccessorImpl#NativeMethodAccessorImpl 13 | 14 | } 15 | ``` 16 | 17 | > c++ invoke 实现 18 | ```c++ 19 | JVM_ENTRY(jobject, JVM_InvokeMethod(JNIEnv *env, jobject method, jobject obj, jobjectArray args0)) 20 | Handle method_handle; 21 | if (thread->stack_overflow_state()->stack_available((address) &method_handle) >= JVMInvokeMethodSlack) { 22 | method_handle = Handle(THREAD, JNIHandles::resolve(method)); 23 | Handle receiver(THREAD, JNIHandles::resolve(obj)); 24 | objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0))); 25 | oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL); 26 | jobject res = JNIHandles::make_local(THREAD, result); 27 | if (JvmtiExport::should_post_vm_object_alloc()) { 28 | oop ret_type = java_lang_reflect_Method::return_type(method_handle()); 29 | assert(ret_type != NULL, "sanity check: ret_type oop must not be NULL!"); 30 | if (java_lang_Class::is_primitive(ret_type)) { 31 | // Only for primitive type vm allocates memory for java object. 32 | // See box() method. 33 | JvmtiExport::post_vm_object_alloc(thread, result); 34 | } 35 | } 36 | return res; 37 | } else { 38 | THROW_0(vmSymbols::java_lang_StackOverflowError()); 39 | } 40 | JVM_END 41 | ``` 42 | 43 | > Reflection.invoke_method 实现 44 | ```c++ 45 | oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS) { 46 | oop mirror = java_lang_reflect_Method::clazz(method_mirror); 47 | int slot = java_lang_reflect_Method::slot(method_mirror); 48 | bool override = java_lang_reflect_Method::override(method_mirror) != 0; 49 | objArrayHandle ptypes(THREAD, objArrayOop(java_lang_reflect_Method::parameter_types(method_mirror))); 50 | 51 | oop return_type_mirror = java_lang_reflect_Method::return_type(method_mirror); 52 | BasicType rtype; 53 | if (java_lang_Class::is_primitive(return_type_mirror)) { 54 | rtype = basic_type_mirror_to_basic_type(return_type_mirror, CHECK_NULL); 55 | } else { 56 | rtype = T_OBJECT; 57 | } 58 | // 找instanceKlass 59 | instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(mirror)); 60 | // 通过slot定位method指针地址 61 | Method* m = klass->method_with_idnum(slot); 62 | if (m == NULL) { 63 | THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke"); 64 | } 65 | // 将method指针包装成handle对象 66 | methodHandle method(THREAD, m); 67 | 68 | // 发起调用 69 | return invoke(klass, method, receiver, override, ptypes, rtype, args, true, THREAD); 70 | } 71 | ``` 72 | 73 | > invoke实现 74 | ```c++ 75 | oop Reflection::invoke(instanceKlassHandle klass, methodHandle reflected_method, 76 | Handle receiver, bool override, objArrayHandle ptypes, 77 | BasicType rtype, objArrayHandle args, bool is_method_invoke, TRAPS) { 78 | ResourceMark rm(THREAD); 79 | 80 | methodHandle method; // actual method to invoke 81 | KlassHandle target_klass; // target klass, receiver's klass for non-static 82 | 83 | // Ensure klass is initialized 84 | klass->initialize(CHECK_NULL); 85 | 86 | bool is_static = reflected_method->is_static(); 87 | if (is_static) { 88 | // ignore receiver argument 89 | method = reflected_method; 90 | target_klass = klass; 91 | } else { 92 | // check for null receiver 93 | if (receiver.is_null()) { 94 | THROW_0(vmSymbols::java_lang_NullPointerException()); 95 | } 96 | // Check class of receiver against class declaring method 97 | if (!receiver->is_a(klass())) { 98 | THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "object is not an instance of declaring class"); 99 | } 100 | // target klass is receiver's klass 101 | target_klass = KlassHandle(THREAD, receiver->klass()); 102 | // no need to resolve if method is private or 103 | if (reflected_method->is_private() || reflected_method->name() == vmSymbols::object_initializer_name()) { 104 | method = reflected_method; 105 | } else { 106 | // resolve based on the receiver 107 | if (reflected_method->method_holder()->is_interface()) { 108 | // resolve interface call 109 | if (ReflectionWrapResolutionErrors) { 110 | // new default: 6531596 111 | // Match resolution errors with those thrown due to reflection inlining 112 | // Linktime resolution & IllegalAccessCheck already done by Class.getMethod() 113 | method = resolve_interface_call(klass, reflected_method, target_klass, receiver, THREAD); 114 | if (HAS_PENDING_EXCEPTION) { 115 | // Method resolution threw an exception; wrap it in an InvocationTargetException 116 | oop resolution_exception = PENDING_EXCEPTION; 117 | CLEAR_PENDING_EXCEPTION; 118 | JavaCallArguments args(Handle(THREAD, resolution_exception)); 119 | THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), 120 | vmSymbols::throwable_void_signature(), 121 | &args); 122 | } 123 | } else { 124 | method = resolve_interface_call(klass, reflected_method, target_klass, receiver, CHECK_(NULL)); 125 | } 126 | } else { 127 | // if the method can be overridden, we resolve using the vtable index. 128 | assert(!reflected_method->has_itable_index(), ""); 129 | int index = reflected_method->vtable_index(); 130 | method = reflected_method; 131 | if (index != Method::nonvirtual_vtable_index) { 132 | // target_klass might be an arrayKlassOop but all vtables start at 133 | // the same place. The cast is to avoid virtual call and assertion. 134 | InstanceKlass* inst = (InstanceKlass*)target_klass(); 135 | method = methodHandle(THREAD, inst->method_at_vtable(index)); 136 | } 137 | if (!method.is_null()) { 138 | // Check for abstract methods as well 139 | if (method->is_abstract()) { 140 | // new default: 6531596 141 | if (ReflectionWrapResolutionErrors) { 142 | ResourceMark rm(THREAD); 143 | Handle h_origexception = Exceptions::new_exception(THREAD, 144 | vmSymbols::java_lang_AbstractMethodError(), 145 | Method::name_and_sig_as_C_string(target_klass(), 146 | method->name(), 147 | method->signature())); 148 | JavaCallArguments args(h_origexception); 149 | THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), 150 | vmSymbols::throwable_void_signature(), 151 | &args); 152 | } else { 153 | ResourceMark rm(THREAD); 154 | THROW_MSG_0(vmSymbols::java_lang_AbstractMethodError(), 155 | Method::name_and_sig_as_C_string(target_klass(), 156 | method->name(), 157 | method->signature())); 158 | } 159 | } 160 | } 161 | } 162 | } 163 | } 164 | 165 | // I believe this is a ShouldNotGetHere case which requires 166 | // an internal vtable bug. If you ever get this please let Karen know. 167 | if (method.is_null()) { 168 | ResourceMark rm(THREAD); 169 | THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), 170 | Method::name_and_sig_as_C_string(klass(), 171 | reflected_method->name(), 172 | reflected_method->signature())); 173 | } 174 | 175 | 176 | // In the JDK 1.4 reflection implementation, the security check is 177 | // done at the Java level 178 | if (!(JDK_Version::is_gte_jdk14x_version() && UseNewReflection)) { 179 | 180 | // Access checking (unless overridden by Method) 181 | if (!override) { 182 | if (!(klass->is_public() && reflected_method->is_public())) { 183 | bool access = Reflection::reflect_check_access(klass(), reflected_method->access_flags(), target_klass(), is_method_invoke, CHECK_NULL); 184 | if (!access) { 185 | return NULL; // exception 186 | } 187 | } 188 | } 189 | 190 | } // !(Universe::is_gte_jdk14x_version() && UseNewReflection) 191 | assert(ptypes->is_objArray(), "just checking"); 192 | int args_len = args.is_null() ? 0 : args->length(); 193 | // Check number of arguments 194 | if (ptypes->length() != args_len) { 195 | THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "wrong number of arguments"); 196 | } 197 | 198 | // Create object to contain parameters for the JavaCall 199 | JavaCallArguments java_args(method->size_of_parameters()); 200 | 201 | if (!is_static) { 202 | java_args.push_oop(receiver); 203 | } 204 | 205 | for (int i = 0; i < args_len; i++) { 206 | oop type_mirror = ptypes->obj_at(i); 207 | oop arg = args->obj_at(i); 208 | if (java_lang_Class::is_primitive(type_mirror)) { 209 | jvalue value; 210 | BasicType ptype = basic_type_mirror_to_basic_type(type_mirror, CHECK_NULL); 211 | BasicType atype = unbox_for_primitive(arg, &value, CHECK_NULL); 212 | if (ptype != atype) { 213 | widen(&value, atype, ptype, CHECK_NULL); 214 | } 215 | switch (ptype) { 216 | case T_BOOLEAN: java_args.push_int(value.z); break; 217 | case T_CHAR: java_args.push_int(value.c); break; 218 | case T_BYTE: java_args.push_int(value.b); break; 219 | case T_SHORT: java_args.push_int(value.s); break; 220 | case T_INT: java_args.push_int(value.i); break; 221 | case T_LONG: java_args.push_long(value.j); break; 222 | case T_FLOAT: java_args.push_float(value.f); break; 223 | case T_DOUBLE: java_args.push_double(value.d); break; 224 | default: 225 | THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch"); 226 | } 227 | } else { 228 | if (arg != NULL) { 229 | Klass* k = java_lang_Class::as_Klass(type_mirror); 230 | if (!arg->is_a(k)) { 231 | THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch"); 232 | } 233 | } 234 | Handle arg_handle(THREAD, arg); // Create handle for argument 235 | java_args.push_oop(arg_handle); // Push handle 236 | } 237 | } 238 | 239 | assert(java_args.size_of_parameters() == method->size_of_parameters(), "just checking"); 240 | 241 | // All oops (including receiver) is passed in as Handles. An potential oop is returned as an 242 | // oop (i.e., NOT as an handle) 243 | JavaValue result(rtype); 244 | JavaCalls::call(&result, method, &java_args, THREAD); 245 | 246 | if (HAS_PENDING_EXCEPTION) { 247 | // Method threw an exception; wrap it in an InvocationTargetException 248 | oop target_exception = PENDING_EXCEPTION; 249 | CLEAR_PENDING_EXCEPTION; 250 | JavaCallArguments args(Handle(THREAD, target_exception)); 251 | THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), 252 | vmSymbols::throwable_void_signature(), 253 | &args); 254 | } else { 255 | if (rtype == T_BOOLEAN || rtype == T_BYTE || rtype == T_CHAR || rtype == T_SHORT) 256 | narrow((jvalue*) result.get_value_addr(), rtype, CHECK_NULL); 257 | return box((jvalue*) result.get_value_addr(), rtype, CHECK_NULL); 258 | } 259 | } 260 | ``` 261 | 262 | 263 | 264 | sun.reflect.NativeMethodAccessorImpl#invoke 265 | 266 | ```java 267 | public Object invoke(Object obj, Object[] args) 268 | throws IllegalArgumentException, InvocationTargetException 269 | { 270 | // We can't inflate methods belonging to vm-anonymous classes because 271 | // that kind of class can't be referred to by name, hence can't be 272 | // found from the generated bytecode. 273 | // 计次来判断是否使用asm生成字节码。默认15次 274 | if (++numInvocations > ReflectionFactory.inflationThreshold() 275 | && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) { 276 | MethodAccessorImpl acc = (MethodAccessorImpl) 277 | new MethodAccessorGenerator(). 278 | generateMethod(method.getDeclaringClass(), 279 | method.getName(), 280 | method.getParameterTypes(), 281 | method.getReturnType(), 282 | method.getExceptionTypes(), 283 | method.getModifiers()); 284 | parent.setDelegate(acc); 285 | } 286 | 287 | return invoke0(method, obj, args); 288 | } 289 | 290 | private static native Object invoke0(Method m, Object obj, Object[] args); 291 | ``` 292 | 293 | native好处:无需生成额外的class和类加载,减少方法区占用,直接使用klass即可 294 | 坏处:c++调用,性能相对低下 295 | 296 | cglib好处: 纯java调用,性能相对较高 297 | 坏处:需要产生额外的class,占用方法区空间,如果量太大则可能会撑爆方法区。 298 | -------------------------------------------------------------------------------- /src/autorun/jdk/tools/HSDB.md: -------------------------------------------------------------------------------- 1 | # HSDB 2 | 3 | 4 | 5 | > [jhsdb](https://docs.oracle.com/javase/9/tools/jhsdb.htm#JSWOR-GUID-0345CAEB-71CE-4D71-97FE-AA53A4AB028E) 6 | > 7 | > -------------------------------------------------------------------------------- /src/autorun/jdk/tools/HSDIS.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jdk/tools/HSDIS.md -------------------------------------------------------------------------------- /src/autorun/jdk/tools/JDB.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jdk/tools/JDB.md -------------------------------------------------------------------------------- /src/autorun/jdk/tools/JINFO.md: -------------------------------------------------------------------------------- 1 | # JInfo 使用技巧 2 | 3 | ## 命令详解 4 | ### 1. 命令描述 5 | #### 1.1 命令格式 6 | 7 | > `jinfo [ option ] pid `
8 | > `jinfo [ option ] executable core`
9 | > `jinfo [ option ] [server-id@]remote-hostname-or-IP` 10 | 11 | #### 1.2 简介 12 | > jinfo prints Java configuration information for a given Java process or core file or a remote debug server. Configuration information includes Java System properties and Java virtual machine command line flags. If the given process is running on a 64-bit VM, you may need to specify the -J-d64 option, 13 | 14 | >e.g.: jinfo -J-d64 -sysprops pid 15 | > 16 | > 参考链接 [jdk8_jinfo](https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jinfo.html#BCGEBFDD) 17 | 18 | 大意就是 `jinfo` 是java虚拟机自带的Java配置信息工具,可以为一个给定的Java进程或核心文件或一个远程调试服务器打印Java配置信息。 19 | 配置信息包括Java系统属性和Java虚拟机命令行标志。
20 | 如果给定的进程在64位虚拟机上运行,你可能需要指定 -J -d64选项,例如: jinfo -J -d64 -sysprops pid 21 | 22 | 23 | 只有 `manageable` 级别的参数才能被 `jinfo` 调整.
24 | 查询`manageable` 级别的命令 25 | > `java -XX:+PrintFlagsInitial | grep manageable` 26 | 27 | 摘自 `Zuul JDK` 28 | 29 | | type | property name | default | level | 30 | | --- | --- | --- | --- | 31 | | intx | CMSAbortablePrecleanWaitMillis | = 100 | {manageable} | 32 | | intx | CMSTriggerInterval | = -1 | {manageable} | 33 | | intx | CMSWaitDuration | = 2000 | {manageable} | 34 | | bool | HeapDumpAfterFullGC | = false | {manageable} | 35 | | bool | HeapDumpBeforeFullGC | = false | {manageable} | 36 | | bool | HeapDumpOnOutOfMemoryError | = false | {manageable} | 37 | |ccstr | HeapDumpPath | = | {manageable} | 38 | |uintx | MaxHeapFreeRatio | = 70 | {manageable} | 39 | |uintx | MinHeapFreeRatio | = 40 | {manageable} | 40 | | bool | PrintClassHistogram | = false | {manageable} | 41 | | bool | PrintClassHistogramAfterFullGC | = false | {manageable} | 42 | | bool | PrintClassHistogramBeforeFullGC | = false | {manageable} | 43 | | bool | PrintConcurrentLocks | = false | {manageable} | 44 | | bool | PrintGC | = false | {manageable} | 45 | | bool | PrintGCDateStamps | = false | {manageable} | 46 | | bool | PrintGCDetails | = false | {manageable} | 47 | | bool | PrintGCID | = false | {manageable} | 48 | | bool | PrintGCTimeStamps | = false | {manageable} | 49 | 50 | 案例1:不重启JVM使用 `jinfo` 动态调整GCLog 51 | 1. 查询进程 `PID` 52 | > `jps -l` 53 | 2. 查看当前 `PrintGCDetails` `PrintGCDateStamps` `PrintGCTimeStamps`参数的值 54 | > `jinfo -flag PrintGCDetails {pid}`
55 | > -XX:-PrintGCDetails
56 | > `jinfo -flag PrintGCDateStamps {pid}`
57 | > -XX:-PrintGCDateStamps
58 | > `jinfo -flag PrintGCTimeStamps {pid}`
59 | > -XX:-PrintGCTimeStamps
60 | 3. 使用 `jinfo` 调整 `PrintGCDetails` `PrintGCDateStamps` `PrintGCTimeStamps` 参数的值 61 | > `jinfo -flag +PrintGCDetails {pid}`
62 | > `PrintGCDateStamps` 和 `PrintGCTimeStamps` 同理
63 | 4. 使用第二步中的命令查询参数值 64 | > 会发现,参数值已经被我们动态的修改掉了。 `-XX:+PrintGCTimeStamps`
65 | 5. 在应用层触发GC, 查看修改后的效果
66 | ` [Times: user=0.00 sys=0.00, real=0.01 secs]` 67 | ```c++ 68 | Heap 69 | PSYoungGen total 76288K, used 3276K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000) 70 | eden space 65536K, 5% used [0x000000076ab00000,0x000000076ae33378,0x000000076eb00000) 71 | from space 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000) 72 | to space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000) 73 | ParOldGen total 175104K, used 370K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000) 74 | object space 175104K, 0% used [0x00000006c0000000,0x00000006c005cbf8,0x00000006cab00000) 75 | Metaspace used 2970K, capacity 4486K, committed 4864K, reserved 1056768K 76 | class space used 311K, capacity 386K, committed 512K, reserved 1048576K 77 | ``` 78 | 79 | 案例2: 输出全部的参数(OracleJdk) 80 | > option
81 | > no option 输出全部的参数和系统属性
82 | > -flag name 输出对应名称的参数
83 | > -flag [+|-]name 开启或者关闭对应名称的参数
84 | > -flag name=value 设定对应名称的参数
85 | > -flags 输出全部的参数
86 | > -sysprops 输出系统属性
87 | 88 | 1. 如案例1 查询对应的 `PID` 89 | 2. `jinfo -flags {pid}`
90 | ![](img/jinfo/jinfo_flags1.png) 91 | 92 | 案例3: 输出当前 `jvm` 进行的全部的系统属性(OracleJdk) 93 | 1. 如案例1 查询对应的 `PID` 94 | 2. `jinfo -sysprops {pid}`
95 | ![](img/jinfo/jinfo_sysprops1.png) -------------------------------------------------------------------------------- /src/autorun/jdk/tools/JITWATCH.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jdk/tools/JITWATCH.md -------------------------------------------------------------------------------- /src/autorun/jdk/tools/JMAP.md: -------------------------------------------------------------------------------- 1 | # JMAP使用技巧 -------------------------------------------------------------------------------- /src/autorun/jdk/tools/JPS.md: -------------------------------------------------------------------------------- 1 | # JPS使用技巧 -------------------------------------------------------------------------------- /src/autorun/jdk/tools/JSADEBUGD.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jdk/tools/JSADEBUGD.md -------------------------------------------------------------------------------- /src/autorun/jdk/tools/JSTACK.md: -------------------------------------------------------------------------------- 1 | # Jstack 使用技巧 2 | 3 | [参考链接](https://docs.oracle.com/javase/7/docs/technotes/tools/share/jstack.html) -------------------------------------------------------------------------------- /src/autorun/jdk/tools/JSTAT.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jdk/tools/JSTAT.md -------------------------------------------------------------------------------- /src/autorun/jdk/tools/img/jinfo/jinfo_flags1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jdk/tools/img/jinfo/jinfo_flags1.png -------------------------------------------------------------------------------- /src/autorun/jdk/tools/img/jinfo/jinfo_sysprops1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jdk/tools/img/jinfo/jinfo_sysprops1.png -------------------------------------------------------------------------------- /src/autorun/jvm/bytecode/BYTE_CODE.md: -------------------------------------------------------------------------------- 1 | # Java 字节码规范 2 | 3 | ## 1. 字节码常见指令 4 | | 操作码 | 助记符 | 释义 | 5 | | ---| --- | --- | 6 | | 00 | nop | 什么都不做| 7 | | 01 | aconst_null | 将 `null` 推送到栈顶 | 8 | | 02 | iconst_m1 | 将整数 `-1` 推送至栈顶 | 9 | | 03 | iconst_0 | 将int类型 `0` 推送至栈顶 | 10 | | 04 | iconst_1 | 将int类型 `1` 推送至栈顶 | 11 | | 05 | iconst_2 | 将int类型 `2` 推送至栈顶 | 12 | | 06 | iconst_3 | 将int类型 `3` 推送至栈顶 | 13 | | 07 | iconst_4 | 将int类型 `4` 推送至栈顶 | 14 | | 08 | iconst_5 | 将int类型 `5` 推送至栈顶 | 15 | | 09 | lconst_0 | 将long类型 `0` 推送至栈顶 | 16 | | 10 | lconst_1 | 将long类型 `1` 推送至栈顶 | 17 | | 11 | fconst_0 | 将float类型 `0` 推送至栈顶 | 18 | | 12 | fconst_1 | 将float类型 `1` 推送至栈顶 | 19 | | 13 | fconst_2 | 将float类型 `2` 推送至栈顶 | 20 | | 14 | dconst_0 | 将double类型 `0` 推送至栈顶 | 21 | | 15 | dconst_1 | 将double类型 `1` 推送至栈顶 | 22 | | 16 | bipush | 将单字节常量值 (`-128~127`) 推送至栈顶 | 23 | | 17 | sipush | 将短整型常量值(`-32768~32767`) 推送至栈顶 | 24 | | 18 | ldc | 将 `int`、 `float` 或 `string` 类型从常量池推送至栈顶 | 25 | | 19 | ldc_w | 将 `int`、 `float` 或 `string` 类型从常量池推送至栈顶(宽索引) | 26 | | 20 | ldc2_w | 将 `long` 或者 `double` 类型从常量池推送至栈顶(宽索引) | 27 | | 21 | iload | 将 `int` 类型本地变量推送至栈顶 | 28 | | 22 | lload | 将 `long` 类型本地变量推送至栈顶 | 29 | | 23 | fload | 将 `float` 类型本地变量推送至栈顶 | 30 | | 24 | dload | 将 `double` 类型本地变量推送至栈顶 | 31 | | 25 | aload | 将指定的引用类型本地变量推送至栈顶 | 32 | | 26 | iload_0 | 将第一个 `int` 类型本地变量推送至栈顶 | 33 | 34 | -------------------------------------------------------------------------------- /src/autorun/jvm/catalog/back.md: -------------------------------------------------------------------------------- 1 | `utilities/globalDefinitions_visCPP.hpp` Windows相关头文件
2 | `utilities/globalDefinitions_sparcWorks.hpp` 非Windows相关头文件 3 | 4 | 主要体现在 `globalDefinitions.hpp` 文件中,使用来决定引入哪一个文件。 5 | ```c++ 6 | #ifdef TARGET_COMPILER_visCPP 7 | # include "utilities/globalDefinitions_visCPP.hpp" 8 | #endif 9 | #ifdef TARGET_COMPILER_sparcWorks 10 | # include "utilities/globalDefinitions_sparcWorks.hpp" 11 | #endif 12 | ``` 13 | 如果使用 `TARGET_COMPILER_visCPP` 相关属性则会使用 `globalDefinitions_visCPP.hpp` 文件,否则会使用默认的 `globalDefinitions_sparcWorks.cpp` 文件 14 | ```cmake 15 | # Used for platform dispatching 16 | CXX_FLAGS=$(CXX_FLAGS) /D TARGET_OS_FAMILY_windows 17 | CXX_FLAGS=$(CXX_FLAGS) /D TARGET_ARCH_$(Platform_arch) 18 | CXX_FLAGS=$(CXX_FLAGS) /D TARGET_ARCH_MODEL_$(Platform_arch_model) 19 | CXX_FLAGS=$(CXX_FLAGS) /D TARGET_OS_ARCH_windows_$(Platform_arch) 20 | CXX_FLAGS=$(CXX_FLAGS) /D TARGET_OS_ARCH_MODEL_windows_$(Platform_arch_model) 21 | CXX_FLAGS=$(CXX_FLAGS) /D TARGET_COMPILER_visCPP 22 | ``` 23 | ## 主控线程 24 | `runtime/thread.cpp` `VMThread::create()` 25 | 26 | ## JVM 线程类型 27 | ```c++ 28 | enum ThreadType { 29 | vm_thread, 30 | cgc_thread, // Concurrent GC thread 31 | pgc_thread, // Parallel GC thread 32 | java_thread, // Java, CodeCacheSweeper, JVMTIAgent and Service threads. 33 | compiler_thread, 34 | watcher_thread, 35 | asynclog_thread, // dedicated to flushing logs 36 | os_thread 37 | }; 38 | ``` -------------------------------------------------------------------------------- /src/autorun/jvm/catalog/catalog.md: -------------------------------------------------------------------------------- 1 | # Hotspot目录结构 2 | 3 | 以jdk8为例 4 | 5 | ![](img/catalog.png) 6 | 7 | > 其中cpu、 os 、 os_cpu都是跟平台相关的。具体这里不再赘述。主要是 `share/vm` 目录 8 | 9 | ## VM目录组件介绍 10 | 11 | ####`adlc` 一些平台相关的描述文件 12 | #### `asm` 汇编相关的操作 13 | #### `c1` c1编译器,又名client编译器 14 | #### `ci` 动态编译器 15 | #### `classfile` 字节码相关 16 | #### `code` 机器码生成 17 | #### `compiler` 动态编译器接口 18 | #### `gc_implementation` gc相关实现 19 | #### `gc_interface` gc相关接口 20 | #### `interpreter` 解释器 21 | #### `libadt` 抽象的数据结构 22 | #### `memory` 内存操作相关 23 | #### `oops` 面向对象oop模型相关(klass/oops) 24 | #### `opto` c2编译器 25 | #### `precompiled` 预编译头文件相关 26 | #### `prims` Hotspot堆外接口 27 | #### `runtime` 运行时相关 28 | #### `services` jmx相关 29 | #### `shark` llvm实现的即时编译器 30 | #### `trace` 统计相关 31 | #### `utilities` 内部工具 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/autorun/jvm/catalog/img/catalog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/catalog/img/catalog.png -------------------------------------------------------------------------------- /src/autorun/jvm/classfile/Classfile_Parser.md: -------------------------------------------------------------------------------- 1 | # 类解析 2 | 3 | > hotspot/src/share/vm/classfile/classFileParser.cpp 4 | 5 | `ClassFileParser::parseClassFile` 6 | 7 | ### 解析常量池 8 | `constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle));` 9 | 10 | ```c++ 11 | AccessFlags access_flags; 12 | jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS; 13 | ``` 14 | -------------------------------------------------------------------------------- /src/autorun/jvm/enviment/ENVIMENT_INIT.md: -------------------------------------------------------------------------------- 1 | # hotspot 调试环境搭建 2 | 3 | ## openjdk 编译步骤 4 | ### 以jdk1.8为例 5 | 1. 安装Ubuntu环境(我这里使用18.04版本,不过版本最好高于16+以上,x86_64环境) 6 | 2. 使用终端更新依赖 7 | > `sudo apt upgrade & sudo apt update` 8 | > 如果是低版本的系统,只要把命令更换为 `sudo apt-get upgrade & sudo apt-get update` 9 | 3. 更新完毕之后安装必要的依赖库 10 | > `sudo apt install libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev libcups2-dev libfreetype6-dev libasound2-dev ccache` 11 | 12 | > `apt` 命令同理 13 | 4. 安装 `git` (推荐) 或者 `hg` 工具用于克隆代码(二选其一即可) 14 | > sudo apt install git / sudo apt install 15 | > 16 | 安装 `mercurial` (也就是hg命令,同上,二选其一即可) 17 | ```shell 18 | sudo add-apt-repository -y ppa:mercurial-ppa/releases 19 | sudo apt update 20 | sudo apt install -y python-pip python-dev 21 | sudo pip install mercurial --upgrade 22 | ``` 23 | > git 仓库地址: `https://github.com/openjdk/jdk/tree/jdk8-b120` 24 | 25 | > hg 仓库地址: `http://hg.openjdk.java.net/jdk8u/jdk8u/` 26 | 5. 克隆 `openjdk` 源码 27 | 如果是git用户, 使用 `git clone -b jdk8-b120 git@github.com:openjdk/jdk.git` 命令克隆(推荐) 28 | 29 | 如果是hg用户则使用 `hg clone http://hg.openjdk.java.net/jdk8u/jdk8u/`
30 | 即可以下载到openjdk的源码. 31 | 下载完成之后cd 到对应目录中 32 | 6. 给 `configure` 脚本增加执行权限 33 | > chmod u+x ./configure 34 | 35 | 7. 下载bootJDK. 36 | > 使用Oracle的jdk7或者openjdk皆可, 我这里选择Oracle的jdk
37 | > jdk下载地址: [下载链接](http://jdk.java.net/java-se-ri/7) 38 | 39 | 8. 配置 `bootJDK` 环境变量(将 `{base_path}` 替换成你自己的路径即可) 40 | 41 | 42 | 请将 {base_path} 替换成你自己的路径!
43 | 请将 {base_path} 替换成你自己的路径!
44 | 请将 {base_path} 替换成你自己的路径!
45 |
46 | 47 | 重要的事情说三遍! 48 | 49 | `sudo vim /etc/profile` # 将配置追加到你的profile文件末尾。使用 `G` 命令在vim的命令模式下快速跳转到文件末尾。然后使用 `O` 插入 50 | ```shell 51 | export JAVA_HOME={base_path}/jdk1.7.0_80 52 | export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar 53 | export PATH=$JAVA_HOME/bin:$ANT_HOME/bin:$PATH 54 | ``` 55 | 然后使用 `:wq` 保存, 使用 `source` 命令使配置生效 `source /etc/profile` 56 | 57 | 9. 准备编译openJDK环境
58 | > `./configure --with-target-bits=64 --with-boot-jdk={base_path}/jdk1.7.0_80 --with-debug-level=slowdebug --enable-debug-symbols ZIP_DEBUGINFO_FILES=0`
59 | 60 | 附录中会贴出 `configure` 命令所支持的参数。现在可以先这么用
61 | 如果出现如下提示则配置成功 62 | ![img](./img/config_succ.png) 63 | 64 | 10. 开始编译openJDK
65 | > `make all DISABLE_HOTSPOT_OS_VERSION_CHECK=OK ZIP_DEBUGINFO_FILES=0`
66 | 如果出现如下提示则编译成功 67 | ![img](./img/build_succ.png) 68 | 69 | 11. 编译中可能出现的一些问题 70 | - 报错信息1(这是我编译时候遇到最多的问题。后续有问题可以提issue. 我这边更新到文档中) 71 | ```c++ 72 | make[6]: *** [/home/autorun/platform/source/jdk/hotspot/make/linux/makefiles/vm.make:297: precompiled.hpp.gch] Error 1 73 | make[5]: *** [/home/autorun/platform/source/jdk/hotspot/make/linux/makefiles/top.make:119: the_vm] Error 2 74 | make[4]: *** [/home/autorun/platform/source/jdk/hotspot/make/linux/Makefile:289: product] Error 2 75 | make[3]: *** [Makefile:217: generic_build2] Error 2 76 | make[2]: *** [Makefile:167: product] Error 2 77 | make[1]: *** [HotspotWrapper.gmk:45: /home/autorun/platform/source/jdk/build/linux-x86_64-normal-server-release/hotspot/_hotspot.timestamp] Error 2 78 | make: *** [/home/autorun/platform/source/jdk//make/Main.gmk:109: hotspot-only] Error 2 79 | ``` 80 | 解决方案: 降低g++和gcc版本即可。 81 | ```shell 82 | sudo apt install -y gcc-4.8 83 | sudo apt install -y g++-4.8 84 | # 重新建立软连接 85 | cd /usr/bin #进入/usr/bin文件夹下 86 | sudo rm -r gcc #移除之前的软连接 87 | sudo ln -sf gcc-4.8 gcc #建立gcc4.8的软连接 88 | sudo rm -r g++ 89 | sudo ln -sf g++-4.8 g++ 90 | ``` 91 | - 报错信息2 92 | ``` 93 | *** This OS is not supported: Linux ght-VirtualBox 4.15.0-142-generic #146~16.04.1-Ubuntu SMP Tue Apr 13 09:27:15 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux 94 | make[5]: *** [check_os_version] Error 1 95 | make[4]: *** [linux_amd64_compiler2/fastdebug] Error 2 96 | make[3]: *** [generic_build2] Error 2 97 | make[2]: *** [debug] Error 2 98 | make[1]: *** [/home/ght/openjdk/build/linux-x86_64-normal-server-slowdebug/hotspot/_hotspot.timestamp] Error 2 99 | make: *** [hotspot-only] Error 2 100 | ``` 101 | 102 | 修改`hotspot/make/linux/Makefile`中 103 | ```bash 104 | SUPPORTED_OS_VERSION = 2.4% 2.5% 2.6% 3% 4% # 增加uname -a所指定的版本 上例中是4.15 增加4%即可 105 | ``` 106 | 107 | 12. 关于 `configure` 脚本和 `make` 的说明 108 | 109 | #### configure 说明 110 | 111 | |OpenJDK Configure Option | Description | 112 | |:----:|:----:| 113 | | --enable-debug | set the debug level to fastdebug (this is a shorthand for --with-debug-level=fastdebug) | 114 | | --with-alsa=path | select the location of the Advanced Linux Sound Architecture (ALSA)Version 0.9.1 or newer of the ALSA files are required for building the OpenJDK on Linux. These Linux files are usually available from an "alsa" of "libasound" development package, and it's highly recommended that you try and use the package provided by the particular version of Linux that you are using.| 115 | | --with-boot-jdk=path | select the Bootstrap JDK | 116 | | --with-boot-jdk-jvmargs="args" | provide the JVM options to be used to run the Bootstrap JDK | 117 | | --with-cacerts=path | select the path to the cacerts file. See http://en.wikipedia.org/wiki/Certificate_Authority for a better understanding of the Certificate Authority (CA). A certificates file named "cacerts" represents a system-wide keystore with CA certificates. In JDK and JRE binary bundles, the "cacerts" file contains root CA certificates from several public CAs (e.g., VeriSign, Thawte, and Baltimore). The source contain a cacerts file without CA root certificates. Formal JDK builders will need to secure permission from each public CA and include the certificates into their own custom cacerts file. Failure to provide a populated cacerts file will result in verification errors of a certificate chain during runtime. By default an empty cacerts file is provided and that should be fine for most JDK developers.| 118 | | --with-cups=path | select the CUPS install location The Common UNIX Printing System (CUPS) Headers are required for building the OpenJDK on Solaris and Linux. The Solaris header files can be obtained by installing the package SFWcups from the Solaris Software Companion CD/DVD, these often will be installed into the directory /opt/sfw/cups. The CUPS header files can always be downloaded from www.cups.org.| 119 | | --with-cups-include=path | select the CUPS include directory location| 120 | | --with-debug-level=level | select the debug information level of release, fastdebug, or slowdebug | 121 | | --with-dev-kit=path | select location of the compiler install or developer install location | 122 | | --with-freetype=path | select the freetype files to use.Expecting the freetype libraries under lib/ and the headers under include/. Version 2.3 or newer of FreeType is required. On Unix systems required files can be available as part of your distribution (while you still may need to upgrade them). Note that you need development version of package that includes both the FreeType library and header files. You can always download latest FreeType version from the FreeType website. Building the freetype 2 libraries from scratch is also possible, however on Windows refer to the Windows FreeType DLL build instructions. Note that by default FreeType is built with byte code hinting support disabled due to licensing restrictions. In this case, text appearance and metrics are expected to differ from Sun's official JDK build. See the SourceForge FreeType2 Home Page for more information. | 123 | |--with-import-hotspot=path | select the location to find hotspot binaries from a previous build to avoid building hotspot | 124 | | --with-target-bits=arg | select 32 or 64 bit build | 125 | | --with-jvm-variants=variants | select the JVM variants to build from, comma separated list that can include: server, client, kernel, zero and zeroshark | 126 | | --with-memory-size=size | select the RAM size that GNU make will think this system has | 127 | | --with-msvcr-dll=path | select the msvcr100.dll file to include in the Windows builds (C/C++ runtime library for Visual Studio).This is usually picked up automatically from the redist directories of Visual Studio 2010.| 128 | | --with-num-cores=cores | select the number of cores to use (processor count or CPU count) | 129 | | --with-x=path | select the location of the X11 and xrender files.The XRender Extension Headers are required for building the OpenJDK on Solaris and Linux. The Linux header files are usually available from a "Xrender" development package, it's recommended that you try and use the package provided by the particular distribution of Linux that you are using. The Solaris XRender header files is included with the other X11 header files in the package SFWxwinc on new enough versions of Solaris and will be installed in /usr/X11/include/X11/extensions/Xrender.h or /usr/openwin/share/include/X11/extensions/Xrender.h | 130 | 131 | 大概解释一下常用的几个参数: 挑出我认为比较实用的几个: 132 | > `--enable-debug` 等价于 `--with-debug-level=fastdebug`, 说到这里,编译时一定要选择debug的版本。要不然很多参数是无法使用的。
133 | > 使用命令: `java -XX:+PrintFlagsFinal -version | wc -l` 可以统计出,product版本的虚拟机参数仅仅有700多个, 而debug版本的参数足足有1300+
134 | > `--with-alsa=path` 这个说的是据说有个更高级的架构叫ALSA.
135 | > `--with-boot-jdk=path` 指定bootJDK地址, 用来编译OpenJDK源码里的Java代码
136 | ![img](./img/languages_label.png)
137 | > 通过上图可以看到, jvm的代码中 `java` 代码的占比是大头。 所以还是要学好java。不要舍本逐末, java YYDS~
138 | > `--with-debug-level=level` 可以指定打某一个版本的包。参数值有 `release`、`fastdebug`、`slowdebug`, 默认值: `release`
139 | > `--with-freetype=path` 可以指定字体库位置。如果不是使用apt安装的话
140 | > `--with-import-hotspot=path` 可以指定由历史构建来构建你的Hotspot,这样应该可以起到加速效果~
141 | > `--with-target-bits=arg` 只支持32和64两个数值,代表操作系统和处理器的位数
142 | > `--with-jvm-variants=variants` 编译JVM的模式,有server, client, kernel, zero and zeroshark 五种 ,默认server模式
143 | > `--with-memory-size=size` 编译时使用多大内存
144 | > `--with-msvcr-dll=path` 这个应该是Windows相关的。用于指定 `msvcr100.dll` 位置,如果在 Visual Studio 2010 环境中则会自动加载
145 | > `--with-num-cores=cores` 编译时指定使用几个CPU数量
146 | 147 | 148 | #### make 说明 149 | |Make Target|Description| 150 | |:---:|:---:| 151 | |empty|build everything but no images| 152 | |all|build everything including images| 153 | |all-conf|build all configurations| 154 | |images|create complete j2sdk and j2re images| 155 | |install|install the generated images locally, typically in /usr/local| 156 | |clean|remove all files generated by make, but not those generated by configure| 157 | |dist-clean|remove all files generated by both and configure (basically killing the configuration)| 158 | |help|give some help on using make, including some interesting make targets| 159 | > `all` 表示编译所有
160 | > `all-conf` 表示单独编译配置
161 | > `clean` 是清除所有的make进度,但不会清除使用`configure`脚本生成的配置信息
162 | > `help` 可以查看make相关配置
163 | 164 | ### 参考链接 165 | [硬核子牙-手把手教你搭建单步调试openjdk环境(值得收藏)](https://mp.weixin.qq.com/s/ZMXEwCJCj_eXFkq8vw-JKA)
166 | [jdk build readme file](http://hg.openjdk.java.net/jdk8/jdk8/raw-file/tip/README-builds.html#linux)
167 | [老郑-openjdk 1.8 源码编译](https://juejin.cn/post/6905377760265863176)
168 | 169 | 下讲分享怎么通过gdb、ide调试Hotspot代码 170 | -------------------------------------------------------------------------------- /src/autorun/jvm/enviment/IDE_DEBUG.md: -------------------------------------------------------------------------------- 1 | # IDE调试配置教程 2 |
3 | 4 | ## 1. IDE列表 5 | 1. Eclipse 6 | 2. JetBrains Clion 7 | 3. NetBeans 8 | 9 | ### 1.1 Eclipse 10 | 11 | #### 简介: 12 | Eclipse是著名的跨平台的自由集成开发环境(IDE)。最初主要用来Java语言开发,但是目前亦有人通过插件使其作为其他计算机语言比如C++和Python的开发工具。 13 | 14 | 所以安装eclipse时请务必安装好jdk~ 15 | 16 | 接下来根据对应的平台选择对应的版本。这里不再赘述 17 | > 下载地址: [点此进入](https://www.eclipse.org/downloads/packages/) 18 | 19 | 1. 安装完毕后开启eclipse, 选择import 你编译好的openjdk 20 | 21 | 22 | 23 | 2. 选择c/c++项目 选择导入即可。 24 | 25 | 26 | 3. 接下来配置运行命令 27 | 28 | ![img](img/ide_debug_ec_3.png) 29 | 30 | 创建调试选项配置,然后将应用程序选择为你自己编译好的路径。在 `argument` 标签中加入你要执行的主类 (可以是任意带main方法的类) 31 | 32 | 在 `environment` 标签中配置对应的classpath路径。是kv结构的。主要让ide顺利的找到你的主类 33 | 34 | ![img](img/ide_debug_ec_4.png) 35 | 36 | 如上所述配置完成之后即可享受你的debug之旅~ 37 | 38 | ### 1.2 JetBrains Clion 39 | 40 | #### 简介 41 | 42 | Clion 是一款专为开发C及C++所设计的跨平台IDE。它是以IntelliJ为基础设计的,包含了许多智能功能来提高开发人员的生产力。CLion帮助开发人员使用智能编辑器来提高代码质量、自动代码重构并且深度整合CMake编译系统,从而提高开发人员的工作效率。 43 | > 下载地址: [点此进入](https://www.jetbrains.com/clion/) 44 | Clion 是一款专为开发C及C++所设计的跨平台IDE。它是以IntelliJ为基础设计的,包含了许多智能功能来提高开发人员的生产力。CLion帮助开发人员使用智能编辑器来提高代码质量、自动代码重构并且深度整合CMake编译系统,从而提高开发人员的工作效率。 45 | 46 | 47 | 1. 导入openjdk 48 | 49 | 2. 索引完成之后生成CMakeLists.txt 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/autorun/jvm/enviment/img/build_succ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/enviment/img/build_succ.png -------------------------------------------------------------------------------- /src/autorun/jvm/enviment/img/config_succ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/enviment/img/config_succ.png -------------------------------------------------------------------------------- /src/autorun/jvm/enviment/img/ide_debug_ec_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/enviment/img/ide_debug_ec_1.png -------------------------------------------------------------------------------- /src/autorun/jvm/enviment/img/ide_debug_ec_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/enviment/img/ide_debug_ec_2.png -------------------------------------------------------------------------------- /src/autorun/jvm/enviment/img/ide_debug_ec_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/enviment/img/ide_debug_ec_3.png -------------------------------------------------------------------------------- /src/autorun/jvm/enviment/img/ide_debug_ec_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/enviment/img/ide_debug_ec_4.png -------------------------------------------------------------------------------- /src/autorun/jvm/enviment/img/languages_label.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/enviment/img/languages_label.png -------------------------------------------------------------------------------- /src/autorun/jvm/jit/JIT1.md: -------------------------------------------------------------------------------- 1 | # JIT 2 | 3 | 4 | > https://zhuanlan.zhihu.com/p/28476709 5 | > 6 | > -------------------------------------------------------------------------------- /src/autorun/jvm/jni/HelloJni.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by autorun on 2021/11/12. 3 | // 4 | #include 5 | #include "HelloJni.h" 6 | using namespace std; 7 | 8 | JNIEXPORT void JNICALL Java_HelloJni_hello(JNIEnv *env, jobject obj) 9 | { 10 | // c语言写法 11 | // jclass jclass1 = (*env).GetObjectClass(obj); 12 | // // c++写法 13 | // jclass jclass2 = env->GetObjectClass(obj); 14 | // 15 | // cout << jclass1 << endl; 16 | // cout << jclass2 << endl; 17 | 18 | 19 | jclass mapKlass = env->FindClass("java/util/HashMap"); 20 | jmethodID constructor = env->GetMethodID(mapKlass, "", "()V"); 21 | jobject mapObj2 = env->NewObject(mapKlass, constructor); 22 | 23 | // toString()Ljava/lang/String; 24 | jobject toStringRst = env->CallObjectMethod(mapObj2, env->GetMethodID(mapKlass, "toString", "()Ljava/lang/String;")); 25 | cout << toStringRst << endl; 26 | 27 | // call hashmap put 28 | // put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 29 | // jint* value = new jint; 30 | // value = 5; 31 | // env->CallDoubleMethodA(mapObj2, env->GetMethodID(mapKlass, "put", 32 | // "<(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;>"), 33 | // value); 34 | // jobject putObj = env->CallObjectMethod(mapObj2, 35 | // env->GetMethodID(mapKlass, "put", 36 | // "<(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;>")); 37 | 38 | // 获取 hashmap的类 39 | // jclass mapObjKlass = env->GetObjectClass(obj); // "java/util/HashMap" 40 | // jobject mapObj1 = env->AllocObject(mapObjKlass); // 只申请内存 41 | // jmethodID constructor = env->GetMethodID(mapObjKlass, "", "()V "); 42 | // jobject mapObj2 = env->NewObject(mapObjKlass, constructor); 43 | // TODO 尝试抛异常 44 | 45 | ; 46 | cout << "version: " << env->GetVersion() << endl; 47 | env->ThrowNew(env->FindClass("java/lang/RuntimeException"), "c++ throw exception!"); 48 | cout << "hello JNI!" << endl; 49 | } 50 | -------------------------------------------------------------------------------- /src/autorun/jvm/jni/HelloJni.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | //#include 3 | #include "base/jni.h" 4 | /* Header for class HelloJni */ 5 | 6 | #ifndef _Included_HelloJni 7 | #define _Included_HelloJni 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | /* 12 | * Class: HelloJni 13 | * Method: hello 14 | * Signature: ()V 15 | */ 16 | JNIEXPORT void JNICALL Java_HelloJni_hello 17 | (JNIEnv *, jobject); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | #endif 23 | -------------------------------------------------------------------------------- /src/autorun/jvm/jni/HelloJni.java: -------------------------------------------------------------------------------- 1 | public class HelloJni { 2 | 3 | public native void hello(); 4 | 5 | } -------------------------------------------------------------------------------- /src/autorun/jvm/jni/JNIEnvAPI.md: -------------------------------------------------------------------------------- 1 | # JNIEnv的一些API 2 | 3 | ## 数据类型映射 4 |
5 | 6 | > java的数据类型和C++的对应关系(大部分可用,小部分需要根据实际情况调整) 7 | 8 | | Java类型 | 本地类型 | 描述 | 9 | | :---: | :---: | :---: | 10 | | boolean | jboolean | C/C++8位整型| 11 | | byte | jbyte | C/C++带符号的8位整型| 12 | | char | jchar | C/C++无符号的16位整型| 13 | | short | jshort | C/C++带符号的16位整型| 14 | | int | jint | C/C++带符号的32位整型| 15 | | long | jlong | C/C++带符号的64位整型| 16 | | float | jfloat | C/C++32位浮点型| 17 | | double | jdouble | C/C++64位浮点型| 18 | | Object | jobject | 任何Java对象,或者没有对应java类型的对象| 19 | | Class | jclass | Class对象| 20 | | String | jstring | 字符串对象| 21 | | Object[] | jobjectArray | 任何对象的数组| 22 | | boolean[] | jbooleanArray | 布尔型数组| 23 | | byte[] | jbyteArray | 比特型数组| 24 | | char[] | jcharArray | 字符型数组| 25 | | short[] | jshortArray | 短整型数组| 26 | | int[] | jintArray | 整型数组| 27 | | long[] | jlongArray | 长整型数组| 28 | | float[] | jfloatArray | 浮点型数组| 29 | | double[] | jdoubleArray | 双浮点型数组| 30 | 31 | > jni 对应的据类型 32 | 33 | |函数 | Java 数组类型 | 本地类型 | 34 | | :---: | :---: | :---: | 35 | |GetBooleanArrayElements | jbooleanArray | jboolean | 36 | |GetByteArrayElements | jbyteArray | jbyte | 37 | |GetCharArrayElements | jcharArray | jchar | 38 | |GetShortArrayElements | jshortArray | jshort | 39 | |GetIntArrayElements | jintArray | jint | 40 | |GetLongArrayElements | jlongArray | jlong | 41 | |GetFloatArrayElements | jfloatArray | jfloat | 42 | |GetDoubleArrayElements | jdoubleArray | jdouble | 43 | 44 | ### JNI相关函数 45 | > 参照 [jni.h](base/jni.h) `struct JNIEnv_` 部分,或者jdk安装目录中 `include` 目录下的 `jni.h` 头文件 46 | 47 | | 函数名 | 返回值 | 描述 | 48 | | :---: | :---: | :---: | 49 | | `GetVersion()`| `jint` | 获取版本号 | 50 | | `DefineClass()`| `jclass` | 加载类 | 51 | | `FindClass()`| `jclass` | 根据类名获取已加载的类 | 52 | | `FromReflectedMethod()`| `jmethodID` | 通过反射获取方法 | 53 | | `FromReflectedField()`| `jfieldID` | 通过反射获取字段 | 54 | | `ToReflectedMethod()`| `jobject` | 通过class,methodId,是否是静态获取方法 | 55 | | `GetSuperclass()`| `jclass` | 获取父类 | 56 | | `IsAssignableFrom()`| `jboolean` | 确定传入类的继承结构是否被包含在调用方内。参照 `java.lang.Class.isAssignableFrom()` | 57 | | `ToReflectedField()`| `jobject` | 反射获取字段 | 58 | | `Throw()`| `jint` | 抛出异常 | 59 | | `ThrowNew()`| `jint` | 抛出异常, 参数不同 | 60 | | `ExceptionOccurred()`| `jthrowable` | 获取发生异常的信息 | 61 | | `ExceptionDescribe()`| `void` | 订阅异常, jvm内部会使用标准输出打印异常信息 | 62 | | `FatalError()`| `void` | 致命错误, jvm会调用os dump现场 | 63 | | `PushLocalFrame()`| `jint` | //TODO ... | 64 | | `PopLocalFrame()`| `jint` | //TODO ... | 65 | | `NewGlobalRef()`| `jobject` | 在全局区创建引用 | 66 | | `DeleteGlobalRef()`| `jobject` | 删除全局区引用 | 67 | | `DeleteLocalRef()`| `jobject` | 删除局部区引用 | 68 | | `IsSameObject()`| `jboolean` | 比较俩对象是否相等 | 69 | | `NewLocalRef()`| `jobject` | 创建本地引用 | 70 | | `EnsureLocalCapacity()`| `jint` | 确保本地容量在参数capacity区间 | 71 | | `AllocObject()`| `jobject` | 根据jclass 分配对象空间 | 72 | | `NewObject()`| `jobject` | 根据jclass和method创建对象 | 73 | | `NewObjectV()`| `jobject` | 根据jclass和method创建对象, 通过`va_list` 传参 | 74 | | `NewObjectA()`| `jobject` | 根据jclass和method创建对象, 通过 `jvalue *args` 传参 | 75 | | `GetObjectClass()`| `jclass` | 通过对象获取其`jklass` 对象 | 76 | | `IsInstanceOf()`| `jboolean` | 比较实例 `Klass` 是否相同 | 77 | | `GetMethodID()`| `jmethodID` | 获取 `methodId` | 78 | | `CallObjectMethod()`| `jobject` | 根据 `methodId` 调用method | 79 | | `CallObjectMethodV()`| `jobject` | 根据 `methodId` 调用method, 含义同 `NewObjectV()` | 80 | | `CallObjectMethodA()`| `jobject` | 根据 `methodId` 调用method, 含义同 `NewObjectA()` | 81 | | `CallBooleanMethod()`| `jboolean` | 根据 `methodId` 调用boolean method | 82 | | `CallBooleanMethodV()`| `jboolean` | 根据 `methodId` 调用boolean method 含义同 `NewObjectV()`| 83 | | `CallBooleanMethodA()`| `jboolean` | 根据 `methodId` 调用boolean method 含义同 `NewObjectA()`| 84 | | `Call*Method()`| `jboolean` | 根据 `methodId` 调用 各种类型的method | 85 | | `CallNonvirtual*Method()`| `*` | 根据 `methodId` 调用 各种类型的非虚method | 86 | | `GetFieldID()`| `jfieldID` | 根据 `field` 获取field信息 | 87 | | `Get*FieldID()`| `*` | 根据 `field` 获取各种类型的field信息 | 88 | | `Set*Field()`| `*` | 根据 `field` 设置各种类型的field值 | 89 | | `CallStatic*Method()`| `*` | 调用各种类型的静态java方法 | 90 | | `NewString()`| `jstring` | 创建`string`对象 | 91 | | `GetStringLength()`| `jsize` | 获取`string`对象的长度, `jsize` 等同于 `jint` | 92 | | `GetStringChars()`| `const jchar*` | 获取`string`对象的值, 转为char数组类型 | 93 | | `ReleaseStringChars()`| `void` | 释放字符串空间 | 94 | | `NewStringUTF()`| `jstring` | 创建utf的 `string` 对象 | 95 | | `GetStringUTFLength()`| `jsize` | 获取 `stringUTF` 字符串对象的长度 | 96 | | `GetStringUTFChars()`| `const char*` | `stringUTF`字符串转`char`数组 | 97 | | `ReleaseStringUTFChars()`| `void` | 释放 | 98 | | `GetArrayLength()`| `jsize` | 获取数组长度 | 99 | | `GetObjectArrayElement()`| `jobject` | 获取数组对象 | 100 | | `SetObjectArrayElement()`| `void` | 设置数组对象指定下标的值 | 101 | | `New*Array()`| `*` | 创建各种类型的数组对象 | 102 | | `Get*ArrayElements()`| `*` | 获取各种类型的数组对象 | 103 | | `Release*ArrayElements()`| `*` | 释放各种类型的数组对象 | 104 | | `Get*ArrayRegion()`| `*` | 获取各种类型数组的区域 | 105 | | `Set*ArrayRegion()`| `*` | 批量替换各类型数组的区域 | 106 | | `RegisterNatives()`| `jint` | 注册本地方法 | 107 | | `UnregisterNatives()`| `jint` | 卸载本地方法 | 108 | | `MonitorEnter()`| `jint` | synchronized进入 | 109 | | `MonitorExit()`| `jint` | synchronized退出 | 110 | | `GetJavaVM()`| `jint` | 获取javaVM对象, 设置到传入的指针中。成功返回0 | 111 | | `GetStringUTFRegion()`| `void` | 获取字符串中某一段数据设置到参数中的指针地址 | 112 | | `GetPrimitiveArrayCritical()`| `void *` | 获取底层数组指针的地址 | 113 | | `ReleasePrimitiveArrayCritical()`| `void` | 根据地址释放数组 | 114 | | `GetStringCritical()`| `jchar *` | 获取字符串值 | 115 | | `ReleaseStringCritical()`| `void` | 释放字符串值 | 116 | | `NewWeakGlobalRef()`| `jweak` | 创建全局虚引用 | 117 | | `DeleteWeakGlobalRef()`| `void` | 删除全局虚引用 | 118 | | `ExceptionCheck()`| `jboolean` | 获取异常栈 | 119 | | `NewDirectByteBuffer()`| `jobject` | 创建直接内存的 `byteBuffer` | 120 | | `GetDirectBufferAddress()`| `void*` | 获取 `byteBuffer` 地址 | 121 | | `GetDirectBufferCapacity()`| `jlong` | 获取 `byteBuffer` 偏移量 | 122 | | `GetObjectRefType()`| `jobjectRefType` | 获取对象引用的类型 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | ## 附录 138 | ### 参考文献
139 | [Java和C或C++的数据类型对照表](https://www.cnblogs.com/jkguo/p/11262741.html) 140 | -------------------------------------------------------------------------------- /src/autorun/jvm/jni/JNI_INIT.md: -------------------------------------------------------------------------------- 1 | # JNI 初始化篇 2 | 3 | > 接JVM初始化篇, 如果没有看过启动篇请先阅读一下启动篇。否则直接看的话比较容易懵逼~ 4 | 5 | ## JNI简介 6 | 7 | jni相关的类文件都在 `hotspot/src/share/vm/prims` 中,后续会出一篇目录结构简介的文章。此处先不介绍, 就记住在那里就行~ 8 | 9 | [JVM启动流程](../start/README.md) 10 | 11 | 在JVM启动流程中介绍过,会赋值ifn的三个函数首地址, 分别是 `CreateJavaVM`、 `GetDefaultJavaVMInitArgs` 、`GetCreatedJavaVMs`. 12 | 13 | 然后会在 `JNI_CreateJavaVM()` 中对 JNIEnv赋值。 14 | ```c++ 15 | 16 | result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again); 17 | if (result == JNI_OK) { 18 | JavaThread *thread = JavaThread::current(); 19 | /* thread is thread_in_vm here */ 20 | // jni_InvokeInterface 赋值。c语言环境中使用改变量。c++ 环境中使用JNIEnv 21 | *vm = (JavaVM *)(&main_vm); // main_vm定义在下面 22 | // JNIEnv赋值。 由此处可以看出,JNIEnv其实是线程私有的。 23 | *(JNIEnv**)penv = thread->jni_environment(); 24 | ... 25 | ``` 26 | 27 | `struct JavaVM_ main_vm = {&jni_InvokeInterface};` 28 | 29 | ### `JNIEnv` 的初始化过程 30 | 1. `JavaMain() java.c` 31 | 2. -> `InitializeJVM() java.c` 32 | 3. -> `JNI_CreateJavaVM() jni.cpp` 33 | 4. -> `Threads::create_vm() thread.cpp` 34 | 5. -> `JavaThread::JavaThread() thread.cpp` 35 | 6. -> `JavaThread::initialize() thread.cpp` 36 | 7. -> `jni_functions() jni.cpp` 37 | 38 | #### 1. 使用 `pthread_create` 回调 `JavaMain()` 参考 [8. ContinueInNewThread0() 函数](../start/README.md "8. ContinueInNewThread0() 函数") 39 | ```c++ 40 | /* Initialize the virtual machine */ 41 | start = CounterGet(); 42 | if (!InitializeJVM(&vm, &env, &ifn)) { 43 | JLI_ReportErrorMessage(JVM_ERROR1); 44 | exit(1); 45 | } 46 | ... 47 | ``` 48 | #### 2. `InitializeJVM()` 49 | ```c++ 50 | // _JAVA_LAUNCHER_DEBUG=true 51 | if (JLI_IsTraceLauncher()) { 52 | int i = 0; 53 | printf("JavaVM args:\n "); 54 | printf("version 0x%08lx, ", (long)args.version); 55 | printf("ignoreUnrecognized is %s, ", 56 | args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE"); 57 | printf("nOptions is %ld\n", (long)args.nOptions); 58 | for (i = 0; i < numOptions; i++) 59 | printf(" option[%2d] = '%s'\n", 60 | i, args.options[i].optionString); 61 | } 62 | r = ifn->CreateJavaVM(pvm, (void **)penv, &args); 63 | ``` 64 | `r = ifn->CreateJavaVM(pvm, (void **)penv, &args);` [链接ifn参数](../start/README.md "#5. 当 `libjvm.so` 动态链接库加载完成后接下来会调用") 65 | #### 3. `JNI_CreateJavaVM()` 66 | 调用 `hotspot/src/share/vm/prims/jni.cpp` `JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args)` 67 | ```c++ 68 | if (Atomic::xchg(1, &vm_created) == 1) { 69 | return JNI_EEXIST; // already created, or create attempt in progress 70 | } 71 | if (Atomic::xchg(0, &safe_to_recreate_vm) == 0) { 72 | return JNI_ERR; // someone tried and failed and retry not allowed. 73 | } 74 | // ... 75 | result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again); 76 | if (result == JNI_OK) { 77 | JavaThread *thread = JavaThread::current(); 78 | /* thread is thread_in_vm here */ 79 | *vm = (JavaVM *)(&main_vm); 80 | *(JNIEnv**)penv = thread->jni_environment(); 81 | 82 | // Tracks the time application was running before GC 83 | RuntimeService::record_application_start(); 84 | 85 | // Notify JVMTI 86 | if (JvmtiExport::should_post_thread_life()) { 87 | JvmtiExport::post_thread_start(thread); 88 | } 89 | 90 | EventThreadStart event; 91 | if (event.should_commit()) { 92 | event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj())); 93 | event.commit(); 94 | } 95 | // ... 96 | ``` 97 | #### 4. `Threads::create_vm()` 98 | 位于 `src/hotspot/share/runtime/thread.cpp` 99 | 100 | ```c++ 101 | // ... 102 | 103 | // Attach the main thread to this os thread 104 | JavaThread* main_thread = new JavaThread(); 105 | main_thread->set_thread_state(_thread_in_vm); 106 | main_thread->initialize_thread_current(); 107 | // must do this before set_active_handles 108 | main_thread->record_stack_base_and_size(); 109 | main_thread->register_thread_stack_with_NMT(); 110 | main_thread->set_active_handles(JNIHandleBlock::allocate_block()); 111 | MACOS_AARCH64_ONLY(main_thread->init_wx()); 112 | 113 | if (!main_thread->set_as_starting_thread()) { 114 | vm_shutdown_during_initialization( 115 | "Failed necessary internal allocation. Out of swap space"); 116 | main_thread->smr_delete(); 117 | *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again 118 | return JNI_ENOMEM; 119 | } 120 | 121 | // ... 122 | ``` 123 | #### 5. `JavaThread::JavaThread()` 124 | `JavaThread* main_thread = new JavaThread();` 会触发 `JavaThread::JavaThread()` 的构造函数调用。 125 | 126 | #### 6. `JavaThread::initialize()` 127 | ```c++ 128 | //... 129 | set_jni_functions(jni_functions()); 130 | // ... 131 | ``` 132 | #### 7. `jni_functions()` 133 | `set_jni_functions(jni_functions());` 设置一堆初始化属性, 然后设置jni对应的方法。 134 | `jni_functions()` 所对应的数组 135 | ```c++ 136 | jni_NativeInterface = { 137 | NULL, 138 | NULL, 139 | NULL, 140 | 141 | NULL, 142 | 143 | jni_GetVersion, 144 | 145 | jni_DefineClass, 146 | jni_FindClass, 147 | 148 | jni_FromReflectedMethod, 149 | jni_FromReflectedField, 150 | 151 | jni_ToReflectedMethod, 152 | 153 | jni_GetSuperclass, 154 | jni_IsAssignableFrom, 155 | 156 | jni_ToReflectedField, 157 | 158 | jni_Throw, 159 | jni_ThrowNew, 160 | // ... 161 | ``` 162 | 163 | ## 流程图 164 | ![img](img/JNI_INIT_process.png) 165 | -------------------------------------------------------------------------------- /src/autorun/jvm/jni/README.md: -------------------------------------------------------------------------------- 1 | # JNI学习笔记 2 | 3 | ## JNI头文件生成 4 | 1. 创建 `.java` 文件 5 | 2. 增加 `native` 的相关方法 6 | 3. 使用 `javac` 生成 `.java` 文件的 `class` 文件和对应的 `.h` 头文件 7 | `javac -h jni_target_dictory jni.java file` 8 | > case:
9 | > `javac -h src/autorun/jvm/jni/ src/autorun/jvm/jni/HelloJni.java` 10 | 4. 如果使用clion类似工具开发时则需要在 `CMakeLists.txt` 增加生成好的 `.h` 文件方便编译 11 | > 在 `CMakeLists.txt` 的 `add_executable` 步骤中增加对应的 `.h` 文件。使IDE找到对应的头文件 12 | 5. 在 `jdk` 的 `$JAVA_HOME` 中将 `jni.h` 拷贝到工程项目中,并且按照第四步将 `jni.h` 文件增加到 `CMakeLists.txt` 中 13 | 6. 同时 `jni.h` 中用到了 `jni_md.h` 的头文件。按照第五步的操作方式 14 | 7. 编写 `.h` 头文件的实现。 15 | 16 | ## jvm 在生成 static 与 实例对象的方法时的差异 17 | 1. 首先如果是 `static` 的 `native` 方法, 参数名为 `jclass`. 换句话说 `jclass` 是拿到的被 `JNIHandles::make_local(klass)` 包装过的 `klass` 实例。 18 | 也就是说实际拿到的实际是jvm 的 `mirrorklass` 对象。至于为什么是JNIHandles包装后的,后续在 `OOP二分模型` 章节中会描述。此处不在赘述 19 | 20 | ## 编译环节 21 | 1. 编译 `so` 文件. 如果是c语言也就是.c文件编译时使用 22 | `gcc --dynamiclib sourceFile -o targetFile` 23 | 如果是c++ 则将上面命令中的 24 | `gcc` 替换为 `g++` 即可。 25 | 26 | ## 加载环节 27 | 1. 编写java代码,加载时可以使用 `System.load(file)` 或者使用 `System.loadLibrary(libname)` 加载对应的本地包 28 | 29 | `System.load(file)` 和 `System.loadLibrary(libname)` 差别。参考如下链接
30 | [Java System.load() 与 System.loadLibrary() 区别解析](https://www.jianshu.com/p/c8a575ad344f) -------------------------------------------------------------------------------- /src/autorun/jvm/jni/base/jawt_md.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Oracle designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Oracle in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 | * or visit www.oracle.com if you need additional information or have any 23 | * questions. 24 | */ 25 | 26 | #ifndef _JAVASOFT_JAWT_MD_H_ 27 | #define _JAVASOFT_JAWT_MD_H_ 28 | 29 | #include "jawt.h" 30 | 31 | #ifdef __OBJC__ 32 | #import 33 | #endif 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | /* 40 | * Mac OS X specific declarations for AWT native interface. 41 | * See notes in jawt.h for an example of use. 42 | */ 43 | 44 | /* 45 | * When calling JAWT_GetAWT with a JAWT version less than 1.7, you must pass this 46 | * flag or you will not be able to get a valid drawing surface and JAWT_GetAWT will 47 | * return false. This is to maintain compatibility with applications that used the 48 | * interface with Java 6 which had multiple rendering models. This flag is not necessary 49 | * when JAWT version 1.7 or greater is used as this is the only supported rendering mode. 50 | * 51 | * Example: 52 | * JAWT awt; 53 | * awt.version = JAWT_VERSION_1_4 | JAWT_MACOSX_USE_CALAYER; 54 | * jboolean success = JAWT_GetAWT(env, &awt); 55 | */ 56 | #define JAWT_MACOSX_USE_CALAYER 0x80000000 57 | 58 | /* 59 | * When the native Cocoa toolkit is in use, the pointer stored in 60 | * JAWT_DrawingSurfaceInfo->platformInfo points to a NSObject that conforms to the 61 | * JAWT_SurfaceLayers protocol. Setting the layer property of this object will cause the 62 | * specified layer to be overlaid on the Components rectangle. If the window the 63 | * Component belongs to has a CALayer attached to it, this layer will be accessible via 64 | * the windowLayer property. 65 | */ 66 | #ifdef __OBJC__ 67 | @protocol JAWT_SurfaceLayers 68 | @property (readwrite, retain) CALayer *layer; 69 | @property (readonly) CALayer *windowLayer; 70 | @end 71 | #endif 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif /* !_JAVASOFT_JAWT_MD_H_ */ 78 | -------------------------------------------------------------------------------- /src/autorun/jvm/jni/base/jni_md.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. 3 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | */ 25 | 26 | #ifndef _JAVASOFT_JNI_MD_H_ 27 | #define _JAVASOFT_JNI_MD_H_ 28 | 29 | #define JNIEXPORT __attribute__((visibility("default"))) 30 | #define JNIIMPORT __attribute__((visibility("default"))) 31 | #define JNICALL 32 | 33 | typedef int ; 34 | #ifdef _LP64 /* 64-bit */ 35 | typedef long jlong; 36 | #else 37 | typedef long long jlong; 38 | #endif 39 | 40 | typedef signed char jbyte; 41 | 42 | #endif /* !_JAVASOFT_JNI_MD_H_ */ 43 | -------------------------------------------------------------------------------- /src/autorun/jvm/jni/build_jni.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ ! -f $(which g++) ]]; then 4 | echo 'not found in path' 5 | exit 6 | fi 7 | 8 | SOURCE_FILE=HelloJni.cpp 9 | TARGET_PATH=../../../../test/autorun/jvm/jni/lib 10 | TARGET_FILE=HelloJni.so 11 | # use g++ in build cpp file 12 | g++ -dynamiclib $SOURCE_FILE -o $TARGET_PATH/$TARGET_FILE 13 | 14 | # shellcheck disable=SC2181 15 | if [ 0 == $? ]; then 16 | echo 'build successfully' 17 | else 18 | echo 'build fail!' 19 | fi -------------------------------------------------------------------------------- /src/autorun/jvm/jni/img/JNI_INIT_process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/jni/img/JNI_INIT_process.png -------------------------------------------------------------------------------- /src/autorun/jvm/jvmti/JVMTI.md: -------------------------------------------------------------------------------- 1 | # JVMTI 2 | 3 | ## 什么是JVMTI 4 | 5 | JVMTI[^1] 全称是`Java Virtual Machine Tool Interfece`是开发和监控工具使用的编程接口。 它为正在运行中的Java应用提供了检查和控制其状态的方法。它是`JVMDI`(JVM Debug Interface)和`JVMPI`(JVM Profiling Interface)的一种整合. 6 | 7 | 8 | 9 | 10 | 11 | [^1]: https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html 12 | 13 | ## 部署代理 14 | 15 | 代理一般是以动态链接库的形式部署,如在`windows`上是`DLL`,在`Solaris`上是`so`,在`mac`上则是`dylib`
16 | 命令行参数:
17 | * -agentlib:\=\ 18 |

19 | -agentlib: 后面的名称是要加载的库的名称. 扩展为操作系统特定的文件名。 将在启动时传递给代理。 例如,如果指定选项-agentlib:foo=opt1,opt2,则VM会尝试从Windows下的系统PATH加载共享库foo.dll,或者Solaris运行环境下从LD_LIBRARY_PATH加载libfoo.so。在`mac`操作系统下不需要设置LD_LIBRARY_PATH ,java 二进制文件将通过它自己的运行路径查找它所依赖的库blifoo.dylib, 如果代理库静态链接到可执行文件中,则不会发生实际加载. 20 |

21 | 22 | * -agentpath:\=\ 23 |

24 | -agentpath: 后面的路径是加载库的绝对路径。 不会发生库名扩展。 将在启动时传递给代理。 例如,如果指定选项 25 | -agentpath:c:\myLibs\foo.dll=opt1,opt2,VM 将尝试加载共享库 c:\myLibs\foo.dll。 如果代理库静态链接到可执行文件中,则不会发生实际加载。

26 | 27 | * -agentlib:jdwp=\ 28 |

29 | 如果JVMTI代理需要特定的库,例如 jdwp,则可以在启动时指定路径. 30 |

31 | ## 生命周期 32 | 代理有两种启动方式,每个代理只调用一次启动函数。 33 | * 代理跟随目标JVM一起启动 Agent_OnLoad函数将会被调用 34 | * 附加到已启动的JVM上 Agent_OnAttach函数将会被调用
35 | 36 | 代理结束时会执行Agent_OnUnload函数(可选)
37 | 38 | > 代理必须包含jvmti.h带有以下语句的文件:`#include `,并且必须包含一个`Agent_OnLoad`函数. 39 | 40 | 41 | ## JVMTI的事件处理 42 | 43 | JVMTI依赖于每个事件的回调.一般会在`Agent_OnLoad`函数中添加事件的回调,例如要使用`InterruptThread`功能,则`can_signal_thread`功能必须打开.
44 | ```c++ 45 | // JVMTI所支持的功能 46 | typedef struct { 47 | unsigned int can_tag_objects : 1; 48 | unsigned int can_generate_field_modification_events : 1; 49 | unsigned int can_generate_field_access_events : 1; 50 | unsigned int can_get_bytecodes : 1; 51 | unsigned int can_get_synthetic_attribute : 1; 52 | unsigned int can_get_owned_monitor_info : 1; 53 | unsigned int can_get_current_contended_monitor : 1; 54 | unsigned int can_get_monitor_info : 1; 55 | unsigned int can_pop_frame : 1; 56 | unsigned int can_redefine_classes : 1; 57 | unsigned int can_signal_thread : 1; 58 | unsigned int can_get_source_file_name : 1; 59 | unsigned int can_get_line_numbers : 1; 60 | unsigned int can_get_source_debug_extension : 1; 61 | unsigned int can_access_local_variables : 1; 62 | unsigned int can_maintain_original_method_order : 1; 63 | unsigned int can_generate_single_step_events : 1; 64 | unsigned int can_generate_exception_events : 1; 65 | unsigned int can_generate_frame_pop_events : 1; 66 | unsigned int can_generate_breakpoint_events : 1; 67 | unsigned int can_suspend : 1; 68 | unsigned int can_redefine_any_class : 1; 69 | unsigned int can_get_current_thread_cpu_time : 1; 70 | unsigned int can_get_thread_cpu_time : 1; 71 | unsigned int can_generate_method_entry_events : 1; 72 | unsigned int can_generate_method_exit_events : 1; 73 | unsigned int can_generate_all_class_hook_events : 1; 74 | unsigned int can_generate_compiled_method_load_events : 1; 75 | unsigned int can_generate_monitor_events : 1; 76 | unsigned int can_generate_vm_object_alloc_events : 1; 77 | unsigned int can_generate_native_method_bind_events : 1; 78 | unsigned int can_generate_garbage_collection_events : 1; 79 | unsigned int can_generate_object_free_events : 1; 80 | unsigned int can_force_early_return : 1; 81 | unsigned int can_get_owned_monitor_stack_depth_info : 1; 82 | unsigned int can_get_constant_pool : 1; 83 | unsigned int can_set_native_method_prefix : 1; 84 | unsigned int can_retransform_classes : 1; 85 | unsigned int can_retransform_any_class : 1; 86 | unsigned int can_generate_resource_exhaustion_heap_events : 1; 87 | unsigned int can_generate_resource_exhaustion_threads_events : 1; 88 | unsigned int : 7; 89 | unsigned int : 16; 90 | unsigned int : 16; 91 | unsigned int : 16; 92 | unsigned int : 16; 93 | unsigned int : 16; 94 | } jvmtiCapabilities; 95 | 96 | // JVMTI 所支持的事件类型 97 | typedef enum { 98 | JVMTI_MIN_EVENT_TYPE_VAL = 50, 99 | JVMTI_EVENT_VM_INIT = 50, 100 | JVMTI_EVENT_VM_DEATH = 51, 101 | JVMTI_EVENT_THREAD_START = 52, 102 | JVMTI_EVENT_THREAD_END = 53, 103 | JVMTI_EVENT_CLASS_FILE_LOAD_HOOK = 54, 104 | JVMTI_EVENT_CLASS_LOAD = 55, 105 | JVMTI_EVENT_CLASS_PREPARE = 56, 106 | JVMTI_EVENT_VM_START = 57, 107 | JVMTI_EVENT_EXCEPTION = 58, 108 | JVMTI_EVENT_EXCEPTION_CATCH = 59, 109 | JVMTI_EVENT_SINGLE_STEP = 60, 110 | JVMTI_EVENT_FRAME_POP = 61, 111 | JVMTI_EVENT_BREAKPOINT = 62, 112 | JVMTI_EVENT_FIELD_ACCESS = 63, 113 | JVMTI_EVENT_FIELD_MODIFICATION = 64, 114 | JVMTI_EVENT_METHOD_ENTRY = 65, 115 | JVMTI_EVENT_METHOD_EXIT = 66, 116 | JVMTI_EVENT_NATIVE_METHOD_BIND = 67, 117 | JVMTI_EVENT_COMPILED_METHOD_LOAD = 68, 118 | JVMTI_EVENT_COMPILED_METHOD_UNLOAD = 69, 119 | JVMTI_EVENT_DYNAMIC_CODE_GENERATED = 70, 120 | JVMTI_EVENT_DATA_DUMP_REQUEST = 71, 121 | JVMTI_EVENT_MONITOR_WAIT = 73, 122 | JVMTI_EVENT_MONITOR_WAITED = 74, 123 | JVMTI_EVENT_MONITOR_CONTENDED_ENTER = 75, 124 | JVMTI_EVENT_MONITOR_CONTENDED_ENTERED = 76, 125 | JVMTI_EVENT_RESOURCE_EXHAUSTED = 80, 126 | JVMTI_EVENT_GARBAGE_COLLECTION_START = 81, 127 | JVMTI_EVENT_GARBAGE_COLLECTION_FINISH = 82, 128 | JVMTI_EVENT_OBJECT_FREE = 83, 129 | JVMTI_EVENT_VM_OBJECT_ALLOC = 84, 130 | JVMTI_MAX_EVENT_TYPE_VAL = 84 131 | } jvmtiEvent; 132 | ``` 133 | 134 | 135 | ```C++ 136 | jvmtiCapabilities capabilities = {0}; 137 | // 设置所支持的功能 138 | capabilities.can_generate_exception_events = 1; 139 | capabilities.can_get_bytecodes = 1; 140 | capabilities.can_get_constant_pool = 1; 141 | // 使用AddCapabilities函数将其添加到JVMTI环境中 142 | jvmti->AddCapabilities(&capabilities); 143 | 144 | // 注册事件通知 启用了VM初始化,异常,线程启动和结束等几个事件,注册的每个事件都必须有一个指定的回调函数, 如当生类型为Exception的事件时,会调用ExceptionCallback 145 | jvmtiEventCallbacks callbacks = {0}; 146 | callbacks.VMInit = VMInit; 147 | callbacks.Exception = ExceptionCallback; 148 | callbacks.ThreadStart = ThreadStartCallback; 149 | callbacks.ThreadEnd = ThreadEndCallback; 150 | jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 151 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL); 152 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION, NULL); 153 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL); 154 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, NULL); 155 | ``` 156 | 157 | ## see also 158 | [JVM事件处理](https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/share/back/eventHandler.c)
159 | [JVMTI](https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/share/javavm/export/jvmti.h) 160 | -------------------------------------------------------------------------------- /src/autorun/jvm/jvmti/README.md: -------------------------------------------------------------------------------- 1 | # JVM TI tools 2 | 3 | Collection of small Java serviceability improvements based on 4 | [JVM Tool Interface](https://docs.oracle.com/en/java/javase/11/docs/specs/jvmti.html). 5 | 6 | - [richNPE](#richnpe) 7 | - [vmtrace](#vmtrace) 8 | - [antimodule](#antimodule) 9 | - [heapsampler](#heapsampler) 10 | - [faketime](#faketime) 11 | - [methodCalledCount](#methodCalledCount) 12 | 13 | ## richNPE 14 | 15 | Enhances `NullPointerException` thrown by JVM with a detailed error message. 16 | 17 | For example, there are several reasons why the following code may throw `NullPointerException`: 18 | 19 | long value = source.map().get(key); 20 | 21 | Either 22 | 23 | - `source` is null, or 24 | - `map()` returns null, or 25 | - `get()` returns null and the subsequent unboxing fails. 26 | 27 | The standard JDK exception message does not give a clue which expression exactly caused NPE, 28 | but when using this tool, the message will look like 29 | 30 | java.lang.NullPointerException: Called method 'get()' on null object at bci 19 31 | 32 | While [JDK-8218628](https://bugs.openjdk.java.net/browse/JDK-8218628) is going to be implemented 33 | in JDK 13, the given agent improves NPE messages for existing JDK 8-12. 34 | 35 | #### Compilation 36 | 37 | # Linux 38 | g++ -O2 -fPIC -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -olibrichNPE.so richNPE.cpp 39 | 40 | # Windows 41 | cl /O2 /LD /I "%JAVA_HOME%/include" -I "%JAVA_HOME%/include/win32" richNPE.cpp 42 | 43 | #### Usage 44 | 45 | java -agentpath:/path/to/librichNPE.so MainClass 46 | 47 | 48 | ## vmtrace 49 | 50 | Traces basic JVM events like 51 | 52 | - [Thread started / terminated](stackframe/stackframe.cpp) 53 | - GC started / finished 54 | - Class loading / class prepared 55 | - Method compiled / unloaded 56 | - Dynamic code generated 57 | 58 | #### Example output 59 | 60 | ```text 61 | [0.05588] Method compiled: java/lang/String. (1056 bytes) 62 | [0.05597] Loading class: java/io/FileOutputStream$1 (557 bytes) 63 | [0.05600] Class prepared: java/io/FileOutputStream$1 64 | [0.05602] Method compiled: java/lang/String.hashCode (512 bytes) 65 | [0.05618] Thread started: main 66 | [0.05622] Loading class: sun/launcher/LauncherHelper (14692 bytes) 67 | [0.05640] Dynamic code generated: I2C/C2I adapters(0xabbebebea0000000)@0x00000000032c38a0 (392 bytes) 68 | [0.05642] Dynamic code generated: I2C/C2I adapters(0xbebebea0)@0x00000000032c36a0 (376 bytes) 69 | ... 70 | ``` 71 | 72 | #### Compilation 73 | 74 | # Linux 75 | g++ -O2 -fPIC -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -olibvmtrace.so vmtrace.cpp 76 | 77 | # Windows 78 | cl /O2 /LD /I "%JAVA_HOME%/include" -I "%JAVA_HOME%/include/win32" vmtrace.cpp 79 | 80 | #### Usage 81 | 82 | java -agentpath:/path/to/libvmtrace.so[=output.log] MainClass 83 | 84 | The log will be written to the file specified in the agent arguments, 85 | or to `stderr` if no arguments given. 86 | 87 | 88 | ## antimodule 89 | 90 | Removes Jigsaw restrictions in JDK 9+ by opening and exporting all 91 | JDK modules to the unnamed module. 92 | 93 | This allows Reflection access to all JDK private fields and methods 94 | with no warnings, even when `--illegal-access=deny` option specified. 95 | This also makes all JDK internal classes like `sun.nio.ch.DirectBuffer` 96 | accessible by the unnamed module. 97 | 98 | The agent is helpful for running older Java applications on JDK 9+ 99 | when application uses private APIs. 100 | 101 | #### Compilation 102 | 103 | # Linux 104 | g++ -O2 -fPIC -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -olibantimodule.so antimodule.cpp 105 | 106 | # Windows 107 | cl /O2 /LD /I "%JAVA_HOME%/include" -I "%JAVA_HOME%/include/win32" antimodule.cpp 108 | 109 | #### Usage 110 | 111 | java -agentpath:/path/to/libantimodule.so MainClass 112 | 113 | 114 | ## heapsampler 115 | 116 | The example of low-overhead heap allocation profiler based on 117 | [JEP 331](https://openjdk.java.net/jeps/331). 118 | 119 | Requires JDK 11 or later. 120 | 121 | #### Example output 122 | 123 | The output is generated in collapsed stacktraces format suitable for 124 | generating [Flame Graphs](https://github.com/brendangregg/FlameGraph/). 125 | 126 | ```text 127 | Allocate.main;java.lang.Long.valueOf;java.lang.Long 49 128 | Allocate.main;java.lang.Object[] 31 129 | java.lang.Thread.run;jdk.internal.misc.Signal$1.run;java.lang.Terminator$1.handle;java.lang.Class 1 130 | jdk.internal.misc.Signal.dispatch;java.lang.Class 1 131 | ``` 132 | 133 | See [async-profiler](https://github.com/jvm-profiling-tools/async-profiler) 134 | for more information about allocation profiling and Flame Graphs. 135 | Note that `heapsampler` works only on JDK 11+, while `async-profiler` 136 | is capable of generating allocation profiles on JDK 7+. 137 | 138 | #### Compilation 139 | 140 | # Linux 141 | g++ -O2 -fPIC -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -olibheapsampler.so heapsampler.cpp 142 | 143 | # Windows 144 | cl /O2 /LD /I "%JAVA_HOME%/include" -I "%JAVA_HOME%/include/win32" heapsampler.cpp 145 | 146 | #### Usage 147 | 148 | java -agentpath:/path/to/libheapsampler.so[=interval] MainClass > output.txt 149 | 150 | The agent can be also loaded dynamically in run-time: 151 | 152 | jcmd JVMTI.agent_load /path/to/libheapsampler.so [interval] 153 | 154 | The optional `interval` argument specifies the sampling interval in bytes. 155 | The default value is 512 KB. 156 | The output is printed on `stdout`. 157 | 158 | 159 | ## faketime 160 | 161 | Changes current date/time for a Java application without affecting system date/time. 162 | 163 | The agent rebinds the native entry for `System.currentTimeMillis` and related methods 164 | and adds the specified offset to the times returned by these methods. 165 | 166 | #### Compilation 167 | 168 | # Linux 169 | g++ -O2 -fPIC -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -olibfaketime.so faketime.cpp 170 | 171 | # Windows 172 | cl /O2 /LD /I "%JAVA_HOME%/include" -I "%JAVA_HOME%/include/win32" faketime.cpp 173 | 174 | #### Usage 175 | 176 | java -agentpath:/path/to/libfaketime.so=timestamp|+-offset MainClass 177 | 178 | where the agent argument is either 179 | 180 | - absolute `timestamp` in milliseconds from Epoch, or 181 | - relative `offset` in milliseconds, if `offset` starts with `+` or `-` 182 | 183 | Since `System.currentTimeMillis` is a JVM intrinsic method, it's also required to disable 184 | the corresponding intrinsic to make sure the JNI method is called: 185 | 186 | java -XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_currentTimeMillis -XX:CompileCommand=dontinline,java.lang.System::currentTimeMillis 187 | 188 | 189 | ## methodCalledCount 190 | 191 | Count the number of times each method is called. Print the number of calls to all methods when unload agent. 192 | 193 | #### Compilation 194 | 195 | # Linux 196 | g++ -O2 -fPIC -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -o liba.so methodCalledCount.cpp 197 | 198 | # mac 199 | g++ -O2 -fPIC -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -o liba.dylib methodCalledCount.cpp 200 | 201 | # Windows 202 | cl /O2 /LD /I "%JAVA_HOME%/include" -I "%JAVA_HOME%/include/win32" methodCalledCount.cpp 203 | 204 | 205 | #### Usage 206 | 207 | java -agentpath:/path/to/liba.dylib MainClass 208 | 209 | 210 | #### Example output 211 | ```text 212 | Method name: AbstractCollection.java# called 8 nums. 213 | Method name: AbstractList.java# called 6 nums. 214 | Method name: AbstractMap.java# called 7 nums. 215 | Method name: AbstractSequentialList.java# called 4 nums. 216 | Method name: AbstractSet.java# called 1 nums. 217 | Method name: AbstractStringBuilder.java# called 71 nums. 218 | Method name: AbstractStringBuilder.java#append called 196 nums. 219 | Method name: AbstractStringBuilder.java#ensureCapacityInternal called 196 nums. 220 | Method name: AbstractStringBuilder.java#newCapacity called 68 nums. 221 | Method name: AccessControlContext.java#calculateFields called 5 nums. 222 | Method name: AccessControlContext.java#combine called 5 nums. 223 | Method name: AccessControlContext.java#optimize called 5 nums. 224 | Method name: AccessController.java#doPrivileged called 37 nums. 225 | Method name: AccessController.java#getContext called 5 nums. 226 | Method name: AccessController.java#getInheritedAccessControlContext called 5 nums. 227 | Method name: AccessController.java#getStackAccessControlContext called 5 nums. 228 | ``` 229 | -------------------------------------------------------------------------------- /src/autorun/jvm/jvmti/antimodule/antimodule.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Odnoklassniki Ltd, Mail.Ru Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | void JNICALL VMInit(jvmtiEnv* jvmti, JNIEnv* env, jthread thread) { 21 | jclass Module = env->FindClass("java/lang/Module"); 22 | if (Module == NULL) { 23 | // Seems like pre-module JDK 24 | env->ExceptionClear(); 25 | return; 26 | } 27 | 28 | jmethodID getPackages = env->GetMethodID(Module, "getPackages", "()Ljava/util/Set;"); 29 | 30 | jmethodID getUnnamedModule = env->GetMethodID( 31 | env->FindClass("java/lang/ClassLoader"), "getUnnamedModule", "()Ljava/lang/Module;"); 32 | 33 | jmethodID toString = env->GetMethodID( 34 | env->FindClass("java/lang/Object"), "toString", "()Ljava/lang/String;"); 35 | 36 | // Get unnamed module of the current thread's ClassLoader 37 | jvmtiThreadInfo thread_info; 38 | jvmti->GetThreadInfo(NULL, &thread_info); 39 | 40 | jobject unnamed_module = env->CallObjectMethod(thread_info.context_class_loader, getUnnamedModule); 41 | 42 | jint module_count = 0; 43 | jobject* modules = NULL; 44 | jvmti->GetAllModules(&module_count, &modules); 45 | 46 | // Scan all loaded modules 47 | for (int i = 0; i < module_count; i++) { 48 | jvmti->AddModuleReads(modules[i], unnamed_module); 49 | 50 | // Get all module packages as one string: "[java.lang, java.io, ...]" 51 | jobject packages = env->CallObjectMethod(modules[i], getPackages); 52 | jstring str = (jstring) env->CallObjectMethod(packages, toString); 53 | 54 | char* c_str = (char*) env->GetStringUTFChars(str, NULL); 55 | if (c_str == NULL) continue; 56 | 57 | // Export and open every package to the unnamed module 58 | char* package = strtok(c_str + 1, ", ]"); 59 | while (package != NULL) { 60 | jvmti->AddModuleExports(modules[i], package, unnamed_module); 61 | jvmti->AddModuleOpens(modules[i], package, unnamed_module); 62 | package = strtok(NULL, ", ]"); 63 | } 64 | 65 | env->ReleaseStringUTFChars(str, c_str); 66 | } 67 | 68 | jvmti->Deallocate((unsigned char*) modules); 69 | } 70 | 71 | JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { 72 | jvmtiEnv* jvmti; 73 | vm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_0); 74 | 75 | jvmtiEventCallbacks callbacks = {0}; 76 | callbacks.VMInit = VMInit; 77 | jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 78 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL); 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /src/autorun/jvm/jvmti/faketime/faketime.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Odnoklassniki Ltd, Mail.Ru Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | static jlong (*real_time_millis)(JNIEnv*, jclass) = NULL; 23 | static jlong (*real_nano_time_adjustment)(JNIEnv*, jclass, jlong) = NULL; 24 | static jlong offset_millis = 0; 25 | 26 | jlong JNICALL fake_time_millis(JNIEnv* env, jclass cls) { 27 | return real_time_millis(env, cls) + offset_millis; 28 | } 29 | 30 | jlong JNICALL fake_nano_time_adjustment(JNIEnv* env, jclass cls, jlong offset_seconds) { 31 | return real_nano_time_adjustment(env, cls, offset_seconds) + offset_millis * 1000000; 32 | } 33 | 34 | void JNICALL NativeMethodBind(jvmtiEnv* jvmti, JNIEnv* env, jthread thread, jmethodID method, 35 | void* address, void** new_address_ptr) { 36 | char* name; 37 | if (jvmti->GetMethodName(method, &name, NULL, NULL) == 0) { 38 | if (real_time_millis == NULL && strcmp(name, "currentTimeMillis") == 0) { 39 | real_time_millis = (jlong (*)(JNIEnv*, jclass)) address; 40 | *new_address_ptr = (void*) fake_time_millis; 41 | } else if (real_nano_time_adjustment == NULL && strcmp(name, "getNanoTimeAdjustment") == 0) { 42 | real_nano_time_adjustment = (jlong (*)(JNIEnv*, jclass, jlong)) address; 43 | *new_address_ptr = (void*) fake_nano_time_adjustment; 44 | } 45 | jvmti->Deallocate((unsigned char*) name); 46 | } 47 | } 48 | 49 | JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { 50 | if (options != NULL) { 51 | if (options[0] == '+' || options[0] == '-') { 52 | offset_millis = atoll(options); // time offset 53 | } else { 54 | offset_millis = atoll(options) - time(NULL) * 1000LL; // absolute time 55 | } 56 | } 57 | 58 | jvmtiEnv* jvmti; 59 | vm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_0); 60 | 61 | jvmtiCapabilities capabilities = {0}; 62 | capabilities.can_generate_native_method_bind_events = 1; 63 | #if JNI_VERSION_9 64 | jvmtiCapabilities potential_capabilities; 65 | jvmti->GetPotentialCapabilities(&potential_capabilities); 66 | capabilities.can_generate_early_vmstart = potential_capabilities.can_generate_early_vmstart; 67 | #endif 68 | jvmti->AddCapabilities(&capabilities); 69 | 70 | jvmtiEventCallbacks callbacks = {0}; 71 | callbacks.NativeMethodBind = NativeMethodBind; 72 | jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 73 | 74 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_NATIVE_METHOD_BIND, NULL); 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /src/autorun/jvm/jvmti/heapsampler/heapsampler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Odnoklassniki Ltd, Mail.Ru Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define MAX_STACK_DEPTH 1024 25 | 26 | struct Frame { 27 | jlong samples; 28 | jlong bytes; 29 | std::map children; 30 | }; 31 | 32 | static jvmtiEnv* jvmti = NULL; 33 | static jrawMonitorID tree_lock; 34 | static std::map root; 35 | 36 | // Converts JVM internal class signature to human readable name 37 | static std::string decode_class_signature(char* class_sig) { 38 | switch (class_sig[0]) { 39 | case 'B': return "byte"; 40 | case 'C': return "char"; 41 | case 'S': return "short"; 42 | case 'I': return "int"; 43 | case 'J': return "long"; 44 | case 'F': return "float"; 45 | case 'D': return "double"; 46 | case 'Z': return "boolean"; 47 | case '[': return decode_class_signature(class_sig + 1) + "[]"; 48 | } 49 | 50 | // Strip 'L' and ';' 51 | class_sig++; 52 | class_sig[std::strlen(class_sig) - 1] = 0; 53 | 54 | // Replace '/' with '.' 55 | for (char* c = class_sig; *c; c++) { 56 | if (*c == '/') *c = '.'; 57 | } 58 | 59 | return class_sig; 60 | } 61 | 62 | static std::string get_method_name(jmethodID method) { 63 | jclass method_class; 64 | char* class_sig = NULL; 65 | char* method_name = NULL; 66 | std::string result; 67 | 68 | if (jvmti->GetMethodDeclaringClass(method, &method_class) == 0 && 69 | jvmti->GetClassSignature(method_class, &class_sig, NULL) == 0 && 70 | jvmti->GetMethodName(method, &method_name, NULL, NULL) == 0) { 71 | result.assign(decode_class_signature(class_sig) + "." + method_name); 72 | } else { 73 | result.assign("[unknown]"); 74 | } 75 | 76 | jvmti->Deallocate((unsigned char*) method_name); 77 | jvmti->Deallocate((unsigned char*) class_sig); 78 | return result; 79 | } 80 | 81 | static void dump_tree(const std::string stack_line, const std::string& class_name, const Frame* f) { 82 | if (f->samples > 0) { 83 | // Output sample in 'collapsed stack traces' format understood by flamegraph.pl 84 | std::cout << stack_line << class_name << "_[i] " << f->samples << std::endl; 85 | } 86 | for (auto it = f->children.begin(); it != f->children.end(); ++it) { 87 | dump_tree(stack_line + get_method_name(it->first) + ";", class_name, &it->second); 88 | } 89 | } 90 | 91 | static void dump_profile() { 92 | for (auto it = root.begin(); it != root.end(); ++it) { 93 | dump_tree("", it->first, &it->second); 94 | } 95 | } 96 | 97 | static void record_stack_trace(char* class_sig, jvmtiFrameInfo* frames, jint count, jlong size) { 98 | Frame* f = &root[decode_class_signature(class_sig)]; 99 | while (--count >= 0) { 100 | f = &f->children[frames[count].method]; 101 | } 102 | f->samples++; 103 | f->bytes += size; 104 | } 105 | 106 | void JNICALL SampledObjectAlloc(jvmtiEnv* jvmti, JNIEnv* env, jthread thread, 107 | jobject object, jclass object_klass, jlong size) { 108 | 109 | jvmtiFrameInfo frames[MAX_STACK_DEPTH]; 110 | jint count; 111 | if (jvmti->GetStackTrace(thread, 0, MAX_STACK_DEPTH, frames, &count) != 0) { 112 | return; 113 | } 114 | 115 | char* class_sig; 116 | if (jvmti->GetClassSignature(object_klass, &class_sig, NULL) != 0) { 117 | return; 118 | } 119 | 120 | jvmti->RawMonitorEnter(tree_lock); 121 | record_stack_trace(class_sig, frames, count, size); 122 | jvmti->RawMonitorExit(tree_lock); 123 | 124 | jvmti->Deallocate((unsigned char*) class_sig); 125 | } 126 | 127 | void JNICALL DataDumpRequest(jvmtiEnv* jvmti) { 128 | jvmti->RawMonitorEnter(tree_lock); 129 | dump_profile(); 130 | jvmti->RawMonitorExit(tree_lock); 131 | } 132 | 133 | void JNICALL VMDeath(jvmtiEnv* jvmti, JNIEnv* env) { 134 | DataDumpRequest(jvmti); 135 | } 136 | 137 | JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { 138 | vm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_0); 139 | 140 | jvmti->CreateRawMonitor("tree_lock", &tree_lock); 141 | 142 | jvmtiCapabilities capabilities = {0}; 143 | capabilities.can_generate_sampled_object_alloc_events = 1; 144 | jvmti->AddCapabilities(&capabilities); 145 | 146 | if (options != NULL && options[0] >= '0' && options[0] <= '9') { 147 | jvmti->SetHeapSamplingInterval(std::atoi(options)); 148 | } 149 | 150 | jvmtiEventCallbacks callbacks = {0}; 151 | callbacks.SampledObjectAlloc = SampledObjectAlloc; 152 | callbacks.DataDumpRequest = DataDumpRequest; 153 | callbacks.VMDeath = VMDeath; 154 | jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 155 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL); 156 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, NULL); 157 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL); 158 | 159 | return 0; 160 | } 161 | 162 | JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) { 163 | // Protect against repeated load 164 | if (jvmti != NULL) { 165 | return 0; 166 | } 167 | return Agent_OnLoad(vm, options, reserved); 168 | } 169 | -------------------------------------------------------------------------------- /src/autorun/jvm/jvmti/methodCalledCount/methodCalledCount.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | map methodCount; 8 | 9 | typedef struct { 10 | 11 | /* JVMTI Environment */ 12 | 13 | jvmtiEnv *jvmti; 14 | 15 | jboolean vm_is_started; 16 | 17 | /* Data access Lock */ 18 | 19 | jrawMonitorID lock; 20 | 21 | } GlobalAgentData; 22 | 23 | static GlobalAgentData *gdata; 24 | 25 | static void 26 | enter_critical_section(jvmtiEnv *jvmti) 27 | { 28 | jvmtiError error; 29 | error = jvmti->RawMonitorEnter(gdata->lock); 30 | } 31 | 32 | 33 | void ExceptionCallback 34 | (jvmtiEnv *jvmti_env, 35 | JNIEnv* jni_env, 36 | jthread thread, 37 | jmethodID method, 38 | jlocation location, 39 | jobject exception, 40 | jmethodID catch_method, 41 | jlocation catch_location) { 42 | char *methodName; 43 | char *signature; 44 | char *generic; 45 | jvmti_env->GetMethodName(method,&methodName,&signature,&generic); 46 | jvmtiThreadInfo threadInfo; 47 | jvmti_env->GetThreadInfo(thread,&threadInfo); 48 | // printf("In thread %s method name is: %s, signature is %s, generic is %s\n", threadInfo->name, methodName,signature,generic); 49 | std::cout << "Current thread " << threadInfo.name << ", method is " << methodName << ", signature is " << signature << " throw exception;" << std::endl; 50 | 51 | jint threads_count_ptr; 52 | jthread *threads_ptr; 53 | jvmtiError err = jvmti_env->GetAllThreads(&threads_count_ptr,&threads_ptr); 54 | 55 | if (err != JVMTI_ERROR_NONE) { 56 | printf("(GetAllThreads) Error expected: %d, got: %d\n", JVMTI_ERROR_NONE, err); 57 | printf("\n"); 58 | } 59 | 60 | jvmtiThreadInfo info1; 61 | if (err == JVMTI_ERROR_NONE && threads_count_ptr >= 1) { 62 | 63 | int i = 0; 64 | 65 | printf("Thread Count: %d\n", threads_count_ptr); 66 | 67 | for ( i=0; i < threads_count_ptr; i++) { 68 | 69 | /* Make sure the stack variables are garbage free */ 70 | 71 | (void)memset(&info1,0, sizeof(info1)); 72 | 73 | jvmtiError err1 = jvmti_env->GetThreadInfo(threads_ptr[i], &info1); 74 | 75 | if (err1 != JVMTI_ERROR_NONE) { 76 | 77 | printf("(GetThreadInfo) Error expected: %d, got: %d\n", JVMTI_ERROR_NONE, err1); 78 | 79 | printf("\n"); 80 | 81 | } 82 | } 83 | printf("Running Thread#%d: %s, Priority: %d, context class loader:%s\n", i+1,info1.name,info1.priority,(info1.context_class_loader == NULL ? ": NULL" : "Not Null")); 84 | } 85 | } 86 | 87 | 88 | void MethodEntryCallback(jvmtiEnv *jvmti_env, 89 | JNIEnv* jni_env, 90 | jthread thread, 91 | jmethodID method) { 92 | char *methodName; 93 | char* signature_ptr; 94 | char* generic_ptr; 95 | jvmti_env->GetMethodName(method,&methodName,&signature_ptr,&generic_ptr); 96 | jclass clazz; 97 | jvmtiError err = jvmti_env->GetMethodDeclaringClass(method,&clazz); 98 | 99 | char* sourceName; 100 | err = jvmti_env->GetSourceFileName(clazz,&sourceName); 101 | if(err != 0) { 102 | printf("GetSourceFileName error code is %d\n",err); 103 | return; 104 | } 105 | string tmp = string(sourceName) + string("#") + string(methodName); 106 | ++methodCount[tmp]; 107 | } 108 | static void 109 | exit_critical_section(jvmtiEnv *jvmti) 110 | 111 | { 112 | 113 | // jvmtiError error; 114 | 115 | jvmti->RawMonitorExit(gdata->lock); 116 | 117 | // check_jvmti_error(jvmti, error, "Cannot exit with raw monitor"); 118 | 119 | } 120 | 121 | 122 | JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { 123 | static GlobalAgentData data; 124 | 125 | (void)memset((void*)&data, 0, sizeof(data)); 126 | 127 | gdata = &data; 128 | jvmtiEnv* jvmti; 129 | vm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_0); 130 | gdata->jvmti = jvmti; 131 | 132 | jvmtiError error; 133 | error = jvmti->CreateRawMonitor("agent data",&(gdata->lock)); 134 | printf("load agent...\n"); 135 | jvmtiCapabilities capa; 136 | (void)memset(&capa, 1, sizeof(jvmtiCapabilities)); 137 | capa.can_generate_method_entry_events = 1; 138 | capa.can_generate_method_exit_events = 1; 139 | capa.can_generate_exception_events = 1; 140 | capa.can_get_source_file_name = 1; 141 | jvmti->AddCapabilities(&capa); 142 | 143 | jvmtiEventCallbacks callbacks = {0}; 144 | callbacks.MethodEntry = MethodEntryCallback; 145 | callbacks.Exception = ExceptionCallback; 146 | jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 147 | 148 | jvmti->SetEventNotificationMode(JVMTI_ENABLE,JVMTI_EVENT_EXCEPTION,NULL); 149 | jvmti->SetEventNotificationMode(JVMTI_ENABLE,JVMTI_EVENT_METHOD_ENTRY,NULL); 150 | jvmti->SetEventNotificationMode(JVMTI_ENABLE,JVMTI_EVENT_METHOD_EXIT,NULL); 151 | 152 | return 0; 153 | 154 | } 155 | 156 | JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) 157 | 158 | { 159 | auto b = methodCount.cbegin(), e = methodCount.cend(); 160 | while (b != e) { 161 | std::cout << "Method name: " << b->first << " called " << b->second << " nums." << std::endl; 162 | ++b; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/autorun/jvm/jvmti/richNPE/richNPE.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Odnoklassniki Ltd, Mail.Ru Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | typedef unsigned char u1; 24 | typedef unsigned short u2; 25 | 26 | static const char* get_exception_message(u1 bytecode) { 27 | switch (bytecode) { 28 | case JVM_OPC_iaload: return "Load from null int array at bci %d"; 29 | case JVM_OPC_laload: return "Load from null long array at bci %d"; 30 | case JVM_OPC_faload: return "Load from null float array at bci %d"; 31 | case JVM_OPC_daload: return "Load from null double array at bci %d"; 32 | case JVM_OPC_aaload: return "Load from null Object array at bci %d"; 33 | case JVM_OPC_baload: return "Load from null byte/boolean array at bci %d"; 34 | case JVM_OPC_caload: return "Load from null char array at bci %d"; 35 | case JVM_OPC_saload: return "Load from null short array at bci %d"; 36 | 37 | case JVM_OPC_iastore: return "Store into null int array at bci %d"; 38 | case JVM_OPC_lastore: return "Store into null long array at bci %d"; 39 | case JVM_OPC_fastore: return "Store into null float array at bci %d"; 40 | case JVM_OPC_dastore: return "Store into null double array at bci %d"; 41 | case JVM_OPC_aastore: return "Store into null Object array at bci %d"; 42 | case JVM_OPC_bastore: return "Store into null byte/boolean array at bci %d"; 43 | case JVM_OPC_castore: return "Store into null char array at bci %d"; 44 | case JVM_OPC_sastore: return "Store into null short array at bci %d"; 45 | 46 | case JVM_OPC_arraylength: return "Get .length of null array"; 47 | 48 | case JVM_OPC_getfield: return "Get field '%s' of null object at bci %d"; 49 | case JVM_OPC_putfield: return "Put field '%s' of null object at bci %d"; 50 | 51 | case JVM_OPC_invokevirtual: // fall through 52 | case JVM_OPC_invokespecial: // fall through 53 | case JVM_OPC_invokeinterface: return "Called method '%s' on null object at bci %d"; 54 | 55 | case JVM_OPC_monitorenter: // fall through 56 | case JVM_OPC_monitorexit: return "Synchronized on null monitor at bci %d"; 57 | 58 | default: return NULL; 59 | } 60 | } 61 | 62 | static u2 get_u2(const u1* bytes) { 63 | return bytes[0] << 8 | bytes[1]; 64 | } 65 | 66 | static u1* get_cpool_at(u1* cpool, u2 index) { 67 | // Length in bytes of a constant pool item with the given tag 68 | static u1 cp_item_size[] = {0, 3, 0, 5, 5, 9, 9, 3, 3, 5, 5, 5, 5, 4, 3, 5, 5, 3, 3}; 69 | 70 | for (unsigned int i = 1; i < index; i++) { 71 | u1 tag = cpool[0]; 72 | cpool += tag == JVM_CONSTANT_Utf8 ? 3 + get_u2(cpool + 1) : cp_item_size[tag]; 73 | } 74 | 75 | return cpool; 76 | } 77 | 78 | static char* get_name_from_cpool(jvmtiEnv* jvmti, jmethodID method, const u1* bytecodes) { 79 | jclass holder; 80 | jvmti->GetMethodDeclaringClass(method, &holder); 81 | 82 | jint cpool_count; 83 | jint cpool_bytes; 84 | u1* cpool; 85 | if (jvmti->GetConstantPool(holder, &cpool_count, &cpool_bytes, &cpool) != 0) { 86 | return strdup(""); 87 | } 88 | 89 | u1* ref = get_cpool_at(cpool, get_u2(bytecodes + 1)); // CONSTANT_Fieldref / Methodref 90 | u1* name_and_type = get_cpool_at(cpool, get_u2(ref + 3)); // CONSTANT_NameAndType 91 | u1* name = get_cpool_at(cpool, get_u2(name_and_type + 1)); // CONSTANT_Utf8 92 | 93 | size_t name_length = get_u2(name + 1); 94 | char* result = (char*) malloc(name_length + 1); 95 | memcpy(result, name + 3, name_length); 96 | result[name_length] = 0; 97 | 98 | jvmti->Deallocate(cpool); 99 | return result; 100 | } 101 | 102 | 103 | // Cache JNI handles as soon as VM initializes 104 | static jclass NullPointerException = NULL; 105 | static jfieldID detailMessage = NULL; 106 | 107 | void JNICALL VMInit(jvmtiEnv* jvmti, JNIEnv* env, jthread thread) { 108 | jclass localNPE = env->FindClass("java/lang/NullPointerException"); 109 | NullPointerException = (jclass) env->NewGlobalRef(localNPE); 110 | 111 | jclass Throwable = env->FindClass("java/lang/Throwable"); 112 | detailMessage = env->GetFieldID(Throwable, "detailMessage", "Ljava/lang/String;"); 113 | } 114 | 115 | void JNICALL ExceptionCallback(jvmtiEnv* jvmti, JNIEnv* env, jthread thread, 116 | jmethodID method, jlocation location, jobject exception, 117 | jmethodID catch_method, jlocation catch_location) { 118 | 119 | if (NullPointerException == NULL || detailMessage == NULL || 120 | !env->IsInstanceOf(exception, NullPointerException)) { 121 | return; 122 | } 123 | 124 | jint bytecode_count; 125 | u1* bytecodes; 126 | if (jvmti->GetBytecodes(method, &bytecode_count, &bytecodes) != 0) { 127 | return; 128 | } 129 | 130 | if (location >= 0 && location < bytecode_count) { 131 | const char* message = get_exception_message(bytecodes[location]); 132 | if (message != NULL) { 133 | char buf[400]; 134 | if (strstr(message, "%s") != NULL) { 135 | char* name = get_name_from_cpool(jvmti, method, bytecodes + location); 136 | snprintf(buf, sizeof(buf), message, name, (int) location); 137 | free(name); 138 | } else { 139 | sprintf(buf, message, (int) location); 140 | } 141 | env->SetObjectField(exception, detailMessage, env->NewStringUTF(buf)); 142 | } 143 | } 144 | 145 | jvmti->Deallocate(bytecodes); 146 | } 147 | 148 | JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { 149 | jvmtiEnv* jvmti; 150 | vm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_0); 151 | 152 | jvmtiCapabilities capabilities = {0}; 153 | capabilities.can_generate_exception_events = 1; 154 | capabilities.can_get_bytecodes = 1; 155 | capabilities.can_get_constant_pool = 1; 156 | jvmti->AddCapabilities(&capabilities); 157 | 158 | jvmtiEventCallbacks callbacks = {0}; 159 | callbacks.VMInit = VMInit; 160 | callbacks.Exception = ExceptionCallback; 161 | jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 162 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL); 163 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION, NULL); 164 | 165 | return 0; 166 | } 167 | -------------------------------------------------------------------------------- /src/autorun/jvm/jvmti/stackframe/StackFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Odnoklassniki Ltd, Mail.Ru Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | public class StackFrame { 18 | 19 | static { 20 | System.loadLibrary("stackframe"); 21 | } 22 | 23 | public static native String getLocation(int depth); 24 | } 25 | -------------------------------------------------------------------------------- /src/autorun/jvm/jvmti/stackframe/stackframe.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Odnoklassniki Ltd, Mail.Ru Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | class MethodInfo { 22 | private: 23 | char* _file = NULL; 24 | jvmtiLineNumberEntry* _line_number_table = NULL; 25 | jint _table_size = 0; 26 | bool _initialized = false; 27 | 28 | public: 29 | bool initialized() { 30 | return _initialized; 31 | } 32 | 33 | void initialize(jvmtiEnv* jvmti, jmethodID method) { 34 | jclass method_class; 35 | if (jvmti->GetMethodDeclaringClass(method, &method_class) == 0) { 36 | jvmti->GetSourceFileName(method_class, &_file); 37 | } 38 | 39 | jvmti->GetLineNumberTable(method, &_table_size, &_line_number_table); 40 | 41 | _initialized = true; 42 | } 43 | 44 | char* file() { 45 | return _file; 46 | } 47 | 48 | int line(jlocation location) { 49 | int line = 0; 50 | jlocation min = 0xffff; 51 | for (int i = 0; i < _table_size; i++) { 52 | jlocation start = _line_number_table[i].start_location; 53 | if (location >= start && start < min) { 54 | line = _line_number_table[i].line_number; 55 | min = start; 56 | } 57 | } 58 | return line; 59 | } 60 | }; 61 | 62 | static jvmtiEnv* jvmti; 63 | static std::map method_cache; 64 | 65 | extern "C" JNIEXPORT jstring JNICALL 66 | Java_StackFrame_getLocation(JNIEnv* env, jclass unused, jint depth) { 67 | jvmtiFrameInfo frame; 68 | jint count; 69 | if (jvmti->GetStackTrace(NULL, depth, 1, &frame, &count) != 0) { 70 | return NULL; 71 | } 72 | 73 | MethodInfo* info = &method_cache[frame.method]; 74 | if (!info->initialized()) { 75 | info->initialize(jvmti, frame.method); 76 | } 77 | 78 | char buf[1024]; 79 | std::snprintf(buf, sizeof(buf), "%s:%d", info->file(), info->line(frame.location)); 80 | return env->NewStringUTF(buf); 81 | } 82 | 83 | jint JNI_OnLoad(JavaVM* vm, void* reserved) { 84 | vm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_0); 85 | 86 | jvmtiCapabilities capabilities = {0}; 87 | capabilities.can_get_source_file_name = 1; 88 | capabilities.can_get_line_numbers = 1; 89 | jvmti->AddCapabilities(&capabilities); 90 | 91 | return JNI_VERSION_1_6; 92 | } 93 | -------------------------------------------------------------------------------- /src/autorun/jvm/jvmti/vmtrace/vmtrace.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Odnoklassniki Ltd, Mail.Ru Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | static FILE* out; 23 | static jrawMonitorID vmtrace_lock; 24 | static jlong start_time; 25 | 26 | static void trace(jvmtiEnv* jvmti, const char* fmt, ...) { 27 | jlong current_time; 28 | jvmti->GetTime(¤t_time); 29 | 30 | char buf[1024]; 31 | va_list args; 32 | va_start(args, fmt); 33 | vsnprintf(buf, sizeof(buf), fmt, args); 34 | va_end(args); 35 | 36 | jvmti->RawMonitorEnter(vmtrace_lock); 37 | 38 | fprintf(out, "[%.5f] %s\n", (current_time - start_time) / 1000000000.0, buf); 39 | 40 | jvmti->RawMonitorExit(vmtrace_lock); 41 | } 42 | 43 | static char* fix_class_name(char* class_name) { 44 | // Strip 'L' and ';' from class signature 45 | class_name[strlen(class_name) - 1] = 0; 46 | return class_name + 1; 47 | } 48 | 49 | 50 | class ClassName { 51 | private: 52 | jvmtiEnv* _jvmti; 53 | char* _name; 54 | 55 | public: 56 | ClassName(jvmtiEnv* jvmti, jclass klass) : _jvmti(jvmti), _name(NULL) { 57 | _jvmti->GetClassSignature(klass, &_name, NULL); 58 | } 59 | 60 | ~ClassName() { 61 | _jvmti->Deallocate((unsigned char*) _name); 62 | } 63 | 64 | char* name() { 65 | return _name == NULL ? NULL : fix_class_name(_name); 66 | } 67 | }; 68 | 69 | class MethodName { 70 | private: 71 | jvmtiEnv* _jvmti; 72 | char* _holder_name; 73 | char* _method_name; 74 | 75 | public: 76 | MethodName(jvmtiEnv* jvmti, jmethodID method) : _jvmti(jvmti), 77 | _holder_name(NULL), 78 | _method_name(NULL) { 79 | jclass holder; 80 | if (_jvmti->GetMethodDeclaringClass(method, &holder) == 0) { 81 | _jvmti->GetClassSignature(holder, &_holder_name, NULL); 82 | _jvmti->GetMethodName(method, &_method_name, NULL, NULL); 83 | } 84 | } 85 | 86 | ~MethodName() { 87 | _jvmti->Deallocate((unsigned char*) _method_name); 88 | _jvmti->Deallocate((unsigned char*) _holder_name); 89 | } 90 | 91 | char* holder() { 92 | return _holder_name == NULL ? NULL : fix_class_name(_holder_name); 93 | } 94 | 95 | char* name() { 96 | return _method_name; 97 | } 98 | }; 99 | 100 | class ThreadName { 101 | private: 102 | jvmtiEnv* _jvmti; 103 | char* _name; 104 | 105 | public: 106 | ThreadName(jvmtiEnv* jvmti, jthread thread) : _jvmti(jvmti), _name(NULL) { 107 | jvmtiThreadInfo info; 108 | _name = _jvmti->GetThreadInfo(thread, &info) == 0 ? info.name : NULL; 109 | } 110 | 111 | ~ThreadName() { 112 | _jvmti->Deallocate((unsigned char*) _name); 113 | } 114 | 115 | char* name() { 116 | return _name; 117 | } 118 | }; 119 | 120 | 121 | void JNICALL VMStart(jvmtiEnv* jvmti, JNIEnv* env) { 122 | trace(jvmti, "VM started"); 123 | } 124 | 125 | void JNICALL VMInit(jvmtiEnv* jvmti, JNIEnv* env, jthread thread) { 126 | trace(jvmti, "VM initialized"); 127 | } 128 | 129 | void JNICALL VMDeath(jvmtiEnv* jvmti, JNIEnv* env) { 130 | trace(jvmti, "VM destroyed"); 131 | } 132 | 133 | void JNICALL ClassFileLoadHook(jvmtiEnv* jvmti, JNIEnv* env, 134 | jclass class_being_redefined, jobject loader, 135 | const char* name, jobject protection_domain, 136 | jint data_len, const unsigned char* data, 137 | jint* new_data_len, unsigned char** new_data) { 138 | trace(jvmti, "Loading class: %s (%d bytes)", name, data_len); 139 | } 140 | 141 | void JNICALL ClassPrepare(jvmtiEnv* jvmti, JNIEnv* env, 142 | jthread thread, jclass klass) { 143 | ClassName cn(jvmti, klass); 144 | trace(jvmti, "Class prepared: %s", cn.name()); 145 | } 146 | 147 | void JNICALL DynamicCodeGenerated(jvmtiEnv* jvmti, const char* name, 148 | const void* address, jint length) { 149 | trace(jvmti, "Dynamic code generated: %s (%d bytes)", name, length); 150 | } 151 | 152 | void JNICALL CompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, 153 | jint code_size, const void* code_addr, 154 | jint map_length, const jvmtiAddrLocationMap* map, 155 | const void* compile_info) { 156 | MethodName mn(jvmti, method); 157 | trace(jvmti, "Method compiled: %s.%s (%d bytes)", mn.holder(), mn.name(), code_size); 158 | } 159 | 160 | void JNICALL CompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method, 161 | const void* code_addr) { 162 | MethodName mn(jvmti, method); 163 | trace(jvmti, "Method flushed: %s.%s", mn.holder(), mn.name()); 164 | } 165 | 166 | void JNICALL ThreadStart(jvmtiEnv* jvmti, JNIEnv* env, jthread thread) { 167 | ThreadName tn(jvmti, thread); 168 | trace(jvmti, "Thread started: %s", tn.name()); 169 | } 170 | 171 | void JNICALL ThreadEnd(jvmtiEnv* jvmti, JNIEnv* env, jthread thread) { 172 | ThreadName tn(jvmti, thread); 173 | trace(jvmti, "Thread finished: %s", tn.name()); 174 | } 175 | 176 | void JNICALL GarbageCollectionStart(jvmtiEnv* jvmti) { 177 | trace(jvmti, "GC started"); 178 | } 179 | 180 | void JNICALL GarbageCollectionFinish(jvmtiEnv* jvmti) { 181 | trace(jvmti, "GC finished"); 182 | } 183 | 184 | JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { 185 | if (options == NULL || !options[0]) { 186 | out = stderr; 187 | } else if ((out = fopen(options, "w")) == NULL) { 188 | fprintf(stderr, "Cannot open output file: %s\n", options); 189 | return 1; 190 | } 191 | 192 | jvmtiEnv* jvmti; 193 | vm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_0); 194 | 195 | jvmti->CreateRawMonitor("vmtrace_lock", &vmtrace_lock); 196 | jvmti->GetTime(&start_time); 197 | 198 | trace(jvmti, "VMTrace started"); 199 | 200 | jvmtiCapabilities capabilities = {0}; 201 | capabilities.can_generate_all_class_hook_events = 1; 202 | capabilities.can_generate_compiled_method_load_events = 1; 203 | capabilities.can_generate_garbage_collection_events = 1; 204 | jvmti->AddCapabilities(&capabilities); 205 | 206 | jvmtiEventCallbacks callbacks = {0}; 207 | callbacks.VMStart = VMStart; 208 | callbacks.VMInit = VMInit; 209 | callbacks.VMDeath = VMDeath; 210 | callbacks.ClassFileLoadHook = ClassFileLoadHook; 211 | callbacks.ClassPrepare = ClassPrepare; 212 | callbacks.DynamicCodeGenerated = DynamicCodeGenerated; 213 | callbacks.CompiledMethodLoad = CompiledMethodLoad; 214 | callbacks.CompiledMethodUnload = CompiledMethodUnload; 215 | callbacks.ThreadStart = ThreadStart; 216 | callbacks.ThreadEnd = ThreadEnd; 217 | callbacks.GarbageCollectionStart = GarbageCollectionStart; 218 | callbacks.GarbageCollectionFinish = GarbageCollectionFinish; 219 | jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 220 | 221 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL); 222 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL); 223 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL); 224 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); 225 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL); 226 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL); 227 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL); 228 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL); 229 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL); 230 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, NULL); 231 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL); 232 | jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL); 233 | 234 | return 0; 235 | } 236 | 237 | JNIEXPORT void JNICALL Agent_OnUnload(JavaVM* vm) { 238 | if (out != NULL && out != stderr) { 239 | fclose(out); 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/autorun/jvm/mem_pool/MEMORY_POOL_INIT.md: -------------------------------------------------------------------------------- 1 | # 内存池初始化 2 | 3 | ## 1. 内存池初始化步骤 4 | 1. `Threads::create_vm() thread.cpp`
5 | 2. `init_globals() init.cpp`
6 | 3. `universe_init() universe.cpp`
7 | 4. `Universe::initialize_heap() universe.cpp`
8 | 5. `Universe::heap()->initialize() universe.cpp`
9 | 10 | ### 1. `Threads::create_vm()` 11 | 12 | ### 2. `init_globals()` 13 | 14 | ### 3. `universe_init()` 15 | 16 | ### 4. `Universe::initialize_heap()` 17 | 18 | 这里判断使用什么类型的gc,同时初始化gc策略。 19 | 20 | 如果启用了(默认启用) `PerfData` (参考jvm参数 `-XX:+UsePerfData`), 则开启jvm内部数据收集。 21 | 作用是动态的调整gc, 对象和jit相关的指标做垃圾回收 22 | 23 | > jdk8 默认使用 ParallelGC, 所以它会调用 24 | ```c++ 25 | Universe::_collectedHeap = new ParallelScavengeHeap(); 26 | Universe::heap()->initialize(); 27 | ``` 28 | 29 | // check and init gc policy 30 | ```c++ 31 | if (UseParallelGC) { 32 | #if INCLUDE_ALL_GCS 33 | Universe::_collectedHeap = new ParallelScavengeHeap(); 34 | #else // INCLUDE_ALL_GCS 35 | fatal("UseParallelGC not supported in this VM."); 36 | #endif // INCLUDE_ALL_GCS 37 | 38 | } else if (UseG1GC) { 39 | #if INCLUDE_ALL_GCS 40 | G1CollectorPolicy* g1p = new G1CollectorPolicy(); 41 | g1p->initialize_all(); 42 | G1CollectedHeap* g1h = new G1CollectedHeap(g1p); 43 | Universe::_collectedHeap = g1h; 44 | #else // INCLUDE_ALL_GCS 45 | fatal("UseG1GC not supported in java kernel vm."); 46 | #endif // INCLUDE_ALL_GCS 47 | 48 | } else { 49 | GenCollectorPolicy *gc_policy; 50 | 51 | if (UseSerialGC) { 52 | gc_policy = new MarkSweepPolicy(); 53 | } else if (UseConcMarkSweepGC) { 54 | #if INCLUDE_ALL_GCS 55 | if (UseAdaptiveSizePolicy) { 56 | gc_policy = new ASConcurrentMarkSweepPolicy(); 57 | } else { 58 | gc_policy = new ConcurrentMarkSweepPolicy(); 59 | } 60 | #else // INCLUDE_ALL_GCS 61 | fatal("UseConcMarkSweepGC not supported in this VM."); 62 | #endif // INCLUDE_ALL_GCS 63 | } else { // default old generation 64 | gc_policy = new MarkSweepPolicy(); 65 | } 66 | gc_policy->initialize_all(); 67 | 68 | Universe::_collectedHeap = new GenCollectedHeap(gc_policy); 69 | } 70 | 71 | jint status = Universe::heap()->initialize(); 72 | if (status != JNI_OK) { 73 | return status; 74 | } 75 | ``` 76 | 77 | ### 5. `Universe::heap()->initialize()` 78 | -------------------------------------------------------------------------------- /src/autorun/jvm/method/CALL_STUB.md: -------------------------------------------------------------------------------- 1 | # CallStub栈帧的创建 2 | 3 | ## 1. 创建步骤 4 | 5 | 6 | ## 附录 7 | 8 | ![](imgs/java_type_mapping_c_type.png) -------------------------------------------------------------------------------- /src/autorun/jvm/method/JAVA_CALLS.md: -------------------------------------------------------------------------------- 1 | # Java方法调用过程 2 | 3 | ## 简介 4 | 5 | > JavaCalls是本地代码执行Java方法调用的一个工具类,会创建一个新的栈帧,做必要的栈帧切换工作,保证新的栈帧与原有的栈帧被正确的链接起来。 6 | > JavaCalls继承自AllStatic类,其定义位于hotspot/src/share/vm/runtime/javaCalls.hpp中,它的方法都是可以直接调用的静态方法,如下图:
7 | 8 | ![](imgs/java_calls_1.png) 9 | 10 | 众所周知,`jvm` 在调用方法时有如下字节码指令 11 | 12 | | 指令名 | 指令含义 | 对应方法 | 13 | |-----------------|----------------------|----------------| 14 | | invokeinterface | 调用接口方法 | `call_virtual` | 15 | | invokevirtual | 调用多态方法 | `call_virtual` | 16 | | invokestatic | 调用静态方法 | `call_static` | 17 | | invokespecial | 调用私有方法、父类方法以及构造方法 | `call_special` | 18 | | invokedynamic | 动态语言支持调用, `lambda` 表达式 | `call_virtual` | 19 | 20 | 其中, `invokedynamic` 比较特殊,在这里暂不赘述,如果有兴趣可以看看 `jdk` 的源码 21 | `java.lang.invoke.LambdaMetafactory`
22 | `java.lang.invoke.MethodHandle`
23 | `java.lang.invoke.CallSite` 24 | 25 | ## JavaCalls 26 | 27 | 源码位置: `hotspot/src/share/vm/runtime/javaCalls.cpp` 28 | 29 | ### call_special 30 | 31 | ```c++ 32 | void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, 33 | JavaCallArguments* args, TRAPS) { 34 | CallInfo callinfo; 35 | LinkResolver::resolve_special_call(callinfo, klass, name, signature, KlassHandle(), false, CHECK); 36 | methodHandle method = callinfo.selected_method(); 37 | assert(method.not_null(), "should have thrown exception"); 38 | 39 | // Invoke the method 40 | JavaCalls::call(result, method, args, CHECK); 41 | } 42 | ``` 43 | 44 | ### call_static 45 | 46 | ```c++ 47 | void JavaCalls::call_static(JavaValue* result, KlassHandle klass, Symbol* name, 48 | Symbol* signature, JavaCallArguments* args, TRAPS) { 49 | CallInfo callinfo; 50 | LinkResolver::resolve_static_call(callinfo, klass, name, signature, KlassHandle(), false, true, CHECK); 51 | methodHandle method = callinfo.selected_method(); 52 | assert(method.not_null(), "should have thrown exception"); 53 | 54 | // Invoke the method 55 | JavaCalls::call(result, method, args, CHECK); 56 | } 57 | ``` 58 | 59 | ### call_virtual 60 | 61 | ```c++ 62 | void JavaCalls::call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol* name, Symbol* signature, 63 | JavaCallArguments* args, TRAPS) { 64 | CallInfo callinfo; 65 | Handle receiver = args->receiver(); 66 | KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass()); 67 | LinkResolver::resolve_virtual_call( 68 | callinfo, receiver, recvrKlass, spec_klass, name, signature, 69 | KlassHandle(), false, true, CHECK); 70 | methodHandle method = callinfo.selected_method(); 71 | assert(method.not_null(), "should have thrown exception"); 72 | 73 | // Invoke the method 74 | JavaCalls::call(result, method, args, CHECK); 75 | } 76 | ``` 77 | 78 | ### call 79 | 80 | ```c++ 81 | void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArguments* args, TRAPS) { 82 | methodHandle method = *m; 83 | JavaThread* thread = (JavaThread*)THREAD; 84 | // 判断是否是java线程 85 | assert(thread->is_Java_thread(), "must be called by a java thread"); 86 | assert(method.not_null(), "must have a method to call"); 87 | // 是否进入safepoint 88 | assert(!SafepointSynchronize::is_at_safepoint(), "call to Java code during VM operation"); 89 | assert(!thread->handle_area()->no_handle_mark_active(), "cannot call out to Java here"); 90 | 91 | 92 | CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();) 93 | 94 | // Verify the arguments 95 | // 是否检查jni参数 96 | if (CheckJNICalls) { 97 | args->verify(method, result->get_type(), thread); 98 | } 99 | else debug_only(args->verify(method, result->get_type(), thread)); 100 | 101 | // Ignore call if method is empty 102 | if (method->is_empty_method()) { 103 | assert(result->get_type() == T_VOID, "an empty method must return a void value"); 104 | return; 105 | } 106 | 107 | 108 | #ifdef ASSERT 109 | { InstanceKlass* holder = method->method_holder(); 110 | // A klass might not be initialized since JavaCall's might be used during the executing of 111 | // the . For example, a Thread.start might start executing on an object that is 112 | // not fully initialized! (bad Java programming style) 113 | assert(holder->is_linked(), "rewritting must have taken place"); 114 | } 115 | #endif 116 | // 检查是否是编译线程 117 | assert(!thread->is_Compiler_thread(), "cannot compile from the compiler"); 118 | // 是否需要jit编译此方法 119 | if (CompilationPolicy::must_be_compiled(method)) { 120 | // jit编译方法 121 | CompileBroker::compile_method(method, InvocationEntryBci, 122 | CompilationPolicy::policy()->initial_compile_level(), 123 | methodHandle(), 0, "must_be_compiled", CHECK); 124 | } 125 | 126 | // Since the call stub sets up like the interpreter we call the from_interpreted_entry 127 | // so we can go compiled via a i2c. Otherwise initial entry method will always 128 | // run interpreted. 129 | address entry_point = method->from_interpreted_entry(); 130 | if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) { 131 | entry_point = method->interpreter_entry(); 132 | } 133 | 134 | // Figure out if the result value is an oop or not (Note: This is a different value 135 | // than result_type. result_type will be T_INT of oops. (it is about size) 136 | // 获取方法返回值 137 | BasicType result_type = runtime_type_from(result); 138 | // 判断返回值是否是对象数组或者oop对象 139 | bool oop_result_flag = (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY); 140 | 141 | // NOTE: if we move the computation of the result_val_address inside 142 | // the call to call_stub, the optimizer produces wrong code. 143 | // 获取到保存方法所调用的结果指针 144 | intptr_t* result_val_address = (intptr_t*)(result->get_value_addr()); 145 | 146 | // Find receiver 147 | // 获取调用端,如果是静态则从args里取,否则使用handle代替 148 | Handle receiver = (!method->is_static()) ? args->receiver() : Handle(); 149 | 150 | // When we reenter Java, we need to reenable the yellow zone which 151 | // might already be disabled when we are in VM. 152 | // 获取当前调用栈是否处于overflow, 如果是则抛出异常 153 | if (thread->stack_yellow_zone_disabled()) { 154 | thread->reguard_stack(); 155 | } 156 | 157 | // Check that there are shadow pages available before changing thread state 158 | // to Java 159 | // 判断当前调用栈是否有足够的内存,如果不够则抛出异常 160 | if (!os::stack_shadow_pages_available(THREAD, method)) { 161 | // Throw stack overflow exception with preinitialized exception. 162 | Exceptions::throw_stack_overflow_exception(THREAD, __FILE__, __LINE__, method); 163 | return; 164 | } else { 165 | // Touch pages checked if the OS needs them to be touched to be mapped. 166 | // 申请内存 167 | os::bang_stack_shadow_pages(); 168 | } 169 | 170 | // do call 171 | // 执行方法调用。 172 | { JavaCallWrapper link(method, receiver, result, CHECK); 173 | { HandleMark hm(thread); // HandleMark used by HandleMarkCleaner 174 | 175 | StubRoutines::call_stub()( 176 | (address)&link, 177 | // (intptr_t*)&(result->_value), // see NOTE above (compiler problem) 178 | result_val_address, // see NOTE above (compiler problem) 179 | result_type, 180 | method(), 181 | entry_point, 182 | args->parameters(), 183 | args->size_of_parameters(), 184 | CHECK 185 | ); 186 | 187 | // 处理调用结果 188 | result = link.result(); // circumvent MS C++ 5.0 compiler bug (result is clobbered across call) 189 | // Preserve oop return value across possible gc points 190 | // 将结果设置到当前线程的vm_result中, 191 | if (oop_result_flag) { 192 | thread->set_vm_result((oop) result->get_jobject()); 193 | } 194 | } 195 | } // Exit JavaCallWrapper (can block - potential return oop must be preserved) 196 | 197 | // Check if a thread stop or suspend should be executed 198 | // The following assert was not realistic. Thread.stop can set that bit at any moment. 199 | //assert(!thread->has_special_runtime_exit_condition(), "no async. exceptions should be installed"); 200 | 201 | // Restore possible oop return 202 | // 设置返回结果,将vm_result清空 203 | if (oop_result_flag) { 204 | result->set_jobject((jobject)thread->vm_result()); 205 | thread->set_vm_result(NULL); 206 | } 207 | } 208 | 209 | void JavaCalls::call(JavaValue* result, methodHandle method, JavaCallArguments* args, TRAPS) { 210 | // Check if we need to wrap a potential OS exception handler around thread 211 | // This is used for e.g. Win32 structured exception handlers 212 | assert(THREAD->is_Java_thread(), "only JavaThreads can make JavaCalls"); 213 | // Need to wrap each and everytime, since there might be native code down the 214 | // stack that has installed its own exception handlers 215 | os::os_exception_wrapper(call_helper, result, &method, args, THREAD); 216 | } 217 | 218 | // os_linux.cpp 219 | void 220 | os::os_exception_wrapper(java_call_t f, JavaValue* value, const methodHandle& method, 221 | JavaCallArguments* args, JavaThread* thread) { 222 | f(value, method, args, thread); 223 | } 224 | ``` 225 | 可以看出来,归根结底都调用了 `call()` 方法,然后其中又调用了 `JavaCalls::call_helper()` 226 | 227 | 接 `call_helper` 228 | 229 | ```c++ 230 | { JavaCallWrapper link(method, receiver, result, CHECK); 231 | { HandleMark hm(thread); // HandleMark used by HandleMarkCleaner 232 | 233 | StubRoutines::call_stub()( 234 | (address)&link, 235 | // (intptr_t*)&(result->_value), // see NOTE above (compiler problem) 236 | result_val_address, // see NOTE above (compiler problem) 237 | result_type, 238 | method(), 239 | entry_point, 240 | args->parameters(), 241 | args->size_of_parameters(), 242 | CHECK 243 | ); 244 | 245 | // 处理调用结果 246 | result = link.result(); // circumvent MS C++ 5.0 compiler bug (result is clobbered across call) 247 | // Preserve oop return value across possible gc points 248 | // 将结果设置到当前线程的vm_result中, 249 | if (oop_result_flag) { 250 | thread->set_vm_result((oop) result->get_jobject()); 251 | } 252 | } 253 | } 254 | 255 | ``` 256 | 257 | ### call_stub 258 | ```c 259 | #define TRAPS JavaThread* THREAD 260 | typedef void (*CallStub)( 261 | address link, 262 | intptr_t* result, 263 | BasicType result_type, 264 | Method* method, 265 | address entry_point, 266 | intptr_t* parameters, 267 | int size_of_parameters, 268 | TRAPS 269 | ); 270 | 271 | JavaCallWrapper link(method, receiver, result, CHECK); // 通过该对象已经搭建起Java函数的调用者与被调用者的桥梁,通过这个对象可以实现堆栈追踪,可以得到整个方法的调用链路 272 | 273 | // JavaCallWrapper 在每个 JavaCall 之前构造,在调用之后销毁。它的目的是分配/释放一个新的句柄块, 274 | // 并保存/恢复最后一个 Java fp/sp。 指向 JavaCallWrapper 的指针存储在堆栈中。 275 | class JavaCallWrapper: StackObj { 276 | friend class VMStructs; 277 | private: 278 | JavaThread* _thread; // the thread to which this call belongs 当前Java函数所在的线程 279 | JNIHandleBlock* _handles; // the saved handle block 本地调用句柄 280 | Method* _callee_method; // to be able to collect arguments if entry frame is top frame 调用者方法对象 281 | oop _receiver; // the receiver of the call (if a non-static call) 被调用者(非静态Java方法) 282 | 283 | JavaFrameAnchor _anchor; // last thread anchor state that we must restore Java线程堆栈对象 284 | 285 | JavaValue* _result; // result value Java方法所返回的值 286 | } 287 | ``` 288 | 289 | 参考文献: https://blog.csdn.net/qq_31865983/article/details/102877069 290 | -------------------------------------------------------------------------------- /src/autorun/jvm/method/imgs/java_calls_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/method/imgs/java_calls_1.png -------------------------------------------------------------------------------- /src/autorun/jvm/method/imgs/java_type_mapping_c_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/method/imgs/java_type_mapping_c_type.png -------------------------------------------------------------------------------- /src/autorun/jvm/oop/Compressed_Oops.md: -------------------------------------------------------------------------------- 1 | # CompressedOops 指针压缩技术(X64系统) 2 | 3 | > 指针压缩技术是针对64位系统的。在 `oop` 模型下,定义的 `java` 对象(`oop`对象) 和 class对象 (`instanceMinorKlass` 对象) 的关系是 4 | > 5 | > `oop` 对象中 除去对象头、填充值和字段数据(成员变量)之外还要存储 `klass` 对象对应的指向。方便获取对应类型。同时,`klass` 对象中还存放着与 `oop` 对象关联度很高的很多属性和操作方法(多态表,`vtable`、`itable`)。 6 | ## JAVA对象布局 7 | ![](img/compressed_oops_1.png) 8 | 9 | ## JVM是怎么实现指针压缩的 10 | 参考此篇: [OOP-KLASS 二分模型](OOP.md) 11 | 12 | ![](img/object_header.png) 13 | 14 | > 指针压缩会在JVM `32G` 内存以上失效,原因如下: 15 | 16 | 32位操作系统 花费的内存空间为: 17 | > 对象头-8字节 + 实例数据 int类型-4字节 + 引用类型-4字节+补充0字节(16是8的倍数) 16个字节 18 | 19 | 64位操作系统 20 | > 对象头-16字节 + 实例数据 int类型-4字节 + 引用类型-8字节+补充4字节(28不是8的倍数补充4字节到达32字节) 32个字节 21 | 22 | 同样的对象需要将近两倍的容量,(实际平均1.5倍),所以需要开启压缩指针: 23 | 24 | 64位开启压缩指针 25 | > 对象头-12字节 + 实例数据 int类型-4字节 + 引用类型-4字节+补充0字节=24个字节 26 | 27 | ## 压缩指针是怎么实现的 28 | 29 | JVM的实现方式是: 30 | > 不再保存所有引用,而是每隔8个字节保存一个引用。例如,原来保存每个引用0、1、2…,现在只保存0、8、16…。因此,指针压缩后,并不是所有引用都保存在堆中,而是以8个字节为间隔保存引用。 31 | 32 | >在实现上,堆中的引用其实还是按照0x0、0x1、0x2…进行存储。只不过当引用被存入64位的寄存器时,JVM将其左移3位(相当于末尾添加3个0),例如0x0、0x1、0x2…分别被转换为0x0、0x8、0x10。而当从寄存器读出时,JVM又可以右移3位,丢弃末尾的0。(oop在堆中是32位,在寄存器中是35位,2的35次方=32G。也就是说,使用32位,来达到35位oop所能引用的堆内存空间) 33 | 34 | 如上也可以解释为什么堆内存大于32G时指针压缩会失效 35 | 36 | ![](img/compressed_oops_2.png) 37 | 38 | ## 哪些信息会被压缩 39 | 40 | 1. 对象的全局静态变量(即类属性) 41 | 2. 对象头信息:64位平台下,原生对象头大小为16字节,压缩后为12字节 42 | 3. 对象的引用类型:64位平台下,引用类型本身大小为8字节,压缩后为4字节 43 | 4. 对象数组类型:64位平台下,数组类型本身大小为24字节,压缩后16字节 44 | 45 | ## JVM 指针压缩参数 46 | -------------------------------------------------------------------------------- /src/autorun/jvm/oop/Klass.md: -------------------------------------------------------------------------------- 1 | # Klass-Java类的描述信息 2 | 3 | 源码位置: `src/hotspot/share/oops/instanceKlass.hpp` 4 | > openjdk8 instanceKlass 5 | ```c++ 6 | // An InstanceKlass is the VM level representation of a Java class. 7 | // It contains all information needed for at class at execution runtime. 8 | 9 | // InstanceKlass layout: 10 | // [C++ vtbl pointer ] Klass 11 | // [subtype cache ] Klass 12 | // [instance size ] Klass 13 | // [java mirror ] Klass 14 | // [super ] Klass 15 | // [access_flags ] Klass 16 | // [name ] Klass 17 | // [first subklass ] Klass 18 | // [next sibling ] Klass 19 | // [array klasses ] 20 | // [methods ] 21 | // [local interfaces ] 22 | // [transitive interfaces ] 23 | // [fields ] 24 | // [constants ] 25 | // [class loader ] 26 | // [source file name ] 27 | // [inner classes ] 28 | // [static field size ] 29 | // [nonstatic field size ] 30 | // [static oop fields size ] 31 | // [nonstatic oop maps size ] 32 | // [has finalize method ] 33 | // [deoptimization mark bit ] 34 | // [initialization state ] 35 | // [initializing thread ] 36 | // [Java vtable length ] 37 | // [oop map cache (stack maps) ] 38 | // [EMBEDDED Java vtable ] size in words = vtable_len 39 | // [EMBEDDED nonstatic oop-map blocks] size in words = nonstatic_oop_map_size 40 | // The embedded nonstatic oop-map blocks are short pairs (offset, length) 41 | // indicating where oops are located in instances of this klass. 42 | // [EMBEDDED implementor of the interface] only exist for interface 43 | // [EMBEDDED host klass ] only exist for an anonymous class (JSR 292 enabled) 44 | ``` 45 | 46 | 主要标注 `klass` 的几种状态。 47 | ```c++ 48 | // See "The Java Virtual Machine Specification" section 2.16.2-5 for a detailed description 49 | // of the class loading & initialization procedure, and the use of the states. 50 | enum ClassState { 51 | allocated, // allocated (but not yet linked) 52 | loaded, // loaded and inserted in class hierarchy (but not linked yet) 53 | linked, // successfully linked/verified (but not initialized yet) 54 | being_initialized, // currently running class initializer 55 | fully_initialized, // initialized (successfull final state) 56 | initialization_error // error happened during initialization 57 | }; 58 | ``` 59 | 60 | 61 | `InstanceKlass::initialize -> InstanceKlass::initialize_impl` 62 | -------------------------------------------------------------------------------- /src/autorun/jvm/oop/Memory_Weave.md: -------------------------------------------------------------------------------- 1 | # 内存编织技术 2 | 3 | -------------------------------------------------------------------------------- /src/autorun/jvm/oop/OOP.md: -------------------------------------------------------------------------------- 1 | # OOP-KLASS 二分模型 2 | 3 | ## 1. OOP概念 4 | > 摘自`《Hotspot实战》` 5 | > 6 | > 设计一个面向对象系统,应当支特面向对象的几个主要特征:封装、继承和至态。在JVM 7 | 中必须能够支特这些特征。我们不禁会问:HotSpot 基于 C++实现,而 C++就是一门面向对象 8 | 话吉,它本身就具有上述面向对象基本特征,那么只需要在HotSpot 内部为每个 Java 类生成 9 | 个C++类,不就行了吗?换句话说,虚拟机行加载一个 Java 类,就在内部创建一个域和方法与 10 | 之相同的C++类对等体。当Java 程序需要创建文例对象时,反映到虚拟机中,就在内部创建相 11 | 应的 C++对象。 12 | > 13 | > 14 | > 事实上,Hotspot 的设计者并没有按照上述思路设计对象表示系统,而是专门设计了OOP-Klass 15 | 分模型: 16 | 17 | * OOP: ordinary object pointer, 或 OOPS. 即普通对象指针,用来描述对象实例信息 18 | * Klass: Java 类的 C++对等体,用来描达 Java 类 19 | 20 | ### 1. OOP 模型 21 | 1. 类结构图
22 | jdk 1.7及以下版本结构图(摘自 `Hotspot` 实战) 23 | ![](img/lt1.7.png) 24 | 25 | jdk1.8及以上版本结构图 26 | ![](img/gt1.8.jpg) 27 | 28 | 2. OOP模型对应代码 29 | 30 | 源码位置: `hotspot/src/share/vm/oops/oop.hpp` 31 | ```c++ 32 | class oopDesc { 33 | private: 34 | volatile markOop _mark; // markOopDesc* markOop 35 | 36 | union _metadata { 37 | Klass* _klass; 38 | narrowKlass _compressed_klass; // juint narrowKlass 39 | } _metadata; 40 | }; 41 | ``` 42 | 3. 代码详解 43 | 44 | `union` 关键字含义: 45 | * `union` 即为联合,它是一种特殊的类。通过关键字`union` 进行定义,一个`union` 可以有多个数据成员。 46 | * 联合体是一种互斥的结构体,也就是说在任意时刻,联合中只能有一个数据成员可以有值。当给联合中某个成员赋值之后,该联合中的其它成员就变成未定义状态了。 47 | 48 | 简单解释一下 49 | * `markOop` 实际上是markOopDesc指针类型,言外之意就是会随着操作系统的位数决定它的大小。 50 | 如x86架构下,指针大小是4字节(Byte), 而64位系统则是8字节。 所以这也就是为什么对象头无法压缩的原因 51 | * 联合体 `_metadata`: 上面也说过联合体是排他的,也就是说同一时刻,只要联合体中的其中一个字段有值,则其它字段都是未定义的状态 52 | * 关于对象指针压缩, 使用 `-XX:(+/-)UseCompressedOops` 来控制是否开启指针压缩。 控制指针压缩的参数如下表格: 53 | 54 | |数据类型|参数名称|默认值|参数类型和支持环境| 55 | | ---| ---| ---| ---| 56 | |bool|UseCompressedOops|true|{lp64_product}| 57 | 58 | 通过上面的表格可以看出来,这个参数是64位jdk,并且是`product`版本的Hotspot级别的参数(当然,自己编译的debug级别的jdk也是可以的。这里使用级别这个词不太准确,请自行脑补) 59 | 60 | 指针压缩完后的效果其实是把8字节大小的指针使用int类型(4字节)的结构体来存储。这样的话其实存储的是内存地址,而且是需要往右偏移3位的一段空间地址。 61 | 所以取地址时,需要左移3位就可以拿到真正的偏移地址了。这里不再赘述。详情移步到 [4.2 指针压缩](Compressed_Oops.md) 章节 62 | 63 | 4. 总结 64 | 65 | `JVM` 在描述 `JAVA` 类型和类型指针 `JAVA` 方法类型和方法指针,常量池缓存类型指针,基本数据类型和数组类型指针。 `HotSpot` 认为以上这几种模型已经足够描述 `JAVA` 程序的全部: 数据、方法、类型、数组和实例。 66 | 67 | 前面我们说过,`OOP` 是描述对象类型的承载主体, Klass是描述类类型的承载主体。 68 | 69 | 70 | `JAVA` 代码中出现 `Entity entity = new Entity(); ` 71 | 这段代码时,`Hotspot` 会先将 `Entity` 这个类类型加载到方法区[^Method_Area](永久代/元空间。不同的 `JVM` 有不同的实现), 然后再 `Hotspot` 堆中为其实例对象 `entity` 对象开辟一块内存空间,存放对象实例数据。 72 | 在 `JVM` 加载 `Entity` 到方法区时,`JVM` 会创建一个 `instanceKlass`,其中保存了 `Entity` 这个类中定义的所有信息,包括变量、方法、父类、接口、构造、属性等, 所以 `instanceKlass` 就是 `Entity` 这个 `JAVA` 类类型结构的对等体。 73 | 而 `instanceOop` 这个普通对象指针 对象中包含了一个指针,这个指针就指向这个 `instanceKlass` 实例。而 `JVM` 在实例化 `Entity` 时会会创建一个 `instanceOop` 实例,该实例便是 `Entity` 对象实例 `entity` 在内存中的对等体。主要存储 `Entity` 实例对象的成员变量。 74 | 其中, instanceOop中有一个指针指向 `instanceKlass`, 通过这个指针, `JVM` 便可以在运行时获取这个类的元信息(反射特性)。 75 | 76 | 77 | ## 附录 78 | [^Method_Area]: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.4 -------------------------------------------------------------------------------- /src/autorun/jvm/oop/img/compressed_oops_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/oop/img/compressed_oops_1.png -------------------------------------------------------------------------------- /src/autorun/jvm/oop/img/compressed_oops_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/oop/img/compressed_oops_2.png -------------------------------------------------------------------------------- /src/autorun/jvm/oop/img/gt1.8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/oop/img/gt1.8.jpg -------------------------------------------------------------------------------- /src/autorun/jvm/oop/img/lt1.7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/oop/img/lt1.7.png -------------------------------------------------------------------------------- /src/autorun/jvm/oop/img/object_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/oop/img/object_header.png -------------------------------------------------------------------------------- /src/autorun/jvm/oop/img/object_store.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/oop/img/object_store.png -------------------------------------------------------------------------------- /src/autorun/jvm/start/README.md: -------------------------------------------------------------------------------- 1 | #jvm start 2 | 3 | ## jvm 启动流程 (linux_x86_64) 4 | 5 | 6 | ### 1. 启动流程 7 | #### 1.1 init SubThread call JavaMain 8 | 1. `main(int argc, char **argv) main.c` 9 | 2. -> `JLI_Launch() java.c` 10 | 3. -> `JVMInit() java_md_solinux.c` 11 | 4. -> `CreateExecutionEnvironment() java_md_solinux.c` 12 | 5. -> `GetJREPath() java_md_solinux.c` 13 | 6. -> `GetJVMPath() java_md_solinux.c` 14 | 7. -> `ContinueInNewThread() java.c` 15 | 8. -> `ContinueInNewThread0() java_md_solinux.c` 16 | 9. -> `if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0)` 17 | 10. -> `pthread_join() pthread_join.c` 18 | 11. -> `JavaMain() java.c` 19 | ##### 1.1 call `JLI_Launch` 20 | > 主要作用: 21 | ##### 1. 进行 `libjvm.so` 加载。
22 | ##### 2. 编译的 `jvm.cpp` 文件 命令类似于 23 | > `g++ --dynamiclib src -o target`. 24 | 参考 [jni 编译环节](../jni/README.md "#编译环节") 25 | ##### 3. `JLI_Launch` 会调用 `LoadJavaVM(jvmpath, &ifn)` 来实现`libjvm.so`的加载、 26 | 参数解析、ClassPath的获取和设置、系统属性设置以及jvm的初始化 27 | ##### 4. *ifn是一个很关键的结构体。位于 `jdk/src/share/bin/java.h` 中 28 | #### 1.2 解析启动参数 29 | [CreateExecutionEnvironment](https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/share/bin/java.c#L236) 30 | ```C++ 31 | // 创建运行时环境 根据启动参数创建32或64位虚拟机, 获取JRE路径, 获取JVM路径 32 | CreateExecutionEnvironment(&argc, &argv, 33 | jrepath, sizeof(jrepath), 34 | jvmpath, sizeof(jvmpath), 35 | jvmcfg, sizeof(jvmcfg)); 36 | ``` 37 | > 检查JRE环境和 `libjvm.so` (linux) 或者 `libjvm.dll` (windows) 或者 libjvm.dylib (macos) 文件是否存在。如果不存在则结束。抛出异常 38 | > 39 | > JRE环境未找到错误信息模板: "Error: Could not find Java SE Runtime Environment." 40 | > 41 | > libjvm动态链接库未找到错误信息模板: "Error: missing `%s' JVM at `%s'.\nPlease install or use the JRE or JDK that contains these missing components." 42 | ```c++ 43 | /* Compute/set the name of the executable */ 44 | -> SetExecname(char **argv) 45 | /* Find out where the JRE is that we will be using. */ 46 | if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) 47 | -> GetApplicationHome(char *buf, jint bufsize) 48 | const char *execname = GetExecName(); $JAVA_HOME/bin/java 49 | -> java.c 50 | char* CheckJvmType // client server 51 | if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, 0 )) // 通过java命令的路径拼接libjvm.so路径 52 | // Does `/home/autorun/openjdk8/jdk8u/build/linux-x86_64-normal-server-slowdebug/jdk/lib/amd64/server/libjvm.so' exist ... yes. 53 | -> if (stat(jvmpath, &s) == 0) 54 | -> stat 55 | /* Get file attributes for FILE and put them in BUF. */ 56 | extern int stat (const char *__restrict __file, 57 | struct stat *__restrict __buf) __THROW __nonnull ((1, 2)); 58 | /* 59 | * we seem to have everything we need, so without further ado 60 | * we return back, otherwise proceed to set the environment. 61 | */ 62 | mustsetenv = RequiresSetenv(wanted, jvmpath); 63 | -> llp = getenv("LD_LIBRARY_PATH"); 64 | /* Return the value of envariable NAME, or NULL if it doesn't exist. */ 65 | extern char *getenv (const char *__name) __THROW __nonnull ((1)) __wur; 66 | 67 | ifn.CreateJavaVM = 0; 68 | ifn.GetDefaultJavaVMInitArgs = 0; 69 | ``` 70 | 71 | ```c++ 72 | typedef struct { 73 | CreateJavaVM_t CreateJavaVM; 74 | GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs; 75 | GetCreatedJavaVMs_t GetCreatedJavaVMs; 76 | } InvocationFunctions; 77 | ``` 78 | 可以看到,里面定义了3个函数指针,具体实现在 `jvm.cpp` 中。在加载完毕后jvm通过 79 | 80 | `libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);` 加载 `libjvm.so` 动态链接库(linux). windows 则是dll文件 81 | > 参考 [dlopen 函数定义](https://baike.baidu.com/item/dlopen/1967576?fr=aladdin) 82 | ##### 5. 当 `libjvm.so` 动态链接库加载完成后接下来会调用 83 | `dlsym(libjvm, "JNI_CreateJavaVM");`
84 | `dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");`
85 | `dlsym(libjvm, "JNI_GetCreatedJavaVMs");`
86 | 给上面提到的`InvocationFunctions` 的`CreateJavaVM`、`GetDefaultJavaVMInitArgs` 和 `GetCreatedJavaVMs` 赋值首地址。以实现方法调用 87 | 88 | > 摘自 `java_md_solinux.c` 89 | ```c++ 90 | ifn->CreateJavaVM = (CreateJavaVM_t) 91 | dlsym(libjvm, "JNI_CreateJavaVM"); 92 | if (ifn->CreateJavaVM == NULL) { 93 | JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); 94 | return JNI_FALSE; 95 | } 96 | 97 | ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) 98 | dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs"); 99 | if (ifn->GetDefaultJavaVMInitArgs == NULL) { 100 | JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); 101 | return JNI_FALSE; 102 | } 103 | 104 | ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t) 105 | dlsym(libjvm, "JNI_GetCreatedJavaVMs"); 106 | if (ifn->GetCreatedJavaVMs == NULL) { 107 | JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); 108 | return JNI_FALSE; 109 | } 110 | ``` 111 | ##### 6. JVMInit() 函数 112 | > 源码位置: jdk/src/solaris/bin/java_md_solinux.c 113 | ```c++ 114 | int 115 | JVMInit(InvocationFunctions* ifn, jlong threadStackSize, 116 | int argc, char **argv, 117 | int mode, char *what, int ret) 118 | { 119 | ShowSplashScreen(); 120 | return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret); 121 | } 122 | ``` 123 | ##### 7. ContinueInNewThread() 函数 124 | > 源码位置: jdk/src/share/bin/java.c 125 | ```c++ 126 | int 127 | ContinueInNewThread(InvocationFunctions* ifn, jlong threadStackSize, 128 | int argc, char **argv, 129 | int mode, char *what, int ret) 130 | { 131 | 132 | /* 133 | * If user doesn't specify stack size, check if VM has a preference. 134 | * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will 135 | * return its default stack size through the init args structure. 136 | */ 137 | if (threadStackSize == 0) { 138 | struct JDK1_1InitArgs args1_1; 139 | memset((void*)&args1_1, 0, sizeof(args1_1)); 140 | args1_1.version = JNI_VERSION_1_1; 141 | ifn->GetDefaultJavaVMInitArgs(&args1_1); /* ignore return value */ 142 | if (args1_1.javaStackSize > 0) { 143 | threadStackSize = args1_1.javaStackSize; 144 | } 145 | } 146 | 147 | { /* Create a new thread to create JVM and invoke main method */ 148 | JavaMainArgs args; 149 | int rslt; 150 | 151 | args.argc = argc; 152 | args.argv = argv; 153 | args.mode = mode; 154 | args.what = what; 155 | args.ifn = *ifn; 156 | 157 | // 创建子线程调用Java主类的mian() 方法 158 | rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args); 159 | /* If the caller has deemed there is an error we 160 | * simply return that, otherwise we return the value of 161 | * the callee 162 | */ 163 | return (ret != 0) ? ret : rslt; 164 | } 165 | } 166 | ``` 167 | ##### 8. ContinueInNewThread0() 函数 168 | > 源码位置: jdk/src/solaris/bin/java_md_solinux.c 169 | ```c++ 170 | pthread_t tid; 171 | pthread_attr_t attr; 172 | pthread_attr_init(&attr); 173 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 174 | 175 | if (stack_size > 0) { 176 | pthread_attr_setstacksize(&attr, stack_size); 177 | } 178 | 179 | // 使用pthread_create系统函数创建新线程去执行JavaMain方法 如果线程创建成功 则返回值为0 180 | if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) { 181 | void * tmp; 182 | // 让出当前线程执行权, 参考`java.lang.Thread.join()` 方法 183 | pthread_join(tid, &tmp); 184 | rslt = (int)tmp; 185 | } else { 186 | /* 187 | * Continue execution in current thread if for some reason (e.g. out of 188 | * memory/LWP) a new thread can't be created. This will likely fail 189 | * later in continuation as JNI_CreateJavaVM needs to create quite a 190 | * few new threads, anyway, just give it a try.. 191 | */ 192 | rslt = continuation(args); 193 | } 194 | 195 | pthread_attr_destroy(&attr); 196 | ``` 197 | 1. 使用pThread库创建线程。并将当前线程执行权让出。 198 | 2. 使用创建的线程去回调 `continuation`, `continuation` 为 `JavaMain` 199 | > rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args); 200 | 201 | ### 启动流程图 202 | ![流程图](img/jvm启动流程图1.png) 203 | 204 | ### 3. 附录 205 | 1. jvm `main.c` 代码(摘自 `openjdk 1.8_b120`) 206 | ```c++ 207 | 208 | #ifdef _MSC_VER 209 | #if _MSC_VER > 1400 && _MSC_VER < 1600 210 | 211 | /* 212 | * When building for Microsoft Windows, main has a dependency on msvcr??.dll. 213 | * 214 | * When using Visual Studio 2005 or 2008, that must be recorded in 215 | * the [java,javaw].exe.manifest file. 216 | * 217 | * As of VS2010 (ver=1600), the runtimes again no longer need manifests. 218 | * 219 | * Reference: 220 | * C:/Program Files/Microsoft SDKs/Windows/v6.1/include/crtdefs.h 221 | */ 222 | #include 223 | #ifdef _M_IX86 224 | 225 | #pragma comment(linker,"/manifestdependency:\"type='win32' " \ 226 | "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT' " \ 227 | "version='" _CRT_ASSEMBLY_VERSION "' " \ 228 | "processorArchitecture='x86' " \ 229 | "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") 230 | 231 | #endif /* _M_IX86 */ 232 | 233 | //This may not be necessary yet for the Windows 64-bit build, but it 234 | //will be when that build environment is updated. Need to test to see 235 | //if it is harmless: 236 | #ifdef _M_AMD64 237 | 238 | #pragma comment(linker,"/manifestdependency:\"type='win32' " \ 239 | "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT' " \ 240 | "version='" _CRT_ASSEMBLY_VERSION "' " \ 241 | "processorArchitecture='amd64' " \ 242 | "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") 243 | 244 | #endif /* _M_AMD64 */ 245 | #endif /* _MSC_VER > 1400 && _MSC_VER < 1600 */ 246 | #endif /* _MSC_VER */ 247 | 248 | /* 249 | * Entry point. 250 | */ 251 | #ifdef JAVAW 252 | 253 | char **__initenv; 254 | 255 | int WINAPI 256 | WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow) 257 | { 258 | int margc; 259 | char** margv; 260 | const jboolean const_javaw = JNI_TRUE; 261 | 262 | __initenv = _environ; 263 | 264 | #else /* JAVAW */ 265 | int 266 | main(int argc, char **argv) 267 | { 268 | int margc; 269 | char** margv; 270 | const jboolean const_javaw = JNI_FALSE; 271 | #endif /* JAVAW */ 272 | #ifdef _WIN32 273 | { 274 | int i = 0; 275 | if (getenv(JLDEBUG_ENV_ENTRY) != NULL) { 276 | printf("Windows original main args:\n"); 277 | for (i = 0 ; i < __argc ; i++) { 278 | printf("wwwd_args[%d] = %s\n", i, __argv[i]); 279 | } 280 | } 281 | } 282 | JLI_CmdToArgs(GetCommandLine()); 283 | margc = JLI_GetStdArgc(); 284 | // add one more to mark the end 285 | margv = (char **)JLI_MemAlloc((margc + 1) * (sizeof(char *))); 286 | { 287 | int i = 0; 288 | StdArg *stdargs = JLI_GetStdArgs(); 289 | for (i = 0 ; i < margc ; i++) { 290 | margv[i] = stdargs[i].arg; 291 | } 292 | margv[i] = NULL; 293 | } 294 | #else /* *NIXES */ 295 | margc = argc; 296 | margv = argv; 297 | #endif /* WIN32 */ 298 | return JLI_Launch(margc, margv, 299 | sizeof(const_jargs) / sizeof(char *), const_jargs, 300 | sizeof(const_appclasspath) / sizeof(char *), const_appclasspath, 301 | FULL_VERSION, 302 | DOT_VERSION, 303 | (const_progname != NULL) ? const_progname : *margv, 304 | (const_launcher != NULL) ? const_launcher : *margv, 305 | (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE, 306 | const_cpwildcard, const_javaw, const_ergo_class); 307 | } 308 | ``` 309 | 310 | > 通过ifdef 编译条件编译。基于Linux内核的Ubuntu系统来讲。最终编译完的代码如下 311 | ```c++ 312 | int 313 | main(int argc, char **argv) 314 | { 315 | int margc; 316 | char** margv; 317 | const jboolean const_javaw = JNI_FALSE; 318 | return JLI_Launch(margc, margv, 319 | sizeof(const_jargs) / sizeof(char *), const_jargs, 320 | sizeof(const_appclasspath) / sizeof(char *), const_appclasspath, 321 | FULL_VERSION, 322 | DOT_VERSION, 323 | (const_progname != NULL) ? const_progname : *margv, 324 | (const_launcher != NULL) ? const_launcher : *margv, 325 | (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE, 326 | const_cpwildcard, const_javaw, const_ergo_class); 327 | } 328 | ``` 329 | 330 | -------------------------------------------------------------------------------- /src/autorun/jvm/start/README2.md: -------------------------------------------------------------------------------- 1 | # jvm 启动流程2 2 | > 上一篇讲了 jvm 在启动时发生的调用关系。此篇讲解回调JVM后又发生了什么 3 | ## 1. jvm call main() 4 | 接上文 `*ifn` 的 `CreateJavaVM_t CreateJavaVM` 5 | 实际调用的是`JNI_CreateJavaVM` 6 | > `JNI_CreateJavaVM` 实现在 `hotspot/src/share/vm/prims/jni.cpp` 中 7 | 8 | `#define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT` 9 | 10 | `_JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args)` 11 | 12 | 1. 使用 `result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again);` 创建jvm应用线程 13 | 14 | 可以看到, 实际调用了 `thread.cpp` 中的 `Threads::create_vm()` 方法 15 | 16 | 2. `Threads::create_vm()` 17 | #### 注:省略部分源码。如果需要查看请移步 `src/hotspot/share/runtime/thread.cpp` 18 | > 源码位置: thread.cpp 19 | ```c++ 20 | // Initialize the output stream module 21 | ostream_init(); 22 | 23 | // Process java launcher properties. 24 | Arguments::process_sun_java_launcher_properties(args); 25 | 26 | // Initialize the os module 27 | os::init(); 28 | 29 | MACOS_AARCH64_ONLY(os::current_thread_enable_wx(WXWrite)); 30 | 31 | // Record VM creation timing statistics 32 | TraceVmCreationTime create_vm_timer; 33 | create_vm_timer.start(); 34 | 35 | // Initialize library-based TLS 36 | ThreadLocalStorage::init(); 37 | 38 | // Initialize system properties. 39 | Arguments::init_system_properties(); 40 | 41 | // So that JDK version can be used as a discriminator when parsing arguments 42 | JDK_Version_init(); 43 | 44 | // Update/Initialize System properties after JDK version number is known 45 | Arguments::init_version_specific_system_properties(); 46 | 47 | // Make sure to initialize log configuration *before* parsing arguments 48 | LogConfiguration::initialize(create_vm_timer.begin_time()); 49 | 50 | SafepointMechanism::initialize(); 51 | 52 | // Convert -Xrun to -agentlib: if there is no JVM_OnLoad 53 | // Must be before create_vm_init_agents() 54 | if (Arguments::init_libraries_at_startup()) { 55 | convert_vm_init_libraries_to_agents(); 56 | } 57 | 58 | // Launch -agentlib/-agentpath and converted -Xrun agents 59 | if (Arguments::init_agents_at_startup()) { 60 | create_vm_init_agents(); 61 | } 62 | 63 | // Initialize Threads state 64 | _number_of_threads = 0; 65 | _number_of_non_daemon_threads = 0; 66 | 67 | // Initialize global data structures and create system classes in heap 68 | vm_init_globals(); 69 | ``` 70 | 总体来说是初始化了系统的环境变量、线程私有存储,设置了标准输入和输出等。 71 | 72 | `MACOS_AARCH64_ONLY(os::current_thread_enable_wx(WXWrite));` 对m1的支持 73 | 74 | 源码位置: hotspot/src/share/vm/runtime/arguments.cpp 75 | Arguments::init_system_properties(); 76 | ```c++ 77 | PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.name", 78 | "Java Virtual Machine Specification", false)); 79 | PropertyList_add(&_system_properties, new SystemProperty("java.vm.version", VM_Version::vm_release(), false)); 80 | PropertyList_add(&_system_properties, new SystemProperty("java.vm.name", VM_Version::vm_name(), false)); 81 | PropertyList_add(&_system_properties, new SystemProperty("java.vm.info", VM_Version::vm_info_string(), true)); 82 | 83 | // following are JVMTI agent writeable properties. 84 | // Properties values are set to NULL and they are 85 | // os specific they are initialized in os::init_system_properties_values(). 86 | _java_ext_dirs = new SystemProperty("java.ext.dirs", NULL, true); 87 | _java_endorsed_dirs = new SystemProperty("java.endorsed.dirs", NULL, true); 88 | _sun_boot_library_path = new SystemProperty("sun.boot.library.path", NULL, true); 89 | _java_library_path = new SystemProperty("java.library.path", NULL, true); 90 | _java_home = new SystemProperty("java.home", NULL, true); 91 | _sun_boot_class_path = new SystemProperty("sun.boot.class.path", NULL, true); 92 | 93 | _java_class_path = new SystemProperty("java.class.path", "", true); 94 | ``` 95 | 规范版本号: `Arguments::init_version_specific_system_properties()` 96 | ```c++ 97 | 98 | if (JDK_Version::is_gte_jdk17x_version()) { 99 | spec_vendor = "Oracle Corporation"; 100 | spec_version = JDK_Version::current().major_version(); 101 | } 102 | jio_snprintf(buffer, bufsz, "1." UINT32_FORMAT, spec_version); 103 | 104 | PropertyList_add(&_system_properties, 105 | new SystemProperty("java.vm.specification.vendor", spec_vendor, false)); 106 | PropertyList_add(&_system_properties, 107 | new SystemProperty("java.vm.specification.version", buffer, false)); 108 | PropertyList_add(&_system_properties, 109 | new SystemProperty("java.vm.vendor", VM_Version::vm_vendor(), false)); 110 | ``` 111 | 112 | 3. 全局高能来了 113 | `vm_init_globals();` 这里面初始化了很多有用的信息。下篇来分析这里面的部分 114 | -------------------------------------------------------------------------------- /src/autorun/jvm/start/README3.md: -------------------------------------------------------------------------------- 1 | # 本期主题 `vm_init_globals();` 2 | 3 | ## 1. 主流程 4 | 1. 源码位置: `hotspot/src/share/vm/runtime/init.cpp` 5 | ```c++ 6 | check_ThreadShadow(); 7 | basic_types_init(); 8 | eventlog_init(); 9 | mutex_init(); 10 | chunkpool_init(); 11 | perfMemory_init(); 12 | ``` 13 | `basic_types_init`主要用于java初始化基础类型 14 | 源码位置:hotspot/src/share/vm/utilities/globalDefinitions.hpp 15 | 16 | `void basic_types_init()` 17 | ```c++ 18 | // Map BasicType to signature character 19 | char type2char_tab[T_CONFLICT+1]={ 0, 0, 0, 0, 'Z', 'C', 'F', 'D', 'B', 'S', 'I', 'J', 'L', '[', 'V', 0, 0, 0, 0, 0}; 20 | enum BasicType { 21 | T_BOOLEAN = 4, 22 | T_CHAR = 5, 23 | T_FLOAT = 6, 24 | T_DOUBLE = 7, 25 | T_BYTE = 8, 26 | T_SHORT = 9, 27 | T_INT = 10, 28 | T_LONG = 11, 29 | T_OBJECT = 12, 30 | T_ARRAY = 13, 31 | T_VOID = 14, 32 | T_ADDRESS = 15, 33 | T_NARROWOOP = 16, 34 | T_METADATA = 17, 35 | T_NARROWKLASS = 18, 36 | T_CONFLICT = 19, // for stack value type with conflicting contents 37 | T_ILLEGAL = 99 38 | }; 39 | ``` 40 | 41 | 42 | ```c++ 43 | for (int i = T_BOOLEAN; i <= T_CONFLICT; i++) { 44 | BasicType vt = (BasicType)i; 45 | BasicType ft = type2field[vt]; 46 | switch (vt) { 47 | // the following types might plausibly show up in memory layouts: 48 | case T_BOOLEAN: 49 | case T_BYTE: 50 | case T_CHAR: 51 | case T_SHORT: 52 | case T_INT: 53 | case T_FLOAT: 54 | case T_DOUBLE: 55 | case T_LONG: 56 | case T_OBJECT: 57 | case T_ADDRESS: // random raw pointer 58 | case T_METADATA: // metadata pointer 59 | case T_NARROWOOP: // compressed pointer 60 | case T_NARROWKLASS: // compressed klass pointer 61 | case T_CONFLICT: // might as well support a bottom type 62 | case T_VOID: // padding or other unaddressed word 63 | // layout type must map to itself 64 | assert(vt == ft, ""); 65 | break; 66 | default: 67 | // non-layout type must map to a (different) layout type 68 | assert(vt != ft, ""); 69 | assert(ft == type2field[ft], ""); 70 | } 71 | // every type must map to same-sized layout type: 72 | assert(type2size[vt] == type2size[ft], ""); 73 | } 74 | ``` 75 | > 压缩指针选项 76 | ```c++ 77 | if (UseCompressedOops) { 78 | // Size info for oops within java objects is fixed 79 | heapOopSize = jintSize; 80 | LogBytesPerHeapOop = LogBytesPerInt; 81 | LogBitsPerHeapOop = LogBitsPerInt; 82 | BytesPerHeapOop = BytesPerInt; 83 | BitsPerHeapOop = BitsPerInt; 84 | } else { 85 | heapOopSize = oopSize; 86 | LogBytesPerHeapOop = LogBytesPerWord; 87 | LogBitsPerHeapOop = LogBitsPerWord; 88 | BytesPerHeapOop = BytesPerWord; 89 | BitsPerHeapOop = BitsPerWord; 90 | } 91 | _type2aelembytes[T_OBJECT] = heapOopSize; 92 | _type2aelembytes[T_ARRAY] = heapOopSize; 93 | ``` 94 | 3. eventlog_init(); 95 | 96 | 97 | 4. 锁类型初始化 `mutex_init();` 98 | ```c++ 99 | def(tty_lock , Mutex , event, true ); // allow to lock in VM 100 | 101 | def(CGC_lock , Monitor, special, true ); // coordinate between fore- and background GC 102 | def(STS_init_lock , Mutex, leaf, true ); 103 | if (UseConcMarkSweepGC) { 104 | def(iCMS_lock , Monitor, special, true ); // CMS incremental mode start/stop notification 105 | } 106 | if (UseConcMarkSweepGC || UseG1GC) { 107 | def(FullGCCount_lock , Monitor, leaf, true ); // in support of ExplicitGCInvokesConcurrent 108 | } 109 | if (UseG1GC) { 110 | def(CMark_lock , Monitor, nonleaf, true ); // coordinate concurrent mark thread 111 | def(CMRegionStack_lock , Mutex, leaf, true ); 112 | def(SATB_Q_FL_lock , Mutex , special, true ); 113 | def(SATB_Q_CBL_mon , Monitor, nonleaf, true ); 114 | def(Shared_SATB_Q_lock , Mutex, nonleaf, true ); 115 | 116 | def(DirtyCardQ_FL_lock , Mutex , special, true ); 117 | def(DirtyCardQ_CBL_mon , Monitor, nonleaf, true ); 118 | def(Shared_DirtyCardQ_lock , Mutex, nonleaf, true ); 119 | 120 | def(FreeList_lock , Mutex, leaf , true ); 121 | def(SecondaryFreeList_lock , Monitor, leaf , true ); 122 | def(OldSets_lock , Mutex , leaf , true ); 123 | def(RootRegionScan_lock , Monitor, leaf , true ); 124 | def(MMUTracker_lock , Mutex , leaf , true ); 125 | def(HotCardCache_lock , Mutex , special , true ); 126 | def(EvacFailureStack_lock , Mutex , nonleaf , true ); 127 | } 128 | def(ParGCRareEvent_lock , Mutex , leaf , true ); 129 | def(DerivedPointerTableGC_lock , Mutex, leaf, true ); 130 | def(CodeCache_lock , Mutex , special, true ); 131 | def(Interrupt_lock , Monitor, special, true ); // used for interrupt processing 132 | def(RawMonitor_lock , Mutex, special, true ); 133 | def(OopMapCacheAlloc_lock , Mutex, leaf, true ); // used for oop_map_cache allocation. 134 | 135 | def(Patching_lock , Mutex , special, true ); // used for safepointing and code patching. 136 | def(ObjAllocPost_lock , Monitor, special, false); 137 | def(Service_lock , Monitor, special, true ); // used for service thread operations 138 | def(JmethodIdCreation_lock , Mutex , leaf, true ); // used for creating jmethodIDs. 139 | 140 | def(SystemDictionary_lock , Monitor, leaf, true ); // lookups done by VM thread 141 | def(PackageTable_lock , Mutex , leaf, false); 142 | def(InlineCacheBuffer_lock , Mutex , leaf, true ); 143 | def(VMStatistic_lock , Mutex , leaf, false); 144 | def(ExpandHeap_lock , Mutex , leaf, true ); // Used during compilation by VM thread 145 | def(JNIHandleBlockFreeList_lock , Mutex , leaf, true ); // handles are used by VM thread 146 | def(SignatureHandlerLibrary_lock , Mutex , leaf, false); 147 | def(SymbolTable_lock , Mutex , leaf+2, true ); 148 | def(StringTable_lock , Mutex , leaf, true ); 149 | def(ProfilePrint_lock , Mutex , leaf, false); // serial profile printing 150 | def(ExceptionCache_lock , Mutex , leaf, false); // serial profile printing 151 | def(OsrList_lock , Mutex , leaf, true ); 152 | def(Debug1_lock , Mutex , leaf, true ); 153 | #ifndef PRODUCT 154 | def(FullGCALot_lock , Mutex , leaf, false); // a lock to make FullGCALot MT safe 155 | #endif 156 | def(BeforeExit_lock , Monitor, leaf, true ); 157 | def(PerfDataMemAlloc_lock , Mutex , leaf, true ); // used for allocating PerfData memory for performance data 158 | def(PerfDataManager_lock , Mutex , leaf, true ); // used for synchronized access to PerfDataManager resources 159 | 160 | // CMS_modUnionTable_lock leaf 161 | // CMS_bitMap_lock leaf + 1 162 | // CMS_freeList_lock leaf + 2 163 | 164 | def(Safepoint_lock , Monitor, safepoint, true ); // locks SnippetCache_lock/Threads_lock 165 | 166 | def(Threads_lock , Monitor, barrier, true ); 167 | 168 | def(VMOperationQueue_lock , Monitor, nonleaf, true ); // VM_thread allowed to block on these 169 | def(VMOperationRequest_lock , Monitor, nonleaf, true ); 170 | def(RetData_lock , Mutex , nonleaf, false); 171 | def(Terminator_lock , Monitor, nonleaf, true ); 172 | def(VtableStubs_lock , Mutex , nonleaf, true ); 173 | def(Notify_lock , Monitor, nonleaf, true ); 174 | def(JNIGlobalHandle_lock , Mutex , nonleaf, true ); // locks JNIHandleBlockFreeList_lock 175 | def(JNICritical_lock , Monitor, nonleaf, true ); // used for JNI critical regions 176 | def(AdapterHandlerLibrary_lock , Mutex , nonleaf, true); 177 | if (UseConcMarkSweepGC) { 178 | def(SLT_lock , Monitor, nonleaf, false ); 179 | // used in CMS GC for locking PLL lock 180 | } 181 | def(Heap_lock , Monitor, nonleaf+1, false); 182 | def(JfieldIdCreation_lock , Mutex , nonleaf+1, true ); // jfieldID, Used in VM_Operation 183 | def(MemberNameTable_lock , Mutex , nonleaf+1, false); // Used to protect MemberNameTable 184 | 185 | def(CompiledIC_lock , Mutex , nonleaf+2, false); // locks VtableStubs_lock, InlineCacheBuffer_lock 186 | def(CompileTaskAlloc_lock , Mutex , nonleaf+2, true ); 187 | def(CompileStatistics_lock , Mutex , nonleaf+2, false); 188 | def(MultiArray_lock , Mutex , nonleaf+2, false); // locks SymbolTable_lock 189 | 190 | def(JvmtiThreadState_lock , Mutex , nonleaf+2, false); // Used by JvmtiThreadState/JvmtiEventController 191 | def(JvmtiPendingEvent_lock , Monitor, nonleaf, false); // Used by JvmtiCodeBlobEvents 192 | def(Management_lock , Mutex , nonleaf+2, false); // used for JVM management 193 | 194 | def(Compile_lock , Mutex , nonleaf+3, true ); 195 | def(MethodData_lock , Mutex , nonleaf+3, false); 196 | 197 | def(MethodCompileQueue_lock , Monitor, nonleaf+4, true ); 198 | def(Debug2_lock , Mutex , nonleaf+4, true ); 199 | def(Debug3_lock , Mutex , nonleaf+4, true ); 200 | def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread 201 | def(CompileThread_lock , Monitor, nonleaf+5, false ); 202 | def(PeriodicTask_lock , Monitor, nonleaf+5, true); 203 | 204 | #ifdef INCLUDE_TRACE 205 | def(JfrMsg_lock , Monitor, leaf, true); 206 | def(JfrBuffer_lock , Mutex, nonleaf+1, true); 207 | def(JfrThreadGroups_lock , Mutex, nonleaf+1, true); 208 | def(JfrStream_lock , Mutex, nonleaf+2, true); 209 | def(JfrStacktrace_lock , Mutex, special, true ); 210 | #endif 211 | ``` 212 | 213 | 内存池初始化 `chunkpool_init()` 214 | `ChunkPool::initialize();` 215 | 216 | ```c++ 217 | static void initialize() { 218 | _large_pool = new ChunkPool(Chunk::size + Chunk::aligned_overhead_size()); 219 | _medium_pool = new ChunkPool(Chunk::medium_size + Chunk::aligned_overhead_size()); 220 | _small_pool = new ChunkPool(Chunk::init_size + Chunk::aligned_overhead_size()); 221 | _tiny_pool = new ChunkPool(Chunk::tiny_size + Chunk::aligned_overhead_size()); 222 | } 223 | ``` 224 | 225 | 性能内存 `perfMemory_init()` 226 | ```c++ 227 | void perfMemory_init() { 228 | 229 | if (!UsePerfData) return; 230 | 231 | PerfMemory::initialize(); 232 | } 233 | ... 234 | void PerfMemory::initialize() { 235 | if (_prologue != NULL) 236 | // initialization already performed 237 | return; 238 | 239 | size_t capacity = align_size_up(PerfDataMemorySize, 240 | os::vm_allocation_granularity()); 241 | 242 | if (PerfTraceMemOps) { 243 | tty->print("PerfDataMemorySize = " SIZE_FORMAT "," 244 | " os::vm_allocation_granularity = " SIZE_FORMAT "," 245 | " adjusted size = " SIZE_FORMAT "\n", 246 | PerfDataMemorySize, 247 | os::vm_allocation_granularity(), 248 | capacity); 249 | } 250 | 251 | // allocate PerfData memory region 252 | create_memory_region(capacity); 253 | 254 | if (_start == NULL) { 255 | 256 | // the PerfMemory region could not be created as desired. Rather 257 | // than terminating the JVM, we revert to creating the instrumentation 258 | // on the C heap. When running in this mode, external monitoring 259 | // clients cannot attach to and monitor this JVM. 260 | // 261 | // the warning is issued only in debug mode in order to avoid 262 | // additional output to the stdout or stderr output streams. 263 | // 264 | if (PrintMiscellaneous && Verbose) { 265 | warning("Could not create PerfData Memory region, reverting to malloc"); 266 | } 267 | 268 | _prologue = NEW_C_HEAP_OBJ(PerfDataPrologue, mtInternal); 269 | } 270 | else { 271 | 272 | // the PerfMemory region was created as expected. 273 | 274 | if (PerfTraceMemOps) { 275 | tty->print("PerfMemory created: address = " INTPTR_FORMAT "," 276 | " size = " SIZE_FORMAT "\n", 277 | (void*)_start, 278 | _capacity); 279 | } 280 | 281 | _prologue = (PerfDataPrologue *)_start; 282 | _end = _start + _capacity; 283 | _top = _start + sizeof(PerfDataPrologue); 284 | } 285 | 286 | assert(_prologue != NULL, "prologue pointer must be initialized"); 287 | 288 | #ifdef VM_LITTLE_ENDIAN 289 | _prologue->magic = (jint)0xc0c0feca; 290 | _prologue->byte_order = PERFDATA_LITTLE_ENDIAN; 291 | #else 292 | _prologue->magic = (jint)0xcafec0c0; 293 | _prologue->byte_order = PERFDATA_BIG_ENDIAN; 294 | #endif 295 | 296 | _prologue->major_version = PERFDATA_MAJOR_VERSION; 297 | _prologue->minor_version = PERFDATA_MINOR_VERSION; 298 | _prologue->accessible = 0; 299 | 300 | _prologue->entry_offset = sizeof(PerfDataPrologue); 301 | _prologue->num_entries = 0; 302 | _prologue->used = 0; 303 | _prologue->overflow = 0; 304 | _prologue->mod_time_stamp = 0; 305 | 306 | OrderAccess::release_store(&_initialized, 1); 307 | } 308 | ``` 309 | 310 | 分配内存 311 | ```c++ 312 | // create the PerfData memory region 313 | // 314 | // This method creates the memory region used to store performance 315 | // data for the JVM. The memory may be created in standard or 316 | // shared memory. 317 | // 318 | void PerfMemory::create_memory_region(size_t size) { 319 | 320 | if (PerfDisableSharedMem) { 321 | // do not share the memory for the performance data. 322 | _start = create_standard_memory(size); 323 | } 324 | else { 325 | _start = create_shared_memory(size); 326 | if (_start == NULL) { 327 | 328 | // creation of the shared memory region failed, attempt 329 | // to create a contiguous, non-shared memory region instead. 330 | // 331 | if (PrintMiscellaneous && Verbose) { 332 | warning("Reverting to non-shared PerfMemory region.\n"); 333 | } 334 | PerfDisableSharedMem = true; 335 | _start = create_standard_memory(size); 336 | } 337 | } 338 | 339 | if (_start != NULL) _capacity = size; 340 | } 341 | ``` 342 | -------------------------------------------------------------------------------- /src/autorun/jvm/start/README4.md: -------------------------------------------------------------------------------- 1 | 2 | ## `init_globals()` 3 | 4 | ```c++ 5 | // ... 6 | // Initialize Java-Level synchronization subsystem 7 | ObjectMonitor::Initialize(); 8 | ObjectSynchronizer::initialize(); 9 | 10 | // Initialize global modules 11 | jint status = init_globals(); 12 | // ... 13 | ``` 14 | 15 | ```c++ 16 | jint init_globals() { 17 | HandleMark hm; 18 | management_init(); 19 | bytecodes_init(); 20 | classLoader_init(); 21 | codeCache_init(); 22 | VM_Version_init(); 23 | os_init_globals(); 24 | stubRoutines_init1(); 25 | jint status = universe_init(); // dependent on codeCache_init and 26 | // stubRoutines_init1 and metaspace_init. 27 | if (status != JNI_OK) 28 | return status; 29 | 30 | interpreter_init(); // before any methods loaded 31 | invocationCounter_init(); // before any methods loaded 32 | marksweep_init(); 33 | accessFlags_init(); 34 | templateTable_init(); 35 | InterfaceSupport_init(); 36 | SharedRuntime::generate_stubs(); 37 | universe2_init(); // dependent on codeCache_init and stubRoutines_init1 38 | referenceProcessor_init(); 39 | jni_handles_init(); 40 | vmStructs_init(); 41 | vtableStubs_init(); 42 | InlineCacheBuffer_init(); 43 | compilerOracle_init(); 44 | compilationPolicy_init(); 45 | compileBroker_init(); 46 | VMRegImpl::set_regName(); 47 | if (!universe_post_init()) { 48 | return JNI_ERR; 49 | } 50 | javaClasses_init(); // must happen after vtable initialization 51 | stubRoutines_init2(); // note: StubRoutines need 2-phase init 52 | 53 | // All the flags that get adjusted by VM_Version_init and os::init_2 54 | // have been set so dump the flags now. 55 | if (PrintFlagsFinal) { 56 | CommandLineFlags::printFlags(tty, false); 57 | } 58 | } 59 | ``` 60 | HandleMark hm; 61 | 62 | ### `management_init()` 63 | ### `bytecodes_init()` 64 | ### `classLoader_init()` 65 | ### `codeCache_init()` 66 | ### `VM_Version_init()` 67 | ### `os_init_globals()` 68 | ### `stubRoutines_init1()` 69 | 70 | ### `jint status = universe_init()` 71 | // dependent on codeCache_init and 72 | // stubRoutines_init1 and metaspace_init. 73 | > 内存单元初始化 74 | 75 | ### `interpreter_init()` 76 | // before any methods loaded 77 | 78 | ### `invocationCounter_init()` 79 | // before any methods loaded 80 | 81 | ### `marksweep_init()` 82 | 83 | 84 | ### `accessFlags_init()` 85 | 86 | 87 | ### `templateTable_init()` 88 | 89 | ### `InterfaceSupport_init()` 90 | 91 | ### `SharedRuntime::generate_stubs()` 92 | 93 | ### `universe2_init()` 94 | // dependent on codeCache_init and stubRoutines_init1 95 | 96 | ### `referenceProcessor_init()` 97 | 98 | ### `jni_handles_init()` 99 | 100 | ### `vmStructs_init()` 101 | 102 | ### `vtableStubs_init()` 103 | 104 | ### `InlineCacheBuffer_init()` 105 | 106 | ### `compilerOracle_init()` 107 | 108 | ### `compilationPolicy_init()` 109 | 110 | ### `compileBroker_init()` 111 | 112 | ### `VMRegImpl::set_regName()` 113 | ```c++ 114 | if (!universe_post_init()) { 115 | return JNI_ERR; 116 | } 117 | ``` 118 | ### `javaClasses_init()` // must happen after vtable initialization 119 | ### `stubRoutines_init2()` // note: StubRoutines need 2-phase init 120 | -------------------------------------------------------------------------------- /src/autorun/jvm/start/img/jvm启动流程图1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/error0702/jvm-study/93a8062c5b74699bea9ef93a4c995a9223698f18/src/autorun/jvm/start/img/jvm启动流程图1.png -------------------------------------------------------------------------------- /src/autorun/other/tools/GDB.md: -------------------------------------------------------------------------------- 1 | # GDB 调试工具 -------------------------------------------------------------------------------- /src/autorun/other/tools/NM.md: -------------------------------------------------------------------------------- 1 | # Linux NM 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/autorun/other/tools/TOP.md: -------------------------------------------------------------------------------- 1 | # TOP命令使用技巧 -------------------------------------------------------------------------------- /test/autorun/jvm/jni/HelloJni.java: -------------------------------------------------------------------------------- 1 | public class HelloJni { 2 | 3 | public native void hello(); 4 | 5 | } -------------------------------------------------------------------------------- /test/autorun/jvm/jni/HelloJniTest.java: -------------------------------------------------------------------------------- 1 | public class HelloJniTest { 2 | 3 | public static void main(String[] args) { 4 | System.load("/Users/autorun/Documents/Develop/Code/c/jvm-study/test/autorun/jvm/jni/lib/HelloJni.so"); 5 | HelloJni hello = new HelloJni(); 6 | hello.hello(); 7 | } 8 | } --------------------------------------------------------------------------------